Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore8
-rw-r--r--.htaccess25
-rw-r--r--.mailmap3
-rw-r--r--.mention-bot33
-rw-r--r--.travis.yml10
m---------3rdparty0
-rw-r--r--AUTHORS21
-rw-r--r--CONTRIBUTING.md16
-rw-r--r--README.md52
-rw-r--r--apps/comments/appinfo/app.php35
-rw-r--r--apps/comments/appinfo/info.xml13
-rw-r--r--apps/comments/css/comments.css82
-rw-r--r--apps/comments/js/app.js20
-rw-r--r--apps/comments/js/commentcollection.js167
-rw-r--r--apps/comments/js/commentmodel.js58
-rw-r--r--apps/comments/js/commentstabview.js386
-rw-r--r--apps/comments/js/commentsummarymodel.js65
-rw-r--r--apps/comments/js/filesplugin.js125
-rw-r--r--apps/comments/tests/js/commentscollectionSpec.js148
-rw-r--r--apps/comments/tests/js/commentstabviewSpec.js374
-rw-r--r--apps/comments/tests/js/filespluginSpec.js102
-rw-r--r--apps/dav/appinfo/app.php35
-rw-r--r--apps/dav/appinfo/application.php130
-rw-r--r--apps/dav/appinfo/database.xml506
-rw-r--r--apps/dav/appinfo/info.xml8
-rw-r--r--apps/dav/appinfo/install.php26
-rw-r--r--apps/dav/appinfo/register_command.php43
-rw-r--r--apps/dav/appinfo/update.php25
-rw-r--r--apps/dav/appinfo/v1/publicwebdav.php5
-rw-r--r--apps/dav/appinfo/v1/webdav.php11
-rw-r--r--apps/dav/appinfo/v2/remote.php20
-rw-r--r--apps/dav/command/createaddressbook.php66
-rw-r--r--apps/dav/command/createcalendar.php81
-rw-r--r--apps/dav/command/migrateaddressbooks.php84
-rw-r--r--apps/dav/command/syncsystemaddressbook.php66
-rw-r--r--apps/dav/lib/caldav/caldavbackend.php1260
-rw-r--r--apps/dav/lib/caldav/calendar.php102
-rw-r--r--apps/dav/lib/caldav/calendarhome.php78
-rw-r--r--apps/dav/lib/caldav/calendarroot.php10
-rw-r--r--apps/dav/lib/caldav/schedule/imipplugin.php128
-rw-r--r--apps/dav/lib/carddav/addressbook.php164
-rw-r--r--apps/dav/lib/carddav/addressbookimpl.php223
-rw-r--r--apps/dav/lib/carddav/addressbookroot.php51
-rw-r--r--apps/dav/lib/carddav/card.php45
-rw-r--r--apps/dav/lib/carddav/carddavbackend.php384
-rw-r--r--apps/dav/lib/carddav/contactsmanager.php65
-rw-r--r--apps/dav/lib/carddav/converter.php171
-rw-r--r--apps/dav/lib/carddav/plugin.php47
-rw-r--r--apps/dav/lib/carddav/syncjob.php40
-rw-r--r--apps/dav/lib/carddav/syncservice.php265
-rw-r--r--apps/dav/lib/carddav/useraddressbooks.php67
-rw-r--r--apps/dav/lib/comments/commentnode.php254
-rw-r--r--apps/dav/lib/comments/commentsplugin.php245
-rw-r--r--apps/dav/lib/comments/entitycollection.php199
-rw-r--r--apps/dav/lib/comments/entitytypecollection.php125
-rw-r--r--apps/dav/lib/comments/rootcollection.php205
-rw-r--r--apps/dav/lib/connector/publicauth.php2
-rw-r--r--apps/dav/lib/connector/sabre/appenabledplugin.php3
-rw-r--r--apps/dav/lib/connector/sabre/auth.php52
-rw-r--r--apps/dav/lib/connector/sabre/blocklegacyclientplugin.php3
-rw-r--r--apps/dav/lib/connector/sabre/commentpropertiesplugin.php130
-rw-r--r--apps/dav/lib/connector/sabre/copyetagheaderplugin.php3
-rw-r--r--apps/dav/lib/connector/sabre/custompropertiesbackend.php2
-rw-r--r--apps/dav/lib/connector/sabre/directory.php32
-rw-r--r--apps/dav/lib/connector/sabre/dummygetresponseplugin.php3
-rw-r--r--apps/dav/lib/connector/sabre/exception/entitytoolarge.php2
-rw-r--r--apps/dav/lib/connector/sabre/exception/filelocked.php3
-rw-r--r--apps/dav/lib/connector/sabre/exception/forbidden.php64
-rw-r--r--apps/dav/lib/connector/sabre/exception/invalidpath.php2
-rw-r--r--apps/dav/lib/connector/sabre/exception/unsupportedmediatype.php2
-rw-r--r--apps/dav/lib/connector/sabre/exceptionloggerplugin.php2
-rw-r--r--apps/dav/lib/connector/sabre/fakelockerplugin.php26
-rw-r--r--apps/dav/lib/connector/sabre/file.php60
-rw-r--r--apps/dav/lib/connector/sabre/filesplugin.php75
-rw-r--r--apps/dav/lib/connector/sabre/listenerplugin.php68
-rw-r--r--apps/dav/lib/connector/sabre/lockplugin.php21
-rw-r--r--apps/dav/lib/connector/sabre/maintenanceplugin.php2
-rw-r--r--apps/dav/lib/connector/sabre/node.php14
-rw-r--r--apps/dav/lib/connector/sabre/objecttree.php29
-rw-r--r--apps/dav/lib/connector/sabre/principal.php128
-rw-r--r--apps/dav/lib/connector/sabre/quotaplugin.php4
-rw-r--r--apps/dav/lib/connector/sabre/server.php2
-rw-r--r--apps/dav/lib/connector/sabre/serverfactory.php26
-rw-r--r--apps/dav/lib/connector/sabre/taglist.php159
-rw-r--r--apps/dav/lib/connector/sabre/tagsplugin.php7
-rw-r--r--apps/dav/lib/dav/groupprincipalbackend.php171
-rw-r--r--apps/dav/lib/dav/sharing/backend.php194
-rw-r--r--apps/dav/lib/dav/sharing/ishareable.php74
-rw-r--r--apps/dav/lib/dav/sharing/plugin.php218
-rw-r--r--apps/dav/lib/dav/sharing/xml/invite.php149
-rw-r--r--apps/dav/lib/dav/sharing/xml/sharerequest.php84
-rw-r--r--apps/dav/lib/dav/systemprincipalbackend.php179
-rw-r--r--apps/dav/lib/files/custompropertiesbackend.php6
-rw-r--r--apps/dav/lib/files/fileshome.php20
-rw-r--r--apps/dav/lib/files/rootcollection.php20
-rw-r--r--apps/dav/lib/hookmanager.php83
-rw-r--r--apps/dav/lib/migration/addressbookadapter.php87
-rw-r--r--apps/dav/lib/migration/migrateaddressbooks.php92
-rw-r--r--apps/dav/lib/rootcollection.php96
-rw-r--r--apps/dav/lib/server.php77
-rw-r--r--apps/dav/lib/systemtag/systemtagmappingnode.php114
-rw-r--r--apps/dav/lib/systemtag/systemtagnode.php160
-rw-r--r--apps/dav/lib/systemtag/systemtagplugin.php247
-rw-r--r--apps/dav/lib/systemtag/systemtagsbyidcollection.php177
-rw-r--r--apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php201
-rw-r--r--apps/dav/lib/systemtag/systemtagsobjecttypecollection.php184
-rw-r--r--apps/dav/lib/systemtag/systemtagsrelationscollection.php73
-rw-r--r--apps/dav/tests/misc/sharing.xml7
-rw-r--r--apps/dav/tests/travis/caldav/install.sh (renamed from apps/dav/tests/travis/carddavtester.sh)17
-rw-r--r--apps/dav/tests/travis/caldav/script.sh19
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/current-user-principal/1.xml6
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/1.txt32
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/1.xml13
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/2.txt33
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/3.txt34
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/4.txt39
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/5.txt38
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/6.txt48
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/1.xml7
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/10.xml6
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/11.xml7
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/2.xml5
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/21.xml7
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/3.xml5
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/4.xml5
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/5.xml8
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/6.xml8
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/7.xml8
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/8.xml6
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/1.xml8
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/4.xml8
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.ics29
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.xml6
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/6.ics29
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/7.ics29
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/8.ics29
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/9.ics29
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/1.xml8
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/4.xml8
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/6.vcf11
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/7.vcf11
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/8.vcf11
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/9.vcf11
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vcurrent-user-principal/1.xml6
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/1.vcf11
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/2.vcf17
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/3.vcf12
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/sync/1.xml7
-rw-r--r--apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/sync/2.xml5
-rw-r--r--apps/dav/tests/travis/caldavtest/serverinfo.dtd (renamed from apps/dav/tests/travis/caldavtest/config/serverinfo.dtd)0
-rw-r--r--apps/dav/tests/travis/caldavtest/serverinfo.xml (renamed from apps/dav/tests/travis/caldavtest/config/serverinfo.xml)10
-rw-r--r--apps/dav/tests/travis/caldavtest/tests/CalDAV/current-user-principal.xml151
-rw-r--r--apps/dav/tests/travis/caldavtest/tests/CalDAV/sharing-calendars.xml589
-rw-r--r--apps/dav/tests/travis/caldavtest/tests/CalDAV/sync-report.xml3329
-rw-r--r--apps/dav/tests/travis/caldavtest/tests/CardDAV/sharing-addressbooks.xml309
-rw-r--r--apps/dav/tests/travis/caldavtest/tests/CardDAV/sync-report.xml1602
-rw-r--r--apps/dav/tests/travis/carddav/install.sh20
-rw-r--r--apps/dav/tests/travis/carddav/script.sh22
-rw-r--r--apps/dav/tests/travis/litmus-v1/install.sh (renamed from apps/dav/tests/travis/litmus-v1.sh)11
-rw-r--r--apps/dav/tests/travis/litmus-v1/script.sh13
-rw-r--r--apps/dav/tests/travis/litmus-v2/install.sh (renamed from apps/dav/tests/travis/litmus-v2.sh)11
-rw-r--r--apps/dav/tests/travis/litmus-v2/script.sh13
-rw-r--r--apps/dav/tests/unit/appinfo/applicationtest.php62
-rw-r--r--apps/dav/tests/unit/bootstrap.php24
-rw-r--r--apps/dav/tests/unit/caldav/caldavbackendtest.php476
-rw-r--r--apps/dav/tests/unit/caldav/calendartest.php64
-rw-r--r--apps/dav/tests/unit/caldav/schedule/imipplugintest.php91
-rw-r--r--apps/dav/tests/unit/carddav/addressbookimpltest.php287
-rw-r--r--apps/dav/tests/unit/carddav/addressbooktest.php64
-rw-r--r--apps/dav/tests/unit/carddav/carddavbackendtest.php461
-rw-r--r--apps/dav/tests/unit/carddav/contactsmanagertest.php43
-rw-r--r--apps/dav/tests/unit/carddav/convertertest.php137
-rw-r--r--apps/dav/tests/unit/carddav/sharing/plugintest.php81
-rw-r--r--apps/dav/tests/unit/carddav/syncservicetest.php138
-rw-r--r--apps/dav/tests/unit/comments/commentnode.php420
-rw-r--r--apps/dav/tests/unit/comments/commentsplugin.php654
-rw-r--r--apps/dav/tests/unit/comments/entitycollection.php116
-rw-r--r--apps/dav/tests/unit/comments/entitytypecollection.php97
-rw-r--r--apps/dav/tests/unit/comments/rootcollection.php160
-rw-r--r--apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php3
-rw-r--r--apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php3
-rw-r--r--apps/dav/tests/unit/connector/sabre/FakeLockerPluginTest.php15
-rw-r--r--apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/auth.php111
-rw-r--r--apps/dav/tests/unit/connector/sabre/commentpropertiesplugin.php148
-rw-r--r--apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php21
-rw-r--r--apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php29
-rw-r--r--apps/dav/tests/unit/connector/sabre/directory.php46
-rw-r--r--apps/dav/tests/unit/connector/sabre/exception/forbiddentest.php57
-rw-r--r--apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php26
-rw-r--r--apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php22
-rw-r--r--apps/dav/tests/unit/connector/sabre/file.php123
-rw-r--r--apps/dav/tests/unit/connector/sabre/filesplugin.php63
-rw-r--r--apps/dav/tests/unit/connector/sabre/node.php24
-rw-r--r--apps/dav/tests/unit/connector/sabre/objecttree.php73
-rw-r--r--apps/dav/tests/unit/connector/sabre/principal.php151
-rw-r--r--apps/dav/tests/unit/connector/sabre/quotaplugin.php22
-rw-r--r--apps/dav/tests/unit/connector/sabre/requesttest/auth.php84
-rw-r--r--apps/dav/tests/unit/connector/sabre/requesttest/downloadtest.php29
-rw-r--r--apps/dav/tests/unit/connector/sabre/requesttest/encryptionuploadtest.php29
-rw-r--r--apps/dav/tests/unit/connector/sabre/requesttest/exceptionplugin.php22
-rw-r--r--apps/dav/tests/unit/connector/sabre/requesttest/requesttest.php25
-rw-r--r--apps/dav/tests/unit/connector/sabre/requesttest/sapi.php22
-rw-r--r--apps/dav/tests/unit/connector/sabre/requesttest/uploadtest.php29
-rw-r--r--apps/dav/tests/unit/connector/sabre/tagsplugin.php21
-rw-r--r--apps/dav/tests/unit/dav/groupprincipaltest.php164
-rw-r--r--apps/dav/tests/unit/dav/sharing/plugintest.php83
-rw-r--r--apps/dav/tests/unit/dav/systemprincipalbackendtest.php131
-rw-r--r--apps/dav/tests/unit/migration/addressbookadaptertest.php129
-rw-r--r--apps/dav/tests/unit/migration/contacts_schema.xml151
-rw-r--r--apps/dav/tests/unit/migration/migrateaddressbooktest.php70
-rw-r--r--apps/dav/tests/unit/phpunit.xml2
-rw-r--r--apps/dav/tests/unit/servertest.php24
-rw-r--r--apps/dav/tests/unit/systemtag/systemtagmappingnode.php132
-rw-r--r--apps/dav/tests/unit/systemtag/systemtagnode.php244
-rw-r--r--apps/dav/tests/unit/systemtag/systemtagplugin.php355
-rw-r--r--apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php244
-rw-r--r--apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php381
-rw-r--r--apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php160
-rw-r--r--apps/encryption/appinfo/app.php2
-rw-r--r--apps/encryption/appinfo/application.php2
-rw-r--r--apps/encryption/appinfo/info.xml5
-rw-r--r--apps/encryption/appinfo/register_command.php2
-rw-r--r--apps/encryption/appinfo/routes.php2
-rw-r--r--apps/encryption/command/enablemasterkey.php2
-rw-r--r--apps/encryption/command/migratekeys.php2
-rw-r--r--apps/encryption/controller/recoverycontroller.php2
-rw-r--r--apps/encryption/controller/settingscontroller.php2
-rw-r--r--apps/encryption/controller/statuscontroller.php2
-rw-r--r--apps/encryption/hooks/contracts/ihook.php2
-rw-r--r--apps/encryption/hooks/userhooks.php9
-rw-r--r--apps/encryption/l10n/es.js2
-rw-r--r--apps/encryption/l10n/es.json2
-rw-r--r--apps/encryption/l10n/es_AR.js1
-rw-r--r--apps/encryption/l10n/es_AR.json1
-rw-r--r--apps/encryption/l10n/et_EE.js1
-rw-r--r--apps/encryption/l10n/et_EE.json1
-rw-r--r--apps/encryption/l10n/he.js59
-rw-r--r--apps/encryption/l10n/he.json57
-rw-r--r--apps/encryption/l10n/nb_NO.js2
-rw-r--r--apps/encryption/l10n/nb_NO.json2
-rw-r--r--apps/encryption/l10n/pt_BR.js2
-rw-r--r--apps/encryption/l10n/pt_BR.json2
-rw-r--r--apps/encryption/l10n/pt_PT.js4
-rw-r--r--apps/encryption/l10n/pt_PT.json4
-rw-r--r--apps/encryption/l10n/sl.js1
-rw-r--r--apps/encryption/l10n/sl.json1
-rw-r--r--apps/encryption/l10n/tr.js2
-rw-r--r--apps/encryption/l10n/tr.json2
-rw-r--r--apps/encryption/lib/crypto/crypt.php61
-rw-r--r--apps/encryption/lib/crypto/decryptall.php2
-rw-r--r--apps/encryption/lib/crypto/encryptall.php20
-rw-r--r--apps/encryption/lib/crypto/encryption.php7
-rw-r--r--apps/encryption/lib/exceptions/multikeydecryptexception.php2
-rw-r--r--apps/encryption/lib/exceptions/multikeyencryptexception.php2
-rw-r--r--apps/encryption/lib/exceptions/privatekeymissingexception.php2
-rw-r--r--apps/encryption/lib/exceptions/publickeymissingexception.php2
-rw-r--r--apps/encryption/lib/hookmanager.php2
-rw-r--r--apps/encryption/lib/keymanager.php30
-rw-r--r--apps/encryption/lib/migration.php8
-rw-r--r--apps/encryption/lib/recovery.php26
-rw-r--r--apps/encryption/lib/session.php2
-rw-r--r--apps/encryption/lib/users/setup.php2
-rw-r--r--apps/encryption/lib/util.php3
-rw-r--r--apps/encryption/settings/settings-admin.php5
-rw-r--r--apps/encryption/settings/settings-personal.php2
-rw-r--r--apps/encryption/tests/command/testenablemasterkey.php2
-rw-r--r--apps/encryption/tests/controller/RecoveryControllerTest.php2
-rw-r--r--apps/encryption/tests/controller/SettingsControllerTest.php2
-rw-r--r--apps/encryption/tests/controller/StatusControllerTest.php2
-rw-r--r--apps/encryption/tests/hooks/UserHooksTest.php2
-rw-r--r--apps/encryption/tests/lib/HookManagerTest.php2
-rw-r--r--apps/encryption/tests/lib/KeyManagerTest.php78
-rw-r--r--apps/encryption/tests/lib/MigrationTest.php45
-rw-r--r--apps/encryption/tests/lib/RecoveryTest.php67
-rw-r--r--apps/encryption/tests/lib/SessionTest.php2
-rw-r--r--apps/encryption/tests/lib/UtilTest.php2
-rw-r--r--apps/encryption/tests/lib/crypto/cryptTest.php2
-rw-r--r--apps/encryption/tests/lib/crypto/decryptalltest.php2
-rw-r--r--apps/encryption/tests/lib/crypto/encryptalltest.php2
-rw-r--r--apps/encryption/tests/lib/crypto/encryptionTest.php2
-rw-r--r--apps/encryption/tests/lib/users/SetupTest.php2
-rw-r--r--apps/encryption/vendor/pbkdf2fallback.php87
-rw-r--r--apps/federation/api/ocsauthapi.php161
-rw-r--r--apps/federation/appinfo/app.php26
-rw-r--r--apps/federation/appinfo/application.php182
-rw-r--r--apps/federation/appinfo/database.xml69
-rw-r--r--apps/federation/appinfo/info.xml17
-rw-r--r--apps/federation/appinfo/install.php23
-rw-r--r--apps/federation/appinfo/register_command.php7
-rw-r--r--apps/federation/appinfo/routes.php47
-rw-r--r--apps/federation/appinfo/update.php23
-rw-r--r--apps/federation/backgroundjob/getsharedsecret.php191
-rw-r--r--apps/federation/backgroundjob/requestsharedsecret.php174
-rw-r--r--apps/federation/command/syncfederationaddressbooks.php53
-rw-r--r--apps/federation/controller/settingscontroller.php123
-rw-r--r--apps/federation/css/settings-admin.css26
-rw-r--r--apps/federation/dav/fedauth.php54
-rw-r--r--apps/federation/img/app.svg4
-rw-r--r--apps/federation/js/settings-admin.js82
-rw-r--r--apps/federation/lib/dbhandler.php290
-rw-r--r--apps/federation/lib/hooks.php50
-rw-r--r--apps/federation/lib/syncfederationaddressbooks.php58
-rw-r--r--apps/federation/lib/syncjob.php43
-rw-r--r--apps/federation/lib/trustedservers.php255
-rw-r--r--apps/federation/middleware/addservermiddleware.php71
-rw-r--r--apps/federation/settings/settings-admin.php43
-rw-r--r--apps/federation/templates/settings-admin.php40
-rw-r--r--apps/federation/tests/api/ocsauthapitest.php191
-rw-r--r--apps/federation/tests/backgroundjob/getsharedsecrettest.php198
-rw-r--r--apps/federation/tests/backgroundjob/requestsharedsecrettest.php169
-rw-r--r--apps/federation/tests/controller/settingscontrollertest.php166
-rw-r--r--apps/federation/tests/dav/fedauthtest.php52
-rw-r--r--apps/federation/tests/lib/dbhandlertest.php283
-rw-r--r--apps/federation/tests/lib/hookstest.php79
-rw-r--r--apps/federation/tests/lib/syncfederationaddressbookstest.php66
-rw-r--r--apps/federation/tests/lib/trustedserverstest.php342
-rw-r--r--apps/federation/tests/middleware/addservermiddlewaretest.php100
-rw-r--r--apps/files/admin.php13
-rw-r--r--apps/files/ajax/delete.php81
-rw-r--r--apps/files/ajax/download.php2
-rw-r--r--apps/files/ajax/getstoragestats.php2
-rw-r--r--apps/files/ajax/list.php2
-rw-r--r--apps/files/ajax/move.php59
-rw-r--r--apps/files/ajax/newfile.php103
-rw-r--r--apps/files/ajax/newfolder.php99
-rw-r--r--apps/files/ajax/rename.php58
-rw-r--r--apps/files/ajax/scan.php102
-rw-r--r--apps/files/ajax/upload.php12
-rw-r--r--apps/files/appinfo/app.php4
-rw-r--r--apps/files/appinfo/application.php2
-rw-r--r--apps/files/appinfo/info.xml6
-rw-r--r--apps/files/appinfo/install.php24
-rw-r--r--apps/files/appinfo/register_command.php5
-rw-r--r--apps/files/appinfo/routes.php4
-rw-r--r--apps/files/appinfo/update.php14
-rw-r--r--apps/files/command/deleteorphanedfiles.php2
-rw-r--r--apps/files/command/scan.php202
-rw-r--r--apps/files/controller/apicontroller.php4
-rw-r--r--apps/files/controller/viewcontroller.php15
-rw-r--r--apps/files/css/detailsView.css3
-rw-r--r--apps/files/css/files.css4
-rw-r--r--apps/files/download.php6
-rw-r--r--apps/files/js/app.js3
-rw-r--r--apps/files/js/favoritesplugin.js2
-rw-r--r--apps/files/js/fileactions.js34
-rw-r--r--apps/files/js/fileactionsmenu.js8
-rw-r--r--apps/files/js/filelist.js650
-rw-r--r--apps/files/js/files.js85
-rw-r--r--apps/files/js/newfilemenu.js20
-rw-r--r--apps/files/js/tagsplugin.js32
-rw-r--r--apps/files/l10n/af_ZA.js2
-rw-r--r--apps/files/l10n/af_ZA.json2
-rw-r--r--apps/files/l10n/ar.js27
-rw-r--r--apps/files/l10n/ar.json27
-rw-r--r--apps/files/l10n/ast.js28
-rw-r--r--apps/files/l10n/ast.json28
-rw-r--r--apps/files/l10n/az.js28
-rw-r--r--apps/files/l10n/az.json28
-rw-r--r--apps/files/l10n/be.js1
-rw-r--r--apps/files/l10n/be.json1
-rw-r--r--apps/files/l10n/bg_BG.js26
-rw-r--r--apps/files/l10n/bg_BG.json26
-rw-r--r--apps/files/l10n/bn_BD.js14
-rw-r--r--apps/files/l10n/bn_BD.json14
-rw-r--r--apps/files/l10n/bn_IN.js3
-rw-r--r--apps/files/l10n/bn_IN.json3
-rw-r--r--apps/files/l10n/bs.js26
-rw-r--r--apps/files/l10n/bs.json26
-rw-r--r--apps/files/l10n/ca.js26
-rw-r--r--apps/files/l10n/ca.json26
-rw-r--r--apps/files/l10n/cs_CZ.js39
-rw-r--r--apps/files/l10n/cs_CZ.json39
-rw-r--r--apps/files/l10n/cy_GB.js8
-rw-r--r--apps/files/l10n/cy_GB.json8
-rw-r--r--apps/files/l10n/da.js28
-rw-r--r--apps/files/l10n/da.json28
-rw-r--r--apps/files/l10n/de.js39
-rw-r--r--apps/files/l10n/de.json39
-rw-r--r--apps/files/l10n/de_AT.js2
-rw-r--r--apps/files/l10n/de_AT.json2
-rw-r--r--apps/files/l10n/de_DE.js44
-rw-r--r--apps/files/l10n/de_DE.json44
-rw-r--r--apps/files/l10n/el.js35
-rw-r--r--apps/files/l10n/el.json35
-rw-r--r--apps/files/l10n/en_GB.js26
-rw-r--r--apps/files/l10n/en_GB.json26
-rw-r--r--apps/files/l10n/eo.js17
-rw-r--r--apps/files/l10n/eo.json17
-rw-r--r--apps/files/l10n/es.js43
-rw-r--r--apps/files/l10n/es.json43
-rw-r--r--apps/files/l10n/es_AR.js24
-rw-r--r--apps/files/l10n/es_AR.json24
-rw-r--r--apps/files/l10n/es_CL.js1
-rw-r--r--apps/files/l10n/es_CL.json1
-rw-r--r--apps/files/l10n/es_MX.js17
-rw-r--r--apps/files/l10n/es_MX.json17
-rw-r--r--apps/files/l10n/et_EE.js33
-rw-r--r--apps/files/l10n/et_EE.json33
-rw-r--r--apps/files/l10n/eu.js26
-rw-r--r--apps/files/l10n/eu.json26
-rw-r--r--apps/files/l10n/fa.js25
-rw-r--r--apps/files/l10n/fa.json25
-rw-r--r--apps/files/l10n/fi_FI.js40
-rw-r--r--apps/files/l10n/fi_FI.json40
-rw-r--r--apps/files/l10n/fr.js41
-rw-r--r--apps/files/l10n/fr.json41
-rw-r--r--apps/files/l10n/gl.js26
-rw-r--r--apps/files/l10n/gl.json26
-rw-r--r--apps/files/l10n/he.js66
-rw-r--r--apps/files/l10n/he.json66
-rw-r--r--apps/files/l10n/hi.js1
-rw-r--r--apps/files/l10n/hi.json1
-rw-r--r--apps/files/l10n/hr.js26
-rw-r--r--apps/files/l10n/hr.json26
-rw-r--r--apps/files/l10n/hu_HU.js41
-rw-r--r--apps/files/l10n/hu_HU.json41
-rw-r--r--apps/files/l10n/hy.js10
-rw-r--r--apps/files/l10n/hy.json10
-rw-r--r--apps/files/l10n/ia.js6
-rw-r--r--apps/files/l10n/ia.json6
-rw-r--r--apps/files/l10n/id.js28
-rw-r--r--apps/files/l10n/id.json28
-rw-r--r--apps/files/l10n/is.js11
-rw-r--r--apps/files/l10n/is.json11
-rw-r--r--apps/files/l10n/it.js39
-rw-r--r--apps/files/l10n/it.json39
-rw-r--r--apps/files/l10n/ja.js39
-rw-r--r--apps/files/l10n/ja.json39
-rw-r--r--apps/files/l10n/ka_GE.js8
-rw-r--r--apps/files/l10n/ka_GE.json8
-rw-r--r--apps/files/l10n/km.js9
-rw-r--r--apps/files/l10n/km.json9
-rw-r--r--apps/files/l10n/kn.js24
-rw-r--r--apps/files/l10n/kn.json24
-rw-r--r--apps/files/l10n/ko.js28
-rw-r--r--apps/files/l10n/ko.json28
-rw-r--r--apps/files/l10n/ku_IQ.js1
-rw-r--r--apps/files/l10n/ku_IQ.json1
-rw-r--r--apps/files/l10n/lb.js5
-rw-r--r--apps/files/l10n/lb.json5
-rw-r--r--apps/files/l10n/lo.js3
-rw-r--r--apps/files/l10n/lo.json3
-rw-r--r--apps/files/l10n/lt_LT.js41
-rw-r--r--apps/files/l10n/lt_LT.json41
-rw-r--r--apps/files/l10n/lv.js26
-rw-r--r--apps/files/l10n/lv.json26
-rw-r--r--apps/files/l10n/mk.js33
-rw-r--r--apps/files/l10n/mk.json33
-rw-r--r--apps/files/l10n/ms_MY.js4
-rw-r--r--apps/files/l10n/ms_MY.json4
-rw-r--r--apps/files/l10n/nb_NO.js41
-rw-r--r--apps/files/l10n/nb_NO.json41
-rw-r--r--apps/files/l10n/nds.js3
-rw-r--r--apps/files/l10n/nds.json3
-rw-r--r--apps/files/l10n/nl.js49
-rw-r--r--apps/files/l10n/nl.json49
-rw-r--r--apps/files/l10n/nn_NO.js10
-rw-r--r--apps/files/l10n/nn_NO.json10
-rw-r--r--apps/files/l10n/oc.js41
-rw-r--r--apps/files/l10n/oc.json41
-rw-r--r--apps/files/l10n/pa.js1
-rw-r--r--apps/files/l10n/pa.json1
-rw-r--r--apps/files/l10n/pl.js24
-rw-r--r--apps/files/l10n/pl.json24
-rw-r--r--apps/files/l10n/pt_BR.js41
-rw-r--r--apps/files/l10n/pt_BR.json41
-rw-r--r--apps/files/l10n/pt_PT.js41
-rw-r--r--apps/files/l10n/pt_PT.json41
-rw-r--r--apps/files/l10n/ro.js24
-rw-r--r--apps/files/l10n/ro.json24
-rw-r--r--apps/files/l10n/ru.js41
-rw-r--r--apps/files/l10n/ru.json41
-rw-r--r--apps/files/l10n/si_LK.js5
-rw-r--r--apps/files/l10n/si_LK.json5
-rw-r--r--apps/files/l10n/sk_SK.js28
-rw-r--r--apps/files/l10n/sk_SK.json28
-rw-r--r--apps/files/l10n/sl.js48
-rw-r--r--apps/files/l10n/sl.json48
-rw-r--r--apps/files/l10n/sq.js41
-rw-r--r--apps/files/l10n/sq.json41
-rw-r--r--apps/files/l10n/sr.js28
-rw-r--r--apps/files/l10n/sr.json28
-rw-r--r--apps/files/l10n/sr@latin.js26
-rw-r--r--apps/files/l10n/sr@latin.json26
-rw-r--r--apps/files/l10n/sv.js28
-rw-r--r--apps/files/l10n/sv.json28
-rw-r--r--apps/files/l10n/ta_LK.js6
-rw-r--r--apps/files/l10n/ta_LK.json6
-rw-r--r--apps/files/l10n/te.js1
-rw-r--r--apps/files/l10n/te.json1
-rw-r--r--apps/files/l10n/th_TH.js41
-rw-r--r--apps/files/l10n/th_TH.json41
-rw-r--r--apps/files/l10n/tr.js30
-rw-r--r--apps/files/l10n/tr.json30
-rw-r--r--apps/files/l10n/ug.js8
-rw-r--r--apps/files/l10n/ug.json8
-rw-r--r--apps/files/l10n/uk.js26
-rw-r--r--apps/files/l10n/uk.json26
-rw-r--r--apps/files/l10n/ur_PK.js2
-rw-r--r--apps/files/l10n/ur_PK.json2
-rw-r--r--apps/files/l10n/vi.js17
-rw-r--r--apps/files/l10n/vi.json17
-rw-r--r--apps/files/l10n/zh_CN.js41
-rw-r--r--apps/files/l10n/zh_CN.json41
-rw-r--r--apps/files/l10n/zh_HK.js2
-rw-r--r--apps/files/l10n/zh_HK.json2
-rw-r--r--apps/files/l10n/zh_TW.js43
-rw-r--r--apps/files/l10n/zh_TW.json43
-rw-r--r--apps/files/lib/activity.php32
-rw-r--r--apps/files/lib/activityhelper.php2
-rw-r--r--apps/files/lib/app.php92
-rw-r--r--apps/files/lib/backgroundjob/deleteorphanedtagsjob.php105
-rw-r--r--apps/files/lib/backgroundjob/scanfiles.php114
-rw-r--r--apps/files/lib/capabilities.php2
-rw-r--r--apps/files/lib/helper.php16
-rw-r--r--apps/files/list.php2
-rw-r--r--apps/files/service/tagservice.php5
-rw-r--r--apps/files/simplelist.php2
-rw-r--r--apps/files/templates/list.php23
-rw-r--r--apps/files/tests/activitytest.php44
-rw-r--r--apps/files/tests/ajax_rename.php232
-rw-r--r--apps/files/tests/backgroundjob/DeleteOrphanedTagsJobTest.php158
-rw-r--r--apps/files/tests/backgroundjob/ScanFilesTest.php133
-rw-r--r--apps/files/tests/command/deleteorphanedfilestest.php10
-rw-r--r--apps/files/tests/controller/ViewControllerTest.php5
-rw-r--r--apps/files/tests/controller/apicontrollertest.php12
-rw-r--r--apps/files/tests/helper.php2
-rw-r--r--apps/files/tests/js/favoritesfilelistspec.js3
-rw-r--r--apps/files/tests/js/fileUploadSpec.js6
-rw-r--r--apps/files/tests/js/fileactionsSpec.js2
-rw-r--r--apps/files/tests/js/fileactionsmenuSpec.js27
-rw-r--r--apps/files/tests/js/filelistSpec.js928
-rw-r--r--apps/files/tests/js/filesSpec.js6
-rw-r--r--apps/files/tests/js/filesummarySpec.js12
-rw-r--r--apps/files/tests/js/newfilemenuSpec.js73
-rw-r--r--apps/files/tests/service/tagservice.php16
-rw-r--r--apps/files_external/ajax/applicable.php4
-rw-r--r--apps/files_external/ajax/oauth1.php4
-rw-r--r--apps/files_external/ajax/oauth2.php5
-rw-r--r--apps/files_external/appinfo/app.php16
-rw-r--r--apps/files_external/appinfo/application.php27
-rw-r--r--apps/files_external/appinfo/database.xml216
-rw-r--r--apps/files_external/appinfo/info.xml5
-rw-r--r--apps/files_external/appinfo/register_command.php49
-rw-r--r--apps/files_external/appinfo/routes.php12
-rw-r--r--apps/files_external/appinfo/update.php30
-rw-r--r--apps/files_external/command/applicable.php157
-rw-r--r--apps/files_external/command/config.php120
-rw-r--r--apps/files_external/command/delete.php114
-rw-r--r--apps/files_external/command/export.php56
-rw-r--r--apps/files_external/command/import.php227
-rw-r--r--apps/files_external/command/listcommand.php248
-rw-r--r--apps/files_external/command/option.php85
-rw-r--r--apps/files_external/controller/ajaxcontroller.php14
-rw-r--r--apps/files_external/controller/globalstoragescontroller.php12
-rw-r--r--apps/files_external/controller/storagescontroller.php59
-rw-r--r--apps/files_external/controller/userglobalstoragescontroller.php200
-rw-r--r--apps/files_external/controller/userstoragescontroller.php42
-rw-r--r--apps/files_external/css/external.css8
-rw-r--r--apps/files_external/css/settings.css8
-rw-r--r--apps/files_external/js/app.js39
-rw-r--r--apps/files_external/js/oauth1.js66
-rw-r--r--apps/files_external/js/oauth2.js94
-rw-r--r--apps/files_external/js/public_key.js14
-rw-r--r--apps/files_external/js/rollingqueue.js137
-rw-r--r--apps/files_external/js/settings.js438
-rw-r--r--apps/files_external/js/statusmanager.js610
-rw-r--r--apps/files_external/l10n/ast.js2
-rw-r--r--apps/files_external/l10n/ast.json2
-rw-r--r--apps/files_external/l10n/az.js2
-rw-r--r--apps/files_external/l10n/az.json2
-rw-r--r--apps/files_external/l10n/bg_BG.js2
-rw-r--r--apps/files_external/l10n/bg_BG.json2
-rw-r--r--apps/files_external/l10n/ca.js3
-rw-r--r--apps/files_external/l10n/ca.json3
-rw-r--r--apps/files_external/l10n/cs_CZ.js19
-rw-r--r--apps/files_external/l10n/cs_CZ.json19
-rw-r--r--apps/files_external/l10n/da.js4
-rw-r--r--apps/files_external/l10n/da.json4
-rw-r--r--apps/files_external/l10n/de.js13
-rw-r--r--apps/files_external/l10n/de.json13
-rw-r--r--apps/files_external/l10n/de_DE.js16
-rw-r--r--apps/files_external/l10n/de_DE.json16
-rw-r--r--apps/files_external/l10n/el.js5
-rw-r--r--apps/files_external/l10n/el.json5
-rw-r--r--apps/files_external/l10n/en_GB.js3
-rw-r--r--apps/files_external/l10n/en_GB.json3
-rw-r--r--apps/files_external/l10n/eo.js2
-rw-r--r--apps/files_external/l10n/eo.json2
-rw-r--r--apps/files_external/l10n/es.js33
-rw-r--r--apps/files_external/l10n/es.json33
-rw-r--r--apps/files_external/l10n/es_AR.js4
-rw-r--r--apps/files_external/l10n/es_AR.json4
-rw-r--r--apps/files_external/l10n/es_MX.js4
-rw-r--r--apps/files_external/l10n/es_MX.json4
-rw-r--r--apps/files_external/l10n/et_EE.js15
-rw-r--r--apps/files_external/l10n/et_EE.json15
-rw-r--r--apps/files_external/l10n/eu.js2
-rw-r--r--apps/files_external/l10n/eu.json2
-rw-r--r--apps/files_external/l10n/fa.js4
-rw-r--r--apps/files_external/l10n/fa.json4
-rw-r--r--apps/files_external/l10n/fi_FI.js17
-rw-r--r--apps/files_external/l10n/fi_FI.json17
-rw-r--r--apps/files_external/l10n/fr.js15
-rw-r--r--apps/files_external/l10n/fr.json15
-rw-r--r--apps/files_external/l10n/gl.js3
-rw-r--r--apps/files_external/l10n/gl.json3
-rw-r--r--apps/files_external/l10n/he.js101
-rw-r--r--apps/files_external/l10n/he.json101
-rw-r--r--apps/files_external/l10n/hr.js2
-rw-r--r--apps/files_external/l10n/hr.json2
-rw-r--r--apps/files_external/l10n/hu_HU.js42
-rw-r--r--apps/files_external/l10n/hu_HU.json42
-rw-r--r--apps/files_external/l10n/hy.js3
-rw-r--r--apps/files_external/l10n/hy.json3
-rw-r--r--apps/files_external/l10n/id.js4
-rw-r--r--apps/files_external/l10n/id.json4
-rw-r--r--apps/files_external/l10n/it.js19
-rw-r--r--apps/files_external/l10n/it.json19
-rw-r--r--apps/files_external/l10n/ja.js17
-rw-r--r--apps/files_external/l10n/ja.json17
-rw-r--r--apps/files_external/l10n/ka_GE.js4
-rw-r--r--apps/files_external/l10n/ka_GE.json4
-rw-r--r--apps/files_external/l10n/km.js4
-rw-r--r--apps/files_external/l10n/km.json4
-rw-r--r--apps/files_external/l10n/ko.js4
-rw-r--r--apps/files_external/l10n/ko.json4
-rw-r--r--apps/files_external/l10n/lt_LT.js7
-rw-r--r--apps/files_external/l10n/lt_LT.json7
-rw-r--r--apps/files_external/l10n/lv.js4
-rw-r--r--apps/files_external/l10n/lv.json4
-rw-r--r--apps/files_external/l10n/nb_NO.js16
-rw-r--r--apps/files_external/l10n/nb_NO.json16
-rw-r--r--apps/files_external/l10n/nds.js4
-rw-r--r--apps/files_external/l10n/nds.json4
-rw-r--r--apps/files_external/l10n/nl.js15
-rw-r--r--apps/files_external/l10n/nl.json15
-rw-r--r--apps/files_external/l10n/oc.js4
-rw-r--r--apps/files_external/l10n/oc.json4
-rw-r--r--apps/files_external/l10n/pl.js3
-rw-r--r--apps/files_external/l10n/pl.json3
-rw-r--r--apps/files_external/l10n/pt_BR.js19
-rw-r--r--apps/files_external/l10n/pt_BR.json19
-rw-r--r--apps/files_external/l10n/pt_PT.js27
-rw-r--r--apps/files_external/l10n/pt_PT.json27
-rw-r--r--apps/files_external/l10n/ro.js2
-rw-r--r--apps/files_external/l10n/ro.json2
-rw-r--r--apps/files_external/l10n/ru.js21
-rw-r--r--apps/files_external/l10n/ru.json21
-rw-r--r--apps/files_external/l10n/sk_SK.js4
-rw-r--r--apps/files_external/l10n/sk_SK.json4
-rw-r--r--apps/files_external/l10n/sl.js27
-rw-r--r--apps/files_external/l10n/sl.json27
-rw-r--r--apps/files_external/l10n/sq.js20
-rw-r--r--apps/files_external/l10n/sq.json20
-rw-r--r--apps/files_external/l10n/sr.js3
-rw-r--r--apps/files_external/l10n/sr.json3
-rw-r--r--apps/files_external/l10n/sr@latin.js2
-rw-r--r--apps/files_external/l10n/sr@latin.json2
-rw-r--r--apps/files_external/l10n/sv.js2
-rw-r--r--apps/files_external/l10n/sv.json2
-rw-r--r--apps/files_external/l10n/th_TH.js19
-rw-r--r--apps/files_external/l10n/th_TH.json19
-rw-r--r--apps/files_external/l10n/tr.js6
-rw-r--r--apps/files_external/l10n/tr.json6
-rw-r--r--apps/files_external/l10n/uk.js2
-rw-r--r--apps/files_external/l10n/uk.json2
-rw-r--r--apps/files_external/l10n/vi.js4
-rw-r--r--apps/files_external/l10n/vi.json4
-rw-r--r--apps/files_external/l10n/zh_CN.js2
-rw-r--r--apps/files_external/l10n/zh_CN.json2
-rw-r--r--apps/files_external/l10n/zh_TW.js8
-rw-r--r--apps/files_external/l10n/zh_TW.json8
-rw-r--r--apps/files_external/lib/amazons3.php4
-rw-r--r--apps/files_external/lib/api.php11
-rw-r--r--apps/files_external/lib/auth/amazons3/accesskey.php4
-rw-r--r--apps/files_external/lib/auth/authmechanism.php5
-rw-r--r--apps/files_external/lib/auth/builtin.php4
-rw-r--r--apps/files_external/lib/auth/iuserprovided.php36
-rw-r--r--apps/files_external/lib/auth/nullmechanism.php4
-rw-r--r--apps/files_external/lib/auth/oauth1/oauth1.php4
-rw-r--r--apps/files_external/lib/auth/oauth2/oauth2.php4
-rw-r--r--apps/files_external/lib/auth/openstack/openstack.php4
-rw-r--r--apps/files_external/lib/auth/openstack/rackspace.php4
-rw-r--r--apps/files_external/lib/auth/password/globalauth.php88
-rw-r--r--apps/files_external/lib/auth/password/logincredentials.php92
-rw-r--r--apps/files_external/lib/auth/password/password.php4
-rw-r--r--apps/files_external/lib/auth/password/sessioncredentials.php9
-rw-r--r--apps/files_external/lib/auth/password/userprovided.php88
-rw-r--r--apps/files_external/lib/auth/publickey/rsa.php7
-rw-r--r--apps/files_external/lib/backend/amazons3.php4
-rw-r--r--apps/files_external/lib/backend/backend.php4
-rw-r--r--apps/files_external/lib/backend/dav.php4
-rw-r--r--apps/files_external/lib/backend/dropbox.php4
-rw-r--r--apps/files_external/lib/backend/ftp.php4
-rw-r--r--apps/files_external/lib/backend/google.php4
-rw-r--r--apps/files_external/lib/backend/legacybackend.php4
-rw-r--r--apps/files_external/lib/backend/local.php4
-rw-r--r--apps/files_external/lib/backend/owncloud.php4
-rw-r--r--apps/files_external/lib/backend/sftp.php4
-rw-r--r--apps/files_external/lib/backend/sftp_key.php4
-rw-r--r--apps/files_external/lib/backend/smb.php8
-rw-r--r--apps/files_external/lib/backend/smb_oc.php7
-rw-r--r--apps/files_external/lib/backend/swift.php4
-rw-r--r--apps/files_external/lib/config.php120
-rw-r--r--apps/files_external/lib/config/configadapter.php33
-rw-r--r--apps/files_external/lib/definitionparameter.php70
-rw-r--r--apps/files_external/lib/dependencytrait.php4
-rw-r--r--apps/files_external/lib/dropbox.php4
-rw-r--r--apps/files_external/lib/etagpropagator.php141
-rw-r--r--apps/files_external/lib/failedcache.php131
-rw-r--r--apps/files_external/lib/failedstorage.php9
-rw-r--r--apps/files_external/lib/frontenddefinitiontrait.php12
-rw-r--r--apps/files_external/lib/ftp.php4
-rw-r--r--apps/files_external/lib/google.php26
-rw-r--r--apps/files_external/lib/identifiertrait.php4
-rw-r--r--apps/files_external/lib/insufficientdataformeaningfulanswerexception.php15
-rw-r--r--apps/files_external/lib/legacydependencycheckpolyfill.php4
-rw-r--r--apps/files_external/lib/missingdependency.php4
-rw-r--r--apps/files_external/lib/notfoundexception.php2
-rw-r--r--apps/files_external/lib/owncloud.php4
-rw-r--r--apps/files_external/lib/personalmount.php15
-rw-r--r--apps/files_external/lib/prioritytrait.php4
-rw-r--r--apps/files_external/lib/sessionstoragewrapper.php4
-rw-r--r--apps/files_external/lib/sftp.php10
-rw-r--r--apps/files_external/lib/smb.php40
-rw-r--r--apps/files_external/lib/storageconfig.php55
-rw-r--r--apps/files_external/lib/storagemodifiertrait.php8
-rw-r--r--apps/files_external/lib/streamwrapper.php2
-rw-r--r--apps/files_external/lib/swift.php66
-rw-r--r--apps/files_external/lib/visibilitytrait.php4
-rw-r--r--apps/files_external/list.php8
-rw-r--r--apps/files_external/migration/dummyusersession.php51
-rw-r--r--apps/files_external/migration/storagemigrator.php140
-rw-r--r--apps/files_external/personal.php35
-rw-r--r--apps/files_external/service/backendservice.php5
-rw-r--r--apps/files_external/service/dbconfigservice.php410
-rw-r--r--apps/files_external/service/globallegacystoragesservice.php44
-rw-r--r--apps/files_external/service/globalstoragesservice.php71
-rw-r--r--apps/files_external/service/importlegacystoragesservice.php46
-rw-r--r--apps/files_external/service/legacystoragesservice.php209
-rw-r--r--apps/files_external/service/storagesservice.php507
-rw-r--r--apps/files_external/service/userglobalstoragesservice.php85
-rw-r--r--apps/files_external/service/userlegacystoragesservice.php54
-rw-r--r--apps/files_external/service/userstoragesservice.php135
-rw-r--r--apps/files_external/service/usertrait.php4
-rw-r--r--apps/files_external/settings.php41
-rw-r--r--apps/files_external/templates/settings.php118
-rw-r--r--apps/files_external/tests/amazons3migration.php16
-rw-r--r--apps/files_external/tests/auth/authmechanismtest.php4
-rw-r--r--apps/files_external/tests/backend/backendtest.php4
-rw-r--r--apps/files_external/tests/backend/legacybackendtest.php4
-rw-r--r--apps/files_external/tests/backends/amazons3.php12
-rw-r--r--apps/files_external/tests/backends/dropbox.php10
-rw-r--r--apps/files_external/tests/backends/ftp.php9
-rw-r--r--apps/files_external/tests/backends/google.php10
-rw-r--r--apps/files_external/tests/backends/owncloud.php10
-rw-r--r--apps/files_external/tests/backends/sftp.php10
-rw-r--r--apps/files_external/tests/backends/sftp_key.php10
-rw-r--r--apps/files_external/tests/backends/smb.php10
-rw-r--r--apps/files_external/tests/backends/swift.php43
-rw-r--r--apps/files_external/tests/backends/webdav.php10
-rw-r--r--apps/files_external/tests/command/applicabletest.php168
-rw-r--r--apps/files_external/tests/command/commandtest.php104
-rw-r--r--apps/files_external/tests/config.php2
-rw-r--r--apps/files_external/tests/controller/globalstoragescontrollertest.php7
-rw-r--r--apps/files_external/tests/controller/storagescontrollertest.php11
-rw-r--r--apps/files_external/tests/controller/userstoragescontrollertest.php8
-rw-r--r--apps/files_external/tests/definitionparameterttest.php28
-rwxr-xr-xapps/files_external/tests/env/entrypoint.sh274
-rwxr-xr-xapps/files_external/tests/env/start-amazons3-ceph.sh9
-rwxr-xr-xapps/files_external/tests/env/start-ftp-morrisjobke.sh10
-rwxr-xr-xapps/files_external/tests/env/start-sftp-atmoz.sh11
-rwxr-xr-xapps/files_external/tests/env/start-smb-silvershell.sh10
-rwxr-xr-xapps/files_external/tests/env/start-smb-windows.sh5
-rwxr-xr-xapps/files_external/tests/env/start-swift-ceph.sh90
-rwxr-xr-xapps/files_external/tests/env/start-webdav-ownCloud.sh15
-rwxr-xr-xapps/files_external/tests/env/stop-swift-ceph.sh36
-rwxr-xr-xapps/files_external/tests/env/wait-for-connection45
-rw-r--r--apps/files_external/tests/etagpropagator.php343
-rw-r--r--apps/files_external/tests/frontenddefinitiontraittest.php6
-rw-r--r--apps/files_external/tests/js/settingsSpec.js125
-rw-r--r--apps/files_external/tests/legacydependencycheckpolyfilltest.php4
-rw-r--r--apps/files_external/tests/owncloudfunctions.php12
-rw-r--r--apps/files_external/tests/personalmounttest.php50
-rw-r--r--apps/files_external/tests/service/backendservicetest.php10
-rw-r--r--apps/files_external/tests/service/dbconfigservicetest.php273
-rw-r--r--apps/files_external/tests/service/globalstoragesservicetest.php349
-rw-r--r--apps/files_external/tests/service/storagesservicetest.php94
-rw-r--r--apps/files_external/tests/service/userglobalstoragesservicetest.php72
-rw-r--r--apps/files_external/tests/service/userstoragesservicetest.php143
-rw-r--r--apps/files_external/tests/storageconfigtest.php4
-rw-r--r--apps/files_sharing/ajax/external.php13
-rw-r--r--apps/files_sharing/ajax/list.php96
-rw-r--r--apps/files_sharing/ajax/publicpreview.php2
-rw-r--r--apps/files_sharing/ajax/shareinfo.php2
-rw-r--r--apps/files_sharing/api/local.php10
-rw-r--r--apps/files_sharing/api/ocssharewrapper.php38
-rw-r--r--apps/files_sharing/api/remote.php5
-rw-r--r--apps/files_sharing/api/server2server.php2
-rw-r--r--apps/files_sharing/api/share20ocs.php545
-rw-r--r--apps/files_sharing/api/sharees.php38
-rw-r--r--apps/files_sharing/appinfo/app.php8
-rw-r--r--apps/files_sharing/appinfo/application.php56
-rw-r--r--apps/files_sharing/appinfo/info.xml5
-rw-r--r--apps/files_sharing/appinfo/install.php2
-rw-r--r--apps/files_sharing/appinfo/routes.php2
-rw-r--r--apps/files_sharing/appinfo/update.php11
-rw-r--r--apps/files_sharing/css/sharetabview.css2
-rw-r--r--apps/files_sharing/js/app.js2
-rw-r--r--apps/files_sharing/js/external.js3
-rw-r--r--apps/files_sharing/js/public.js50
-rw-r--r--apps/files_sharing/js/share.js25
-rw-r--r--apps/files_sharing/js/sharedfilelist.js4
-rw-r--r--apps/files_sharing/l10n/cs_CZ.js1
-rw-r--r--apps/files_sharing/l10n/cs_CZ.json1
-rw-r--r--apps/files_sharing/l10n/de.js2
-rw-r--r--apps/files_sharing/l10n/de.json2
-rw-r--r--apps/files_sharing/l10n/de_DE.js12
-rw-r--r--apps/files_sharing/l10n/de_DE.json12
-rw-r--r--apps/files_sharing/l10n/es.js2
-rw-r--r--apps/files_sharing/l10n/es.json2
-rw-r--r--apps/files_sharing/l10n/es_AR.js1
-rw-r--r--apps/files_sharing/l10n/es_AR.json1
-rw-r--r--apps/files_sharing/l10n/et_EE.js2
-rw-r--r--apps/files_sharing/l10n/et_EE.json2
-rw-r--r--apps/files_sharing/l10n/fi_FI.js1
-rw-r--r--apps/files_sharing/l10n/fi_FI.json1
-rw-r--r--apps/files_sharing/l10n/fr.js1
-rw-r--r--apps/files_sharing/l10n/fr.json1
-rw-r--r--apps/files_sharing/l10n/he.js73
-rw-r--r--apps/files_sharing/l10n/he.json73
-rw-r--r--apps/files_sharing/l10n/hu_HU.js1
-rw-r--r--apps/files_sharing/l10n/hu_HU.json1
-rw-r--r--apps/files_sharing/l10n/it.js1
-rw-r--r--apps/files_sharing/l10n/it.json1
-rw-r--r--apps/files_sharing/l10n/ja.js7
-rw-r--r--apps/files_sharing/l10n/ja.json7
-rw-r--r--apps/files_sharing/l10n/lt_LT.js1
-rw-r--r--apps/files_sharing/l10n/lt_LT.json1
-rw-r--r--apps/files_sharing/l10n/mk.js35
-rw-r--r--apps/files_sharing/l10n/mk.json35
-rw-r--r--apps/files_sharing/l10n/nb_NO.js1
-rw-r--r--apps/files_sharing/l10n/nb_NO.json1
-rw-r--r--apps/files_sharing/l10n/nl.js1
-rw-r--r--apps/files_sharing/l10n/nl.json1
-rw-r--r--apps/files_sharing/l10n/pt_BR.js17
-rw-r--r--apps/files_sharing/l10n/pt_BR.json17
-rw-r--r--apps/files_sharing/l10n/pt_PT.js1
-rw-r--r--apps/files_sharing/l10n/pt_PT.json1
-rw-r--r--apps/files_sharing/l10n/ru.js1
-rw-r--r--apps/files_sharing/l10n/ru.json1
-rw-r--r--apps/files_sharing/l10n/sl.js3
-rw-r--r--apps/files_sharing/l10n/sl.json3
-rw-r--r--apps/files_sharing/l10n/sq.js6
-rw-r--r--apps/files_sharing/l10n/sq.json6
-rw-r--r--apps/files_sharing/l10n/th_TH.js1
-rw-r--r--apps/files_sharing/l10n/th_TH.json1
-rw-r--r--apps/files_sharing/l10n/zh_TW.js21
-rw-r--r--apps/files_sharing/l10n/zh_TW.json21
-rw-r--r--apps/files_sharing/lib/activity.php2
-rw-r--r--apps/files_sharing/lib/cache.php495
-rw-r--r--apps/files_sharing/lib/capabilities.php2
-rw-r--r--apps/files_sharing/lib/controllers/externalsharescontroller.php6
-rw-r--r--apps/files_sharing/lib/controllers/sharecontroller.php308
-rw-r--r--apps/files_sharing/lib/deleteorphanedsharesjob.php2
-rw-r--r--apps/files_sharing/lib/exceptions/brokenpath.php2
-rw-r--r--apps/files_sharing/lib/exceptions/s2sexception.php2
-rw-r--r--apps/files_sharing/lib/expiresharesjob.php2
-rw-r--r--apps/files_sharing/lib/external/cache.php2
-rw-r--r--apps/files_sharing/lib/external/manager.php6
-rw-r--r--apps/files_sharing/lib/external/mount.php2
-rw-r--r--apps/files_sharing/lib/external/mountprovider.php2
-rw-r--r--apps/files_sharing/lib/external/scanner.php2
-rw-r--r--apps/files_sharing/lib/external/storage.php17
-rw-r--r--apps/files_sharing/lib/helper.php28
-rw-r--r--apps/files_sharing/lib/hooks.php2
-rw-r--r--apps/files_sharing/lib/isharedstorage.php2
-rw-r--r--apps/files_sharing/lib/maintainer.php4
-rw-r--r--apps/files_sharing/lib/middleware/sharingcheckmiddleware.php3
-rw-r--r--apps/files_sharing/lib/migration.php245
-rw-r--r--apps/files_sharing/lib/mountprovider.php18
-rw-r--r--apps/files_sharing/lib/notifier.php6
-rw-r--r--apps/files_sharing/lib/propagation/changewatcher.php110
-rw-r--r--apps/files_sharing/lib/propagation/grouppropagationmanager.php133
-rw-r--r--apps/files_sharing/lib/propagation/propagationmanager.php144
-rw-r--r--apps/files_sharing/lib/propagation/recipientpropagator.php164
-rw-r--r--apps/files_sharing/lib/scanner.php31
-rw-r--r--apps/files_sharing/lib/share/file.php2
-rw-r--r--apps/files_sharing/lib/share/folder.php4
-rw-r--r--apps/files_sharing/lib/sharedmount.php34
-rw-r--r--apps/files_sharing/lib/sharedpropagator.php44
-rw-r--r--apps/files_sharing/lib/sharedstorage.php70
-rw-r--r--apps/files_sharing/lib/updater.php43
-rw-r--r--apps/files_sharing/lib/watcher.php80
-rw-r--r--apps/files_sharing/list.php2
-rw-r--r--apps/files_sharing/public.php2
-rw-r--r--apps/files_sharing/settings-admin.php2
-rw-r--r--apps/files_sharing/settings-personal.php7
-rw-r--r--apps/files_sharing/templates/public.php10
-rw-r--r--apps/files_sharing/tests/activity.php22
-rw-r--r--apps/files_sharing/tests/api.php6
-rw-r--r--apps/files_sharing/tests/api/share20ocstest.php1295
-rw-r--r--apps/files_sharing/tests/api/shareestest.php52
-rw-r--r--apps/files_sharing/tests/backend.php10
-rw-r--r--apps/files_sharing/tests/cache.php8
-rw-r--r--apps/files_sharing/tests/capabilities.php5
-rw-r--r--apps/files_sharing/tests/controller/externalsharecontroller.php2
-rw-r--r--apps/files_sharing/tests/controller/sharecontroller.php373
-rw-r--r--apps/files_sharing/tests/deleteorphanedsharesjobtest.php10
-rw-r--r--apps/files_sharing/tests/etagpropagation.php93
-rw-r--r--apps/files_sharing/tests/expiresharesjobtest.php10
-rw-r--r--apps/files_sharing/tests/external/cache.php26
-rw-r--r--apps/files_sharing/tests/external/managertest.php10
-rw-r--r--apps/files_sharing/tests/external/scannertest.php2
-rw-r--r--apps/files_sharing/tests/externalstorage.php5
-rw-r--r--apps/files_sharing/tests/groupetagpropagation.php104
-rw-r--r--apps/files_sharing/tests/grouppropagationmanager.php173
-rw-r--r--apps/files_sharing/tests/helper.php23
-rw-r--r--apps/files_sharing/tests/js/externalSpec.js4
-rw-r--r--apps/files_sharing/tests/js/publicAppSpec.js27
-rw-r--r--apps/files_sharing/tests/js/sharedfilelistSpec.js28
-rw-r--r--apps/files_sharing/tests/locking.php11
-rw-r--r--apps/files_sharing/tests/middleware/sharingcheckmiddleware.php2
-rw-r--r--apps/files_sharing/tests/migrationtest.php296
-rw-r--r--apps/files_sharing/tests/permissions.php8
-rw-r--r--apps/files_sharing/tests/propagationtestcase.php103
-rw-r--r--apps/files_sharing/tests/server2server.php5
-rw-r--r--apps/files_sharing/tests/share.php10
-rw-r--r--apps/files_sharing/tests/sharedmount.php224
-rw-r--r--apps/files_sharing/tests/sharedstorage.php4
-rw-r--r--apps/files_sharing/tests/sizepropagation.php10
-rw-r--r--apps/files_sharing/tests/testcase.php29
-rw-r--r--apps/files_sharing/tests/unsharechildren.php10
-rw-r--r--apps/files_sharing/tests/updater.php11
-rw-r--r--apps/files_sharing/tests/watcher.php19
-rw-r--r--apps/files_trashbin/ajax/delete.php2
-rw-r--r--apps/files_trashbin/ajax/isEmpty.php2
-rw-r--r--apps/files_trashbin/ajax/list.php2
-rw-r--r--apps/files_trashbin/ajax/preview.php5
-rw-r--r--apps/files_trashbin/ajax/undelete.php2
-rw-r--r--apps/files_trashbin/appinfo/app.php2
-rw-r--r--apps/files_trashbin/appinfo/application.php2
-rw-r--r--apps/files_trashbin/appinfo/info.xml3
-rw-r--r--apps/files_trashbin/appinfo/install.php2
-rw-r--r--apps/files_trashbin/appinfo/register_command.php2
-rw-r--r--apps/files_trashbin/appinfo/routes.php2
-rw-r--r--apps/files_trashbin/appinfo/update.php10
-rw-r--r--apps/files_trashbin/command/cleanup.php2
-rw-r--r--apps/files_trashbin/command/expire.php14
-rw-r--r--apps/files_trashbin/js/app.js5
-rw-r--r--apps/files_trashbin/js/filelist.js72
-rw-r--r--apps/files_trashbin/l10n/ar.js1
-rw-r--r--apps/files_trashbin/l10n/ar.json1
-rw-r--r--apps/files_trashbin/l10n/ast.js2
-rw-r--r--apps/files_trashbin/l10n/ast.json2
-rw-r--r--apps/files_trashbin/l10n/az.js6
-rw-r--r--apps/files_trashbin/l10n/az.json6
-rw-r--r--apps/files_trashbin/l10n/bg_BG.js4
-rw-r--r--apps/files_trashbin/l10n/bg_BG.json4
-rw-r--r--apps/files_trashbin/l10n/bn_BD.js4
-rw-r--r--apps/files_trashbin/l10n/bn_BD.json4
-rw-r--r--apps/files_trashbin/l10n/bn_IN.js4
-rw-r--r--apps/files_trashbin/l10n/bn_IN.json4
-rw-r--r--apps/files_trashbin/l10n/bs.js4
-rw-r--r--apps/files_trashbin/l10n/bs.json4
-rw-r--r--apps/files_trashbin/l10n/ca.js4
-rw-r--r--apps/files_trashbin/l10n/ca.json4
-rw-r--r--apps/files_trashbin/l10n/cs_CZ.js6
-rw-r--r--apps/files_trashbin/l10n/cs_CZ.json6
-rw-r--r--apps/files_trashbin/l10n/cy_GB.js4
-rw-r--r--apps/files_trashbin/l10n/cy_GB.json4
-rw-r--r--apps/files_trashbin/l10n/da.js6
-rw-r--r--apps/files_trashbin/l10n/da.json6
-rw-r--r--apps/files_trashbin/l10n/de.js6
-rw-r--r--apps/files_trashbin/l10n/de.json6
-rw-r--r--apps/files_trashbin/l10n/de_AT.js4
-rw-r--r--apps/files_trashbin/l10n/de_AT.json4
-rw-r--r--apps/files_trashbin/l10n/de_DE.js6
-rw-r--r--apps/files_trashbin/l10n/de_DE.json6
-rw-r--r--apps/files_trashbin/l10n/el.js6
-rw-r--r--apps/files_trashbin/l10n/el.json6
-rw-r--r--apps/files_trashbin/l10n/en_GB.js4
-rw-r--r--apps/files_trashbin/l10n/en_GB.json4
-rw-r--r--apps/files_trashbin/l10n/eo.js4
-rw-r--r--apps/files_trashbin/l10n/eo.json4
-rw-r--r--apps/files_trashbin/l10n/es.js6
-rw-r--r--apps/files_trashbin/l10n/es.json6
-rw-r--r--apps/files_trashbin/l10n/es_AR.js4
-rw-r--r--apps/files_trashbin/l10n/es_AR.json4
-rw-r--r--apps/files_trashbin/l10n/es_MX.js4
-rw-r--r--apps/files_trashbin/l10n/es_MX.json4
-rw-r--r--apps/files_trashbin/l10n/et_EE.js6
-rw-r--r--apps/files_trashbin/l10n/et_EE.json6
-rw-r--r--apps/files_trashbin/l10n/eu.js4
-rw-r--r--apps/files_trashbin/l10n/eu.json4
-rw-r--r--apps/files_trashbin/l10n/fa.js2
-rw-r--r--apps/files_trashbin/l10n/fa.json2
-rw-r--r--apps/files_trashbin/l10n/fi_FI.js6
-rw-r--r--apps/files_trashbin/l10n/fi_FI.json6
-rw-r--r--apps/files_trashbin/l10n/fr.js6
-rw-r--r--apps/files_trashbin/l10n/fr.json6
-rw-r--r--apps/files_trashbin/l10n/gl.js6
-rw-r--r--apps/files_trashbin/l10n/gl.json6
-rw-r--r--apps/files_trashbin/l10n/he.js10
-rw-r--r--apps/files_trashbin/l10n/he.json10
-rw-r--r--apps/files_trashbin/l10n/hr.js4
-rw-r--r--apps/files_trashbin/l10n/hr.json4
-rw-r--r--apps/files_trashbin/l10n/hu_HU.js6
-rw-r--r--apps/files_trashbin/l10n/hu_HU.json6
-rw-r--r--apps/files_trashbin/l10n/hy.js4
-rw-r--r--apps/files_trashbin/l10n/hy.json4
-rw-r--r--apps/files_trashbin/l10n/ia.js4
-rw-r--r--apps/files_trashbin/l10n/ia.json4
-rw-r--r--apps/files_trashbin/l10n/id.js6
-rw-r--r--apps/files_trashbin/l10n/id.json6
-rw-r--r--apps/files_trashbin/l10n/is.js4
-rw-r--r--apps/files_trashbin/l10n/is.json4
-rw-r--r--apps/files_trashbin/l10n/it.js6
-rw-r--r--apps/files_trashbin/l10n/it.json6
-rw-r--r--apps/files_trashbin/l10n/ja.js6
-rw-r--r--apps/files_trashbin/l10n/ja.json6
-rw-r--r--apps/files_trashbin/l10n/ka_GE.js4
-rw-r--r--apps/files_trashbin/l10n/ka_GE.json4
-rw-r--r--apps/files_trashbin/l10n/km.js4
-rw-r--r--apps/files_trashbin/l10n/km.json4
-rw-r--r--apps/files_trashbin/l10n/kn.js4
-rw-r--r--apps/files_trashbin/l10n/kn.json4
-rw-r--r--apps/files_trashbin/l10n/ko.js6
-rw-r--r--apps/files_trashbin/l10n/ko.json6
-rw-r--r--apps/files_trashbin/l10n/lb.js4
-rw-r--r--apps/files_trashbin/l10n/lb.json4
-rw-r--r--apps/files_trashbin/l10n/lt_LT.js6
-rw-r--r--apps/files_trashbin/l10n/lt_LT.json6
-rw-r--r--apps/files_trashbin/l10n/lv.js4
-rw-r--r--apps/files_trashbin/l10n/lv.json4
-rw-r--r--apps/files_trashbin/l10n/mk.js7
-rw-r--r--apps/files_trashbin/l10n/mk.json7
-rw-r--r--apps/files_trashbin/l10n/ms_MY.js4
-rw-r--r--apps/files_trashbin/l10n/ms_MY.json4
-rw-r--r--apps/files_trashbin/l10n/nb_NO.js6
-rw-r--r--apps/files_trashbin/l10n/nb_NO.json6
-rw-r--r--apps/files_trashbin/l10n/nds.js1
-rw-r--r--apps/files_trashbin/l10n/nds.json1
-rw-r--r--apps/files_trashbin/l10n/nl.js6
-rw-r--r--apps/files_trashbin/l10n/nl.json6
-rw-r--r--apps/files_trashbin/l10n/nn_NO.js4
-rw-r--r--apps/files_trashbin/l10n/nn_NO.json4
-rw-r--r--apps/files_trashbin/l10n/oc.js2
-rw-r--r--apps/files_trashbin/l10n/oc.json2
-rw-r--r--apps/files_trashbin/l10n/pa.js4
-rw-r--r--apps/files_trashbin/l10n/pa.json4
-rw-r--r--apps/files_trashbin/l10n/pl.js4
-rw-r--r--apps/files_trashbin/l10n/pl.json4
-rw-r--r--apps/files_trashbin/l10n/pt_BR.js10
-rw-r--r--apps/files_trashbin/l10n/pt_BR.json10
-rw-r--r--apps/files_trashbin/l10n/pt_PT.js6
-rw-r--r--apps/files_trashbin/l10n/pt_PT.json6
-rw-r--r--apps/files_trashbin/l10n/ro.js4
-rw-r--r--apps/files_trashbin/l10n/ro.json4
-rw-r--r--apps/files_trashbin/l10n/ru.js6
-rw-r--r--apps/files_trashbin/l10n/ru.json6
-rw-r--r--apps/files_trashbin/l10n/si_LK.js4
-rw-r--r--apps/files_trashbin/l10n/si_LK.json4
-rw-r--r--apps/files_trashbin/l10n/sk_SK.js6
-rw-r--r--apps/files_trashbin/l10n/sk_SK.json6
-rw-r--r--apps/files_trashbin/l10n/sl.js6
-rw-r--r--apps/files_trashbin/l10n/sl.json6
-rw-r--r--apps/files_trashbin/l10n/sq.js2
-rw-r--r--apps/files_trashbin/l10n/sq.json2
-rw-r--r--apps/files_trashbin/l10n/sr.js6
-rw-r--r--apps/files_trashbin/l10n/sr.json6
-rw-r--r--apps/files_trashbin/l10n/sr@latin.js4
-rw-r--r--apps/files_trashbin/l10n/sr@latin.json4
-rw-r--r--apps/files_trashbin/l10n/sv.js2
-rw-r--r--apps/files_trashbin/l10n/sv.json2
-rw-r--r--apps/files_trashbin/l10n/ta_LK.js4
-rw-r--r--apps/files_trashbin/l10n/ta_LK.json4
-rw-r--r--apps/files_trashbin/l10n/te.js4
-rw-r--r--apps/files_trashbin/l10n/te.json4
-rw-r--r--apps/files_trashbin/l10n/th_TH.js6
-rw-r--r--apps/files_trashbin/l10n/th_TH.json6
-rw-r--r--apps/files_trashbin/l10n/tr.js6
-rw-r--r--apps/files_trashbin/l10n/tr.json6
-rw-r--r--apps/files_trashbin/l10n/ug.js4
-rw-r--r--apps/files_trashbin/l10n/ug.json4
-rw-r--r--apps/files_trashbin/l10n/uk.js5
-rw-r--r--apps/files_trashbin/l10n/uk.json5
-rw-r--r--apps/files_trashbin/l10n/ur_PK.js4
-rw-r--r--apps/files_trashbin/l10n/ur_PK.json4
-rw-r--r--apps/files_trashbin/l10n/vi.js4
-rw-r--r--apps/files_trashbin/l10n/vi.json4
-rw-r--r--apps/files_trashbin/l10n/zh_CN.js6
-rw-r--r--apps/files_trashbin/l10n/zh_CN.json6
-rw-r--r--apps/files_trashbin/l10n/zh_HK.js4
-rw-r--r--apps/files_trashbin/l10n/zh_HK.json4
-rw-r--r--apps/files_trashbin/l10n/zh_TW.js2
-rw-r--r--apps/files_trashbin/l10n/zh_TW.json2
-rw-r--r--apps/files_trashbin/lib/backgroundjob/expiretrash.php2
-rw-r--r--apps/files_trashbin/lib/capabilities.php2
-rw-r--r--apps/files_trashbin/lib/exceptions/copyrecursiveexception.php2
-rw-r--r--apps/files_trashbin/lib/expiration.php2
-rw-r--r--apps/files_trashbin/lib/helper.php11
-rw-r--r--apps/files_trashbin/lib/hooks.php4
-rw-r--r--apps/files_trashbin/lib/storage.php7
-rw-r--r--apps/files_trashbin/lib/trashbin.php89
-rw-r--r--apps/files_trashbin/list.php2
-rw-r--r--apps/files_trashbin/templates/index.php4
-rw-r--r--apps/files_trashbin/tests/backgroundjob/expiretrash.php2
-rw-r--r--apps/files_trashbin/tests/command/cleanuptest.php10
-rw-r--r--apps/files_trashbin/tests/command/expiretest.php13
-rw-r--r--apps/files_trashbin/tests/expiration.php2
-rw-r--r--apps/files_trashbin/tests/storage.php27
-rw-r--r--apps/files_trashbin/tests/trashbin.php40
-rw-r--r--apps/files_versions/ajax/getVersions.php2
-rw-r--r--apps/files_versions/ajax/preview.php5
-rw-r--r--apps/files_versions/ajax/rollbackVersion.php2
-rw-r--r--apps/files_versions/appinfo/app.php2
-rw-r--r--apps/files_versions/appinfo/application.php2
-rw-r--r--apps/files_versions/appinfo/info.xml3
-rw-r--r--apps/files_versions/appinfo/install.php2
-rw-r--r--apps/files_versions/appinfo/register_command.php2
-rw-r--r--apps/files_versions/appinfo/routes.php2
-rw-r--r--apps/files_versions/appinfo/update.php9
-rw-r--r--apps/files_versions/command/cleanup.php2
-rw-r--r--apps/files_versions/command/expire.php21
-rw-r--r--apps/files_versions/download.php5
-rw-r--r--apps/files_versions/l10n/he.js5
-rw-r--r--apps/files_versions/l10n/he.json5
-rw-r--r--apps/files_versions/l10n/hy.js3
-rw-r--r--apps/files_versions/l10n/hy.json3
-rw-r--r--apps/files_versions/lib/backgroundjob/expireversions.php2
-rw-r--r--apps/files_versions/lib/capabilities.php2
-rw-r--r--apps/files_versions/lib/expiration.php2
-rw-r--r--apps/files_versions/lib/hooks.php4
-rw-r--r--apps/files_versions/lib/storage.php73
-rw-r--r--apps/files_versions/tests/command/cleanuptest.php10
-rw-r--r--apps/files_versions/tests/command/expiretest.php10
-rw-r--r--apps/files_versions/tests/expirationtest.php2
-rw-r--r--apps/files_versions/tests/versions.php26
-rw-r--r--apps/provisioning_api/appinfo/info.xml8
-rw-r--r--apps/provisioning_api/appinfo/routes.php5
-rw-r--r--apps/provisioning_api/lib/apps.php12
-rw-r--r--apps/provisioning_api/lib/groups.php14
-rw-r--r--apps/provisioning_api/lib/users.php6
-rw-r--r--apps/provisioning_api/tests/appstest.php52
-rw-r--r--apps/provisioning_api/tests/groupstest.php45
-rw-r--r--apps/provisioning_api/tests/testcase.php8
-rw-r--r--apps/provisioning_api/tests/userstest.php64
-rw-r--r--apps/systemtags/activity/extension.php300
-rw-r--r--apps/systemtags/activity/listener.php223
-rw-r--r--apps/systemtags/appinfo/app.php75
-rw-r--r--apps/systemtags/appinfo/info.xml16
-rw-r--r--apps/systemtags/js/app.js20
-rw-r--r--apps/systemtags/js/filesplugin.js41
-rw-r--r--apps/systemtags/js/systemtagsinfoview.js145
-rw-r--r--apps/systemtags/tests/js/systemtagsinfoviewSpec.js176
-rw-r--r--apps/testing/appinfo/info.xml12
-rw-r--r--apps/testing/appinfo/routes.php46
-rw-r--r--apps/testing/config.php70
-rw-r--r--apps/testing/img/app.svg4
-rw-r--r--apps/user_ldap/ajax/clearMappings.php2
-rw-r--r--apps/user_ldap/ajax/deleteConfiguration.php2
-rw-r--r--apps/user_ldap/ajax/getConfiguration.php2
-rw-r--r--apps/user_ldap/ajax/getNewServerConfigPrefix.php2
-rw-r--r--apps/user_ldap/ajax/setConfiguration.php2
-rw-r--r--apps/user_ldap/ajax/testConfiguration.php4
-rw-r--r--apps/user_ldap/ajax/wizard.php5
-rw-r--r--apps/user_ldap/appinfo/app.php5
-rw-r--r--apps/user_ldap/appinfo/info.xml3
-rw-r--r--apps/user_ldap/appinfo/install.php2
-rw-r--r--apps/user_ldap/appinfo/register_command.php2
-rw-r--r--apps/user_ldap/appinfo/routes.php2
-rw-r--r--apps/user_ldap/appinfo/update.php19
-rw-r--r--apps/user_ldap/command/checkuser.php2
-rw-r--r--apps/user_ldap/command/createemptyconfig.php2
-rw-r--r--apps/user_ldap/command/deleteconfig.php2
-rw-r--r--apps/user_ldap/command/search.php2
-rw-r--r--apps/user_ldap/command/setconfig.php2
-rw-r--r--apps/user_ldap/command/showconfig.php2
-rw-r--r--apps/user_ldap/command/showremnants.php29
-rw-r--r--apps/user_ldap/command/testconfig.php2
-rw-r--r--apps/user_ldap/group_ldap.php85
-rw-r--r--apps/user_ldap/group_proxy.php4
-rw-r--r--apps/user_ldap/js/wizard/wizardTabAdvanced.js13
-rw-r--r--apps/user_ldap/js/wizard/wizardTabGeneric.js6
-rw-r--r--apps/user_ldap/l10n/de_DE.js1
-rw-r--r--apps/user_ldap/l10n/de_DE.json1
-rw-r--r--apps/user_ldap/l10n/es.js1
-rw-r--r--apps/user_ldap/l10n/es.json1
-rw-r--r--apps/user_ldap/l10n/et_EE.js6
-rw-r--r--apps/user_ldap/l10n/et_EE.json6
-rw-r--r--apps/user_ldap/l10n/eu.js27
-rw-r--r--apps/user_ldap/l10n/eu.json27
-rw-r--r--apps/user_ldap/l10n/fi_FI.js14
-rw-r--r--apps/user_ldap/l10n/fi_FI.json14
-rw-r--r--apps/user_ldap/l10n/he.js102
-rw-r--r--apps/user_ldap/l10n/he.json102
-rw-r--r--apps/user_ldap/l10n/ko.js1
-rw-r--r--apps/user_ldap/l10n/ko.json1
-rw-r--r--apps/user_ldap/l10n/lt_LT.js6
-rw-r--r--apps/user_ldap/l10n/lt_LT.json6
-rw-r--r--apps/user_ldap/l10n/mk.js1
-rw-r--r--apps/user_ldap/l10n/mk.json1
-rw-r--r--apps/user_ldap/l10n/nb_NO.js1
-rw-r--r--apps/user_ldap/l10n/nb_NO.json1
-rw-r--r--apps/user_ldap/l10n/oc.js1
-rw-r--r--apps/user_ldap/l10n/oc.json1
-rw-r--r--apps/user_ldap/l10n/pt_PT.js21
-rw-r--r--apps/user_ldap/l10n/pt_PT.json21
-rw-r--r--apps/user_ldap/l10n/ru.js1
-rw-r--r--apps/user_ldap/l10n/ru.json1
-rw-r--r--apps/user_ldap/l10n/sl.js11
-rw-r--r--apps/user_ldap/l10n/sl.json11
-rw-r--r--apps/user_ldap/l10n/sq.js12
-rw-r--r--apps/user_ldap/l10n/sq.json12
-rw-r--r--apps/user_ldap/l10n/sr.js1
-rw-r--r--apps/user_ldap/l10n/sr.json1
-rw-r--r--apps/user_ldap/l10n/th_TH.js1
-rw-r--r--apps/user_ldap/l10n/th_TH.json1
-rw-r--r--apps/user_ldap/l10n/tr.js1
-rw-r--r--apps/user_ldap/l10n/tr.json1
-rw-r--r--apps/user_ldap/l10n/zh_TW.js1
-rw-r--r--apps/user_ldap/l10n/zh_TW.json1
-rw-r--r--apps/user_ldap/lib/access.php239
-rw-r--r--apps/user_ldap/lib/backendutility.php2
-rw-r--r--apps/user_ldap/lib/configuration.php11
-rw-r--r--apps/user_ldap/lib/connection.php13
-rw-r--r--apps/user_ldap/lib/filesystemhelper.php2
-rw-r--r--apps/user_ldap/lib/helper.php4
-rw-r--r--apps/user_ldap/lib/ildapwrapper.php4
-rw-r--r--apps/user_ldap/lib/jobs.php7
-rw-r--r--apps/user_ldap/lib/jobs/cleanup.php2
-rw-r--r--apps/user_ldap/lib/ldap.php13
-rw-r--r--apps/user_ldap/lib/ldaputility.php2
-rw-r--r--apps/user_ldap/lib/logwrapper.php2
-rw-r--r--apps/user_ldap/lib/mapping/abstractmapping.php14
-rw-r--r--apps/user_ldap/lib/mapping/groupmapping.php2
-rw-r--r--apps/user_ldap/lib/mapping/usermapping.php2
-rw-r--r--apps/user_ldap/lib/proxy.php8
-rw-r--r--apps/user_ldap/lib/user/deletedusersindex.php2
-rw-r--r--apps/user_ldap/lib/user/iusertools.php2
-rw-r--r--apps/user_ldap/lib/user/manager.php31
-rw-r--r--apps/user_ldap/lib/user/offlineuser.php2
-rw-r--r--apps/user_ldap/lib/user/user.php30
-rw-r--r--apps/user_ldap/lib/wizard.php21
-rw-r--r--apps/user_ldap/lib/wizardresult.php4
-rw-r--r--apps/user_ldap/settings.php4
-rw-r--r--apps/user_ldap/templates/settings.php1
-rw-r--r--apps/user_ldap/tests/access.php13
-rw-r--r--apps/user_ldap/tests/configuration.php2
-rw-r--r--apps/user_ldap/tests/connection.php12
-rw-r--r--apps/user_ldap/tests/group_ldap.php23
-rw-r--r--apps/user_ldap/tests/integration/abstractintegrationtest.php2
-rw-r--r--apps/user_ldap/tests/integration/exceptionOnLostConnection.php2
-rw-r--r--apps/user_ldap/tests/integration/fakemanager.php2
-rw-r--r--apps/user_ldap/tests/integration/lib/IntegrationTestAccessGroupsMatchFilter.php2
-rw-r--r--apps/user_ldap/tests/integration/lib/integrationtestbackupserver.php2
-rw-r--r--apps/user_ldap/tests/integration/lib/integrationtestbatchapplyuserattributes.php72
-rw-r--r--apps/user_ldap/tests/integration/lib/integrationtestconnect.php166
-rw-r--r--apps/user_ldap/tests/integration/lib/integrationtestcountusersbyloginname.php2
-rw-r--r--apps/user_ldap/tests/integration/lib/integrationtestfetchusersbyloginname.php2
-rw-r--r--apps/user_ldap/tests/integration/lib/integrationtestpaging.php2
-rw-r--r--apps/user_ldap/tests/integration/lib/integrationtestuserhome.php2
-rw-r--r--apps/user_ldap/tests/integration/lib/user/IntegrationTestUserAvatar.php5
-rw-r--r--apps/user_ldap/tests/integration/setup-scripts/createExplicitGroups.php2
-rw-r--r--apps/user_ldap/tests/integration/setup-scripts/createExplicitGroupsDifferentOU.php2
-rw-r--r--apps/user_ldap/tests/integration/setup-scripts/createExplicitUsers.php2
-rw-r--r--apps/user_ldap/tests/integration/setup-scripts/createUsersWithoutDisplayName.php59
-rw-r--r--apps/user_ldap/tests/jobs/cleanup.php2
-rw-r--r--apps/user_ldap/tests/mapping/abstractmappingtest.php2
-rw-r--r--apps/user_ldap/tests/mapping/groupmapping.php10
-rw-r--r--apps/user_ldap/tests/mapping/usermapping.php10
-rw-r--r--apps/user_ldap/tests/user/manager.php45
-rw-r--r--apps/user_ldap/tests/user/user.php130
-rw-r--r--apps/user_ldap/tests/user_ldap.php79
-rw-r--r--apps/user_ldap/tests/wizard.php10
-rw-r--r--apps/user_ldap/user_ldap.php56
-rw-r--r--apps/user_ldap/user_proxy.php4
-rwxr-xr-xautotest-external.sh88
-rwxr-xr-xautotest.sh17
-rw-r--r--bower.json7
-rw-r--r--build/integration/capabilities_features/capabilities.feature217
-rw-r--r--build/integration/composer.json3
-rw-r--r--build/integration/config/behat.yml22
-rw-r--r--build/integration/data/textfile.txt3
-rw-r--r--build/integration/features/bootstrap/BasicStructure.php188
-rw-r--r--build/integration/features/bootstrap/CapabilitiesContext.php134
-rw-r--r--build/integration/features/bootstrap/FeatureContext.php921
-rw-r--r--build/integration/features/bootstrap/FederationContext.php27
-rw-r--r--build/integration/features/bootstrap/Provisioning.php568
-rw-r--r--build/integration/features/bootstrap/Sharing.php374
-rw-r--r--build/integration/features/bootstrap/WebDav.php178
-rw-r--r--build/integration/features/provisioning-v1.feature28
-rw-r--r--build/integration/features/sharing-v1.feature246
-rw-r--r--build/integration/features/webdav-related.feature45
-rw-r--r--build/integration/federation_features/federated.feature26
-rwxr-xr-xbuild/integration/run.sh25
-rw-r--r--build/license.php10
-rwxr-xr-xbuildjsdocs.sh2
-rw-r--r--config/config.sample.php100
-rw-r--r--console.php18
-rw-r--r--core/ajax/appconfig.php2
-rw-r--r--core/ajax/preview.php2
-rw-r--r--core/ajax/share.php23
-rw-r--r--core/ajax/update.php15
-rw-r--r--core/application.php8
-rw-r--r--core/command/app/checkcode.php8
-rw-r--r--core/command/app/disable.php19
-rw-r--r--core/command/app/enable.php43
-rw-r--r--core/command/app/getpath.php62
-rw-r--r--core/command/app/listapps.php34
-rw-r--r--core/command/base.php40
-rw-r--r--core/command/check.php2
-rw-r--r--core/command/config/app/deleteconfig.php2
-rw-r--r--core/command/config/app/getconfig.php2
-rw-r--r--core/command/config/app/setconfig.php2
-rw-r--r--core/command/config/import.php2
-rw-r--r--core/command/config/listconfigs.php2
-rw-r--r--core/command/config/system/deleteconfig.php62
-rw-r--r--core/command/config/system/getconfig.php21
-rw-r--r--core/command/config/system/setconfig.php135
-rw-r--r--core/command/db/converttype.php4
-rw-r--r--core/command/db/generatechangescript.php4
-rw-r--r--core/command/encryption/changekeystorageroot.php2
-rw-r--r--core/command/encryption/decryptall.php2
-rw-r--r--core/command/encryption/disable.php2
-rw-r--r--core/command/encryption/enable.php2
-rw-r--r--core/command/encryption/encryptall.php2
-rw-r--r--core/command/encryption/listmodules.php2
-rw-r--r--core/command/encryption/setdefaultmodule.php2
-rw-r--r--core/command/encryption/showkeystorageroot.php2
-rw-r--r--core/command/encryption/status.php2
-rw-r--r--core/command/integrity/signapp.php107
-rw-r--r--core/command/integrity/signcore.php100
-rw-r--r--core/command/l10n/createjs.php2
-rw-r--r--core/command/log/manage.php4
-rw-r--r--core/command/log/owncloud.php4
-rw-r--r--core/command/maintenance/install.php10
-rw-r--r--core/command/maintenance/mimetype/updatedb.php4
-rw-r--r--core/command/maintenance/mimetype/updatejs.php6
-rw-r--r--core/command/maintenance/mode.php2
-rw-r--r--core/command/maintenance/repair.php4
-rw-r--r--core/command/maintenance/singleuser.php2
-rw-r--r--core/command/security/importcertificate.php67
-rw-r--r--core/command/security/listcertificates.php96
-rw-r--r--core/command/security/removecertificate.php59
-rw-r--r--core/command/status.php4
-rw-r--r--core/command/upgrade.php24
-rw-r--r--core/command/user/add.php2
-rw-r--r--core/command/user/delete.php2
-rw-r--r--core/command/user/lastseen.php2
-rw-r--r--core/command/user/report.php2
-rw-r--r--core/command/user/resetpassword.php2
-rw-r--r--core/controller/avatarcontroller.php (renamed from core/avatar/avatarcontroller.php)33
-rw-r--r--core/controller/lostcontroller.php (renamed from core/lostpassword/controller/lostcontroller.php)22
-rw-r--r--core/controller/setupcontroller.php (renamed from core/setup/controller.php)9
-rw-r--r--core/controller/usercontroller.php (renamed from core/user/usercontroller.php)4
-rw-r--r--core/css/apps.css21
-rw-r--r--core/css/header.css7
-rw-r--r--core/css/icons.css15
-rw-r--r--core/css/inputs.css20
-rw-r--r--core/css/jquery.ocdialog.css2
-rw-r--r--core/css/lostpassword/resetpassword.css (renamed from core/lostpassword/css/resetpassword.css)0
-rw-r--r--core/css/mobile.css1
-rw-r--r--core/css/share.css2
-rw-r--r--core/css/styles.css43
-rw-r--r--core/css/systemtags.css85
-rw-r--r--core/img/actions/add.svg5
-rw-r--r--core/img/actions/checkbox-checked-disabled.pngbin0 -> 233 bytes
-rw-r--r--core/img/actions/checkbox-checked-disabled.svg5
-rw-r--r--core/img/actions/checkbox-checked.svg2
-rw-r--r--core/img/actions/checkbox-disabled-white.pngbin0 -> 134 bytes
-rw-r--r--core/img/actions/checkbox-disabled-white.svg5
-rw-r--r--core/img/actions/checkbox-disabled.pngbin0 -> 134 bytes
-rw-r--r--core/img/actions/checkbox-disabled.svg5
-rw-r--r--core/img/actions/checkbox-mixed.svg2
-rw-r--r--core/img/actions/checkbox.svg2
-rw-r--r--core/img/actions/checkmark-color.pngbin0 -> 279 bytes
-rw-r--r--core/img/actions/checkmark-color.svg2
-rw-r--r--core/img/actions/checkmark-white.svg4
-rw-r--r--core/img/actions/checkmark.svg2
-rw-r--r--core/img/actions/close.svg2
-rw-r--r--core/img/actions/comment.pngbin0 -> 169 bytes
-rw-r--r--core/img/actions/comment.svg4
-rw-r--r--core/img/actions/delete-hover.pngbin274 -> 208 bytes
-rw-r--r--core/img/actions/delete-hover.svg2
-rw-r--r--core/img/actions/delete.pngbin243 -> 208 bytes
-rw-r--r--core/img/actions/download.svg3
-rw-r--r--core/img/actions/error-color.pngbin0 -> 228 bytes
-rw-r--r--core/img/actions/error-color.svg4
-rw-r--r--core/img/actions/error-white.pngbin0 -> 228 bytes
-rw-r--r--core/img/actions/error-white.svg4
-rw-r--r--core/img/actions/error.pngbin0 -> 160 bytes
-rw-r--r--core/img/actions/error.svg4
-rw-r--r--core/img/actions/logout.pngbin3071 -> 2993 bytes
-rw-r--r--core/img/actions/logout.svg58
-rw-r--r--core/img/actions/menu.svg12
-rw-r--r--core/img/actions/public.svg4
-rw-r--r--core/img/actions/radio-checked-disabled.pngbin0 -> 378 bytes
-rw-r--r--core/img/actions/radio-checked-disabled.svg5
-rw-r--r--core/img/actions/radio-checked.pngbin0 -> 425 bytes
-rw-r--r--core/img/actions/radio-checked.svg5
-rw-r--r--core/img/actions/radio-disabled.pngbin0 -> 317 bytes
-rw-r--r--core/img/actions/radio-disabled.svg5
-rw-r--r--core/img/actions/radio-white.pngbin0 -> 336 bytes
-rw-r--r--core/img/actions/radio-white.svg4
-rw-r--r--core/img/actions/radio.pngbin0 -> 321 bytes
-rw-r--r--core/img/actions/radio.svg5
-rw-r--r--core/img/actions/starred.svg2
-rw-r--r--core/img/actions/toggle.svg2
-rw-r--r--core/img/actions/view-close.pngbin1442 -> 1126 bytes
-rw-r--r--core/img/actions/view-close.svg2
-rw-r--r--core/img/actions/view-next.pngbin1215 -> 959 bytes
-rw-r--r--core/img/actions/view-next.svg2
-rw-r--r--core/img/actions/view-pause.pngbin682 -> 648 bytes
-rw-r--r--core/img/actions/view-pause.svg6
-rw-r--r--core/img/actions/view-play.pngbin870 -> 804 bytes
-rw-r--r--core/img/actions/view-play.svg6
-rw-r--r--core/img/actions/view-previous.pngbin1189 -> 984 bytes
-rw-r--r--core/img/actions/view-previous.svg2
-rw-r--r--core/img/default-app-icon.svg4
-rw-r--r--core/js/avatar.js10
-rw-r--r--core/js/config.php25
-rw-r--r--core/js/core.json14
-rw-r--r--core/js/files/client.js685
-rw-r--r--core/js/files/fileinfo.js138
-rw-r--r--core/js/files/iedavclient.js166
-rw-r--r--core/js/integritycheck-failed-notification.js38
-rw-r--r--core/js/jquery.avatar.js62
-rw-r--r--core/js/js.js85
-rw-r--r--core/js/lostpassword.js12
-rw-r--r--core/js/mimetypelist.js30
-rw-r--r--core/js/oc-backbone-webdav.js327
-rw-r--r--core/js/oc-backbone.js2
-rw-r--r--core/js/oc-dialogs.js3
-rw-r--r--core/js/placeholder.js12
-rw-r--r--core/js/select2-toggleselect.js54
-rw-r--r--core/js/setupchecks.js94
-rw-r--r--core/js/share.js7
-rw-r--r--core/js/shareconfigmodel.js20
-rw-r--r--core/js/sharedialogexpirationview.js10
-rw-r--r--core/js/sharedialoglinkshareview.js37
-rw-r--r--core/js/sharedialogshareelistview.js72
-rw-r--r--core/js/sharedialogview.js103
-rw-r--r--core/js/shareitemmodel.js368
-rw-r--r--core/js/systemtags/systemtagmodel.js49
-rw-r--r--core/js/systemtags/systemtags.js57
-rw-r--r--core/js/systemtags/systemtagscollection.js89
-rw-r--r--core/js/systemtags/systemtagsinputfield.js441
-rw-r--r--core/js/systemtags/systemtagsmappingcollection.js87
-rw-r--r--core/js/tests/specHelper.js4
-rw-r--r--core/js/tests/specs/coreSpec.js8
-rw-r--r--core/js/tests/specs/files/clientSpec.js705
-rw-r--r--core/js/tests/specs/oc-backbone-webdavSpec.js390
-rw-r--r--core/js/tests/specs/setupchecksSpec.js171
-rw-r--r--core/js/tests/specs/sharedialogshareelistview.js12
-rw-r--r--core/js/tests/specs/sharedialogviewSpec.js559
-rw-r--r--core/js/tests/specs/shareitemmodelSpec.js580
-rw-r--r--core/js/tests/specs/systemtags/systemtagsSpec.js69
-rw-r--r--core/js/tests/specs/systemtags/systemtagscollectionSpec.js84
-rw-r--r--core/js/tests/specs/systemtags/systemtagsinputfieldSpec.js476
-rw-r--r--core/js/update.js2
-rw-r--r--core/l10n/af_ZA.js14
-rw-r--r--core/l10n/af_ZA.json14
-rw-r--r--core/l10n/ar.js15
-rw-r--r--core/l10n/ar.json15
-rw-r--r--core/l10n/ast.js22
-rw-r--r--core/l10n/ast.json22
-rw-r--r--core/l10n/az.js3
-rw-r--r--core/l10n/az.json3
-rw-r--r--core/l10n/bg_BG.js22
-rw-r--r--core/l10n/bg_BG.json22
-rw-r--r--core/l10n/bn_BD.js15
-rw-r--r--core/l10n/bn_BD.json15
-rw-r--r--core/l10n/bn_IN.js1
-rw-r--r--core/l10n/bn_IN.json1
-rw-r--r--core/l10n/bs.js22
-rw-r--r--core/l10n/bs.json22
-rw-r--r--core/l10n/ca.js29
-rw-r--r--core/l10n/ca.json29
-rw-r--r--core/l10n/cs_CZ.js53
-rw-r--r--core/l10n/cs_CZ.json53
-rw-r--r--core/l10n/cy_GB.js13
-rw-r--r--core/l10n/cy_GB.json13
-rw-r--r--core/l10n/da.js30
-rw-r--r--core/l10n/da.json30
-rw-r--r--core/l10n/de.js42
-rw-r--r--core/l10n/de.json42
-rw-r--r--core/l10n/de_DE.js44
-rw-r--r--core/l10n/de_DE.json44
-rw-r--r--core/l10n/el.js31
-rw-r--r--core/l10n/el.json31
-rw-r--r--core/l10n/en_GB.js24
-rw-r--r--core/l10n/en_GB.json24
-rw-r--r--core/l10n/eo.js11
-rw-r--r--core/l10n/eo.json11
-rw-r--r--core/l10n/es.js53
-rw-r--r--core/l10n/es.json53
-rw-r--r--core/l10n/es_AR.js13
-rw-r--r--core/l10n/es_AR.json13
-rw-r--r--core/l10n/es_CL.js2
-rw-r--r--core/l10n/es_CL.json2
-rw-r--r--core/l10n/es_MX.js13
-rw-r--r--core/l10n/es_MX.json13
-rw-r--r--core/l10n/et_EE.js30
-rw-r--r--core/l10n/et_EE.json30
-rw-r--r--core/l10n/eu.js28
-rw-r--r--core/l10n/eu.json28
-rw-r--r--core/l10n/fa.js17
-rw-r--r--core/l10n/fa.json17
-rw-r--r--core/l10n/fi_FI.js53
-rw-r--r--core/l10n/fi_FI.json53
-rw-r--r--core/l10n/fr.js57
-rw-r--r--core/l10n/fr.json57
-rw-r--r--core/l10n/gl.js24
-rw-r--r--core/l10n/gl.json24
-rw-r--r--core/l10n/he.js205
-rw-r--r--core/l10n/he.json205
-rw-r--r--core/l10n/hi.js6
-rw-r--r--core/l10n/hi.json6
-rw-r--r--core/l10n/hr.js22
-rw-r--r--core/l10n/hr.json22
-rw-r--r--core/l10n/hu_HU.js36
-rw-r--r--core/l10n/hu_HU.json36
-rw-r--r--core/l10n/hy.js7
-rw-r--r--core/l10n/hy.json7
-rw-r--r--core/l10n/ia.js16
-rw-r--r--core/l10n/ia.json16
-rw-r--r--core/l10n/id.js31
-rw-r--r--core/l10n/id.json31
-rw-r--r--core/l10n/is.js28
-rw-r--r--core/l10n/is.json28
-rw-r--r--core/l10n/it.js53
-rw-r--r--core/l10n/it.json53
-rw-r--r--core/l10n/ja.js52
-rw-r--r--core/l10n/ja.json52
-rw-r--r--core/l10n/ka_GE.js13
-rw-r--r--core/l10n/ka_GE.json13
-rw-r--r--core/l10n/km.js11
-rw-r--r--core/l10n/km.json11
-rw-r--r--core/l10n/kn.js22
-rw-r--r--core/l10n/kn.json22
-rw-r--r--core/l10n/ko.js31
-rw-r--r--core/l10n/ko.json31
-rw-r--r--core/l10n/ku_IQ.js6
-rw-r--r--core/l10n/ku_IQ.json6
-rw-r--r--core/l10n/lb.js13
-rw-r--r--core/l10n/lb.json13
-rw-r--r--core/l10n/lt_LT.js20
-rw-r--r--core/l10n/lt_LT.json20
-rw-r--r--core/l10n/lv.js15
-rw-r--r--core/l10n/lv.json15
-rw-r--r--core/l10n/mk.js56
-rw-r--r--core/l10n/mk.json56
-rw-r--r--core/l10n/ms_MY.js9
-rw-r--r--core/l10n/ms_MY.json9
-rw-r--r--core/l10n/my_MM.js4
-rw-r--r--core/l10n/my_MM.json4
-rw-r--r--core/l10n/nb_NO.js47
-rw-r--r--core/l10n/nb_NO.json47
-rw-r--r--core/l10n/nds.js8
-rw-r--r--core/l10n/nds.json8
-rw-r--r--core/l10n/nl.js54
-rw-r--r--core/l10n/nl.json54
-rw-r--r--core/l10n/nn_NO.js15
-rw-r--r--core/l10n/nn_NO.json15
-rw-r--r--core/l10n/oc.js31
-rw-r--r--core/l10n/oc.json31
-rw-r--r--core/l10n/pa.js1
-rw-r--r--core/l10n/pa.json1
-rw-r--r--core/l10n/pl.js22
-rw-r--r--core/l10n/pl.json22
-rw-r--r--core/l10n/pt_BR.js59
-rw-r--r--core/l10n/pt_BR.json59
-rw-r--r--core/l10n/pt_PT.js57
-rw-r--r--core/l10n/pt_PT.json57
-rw-r--r--core/l10n/ro.js17
-rw-r--r--core/l10n/ro.json17
-rw-r--r--core/l10n/ru.js117
-rw-r--r--core/l10n/ru.json117
-rw-r--r--core/l10n/si_LK.js7
-rw-r--r--core/l10n/si_LK.json7
-rw-r--r--core/l10n/sk_SK.js27
-rw-r--r--core/l10n/sk_SK.json27
-rw-r--r--core/l10n/sl.js77
-rw-r--r--core/l10n/sl.json77
-rw-r--r--core/l10n/sq.js55
-rw-r--r--core/l10n/sq.json55
-rw-r--r--core/l10n/sr.js24
-rw-r--r--core/l10n/sr.json24
-rw-r--r--core/l10n/sr@latin.js22
-rw-r--r--core/l10n/sr@latin.json22
-rw-r--r--core/l10n/sv.js22
-rw-r--r--core/l10n/sv.json22
-rw-r--r--core/l10n/ta_LK.js13
-rw-r--r--core/l10n/ta_LK.json13
-rw-r--r--core/l10n/te.js4
-rw-r--r--core/l10n/te.json4
-rw-r--r--core/l10n/th_TH.js56
-rw-r--r--core/l10n/th_TH.json56
-rw-r--r--core/l10n/tr.js41
-rw-r--r--core/l10n/tr.json41
-rw-r--r--core/l10n/ug.js5
-rw-r--r--core/l10n/ug.json5
-rw-r--r--core/l10n/uk.js27
-rw-r--r--core/l10n/uk.json27
-rw-r--r--core/l10n/ur_PK.js10
-rw-r--r--core/l10n/ur_PK.json10
-rw-r--r--core/l10n/vi.js13
-rw-r--r--core/l10n/vi.json13
-rw-r--r--core/l10n/zh_CN.js41
-rw-r--r--core/l10n/zh_CN.json41
-rw-r--r--core/l10n/zh_HK.js12
-rw-r--r--core/l10n/zh_HK.json12
-rw-r--r--core/l10n/zh_TW.js64
-rw-r--r--core/l10n/zh_TW.json64
-rw-r--r--core/lostpassword/css/lostpassword.css31
-rw-r--r--core/register_command.php26
-rw-r--r--core/routes.php2
-rw-r--r--core/search/ajax/search.php2
-rw-r--r--core/search/js/search.js12
-rw-r--r--core/shipped.json7
-rw-r--r--core/strings.php2
-rw-r--r--core/tags/controller.php2
-rw-r--r--core/templates/404.php2
-rw-r--r--core/templates/internalmail.php2
-rw-r--r--core/templates/layout.user.php6
-rw-r--r--core/templates/login.php10
-rw-r--r--core/templates/lostpassword/email.php (renamed from core/lostpassword/templates/email.php)2
-rw-r--r--core/templates/lostpassword/resetpassword.php (renamed from core/lostpassword/templates/resetpassword.php)4
-rw-r--r--core/templates/mail.php2
-rw-r--r--core/templates/untrustedDomain.php2
-rw-r--r--core/templates/update.admin.php6
-rw-r--r--core/vendor/.gitignore13
-rw-r--r--core/vendor/backbone/.bower.json13
-rw-r--r--core/vendor/backbone/backbone.js241
-rw-r--r--core/vendor/base64/.bower.json29
-rw-r--r--core/vendor/base64/LICENSE14
-rw-r--r--core/vendor/base64/base64.js61
-rw-r--r--core/vendor/bootstrap/js/tooltip.js4
-rw-r--r--core/vendor/davclient.js/LICENSE27
-rw-r--r--core/vendor/davclient.js/lib/client.js389
-rw-r--r--core/vendor/es6-promise/.bower.json40
-rw-r--r--core/vendor/es6-promise/.npmignore11
-rw-r--r--core/vendor/es6-promise/.release.json17
-rw-r--r--core/vendor/es6-promise/.spmignore11
-rw-r--r--core/vendor/es6-promise/LICENSE19
-rw-r--r--core/vendor/es6-promise/dist/es6-promise.js972
-rw-r--r--cron.php15
-rw-r--r--db_structure.xml482
-rw-r--r--index.php2
-rw-r--r--issue_template.md20
-rw-r--r--lib/autoloader.php10
-rw-r--r--lib/base.php97
-rw-r--r--lib/l10n/ast.js3
-rw-r--r--lib/l10n/ast.json3
-rw-r--r--lib/l10n/bg_BG.js3
-rw-r--r--lib/l10n/bg_BG.json3
-rw-r--r--lib/l10n/ca.js3
-rw-r--r--lib/l10n/ca.json3
-rw-r--r--lib/l10n/cs_CZ.js15
-rw-r--r--lib/l10n/cs_CZ.json15
-rw-r--r--lib/l10n/da.js3
-rw-r--r--lib/l10n/da.json3
-rw-r--r--lib/l10n/de.js3
-rw-r--r--lib/l10n/de.json3
-rw-r--r--lib/l10n/de_DE.js5
-rw-r--r--lib/l10n/de_DE.json5
-rw-r--r--lib/l10n/el.js3
-rw-r--r--lib/l10n/el.json3
-rw-r--r--lib/l10n/en_GB.js3
-rw-r--r--lib/l10n/en_GB.json3
-rw-r--r--lib/l10n/eo.js2
-rw-r--r--lib/l10n/eo.json2
-rw-r--r--lib/l10n/es.js16
-rw-r--r--lib/l10n/es.json16
-rw-r--r--lib/l10n/es_AR.js4
-rw-r--r--lib/l10n/es_AR.json4
-rw-r--r--lib/l10n/et_EE.js4
-rw-r--r--lib/l10n/et_EE.json4
-rw-r--r--lib/l10n/eu.js3
-rw-r--r--lib/l10n/eu.json3
-rw-r--r--lib/l10n/fa.js1
-rw-r--r--lib/l10n/fa.json1
-rw-r--r--lib/l10n/fi_FI.js15
-rw-r--r--lib/l10n/fi_FI.json15
-rw-r--r--lib/l10n/fr.js17
-rw-r--r--lib/l10n/fr.json17
-rw-r--r--lib/l10n/gl.js3
-rw-r--r--lib/l10n/gl.json3
-rw-r--r--lib/l10n/he.js60
-rw-r--r--lib/l10n/he.json60
-rw-r--r--lib/l10n/hr.js3
-rw-r--r--lib/l10n/hr.json3
-rw-r--r--lib/l10n/hu_HU.js15
-rw-r--r--lib/l10n/hu_HU.json15
-rw-r--r--lib/l10n/id.js3
-rw-r--r--lib/l10n/id.json3
-rw-r--r--lib/l10n/it.js15
-rw-r--r--lib/l10n/it.json15
-rw-r--r--lib/l10n/ja.js14
-rw-r--r--lib/l10n/ja.json14
-rw-r--r--lib/l10n/ko.js3
-rw-r--r--lib/l10n/ko.json3
-rw-r--r--lib/l10n/lt_LT.js8
-rw-r--r--lib/l10n/lt_LT.json8
-rw-r--r--lib/l10n/mk.js3
-rw-r--r--lib/l10n/mk.json3
-rw-r--r--lib/l10n/nb_NO.js14
-rw-r--r--lib/l10n/nb_NO.json14
-rw-r--r--lib/l10n/nl.js15
-rw-r--r--lib/l10n/nl.json15
-rw-r--r--lib/l10n/oc.js3
-rw-r--r--lib/l10n/oc.json3
-rw-r--r--lib/l10n/pl.js3
-rw-r--r--lib/l10n/pl.json3
-rw-r--r--lib/l10n/pt_BR.js15
-rw-r--r--lib/l10n/pt_BR.json15
-rw-r--r--lib/l10n/pt_PT.js23
-rw-r--r--lib/l10n/pt_PT.json23
-rw-r--r--lib/l10n/ro.js1
-rw-r--r--lib/l10n/ro.json1
-rw-r--r--lib/l10n/ru.js15
-rw-r--r--lib/l10n/ru.json15
-rw-r--r--lib/l10n/sk_SK.js3
-rw-r--r--lib/l10n/sk_SK.json3
-rw-r--r--lib/l10n/sl.js6
-rw-r--r--lib/l10n/sl.json6
-rw-r--r--lib/l10n/sq.js15
-rw-r--r--lib/l10n/sq.json15
-rw-r--r--lib/l10n/sr.js3
-rw-r--r--lib/l10n/sr.json3
-rw-r--r--lib/l10n/sv.js4
-rw-r--r--lib/l10n/sv.json4
-rw-r--r--lib/l10n/th_TH.js15
-rw-r--r--lib/l10n/th_TH.json15
-rw-r--r--lib/l10n/tr.js5
-rw-r--r--lib/l10n/tr.json5
-rw-r--r--lib/l10n/uk.js3
-rw-r--r--lib/l10n/uk.json3
-rw-r--r--lib/l10n/zh_CN.js2
-rw-r--r--lib/l10n/zh_CN.json2
-rw-r--r--lib/l10n/zh_TW.js14
-rw-r--r--lib/l10n/zh_TW.json14
-rw-r--r--lib/private/activity/event.php2
-rw-r--r--lib/private/activitymanager.php11
-rw-r--r--lib/private/allconfig.php57
-rw-r--r--lib/private/api.php2
-rw-r--r--lib/private/app.php134
-rw-r--r--lib/private/app/appmanager.php41
-rw-r--r--lib/private/app/codechecker/abstractcheck.php2
-rw-r--r--lib/private/app/codechecker/codechecker.php2
-rw-r--r--lib/private/app/codechecker/deprecationcheck.php2
-rw-r--r--lib/private/app/codechecker/emptycheck.php2
-rw-r--r--lib/private/app/codechecker/icheck.php2
-rw-r--r--lib/private/app/codechecker/infochecker.php8
-rw-r--r--lib/private/app/codechecker/nodevisitor.php2
-rw-r--r--lib/private/app/codechecker/privatecheck.php2
-rw-r--r--lib/private/app/codechecker/strongcomparisoncheck.php2
-rw-r--r--lib/private/app/dependencyanalyzer.php4
-rw-r--r--lib/private/app/infoparser.php6
-rw-r--r--lib/private/app/platform.php4
-rw-r--r--lib/private/app/platformrepository.php5
-rw-r--r--lib/private/appconfig.php17
-rw-r--r--lib/private/appframework/app.php4
-rw-r--r--lib/private/appframework/core/api.php4
-rw-r--r--lib/private/appframework/db/db.php17
-rw-r--r--lib/private/appframework/dependencyinjection/dicontainer.php52
-rw-r--r--lib/private/appframework/http.php5
-rw-r--r--lib/private/appframework/http/dispatcher.php2
-rw-r--r--lib/private/appframework/http/output.php2
-rw-r--r--lib/private/appframework/http/request.php47
-rw-r--r--lib/private/appframework/middleware/middlewaredispatcher.php2
-rw-r--r--lib/private/appframework/middleware/security/corsmiddleware.php3
-rw-r--r--lib/private/appframework/middleware/security/exceptions/appnotenabledexception.php38
-rw-r--r--lib/private/appframework/middleware/security/exceptions/crosssiterequestforgeryexception.php38
-rw-r--r--lib/private/appframework/middleware/security/exceptions/notadminexception.php38
-rw-r--r--lib/private/appframework/middleware/security/exceptions/notloggedinexception.php38
-rw-r--r--lib/private/appframework/middleware/security/exceptions/securityexception.php (renamed from lib/private/appframework/middleware/security/securityexception.php)23
-rw-r--r--lib/private/appframework/middleware/security/securitymiddleware.php85
-rw-r--r--lib/private/appframework/middleware/sessionmiddleware.php2
-rw-r--r--lib/private/appframework/routing/routeactionhandler.php2
-rw-r--r--lib/private/appframework/routing/routeconfig.php4
-rw-r--r--lib/private/appframework/utility/controllermethodreflector.php27
-rw-r--r--lib/private/appframework/utility/simplecontainer.php6
-rw-r--r--lib/private/appframework/utility/timefactory.php2
-rw-r--r--lib/private/apphelper.php10
-rw-r--r--lib/private/archive.php3
-rw-r--r--lib/private/archive/tar.php7
-rw-r--r--lib/private/archive/zip.php2
-rw-r--r--lib/private/avatar.php135
-rw-r--r--lib/private/avatarmanager.php34
-rw-r--r--lib/private/backgroundjob/job.php8
-rw-r--r--lib/private/backgroundjob/joblist.php184
-rw-r--r--lib/private/backgroundjob/legacy/queuedjob.php2
-rw-r--r--lib/private/backgroundjob/legacy/regularjob.php2
-rw-r--r--lib/private/backgroundjob/queuedjob.php2
-rw-r--r--lib/private/backgroundjob/timedjob.php2
-rw-r--r--lib/private/cache/cappedmemorycache.php87
-rw-r--r--lib/private/cache/file.php8
-rw-r--r--lib/private/capabilitiesmanager.php2
-rw-r--r--lib/private/command/asyncbus.php2
-rw-r--r--lib/private/command/callablejob.php2
-rw-r--r--lib/private/command/closurejob.php2
-rw-r--r--lib/private/command/commandjob.php2
-rw-r--r--lib/private/command/fileaccess.php2
-rw-r--r--lib/private/command/queuebus.php2
-rw-r--r--lib/private/comments/comment.php375
-rw-r--r--lib/private/comments/manager.php710
-rw-r--r--lib/private/comments/managerfactory.php58
-rw-r--r--lib/private/config.php11
-rw-r--r--lib/private/console/application.php27
-rw-r--r--lib/private/console/timestampformatter.php2
-rw-r--r--lib/private/contacts/localaddressbook.php118
-rw-r--r--lib/private/contactsmanager.php4
-rw-r--r--lib/private/databaseexception.php2
-rw-r--r--lib/private/databasesetupexception.php2
-rw-r--r--lib/private/datetimeformatter.php2
-rw-r--r--lib/private/datetimezone.php2
-rw-r--r--lib/private/db.php73
-rw-r--r--lib/private/db/adapter.php2
-rw-r--r--lib/private/db/adaptermysql.php2
-rw-r--r--lib/private/db/adapteroci8.php6
-rw-r--r--lib/private/db/adapterpgsql.php2
-rw-r--r--lib/private/db/adaptersqlite.php2
-rw-r--r--lib/private/db/adaptersqlsrv.php2
-rw-r--r--lib/private/db/connection.php68
-rw-r--r--lib/private/db/connectionfactory.php2
-rw-r--r--lib/private/db/mdb2schemamanager.php11
-rw-r--r--lib/private/db/mdb2schemareader.php4
-rw-r--r--lib/private/db/mdb2schemawriter.php20
-rw-r--r--lib/private/db/migrationexception.php2
-rw-r--r--lib/private/db/migrator.php4
-rw-r--r--lib/private/db/mysqlmigrator.php2
-rw-r--r--lib/private/db/nocheckmigrator.php2
-rw-r--r--lib/private/db/ocsqliteplatform.php2
-rw-r--r--lib/private/db/oracleconnection.php2
-rw-r--r--lib/private/db/oraclemigrator.php2
-rw-r--r--lib/private/db/pgsqltools.php2
-rw-r--r--lib/private/db/querybuilder/compositeexpression.php2
-rw-r--r--lib/private/db/querybuilder/expressionbuilder.php54
-rw-r--r--lib/private/db/querybuilder/literal.php2
-rw-r--r--lib/private/db/querybuilder/ociexpressionbuilder.php135
-rw-r--r--lib/private/db/querybuilder/parameter.php2
-rw-r--r--lib/private/db/querybuilder/querybuilder.php109
-rw-r--r--lib/private/db/querybuilder/queryfunction.php2
-rw-r--r--lib/private/db/querybuilder/quotehelper.php4
-rw-r--r--lib/private/db/sqlitemigrator.php2
-rw-r--r--lib/private/db/sqlitesessioninit.php2
-rw-r--r--lib/private/db/statementwrapper.php6
-rw-r--r--lib/private/defaults.php9
-rw-r--r--lib/private/diagnostics/event.php2
-rw-r--r--lib/private/diagnostics/eventlogger.php2
-rw-r--r--lib/private/diagnostics/nulleventlogger.php2
-rw-r--r--lib/private/diagnostics/nullquerylogger.php2
-rw-r--r--lib/private/diagnostics/query.php2
-rw-r--r--lib/private/diagnostics/querylogger.php4
-rw-r--r--lib/private/encryption/decryptall.php2
-rw-r--r--lib/private/encryption/exceptions/decryptionfailedexception.php2
-rw-r--r--lib/private/encryption/exceptions/emptyencryptiondataexception.php2
-rw-r--r--lib/private/encryption/exceptions/encryptionfailedexception.php2
-rw-r--r--lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php2
-rw-r--r--lib/private/encryption/exceptions/encryptionheadertolargeexception.php2
-rw-r--r--lib/private/encryption/exceptions/modulealreadyexistsexception.php2
-rw-r--r--lib/private/encryption/exceptions/moduledoesnotexistsexception.php2
-rw-r--r--lib/private/encryption/exceptions/unknowncipherexception.php2
-rw-r--r--lib/private/encryption/file.php2
-rw-r--r--lib/private/encryption/hookmanager.php2
-rw-r--r--lib/private/encryption/keys/storage.php2
-rw-r--r--lib/private/encryption/manager.php2
-rw-r--r--lib/private/encryption/update.php2
-rw-r--r--lib/private/encryption/util.php2
-rw-r--r--lib/private/eventsource.php4
-rw-r--r--lib/private/filechunking.php2
-rw-r--r--lib/private/files.php22
-rw-r--r--lib/private/files/cache/cache.php259
-rw-r--r--lib/private/files/cache/cacheentry.php114
-rw-r--r--lib/private/files/cache/changepropagator.php117
-rw-r--r--lib/private/files/cache/homecache.php6
-rw-r--r--lib/private/files/cache/movefromcachetrait.php87
-rw-r--r--lib/private/files/cache/propagator.php74
-rw-r--r--lib/private/files/cache/scanner.php77
-rw-r--r--lib/private/files/cache/storage.php8
-rw-r--r--lib/private/files/cache/updater.php183
-rw-r--r--lib/private/files/cache/watcher.php15
-rw-r--r--lib/private/files/cache/wrapper/cachejail.php15
-rw-r--r--lib/private/files/cache/wrapper/cachepermissionsmask.php4
-rw-r--r--lib/private/files/cache/wrapper/cachewrapper.php51
-rw-r--r--lib/private/files/config/cachedmountinfo.php107
-rw-r--r--lib/private/files/config/mountprovidercollection.php32
-rw-r--r--lib/private/files/config/usermountcache.php291
-rw-r--r--lib/private/files/config/usermountcachelistener.php48
-rw-r--r--lib/private/files/fileinfo.php59
-rw-r--r--lib/private/files/filesystem.php18
-rw-r--r--lib/private/files/mount/manager.php4
-rw-r--r--lib/private/files/mount/mountpoint.php4
-rw-r--r--lib/private/files/mount/moveablemount.php2
-rw-r--r--lib/private/files/node/file.php12
-rw-r--r--lib/private/files/node/folder.php7
-rw-r--r--lib/private/files/node/hookconnector.php21
-rw-r--r--lib/private/files/node/node.php6
-rw-r--r--lib/private/files/node/nonexistingfile.php62
-rw-r--r--lib/private/files/node/nonexistingfolder.php62
-rw-r--r--lib/private/files/node/root.php4
-rw-r--r--lib/private/files/objectstore/homeobjectstorestorage.php2
-rw-r--r--lib/private/files/objectstore/noopscanner.php2
-rw-r--r--lib/private/files/objectstore/objectstorestorage.php16
-rw-r--r--lib/private/files/objectstore/swift.php11
-rw-r--r--lib/private/files/storage/common.php47
-rw-r--r--lib/private/files/storage/commontest.php2
-rw-r--r--lib/private/files/storage/dav.php34
-rw-r--r--lib/private/files/storage/flysystem.php2
-rw-r--r--lib/private/files/storage/home.php2
-rw-r--r--lib/private/files/storage/local.php2
-rw-r--r--lib/private/files/storage/localtempfiletrait.php5
-rw-r--r--lib/private/files/storage/polyfill/copydirectory.php2
-rw-r--r--lib/private/files/storage/storage.php18
-rw-r--r--lib/private/files/storage/storagefactory.php2
-rw-r--r--lib/private/files/storage/temporary.php4
-rw-r--r--lib/private/files/storage/wrapper/availability.php6
-rw-r--r--lib/private/files/storage/wrapper/encryption.php6
-rw-r--r--lib/private/files/storage/wrapper/jail.php2
-rw-r--r--lib/private/files/storage/wrapper/permissionsmask.php4
-rw-r--r--lib/private/files/storage/wrapper/quota.php8
-rw-r--r--lib/private/files/storage/wrapper/wrapper.php33
-rw-r--r--lib/private/files/stream/close.php2
-rw-r--r--lib/private/files/stream/dir.php3
-rw-r--r--lib/private/files/stream/encryption.php16
-rw-r--r--lib/private/files/stream/oc.php4
-rw-r--r--lib/private/files/stream/quota.php2
-rw-r--r--lib/private/files/stream/staticstream.php2
-rw-r--r--lib/private/files/type/detection.php10
-rw-r--r--lib/private/files/type/loader.php4
-rw-r--r--lib/private/files/type/templatemanager.php4
-rw-r--r--lib/private/files/utils/scanner.php37
-rw-r--r--lib/private/files/view.php356
-rw-r--r--lib/private/forbiddenexception.php2
-rw-r--r--lib/private/group.php6
-rw-r--r--lib/private/group/backend.php10
-rw-r--r--lib/private/group/database.php139
-rw-r--r--lib/private/group/dummy.php4
-rw-r--r--lib/private/group/example.php4
-rw-r--r--lib/private/group/group.php4
-rw-r--r--lib/private/group/interface.php69
-rw-r--r--lib/private/group/manager.php19
-rw-r--r--lib/private/group/metadata.php2
-rw-r--r--lib/private/helper.php265
-rw-r--r--lib/private/hintexception.php5
-rw-r--r--lib/private/hook.php38
-rw-r--r--lib/private/hooks/basicemitter.php2
-rw-r--r--lib/private/hooks/emitter.php2
-rw-r--r--lib/private/hooks/emittertrait.php2
-rw-r--r--lib/private/hooks/forwardingemitter.php2
-rw-r--r--lib/private/hooks/legacyemitter.php2
-rw-r--r--lib/private/hooks/publicemitter.php2
-rw-r--r--lib/private/http/client/client.php18
-rw-r--r--lib/private/http/client/clientservice.php2
-rw-r--r--lib/private/http/client/response.php2
-rw-r--r--lib/private/httphelper.php2
-rw-r--r--lib/private/image.php19
-rw-r--r--lib/private/installer.php114
-rw-r--r--lib/private/integritycheck/checker.php523
-rw-r--r--lib/private/integritycheck/exceptions/invalidsignatureexception.php30
-rw-r--r--lib/private/integritycheck/helpers/applocator.php56
-rw-r--r--lib/private/integritycheck/helpers/environmenthelper.php48
-rw-r--r--lib/private/integritycheck/helpers/fileaccesshelper.php61
-rw-r--r--lib/private/integritycheck/iterator/excludefilebynamefilteriterator.php58
-rw-r--r--lib/private/integritycheck/iterator/excludefoldersbypathfilteriterator.php53
-rw-r--r--lib/private/json.php4
-rw-r--r--lib/private/l10n/factory.php319
-rw-r--r--lib/private/l10n/l10n.php216
-rw-r--r--lib/private/l10n/string.php24
-rw-r--r--lib/private/largefilehelper.php2
-rw-r--r--lib/private/legacy/config.php94
-rw-r--r--lib/private/legacy/l10n.php (renamed from lib/private/l10n.php)321
-rw-r--r--lib/private/lock/abstractlockingprovider.php4
-rw-r--r--lib/private/lock/dblockingprovider.php10
-rw-r--r--lib/private/lock/memcachelockingprovider.php11
-rw-r--r--lib/private/lock/nooplockingprovider.php2
-rw-r--r--lib/private/log.php44
-rw-r--r--lib/private/log/errorhandler.php2
-rw-r--r--lib/private/log/owncloud.php45
-rw-r--r--lib/private/log/rotate.php4
-rw-r--r--lib/private/log/syslog.php5
-rw-r--r--lib/private/mail/mailer.php2
-rw-r--r--lib/private/mail/message.php13
-rw-r--r--lib/private/memcache/apc.php7
-rw-r--r--lib/private/memcache/apcu.php108
-rw-r--r--lib/private/memcache/arraycache.php2
-rw-r--r--lib/private/memcache/cache.php4
-rw-r--r--lib/private/memcache/cadtrait.php2
-rw-r--r--lib/private/memcache/castrait.php2
-rw-r--r--lib/private/memcache/factory.php4
-rw-r--r--lib/private/memcache/memcached.php43
-rw-r--r--lib/private/memcache/nullcache.php4
-rw-r--r--lib/private/memcache/redis.php11
-rw-r--r--lib/private/memcache/xcache.php7
-rw-r--r--lib/private/naturalsort.php4
-rw-r--r--lib/private/naturalsort_defaultcollator.php2
-rw-r--r--lib/private/navigationmanager.php4
-rw-r--r--lib/private/needsupdateexception.php2
-rw-r--r--lib/private/notification/action.php8
-rw-r--r--lib/private/notification/manager.php52
-rw-r--r--lib/private/notification/notification.php54
-rw-r--r--lib/private/notsquareexception.php2
-rw-r--r--lib/private/ocs.php2
-rw-r--r--lib/private/ocs/cloud.php12
-rw-r--r--lib/private/ocs/config.php2
-rw-r--r--lib/private/ocs/corecapabilities.php3
-rw-r--r--lib/private/ocs/exception.php2
-rw-r--r--lib/private/ocs/person.php2
-rw-r--r--lib/private/ocs/privatedata.php2
-rw-r--r--lib/private/ocs/result.php4
-rw-r--r--lib/private/ocsclient.php7
-rw-r--r--lib/private/preview.php13
-rw-r--r--lib/private/preview/bitmap.php2
-rw-r--r--lib/private/preview/bmp.php2
-rw-r--r--lib/private/preview/font.php2
-rw-r--r--lib/private/preview/gif.php2
-rw-r--r--lib/private/preview/illustrator.php2
-rw-r--r--lib/private/preview/image.php2
-rw-r--r--lib/private/preview/jpeg.php2
-rw-r--r--lib/private/preview/markdown.php2
-rw-r--r--lib/private/preview/movie.php7
-rw-r--r--lib/private/preview/mp3.php2
-rw-r--r--lib/private/preview/msoffice2003.php2
-rw-r--r--lib/private/preview/msoffice2007.php2
-rw-r--r--lib/private/preview/msofficedoc.php2
-rw-r--r--lib/private/preview/office.php10
-rw-r--r--lib/private/preview/opendocument.php2
-rw-r--r--lib/private/preview/pdf.php2
-rw-r--r--lib/private/preview/photoshop.php2
-rw-r--r--lib/private/preview/png.php2
-rw-r--r--lib/private/preview/postscript.php2
-rw-r--r--lib/private/preview/provider.php2
-rw-r--r--lib/private/preview/staroffice.php2
-rw-r--r--lib/private/preview/svg.php2
-rw-r--r--lib/private/preview/tiff.php2
-rw-r--r--lib/private/preview/txt.php2
-rw-r--r--lib/private/preview/xbitmap.php2
-rw-r--r--lib/private/previewmanager.php2
-rw-r--r--lib/private/repair.php14
-rw-r--r--lib/private/repair/assetcache.php (renamed from lib/repair/assetcache.php)2
-rw-r--r--lib/private/repair/cleantags.php (renamed from lib/repair/cleantags.php)5
-rw-r--r--lib/private/repair/collation.php (renamed from lib/repair/collation.php)2
-rw-r--r--lib/private/repair/dropoldjobs.php (renamed from lib/repair/dropoldjobs.php)2
-rw-r--r--lib/private/repair/dropoldtables.php (renamed from lib/repair/dropoldtables.php)4
-rw-r--r--lib/private/repair/filletags.php (renamed from lib/repair/filletags.php)2
-rw-r--r--lib/private/repair/innodb.php (renamed from lib/repair/innodb.php)4
-rw-r--r--lib/private/repair/oldgroupmembershipshares.php (renamed from lib/repair/oldgroupmembershipshares.php)2
-rw-r--r--lib/private/repair/preview.php (renamed from lib/repair/preview.php)2
-rw-r--r--lib/private/repair/removegetetagentries.php (renamed from lib/repair/removegetetagentries.php)2
-rw-r--r--lib/private/repair/repairinvalidshares.php (renamed from lib/repair/repairinvalidshares.php)3
-rw-r--r--lib/private/repair/repairlegacystorages.php (renamed from lib/repair/repairlegacystorages.php)2
-rw-r--r--lib/private/repair/repairmimetypes.php (renamed from lib/repair/repairmimetypes.php)19
-rw-r--r--lib/private/repair/searchlucenetables.php (renamed from lib/repair/searchlucenetables.php)6
-rw-r--r--lib/private/repair/sqliteautoincrement.php (renamed from lib/repair/sqliteautoincrement.php)2
-rw-r--r--lib/private/repair/updatecertificatestore.php (renamed from lib/repair/updatecertificatestore.php)2
-rw-r--r--lib/private/repair/updateoutdatedocsids.php (renamed from lib/repair/updateoutdatedocsids.php)2
-rw-r--r--lib/private/repairexception.php2
-rw-r--r--lib/private/repairstep.php2
-rw-r--r--lib/private/response.php6
-rw-r--r--lib/private/route/cachingrouter.php9
-rw-r--r--lib/private/route/route.php4
-rw-r--r--lib/private/route/router.php131
-rw-r--r--lib/private/search.php2
-rw-r--r--lib/private/search/provider/file.php2
-rw-r--r--lib/private/search/result/audio.php2
-rw-r--r--lib/private/search/result/file.php2
-rw-r--r--lib/private/search/result/folder.php2
-rw-r--r--lib/private/search/result/image.php2
-rw-r--r--lib/private/security/certificate.php2
-rw-r--r--lib/private/security/certificatemanager.php91
-rw-r--r--lib/private/security/credentialsmanager.php125
-rw-r--r--lib/private/security/crypto.php7
-rw-r--r--lib/private/security/csp/contentsecuritypolicy.php199
-rw-r--r--lib/private/security/csp/contentsecuritypolicymanager.php73
-rw-r--r--lib/private/security/csrf/csrftoken.php69
-rw-r--r--lib/private/security/csrf/csrftokengenerator.php52
-rw-r--r--lib/private/security/csrf/csrftokenmanager.php97
-rw-r--r--lib/private/security/csrf/tokenstorage/sessionstorage.php80
-rw-r--r--lib/private/security/hasher.php4
-rw-r--r--lib/private/security/securerandom.php47
-rw-r--r--lib/private/security/stringutils.php60
-rw-r--r--lib/private/security/trusteddomainhelper.php9
-rw-r--r--lib/private/server.php267
-rw-r--r--lib/private/servercontainer.php89
-rw-r--r--lib/private/servernotavailableexception.php2
-rw-r--r--lib/private/serviceunavailableexception.php2
-rw-r--r--lib/private/session/cryptosessiondata.php12
-rw-r--r--lib/private/session/cryptowrapper.php6
-rw-r--r--lib/private/session/internal.php32
-rw-r--r--lib/private/session/memory.php10
-rw-r--r--lib/private/session/session.php2
-rw-r--r--lib/private/setup.php68
-rw-r--r--lib/private/setup/abstractdatabase.php2
-rw-r--r--lib/private/setup/mysql.php30
-rw-r--r--lib/private/setup/oci.php5
-rw-r--r--lib/private/setup/postgresql.php13
-rw-r--r--lib/private/setup/sqlite.php5
-rw-r--r--lib/private/share/constants.php2
-rw-r--r--lib/private/share/helper.php38
-rw-r--r--lib/private/share/hooks.php6
-rw-r--r--lib/private/share/mailnotifications.php60
-rw-r--r--lib/private/share/searchresultsorter.php4
-rw-r--r--lib/private/share/share.php244
-rw-r--r--lib/private/share20/defaultshareprovider.php768
-rw-r--r--lib/private/share20/exception/backenderror.php2
-rw-r--r--lib/private/share20/exception/invalidshare.php (renamed from lib/private/share20/exception/sharenotfound.php)4
-rw-r--r--lib/private/share20/exception/providerexception.php27
-rw-r--r--lib/private/share20/ishare.php177
-rw-r--r--lib/private/share20/ishareprovider.php98
-rw-r--r--lib/private/share20/manager.php964
-rw-r--r--lib/private/share20/providerfactory.php90
-rw-r--r--lib/private/share20/share.php259
-rw-r--r--lib/private/streamer.php2
-rw-r--r--lib/private/subadmin.php4
-rw-r--r--lib/private/systemconfig.php20
-rw-r--r--lib/private/systemtag/managerfactory.php79
-rw-r--r--lib/private/systemtag/systemtag.php91
-rw-r--r--lib/private/systemtag/systemtagmanager.php322
-rw-r--r--lib/private/systemtag/systemtagobjectmapper.php249
-rw-r--r--lib/private/tagging/tag.php2
-rw-r--r--lib/private/tagging/tagmapper.php2
-rw-r--r--lib/private/tagmanager.php2
-rw-r--r--lib/private/tags.php13
-rw-r--r--lib/private/template.php31
-rw-r--r--lib/private/template/base.php7
-rw-r--r--lib/private/template/cssresourcelocator.php2
-rw-r--r--lib/private/template/functions.php29
-rw-r--r--lib/private/template/jsresourcelocator.php2
-rw-r--r--lib/private/template/resourcelocator.php4
-rw-r--r--lib/private/template/resourcenotfoundexception.php2
-rw-r--r--lib/private/template/templatefilelocator.php2
-rw-r--r--lib/private/templatelayout.php107
-rw-r--r--lib/private/tempmanager.php19
-rw-r--r--lib/private/updater.php33
-rw-r--r--lib/private/urlgenerator.php9
-rw-r--r--lib/private/user.php145
-rw-r--r--lib/private/user/backend.php4
-rw-r--r--lib/private/user/database.php10
-rw-r--r--lib/private/user/interface.php68
-rw-r--r--lib/private/user/loginexception.php2
-rw-r--r--lib/private/user/manager.php50
-rw-r--r--lib/private/user/nouserexception.php2
-rw-r--r--lib/private/user/session.php11
-rw-r--r--lib/private/user/user.php148
-rw-r--r--lib/private/util.php327
-rw-r--r--lib/public/activity/iconsumer.php2
-rw-r--r--lib/public/activity/ievent.php2
-rw-r--r--lib/public/activity/iextension.php5
-rw-r--r--lib/public/activity/imanager.php5
-rw-r--r--lib/public/api.php2
-rw-r--r--lib/public/app.php9
-rw-r--r--lib/public/app/iappmanager.php3
-rw-r--r--lib/public/appframework/apicontroller.php2
-rw-r--r--lib/public/appframework/app.php2
-rw-r--r--lib/public/appframework/controller.php4
-rw-r--r--lib/public/appframework/db/doesnotexistexception.php2
-rw-r--r--lib/public/appframework/db/entity.php2
-rw-r--r--lib/public/appframework/db/mapper.php2
-rw-r--r--lib/public/appframework/db/multipleobjectsreturnedexception.php2
-rw-r--r--lib/public/appframework/http.php2
-rw-r--r--lib/public/appframework/http/contentsecuritypolicy.php337
-rw-r--r--lib/public/appframework/http/datadisplayresponse.php2
-rw-r--r--lib/public/appframework/http/datadownloadresponse.php2
-rw-r--r--lib/public/appframework/http/dataresponse.php2
-rw-r--r--lib/public/appframework/http/downloadresponse.php2
-rw-r--r--lib/public/appframework/http/emptycontentsecuritypolicy.php387
-rw-r--r--lib/public/appframework/http/icallbackresponse.php2
-rw-r--r--lib/public/appframework/http/ioutput.php2
-rw-r--r--lib/public/appframework/http/jsonresponse.php2
-rw-r--r--lib/public/appframework/http/notfoundresponse.php2
-rw-r--r--lib/public/appframework/http/ocsresponse.php2
-rw-r--r--lib/public/appframework/http/redirectresponse.php2
-rw-r--r--lib/public/appframework/http/response.php2
-rw-r--r--lib/public/appframework/http/streamresponse.php2
-rw-r--r--lib/public/appframework/http/templateresponse.php2
-rw-r--r--lib/public/appframework/iapi.php2
-rw-r--r--lib/public/appframework/iappcontainer.php2
-rw-r--r--lib/public/appframework/middleware.php2
-rw-r--r--lib/public/appframework/ocscontroller.php2
-rw-r--r--lib/public/appframework/queryexception.php2
-rw-r--r--lib/public/appframework/utility/icontrollermethodreflector.php2
-rw-r--r--lib/public/appframework/utility/itimefactory.php2
-rw-r--r--lib/public/authentication/iapachebackend.php2
-rw-r--r--lib/public/autoloadnotallowedexception.php4
-rw-r--r--lib/public/backgroundjob.php42
-rw-r--r--lib/public/backgroundjob/ijob.php23
-rw-r--r--lib/public/backgroundjob/ijoblist.php17
-rw-r--r--lib/public/capabilities/icapability.php2
-rw-r--r--lib/public/command/ibus.php2
-rw-r--r--lib/public/command/icommand.php2
-rw-r--r--lib/public/comments/icomment.php234
-rw-r--r--lib/public/comments/icommentsmanager.php237
-rw-r--r--lib/public/comments/icommentsmanagerfactory.php51
-rw-r--r--lib/public/comments/illegalidchangeexception.php27
-rw-r--r--lib/public/comments/notfoundexception.php27
-rw-r--r--lib/public/config.php2
-rw-r--r--lib/public/constants.php2
-rw-r--r--lib/public/contacts.php4
-rw-r--r--lib/public/contacts/imanager.php4
-rw-r--r--lib/public/db.php2
-rw-r--r--lib/public/db/querybuilder/icompositeexpression.php2
-rw-r--r--lib/public/db/querybuilder/iexpressionbuilder.php100
-rw-r--r--lib/public/db/querybuilder/iliteral.php2
-rw-r--r--lib/public/db/querybuilder/iparameter.php2
-rw-r--r--lib/public/db/querybuilder/iquerybuilder.php102
-rw-r--r--lib/public/db/querybuilder/iqueryfunction.php2
-rw-r--r--lib/public/defaults.php2
-rw-r--r--lib/public/diagnostics/ievent.php2
-rw-r--r--lib/public/diagnostics/ieventlogger.php2
-rw-r--r--lib/public/diagnostics/iquery.php2
-rw-r--r--lib/public/diagnostics/iquerylogger.php2
-rw-r--r--lib/public/encryption/exceptions/genericencryptionexception.php2
-rw-r--r--lib/public/encryption/iencryptionmodule.php2
-rw-r--r--lib/public/encryption/ifile.php2
-rw-r--r--lib/public/encryption/imanager.php2
-rw-r--r--lib/public/encryption/keys/istorage.php2
-rw-r--r--lib/public/files.php4
-rw-r--r--lib/public/files/alreadyexistsexception.php2
-rw-r--r--lib/public/files/cache/icache.php249
-rw-r--r--lib/public/files/cache/icacheentry.php134
-rw-r--r--lib/public/files/cache/ipropagator.php37
-rw-r--r--lib/public/files/cache/iscanner.php81
-rw-r--r--lib/public/files/cache/iupdater.php75
-rw-r--r--lib/public/files/cache/iwatcher.php82
-rw-r--r--lib/public/files/config/icachedmountinfo.php62
-rw-r--r--lib/public/files/config/imountprovider.php2
-rw-r--r--lib/public/files/config/imountprovidercollection.php11
-rw-r--r--lib/public/files/config/iusermountcache.php104
-rw-r--r--lib/public/files/entitytoolargeexception.php2
-rw-r--r--lib/public/files/file.php2
-rw-r--r--lib/public/files/fileinfo.php12
-rw-r--r--lib/public/files/filenametoolongexception.php2
-rw-r--r--lib/public/files/folder.php2
-rw-r--r--lib/public/files/forbiddenexception.php55
-rw-r--r--lib/public/files/ihomestorage.php2
-rw-r--r--lib/public/files/imimetypedetector.php2
-rw-r--r--lib/public/files/imimetypeloader.php4
-rw-r--r--lib/public/files/invalidcharacterinpathexception.php2
-rw-r--r--lib/public/files/invalidcontentexception.php2
-rw-r--r--lib/public/files/invalidpathexception.php2
-rw-r--r--lib/public/files/irootfolder.php2
-rw-r--r--lib/public/files/locknotacquiredexception.php2
-rw-r--r--lib/public/files/mount/imountmanager.php2
-rw-r--r--lib/public/files/mount/imountpoint.php2
-rw-r--r--lib/public/files/node.php10
-rw-r--r--lib/public/files/notenoughspaceexception.php2
-rw-r--r--lib/public/files/notfoundexception.php2
-rw-r--r--lib/public/files/notpermittedexception.php2
-rw-r--r--lib/public/files/objectstore/iobjectstore.php2
-rw-r--r--lib/public/files/reservedwordexception.php2
-rw-r--r--lib/public/files/storage.php17
-rw-r--r--lib/public/files/storage/ilockingstorage.php60
-rw-r--r--lib/public/files/storage/istorage.php482
-rw-r--r--lib/public/files/storage/istoragefactory.php2
-rw-r--r--lib/public/files/storageauthexception.php41
-rw-r--r--lib/public/files/storagebadconfigexception.php42
-rw-r--r--lib/public/files/storageconnectionexception.php41
-rw-r--r--lib/public/files/storageinvalidexception.php2
-rw-r--r--lib/public/files/storagenotavailableexception.php17
-rw-r--r--lib/public/files/storagetimeoutexception.php41
-rw-r--r--lib/public/groupinterface.php72
-rw-r--r--lib/public/http/client/iclient.php2
-rw-r--r--lib/public/http/client/iclientservice.php2
-rw-r--r--lib/public/http/client/iresponse.php2
-rw-r--r--lib/public/iaddressbook.php4
-rw-r--r--lib/public/iappconfig.php4
-rw-r--r--lib/public/iavatar.php20
-rw-r--r--lib/public/iavatarmanager.php4
-rw-r--r--lib/public/icache.php2
-rw-r--r--lib/public/icachefactory.php2
-rw-r--r--lib/public/icertificate.php2
-rw-r--r--lib/public/icertificatemanager.php14
-rw-r--r--lib/public/iconfig.php2
-rw-r--r--lib/public/icontainer.php2
-rw-r--r--lib/public/idatetimeformatter.php2
-rw-r--r--lib/public/idatetimezone.php2
-rw-r--r--lib/public/idb.php2
-rw-r--r--lib/public/idbconnection.php16
-rw-r--r--lib/public/ieventsource.php2
-rw-r--r--lib/public/igroup.php2
-rw-r--r--lib/public/igroupmanager.php7
-rw-r--r--lib/public/ihelper.php2
-rw-r--r--lib/public/iimage.php2
-rw-r--r--lib/public/il10n.php7
-rw-r--r--lib/public/ilogger.php10
-rw-r--r--lib/public/image.php2
-rw-r--r--lib/public/imemcache.php2
-rw-r--r--lib/public/imemcachettl.php39
-rw-r--r--lib/public/inavigationmanager.php2
-rw-r--r--lib/public/ipreview.php2
-rw-r--r--lib/public/irequest.php22
-rw-r--r--lib/public/isearch.php2
-rw-r--r--lib/public/iservercontainer.php59
-rw-r--r--lib/public/isession.php11
-rw-r--r--lib/public/itagmanager.php2
-rw-r--r--lib/public/itags.php2
-rw-r--r--lib/public/itempmanager.php4
-rw-r--r--lib/public/iurlgenerator.php2
-rw-r--r--lib/public/iuser.php36
-rw-r--r--lib/public/iuserbackend.php2
-rw-r--r--lib/public/iusermanager.php10
-rw-r--r--lib/public/iusersession.php2
-rw-r--r--lib/public/json.php2
-rw-r--r--lib/public/l10n/ifactory.php45
-rw-r--r--lib/public/lock/ilockingprovider.php2
-rw-r--r--lib/public/lock/lockedexception.php2
-rw-r--r--lib/public/mail/imailer.php2
-rw-r--r--lib/public/notification/iaction.php (renamed from lib/private/notification/iaction.php)31
-rw-r--r--lib/public/notification/iapp.php (renamed from lib/private/notification/iapp.php)18
-rw-r--r--lib/public/notification/imanager.php (renamed from lib/private/notification/imanager.php)30
-rw-r--r--lib/public/notification/inotification.php (renamed from lib/private/notification/inotification.php)84
-rw-r--r--lib/public/notification/inotifier.php (renamed from lib/private/notification/inotifier.php)14
-rw-r--r--lib/public/preconditionnotmetexception.php2
-rw-r--r--lib/public/preview/iprovider.php2
-rw-r--r--lib/public/response.php2
-rw-r--r--lib/public/route/iroute.php4
-rw-r--r--lib/public/route/irouter.php19
-rw-r--r--lib/public/sabrepluginevent.php17
-rw-r--r--lib/public/sabrepluginexception.php2
-rw-r--r--lib/public/search/pagedprovider.php2
-rw-r--r--lib/public/search/provider.php2
-rw-r--r--lib/public/search/result.php2
-rw-r--r--lib/public/security/icontentsecuritypolicymanager.php50
-rw-r--r--lib/public/security/icredentialsmanager.php71
-rw-r--r--lib/public/security/icrypto.php2
-rw-r--r--lib/public/security/ihasher.php2
-rw-r--r--lib/public/security/isecurerandom.php13
-rw-r--r--lib/public/security/stringutils.php5
-rw-r--r--lib/public/share.php4
-rw-r--r--lib/public/share/exceptions/genericshareexception.php28
-rw-r--r--lib/public/share/exceptions/sharenotfound.php32
-rw-r--r--lib/public/share/imanager.php232
-rw-r--r--lib/public/share/iproviderfactory.php57
-rw-r--r--lib/public/share/ishare.php298
-rw-r--r--lib/public/share/ishareprovider.php151
-rw-r--r--lib/public/share_backend.php4
-rw-r--r--lib/public/share_backend_collection.php2
-rw-r--r--lib/public/share_backend_file_dependent.php2
-rw-r--r--lib/public/systemtag/isystemtag.php68
-rw-r--r--lib/public/systemtag/isystemtagmanager.php116
-rw-r--r--lib/public/systemtag/isystemtagmanagerfactory.php59
-rw-r--r--lib/public/systemtag/isystemtagobjectmapper.php126
-rw-r--r--lib/public/systemtag/managerevent.php85
-rw-r--r--lib/public/systemtag/mapperevent.php93
-rw-r--r--lib/public/systemtag/tagalreadyexistsexception.php29
-rw-r--r--lib/public/systemtag/tagnotfoundexception.php56
-rw-r--r--lib/public/template.php8
-rw-r--r--lib/public/user.php4
-rw-r--r--lib/public/userinterface.php72
-rw-r--r--lib/public/util.php64
-rw-r--r--lib/repair/repairconfig.php80
-rw-r--r--ocs/providers.php50
-rw-r--r--ocs/routes.php4
-rw-r--r--ocs/v1.php4
-rw-r--r--ocs/v2.php2
-rw-r--r--public.php2
-rw-r--r--remote.php6
-rw-r--r--resources/codesigning/core.crt24
-rw-r--r--resources/codesigning/root.crt66
-rw-r--r--resources/config/ca-bundle.crt179
-rw-r--r--resources/config/mimetypealiases.dist.json4
-rw-r--r--resources/config/mimetypemapping.dist.json4
-rw-r--r--settings/admin.php24
-rw-r--r--settings/ajax/changedisplayname.php67
-rw-r--r--settings/ajax/disableapp.php2
-rw-r--r--settings/ajax/enableapp.php2
-rw-r--r--settings/ajax/installapp.php2
-rw-r--r--settings/ajax/navigationdetect.php4
-rw-r--r--settings/ajax/setlanguage.php4
-rw-r--r--settings/ajax/setquota.php2
-rw-r--r--settings/ajax/togglegroups.php2
-rw-r--r--settings/ajax/togglesubadmins.php3
-rw-r--r--settings/ajax/uninstallapp.php2
-rw-r--r--settings/ajax/updateapp.php2
-rw-r--r--settings/application.php19
-rw-r--r--settings/changepassword/controller.php8
-rw-r--r--settings/controller/appsettingscontroller.php20
-rw-r--r--settings/controller/certificatecontroller.php73
-rw-r--r--settings/controller/checksetupcontroller.php86
-rw-r--r--settings/controller/encryptioncontroller.php2
-rw-r--r--settings/controller/groupscontroller.php2
-rw-r--r--settings/controller/logsettingscontroller.php2
-rw-r--r--settings/controller/mailsettingscontroller.php2
-rw-r--r--settings/controller/securitysettingscontroller.php2
-rw-r--r--settings/controller/userscontroller.php86
-rw-r--r--settings/css/settings.css78
-rw-r--r--settings/help.php13
-rw-r--r--settings/js/admin.js9
-rw-r--r--settings/js/apps.js13
-rw-r--r--settings/js/certificates.js69
-rw-r--r--settings/js/personal.js95
-rw-r--r--settings/js/users/users.js60
-rw-r--r--settings/l10n/af_ZA.js2
-rw-r--r--settings/l10n/af_ZA.json2
-rw-r--r--settings/l10n/ar.js32
-rw-r--r--settings/l10n/ar.json32
-rw-r--r--settings/l10n/ast.js40
-rw-r--r--settings/l10n/ast.json40
-rw-r--r--settings/l10n/az.js61
-rw-r--r--settings/l10n/az.json61
-rw-r--r--settings/l10n/bg_BG.js61
-rw-r--r--settings/l10n/bg_BG.json61
-rw-r--r--settings/l10n/bn_BD.js19
-rw-r--r--settings/l10n/bn_BD.json19
-rw-r--r--settings/l10n/bn_IN.js3
-rw-r--r--settings/l10n/bn_IN.json3
-rw-r--r--settings/l10n/bs.js49
-rw-r--r--settings/l10n/bs.json49
-rw-r--r--settings/l10n/ca.js61
-rw-r--r--settings/l10n/ca.json61
-rw-r--r--settings/l10n/cs_CZ.js77
-rw-r--r--settings/l10n/cs_CZ.json77
-rw-r--r--settings/l10n/cy_GB.js7
-rw-r--r--settings/l10n/cy_GB.json7
-rw-r--r--settings/l10n/da.js65
-rw-r--r--settings/l10n/da.json65
-rw-r--r--settings/l10n/de.js72
-rw-r--r--settings/l10n/de.json72
-rw-r--r--settings/l10n/de_AT.js5
-rw-r--r--settings/l10n/de_AT.json5
-rw-r--r--settings/l10n/de_DE.js80
-rw-r--r--settings/l10n/de_DE.json80
-rw-r--r--settings/l10n/el.js65
-rw-r--r--settings/l10n/el.json65
-rw-r--r--settings/l10n/en_GB.js63
-rw-r--r--settings/l10n/en_GB.json63
-rw-r--r--settings/l10n/eo.js28
-rw-r--r--settings/l10n/eo.json28
-rw-r--r--settings/l10n/es.js78
-rw-r--r--settings/l10n/es.json78
-rw-r--r--settings/l10n/es_AR.js39
-rw-r--r--settings/l10n/es_AR.json39
-rw-r--r--settings/l10n/es_CL.js2
-rw-r--r--settings/l10n/es_CL.json2
-rw-r--r--settings/l10n/es_MX.js31
-rw-r--r--settings/l10n/es_MX.json31
-rw-r--r--settings/l10n/et_EE.js64
-rw-r--r--settings/l10n/et_EE.json64
-rw-r--r--settings/l10n/eu.js53
-rw-r--r--settings/l10n/eu.json53
-rw-r--r--settings/l10n/fa.js59
-rw-r--r--settings/l10n/fa.json59
-rw-r--r--settings/l10n/fi_FI.js78
-rw-r--r--settings/l10n/fi_FI.json78
-rw-r--r--settings/l10n/fr.js77
-rw-r--r--settings/l10n/fr.json77
-rw-r--r--settings/l10n/gl.js64
-rw-r--r--settings/l10n/gl.json64
-rw-r--r--settings/l10n/he.js268
-rw-r--r--settings/l10n/he.json268
-rw-r--r--settings/l10n/hi.js2
-rw-r--r--settings/l10n/hi.json2
-rw-r--r--settings/l10n/hr.js42
-rw-r--r--settings/l10n/hr.json42
-rw-r--r--settings/l10n/hu_HU.js75
-rw-r--r--settings/l10n/hu_HU.json75
-rw-r--r--settings/l10n/hy.js7
-rw-r--r--settings/l10n/hy.json7
-rw-r--r--settings/l10n/ia.js13
-rw-r--r--settings/l10n/ia.json13
-rw-r--r--settings/l10n/id.js65
-rw-r--r--settings/l10n/id.json65
-rw-r--r--settings/l10n/is.js14
-rw-r--r--settings/l10n/is.json14
-rw-r--r--settings/l10n/it.js77
-rw-r--r--settings/l10n/it.json77
-rw-r--r--settings/l10n/ja.js79
-rw-r--r--settings/l10n/ja.json79
-rw-r--r--settings/l10n/ka_GE.js16
-rw-r--r--settings/l10n/ka_GE.json16
-rw-r--r--settings/l10n/km.js24
-rw-r--r--settings/l10n/km.json24
-rw-r--r--settings/l10n/kn.js17
-rw-r--r--settings/l10n/kn.json17
-rw-r--r--settings/l10n/ko.js67
-rw-r--r--settings/l10n/ko.json67
-rw-r--r--settings/l10n/ku_IQ.js5
-rw-r--r--settings/l10n/ku_IQ.json5
-rw-r--r--settings/l10n/lb.js15
-rw-r--r--settings/l10n/lb.json15
-rw-r--r--settings/l10n/lo.js4
-rw-r--r--settings/l10n/lo.json4
-rw-r--r--settings/l10n/lt_LT.js46
-rw-r--r--settings/l10n/lt_LT.json46
-rw-r--r--settings/l10n/lv.js37
-rw-r--r--settings/l10n/lv.json37
-rw-r--r--settings/l10n/mk.js57
-rw-r--r--settings/l10n/mk.json57
-rw-r--r--settings/l10n/mn.js8
-rw-r--r--settings/l10n/mn.json8
-rw-r--r--settings/l10n/ms_MY.js12
-rw-r--r--settings/l10n/ms_MY.json12
-rw-r--r--settings/l10n/my_MM.js4
-rw-r--r--settings/l10n/my_MM.json4
-rw-r--r--settings/l10n/nb_NO.js76
-rw-r--r--settings/l10n/nb_NO.json76
-rw-r--r--settings/l10n/nds.js4
-rw-r--r--settings/l10n/nds.json4
-rw-r--r--settings/l10n/nl.js79
-rw-r--r--settings/l10n/nl.json79
-rw-r--r--settings/l10n/nn_NO.js25
-rw-r--r--settings/l10n/nn_NO.json25
-rw-r--r--settings/l10n/oc.js65
-rw-r--r--settings/l10n/oc.json65
-rw-r--r--settings/l10n/pa.js2
-rw-r--r--settings/l10n/pa.json2
-rw-r--r--settings/l10n/pl.js57
-rw-r--r--settings/l10n/pl.json57
-rw-r--r--settings/l10n/pt_BR.js79
-rw-r--r--settings/l10n/pt_BR.json79
-rw-r--r--settings/l10n/pt_PT.js97
-rw-r--r--settings/l10n/pt_PT.json97
-rw-r--r--settings/l10n/ro.js34
-rw-r--r--settings/l10n/ro.json34
-rw-r--r--settings/l10n/ru.js77
-rw-r--r--settings/l10n/ru.json77
-rw-r--r--settings/l10n/si_LK.js10
-rw-r--r--settings/l10n/si_LK.json10
-rw-r--r--settings/l10n/sk_SK.js61
-rw-r--r--settings/l10n/sk_SK.json61
-rw-r--r--settings/l10n/sl.js84
-rw-r--r--settings/l10n/sl.json84
-rw-r--r--settings/l10n/sq.js83
-rw-r--r--settings/l10n/sq.json83
-rw-r--r--settings/l10n/sr.js63
-rw-r--r--settings/l10n/sr.json63
-rw-r--r--settings/l10n/sr@latin.js17
-rw-r--r--settings/l10n/sr@latin.json17
-rw-r--r--settings/l10n/sv.js53
-rw-r--r--settings/l10n/sv.json53
-rw-r--r--settings/l10n/ta_LK.js11
-rw-r--r--settings/l10n/ta_LK.json11
-rw-r--r--settings/l10n/te.js6
-rw-r--r--settings/l10n/te.json6
-rw-r--r--settings/l10n/th_TH.js77
-rw-r--r--settings/l10n/th_TH.json77
-rw-r--r--settings/l10n/tr.js73
-rw-r--r--settings/l10n/tr.json73
-rw-r--r--settings/l10n/ug.js10
-rw-r--r--settings/l10n/ug.json10
-rw-r--r--settings/l10n/uk.js63
-rw-r--r--settings/l10n/uk.json63
-rw-r--r--settings/l10n/ur_PK.js4
-rw-r--r--settings/l10n/ur_PK.json4
-rw-r--r--settings/l10n/vi.js24
-rw-r--r--settings/l10n/vi.json24
-rw-r--r--settings/l10n/zh_CN.js71
-rw-r--r--settings/l10n/zh_CN.json71
-rw-r--r--settings/l10n/zh_HK.js13
-rw-r--r--settings/l10n/zh_HK.json13
-rw-r--r--settings/l10n/zh_TW.js250
-rw-r--r--settings/l10n/zh_TW.json250
-rw-r--r--settings/languageCodes.php2
-rw-r--r--settings/middleware/subadminmiddleware.php2
-rw-r--r--settings/personal.php48
-rw-r--r--settings/routes.php12
-rw-r--r--settings/templates/admin.php47
-rw-r--r--settings/templates/apps.php18
-rw-r--r--settings/templates/certificates.php44
-rw-r--r--settings/templates/email.new_user.php2
-rw-r--r--settings/templates/personal.php216
-rw-r--r--settings/users.php12
-rw-r--r--status.php4
-rw-r--r--tests/core/command/config/system/deleteconfigtest.php110
-rw-r--r--tests/core/command/config/system/getconfigtest.php18
-rw-r--r--tests/core/command/config/system/setconfigtest.php146
-rw-r--r--tests/core/controller/avatarcontrollertest.php (renamed from tests/core/avatar/avatarcontrollertest.php)68
-rw-r--r--tests/core/controller/lostcontrollertest.php (renamed from tests/core/lostpassword/controller/lostcontrollertest.php)189
-rw-r--r--tests/data/integritycheck/SomeApp.crt28
-rw-r--r--tests/data/integritycheck/SomeApp.key51
-rw-r--r--tests/data/integritycheck/app/AnotherFile.txt1
-rw-r--r--tests/data/integritycheck/app/subfolder/file.txt1
-rw-r--r--tests/data/integritycheck/appWithInvalidData/AnotherFile.txt1
-rw-r--r--tests/data/integritycheck/appWithInvalidData/UnecessaryFile0
-rw-r--r--tests/data/integritycheck/core.crt28
-rw-r--r--tests/data/integritycheck/core.key51
-rw-r--r--tests/data/integritycheck/htaccessUnmodified/.htaccess1
-rw-r--r--tests/data/integritycheck/htaccessUnmodified/subfolder/.htaccess4
-rw-r--r--tests/data/integritycheck/htaccessWithInvalidModifiedContent/.htaccess5
-rw-r--r--tests/data/integritycheck/htaccessWithValidModifiedContent/.htaccess4
-rw-r--r--tests/data/integritycheck/htaccessWithValidModifiedContent/subfolder/.htaccess4
-rw-r--r--tests/data/integritycheck/root.crt28
-rw-r--r--tests/data/integritycheck/root.key51
-rw-r--r--tests/enable_all.php2
-rw-r--r--tests/karma.config.js32
-rw-r--r--tests/lib/allconfig.php33
-rw-r--r--tests/lib/app.php22
-rw-r--r--tests/lib/app/dependencyanalyzer.php3
-rw-r--r--tests/lib/app/infoparser.php3
-rw-r--r--tests/lib/app/manager.php104
-rw-r--r--tests/lib/appconfig.php7
-rw-r--r--tests/lib/appframework/AppTest.php7
-rw-r--r--tests/lib/appframework/dependencyinjection/DIContainerTest.php4
-rw-r--r--tests/lib/appframework/http/ContentSecurityPolicyTest.php17
-rw-r--r--tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php430
-rw-r--r--tests/lib/appframework/http/RequestTest.php153
-rw-r--r--tests/lib/appframework/middleware/security/CORSMiddlewareTest.php6
-rw-r--r--tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php171
-rw-r--r--tests/lib/appframework/routing/RoutingTest.php6
-rw-r--r--tests/lib/appframework/utility/ControllerMethodReflectorTest.php23
-rw-r--r--tests/lib/autoloader.php2
-rw-r--r--tests/lib/avatar.php89
-rw-r--r--tests/lib/avatarmanagertest.php76
-rw-r--r--tests/lib/avatartest.php172
-rw-r--r--tests/lib/backgroundjob/job.php16
-rw-r--r--tests/lib/backgroundjob/joblist.php57
-rw-r--r--tests/lib/cache.php2
-rw-r--r--tests/lib/cache/cappedmemorycache.php79
-rw-r--r--tests/lib/cache/file.php20
-rw-r--r--tests/lib/command/integrity/SignAppTest.php253
-rw-r--r--tests/lib/command/integrity/SignCoreTest.php209
-rw-r--r--tests/lib/comments/comment.php112
-rw-r--r--tests/lib/comments/fakefactory.php18
-rw-r--r--tests/lib/comments/fakemanager.php41
-rw-r--r--tests/lib/comments/manager.php633
-rw-r--r--tests/lib/configtests.php2
-rw-r--r--tests/lib/contacts/localadressbook.php98
-rw-r--r--tests/lib/db.php9
-rw-r--r--tests/lib/db/connection.php107
-rw-r--r--tests/lib/db/mdb2schemamanager.php11
-rw-r--r--tests/lib/db/migrator.php9
-rw-r--r--tests/lib/db/mysqlmigration.php7
-rw-r--r--tests/lib/db/querybuilder/expressionbuildertest.php97
-rw-r--r--tests/lib/db/querybuilder/querybuildertest.php250
-rw-r--r--tests/lib/db/sqlitemigration.php7
-rw-r--r--tests/lib/dbschema.php11
-rw-r--r--tests/lib/encryption/decryptalltest.php7
-rw-r--r--tests/lib/files/cache/cache.php18
-rw-r--r--tests/lib/files/cache/changepropagator.php97
-rw-r--r--tests/lib/files/cache/homecache.php9
-rw-r--r--tests/lib/files/cache/movefromcachetraittest.php31
-rw-r--r--tests/lib/files/cache/scanner.php11
-rw-r--r--tests/lib/files/cache/updater.php48
-rw-r--r--tests/lib/files/cache/updaterlegacy.php61
-rw-r--r--tests/lib/files/cache/watcher.php7
-rw-r--r--tests/lib/files/cache/wrapper/cachejail.php7
-rw-r--r--tests/lib/files/cache/wrapper/cachepermissionsmask.php7
-rw-r--r--tests/lib/files/config/usermountcache.php375
-rw-r--r--tests/lib/files/etagtest.php19
-rw-r--r--tests/lib/files/filesystem.php50
-rw-r--r--tests/lib/files/node/file.php14
-rw-r--r--tests/lib/files/node/folder.php18
-rw-r--r--tests/lib/files/node/hookconnector.php27
-rw-r--r--tests/lib/files/node/integration.php7
-rw-r--r--tests/lib/files/node/node.php10
-rw-r--r--tests/lib/files/objectstore/swift.php15
-rw-r--r--tests/lib/files/pathverificationtest.php7
-rw-r--r--tests/lib/files/storage/commontest.php9
-rw-r--r--tests/lib/files/storage/copydirectory.php7
-rw-r--r--tests/lib/files/storage/home.php9
-rw-r--r--tests/lib/files/storage/homestoragequota.php81
-rw-r--r--tests/lib/files/storage/local.php9
-rw-r--r--tests/lib/files/storage/storage.php13
-rw-r--r--tests/lib/files/storage/wrapper/quota.php13
-rw-r--r--tests/lib/files/storage/wrapper/wrapper.php2
-rw-r--r--tests/lib/files/utils/scanner.php76
-rw-r--r--tests/lib/files/view.php44
-rw-r--r--tests/lib/group.php6
-rw-r--r--tests/lib/group/backend.php90
-rw-r--r--tests/lib/group/database.php62
-rw-r--r--tests/lib/group/dummy.php5
-rw-r--r--tests/lib/helper.php238
-rw-r--r--tests/lib/helperstorage.php27
-rw-r--r--tests/lib/installer.php25
-rw-r--r--tests/lib/integritycheck/checkertest.php1011
-rw-r--r--tests/lib/integritycheck/helpers/AppLocatorTest.php51
-rw-r--r--tests/lib/integritycheck/helpers/EnvironmentHelperTest.php43
-rw-r--r--tests/lib/integritycheck/helpers/FileAccessHelperTest.php43
-rw-r--r--tests/lib/l10n/factorytest.php425
-rw-r--r--tests/lib/l10n/l10nlegacytest.php (renamed from tests/lib/l10n.php)66
-rw-r--r--tests/lib/l10n/l10ntest.php165
-rw-r--r--tests/lib/lock/dblockingprovider.php15
-rw-r--r--tests/lib/log/owncloud.php28
-rw-r--r--tests/lib/notification/actiontest.php54
-rw-r--r--tests/lib/notification/managertest.php167
-rw-r--r--tests/lib/notification/notificationtest.php154
-rw-r--r--tests/lib/ocs/privatedata.php5
-rw-r--r--tests/lib/ocsclienttest.php141
-rw-r--r--tests/lib/preview.php7
-rw-r--r--tests/lib/preview/bitmap.php7
-rw-r--r--tests/lib/preview/image.php7
-rw-r--r--tests/lib/preview/mp3.php7
-rw-r--r--tests/lib/preview/svg.php7
-rw-r--r--tests/lib/preview/txt.php7
-rw-r--r--tests/lib/repair/cleantags.php18
-rw-r--r--tests/lib/repair/dropoldjobs.php2
-rw-r--r--tests/lib/repair/dropoldtables.php2
-rw-r--r--tests/lib/repair/oldgroupmembershipsharestest.php28
-rw-r--r--tests/lib/repair/removegetetagentriestest.php7
-rw-r--r--tests/lib/repair/repaircollation.php4
-rw-r--r--tests/lib/repair/repairinnodb.php4
-rw-r--r--tests/lib/repair/repairinvalidsharestest.php16
-rw-r--r--tests/lib/repair/repairlegacystorage.php4
-rw-r--r--tests/lib/repair/repairmimetypes.php31
-rw-r--r--tests/lib/repair/repairsqliteautoincrement.php4
-rw-r--r--tests/lib/security/certificatemanager.php29
-rw-r--r--tests/lib/security/credentialsmanager.php102
-rw-r--r--tests/lib/security/csp/ContentSecurityPolicyManagerTest.php66
-rw-r--r--tests/lib/security/csrf/CsrfTokenGeneratorTest.php54
-rw-r--r--tests/lib/security/csrf/CsrfTokenManagerTest.php134
-rw-r--r--tests/lib/security/csrf/CsrfTokenTest.php33
-rw-r--r--tests/lib/security/csrf/tokenstorage/SessionStorageTest.php107
-rw-r--r--tests/lib/security/securerandom.php13
-rw-r--r--tests/lib/security/stringutils.php38
-rw-r--r--tests/lib/security/trusteddomainhelper.php2
-rw-r--r--tests/lib/server.php34
-rw-r--r--tests/lib/setup.php13
-rw-r--r--tests/lib/share/MailNotificationsTest.php199
-rw-r--r--tests/lib/share/helper.php37
-rw-r--r--tests/lib/share/hooktests.php7
-rw-r--r--tests/lib/share/share.php43
-rw-r--r--tests/lib/share20/defaultshareprovidertest.php2051
-rw-r--r--tests/lib/share20/managertest.php2158
-rw-r--r--tests/lib/streamwrappers.php9
-rw-r--r--tests/lib/systemtag/systemtagmanagertest.php424
-rw-r--r--tests/lib/systemtag/systemtagobjectmappertest.php354
-rw-r--r--tests/lib/tags.php17
-rw-r--r--tests/lib/testcase.php106
-rw-r--r--tests/lib/updater.php47
-rw-r--r--tests/lib/urlGenerator.php (renamed from tests/lib/urlgenerator.php)7
-rw-r--r--tests/lib/user.php36
-rw-r--r--tests/lib/user/database.php5
-rw-r--r--tests/lib/user/manager.php25
-rw-r--r--tests/lib/user/session.php20
-rw-r--r--tests/lib/user/user.php27
-rw-r--r--tests/lib/util.php267
-rw-r--r--tests/lib/utilcheckserver.php12
-rw-r--r--tests/phpunit-autotest-external.xml1
-rw-r--r--tests/settings/controller/AppSettingsControllerTest.php42
-rw-r--r--tests/settings/controller/CertificateControllerTest.php4
-rw-r--r--tests/settings/controller/CheckSetupControllerTest.php454
-rw-r--r--tests/settings/controller/EncryptionControllerTest.php3
-rw-r--r--tests/settings/controller/userscontrollertest.php312
-rw-r--r--tests/startsessionlistener.php3
-rw-r--r--version.php6
2740 files changed, 94565 insertions, 26708 deletions
diff --git a/.gitignore b/.gitignore
index 531e372e607..2e42105ad83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,18 +9,18 @@
# ignore all apps except core ones
/apps*/*
+!/apps/comments
!/apps/dav
!/apps/files
-!/apps/files_encryption
+!/apps/federation
!/apps/encryption
-!/apps/encryption_dummy
!/apps/files_external
!/apps/files_sharing
!/apps/files_trashbin
!/apps/files_versions
!/apps/user_ldap
-!/apps/user_webdavauth
-!apps/provisioning_api
+!/apps/provisioning_api
+!/apps/systemtags
/apps/files_external/3rdparty/irodsphp/PHPUnitTest
/apps/files_external/3rdparty/irodsphp/web
/apps/files_external/3rdparty/irodsphp/prods/test
diff --git a/.htaccess b/.htaccess
index b68adb43412..725efa0971a 100644
--- a/.htaccess
+++ b/.htaccess
@@ -1,4 +1,3 @@
-# Version: 9.0.0
<IfModule mod_headers.c>
<IfModule mod_setenvif.c>
<IfModule mod_fcgid.c>
@@ -16,6 +15,8 @@
Header set X-XSS-Protection "1; mode=block"
Header set X-Robots-Tag "none"
Header set X-Frame-Options "SAMEORIGIN"
+ Header set X-Download-Options "noopen"
+ Header set X-Permitted-Cross-Domain-Policies "none"
SetEnv modHeadersAvailable true
</IfModule>
@@ -41,11 +42,29 @@
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteRule ^\.well-known/host-meta /public.php?service=host-meta [QSA,L]
RewriteRule ^\.well-known/host-meta\.json /public.php?service=host-meta-json [QSA,L]
- RewriteRule ^\.well-known/carddav /remote.php/carddav/ [R=301,L]
- RewriteRule ^\.well-known/caldav /remote.php/caldav/ [R=301,L]
+ RewriteRule ^\.well-known/carddav /remote.php/dav/ [R=301,L]
+ RewriteRule ^\.well-known/caldav /remote.php/dav/ [R=301,L]
RewriteRule ^remote/(.*) remote.php [QSA,L]
RewriteRule ^(build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
+ RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/.*
RewriteRule ^(\.|autotest|occ|issue|indie|db_|console).* - [R=404,L]
+
+ # Rewrite rules for `front_controller_active`
+ Options -MultiViews
+ RewriteRule ^core/js/oc.js$ index.php/core/js/oc.js [PT,E=PATH_INFO:$1]
+ RewriteRule ^core/preview.png$ index.php/core/preview.png [PT,E=PATH_INFO:$1]
+ RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff|ico)$
+ RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
+ RewriteCond %{REQUEST_FILENAME} !/remote.php
+ RewriteCond %{REQUEST_FILENAME} !/public.php
+ RewriteCond %{REQUEST_FILENAME} !/cron.php
+ RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
+ RewriteCond %{REQUEST_FILENAME} !/status.php
+ RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
+ RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
+ RewriteCond %{REQUEST_FILENAME} !/updater/
+ RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/.*
+ RewriteRule .* index.php [PT,E=PATH_INFO:$1]
</IfModule>
<IfModule mod_mime.c>
AddType image/svg+xml svg svgz
diff --git a/.mailmap b/.mailmap
index ec69fc5318e..7d6e6c7ee5d 100644
--- a/.mailmap
+++ b/.mailmap
@@ -305,7 +305,8 @@ Robin Appelman <icewind@owncloud.com> Robin <robin@Amaya.(none)>
Robin Appelman <icewind@owncloud.com> Robin Appelman <icewind1991@gmail.com>
Robin Appelman <icewind@owncloud.com> Robin Appelman <icewind1991@gmail>
Robin Appelman <icewind@owncloud.com> Robin Appelman <robin@icewind.nl>
-Robin McCorkell <rmccorkell@karoshi.org.uk> Robin McCorkell <rmccorkell@owncloud.com>
+Robin McCorkell <robin@mccorkell.me.uk> Robin McCorkell <rmccorkell@karoshi.org.uk>
+Robin McCorkell <robin@mccorkell.me.uk> Robin McCorkell <rmccorkell@owncloud.com>
Rodrigo Hjort <rodrigo.hjort@gmail.com>
Roeland Jago Douma <rullzer@owncloud.com> Roeland Jago Douma <roeland@famdouma.nl>
rok <brejktru@gmail.com>
diff --git a/.mention-bot b/.mention-bot
new file mode 100644
index 00000000000..5997a7a03bb
--- /dev/null
+++ b/.mention-bot
@@ -0,0 +1,33 @@
+{
+ "maxReviewers": 3,
+ "numFilesToCheck": 5,
+ "alwaysNotifyForPaths": [
+ {
+ "name": "DeepDiver1975",
+ "files": [
+ "apps/dav/**"
+ ]
+ },
+ {
+ "name": "nickvergessen",
+ "files": [
+ "lib/private/activity/**",
+ "lib/private/notification/**",
+ "lib/public/activity/**",
+ "lib/public/notification/**"
+ ]
+ },
+ {
+ "name": "Xenopathic",
+ "files": [
+ "apps/files_external/**"
+ ]
+ }
+ ],
+ "userBlacklist": [
+ "owncloud-bot",
+ "scrutinizer-auto-fixer",
+ "th3fallen",
+ "zander"
+ ]
+}
diff --git a/.travis.yml b/.travis.yml
index 49a9e07e3fd..4f79311c33c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,20 +25,22 @@ before_install:
install:
- sh -c "if [ '$TEST_DAV' = '1' ]; then bash tests/travis/install.sh $DB; fi"
+ - sh -c "if [ '$TEST_DAV' = '1' ]; then bash apps/dav/tests/travis/$TC/install.sh; fi"
+
script:
- sh -c "if [ '$TEST_DAV' != '1' ]; then echo \"Not testing DAV\"; fi"
- sh -c "if [ '$TEST_DAV' = '1' ]; then echo \"Testing DAV\"; fi"
- - sh -c "if [ '$TEST_DAV' = '1' ]; then bash apps/dav/tests/travis/$TC.sh; fi"
+ - sh -c "if [ '$TEST_DAV' = '1' ]; then bash apps/dav/tests/travis/$TC/script.sh; fi"
matrix:
include:
- php: 5.4
env: DB=pgsql;TC=litmus-v1
- php: 5.4
- env: DB=pgsql;TC=carddavtester
-# - php: 5.4
-# env: DB=mysql;TC=caldavtester
+ env: DB=sqlite;TC=carddav
+ - php: 5.4
+ env: DB=sqlite;TC=caldav
fast_finish: true
diff --git a/3rdparty b/3rdparty
-Subproject be700d4918627e06eb3e8c5f3b025911061badf
+Subproject 7e0c3708d7b44a132e2e360fd39a663af7c1f13
diff --git a/AUTHORS b/AUTHORS
index efcc7efd127..95306f5df45 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -4,6 +4,7 @@ ownCloud is written by:
- Administrator <Administrator@WINDOWS-2012>
- Aldo "xoen" Giambelluca <xoen@xoen.org>
- Alexander Bergolth <leo@strike.wu.ac.at>
+ - Andreas Böhler <dev@aboehler.at>
- Andreas Ergenzinger <andreas.ergenzinger@gmx.de>
- Andreas Fischer <bantu@owncloud.com>
- Andrew Brown <andrew@casabrown.com>
@@ -25,6 +26,8 @@ ownCloud is written by:
- Christian Berendt <berendt@b1-systems.de>
- Christian Kampka <christian@kampka.net>
- Christian Reiner <github@christian-reiner.info>
+ - Christian Schnidrig <christian.schnidrig@switch.ch>
+ - Christian Weiske <cweiske@cweiske.de>
- Christopher Schäpers <kondou@ts.unde.re>
- Christopher T. Johnson <ctjctj@gmail.com>
- Clark Tomlinson <fallen013@gmail.com>
@@ -33,9 +36,9 @@ ownCloud is written by:
- Daniel Hansson <enoch85@gmail.com>
- Daniel Molkentin <daniel@molkentin.de>
- David Prévot <taffit@debian.org>
- - David Reagan <reagand@lanecc.edu>
- Dominik Schmidt <dev@dominik-schmidt.de>
- Donald Buczek <buczek@molgen.mpg.de>
+ - Edward Crompton <edward.crompton@gmail.com>
- Fabian Henze <flyser42@gmx.de>
- Felix Böhm <felixboehm@gmx.de>
- Felix Moeller <mail@felixmoeller.de>
@@ -50,6 +53,7 @@ ownCloud is written by:
- Georg Ehrke <georg@owncloud.com>
- Guillaume AMAT <guillaume.amat@informatique-libre.com>
- Hasso Tepper <hasso@zone.ee>
+ - Hendrik Leppelsack <hendrik@leppelsack.de>
- Hugo Gonzalez Labrador <hglavra@gmail.com>
- Individual IT Services <info@individual-it.net>
- Jakob Sack <mail@jakobsack.de>
@@ -57,6 +61,7 @@ ownCloud is written by:
- Jean-Louis Dupond <jean-louis@dupond.be>
- Jens-Christian Fischer <jens-christian.fischer@switch.ch>
- Jesus Macias <jmacias@full-on-net.com>
+ - Jesús Macias <jmacias@solidgear.es>
- Joas Schilling <nickvergessen@owncloud.com>
- Johan Björk <johanimon@gmail.com>
- Johannes Willnecker <johannes@willnecker.com>
@@ -73,13 +78,13 @@ ownCloud is written by:
- Lukas Reschke <lukas@owncloud.com>
- Luke Policinski <lpolicinski@gmail.com>
- Lyonel Vincent <lyonel@ezix.org>
+ - Mario Kolling <mario.kolling@serpro.gov.br>
- Markus Goetz <markus@woboq.com>
- Martin Konrad <info@martin-konrad.net>
- Martin Konrad <konrad@frib.msu.edu>
- Martin Mattel <martin.mattel@diemattels.at>
- Marvin Thomas Rabe <mrabe@marvinrabe.de>
- Masaki Kawabata Neto <masaki.kawabata@gmail.com>
- - Matthias Rieber <matthias@zu-con.org>
- Michael Gapczynski <GapczynskiM@gmail.com>
- Michael Göhler <somebody.here@gmx.de>
- Michael Kuhn <suraia@ikkoku.de>
@@ -87,6 +92,7 @@ ownCloud is written by:
- Michael Roth <michael.roth@rz.uni-augsburg.de>
- Michael Telatynski <7t3chguy@gmail.com>
- Miguel Prokop <miguel.prokop@vtu.com>
+ - Mitar <mitar.git@tnode.com>
- Morris Jobke <hey@morrisjobke.de>
- Nicolai Ehemann <en@enlightened.de>
- Nicolas Grekas <nicolas.grekas@gmail.com>
@@ -105,13 +111,16 @@ ownCloud is written by:
- Philippe Jung <phil.jung@free.fr>
- Philippe Le Brouster <plb@nebkha.net>
- Qingping Hou <dave2008713@gmail.com>
+ - Raghu Nayyar <hey@raghunayyar.com>
- Raghu Nayyar <me@iraghu.com>
+ - Ralph Krimmel <rkrimme1@gwdg.de>
- Ramiro Aparicio <rapariciog@gmail.com>
- Randolph Carter <RandolphCarter@fantasymail.de>
- RealRancor <Fisch.666@gmx.de>
- Remco Brenninkmeijer <requist1@starmail.nl>
+ - Renaud Fortier <Renaud.Fortier@fsaa.ulaval.ca>
- Robin Appelman <icewind@owncloud.com>
- - Robin McCorkell <rmccorkell@karoshi.org.uk>
+ - Robin McCorkell <robin@mccorkell.me.uk>
- Roeland Jago Douma <rullzer@owncloud.com>
- Roman Geber <rgeber@owncloudapps.com>
- Ross Nicoll <jrn@jrn.me.uk>
@@ -135,16 +144,15 @@ ownCloud is written by:
- Thomas Schmidt <tschmidt@suse.de>
- Thomas Tanghus <thomas@tanghus.net>
- Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
+ - Tim Dettrick <t.dettrick@uq.edu.au>
- Tobia De Koninck <tobia@ledfan.be>
- Tobias Kaminsky <tobias@kaminsky.me>
- Tom Needham <tom@owncloud.com>
- - Valerio Ponte <valerio.ponte@gmail.com>
- Victor Dubiniuk <dubiniuk@owncloud.com>
- Viktor Szépe <viktor@szepe.net>
- Vincent Cloutier <vincent1cloutier@gmail.com>
- Vincent Petry <pvince81@owncloud.com>
- Volkan Gezer <volkangezer@gmail.com>
- - Volker Fröhlich <volker27@gmx.at>
- adrien <adrien.waksberg@believedigital.com>
- brumsel <brumsel@losecatcher.de>
- cetra3 <peter@parashift.com.au>
@@ -152,19 +160,18 @@ ownCloud is written by:
- dampfklon <me@dampfklon.de>
- davidgumberg <davidnoizgumberg@gmail.com>
- derkostka <sebastian.kostka@gmail.com>
- - drarko <drarko@users.noreply.github.com>
- eduardo <eduardo@vnexu.net>
- fabian <fabian@web2.0-apps.de>
- goodkiller <markopraakli@gmail.com>
- helix84 <helix84@centrum.sk>
- hkjolhede <hkjolhede@gmail.com>
- ideaship <ideaship@users.noreply.github.com>
- - itheiss <ingo.theiss@i-matrixx.de>
- j-ed <juergen@eisfair.org>
- jknockaert <jasper@knockaert.nl>
- macjohnny <estebanmarin@gmx.ch>
- marc0s <marcos@tenak.net>
- martin-rueegg <martin.rueegg@metaworx.ch>
+ - martin.mattel@diemattels.at <martin.mattel@diemattels.at>
- michag86 <micha_g@arcor.de>
- nishiki <nishiki@yaegashi.fr>
- root <root@oc.(none)>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ecd2b1e49e5..66d54c61e98 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -18,20 +18,8 @@ If you have questions about how to install or use ownCloud, please direct these
- [iOS client](https://github.com/owncloud/ios/issues)
- [Desktop client](https://github.com/owncloud/client/issues)
- [Documentation](https://github.com/owncloud/documentation/issues)
- - Apps:
- - [Activity](https://github.com/owncloud/activity/issues)
- - [Bookmarks](https://github.com/owncloud/bookmarks/issues)
- - [Calendar](https://github.com/owncloud/calendar/issues)
- - [Contacts](https://github.com/owncloud/contacts/issues)
- - [Documents](https://github.com/owncloud/documents/issues)
- - [Gallery](https://github.com/owncloud/gallery/issues)
- - [Mail](https://github.com/owncloud/mail/issues)
- - [Music](https://github.com/owncloud/music/issues)
- - [News](https://github.com/owncloud/news/issues)
- - [Notes](https://github.com/owncloud/notes/issues)
- - [Shorty](https://github.com/owncloud/shorty/issues)
- - [Tasks](https://github.com/owncloud/tasks/issues)
- - [All other apps](https://github.com/owncloud/apps/issues)
+ - [ownCloud apps](https://github.com/owncloud/core/wiki/Maintainers#apps-repo)
+
* Report the issue using our [template][template], it includes all the information we need to track down the issue.
Help us to maximize the effort we can spend fixing issues and adding new features, by not reporting duplicate issues.
diff --git a/README.md b/README.md
index 4dfa36237bb..c1a9043ce70 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,43 @@
-# ownCloud
+# ownCloud Core
-[ownCloud](http://ownCloud.org) gives you freedom and control over your own data.
-A personal cloud which runs on your own server.
-
-### Build Status on [Jenkins CI](https://ci.owncloud.org/)
-Git master: [![Build Status](https://ci.owncloud.org/job/server-master-linux/badge/icon)](https://ci.owncloud.org/job/server-master-linux/)
+[![Build Status](https://ci.owncloud.org/job/server-master-linux/badge/icon)](https://ci.owncloud.org/job/server-master-linux/)
+[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/owncloud/core/badges/quality-score.png?s=ce2f5ded03d4ac628e9ee5c767243fa7412e644f)](https://scrutinizer-ci.com/g/owncloud/core/)
+[![CodeClimate](https://codeclimate.com/github/owncloud/core/badges/gpa.svg)](https://codeclimate.com/github/owncloud/core)
+[![Coverity](https://scan.coverity.com/projects/6893/badge.svg)](https://scan.coverity.com/projects/owncloud-core)
+[![Dependency Status](https://www.versioneye.com/user/projects/54f4a2384f3108959a000a16/badge.svg?style=flat)](https://www.versioneye.com/user/projects/54f4a2384f3108959a000a16)
+[![Dependency Status](https://www.versioneye.com/user/projects/54d1f76f3ca0840b190000c0/badge.svg?style=flat)](https://www.versioneye.com/user/projects/54d1f76f3ca0840b190000c0)
-Quality:
- - Scrutinizer: [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/owncloud/core/badges/quality-score.png?s=ce2f5ded03d4ac628e9ee5c767243fa7412e644f)](https://scrutinizer-ci.com/g/owncloud/core/)
- - CodeClimate: [![Code Climate](https://codeclimate.com/github/owncloud/core/badges/gpa.svg)](https://codeclimate.com/github/owncloud/core)
- - Coverity: [![Coverity](https://scan.coverity.com/projects/6893/badge.svg)](https://scan.coverity.com/projects/owncloud-core)
+**[ownCloud](http://ownCloud.org) gives you freedom and control over your own data.
+A personal cloud which runs on your own server.**
-Dependencies:
+![](https://github.com/owncloud/screenshots/blob/master/files/sidebar_1.png)
-[![Dependency Status](https://www.versioneye.com/user/projects/54f4a2384f3108959a000a16/badge.svg?style=flat)](https://www.versioneye.com/user/projects/54f4a2384f3108959a000a16)
+## Why is this so awesome?
+* :file_folder: **Access your Data** You can store your files, contacts, calendars and more on a server of your choosing.
+* :package: **Sync your Data** You keep your files, contacts, calendars and more synchronized amongst your devices.
+* :arrows_counterclockwise: **Share your Data** You share your data with others, and give them access to your latest photo galleries, your calendar or anything else you want them to see.
+* :rocket: **Expandable with dozens of Apps** ...like Calendar, Contacts, Mail or News.
+* :cloud: **All Benefits of the Cloud** ...on your own Server.
+* :lock: **Encryption** You can encrypt data in transit with secure https connections. You can enable the encryption app to encrypt data on storage for improved security and privacy.
+* ...
-[![Dependency Status](https://www.versioneye.com/user/projects/54d1f76f3ca0840b190000c0/badge.svg?style=flat)](https://www.versioneye.com/user/projects/54d1f76f3ca0840b190000c0)
-
-### Installation instructions
+## Installation instructions
https://doc.owncloud.org/server/9.0/developer_manual/app/index.html
-### Contribution Guidelines
+## Contribution Guidelines
https://owncloud.org/contribute/
-### Get in touch
-* [Forum](https://forum.owncloud.org)
-* [Mailing list](https://mailman.owncloud.org/mailman/listinfo)
-* [IRC channel](https://webchat.freenode.net/?channels=owncloud)
-* [Twitter](https://twitter.com/ownClouders)
+## Support
+Learn about the diffrent ways you can get support for ownCloud: https://owncloud.org/support/
+
+## Get in touch
+* :clipboard: [Forum](https://forum.owncloud.org)
+* :envelope: [Mailing list](https://mailman.owncloud.org/mailman/listinfo)
+* :hash: [IRC channel](https://webchat.freenode.net/?channels=owncloud)
+* :busts_in_silhouette: [Facebook] (https://facebook.com/ownclouders)
+* :hatching_chick: [Twitter](https://twitter.com/ownClouders)
-### Important notice on translations
+## Important notice on translations
Please submit translations via Transifex:
https://www.transifex.com/projects/p/owncloud/
diff --git a/apps/comments/appinfo/app.php b/apps/comments/appinfo/app.php
new file mode 100644
index 00000000000..a1eb4f6899d
--- /dev/null
+++ b/apps/comments/appinfo/app.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+$eventDispatcher = \OC::$server->getEventDispatcher();
+$eventDispatcher->addListener(
+ 'OCA\Files::loadAdditionalScripts',
+ function() {
+ \OCP\Util::addScript('oc-backbone-webdav');
+ \OCP\Util::addScript('comments', 'app');
+ \OCP\Util::addScript('comments', 'commentmodel');
+ \OCP\Util::addScript('comments', 'commentcollection');
+ \OCP\Util::addScript('comments', 'commentsummarymodel');
+ \OCP\Util::addScript('comments', 'commentstabview');
+ \OCP\Util::addScript('comments', 'filesplugin');
+ \OCP\Util::addStyle('comments', 'comments');
+ }
+);
diff --git a/apps/comments/appinfo/info.xml b/apps/comments/appinfo/info.xml
new file mode 100644
index 00000000000..f3693150639
--- /dev/null
+++ b/apps/comments/appinfo/info.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<info>
+ <id>comments</id>
+ <name>Comments</name>
+ <description>Files app plugin to add comments to files</description>
+ <licence>AGPL</licence>
+ <author>Arthur Shiwon, Vincent Petry</author>
+ <default_enable/>
+ <version>0.1</version>
+ <dependencies>
+ <owncloud min-version="9.0" max-version="9.0" />
+ </dependencies>
+</info>
diff --git a/apps/comments/css/comments.css b/apps/comments/css/comments.css
new file mode 100644
index 00000000000..b86ed38efe7
--- /dev/null
+++ b/apps/comments/css/comments.css
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+#commentsTabView .newCommentForm {
+ margin-bottom: 20px;
+}
+
+#commentsTabView .newCommentForm .message {
+ width: 90%;
+ resize: none;
+}
+
+#commentsTabView .newCommentForm .submitLoading {
+ background-position: left;
+}
+
+#commentsTabView .comment {
+ margin-bottom: 30px;
+}
+
+#commentsTabView .comment .avatar {
+ width: 28px;
+ height: 28px;
+ line-height: 28px;
+}
+
+#commentsTabView .authorRow>div {
+ display: inline-block;
+ vertical-align: middle;
+}
+
+#commentsTabView .comment .authorRow {
+ margin-bottom: 5px;
+ position: relative;
+}
+
+#commentsTabView .comment .author {
+ font-weight: bold;
+}
+
+#commentsTabView .comment .date {
+ position: absolute;
+ right: 0;
+}
+
+#commentsTabView .comment .action {
+ opacity: 0;
+ vertical-align: middle;
+ display: inline-block;
+}
+
+#commentsTabView .comment:hover .action {
+ opacity: 0.3;
+}
+
+#commentsTabView .comment .action:hover {
+ opacity: 1;
+}
+
+#commentsTabView .comment .action.delete {
+ position: absolute;
+ right: 0;
+}
+
+#commentsTabView .comment.disabled {
+ opacity: 0.3;
+}
+
+#commentsTabView .comment.disabled .action {
+ visibility: hidden;
+}
+
+.app-files .action-comment>img {
+ margin-right: 5px;
+}
diff --git a/apps/comments/js/app.js b/apps/comments/js/app.js
new file mode 100644
index 00000000000..547059393a5
--- /dev/null
+++ b/apps/comments/js/app.js
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2016 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function() {
+ if (!OCA.Comments) {
+ /**
+ * @namespace
+ */
+ OCA.Comments = {};
+ }
+
+})();
+
diff --git a/apps/comments/js/commentcollection.js b/apps/comments/js/commentcollection.js
new file mode 100644
index 00000000000..a15039cf484
--- /dev/null
+++ b/apps/comments/js/commentcollection.js
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC, OCA) {
+
+ /**
+ * @class OCA.Comments.CommentCollection
+ * @classdesc
+ *
+ * Collection of comments assigned to a file
+ *
+ */
+ var CommentCollection = OC.Backbone.Collection.extend(
+ /** @lends OCA.Comments.CommentCollection.prototype */ {
+
+ sync: OC.Backbone.davSync,
+
+ model: OCA.Comments.CommentModel,
+
+ /**
+ * Object type
+ *
+ * @type string
+ */
+ _objectType: 'files',
+
+ /**
+ * Object id
+ *
+ * @type string
+ */
+ _objectId: null,
+
+ /**
+ * True if there are no more page results left to fetch
+ *
+ * @type bool
+ */
+ _endReached: false,
+
+ /**
+ * Number of comments to fetch per page
+ *
+ * @type int
+ */
+ _limit : 20,
+
+ /**
+ * Initializes the collection
+ *
+ * @param {string} [options.objectType] object type
+ * @param {string} [options.objectId] object id
+ */
+ initialize: function(models, options) {
+ options = options || {};
+ if (options.objectType) {
+ this._objectType = options.objectType;
+ }
+ if (options.objectId) {
+ this._objectId = options.objectId;
+ }
+ },
+
+ url: function() {
+ return OC.linkToRemote('dav') + '/comments/' +
+ encodeURIComponent(this._objectType) + '/' +
+ encodeURIComponent(this._objectId) + '/';
+ },
+
+ setObjectId: function(objectId) {
+ this._objectId = objectId;
+ },
+
+ hasMoreResults: function() {
+ return !this._endReached;
+ },
+
+ reset: function() {
+ this._endReached = false;
+ this._summaryModel = null;
+ return OC.Backbone.Collection.prototype.reset.apply(this, arguments);
+ },
+
+ /**
+ * Fetch the next set of results
+ */
+ fetchNext: function(options) {
+ var self = this;
+ if (!this.hasMoreResults()) {
+ return null;
+ }
+
+ var body = '<?xml version="1.0" encoding="utf-8" ?>\n' +
+ '<oc:filter-comments xmlns:D="DAV:" xmlns:oc="http://owncloud.org/ns">\n' +
+ // load one more so we know there is more
+ ' <oc:limit>' + (this._limit + 1) + '</oc:limit>\n' +
+ ' <oc:offset>' + this.length + '</oc:offset>\n' +
+ '</oc:filter-comments>\n';
+
+ options = options || {};
+ var success = options.success;
+ options = _.extend({
+ remove: false,
+ parse: true,
+ data: body,
+ davProperties: CommentCollection.prototype.model.prototype.davProperties,
+ success: function(resp) {
+ if (resp.length <= self._limit) {
+ // no new entries, end reached
+ self._endReached = true;
+ } else {
+ // remove last entry, for next page load
+ resp = _.initial(resp);
+ }
+ if (!self.set(resp, options)) {
+ return false;
+ }
+ if (success) {
+ success.apply(null, arguments);
+ }
+ self.trigger('sync', 'REPORT', self, options);
+ }
+ }, options);
+
+ return this.sync('REPORT', this, options);
+ },
+
+ /**
+ * Returns the matching summary model
+ *
+ * @return {OCA.Comments.CommentSummaryModel} summary model
+ */
+ getSummaryModel: function() {
+ if (!this._summaryModel) {
+ this._summaryModel = new OCA.Comments.CommentSummaryModel({
+ id: this._objectId,
+ objectType: this._objectType
+ });
+ }
+ return this._summaryModel;
+ },
+
+ /**
+ * Updates the read marker for this comment thread
+ *
+ * @param {Date} [date] optional date, defaults to now
+ * @param {Object} [options] backbone options
+ */
+ updateReadMarker: function(date, options) {
+ options = options || {};
+
+ return this.getSummaryModel().save({
+ readMarker: (date || new Date()).toUTCString()
+ }, options);
+ }
+ });
+
+ OCA.Comments.CommentCollection = CommentCollection;
+})(OC, OCA);
+
diff --git a/apps/comments/js/commentmodel.js b/apps/comments/js/commentmodel.js
new file mode 100644
index 00000000000..89492707b61
--- /dev/null
+++ b/apps/comments/js/commentmodel.js
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC, OCA) {
+ var NS_OWNCLOUD = 'http://owncloud.org/ns';
+ /**
+ * @class OCA.Comments.CommentModel
+ * @classdesc
+ *
+ * Comment
+ *
+ */
+ var CommentModel = OC.Backbone.Model.extend(
+ /** @lends OCA.Comments.CommentModel.prototype */ {
+ sync: OC.Backbone.davSync,
+
+ defaults: {
+ actorType: 'users',
+ objectType: 'files'
+ },
+
+ davProperties: {
+ 'id': '{' + NS_OWNCLOUD + '}id',
+ 'message': '{' + NS_OWNCLOUD + '}message',
+ 'actorType': '{' + NS_OWNCLOUD + '}actorType',
+ 'actorId': '{' + NS_OWNCLOUD + '}actorId',
+ 'actorDisplayName': '{' + NS_OWNCLOUD + '}actorDisplayName',
+ 'creationDateTime': '{' + NS_OWNCLOUD + '}creationDateTime',
+ 'objectType': '{' + NS_OWNCLOUD + '}objectType',
+ 'objectId': '{' + NS_OWNCLOUD + '}objectId',
+ 'isUnread': '{' + NS_OWNCLOUD + '}isUnread'
+ },
+
+ parse: function(data) {
+ return {
+ id: data.id,
+ message: data.message,
+ actorType: data.actorType,
+ actorId: data.actorId,
+ actorDisplayName: data.actorDisplayName,
+ creationDateTime: data.creationDateTime,
+ objectType: data.objectType,
+ objectId: data.objectId,
+ isUnread: (data.isUnread === 'true')
+ };
+ }
+ });
+
+ OCA.Comments.CommentModel = CommentModel;
+})(OC, OCA);
+
diff --git a/apps/comments/js/commentstabview.js b/apps/comments/js/commentstabview.js
new file mode 100644
index 00000000000..8faf98b35ab
--- /dev/null
+++ b/apps/comments/js/commentstabview.js
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+/* global Handlebars */
+
+(function(OC, OCA) {
+ var TEMPLATE =
+ '<ul class="comments">' +
+ '</ul>' +
+ '<div class="empty hidden">{{emptyResultLabel}}</div>' +
+ '<input type="button" class="showMore hidden" value="{{moreLabel}}"' +
+ ' name="show-more" id="show-more" />' +
+ '<div class="loading hidden" style="height: 50px"></div>';
+
+ var EDIT_COMMENT_TEMPLATE =
+ '<div class="newCommentRow comment" data-id="{{id}}">' +
+ ' <div class="authorRow">' +
+ ' {{#if avatarEnabled}}' +
+ ' <div class="avatar" data-username="{{actorId}}"></div>' +
+ ' {{/if}}' +
+ ' <div class="author">{{actorDisplayName}}</div>' +
+ '{{#if isEditMode}}' +
+ ' <a href="#" class="action delete icon icon-delete has-tooltip" title="{{deleteTooltip}}"></a>' +
+ '{{/if}}' +
+ ' </div>' +
+ ' <form class="newCommentForm">' +
+ ' <textarea class="message" placeholder="{{newMessagePlaceholder}}">{{{message}}}</textarea>' +
+ ' <input class="submit" type="submit" value="{{submitText}}" />' +
+ '{{#if isEditMode}}' +
+ ' <input class="cancel" type="button" value="{{cancelText}}" />' +
+ '{{/if}}' +
+ ' <div class="submitLoading icon-loading-small hidden"></div>'+
+ ' </form>' +
+ '</div>';
+
+ var COMMENT_TEMPLATE =
+ '<li class="comment{{#if isUnread}} unread{{/if}}" data-id="{{id}}">' +
+ ' <div class="authorRow">' +
+ ' {{#if avatarEnabled}}' +
+ ' <div class="avatar" {{#if actorId}}data-username="{{actorId}}"{{/if}}> </div>' +
+ ' {{/if}}' +
+ ' <div class="author">{{actorDisplayName}}</div>' +
+ '{{#if isUserAuthor}}' +
+ ' <a href="#" class="action edit icon icon-rename has-tooltip" title="{{editTooltip}}"></a>' +
+ '{{/if}}' +
+ ' <div class="date has-tooltip" title="{{altDate}}">{{date}}</div>' +
+ ' </div>' +
+ ' <div class="message">{{{formattedMessage}}}</div>' +
+ '</li>';
+
+ /**
+ * @memberof OCA.Comments
+ */
+ var CommentsTabView = OCA.Files.DetailTabView.extend(
+ /** @lends OCA.Comments.CommentsTabView.prototype */ {
+ id: 'commentsTabView',
+ className: 'tab commentsTabView',
+
+ events: {
+ 'submit .newCommentForm': '_onSubmitComment',
+ 'click .showMore': '_onClickShowMore',
+ 'click .action.edit': '_onClickEditComment',
+ 'click .action.delete': '_onClickDeleteComment',
+ 'click .cancel': '_onClickCloseComment'
+ },
+
+ initialize: function() {
+ OCA.Files.DetailTabView.prototype.initialize.apply(this, arguments);
+ this.collection = new OCA.Comments.CommentCollection();
+ this.collection.on('request', this._onRequest, this);
+ this.collection.on('sync', this._onEndRequest, this);
+ this.collection.on('add', this._onAddModel, this);
+
+ this._avatarsEnabled = !!OC.config.enable_avatars;
+
+ // TODO: error handling
+ },
+
+ template: function(params) {
+ if (!this._template) {
+ this._template = Handlebars.compile(TEMPLATE);
+ }
+ var currentUser = OC.getCurrentUser();
+ return this._template(_.extend({
+ avatarEnabled: this._avatarsEnabled,
+ actorId: currentUser.uid,
+ actorDisplayName: currentUser.displayName
+ }, params));
+ },
+
+ editCommentTemplate: function(params) {
+ if (!this._editCommentTemplate) {
+ this._editCommentTemplate = Handlebars.compile(EDIT_COMMENT_TEMPLATE);
+ }
+ var currentUser = OC.getCurrentUser();
+ return this._editCommentTemplate(_.extend({
+ avatarEnabled: this._avatarsEnabled,
+ actorId: currentUser.uid,
+ actorDisplayName: currentUser.displayName,
+ newMessagePlaceholder: t('comments', 'Type in a new comment...'),
+ deleteTooltip: t('comments', 'Delete comment'),
+ submitText: t('comments', 'Post'),
+ cancelText: t('comments', 'Cancel')
+ }, params));
+ },
+
+ commentTemplate: function(params) {
+ if (!this._commentTemplate) {
+ this._commentTemplate = Handlebars.compile(COMMENT_TEMPLATE);
+ }
+
+ params = _.extend({
+ avatarEnabled: this._avatarsEnabled,
+ editTooltip: t('comments', 'Edit comment'),
+ isUserAuthor: OC.getCurrentUser().uid === params.actorId
+ }, params);
+
+ if (params.actorType === 'deleted_users') {
+ // makes the avatar a X
+ params.actorId = null;
+ params.actorDisplayName = t('comments', '[Deleted user]');
+ }
+
+ return this._commentTemplate(params);
+ },
+
+ getLabel: function() {
+ return t('comments', 'Comments');
+ },
+
+ setFileInfo: function(fileInfo) {
+ if (fileInfo) {
+ this.model = fileInfo;
+ this.render();
+ this.collection.setObjectId(fileInfo.id);
+ // reset to first page
+ this.collection.reset([], {silent: true});
+ this.nextPage();
+ } else {
+ this.model = null;
+ this.render();
+ this.collection.reset();
+ }
+ },
+
+ render: function() {
+ this.$el.html(this.template({
+ emptyResultLabel: t('comments', 'No other comments available'),
+ moreLabel: t('comments', 'More comments...')
+ }));
+ this.$el.find('.comments').before(this.editCommentTemplate({}));
+ this.$el.find('.has-tooltip').tooltip();
+ this.$container = this.$el.find('ul.comments');
+ if (this._avatarsEnabled) {
+ this.$el.find('.avatar').avatar(OC.getCurrentUser().uid, 28);
+ }
+ this.delegateEvents();
+ },
+
+ _formatItem: function(commentModel) {
+ var timestamp = new Date(commentModel.get('creationDateTime')).getTime();
+ var data = _.extend({
+ date: OC.Util.relativeModifiedDate(timestamp),
+ altDate: OC.Util.formatDate(timestamp),
+ formattedMessage: this._formatMessage(commentModel.get('message'))
+ }, commentModel.attributes);
+ return data;
+ },
+
+ _toggleLoading: function(state) {
+ this._loading = state;
+ this.$el.find('.loading').toggleClass('hidden', !state);
+ },
+
+ _onRequest: function(type) {
+ if (type === 'REPORT') {
+ this._toggleLoading(true);
+ this.$el.find('.showMore').addClass('hidden');
+ }
+ },
+
+ _onEndRequest: function(type) {
+ var fileInfoModel = this.model;
+ this._toggleLoading(false);
+ this.$el.find('.empty').toggleClass('hidden', !!this.collection.length);
+ this.$el.find('.showMore').toggleClass('hidden', !this.collection.hasMoreResults());
+
+ if (type !== 'REPORT') {
+ return;
+ }
+
+ // find first unread comment
+ var firstUnreadComment = this.collection.findWhere({isUnread: true});
+ if (firstUnreadComment) {
+ // update read marker
+ this.collection.updateReadMarker(
+ null,
+ {
+ success: function() {
+ fileInfoModel.set('commentsUnread', 0);
+ }
+ }
+ );
+ }
+ },
+
+ _onAddModel: function(model, collection, options) {
+ var $el = $(this.commentTemplate(this._formatItem(model)));
+ if (!_.isUndefined(options.at) && collection.length > 1) {
+ this.$container.find('li').eq(options.at).before($el);
+ } else {
+ this.$container.append($el);
+ }
+
+ this._postRenderItem($el);
+ },
+
+ _postRenderItem: function($el) {
+ $el.find('.has-tooltip').tooltip();
+ if(this._avatarsEnabled) {
+ $el.find('.avatar').each(function() {
+ var $this = $(this);
+ $this.avatar($this.attr('data-username'), 28);
+ });
+ }
+ },
+
+ /**
+ * Convert a message to be displayed in HTML,
+ * converts newlines to <br> tags.
+ */
+ _formatMessage: function(message) {
+ return escapeHTML(message).replace(/\n/g, '<br/>');
+ },
+
+ nextPage: function() {
+ if (this._loading || !this.collection.hasMoreResults()) {
+ return;
+ }
+
+ this.collection.fetchNext();
+ },
+
+ _onClickEditComment: function(ev) {
+ ev.preventDefault();
+ var $comment = $(ev.target).closest('.comment');
+ var commentId = $comment.data('id');
+ var commentToEdit = this.collection.get(commentId);
+ var $formRow = $(this.editCommentTemplate(_.extend({
+ isEditMode: true,
+ submitText: t('comments', 'Save')
+ }, commentToEdit.attributes)));
+
+ $comment.addClass('hidden');
+ // spawn form
+ $comment.after($formRow);
+ $formRow.data('commentEl', $comment);
+
+ // copy avatar element from original to avoid flickering
+ $formRow.find('.avatar').replaceWith($comment.find('.avatar').clone());
+ $formRow.find('.has-tooltip').tooltip();
+
+ return false;
+ },
+
+ _onClickCloseComment: function(ev) {
+ ev.preventDefault();
+ var $row = $(ev.target).closest('.comment');
+ $row.data('commentEl').removeClass('hidden');
+ $row.remove();
+ return false;
+ },
+
+ _onClickDeleteComment: function(ev) {
+ ev.preventDefault();
+ var $comment = $(ev.target).closest('.comment');
+ var commentId = $comment.data('id');
+ var $loading = $comment.find('.submitLoading');
+
+ $comment.addClass('disabled');
+ $loading.removeClass('hidden');
+ this.collection.get(commentId).destroy({
+ success: function() {
+ $comment.data('commentEl').remove();
+ $comment.remove();
+ },
+ error: function(msg) {
+ $loading.addClass('hidden');
+ $comment.removeClass('disabled');
+ OC.Notification.showTemporary(msg);
+ }
+ });
+
+
+ return false;
+ },
+
+ _onClickShowMore: function(ev) {
+ ev.preventDefault();
+ this.nextPage();
+ },
+
+ _onSubmitComment: function(e) {
+ var self = this;
+ var $form = $(e.target);
+ var commentId = $form.closest('.comment').data('id');
+ var currentUser = OC.getCurrentUser();
+ var $submit = $form.find('.submit');
+ var $loading = $form.find('.submitLoading');
+ var $textArea = $form.find('textarea');
+ var message = $textArea.val().trim();
+ e.preventDefault();
+
+ if (!message.length) {
+ return;
+ }
+
+ $textArea.prop('disabled', true);
+ $submit.addClass('hidden');
+ $loading.removeClass('hidden');
+
+ if (commentId) {
+ // edit mode
+ var comment = this.collection.get(commentId);
+ comment.save({
+ message: $textArea.val()
+ }, {
+ success: function(model) {
+ var $row = $form.closest('.comment');
+ $submit.removeClass('hidden');
+ $loading.addClass('hidden');
+ $row.data('commentEl')
+ .removeClass('hidden')
+ .find('.message')
+ .html(self._formatMessage(model.get('message')));
+ $row.remove();
+ },
+ error: function(msg) {
+ $submit.removeClass('hidden');
+ $loading.addClass('hidden');
+ $textArea.prop('disabled', false);
+
+ OC.Notification.showTemporary(msg);
+ }
+ });
+ } else {
+ this.collection.create({
+ actorId: currentUser.uid,
+ actorDisplayName: currentUser.displayName,
+ actorType: 'users',
+ verb: 'comment',
+ message: $textArea.val(),
+ creationDateTime: (new Date()).toUTCString()
+ }, {
+ at: 0,
+ // wait for real creation before adding
+ wait: true,
+ success: function() {
+ $submit.removeClass('hidden');
+ $loading.addClass('hidden');
+ $textArea.val('').prop('disabled', false);
+ },
+ error: function(msg) {
+ $submit.removeClass('hidden');
+ $loading.addClass('hidden');
+ $textArea.prop('disabled', false);
+
+ OC.Notification.showTemporary(msg);
+ }
+ });
+ }
+
+ return false;
+ }
+ });
+
+ OCA.Comments.CommentsTabView = CommentsTabView;
+})(OC, OCA);
+
diff --git a/apps/comments/js/commentsummarymodel.js b/apps/comments/js/commentsummarymodel.js
new file mode 100644
index 00000000000..d405315ca1f
--- /dev/null
+++ b/apps/comments/js/commentsummarymodel.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC, OCA) {
+ var NS_OWNCLOUD = 'http://owncloud.org/ns';
+ /**
+ * @class OCA.Comments.CommentSummaryModel
+ * @classdesc
+ *
+ * Model containing summary information related to comments
+ * like the read marker.
+ *
+ */
+ var CommentSummaryModel = OC.Backbone.Model.extend(
+ /** @lends OCA.Comments.CommentSummaryModel.prototype */ {
+ sync: OC.Backbone.davSync,
+
+ /**
+ * Object type
+ *
+ * @type string
+ */
+ _objectType: 'files',
+
+ /**
+ * Object id
+ *
+ * @type string
+ */
+ _objectId: null,
+
+ davProperties: {
+ 'readMarker': '{' + NS_OWNCLOUD + '}readMarker'
+ },
+
+ /**
+ * Initializes the summary model
+ *
+ * @param {string} [options.objectType] object type
+ * @param {string} [options.objectId] object id
+ */
+ initialize: function(attrs, options) {
+ options = options || {};
+ if (options.objectType) {
+ this._objectType = options.objectType;
+ }
+ },
+
+ url: function() {
+ return OC.linkToRemote('dav') + '/comments/' +
+ encodeURIComponent(this._objectType) + '/' +
+ encodeURIComponent(this.id) + '/';
+ }
+ });
+
+ OCA.Comments.CommentSummaryModel = CommentSummaryModel;
+})(OC, OCA);
+
diff --git a/apps/comments/js/filesplugin.js b/apps/comments/js/filesplugin.js
new file mode 100644
index 00000000000..bf6bb05146b
--- /dev/null
+++ b/apps/comments/js/filesplugin.js
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+/* global Handlebars */
+
+(function() {
+ var TEMPLATE_COMMENTS_UNREAD =
+ '<a class="action action-comment permanent" title="{{countMessage}}" href="#">' +
+ '<img class="svg" src="{{iconUrl}}"/>' +
+ '{{count}}' +
+ '</a>';
+
+ OCA.Comments = _.extend({}, OCA.Comments);
+ if (!OCA.Comments) {
+ /**
+ * @namespace
+ */
+ OCA.Comments = {};
+ }
+
+ /**
+ * @namespace
+ */
+ OCA.Comments.FilesPlugin = {
+ allowedLists: [
+ 'files',
+ 'favorites'
+ ],
+
+ _formatCommentCount: function(count) {
+ if (!this._commentsUnreadTemplate) {
+ this._commentsUnreadTemplate = Handlebars.compile(TEMPLATE_COMMENTS_UNREAD);
+ }
+ return this._commentsUnreadTemplate({
+ count: count,
+ countMessage: t('comments', '{count} unread comments', {count: count}),
+ iconUrl: OC.imagePath('core', 'actions/comment')
+ });
+ },
+
+ attach: function(fileList) {
+ var self = this;
+ if (this.allowedLists.indexOf(fileList.id) < 0) {
+ return;
+ }
+
+ fileList.registerTabView(new OCA.Comments.CommentsTabView('commentsTabView'));
+
+ var NS_OC = 'http://owncloud.org/ns';
+
+ var oldGetWebdavProperties = fileList._getWebdavProperties;
+ fileList._getWebdavProperties = function() {
+ var props = oldGetWebdavProperties.apply(this, arguments);
+ props.push('{' + NS_OC + '}comments-unread');
+ return props;
+ };
+
+ fileList.filesClient.addFileInfoParser(function(response) {
+ var data = {};
+ var props = response.propStat[0].properties;
+ var commentsUnread = props['{' + NS_OC + '}comments-unread'];
+ if (!_.isUndefined(commentsUnread) && commentsUnread !== '') {
+ data.commentsUnread = parseInt(commentsUnread, 10);
+ }
+ return data;
+ });
+
+ fileList.$el.addClass('has-comments');
+ var oldCreateRow = fileList._createRow;
+ fileList._createRow = function(fileData) {
+ var $tr = oldCreateRow.apply(this, arguments);
+ if (fileData.commentsUnread) {
+ $tr.attr('data-comments-unread', fileData.commentsUnread);
+ }
+ return $tr;
+ };
+
+ // register "comment" action for reading comments
+ fileList.fileActions.registerAction({
+ name: 'Comment',
+ displayName: t('comments', 'Comment'),
+ mime: 'all',
+ permissions: OC.PERMISSION_READ,
+ type: OCA.Files.FileActions.TYPE_INLINE,
+ render: function(actionSpec, isDefault, context) {
+ var $file = context.$file;
+ var unreadComments = $file.data('comments-unread');
+ if (unreadComments) {
+ var $actionLink = $(self._formatCommentCount(unreadComments));
+ context.$file.find('a.name>span.fileactions').append($actionLink);
+ return $actionLink;
+ }
+ return '';
+ },
+ actionHandler: function(fileName, context) {
+ context.$file.find('.action-comment').tooltip('hide');
+ // open sidebar in comments section
+ context.fileList.showDetailsView(fileName, 'commentsTabView');
+ }
+ });
+
+ // add attribute to "elementToFile"
+ var oldElementToFile = fileList.elementToFile;
+ fileList.elementToFile = function($el) {
+ var fileInfo = oldElementToFile.apply(this, arguments);
+ var commentsUnread = $el.data('comments-unread');
+ if (commentsUnread) {
+ fileInfo.commentsUnread = commentsUnread;
+ }
+ return fileInfo;
+ };
+ }
+ };
+
+})();
+
+OC.Plugins.register('OCA.Files.FileList', OCA.Comments.FilesPlugin);
+
diff --git a/apps/comments/tests/js/commentscollectionSpec.js b/apps/comments/tests/js/commentscollectionSpec.js
new file mode 100644
index 00000000000..2f41a272f67
--- /dev/null
+++ b/apps/comments/tests/js/commentscollectionSpec.js
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License comment 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+describe('OCA.Comments.CommentCollection', function() {
+ var CommentCollection = OCA.Comments.CommentCollection;
+ var collection, syncStub;
+ var comment1, comment2, comment3;
+
+ beforeEach(function() {
+ syncStub = sinon.stub(CommentCollection.prototype, 'sync');
+ collection = new CommentCollection();
+ collection.setObjectId(5);
+
+ comment1 = {
+ id: 1,
+ actorType: 'users',
+ actorId: 'user1',
+ actorDisplayName: 'User One',
+ objectType: 'files',
+ objectId: 5,
+ message: 'First',
+ creationDateTime: Date.UTC(2016, 1, 3, 10, 5, 0)
+ };
+ comment2 = {
+ id: 2,
+ actorType: 'users',
+ actorId: 'user2',
+ actorDisplayName: 'User Two',
+ objectType: 'files',
+ objectId: 5,
+ message: 'Second\nNewline',
+ creationDateTime: Date.UTC(2016, 1, 3, 10, 0, 0)
+ };
+ comment3 = {
+ id: 3,
+ actorType: 'users',
+ actorId: 'user3',
+ actorDisplayName: 'User Three',
+ objectType: 'files',
+ objectId: 5,
+ message: 'Third',
+ creationDateTime: Date.UTC(2016, 1, 3, 5, 0, 0)
+ };
+ });
+ afterEach(function() {
+ syncStub.restore();
+ });
+
+ it('fetches the next page', function() {
+ collection._limit = 2;
+ collection.fetchNext();
+
+ expect(syncStub.calledOnce).toEqual(true);
+ expect(syncStub.lastCall.args[0]).toEqual('REPORT');
+ var options = syncStub.lastCall.args[2];
+ expect(options.remove).toEqual(false);
+
+ var parser = new DOMParser();
+ var doc = parser.parseFromString(options.data, "application/xml");
+ expect(doc.getElementsByTagNameNS('http://owncloud.org/ns', 'limit')[0].textContent).toEqual('3');
+ expect(doc.getElementsByTagNameNS('http://owncloud.org/ns', 'offset')[0].textContent).toEqual('0');
+
+ syncStub.yieldTo('success', [comment1, comment2, comment3]);
+
+ expect(collection.length).toEqual(2);
+ expect(collection.hasMoreResults()).toEqual(true);
+
+ collection.fetchNext();
+
+ expect(syncStub.calledTwice).toEqual(true);
+ options = syncStub.lastCall.args[2];
+ doc = parser.parseFromString(options.data, "application/xml");
+ expect(doc.getElementsByTagNameNS('http://owncloud.org/ns', 'limit')[0].textContent).toEqual('3');
+ expect(doc.getElementsByTagNameNS('http://owncloud.org/ns', 'offset')[0].textContent).toEqual('2');
+
+ syncStub.yieldTo('success', [comment3]);
+
+ expect(collection.length).toEqual(3);
+ expect(collection.hasMoreResults()).toEqual(false);
+
+ collection.fetchNext();
+
+ // no further requests
+ expect(syncStub.calledTwice).toEqual(true);
+ });
+ it('resets page counted when calling reset', function() {
+ collection.fetchNext();
+
+ syncStub.yieldTo('success', [comment1]);
+
+ expect(collection.hasMoreResults()).toEqual(false);
+
+ collection.reset();
+
+ expect(collection.hasMoreResults()).toEqual(true);
+ });
+ describe('resetting read marker', function() {
+ var updateStub;
+ var clock;
+
+ beforeEach(function() {
+ updateStub = sinon.stub(OCA.Comments.CommentSummaryModel.prototype, 'save');
+ clock = sinon.useFakeTimers(Date.UTC(2016, 1, 3, 10, 5, 9));
+ });
+ afterEach(function() {
+ updateStub.restore();
+ clock.restore();
+ });
+
+ it('resets read marker to the default date', function() {
+ var successStub = sinon.stub();
+ collection.updateReadMarker(null, {
+ success: successStub
+ });
+
+ expect(updateStub.calledOnce).toEqual(true);
+ expect(updateStub.lastCall.args[0]).toEqual({
+ readMarker: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString()
+ });
+
+ updateStub.yieldTo('success');
+
+ expect(successStub.calledOnce).toEqual(true);
+ });
+ it('resets read marker to the given date', function() {
+ var successStub = sinon.stub();
+ collection.updateReadMarker(new Date(Date.UTC(2016, 1, 2, 3, 4, 5)), {
+ success: successStub
+ });
+
+ expect(updateStub.calledOnce).toEqual(true);
+ expect(updateStub.lastCall.args[0]).toEqual({
+ readMarker: new Date(Date.UTC(2016, 1, 2, 3, 4, 5)).toUTCString()
+ });
+
+ updateStub.yieldTo('success');
+
+ expect(successStub.calledOnce).toEqual(true);
+ });
+ });
+});
+
diff --git a/apps/comments/tests/js/commentstabviewSpec.js b/apps/comments/tests/js/commentstabviewSpec.js
new file mode 100644
index 00000000000..9e986899f7d
--- /dev/null
+++ b/apps/comments/tests/js/commentstabviewSpec.js
@@ -0,0 +1,374 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2016 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* comment 3 of the License, or any later comment.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+describe('OCA.Comments.CommentsTabView tests', function() {
+ var view, fileInfoModel;
+ var fetchStub;
+ var testComments;
+ var clock;
+
+ beforeEach(function() {
+ clock = sinon.useFakeTimers(Date.UTC(2016, 1, 3, 10, 5, 9));
+ fetchStub = sinon.stub(OCA.Comments.CommentCollection.prototype, 'fetchNext');
+ view = new OCA.Comments.CommentsTabView();
+ fileInfoModel = new OCA.Files.FileInfoModel({
+ id: 5,
+ name: 'One.txt',
+ mimetype: 'text/plain',
+ permissions: 31,
+ path: '/subdir',
+ size: 123456789,
+ etag: 'abcdefg',
+ mtime: Date.UTC(2016, 1, 0, 0, 0, 0)
+ });
+ view.render();
+ var comment1 = new OCA.Comments.CommentModel({
+ id: 1,
+ actorType: 'users',
+ actorId: 'user1',
+ actorDisplayName: 'User One',
+ objectType: 'files',
+ objectId: 5,
+ message: 'First',
+ creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 0)).toUTCString()
+ });
+ var comment2 = new OCA.Comments.CommentModel({
+ id: 2,
+ actorType: 'users',
+ actorId: 'user2',
+ actorDisplayName: 'User Two',
+ objectType: 'files',
+ objectId: 5,
+ message: 'Second\nNewline',
+ creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 0, 0)).toUTCString()
+ });
+
+ testComments = [comment1, comment2];
+ });
+ afterEach(function() {
+ view.remove();
+ view = undefined;
+ fetchStub.restore();
+ clock.restore();
+ });
+ describe('rendering', function() {
+ it('reloads matching comments when setting file info model', function() {
+ view.setFileInfo(fileInfoModel);
+ expect(fetchStub.calledOnce).toEqual(true);
+ });
+
+ it('renders loading icon while fetching comments', function() {
+ view.setFileInfo(fileInfoModel);
+ view.collection.trigger('request');
+
+ expect(view.$el.find('.loading').length).toEqual(1);
+ expect(view.$el.find('.comments li').length).toEqual(0);
+ });
+
+ it('renders comments', function() {
+ view.setFileInfo(fileInfoModel);
+ view.collection.set(testComments);
+
+ var $comments = view.$el.find('.comments>li');
+ expect($comments.length).toEqual(2);
+ var $item = $comments.eq(0);
+ expect($item.find('.author').text()).toEqual('User One');
+ expect($item.find('.date').text()).toEqual('seconds ago');
+ expect($item.find('.message').text()).toEqual('First');
+
+ $item = $comments.eq(1);
+ expect($item.find('.author').text()).toEqual('User Two');
+ expect($item.find('.date').text()).toEqual('5 minutes ago');
+ expect($item.find('.message').html()).toEqual('Second<br>Newline');
+ });
+
+ it('renders comments from deleted user differently', function() {
+ testComments[0].set('actorType', 'deleted_users', {silent: true});
+ view.collection.set(testComments);
+
+ var $item = view.$el.find('.comment[data-id=1]');
+ expect($item.find('.author').text()).toEqual('[Deleted user]');
+ expect($item.find('.avatar').attr('data-username')).not.toBeDefined();
+ });
+ });
+ describe('more comments', function() {
+ var hasMoreResultsStub;
+
+ beforeEach(function() {
+ view.collection.set(testComments);
+ hasMoreResultsStub = sinon.stub(OCA.Comments.CommentCollection.prototype, 'hasMoreResults');
+ });
+ afterEach(function() {
+ hasMoreResultsStub.restore();
+ });
+
+ it('shows "More comments" button when more comments are available', function() {
+ hasMoreResultsStub.returns(true);
+ view.collection.trigger('sync');
+
+ expect(view.$el.find('.showMore').hasClass('hidden')).toEqual(false);
+ });
+ it('does not show "More comments" button when more comments are available', function() {
+ hasMoreResultsStub.returns(false);
+ view.collection.trigger('sync');
+
+ expect(view.$el.find('.showMore').hasClass('hidden')).toEqual(true);
+ });
+ it('fetches and appends the next page when clicking the "More" button', function() {
+ hasMoreResultsStub.returns(true);
+
+ expect(fetchStub.notCalled).toEqual(true);
+
+ view.$el.find('.showMore').click();
+
+ expect(fetchStub.calledOnce).toEqual(true);
+ });
+ it('appends comment to the list when added to collection', function() {
+ var comment3 = new OCA.Comments.CommentModel({
+ id: 3,
+ actorType: 'users',
+ actorId: 'user3',
+ actorDisplayName: 'User Three',
+ objectType: 'files',
+ objectId: 5,
+ message: 'Third',
+ creationDateTime: new Date(Date.UTC(2016, 1, 3, 5, 0, 0)).toUTCString()
+ });
+
+ view.collection.add(comment3);
+
+ expect(view.$el.find('.comments>li').length).toEqual(3);
+
+ var $item = view.$el.find('.comments>li').eq(2);
+ expect($item.find('.author').text()).toEqual('User Three');
+ expect($item.find('.date').text()).toEqual('5 hours ago');
+ expect($item.find('.message').html()).toEqual('Third');
+ });
+ });
+ describe('posting comments', function() {
+ var createStub;
+ var currentUserStub;
+
+ beforeEach(function() {
+ view.collection.set(testComments);
+ createStub = sinon.stub(OCA.Comments.CommentCollection.prototype, 'create');
+ currentUserStub = sinon.stub(OC, 'getCurrentUser');
+ currentUserStub.returns({
+ uid: 'testuser',
+ displayName: 'Test User'
+ });
+ });
+ afterEach(function() {
+ createStub.restore();
+ currentUserStub.restore();
+ });
+
+ it('creates a new comment when clicking post button', function() {
+ view.$el.find('.message').val('New message');
+ view.$el.find('form').submit();
+
+ expect(createStub.calledOnce).toEqual(true);
+ expect(createStub.lastCall.args[0]).toEqual({
+ actorId: 'testuser',
+ actorDisplayName: 'Test User',
+ actorType: 'users',
+ verb: 'comment',
+ message: 'New message',
+ creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString()
+ });
+ });
+ it('does not create a comment if the field is empty', function() {
+ view.$el.find('.message').val(' ');
+ view.$el.find('form').submit();
+
+ expect(createStub.notCalled).toEqual(true);
+ });
+
+ });
+ describe('editing comments', function() {
+ var saveStub;
+ var currentUserStub;
+
+ beforeEach(function() {
+ saveStub = sinon.stub(OCA.Comments.CommentModel.prototype, 'save');
+ currentUserStub = sinon.stub(OC, 'getCurrentUser');
+ currentUserStub.returns({
+ uid: 'testuser',
+ displayName: 'Test User'
+ });
+ view.collection.add({
+ id: 1,
+ actorId: 'testuser',
+ actorDisplayName: 'Test User',
+ actorType: 'users',
+ verb: 'comment',
+ message: 'New message',
+ creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString()
+ });
+ view.collection.add({
+ id: 2,
+ actorId: 'anotheruser',
+ actorDisplayName: 'Another User',
+ actorType: 'users',
+ verb: 'comment',
+ message: 'New message from another user',
+ creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString()
+ });
+ });
+ afterEach(function() {
+ saveStub.restore();
+ currentUserStub.restore();
+ });
+
+ it('shows edit link for owner comments', function() {
+ var $comment = view.$el.find('.comment[data-id=1]');
+ expect($comment.length).toEqual(1);
+ expect($comment.find('.action.edit').length).toEqual(1);
+ });
+
+ it('does not show edit link for other user\'s comments', function() {
+ var $comment = view.$el.find('.comment[data-id=2]');
+ expect($comment.length).toEqual(1);
+ expect($comment.find('.action.edit').length).toEqual(0);
+ });
+
+ it('shows edit form when clicking edit', function() {
+ var $comment = view.$el.find('.comment[data-id=1]');
+ $comment.find('.action.edit').click();
+
+ expect($comment.hasClass('hidden')).toEqual(true);
+ var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]');
+ expect($formRow.length).toEqual(1);
+ });
+
+ it('saves message and updates comment item when clicking save', function() {
+ var $comment = view.$el.find('.comment[data-id=1]');
+ $comment.find('.action.edit').click();
+
+ var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]');
+ expect($formRow.length).toEqual(1);
+
+ $formRow.find('textarea').val('modified\nmessage');
+ $formRow.find('form').submit();
+
+ expect(saveStub.calledOnce).toEqual(true);
+ expect(saveStub.lastCall.args[0]).toEqual({
+ message: 'modified\nmessage'
+ });
+
+ var model = view.collection.get(1);
+ // simulate the fact that save sets the attribute
+ model.set('message', 'modified\nmessage');
+ saveStub.yieldTo('success', model);
+
+ // original comment element is visible again
+ expect($comment.hasClass('hidden')).toEqual(false);
+ // and its message was updated
+ expect($comment.find('.message').html()).toEqual('modified<br>message');
+
+ // form row is gone
+ $formRow = view.$el.find('.newCommentRow.comment[data-id=1]');
+ expect($formRow.length).toEqual(0);
+ });
+
+ it('restores original comment when cancelling', function() {
+ var $comment = view.$el.find('.comment[data-id=1]');
+ $comment.find('.action.edit').click();
+
+ var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]');
+ expect($formRow.length).toEqual(1);
+
+ $formRow.find('textarea').val('modified\nmessage');
+ $formRow.find('.cancel').click();
+
+ expect(saveStub.notCalled).toEqual(true);
+
+ // original comment element is visible again
+ expect($comment.hasClass('hidden')).toEqual(false);
+ // and its message was not updated
+ expect($comment.find('.message').html()).toEqual('New message');
+
+ // form row is gone
+ $formRow = view.$el.find('.newCommentRow.comment[data-id=1]');
+ expect($formRow.length).toEqual(0);
+ });
+
+ it('destroys model when clicking delete', function() {
+ var destroyStub = sinon.stub(OCA.Comments.CommentModel.prototype, 'destroy');
+ var $comment = view.$el.find('.comment[data-id=1]');
+ $comment.find('.action.edit').click();
+
+ var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]');
+ expect($formRow.length).toEqual(1);
+
+ $formRow.find('.delete').click();
+
+ expect(destroyStub.calledOnce).toEqual(true);
+ expect(destroyStub.thisValues[0].id).toEqual(1);
+
+ destroyStub.yieldTo('success');
+
+ // original comment element is gone
+ $comment = view.$el.find('.comment[data-id=1]');
+ expect($comment.length).toEqual(0);
+
+ // form row is gone
+ $formRow = view.$el.find('.newCommentRow.comment[data-id=1]');
+ expect($formRow.length).toEqual(0);
+
+ destroyStub.restore();
+ });
+ });
+ describe('read marker', function() {
+ var updateMarkerStub;
+
+ beforeEach(function() {
+ updateMarkerStub = sinon.stub(OCA.Comments.CommentCollection.prototype, 'updateReadMarker');
+ });
+ afterEach(function() {
+ updateMarkerStub.restore();
+ });
+
+ it('resets the read marker after REPORT', function() {
+ testComments[0].set('isUnread', true, {silent: true});
+ testComments[1].set('isUnread', true, {silent: true});
+ view.collection.set(testComments);
+ view.collection.trigger('sync', 'REPORT');
+
+ expect(updateMarkerStub.calledOnce).toEqual(true);
+ expect(updateMarkerStub.lastCall.args[0]).toBeFalsy();
+ });
+ it('does not reset the read marker if there was no unread comments', function() {
+ view.collection.set(testComments);
+ view.collection.trigger('sync', 'REPORT');
+
+ expect(updateMarkerStub.notCalled).toEqual(true);
+ });
+ it('does not reset the read marker when posting comments', function() {
+ testComments[0].set('isUnread', true, {silent: true});
+ testComments[1].set('isUnread', true, {silent: true});
+ view.collection.set(testComments);
+ view.collection.trigger('sync', 'POST');
+
+ expect(updateMarkerStub.notCalled).toEqual(true);
+ });
+ });
+});
diff --git a/apps/comments/tests/js/filespluginSpec.js b/apps/comments/tests/js/filespluginSpec.js
new file mode 100644
index 00000000000..78becc5af09
--- /dev/null
+++ b/apps/comments/tests/js/filespluginSpec.js
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+describe('OCA.Comments.FilesPlugin tests', function() {
+ var fileList;
+ var testFiles;
+
+ beforeEach(function() {
+ var $content = $('<div id="content"></div>');
+ $('#testArea').append($content);
+ // dummy file list
+ var $div = $(
+ '<div>' +
+ '<table id="filestable">' +
+ '<thead></thead>' +
+ '<tbody id="fileList"></tbody>' +
+ '</table>' +
+ '</div>');
+ $('#content').append($div);
+
+ fileList = new OCA.Files.FileList($div);
+ OCA.Comments.FilesPlugin.attach(fileList);
+
+ testFiles = [{
+ id: 1,
+ type: 'file',
+ name: 'One.txt',
+ path: '/subdir',
+ mimetype: 'text/plain',
+ size: 12,
+ permissions: OC.PERMISSION_ALL,
+ etag: 'abc',
+ shareOwner: 'User One',
+ isShareMountPoint: false,
+ commentsUnread: 3
+ }];
+ });
+ afterEach(function() {
+ fileList.destroy();
+ fileList = null;
+ });
+
+ describe('Comment icon', function() {
+ it('does not render icon when no unread comments available', function() {
+ testFiles[0].commentsUnread = 0;
+ fileList.setFiles(testFiles);
+ var $tr = fileList.findFileEl('One.txt');
+ expect($tr.find('.action-comment').length).toEqual(0);
+ });
+ it('renders comment icon and extra data', function() {
+ var $action, $tr;
+ fileList.setFiles(testFiles);
+ $tr = fileList.findFileEl('One.txt');
+ $action = $tr.find('.action-comment');
+ expect($action.length).toEqual(1);
+ expect($action.hasClass('permanent')).toEqual(true);
+
+ expect($tr.attr('data-comments-unread')).toEqual('3');
+ });
+ it('clicking icon opens sidebar', function() {
+ var sidebarStub = sinon.stub(fileList, 'showDetailsView');
+ var $action, $tr;
+ fileList.setFiles(testFiles);
+ $tr = fileList.findFileEl('One.txt');
+ $action = $tr.find('.action-comment');
+ $action.click();
+
+ expect(sidebarStub.calledOnce).toEqual(true);
+ expect(sidebarStub.lastCall.args[0]).toEqual('One.txt');
+ expect(sidebarStub.lastCall.args[1]).toEqual('commentsTabView');
+ });
+ });
+ describe('elementToFile', function() {
+ it('returns comment count', function() {
+ fileList.setFiles(testFiles);
+ var $tr = fileList.findFileEl('One.txt');
+ var data = fileList.elementToFile($tr);
+ expect(data.commentsUnread).toEqual(3);
+ });
+ it('does not set comment count when not set', function() {
+ delete testFiles[0].commentsUnread;
+ fileList.setFiles(testFiles);
+ var $tr = fileList.findFileEl('One.txt');
+ var data = fileList.elementToFile($tr);
+ expect(data.commentsUnread).not.toBeDefined();
+ });
+ it('does not set comment count when zero', function() {
+ testFiles[0].commentsUnread = 0;
+ fileList.setFiles(testFiles);
+ var $tr = fileList.findFileEl('One.txt');
+ var data = fileList.elementToFile($tr);
+ expect(data.commentsUnread).not.toBeDefined();
+ });
+ });
+});
diff --git a/apps/dav/appinfo/app.php b/apps/dav/appinfo/app.php
new file mode 100644
index 00000000000..d33545222b0
--- /dev/null
+++ b/apps/dav/appinfo/app.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+use OCA\Dav\AppInfo\Application;
+
+$app = new Application();
+$app->registerHooks();
+
+\OC::$server->registerService('CardDAVSyncService', function() use ($app) {
+ return $app->getSyncService();
+});
+
+$cm = \OC::$server->getContactsManager();
+$cm->register(function() use ($cm, $app) {
+ $userId = \OC::$server->getUserSession()->getUser()->getUID();
+ $app->setupContactsProvider($cm, $userId);
+});
diff --git a/apps/dav/appinfo/application.php b/apps/dav/appinfo/application.php
new file mode 100644
index 00000000000..07905db7368
--- /dev/null
+++ b/apps/dav/appinfo/application.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\Dav\AppInfo;
+
+use OCA\DAV\CardDAV\ContactsManager;
+use OCA\DAV\CardDAV\SyncJob;
+use OCA\DAV\CardDAV\SyncService;
+use OCA\DAV\HookManager;
+use OCA\Dav\Migration\AddressBookAdapter;
+use OCA\Dav\Migration\MigrateAddressbooks;
+use \OCP\AppFramework\App;
+use OCP\AppFramework\IAppContainer;
+use OCP\Contacts\IManager;
+use OCP\IUser;
+
+class Application extends App {
+
+ /**
+ * Application constructor.
+ *
+ * @param array $urlParams
+ */
+ public function __construct (array $urlParams=array()) {
+ parent::__construct('dav', $urlParams);
+
+ $container = $this->getContainer();
+ $container->registerService('ContactsManager', function($c) {
+ /** @var IAppContainer $c */
+ return new ContactsManager(
+ $c->query('CardDavBackend')
+ );
+ });
+
+ $container->registerService('HookManager', function($c) {
+ /** @var IAppContainer $c */
+ return new HookManager(
+ $c->getServer()->getUserManager(),
+ $c->query('SyncService')
+ );
+ });
+
+ $container->registerService('SyncService', function($c) {
+ /** @var IAppContainer $c */
+ return new SyncService(
+ $c->query('CardDavBackend'),
+ $c->getServer()->getUserManager()
+ );
+ });
+
+ $container->registerService('CardDavBackend', function($c) {
+ /** @var IAppContainer $c */
+ $db = $c->getServer()->getDatabaseConnection();
+ $logger = $c->getServer()->getLogger();
+ $principal = new \OCA\DAV\Connector\Sabre\Principal(
+ $c->getServer()->getUserManager(),
+ $c->getServer()->getGroupManager()
+ );
+ return new \OCA\DAV\CardDAV\CardDavBackend($db, $principal, $logger);
+ });
+
+ $container->registerService('MigrateAddressbooks', function($c) {
+ /** @var IAppContainer $c */
+ $db = $c->getServer()->getDatabaseConnection();
+ return new MigrateAddressbooks(
+ new AddressBookAdapter($db),
+ $c->query('CardDavBackend')
+ );
+ });
+ }
+
+ /**
+ * @param IManager $contactsManager
+ * @param string $userID
+ */
+ public function setupContactsProvider(IManager $contactsManager, $userID) {
+ /** @var ContactsManager $cm */
+ $cm = $this->getContainer()->query('ContactsManager');
+ $cm->setupContactsProvider($contactsManager, $userID);
+ }
+
+ public function registerHooks() {
+ /** @var HookManager $hm */
+ $hm = $this->getContainer()->query('HookManager');
+ $hm->setup();
+ }
+
+ public function getSyncService() {
+ return $this->getContainer()->query('SyncService');
+ }
+
+ public function setupCron() {
+ $jl = $this->getContainer()->getServer()->getJobList();
+ $jl->add(new SyncJob());
+ }
+
+ public function migrateAddressbooks() {
+
+ try {
+ $migration = $this->getContainer()->query('MigrateAddressbooks');
+ $migration->setup();
+ $userManager = $this->getContainer()->getServer()->getUserManager();
+
+ $userManager->callForAllUsers(function($user) use($migration) {
+ /** @var IUser $user */
+ $migration->migrateForUser($user->getUID());
+ });
+ } catch (\Exception $ex) {
+ $this->getContainer()->getServer()->getLogger()->logException($ex);
+ }
+ }
+
+}
diff --git a/apps/dav/appinfo/database.xml b/apps/dav/appinfo/database.xml
index f3fd5079949..4221e590fa5 100644
--- a/apps/dav/appinfo/database.xml
+++ b/apps/dav/appinfo/database.xml
@@ -183,4 +183,510 @@ CREATE TABLE addressbookchanges (
</declaration>
</table>
+
+<!--
+CREATE TABLE calendarobjects (
+ id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ calendardata MEDIUMBLOB,
+ uri VARBINARY(200),
+ calendarid INTEGER UNSIGNED NOT NULL,
+ lastmodified INT(11) UNSIGNED,
+ etag VARBINARY(32),
+ size INT(11) UNSIGNED NOT NULL,
+ componenttype VARBINARY(8),
+ firstoccurence INT(11) UNSIGNED,
+ lastoccurence INT(11) UNSIGNED,
+ uid VARBINARY(200),
+ UNIQUE(calendarid, uri)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+-->
+<table>
+ <name>*dbprefix*calendarobjects</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>calendardata</name>
+ <type>blob</type>
+ </field>
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>calendarid</name>
+ <type>integer</type>
+ <unsigned>true</unsigned>
+ <notnull>true</notnull>
+ </field>
+ <field>
+ <name>lastmodified</name>
+ <type>integer</type>
+ <unsigned>true</unsigned>
+ </field>
+ <field>
+ <name>etag</name>
+ <type>text</type>
+ <length>32</length>
+ </field>
+ <field>
+ <name>size</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>componenttype</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>firstoccurence</name>
+ <type>integer</type>
+ <unsigned>true</unsigned>
+ </field>
+ <field>
+ <name>lastoccurence</name>
+ <type>integer</type>
+ <unsigned>true</unsigned>
+ </field>
+ <field>
+ <name>uid</name>
+ <type>text</type>
+ </field>
+ <index>
+ <name>calobjects_index</name>
+ <unique>true</unique>
+ <field>
+ <name>calendarid</name>
+ </field>
+ <field>
+ <name>uri</name>
+ </field>
+ </index>
+ </declaration>
+</table>
+ <!--
+ CREATE TABLE calendars (
+ id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ principaluri VARBINARY(100),
+ displayname VARCHAR(100),
+ uri VARBINARY(200),
+ synctoken INTEGER UNSIGNED NOT NULL DEFAULT '1',
+ description TEXT,
+ calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0',
+ calendarcolor VARBINARY(10),
+ timezone TEXT,
+ components VARBINARY(20),
+ transparent TINYINT(1) NOT NULL DEFAULT '0',
+ UNIQUE(principaluri, uri)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+ -->
+<table>
+ <name>*dbprefix*calendars</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>principaluri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>displayname</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>synctoken</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ </field>
+ <field>
+ <name>description</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>calendarorder</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ </field>
+ <field>
+ <name>calendarcolor</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>timezone</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>components</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>transparent</name>
+ <type>integer</type>
+ <length>1</length>
+ <notnull>true</notnull>
+ <default>0</default>
+ </field>
+ <index>
+ <name>calendars_index</name>
+ <unique>true</unique>
+ <field>
+ <name>principaluri</name>
+ </field>
+ <field>
+ <name>uri</name>
+ </field>
+ </index>
+ </declaration>
+</table>
+ <!--
+ CREATE TABLE calendarchanges (
+ id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ uri VARBINARY(200) NOT NULL,
+ synctoken INT(11) UNSIGNED NOT NULL,
+ calendarid INT(11) UNSIGNED NOT NULL,
+ operation TINYINT(1) NOT NULL,
+ INDEX calendarid_synctoken (calendarid, synctoken)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+ -->
+ <table>
+ <name>*dbprefix*calendarchanges</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>synctoken</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ </field>
+ <field>
+ <name>calendarid</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ </field>
+ <field>
+ <name>operation</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <length>1</length>
+ </field>
+
+ <index>
+ <name>calendarid_synctoken</name>
+ <field>
+ <name>calendarid</name>
+ </field>
+ <field>
+ <name>synctoken</name>
+ </field>
+ </index>
+
+ </declaration>
+ </table>
+
+ <!--
+ CREATE TABLE calendarsubscriptions (
+ id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ uri VARBINARY(200) NOT NULL,
+ principaluri VARBINARY(100) NOT NULL,
+ source TEXT,
+ displayname VARCHAR(100),
+ refreshrate VARCHAR(10),
+ calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0',
+ calendarcolor VARBINARY(10),
+ striptodos TINYINT(1) NULL,
+ stripalarms TINYINT(1) NULL,
+ stripattachments TINYINT(1) NULL,
+ lastmodified INT(11) UNSIGNED,
+ UNIQUE(principaluri, uri)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+ -->
+<table>
+ <name>*dbprefix*calendarsubscriptions</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>principaluri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>source</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>displayname</name>
+ <type>text</type>
+ <length>100</length>
+ </field>
+ <field>
+ <name>refreshrate</name>
+ <type>text</type>
+ <length>10</length>
+ </field>
+ <field>
+ <name>calendarorder</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ </field>
+ <field>
+ <name>calendarcolor</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>striptodos</name>
+ <type>integer</type>
+ <length>1</length>
+ </field>
+ <field>
+ <name>stripalarms</name>
+ <type>integer</type>
+ <length>1</length>
+ </field>
+ <field>
+ <name>stripattachments</name>
+ <type>integer</type>
+ <length>1</length>
+ </field>
+ <field>
+ <name>lastmodified</name>
+ <type>integer</type>
+ <unsigned>true</unsigned>
+ </field>
+ <index>
+ <name>calsub_index</name>
+ <unique>true</unique>
+ <field>
+ <name>principaluri</name>
+ </field>
+ <field>
+ <name>uri</name>
+ </field>
+ </index>
+ </declaration>
+</table>
+ <!--
+ CREATE TABLE schedulingobjects (
+ id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ principaluri VARBINARY(255),
+ calendardata MEDIUMBLOB,
+ uri VARBINARY(200),
+ lastmodified INT(11) UNSIGNED,
+ etag VARBINARY(32),
+ size INT(11) UNSIGNED NOT NULL
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+ -->
+
+ <table>
+ <name>*dbprefix*schedulingobjects</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>principaluri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>calendardata</name>
+ <type>blob</type>
+ </field>
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>lastmodified</name>
+ <type>integer</type>
+ <unsigned>true</unsigned>
+ </field>
+ <field>
+ <name>etag</name>
+ <type>text</type>
+ <length>32</length>
+ </field>
+ <field>
+ <name>size</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+
+ </declaration>
+ </table>
+
+ <table>
+ <name>*dbprefix*cards_properties</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>addressbookid</name>
+ <type>integer</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>11</length>
+ </field>
+ <field>
+ <name>cardid</name>
+ <type>integer</type>
+ <default></default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>name</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>64</length>
+ </field>
+ <field>
+ <name>value</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+ <field>
+ <name>preferred</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <length>4</length>
+ </field>
+ <index>
+ <name>card_contactid_index</name>
+ <field>
+ <name>cardid</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ <index>
+ <name>card_name_index</name>
+ <field>
+ <name>name</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ <index>
+ <name>card_value_index</name>
+ <field>
+ <name>value</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ </declaration>
+ </table>
+
+ <table>
+ <name>*dbprefix*dav_shares</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>principaluri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>type</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>access</name>
+ <type>integer</type>
+ <length>1</length>
+ </field>
+ <field>
+ <name>resourceid</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ </field>
+ <index>
+ <name>dav_shares_index</name>
+ <unique>true</unique>
+ <field>
+ <name>principaluri</name>
+ </field>
+ <field>
+ <name>resourceid</name>
+ </field>
+ <field>
+ <name>type</name>
+ </field>
+ </index>
+ </declaration>
+ </table>
</database>
diff --git a/apps/dav/appinfo/info.xml b/apps/dav/appinfo/info.xml
index 11025115691..f035d19d862 100644
--- a/apps/dav/appinfo/info.xml
+++ b/apps/dav/appinfo/info.xml
@@ -5,10 +5,7 @@
<description>ownCloud WebDAV endpoint</description>
<licence>AGPL</licence>
<author>owncloud.org</author>
- <version>0.1.2</version>
- <requiremin>9.0</requiremin>
- <shipped>true</shipped>
- <standalone/>
+ <version>0.1.4</version>
<default_enable/>
<types>
<filesystem/>
@@ -21,4 +18,7 @@
<public>
<webdav>appinfo/v1/publicwebdav.php</webdav>
</public>
+ <dependencies>
+ <owncloud min-version="9.0" max-version="9.0" />
+ </dependencies>
</info>
diff --git a/apps/dav/appinfo/install.php b/apps/dav/appinfo/install.php
new file mode 100644
index 00000000000..f6ef533958e
--- /dev/null
+++ b/apps/dav/appinfo/install.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+use OCA\Dav\AppInfo\Application;
+
+$app = new Application();
+$app->setupCron();
+$app->migrateAddressbooks();
diff --git a/apps/dav/appinfo/register_command.php b/apps/dav/appinfo/register_command.php
index c996dd44063..e8ca370f84f 100644
--- a/apps/dav/appinfo/register_command.php
+++ b/apps/dav/appinfo/register_command.php
@@ -1,8 +1,47 @@
<?php
-
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+use OCA\Dav\AppInfo\Application;
use OCA\DAV\Command\CreateAddressBook;
+use OCA\DAV\Command\CreateCalendar;
+use OCA\Dav\Command\MigrateAddressbooks;
+use OCA\DAV\Command\SyncSystemAddressBook;
+$config = \OC::$server->getConfig();
$dbConnection = \OC::$server->getDatabaseConnection();
$userManager = OC::$server->getUserManager();
+$groupManager = OC::$server->getGroupManager();
+$config = \OC::$server->getConfig();
+$logger = \OC::$server->getLogger();
+
+$app = new Application();
+
/** @var Symfony\Component\Console\Application $application */
-$application->add(new CreateAddressBook($userManager, $dbConnection));
+$application->add(new CreateAddressBook($userManager, $groupManager, $dbConnection, $logger));
+$application->add(new CreateCalendar($userManager, $groupManager, $dbConnection));
+$application->add(new SyncSystemAddressBook($app->getSyncService()));
+
+// the occ tool is *for now* only available in debug mode for developers to test
+if ($config->getSystemValue('debug', false)){
+ $app = new \OCA\Dav\AppInfo\Application();
+ $migration = $app->getContainer()->query('MigrateAddressbooks');
+ $application->add(new MigrateAddressbooks($userManager, $migration));
+}
diff --git a/apps/dav/appinfo/update.php b/apps/dav/appinfo/update.php
new file mode 100644
index 00000000000..aaa36052cd2
--- /dev/null
+++ b/apps/dav/appinfo/update.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+use OCA\Dav\AppInfo\Application;
+
+$app = new Application();
+$app->setupCron();
diff --git a/apps/dav/appinfo/v1/publicwebdav.php b/apps/dav/appinfo/v1/publicwebdav.php
index cf0488038d3..6ddb570aca8 100644
--- a/apps/dav/appinfo/v1/publicwebdav.php
+++ b/apps/dav/appinfo/v1/publicwebdav.php
@@ -1,11 +1,13 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -39,7 +41,6 @@ $serverFactory = new OCA\DAV\Connector\Sabre\ServerFactory(
\OC::$server->getUserSession(),
\OC::$server->getMountManager(),
\OC::$server->getTagManager(),
- \OC::$server->getEventDispatcher(),
\OC::$server->getRequest()
);
diff --git a/apps/dav/appinfo/v1/webdav.php b/apps/dav/appinfo/v1/webdav.php
index 8324f962b8e..d75c3526bdd 100644
--- a/apps/dav/appinfo/v1/webdav.php
+++ b/apps/dav/appinfo/v1/webdav.php
@@ -1,16 +1,10 @@
<?php
/**
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -40,7 +34,6 @@ $serverFactory = new \OCA\DAV\Connector\Sabre\ServerFactory(
\OC::$server->getUserSession(),
\OC::$server->getMountManager(),
\OC::$server->getTagManager(),
- \OC::$server->getEventDispatcher(),
\OC::$server->getRequest()
);
diff --git a/apps/dav/appinfo/v2/remote.php b/apps/dav/appinfo/v2/remote.php
index 02457bd3ccc..4e9cf8fd082 100644
--- a/apps/dav/appinfo/v2/remote.php
+++ b/apps/dav/appinfo/v2/remote.php
@@ -1,5 +1,23 @@
<?php
-
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
// no php execution timeout for webdav
set_time_limit(0);
diff --git a/apps/dav/command/createaddressbook.php b/apps/dav/command/createaddressbook.php
index 286871b39e2..3d99afd4ba3 100644
--- a/apps/dav/command/createaddressbook.php
+++ b/apps/dav/command/createaddressbook.php
@@ -1,9 +1,32 @@
<?php
-
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV\Command;
use OCA\DAV\CardDAV\CardDavBackend;
+use OCA\DAV\Connector\Sabre\Principal;
+use OCP\IConfig;
use OCP\IDBConnection;
+use OCP\IGroupManager;
+use OCP\ILogger;
use OCP\IUserManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@@ -18,26 +41,40 @@ class CreateAddressBook extends Command {
/** @var \OCP\IDBConnection */
protected $dbConnection;
+ /** @var ILogger */
+ private $logger;
+
+ /** @var IGroupManager $groupManager */
+ private $groupManager;
+
/**
* @param IUserManager $userManager
* @param IDBConnection $dbConnection
+ * @param IConfig $config
+ * @param ILogger $logger
*/
- function __construct(IUserManager $userManager, IDBConnection $dbConnection) {
+ function __construct(IUserManager $userManager,
+ IGroupManager $groupManager,
+ IDBConnection $dbConnection,
+ ILogger $logger
+ ) {
parent::__construct();
$this->userManager = $userManager;
+ $this->groupManager = $groupManager;
$this->dbConnection = $dbConnection;
+ $this->logger = $logger;
}
protected function configure() {
$this
- ->setName('dav:create-addressbook')
- ->setDescription('Create a dav addressbook')
- ->addArgument('user',
- InputArgument::REQUIRED,
- 'User for whom the addressbook will be created')
- ->addArgument('name',
- InputArgument::REQUIRED,
- 'Name of the addressbook');
+ ->setName('dav:create-addressbook')
+ ->setDescription('Create a dav addressbook')
+ ->addArgument('user',
+ InputArgument::REQUIRED,
+ 'User for whom the addressbook will be created')
+ ->addArgument('name',
+ InputArgument::REQUIRED,
+ 'Name of the addressbook');
}
protected function execute(InputInterface $input, OutputInterface $output) {
@@ -45,8 +82,13 @@ class CreateAddressBook extends Command {
if (!$this->userManager->userExists($user)) {
throw new \InvalidArgumentException("User <$user> in unknown.");
}
+ $principalBackend = new Principal(
+ $this->userManager,
+ $this->groupManager
+ );
+
$name = $input->getArgument('name');
- $carddav = new CardDavBackend($this->dbConnection);
- $carddav->createAddressBook("principals/$user", $name, []);
+ $carddav = new CardDavBackend($this->dbConnection, $principalBackend, $this->logger);
+ $carddav->createAddressBook("principals/users/$user", $name, []);
}
}
diff --git a/apps/dav/command/createcalendar.php b/apps/dav/command/createcalendar.php
new file mode 100644
index 00000000000..d7f82dd0e52
--- /dev/null
+++ b/apps/dav/command/createcalendar.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\Command;
+
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\Connector\Sabre\Principal;
+use OCP\IDBConnection;
+use OCP\IGroupManager;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class CreateCalendar extends Command {
+
+ /** @var IUserManager */
+ protected $userManager;
+
+ /** @var IGroupManager $groupManager */
+ private $groupManager;
+
+ /** @var \OCP\IDBConnection */
+ protected $dbConnection;
+
+ /**
+ * @param IUserManager $userManager
+ * @param IDBConnection $dbConnection
+ */
+ function __construct(IUserManager $userManager, IGroupManager $groupManager, IDBConnection $dbConnection) {
+ parent::__construct();
+ $this->userManager = $userManager;
+ $this->groupManager = $groupManager;
+ $this->dbConnection = $dbConnection;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('dav:create-calendar')
+ ->setDescription('Create a dav calendar')
+ ->addArgument('user',
+ InputArgument::REQUIRED,
+ 'User for whom the calendar will be created')
+ ->addArgument('name',
+ InputArgument::REQUIRED,
+ 'Name of the calendar');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $user = $input->getArgument('user');
+ if (!$this->userManager->userExists($user)) {
+ throw new \InvalidArgumentException("User <$user> in unknown.");
+ }
+ $principalBackend = new Principal(
+ $this->userManager,
+ $this->groupManager
+ );
+
+ $name = $input->getArgument('name');
+ $caldav = new CalDavBackend($this->dbConnection, $principalBackend);
+ $caldav->createCalendar("principals/users/$user", $name, []);
+ }
+}
diff --git a/apps/dav/command/migrateaddressbooks.php b/apps/dav/command/migrateaddressbooks.php
new file mode 100644
index 00000000000..2ab7113ab1f
--- /dev/null
+++ b/apps/dav/command/migrateaddressbooks.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Dav\Command;
+
+use OCP\IUser;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class MigrateAddressbooks extends Command {
+
+ /** @var IUserManager */
+ protected $userManager;
+
+ /** @var \OCA\Dav\Migration\MigrateAddressbooks */
+ private $service;
+
+ /**
+ * @param IUserManager $userManager
+ * @param \OCA\Dav\Migration\MigrateAddressbooks $service
+ */
+ function __construct(IUserManager $userManager,
+ \OCA\Dav\Migration\MigrateAddressbooks $service
+ ) {
+ parent::__construct();
+ $this->userManager = $userManager;
+ $this->service = $service;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('dav:migrate-addressbooks')
+ ->setDescription('Migrate addressbooks from the contacts app to core')
+ ->addArgument('user',
+ InputArgument::OPTIONAL,
+ 'User for whom all addressbooks will be migrated');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $this->service->setup();
+
+ $user = $input->getArgument('user');
+ if (!is_null($user)) {
+ if (!$this->userManager->userExists($user)) {
+ throw new \InvalidArgumentException("User <$user> in unknown.");
+ }
+ $output->writeln("Start migration for $user");
+ $this->service->migrateForUser($user);
+ }
+ $output->writeln("Start migration of all known users ...");
+ $p = new ProgressBar($output);
+ $p->start();
+ $this->userManager->callForAllUsers(function($user) use ($p) {
+ $p->advance();
+ /** @var IUser $user */
+ $this->service->migrateForUser($user->getUID());
+ });
+
+ $p->finish();
+ $output->writeln('');
+ }
+}
diff --git a/apps/dav/command/syncsystemaddressbook.php b/apps/dav/command/syncsystemaddressbook.php
new file mode 100644
index 00000000000..b83a37131c3
--- /dev/null
+++ b/apps/dav/command/syncsystemaddressbook.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\Command;
+
+use OCA\DAV\CardDAV\SyncService;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SyncSystemAddressBook extends Command {
+
+ /** @var SyncService */
+ private $syncService;
+
+ /**
+ * @param IUserManager $userManager
+ * @param SyncService $syncService
+ */
+ function __construct(SyncService $syncService) {
+ parent::__construct();
+ $this->syncService = $syncService;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('dav:sync-system-addressbook')
+ ->setDescription('Synchronizes users to the system addressbook');
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ */
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $output->writeln('Syncing users ...');
+ $progress = new ProgressBar($output);
+ $progress->start();
+ $this->syncService->syncInstance(function() use ($progress) {
+ $progress->advance();
+ });
+
+ $progress->finish();
+ $output->writeln('');
+ }
+}
diff --git a/apps/dav/lib/caldav/caldavbackend.php b/apps/dav/lib/caldav/caldavbackend.php
new file mode 100644
index 00000000000..3aa493e5087
--- /dev/null
+++ b/apps/dav/lib/caldav/caldavbackend.php
@@ -0,0 +1,1260 @@
+<?php
+/**
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\CalDAV;
+
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCA\DAV\Connector\Sabre\Principal;
+use OCA\DAV\DAV\Sharing\Backend;
+use Sabre\CalDAV\Backend\AbstractBackend;
+use Sabre\CalDAV\Backend\SchedulingSupport;
+use Sabre\CalDAV\Backend\SubscriptionSupport;
+use Sabre\CalDAV\Backend\SyncSupport;
+use Sabre\CalDAV\Plugin;
+use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp;
+use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
+use Sabre\DAV;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\HTTP\URLUtil;
+use Sabre\VObject\DateTimeParser;
+use Sabre\VObject\Reader;
+use Sabre\VObject\RecurrenceIterator;
+
+/**
+ * Class CalDavBackend
+ *
+ * Code is heavily inspired by https://github.com/fruux/sabre-dav/blob/master/lib/CalDAV/Backend/PDO.php
+ *
+ * @package OCA\DAV\CalDAV
+ */
+class CalDavBackend extends AbstractBackend implements SyncSupport, SubscriptionSupport, SchedulingSupport {
+
+ /**
+ * We need to specify a max date, because we need to stop *somewhere*
+ *
+ * On 32 bit system the maximum for a signed integer is 2147483647, so
+ * MAX_DATE cannot be higher than date('Y-m-d', 2147483647) which results
+ * in 2038-01-19 to avoid problems when the date is converted
+ * to a unix timestamp.
+ */
+ const MAX_DATE = '2038-01-01';
+
+ /**
+ * List of CalDAV properties, and how they map to database fieldnames
+ * Add your own properties by simply adding on to this array.
+ *
+ * Note that only string-based properties are supported here.
+ *
+ * @var array
+ */
+ public $propertyMap = [
+ '{DAV:}displayname' => 'displayname',
+ '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description',
+ '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'timezone',
+ '{http://apple.com/ns/ical/}calendar-order' => 'calendarorder',
+ '{http://apple.com/ns/ical/}calendar-color' => 'calendarcolor',
+ ];
+
+ /**
+ * List of subscription properties, and how they map to database fieldnames.
+ *
+ * @var array
+ */
+ public $subscriptionPropertyMap = [
+ '{DAV:}displayname' => 'displayname',
+ '{http://apple.com/ns/ical/}refreshrate' => 'refreshrate',
+ '{http://apple.com/ns/ical/}calendar-order' => 'calendarorder',
+ '{http://apple.com/ns/ical/}calendar-color' => 'calendarcolor',
+ '{http://calendarserver.org/ns/}subscribed-strip-todos' => 'striptodos',
+ '{http://calendarserver.org/ns/}subscribed-strip-alarms' => 'stripalarms',
+ '{http://calendarserver.org/ns/}subscribed-strip-attachments' => 'stripattachments',
+ ];
+
+ /** @var \OCP\IDBConnection */
+ private $db;
+
+ /** @var Backend */
+ private $sharingBackend;
+
+ /** @var Principal */
+ private $principalBackend;
+
+ /**
+ * CalDavBackend constructor.
+ *
+ * @param \OCP\IDBConnection $db
+ */
+ public function __construct(\OCP\IDBConnection $db, Principal $principalBackend) {
+ $this->db = $db;
+ $this->principalBackend = $principalBackend;
+ $this->sharingBackend = new Backend($this->db, 'calendar');
+ }
+
+ /**
+ * Returns a list of calendars for a principal.
+ *
+ * Every project is an array with the following keys:
+ * * id, a unique id that will be used by other functions to modify the
+ * calendar. This can be the same as the uri or a database key.
+ * * uri, which the basename of the uri with which the calendar is
+ * accessed.
+ * * principaluri. The owner of the calendar. Almost always the same as
+ * principalUri passed to this method.
+ *
+ * Furthermore it can contain webdav properties in clark notation. A very
+ * common one is '{DAV:}displayname'.
+ *
+ * Many clients also require:
+ * {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
+ * For this property, you can just return an instance of
+ * Sabre\CalDAV\Property\SupportedCalendarComponentSet.
+ *
+ * If you return {http://sabredav.org/ns}read-only and set the value to 1,
+ * ACL will automatically be put in read-only mode.
+ *
+ * @param string $principalUri
+ * @return array
+ */
+ function getCalendarsForUser($principalUri) {
+ $fields = array_values($this->propertyMap);
+ $fields[] = 'id';
+ $fields[] = 'uri';
+ $fields[] = 'synctoken';
+ $fields[] = 'components';
+ $fields[] = 'principaluri';
+ $fields[] = 'transparent';
+
+ // Making fields a comma-delimited list
+ $query = $this->db->getQueryBuilder();
+ $query->select($fields)->from('calendars')
+ ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)))
+ ->orderBy('calendarorder', 'ASC');
+ $stmt = $query->execute();
+
+ $calendars = [];
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+
+ $components = [];
+ if ($row['components']) {
+ $components = explode(',',$row['components']);
+ }
+
+ $calendar = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $row['principaluri'],
+ '{' . Plugin::NS_CALENDARSERVER . '}getctag' => 'http://sabre.io/ns/sync/' . ($row['synctoken']?$row['synctoken']:'0'),
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
+ '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet($components),
+ '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'),
+ ];
+
+ foreach($this->propertyMap as $xmlName=>$dbName) {
+ $calendar[$xmlName] = $row[$dbName];
+ }
+
+ $calendars[$calendar['id']] = $calendar;
+ }
+
+ $stmt->closeCursor();
+
+ // query for shared calendars
+ $principals = $this->principalBackend->getGroupMembership($principalUri);
+ $principals[]= $principalUri;
+
+ $fields = array_values($this->propertyMap);
+ $fields[] = 'a.id';
+ $fields[] = 'a.uri';
+ $fields[] = 'a.synctoken';
+ $fields[] = 'a.components';
+ $fields[] = 'a.principaluri';
+ $fields[] = 'a.transparent';
+ $query = $this->db->getQueryBuilder();
+ $result = $query->select($fields)
+ ->from('dav_shares', 's')
+ ->join('s', 'calendars', 'a', $query->expr()->eq('s.resourceid', 'a.id'))
+ ->where($query->expr()->in('s.principaluri', $query->createParameter('principaluri')))
+ ->andWhere($query->expr()->eq('s.type', $query->createParameter('type')))
+ ->setParameter('type', 'calendar')
+ ->setParameter('principaluri', $principals, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
+ ->execute();
+
+ while($row = $result->fetch()) {
+ list(, $name) = URLUtil::splitPath($row['principaluri']);
+ $uri = $row['uri'] . '_shared_by_' . $name;
+ $row['displayname'] = $row['displayname'] . "($name)";
+ $components = [];
+ if ($row['components']) {
+ $components = explode(',',$row['components']);
+ }
+ $calendar = [
+ 'id' => $row['id'],
+ 'uri' => $uri,
+ 'principaluri' => $principalUri,
+ '{' . Plugin::NS_CALENDARSERVER . '}getctag' => 'http://sabre.io/ns/sync/' . ($row['synctoken']?$row['synctoken']:'0'),
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
+ '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet($components),
+ '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'),
+ '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $row['principaluri'],
+ ];
+
+ foreach($this->propertyMap as $xmlName=>$dbName) {
+ $calendar[$xmlName] = $row[$dbName];
+ }
+
+ $calendars[$calendar['id']] = $calendar;
+ }
+ $result->closeCursor();
+
+ return array_values($calendars);
+ }
+
+ /**
+ * Creates a new calendar for a principal.
+ *
+ * If the creation was a success, an id must be returned that can be used to reference
+ * this calendar in other methods, such as updateCalendar.
+ *
+ * @param string $principalUri
+ * @param string $calendarUri
+ * @param array $properties
+ * @return void
+ */
+ function createCalendar($principalUri, $calendarUri, array $properties) {
+ $values = [
+ 'principaluri' => $principalUri,
+ 'uri' => $calendarUri,
+ 'synctoken' => 1,
+ 'transparent' => 0,
+ 'components' => 'VEVENT,VTODO',
+ 'displayname' => $calendarUri
+ ];
+
+ // Default value
+ $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
+ if (isset($properties[$sccs])) {
+ if (!($properties[$sccs] instanceof SupportedCalendarComponentSet)) {
+ throw new DAV\Exception('The ' . $sccs . ' property must be of type: \Sabre\CalDAV\Property\SupportedCalendarComponentSet');
+ }
+ $values['components'] = implode(',',$properties[$sccs]->getValue());
+ }
+ $transp = '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp';
+ if (isset($properties[$transp])) {
+ $values['transparent'] = $properties[$transp]->getValue()==='transparent';
+ }
+
+ foreach($this->propertyMap as $xmlName=>$dbName) {
+ if (isset($properties[$xmlName])) {
+ $values[$dbName] = $properties[$xmlName];
+ }
+ }
+
+ $query = $this->db->getQueryBuilder();
+ $query->insert('calendars');
+ foreach($values as $column => $value) {
+ $query->setValue($column, $query->createNamedParameter($value));
+ }
+ $query->execute();
+ }
+
+ /**
+ * Updates properties for a calendar.
+ *
+ * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+ * To do the actual updates, you must tell this object which properties
+ * you're going to process with the handle() method.
+ *
+ * Calling the handle method is like telling the PropPatch object "I
+ * promise I can handle updating this property".
+ *
+ * Read the PropPatch documentation for more info and examples.
+ *
+ * @param \Sabre\DAV\PropPatch $propPatch
+ * @return void
+ */
+ function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) {
+ $supportedProperties = array_keys($this->propertyMap);
+ $supportedProperties[] = '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp';
+
+ $propPatch->handle($supportedProperties, function($mutations) use ($calendarId) {
+ $newValues = [];
+ foreach ($mutations as $propertyName => $propertyValue) {
+
+ switch ($propertyName) {
+ case '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' :
+ $fieldName = 'transparent';
+ $newValues[$fieldName] = $propertyValue->getValue() === 'transparent';
+ break;
+ default :
+ $fieldName = $this->propertyMap[$propertyName];
+ $newValues[$fieldName] = $propertyValue;
+ break;
+ }
+
+ }
+ $query = $this->db->getQueryBuilder();
+ $query->update('calendars');
+ foreach ($newValues as $fieldName => $value) {
+ $query->set($fieldName, $query->createNamedParameter($value));
+ }
+ $query->where($query->expr()->eq('id', $query->createNamedParameter($calendarId)));
+ $query->execute();
+
+ $this->addChange($calendarId, "", 2);
+
+ return true;
+ });
+ }
+
+ /**
+ * Delete a calendar and all it's objects
+ *
+ * @param mixed $calendarId
+ * @return void
+ */
+ function deleteCalendar($calendarId) {
+ $stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ?');
+ $stmt->execute([$calendarId]);
+
+ $stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendars` WHERE `id` = ?');
+ $stmt->execute([$calendarId]);
+
+ $stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarchanges` WHERE `calendarid` = ?');
+ $stmt->execute([$calendarId]);
+
+ $this->sharingBackend->deleteAllShares($calendarId);
+ }
+
+ /**
+ * Returns all calendar objects within a calendar.
+ *
+ * Every item contains an array with the following keys:
+ * * calendardata - The iCalendar-compatible calendar data
+ * * uri - a unique key which will be used to construct the uri. This can
+ * be any arbitrary string, but making sure it ends with '.ics' is a
+ * good idea. This is only the basename, or filename, not the full
+ * path.
+ * * lastmodified - a timestamp of the last modification time
+ * * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
+ * '"abcdef"')
+ * * size - The size of the calendar objects, in bytes.
+ * * component - optional, a string containing the type of object, such
+ * as 'vevent' or 'vtodo'. If specified, this will be used to populate
+ * the Content-Type header.
+ *
+ * Note that the etag is optional, but it's highly encouraged to return for
+ * speed reasons.
+ *
+ * The calendardata is also optional. If it's not returned
+ * 'getCalendarObject' will be called later, which *is* expected to return
+ * calendardata.
+ *
+ * If neither etag or size are specified, the calendardata will be
+ * used/fetched to determine these numbers. If both are specified the
+ * amount of times this is needed is reduced by a great degree.
+ *
+ * @param mixed $calendarId
+ * @return array
+ */
+ function getCalendarObjects($calendarId) {
+ $query = $this->db->getQueryBuilder();
+ $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'componenttype'])
+ ->from('calendarobjects')
+ ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)));
+ $stmt = $query->execute();
+
+ $result = [];
+ foreach($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) {
+ $result[] = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'lastmodified' => $row['lastmodified'],
+ 'etag' => '"' . $row['etag'] . '"',
+ 'calendarid' => $row['calendarid'],
+ 'size' => (int)$row['size'],
+ 'component' => strtolower($row['componenttype']),
+ ];
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns information from a single calendar object, based on it's object
+ * uri.
+ *
+ * The object uri is only the basename, or filename and not a full path.
+ *
+ * The returned array must have the same keys as getCalendarObjects. The
+ * 'calendardata' object is required here though, while it's not required
+ * for getCalendarObjects.
+ *
+ * This method must return null if the object did not exist.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @return array|null
+ */
+ function getCalendarObject($calendarId, $objectUri) {
+
+ $query = $this->db->getQueryBuilder();
+ $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype'])
+ ->from('calendarobjects')
+ ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)))
+ ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri)));
+ $stmt = $query->execute();
+ $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+
+ if(!$row) return null;
+
+ return [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'lastmodified' => $row['lastmodified'],
+ 'etag' => '"' . $row['etag'] . '"',
+ 'calendarid' => $row['calendarid'],
+ 'size' => (int)$row['size'],
+ 'calendardata' => $this->readBlob($row['calendardata']),
+ 'component' => strtolower($row['componenttype']),
+ ];
+ }
+
+ /**
+ * Returns a list of calendar objects.
+ *
+ * This method should work identical to getCalendarObject, but instead
+ * return all the calendar objects in the list as an array.
+ *
+ * If the backend supports this, it may allow for some speed-ups.
+ *
+ * @param mixed $calendarId
+ * @param string[] $uris
+ * @return array
+ */
+ function getMultipleCalendarObjects($calendarId, array $uris) {
+ $query = $this->db->getQueryBuilder();
+ $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype'])
+ ->from('calendarobjects')
+ ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)))
+ ->andWhere($query->expr()->in('uri', $query->createParameter('uri')))
+ ->setParameter('uri', $uris, IQueryBuilder::PARAM_STR_ARRAY);
+
+ $stmt = $query->execute();
+
+ $result = [];
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+
+ $result[] = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'lastmodified' => $row['lastmodified'],
+ 'etag' => '"' . $row['etag'] . '"',
+ 'calendarid' => $row['calendarid'],
+ 'size' => (int)$row['size'],
+ 'calendardata' => $this->readBlob($row['calendardata']),
+ 'component' => strtolower($row['componenttype']),
+ ];
+
+ }
+ return $result;
+ }
+
+ /**
+ * Creates a new calendar object.
+ *
+ * The object uri is only the basename, or filename and not a full path.
+ *
+ * It is possible return an etag from this function, which will be used in
+ * the response to this PUT request. Note that the ETag must be surrounded
+ * by double-quotes.
+ *
+ * However, you should only really return this ETag if you don't mangle the
+ * calendar-data. If the result of a subsequent GET to this object is not
+ * the exact same as this request body, you should omit the ETag.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @param string $calendarData
+ * @return string
+ */
+ function createCalendarObject($calendarId, $objectUri, $calendarData) {
+ $extraData = $this->getDenormalizedData($calendarData);
+
+ $query = $this->db->getQueryBuilder();
+ $query->insert('calendarobjects')
+ ->values([
+ 'calendarid' => $query->createNamedParameter($calendarId),
+ 'uri' => $query->createNamedParameter($objectUri),
+ 'calendardata' => $query->createNamedParameter($calendarData, \PDO::PARAM_LOB),
+ 'lastmodified' => $query->createNamedParameter(time()),
+ 'etag' => $query->createNamedParameter($extraData['etag']),
+ 'size' => $query->createNamedParameter($extraData['size']),
+ 'componenttype' => $query->createNamedParameter($extraData['componentType']),
+ 'firstoccurence' => $query->createNamedParameter($extraData['firstOccurence']),
+ 'lastoccurence' => $query->createNamedParameter($extraData['lastOccurence']),
+ 'uid' => $query->createNamedParameter($extraData['uid']),
+ ])
+ ->execute();
+
+ $this->addChange($calendarId, $objectUri, 1);
+
+ return '"' . $extraData['etag'] . '"';
+ }
+
+ /**
+ * Updates an existing calendarobject, based on it's uri.
+ *
+ * The object uri is only the basename, or filename and not a full path.
+ *
+ * It is possible return an etag from this function, which will be used in
+ * the response to this PUT request. Note that the ETag must be surrounded
+ * by double-quotes.
+ *
+ * However, you should only really return this ETag if you don't mangle the
+ * calendar-data. If the result of a subsequent GET to this object is not
+ * the exact same as this request body, you should omit the ETag.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @param string $calendarData
+ * @return string
+ */
+ function updateCalendarObject($calendarId, $objectUri, $calendarData) {
+ $extraData = $this->getDenormalizedData($calendarData);
+
+ $query = $this->db->getQueryBuilder();
+ $query->update('calendarobjects')
+ ->set('calendardata', $query->createNamedParameter($calendarData, \PDO::PARAM_LOB))
+ ->set('lastmodified', $query->createNamedParameter(time()))
+ ->set('etag', $query->createNamedParameter($extraData['etag']))
+ ->set('size', $query->createNamedParameter($extraData['size']))
+ ->set('componenttype', $query->createNamedParameter($extraData['componentType']))
+ ->set('firstoccurence', $query->createNamedParameter($extraData['firstOccurence']))
+ ->set('lastoccurence', $query->createNamedParameter($extraData['lastOccurence']))
+ ->set('uid', $query->createNamedParameter($extraData['uid']))
+ ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)))
+ ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri)))
+ ->execute();
+
+ $this->addChange($calendarId, $objectUri, 2);
+
+ return '"' . $extraData['etag'] . '"';
+ }
+
+ /**
+ * Deletes an existing calendar object.
+ *
+ * The object uri is only the basename, or filename and not a full path.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @return void
+ */
+ function deleteCalendarObject($calendarId, $objectUri) {
+ $stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ? AND `uri` = ?');
+ $stmt->execute([$calendarId, $objectUri]);
+
+ $this->addChange($calendarId, $objectUri, 3);
+ }
+
+ /**
+ * Performs a calendar-query on the contents of this calendar.
+ *
+ * The calendar-query is defined in RFC4791 : CalDAV. Using the
+ * calendar-query it is possible for a client to request a specific set of
+ * object, based on contents of iCalendar properties, date-ranges and
+ * iCalendar component types (VTODO, VEVENT).
+ *
+ * This method should just return a list of (relative) urls that match this
+ * query.
+ *
+ * The list of filters are specified as an array. The exact array is
+ * documented by Sabre\CalDAV\CalendarQueryParser.
+ *
+ * Note that it is extremely likely that getCalendarObject for every path
+ * returned from this method will be called almost immediately after. You
+ * may want to anticipate this to speed up these requests.
+ *
+ * This method provides a default implementation, which parses *all* the
+ * iCalendar objects in the specified calendar.
+ *
+ * This default may well be good enough for personal use, and calendars
+ * that aren't very large. But if you anticipate high usage, big calendars
+ * or high loads, you are strongly adviced to optimize certain paths.
+ *
+ * The best way to do so is override this method and to optimize
+ * specifically for 'common filters'.
+ *
+ * Requests that are extremely common are:
+ * * requests for just VEVENTS
+ * * requests for just VTODO
+ * * requests with a time-range-filter on either VEVENT or VTODO.
+ *
+ * ..and combinations of these requests. It may not be worth it to try to
+ * handle every possible situation and just rely on the (relatively
+ * easy to use) CalendarQueryValidator to handle the rest.
+ *
+ * Note that especially time-range-filters may be difficult to parse. A
+ * time-range filter specified on a VEVENT must for instance also handle
+ * recurrence rules correctly.
+ * A good example of how to interprete all these filters can also simply
+ * be found in Sabre\CalDAV\CalendarQueryFilter. This class is as correct
+ * as possible, so it gives you a good idea on what type of stuff you need
+ * to think of.
+ *
+ * @param mixed $calendarId
+ * @param array $filters
+ * @return array
+ */
+ function calendarQuery($calendarId, array $filters) {
+ $componentType = null;
+ $requirePostFilter = true;
+ $timeRange = null;
+
+ // if no filters were specified, we don't need to filter after a query
+ if (!$filters['prop-filters'] && !$filters['comp-filters']) {
+ $requirePostFilter = false;
+ }
+
+ // Figuring out if there's a component filter
+ if (count($filters['comp-filters']) > 0 && !$filters['comp-filters'][0]['is-not-defined']) {
+ $componentType = $filters['comp-filters'][0]['name'];
+
+ // Checking if we need post-filters
+ if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['time-range'] && !$filters['comp-filters'][0]['prop-filters']) {
+ $requirePostFilter = false;
+ }
+ // There was a time-range filter
+ if ($componentType == 'VEVENT' && isset($filters['comp-filters'][0]['time-range'])) {
+ $timeRange = $filters['comp-filters'][0]['time-range'];
+
+ // If start time OR the end time is not specified, we can do a
+ // 100% accurate mysql query.
+ if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['prop-filters'] && (!$timeRange['start'] || !$timeRange['end'])) {
+ $requirePostFilter = false;
+ }
+ }
+
+ }
+ $columns = ['uri'];
+ if ($requirePostFilter) {
+ $columns = ['uri', 'calendardata'];
+ }
+ $query = $this->db->getQueryBuilder();
+ $query->select($columns)
+ ->from('calendarobjects')
+ ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId)));
+
+ if ($componentType) {
+ $query->andWhere($query->expr()->eq('componenttype', $query->createNamedParameter($componentType)));
+ }
+
+ if ($timeRange && $timeRange['start']) {
+ $query->andWhere($query->expr()->gt('lastoccurence', $query->createNamedParameter($timeRange['start']->getTimeStamp())));
+ }
+ if ($timeRange && $timeRange['end']) {
+ $query->andWhere($query->expr()->lt('firstoccurence', $query->createNamedParameter($timeRange['end']->getTimeStamp())));
+ }
+
+ $stmt = $query->execute();
+
+ $result = [];
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+ if ($requirePostFilter) {
+ if (!$this->validateFilterForObject($row, $filters)) {
+ continue;
+ }
+ }
+ $result[] = $row['uri'];
+ }
+
+ return $result;
+ }
+
+ /**
+ * Searches through all of a users calendars and calendar objects to find
+ * an object with a specific UID.
+ *
+ * This method should return the path to this object, relative to the
+ * calendar home, so this path usually only contains two parts:
+ *
+ * calendarpath/objectpath.ics
+ *
+ * If the uid is not found, return null.
+ *
+ * This method should only consider * objects that the principal owns, so
+ * any calendars owned by other principals that also appear in this
+ * collection should be ignored.
+ *
+ * @param string $principalUri
+ * @param string $uid
+ * @return string|null
+ */
+ function getCalendarObjectByUID($principalUri, $uid) {
+
+ $query = $this->db->getQueryBuilder();
+ $query->select([$query->createFunction('c.`uri` AS `calendaruri`'), $query->createFunction('co.`uri` AS `objecturi`')])
+ ->from('calendarobjects', 'co')
+ ->leftJoin('co', 'calendars', 'c', 'co.`calendarid` = c.`id`')
+ ->where($query->expr()->eq('c.principaluri', $query->createNamedParameter($principalUri)))
+ ->andWhere($query->expr()->eq('co.uid', $query->createNamedParameter($uid)));
+
+ $stmt = $query->execute();
+
+ if ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+ return $row['calendaruri'] . '/' . $row['objecturi'];
+ }
+
+ return null;
+ }
+
+ /**
+ * The getChanges method returns all the changes that have happened, since
+ * the specified syncToken in the specified calendar.
+ *
+ * This function should return an array, such as the following:
+ *
+ * [
+ * 'syncToken' => 'The current synctoken',
+ * 'added' => [
+ * 'new.txt',
+ * ],
+ * 'modified' => [
+ * 'modified.txt',
+ * ],
+ * 'deleted' => [
+ * 'foo.php.bak',
+ * 'old.txt'
+ * ]
+ * );
+ *
+ * The returned syncToken property should reflect the *current* syncToken
+ * of the calendar, as reported in the {http://sabredav.org/ns}sync-token
+ * property This is * needed here too, to ensure the operation is atomic.
+ *
+ * If the $syncToken argument is specified as null, this is an initial
+ * sync, and all members should be reported.
+ *
+ * The modified property is an array of nodenames that have changed since
+ * the last token.
+ *
+ * The deleted property is an array with nodenames, that have been deleted
+ * from collection.
+ *
+ * The $syncLevel argument is basically the 'depth' of the report. If it's
+ * 1, you only have to report changes that happened only directly in
+ * immediate descendants. If it's 2, it should also include changes from
+ * the nodes below the child collections. (grandchildren)
+ *
+ * The $limit argument allows a client to specify how many results should
+ * be returned at most. If the limit is not specified, it should be treated
+ * as infinite.
+ *
+ * If the limit (infinite or not) is higher than you're willing to return,
+ * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
+ *
+ * If the syncToken is expired (due to data cleanup) or unknown, you must
+ * return null.
+ *
+ * The limit is 'suggestive'. You are free to ignore it.
+ *
+ * @param string $calendarId
+ * @param string $syncToken
+ * @param int $syncLevel
+ * @param int $limit
+ * @return array
+ */
+ function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null) {
+ // Current synctoken
+ $stmt = $this->db->prepare('SELECT `synctoken` FROM `*PREFIX*calendars` WHERE `id` = ?');
+ $stmt->execute([ $calendarId ]);
+ $currentToken = $stmt->fetchColumn(0);
+
+ if (is_null($currentToken)) {
+ return null;
+ }
+
+ $result = [
+ 'syncToken' => $currentToken,
+ 'added' => [],
+ 'modified' => [],
+ 'deleted' => [],
+ ];
+
+ if ($syncToken) {
+
+ $query = "SELECT `uri`, `operation` FROM `*PREFIX*calendarchanges` WHERE `synctoken` >= ? AND `synctoken` < ? AND `calendarid` = ? ORDER BY `synctoken`";
+ if ($limit>0) {
+ $query.= " `LIMIT` " . (int)$limit;
+ }
+
+ // Fetching all changes
+ $stmt = $this->db->prepare($query);
+ $stmt->execute([$syncToken, $currentToken, $calendarId]);
+
+ $changes = [];
+
+ // This loop ensures that any duplicates are overwritten, only the
+ // last change on a node is relevant.
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+
+ $changes[$row['uri']] = $row['operation'];
+
+ }
+
+ foreach($changes as $uri => $operation) {
+
+ switch($operation) {
+ case 1 :
+ $result['added'][] = $uri;
+ break;
+ case 2 :
+ $result['modified'][] = $uri;
+ break;
+ case 3 :
+ $result['deleted'][] = $uri;
+ break;
+ }
+
+ }
+ } else {
+ // No synctoken supplied, this is the initial sync.
+ $query = "SELECT `uri` FROM `*PREFIX*calendarobjects` WHERE `calendarid` = ?";
+ $stmt = $this->db->prepare($query);
+ $stmt->execute([$calendarId]);
+
+ $result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN);
+ }
+ return $result;
+
+ }
+
+ /**
+ * Returns a list of subscriptions for a principal.
+ *
+ * Every subscription is an array with the following keys:
+ * * id, a unique id that will be used by other functions to modify the
+ * subscription. This can be the same as the uri or a database key.
+ * * uri. This is just the 'base uri' or 'filename' of the subscription.
+ * * principaluri. The owner of the subscription. Almost always the same as
+ * principalUri passed to this method.
+ *
+ * Furthermore, all the subscription info must be returned too:
+ *
+ * 1. {DAV:}displayname
+ * 2. {http://apple.com/ns/ical/}refreshrate
+ * 3. {http://calendarserver.org/ns/}subscribed-strip-todos (omit if todos
+ * should not be stripped).
+ * 4. {http://calendarserver.org/ns/}subscribed-strip-alarms (omit if alarms
+ * should not be stripped).
+ * 5. {http://calendarserver.org/ns/}subscribed-strip-attachments (omit if
+ * attachments should not be stripped).
+ * 6. {http://calendarserver.org/ns/}source (Must be a
+ * Sabre\DAV\Property\Href).
+ * 7. {http://apple.com/ns/ical/}calendar-color
+ * 8. {http://apple.com/ns/ical/}calendar-order
+ * 9. {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
+ * (should just be an instance of
+ * Sabre\CalDAV\Property\SupportedCalendarComponentSet, with a bunch of
+ * default components).
+ *
+ * @param string $principalUri
+ * @return array
+ */
+ function getSubscriptionsForUser($principalUri) {
+ $fields = array_values($this->subscriptionPropertyMap);
+ $fields[] = 'id';
+ $fields[] = 'uri';
+ $fields[] = 'source';
+ $fields[] = 'principaluri';
+ $fields[] = 'lastmodified';
+
+ $query = $this->db->getQueryBuilder();
+ $query->select($fields)
+ ->from('calendarsubscriptions')
+ ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)))
+ ->orderBy('calendarorder', 'asc');
+ $stmt =$query->execute();
+
+ $subscriptions = [];
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+
+ $subscription = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $row['principaluri'],
+ 'source' => $row['source'],
+ 'lastmodified' => $row['lastmodified'],
+
+ '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO', 'VEVENT']),
+ ];
+
+ foreach($this->subscriptionPropertyMap as $xmlName=>$dbName) {
+ if (!is_null($row[$dbName])) {
+ $subscription[$xmlName] = $row[$dbName];
+ }
+ }
+
+ $subscriptions[] = $subscription;
+
+ }
+
+ return $subscriptions;
+ }
+
+ /**
+ * Creates a new subscription for a principal.
+ *
+ * If the creation was a success, an id must be returned that can be used to reference
+ * this subscription in other methods, such as updateSubscription.
+ *
+ * @param string $principalUri
+ * @param string $uri
+ * @param array $properties
+ * @return mixed
+ */
+ function createSubscription($principalUri, $uri, array $properties) {
+
+ if (!isset($properties['{http://calendarserver.org/ns/}source'])) {
+ throw new Forbidden('The {http://calendarserver.org/ns/}source property is required when creating subscriptions');
+ }
+
+ $values = [
+ 'principaluri' => $principalUri,
+ 'uri' => $uri,
+ 'source' => $properties['{http://calendarserver.org/ns/}source']->getHref(),
+ 'lastmodified' => time(),
+ ];
+
+ foreach($this->subscriptionPropertyMap as $xmlName=>$dbName) {
+ if (isset($properties[$xmlName])) {
+
+ $values[$dbName] = $properties[$xmlName];
+ $fieldNames[] = $dbName;
+ }
+ }
+
+ $query = $this->db->getQueryBuilder();
+ $query->insert('calendarsubscriptions')
+ ->values([
+ 'principaluri' => $query->createNamedParameter($values['principaluri']),
+ 'uri' => $query->createNamedParameter($values['uri']),
+ 'source' => $query->createNamedParameter($values['source']),
+ 'lastmodified' => $query->createNamedParameter($values['lastmodified']),
+ ])
+ ->execute();
+
+ return $this->db->lastInsertId('*PREFIX*calendarsubscriptions');
+ }
+
+ /**
+ * Updates a subscription
+ *
+ * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+ * To do the actual updates, you must tell this object which properties
+ * you're going to process with the handle() method.
+ *
+ * Calling the handle method is like telling the PropPatch object "I
+ * promise I can handle updating this property".
+ *
+ * Read the PropPatch documentation for more info and examples.
+ *
+ * @param mixed $subscriptionId
+ * @param \Sabre\DAV\PropPatch $propPatch
+ * @return void
+ */
+ function updateSubscription($subscriptionId, DAV\PropPatch $propPatch) {
+ $supportedProperties = array_keys($this->subscriptionPropertyMap);
+ $supportedProperties[] = '{http://calendarserver.org/ns/}source';
+
+ $propPatch->handle($supportedProperties, function($mutations) use ($subscriptionId) {
+
+ $newValues = [];
+
+ foreach($mutations as $propertyName=>$propertyValue) {
+ if ($propertyName === '{http://calendarserver.org/ns/}source') {
+ $newValues['source'] = $propertyValue->getHref();
+ } else {
+ $fieldName = $this->subscriptionPropertyMap[$propertyName];
+ $newValues[$fieldName] = $propertyValue;
+ }
+ }
+
+ $query = $this->db->getQueryBuilder();
+ $query->update('calendarsubscriptions')
+ ->set('lastmodified', $query->createNamedParameter(time()));
+ foreach($newValues as $fieldName=>$value) {
+ $query->set($fieldName, $query->createNamedParameter($value));
+ }
+ $query->where($query->expr()->eq('id', $query->createNamedParameter($subscriptionId)))
+ ->execute();
+
+ return true;
+
+ });
+ }
+
+ /**
+ * Deletes a subscription.
+ *
+ * @param mixed $subscriptionId
+ * @return void
+ */
+ function deleteSubscription($subscriptionId) {
+ $query = $this->db->getQueryBuilder();
+ $query->delete('calendarsubscriptions')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($subscriptionId)))
+ ->execute();
+ }
+
+ /**
+ * Returns a single scheduling object for the inbox collection.
+ *
+ * The returned array should contain the following elements:
+ * * uri - A unique basename for the object. This will be used to
+ * construct a full uri.
+ * * calendardata - The iCalendar object
+ * * lastmodified - The last modification date. Can be an int for a unix
+ * timestamp, or a PHP DateTime object.
+ * * etag - A unique token that must change if the object changed.
+ * * size - The size of the object, in bytes.
+ *
+ * @param string $principalUri
+ * @param string $objectUri
+ * @return array
+ */
+ function getSchedulingObject($principalUri, $objectUri) {
+ $query = $this->db->getQueryBuilder();
+ $stmt = $query->select(['uri', 'calendardata', 'lastmodified', 'etag', 'size'])
+ ->from('schedulingobjects')
+ ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)))
+ ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri)))
+ ->execute();
+
+ $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+
+ if(!$row) {
+ return null;
+ }
+
+ return [
+ 'uri' => $row['uri'],
+ 'calendardata' => $row['calendardata'],
+ 'lastmodified' => $row['lastmodified'],
+ 'etag' => '"' . $row['etag'] . '"',
+ 'size' => (int)$row['size'],
+ ];
+ }
+
+ /**
+ * Returns all scheduling objects for the inbox collection.
+ *
+ * These objects should be returned as an array. Every item in the array
+ * should follow the same structure as returned from getSchedulingObject.
+ *
+ * The main difference is that 'calendardata' is optional.
+ *
+ * @param string $principalUri
+ * @return array
+ */
+ function getSchedulingObjects($principalUri) {
+ $query = $this->db->getQueryBuilder();
+ $stmt = $query->select(['uri', 'calendardata', 'lastmodified', 'etag', 'size'])
+ ->from('schedulingobjects')
+ ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)))
+ ->execute();
+
+ $result = [];
+ foreach($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) {
+ $result[] = [
+ 'calendardata' => $row['calendardata'],
+ 'uri' => $row['uri'],
+ 'lastmodified' => $row['lastmodified'],
+ 'etag' => '"' . $row['etag'] . '"',
+ 'size' => (int)$row['size'],
+ ];
+ }
+
+ return $result;
+ }
+
+ /**
+ * Deletes a scheduling object from the inbox collection.
+ *
+ * @param string $principalUri
+ * @param string $objectUri
+ * @return void
+ */
+ function deleteSchedulingObject($principalUri, $objectUri) {
+ $query = $this->db->getQueryBuilder();
+ $query->delete('schedulingobjects')
+ ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)))
+ ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri)))
+ ->execute();
+ }
+
+ /**
+ * Creates a new scheduling object. This should land in a users' inbox.
+ *
+ * @param string $principalUri
+ * @param string $objectUri
+ * @param string $objectData
+ * @return void
+ */
+ function createSchedulingObject($principalUri, $objectUri, $objectData) {
+ $query = $this->db->getQueryBuilder();
+ $query->insert('schedulingobjects')
+ ->values([
+ 'principaluri' => $query->createNamedParameter($principalUri),
+ 'calendardata' => $query->createNamedParameter($objectData),
+ 'uri' => $query->createNamedParameter($objectUri),
+ 'lastmodified' => $query->createNamedParameter(time()),
+ 'etag' => $query->createNamedParameter(md5($objectData)),
+ 'size' => $query->createNamedParameter(strlen($objectData))
+ ])
+ ->execute();
+ }
+
+ /**
+ * Adds a change record to the calendarchanges table.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @param int $operation 1 = add, 2 = modify, 3 = delete.
+ * @return void
+ */
+ protected function addChange($calendarId, $objectUri, $operation) {
+
+ $stmt = $this->db->prepare('INSERT INTO `*PREFIX*calendarchanges` (`uri`, `synctoken`, `calendarid`, `operation`) SELECT ?, `synctoken`, ?, ? FROM `*PREFIX*calendars` WHERE `id` = ?');
+ $stmt->execute([
+ $objectUri,
+ $calendarId,
+ $operation,
+ $calendarId
+ ]);
+ $stmt = $this->db->prepare('UPDATE `*PREFIX*calendars` SET `synctoken` = `synctoken` + 1 WHERE `id` = ?');
+ $stmt->execute([
+ $calendarId
+ ]);
+
+ }
+
+ /**
+ * Parses some information from calendar objects, used for optimized
+ * calendar-queries.
+ *
+ * Returns an array with the following keys:
+ * * etag - An md5 checksum of the object without the quotes.
+ * * size - Size of the object in bytes
+ * * componentType - VEVENT, VTODO or VJOURNAL
+ * * firstOccurence
+ * * lastOccurence
+ * * uid - value of the UID property
+ *
+ * @param string $calendarData
+ * @return array
+ */
+ protected function getDenormalizedData($calendarData) {
+
+ $vObject = Reader::read($calendarData);
+ $componentType = null;
+ $component = null;
+ $firstOccurence = null;
+ $lastOccurence = null;
+ $uid = null;
+ foreach($vObject->getComponents() as $component) {
+ if ($component->name!=='VTIMEZONE') {
+ $componentType = $component->name;
+ $uid = (string)$component->UID;
+ break;
+ }
+ }
+ if (!$componentType) {
+ throw new \Sabre\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
+ }
+ if ($componentType === 'VEVENT') {
+ $firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp();
+ // Finding the last occurence is a bit harder
+ if (!isset($component->RRULE)) {
+ if (isset($component->DTEND)) {
+ $lastOccurence = $component->DTEND->getDateTime()->getTimeStamp();
+ } elseif (isset($component->DURATION)) {
+ $endDate = clone $component->DTSTART->getDateTime();
+ $endDate->add(DateTimeParser::parse($component->DURATION->getValue()));
+ $lastOccurence = $endDate->getTimeStamp();
+ } elseif (!$component->DTSTART->hasTime()) {
+ $endDate = clone $component->DTSTART->getDateTime();
+ $endDate->modify('+1 day');
+ $lastOccurence = $endDate->getTimeStamp();
+ } else {
+ $lastOccurence = $firstOccurence;
+ }
+ } else {
+ $it = new RecurrenceIterator($vObject, (string)$component->UID);
+ $maxDate = new \DateTime(self::MAX_DATE);
+ if ($it->isInfinite()) {
+ $lastOccurence = $maxDate->getTimeStamp();
+ } else {
+ $end = $it->getDtEnd();
+ while($it->valid() && $end < $maxDate) {
+ $end = $it->getDtEnd();
+ $it->next();
+
+ }
+ $lastOccurence = $end->getTimeStamp();
+ }
+
+ }
+ }
+
+ return [
+ 'etag' => md5($calendarData),
+ 'size' => strlen($calendarData),
+ 'componentType' => $componentType,
+ 'firstOccurence' => $firstOccurence,
+ 'lastOccurence' => $lastOccurence,
+ 'uid' => $uid,
+ ];
+
+ }
+
+ private function readBlob($cardData) {
+ if (is_resource($cardData)) {
+ return stream_get_contents($cardData);
+ }
+
+ return $cardData;
+ }
+
+ public function updateShares($shareable, $add, $remove) {
+ $this->sharingBackend->updateShares($shareable, $add, $remove);
+ }
+
+ public function getShares($resourceId) {
+ return $this->sharingBackend->getShares($resourceId);
+ }
+
+ public function applyShareAcl($addressBookId, $acl) {
+ return $this->sharingBackend->applyShareAcl($addressBookId, $acl);
+ }
+
+}
diff --git a/apps/dav/lib/caldav/calendar.php b/apps/dav/lib/caldav/calendar.php
new file mode 100644
index 00000000000..8ed5b6563d0
--- /dev/null
+++ b/apps/dav/lib/caldav/calendar.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace OCA\DAV\CalDAV;
+
+use OCA\DAV\DAV\Sharing\IShareable;
+use Sabre\DAV\Exception\Forbidden;
+
+class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
+
+ /**
+ * Updates the list of shares.
+ *
+ * The first array is a list of people that are to be added to the
+ * resource.
+ *
+ * Every element in the add array has the following properties:
+ * * href - A url. Usually a mailto: address
+ * * commonName - Usually a first and last name, or false
+ * * summary - A description of the share, can also be false
+ * * readOnly - A boolean value
+ *
+ * Every element in the remove array is just the address string.
+ *
+ * @param array $add
+ * @param array $remove
+ * @return void
+ */
+ function updateShares(array $add, array $remove) {
+ /** @var CalDavBackend $calDavBackend */
+ $calDavBackend = $this->caldavBackend;
+ $calDavBackend->updateShares($this, $add, $remove);
+ }
+
+ /**
+ * Returns the list of people whom this resource is shared with.
+ *
+ * Every element in this array should have the following properties:
+ * * href - Often a mailto: address
+ * * commonName - Optional, for example a first + last name
+ * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
+ * * readOnly - boolean
+ * * summary - Optional, a description for the share
+ *
+ * @return array
+ */
+ function getShares() {
+ /** @var CalDavBackend $calDavBackend */
+ $calDavBackend = $this->caldavBackend;
+ return $calDavBackend->getShares($this->getResourceId());
+ }
+
+ /**
+ * @return int
+ */
+ public function getResourceId() {
+ return $this->calendarInfo['id'];
+ }
+
+ function getACL() {
+ $acl = parent::getACL();
+
+ /** @var CalDavBackend $calDavBackend */
+ $calDavBackend = $this->caldavBackend;
+ return $calDavBackend->applyShareAcl($this->getResourceId(), $acl);
+ }
+
+ function getChildACL() {
+ $acl = parent::getChildACL();
+
+ /** @var CalDavBackend $calDavBackend */
+ $calDavBackend = $this->caldavBackend;
+ return $calDavBackend->applyShareAcl($this->getResourceId(), $acl);
+ }
+
+ function getOwner() {
+ if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) {
+ return $this->calendarInfo['{http://owncloud.org/ns}owner-principal'];
+ }
+ return parent::getOwner();
+ }
+
+ function delete() {
+ if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) {
+ $principal = 'principal:' . parent::getOwner();
+ $shares = $this->getShares();
+ $shares = array_filter($shares, function($share) use ($principal){
+ return $share['href'] === $principal;
+ });
+ if (empty($shares)) {
+ throw new Forbidden();
+ }
+
+ /** @var CalDavBackend $calDavBackend */
+ $calDavBackend = $this->caldavBackend;
+ $calDavBackend->updateShares($this, [], [
+ 'href' => $principal
+ ]);
+ return;
+ }
+ parent::delete();
+ }
+}
diff --git a/apps/dav/lib/caldav/calendarhome.php b/apps/dav/lib/caldav/calendarhome.php
new file mode 100644
index 00000000000..7f98dfb94e0
--- /dev/null
+++ b/apps/dav/lib/caldav/calendarhome.php
@@ -0,0 +1,78 @@
+<?php
+
+namespace OCA\DAV\CalDAV;
+
+use Sabre\CalDAV\Backend\NotificationSupport;
+use Sabre\CalDAV\Backend\SchedulingSupport;
+use Sabre\CalDAV\Backend\SubscriptionSupport;
+use Sabre\CalDAV\Schedule\Inbox;
+use Sabre\CalDAV\Schedule\Outbox;
+use Sabre\CalDAV\Subscriptions\Subscription;
+use Sabre\DAV\Exception\NotFound;
+
+class CalendarHome extends \Sabre\CalDAV\CalendarHome {
+
+ /**
+ * @inheritdoc
+ */
+ function getChildren() {
+ $calendars = $this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']);
+ $objs = [];
+ foreach ($calendars as $calendar) {
+ $objs[] = new Calendar($this->caldavBackend, $calendar);
+ }
+
+ if ($this->caldavBackend instanceof SchedulingSupport) {
+ $objs[] = new Inbox($this->caldavBackend, $this->principalInfo['uri']);
+ $objs[] = new Outbox($this->principalInfo['uri']);
+ }
+
+ // We're adding a notifications node, if it's supported by the backend.
+ if ($this->caldavBackend instanceof NotificationSupport) {
+ $objs[] = new \Sabre\CalDAV\Notifications\Collection($this->caldavBackend, $this->principalInfo['uri']);
+ }
+
+ // If the backend supports subscriptions, we'll add those as well,
+ if ($this->caldavBackend instanceof SubscriptionSupport) {
+ foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) {
+ $objs[] = new Subscription($this->caldavBackend, $subscription);
+ }
+ }
+
+ return $objs;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function getChild($name) {
+ // Special nodes
+ if ($name === 'inbox' && $this->caldavBackend instanceof SchedulingSupport) {
+ return new Inbox($this->caldavBackend, $this->principalInfo['uri']);
+ }
+ if ($name === 'outbox' && $this->caldavBackend instanceof SchedulingSupport) {
+ return new Outbox($this->principalInfo['uri']);
+ }
+ if ($name === 'notifications' && $this->caldavBackend instanceof NotificationSupport) {
+ return new \Sabre\CalDAv\Notifications\Collection($this->caldavBackend, $this->principalInfo['uri']);
+ }
+
+ // Calendars
+ foreach ($this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']) as $calendar) {
+ if ($calendar['uri'] === $name) {
+ return new Calendar($this->caldavBackend, $calendar);
+ }
+ }
+
+ if ($this->caldavBackend instanceof SubscriptionSupport) {
+ foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) {
+ if ($subscription['uri'] === $name) {
+ return new Subscription($this->caldavBackend, $subscription);
+ }
+ }
+
+ }
+
+ throw new NotFound('Node with name \'' . $name . '\' could not be found');
+ }
+} \ No newline at end of file
diff --git a/apps/dav/lib/caldav/calendarroot.php b/apps/dav/lib/caldav/calendarroot.php
new file mode 100644
index 00000000000..ae5fc54cdf3
--- /dev/null
+++ b/apps/dav/lib/caldav/calendarroot.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace OCA\DAV\CalDAV;
+
+class CalendarRoot extends \Sabre\CalDAV\CalendarRoot {
+
+ function getChildForPrincipal(array $principal) {
+ return new CalendarHome($this->caldavBackend, $principal);
+ }
+} \ No newline at end of file
diff --git a/apps/dav/lib/caldav/schedule/imipplugin.php b/apps/dav/lib/caldav/schedule/imipplugin.php
new file mode 100644
index 00000000000..d9f2ec674f0
--- /dev/null
+++ b/apps/dav/lib/caldav/schedule/imipplugin.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\CalDAV\Schedule;
+
+use OCP\ILogger;
+use OCP\Mail\IMailer;
+use Sabre\DAV;
+use Sabre\VObject\ITip;
+use Sabre\CalDAV\Schedule\IMipPlugin as SabreIMipPlugin;
+/**
+ * iMIP handler.
+ *
+ * This class is responsible for sending out iMIP messages. iMIP is the
+ * email-based transport for iTIP. iTIP deals with scheduling operations for
+ * iCalendar objects.
+ *
+ * If you want to customize the email that gets sent out, you can do so by
+ * extending this class and overriding the sendMessage method.
+ *
+ * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class IMipPlugin extends SabreIMipPlugin {
+
+ /** @var IMailer */
+ private $mailer;
+
+ /** @var ILogger */
+ private $logger;
+
+ /**
+ * Creates the email handler.
+ *
+ * @param IMailer $mailer
+ */
+ function __construct(IMailer $mailer, ILogger $logger) {
+ parent::__construct('');
+ $this->mailer = $mailer;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Event handler for the 'schedule' event.
+ *
+ * @param ITip\Message $iTipMessage
+ * @return void
+ */
+ function schedule(ITip\Message $iTipMessage) {
+
+ // Not sending any emails if the system considers the update
+ // insignificant.
+ if (!$iTipMessage->significantChange) {
+ if (!$iTipMessage->scheduleStatus) {
+ $iTipMessage->scheduleStatus = '1.0;We got the message, but it\'s not significant enough to warrant an email';
+ }
+ return;
+ }
+
+ $summary = $iTipMessage->message->VEVENT->SUMMARY;
+
+ if (parse_url($iTipMessage->sender, PHP_URL_SCHEME) !== 'mailto') {
+ return;
+ }
+
+ if (parse_url($iTipMessage->recipient, PHP_URL_SCHEME) !== 'mailto') {
+ return;
+ }
+
+ $sender = substr($iTipMessage->sender, 7);
+ $recipient = substr($iTipMessage->recipient, 7);
+
+ $senderName = ($iTipMessage->senderName) ? $iTipMessage->senderName : null;
+ $recipientName = ($iTipMessage->recipientName) ? $iTipMessage->recipientName : null;
+
+ $subject = 'SabreDAV iTIP message';
+ switch (strtoupper($iTipMessage->method)) {
+ case 'REPLY' :
+ $subject = 'Re: ' . $summary;
+ break;
+ case 'REQUEST' :
+ $subject = $summary;
+ break;
+ case 'CANCEL' :
+ $subject = 'Cancelled: ' . $summary;
+ break;
+ }
+
+ $contentType = 'text/calendar; charset=UTF-8; method=' . $iTipMessage->method;
+
+ $message = $this->mailer->createMessage();
+
+ $message->setReplyTo([$sender => $senderName])
+ ->setTo([$recipient => $recipientName])
+ ->setSubject($subject)
+ ->setBody($iTipMessage->message->serialize(), $contentType);
+ try {
+ $failed = $this->mailer->send($message);
+ if ($failed) {
+ $this->logger->error('Unable to deliver message to {failed}', ['app' => 'dav', 'failed' => implode(', ', $failed)]);
+ $iTipMessage->scheduleStatus = '5.0; EMail delivery failed';
+ }
+ $iTipMessage->scheduleStatus = '1.1; Scheduling message is sent via iMip';
+ } catch(\Exception $ex) {
+ $this->logger->logException($ex, ['app' => 'dav']);
+ $iTipMessage->scheduleStatus = '5.0; EMail delivery failed';
+ }
+ }
+
+}
diff --git a/apps/dav/lib/carddav/addressbook.php b/apps/dav/lib/carddav/addressbook.php
new file mode 100644
index 00000000000..ca3f5ba0ef6
--- /dev/null
+++ b/apps/dav/lib/carddav/addressbook.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\CardDAV;
+
+use OCA\DAV\DAV\Sharing\IShareable;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\NotFound;
+
+class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
+
+ public function __construct(CardDavBackend $carddavBackend, array $addressBookInfo) {
+ parent::__construct($carddavBackend, $addressBookInfo);
+ }
+
+ /**
+ * Updates the list of shares.
+ *
+ * The first array is a list of people that are to be added to the
+ * addressbook.
+ *
+ * Every element in the add array has the following properties:
+ * * href - A url. Usually a mailto: address
+ * * commonName - Usually a first and last name, or false
+ * * summary - A description of the share, can also be false
+ * * readOnly - A boolean value
+ *
+ * Every element in the remove array is just the address string.
+ *
+ * @param array $add
+ * @param array $remove
+ * @return void
+ */
+ function updateShares(array $add, array $remove) {
+ /** @var CardDavBackend $carddavBackend */
+ $carddavBackend = $this->carddavBackend;
+ $carddavBackend->updateShares($this, $add, $remove);
+ }
+
+ /**
+ * Returns the list of people whom this addressbook is shared with.
+ *
+ * Every element in this array should have the following properties:
+ * * href - Often a mailto: address
+ * * commonName - Optional, for example a first + last name
+ * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
+ * * readOnly - boolean
+ * * summary - Optional, a description for the share
+ *
+ * @return array
+ */
+ function getShares() {
+ /** @var CardDavBackend $carddavBackend */
+ $carddavBackend = $this->carddavBackend;
+ return $carddavBackend->getShares($this->getResourceId());
+ }
+
+ function getACL() {
+ $acl = parent::getACL();
+ if ($this->getOwner() === 'principals/system/system') {
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => '{DAV:}authenticated',
+ 'protected' => true,
+ ];
+ }
+
+ // add the current user
+ if (isset($this->addressBookInfo['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal'])) {
+ $owner = $this->addressBookInfo['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal'];
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => $owner,
+ 'protected' => true,
+ ];
+ if ($this->addressBookInfo['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only']) {
+ $acl[] = [
+ 'privilege' => '{DAV:}write',
+ 'principal' => $owner,
+ 'protected' => true,
+ ];
+ }
+ }
+
+ /** @var CardDavBackend $carddavBackend */
+ $carddavBackend = $this->carddavBackend;
+ return $carddavBackend->applyShareAcl($this->getResourceId(), $acl);
+ }
+
+ function getChildACL() {
+ $acl = parent::getChildACL();
+ if ($this->getOwner() === 'principals/system/system') {
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => '{DAV:}authenticated',
+ 'protected' => true,
+ ];
+ }
+
+ /** @var CardDavBackend $carddavBackend */
+ $carddavBackend = $this->carddavBackend;
+ return $carddavBackend->applyShareAcl($this->getResourceId(), $acl);
+ }
+
+ function getChild($name) {
+ $obj = $this->carddavBackend->getCard($this->getResourceId(), $name);
+ if (!$obj) {
+ throw new NotFound('Card not found');
+ }
+ return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
+ }
+
+ /**
+ * @return int
+ */
+ public function getResourceId() {
+ return $this->addressBookInfo['id'];
+ }
+
+ function getOwner() {
+ if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
+ return $this->addressBookInfo['{http://owncloud.org/ns}owner-principal'];
+ }
+ return parent::getOwner();
+ }
+
+ function delete() {
+ if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
+ $principal = 'principal:' . parent::getOwner();
+ $shares = $this->getShares();
+ $shares = array_filter($shares, function($share) use ($principal){
+ return $share['href'] === $principal;
+ });
+ if (empty($shares)) {
+ throw new Forbidden();
+ }
+
+ /** @var CardDavBackend $cardDavBackend */
+ $cardDavBackend = $this->carddavBackend;
+ $cardDavBackend->updateShares($this, [], [
+ 'href' => $principal
+ ]);
+ return;
+ }
+ parent::delete();
+ }
+}
diff --git a/apps/dav/lib/carddav/addressbookimpl.php b/apps/dav/lib/carddav/addressbookimpl.php
new file mode 100644
index 00000000000..1d7b55c1a5d
--- /dev/null
+++ b/apps/dav/lib/carddav/addressbookimpl.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\CardDAV;
+
+use OCP\Constants;
+use OCP\IAddressBook;
+use Sabre\VObject\Component\VCard;
+use Sabre\VObject\Property\Text;
+use Sabre\VObject\Reader;
+use Sabre\VObject\UUIDUtil;
+
+class AddressBookImpl implements IAddressBook {
+
+ /** @var CardDavBackend */
+ private $backend;
+
+ /** @var array */
+ private $addressBookInfo;
+
+ /** @var AddressBook */
+ private $addressBook;
+
+ /**
+ * AddressBookImpl constructor.
+ *
+ * @param AddressBook $addressBook
+ * @param array $addressBookInfo
+ * @param CardDavBackend $backend
+ */
+ public function __construct(
+ AddressBook $addressBook,
+ array $addressBookInfo,
+ CardDavBackend $backend) {
+
+ $this->addressBook = $addressBook;
+ $this->addressBookInfo = $addressBookInfo;
+ $this->backend = $backend;
+ }
+
+ /**
+ * @return string defining the technical unique key
+ * @since 5.0.0
+ */
+ public function getKey() {
+ return $this->addressBookInfo['id'];
+ }
+
+ /**
+ * In comparison to getKey() this function returns a human readable (maybe translated) name
+ *
+ * @return mixed
+ * @since 5.0.0
+ */
+ public function getDisplayName() {
+ return $this->addressBookInfo['{DAV:}displayname'];
+ }
+
+ /**
+ * @param string $pattern which should match within the $searchProperties
+ * @param array $searchProperties defines the properties within the query pattern should match
+ * @param array $options - for future use. One should always have options!
+ * @return array an array of contacts which are arrays of key-value-pairs
+ * @since 5.0.0
+ */
+ public function search($pattern, $searchProperties, $options) {
+ $result = $this->backend->search($this->getKey(), $pattern, $searchProperties);
+
+ $vCards = [];
+ foreach ($result as $cardData) {
+ $vCards[] = $this->vCard2Array($this->readCard($cardData));
+ }
+
+ return $vCards;
+ }
+
+ /**
+ * @param array $properties this array if key-value-pairs defines a contact
+ * @return array an array representing the contact just created or updated
+ * @since 5.0.0
+ */
+ public function createOrUpdate($properties) {
+ $update = false;
+ if (!isset($properties['UID'])) { // create a new contact
+ $uid = $this->createUid();
+ $uri = $uid . '.vcf';
+ $vCard = $this->createEmptyVCard($uid);
+ } else { // update existing contact
+ $uid = $properties['UID'];
+ $uri = $uid . '.vcf';
+ $vCardData = $this->backend->getCard($this->getKey(), $uri);
+ $vCard = $this->readCard($vCardData['carddata']);
+ $update = true;
+ }
+
+ foreach ($properties as $key => $value) {
+ $vCard->$key = $vCard->createProperty($key, $value);
+ }
+
+ if ($update) {
+ $this->backend->updateCard($this->getKey(), $uri, $vCard->serialize());
+ } else {
+ $this->backend->createCard($this->getKey(), $uri, $vCard->serialize());
+ }
+
+ return $this->vCard2Array($vCard);
+
+ }
+
+ /**
+ * @return mixed
+ * @since 5.0.0
+ */
+ public function getPermissions() {
+ $permissions = $this->addressBook->getACL();
+ $result = 0;
+ foreach ($permissions as $permission) {
+ switch($permission['privilege']) {
+ case '{DAV:}read':
+ $result |= Constants::PERMISSION_READ;
+ break;
+ case '{DAV:}write':
+ $result |= Constants::PERMISSION_CREATE;
+ $result |= Constants::PERMISSION_UPDATE;
+ break;
+ case '{DAV:}all':
+ $result |= Constants::PERMISSION_ALL;
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param object $id the unique identifier to a contact
+ * @return bool successful or not
+ * @since 5.0.0
+ */
+ public function delete($id) {
+ $uri = $this->backend->getCardUri($id);
+ return $this->backend->deleteCard($this->addressBookInfo['id'], $uri);
+ }
+
+ /**
+ * read vCard data into a vCard object
+ *
+ * @param string $cardData
+ * @return VCard
+ */
+ protected function readCard($cardData) {
+ return Reader::read($cardData);
+ }
+
+ /**
+ * create UID for contact
+ *
+ * @return string
+ */
+ protected function createUid() {
+ do {
+ $uid = $this->getUid();
+ $contact = $this->backend->getContact($uid . '.vcf');
+ } while (!empty($contact));
+
+ return $uid;
+ }
+
+ /**
+ * getUid is only there for testing, use createUid instead
+ */
+ protected function getUid() {
+ return UUIDUtil::getUUID();
+ }
+
+ /**
+ * create empty vcard
+ *
+ * @param string $uid
+ * @return VCard
+ */
+ protected function createEmptyVCard($uid) {
+ $vCard = new VCard();
+ $vCard->add(new Text($vCard, 'UID', $uid));
+ return $vCard;
+ }
+
+ /**
+ * create array with all vCard properties
+ *
+ * @param VCard $vCard
+ * @return array
+ */
+ protected function vCard2Array(VCard $vCard) {
+ $result = [];
+ foreach ($vCard->children as $property) {
+ $result[$property->name] = $property->getValue();
+ }
+ if ($this->addressBookInfo['principaluri'] === 'principals/system/system' &&
+ $this->addressBookInfo['uri'] === 'system') {
+ $result['isLocalSystemBook'] = true;
+ }
+ return $result;
+ }
+}
diff --git a/apps/dav/lib/carddav/addressbookroot.php b/apps/dav/lib/carddav/addressbookroot.php
new file mode 100644
index 00000000000..2680135dec2
--- /dev/null
+++ b/apps/dav/lib/carddav/addressbookroot.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\CardDAV;
+
+class AddressBookRoot extends \Sabre\CardDAV\AddressBookRoot {
+
+ /**
+ * This method returns a node for a principal.
+ *
+ * The passed array contains principal information, and is guaranteed to
+ * at least contain a uri item. Other properties may or may not be
+ * supplied by the authentication backend.
+ *
+ * @param array $principal
+ * @return \Sabre\DAV\INode
+ */
+ function getChildForPrincipal(array $principal) {
+
+ return new UserAddressBooks($this->carddavBackend, $principal['uri']);
+
+ }
+
+ function getName() {
+
+ // Grabbing all the components of the principal path.
+ $parts = explode('/', $this->principalPrefix);
+
+ // We are only interested in the second part.
+ return $parts[1];
+
+ }
+
+}
diff --git a/apps/dav/lib/carddav/card.php b/apps/dav/lib/carddav/card.php
new file mode 100644
index 00000000000..d848f2e28ec
--- /dev/null
+++ b/apps/dav/lib/carddav/card.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\CardDAV;
+
+class Card extends \Sabre\CardDAV\Card {
+
+ function getACL() {
+ $acl = parent::getACL();
+ if ($this->getOwner() === 'principals/system/system') {
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => '{DAV:}authenticated',
+ 'protected' => true,
+ ];
+ }
+
+ /** @var CardDavBackend $carddavBackend */
+ $carddavBackend = $this->carddavBackend;
+ return $carddavBackend->applyShareAcl($this->getBookId(), $acl);
+ }
+
+ private function getBookId() {
+ return $this->addressBookInfo['id'];
+ }
+
+}
diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php
index b2597baedc6..9ca166c22a2 100644
--- a/apps/dav/lib/carddav/carddavbackend.php
+++ b/apps/dav/lib/carddav/carddavbackend.php
@@ -1,9 +1,11 @@
<?php
-
/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,19 +24,59 @@
namespace OCA\DAV\CardDAV;
+use OCA\DAV\Connector\Sabre\Principal;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCA\DAV\DAV\Sharing\Backend;
+use OCA\DAV\DAV\Sharing\IShareable;
+use OCP\IDBConnection;
use Sabre\CardDAV\Backend\BackendInterface;
use Sabre\CardDAV\Backend\SyncSupport;
use Sabre\CardDAV\Plugin;
use Sabre\DAV\Exception\BadRequest;
+use Sabre\HTTP\URLUtil;
+use Sabre\VObject\Component\VCard;
+use Sabre\VObject\Reader;
class CardDavBackend implements BackendInterface, SyncSupport {
- public function __construct(\OCP\IDBConnection $db) {
+ /** @var Principal */
+ private $principalBackend;
+
+ /** @var string */
+ private $dbCardsTable = 'cards';
+
+ /** @var string */
+ private $dbCardsPropertiesTable = 'cards_properties';
+
+ /** @var IDBConnection */
+ private $db;
+
+ /** @var Backend */
+ private $sharingBackend;
+
+ /** @var array properties to index */
+ public static $indexProperties = array(
+ 'BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME',
+ 'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO', 'CLOUD');
+
+ const ACCESS_OWNER = 1;
+ const ACCESS_READ_WRITE = 2;
+ const ACCESS_READ = 3;
+
+ /**
+ * CardDavBackend constructor.
+ *
+ * @param IDBConnection $db
+ * @param Principal $principalBackend
+ */
+ public function __construct(IDBConnection $db, Principal $principalBackend) {
$this->db = $db;
+ $this->principalBackend = $principalBackend;
+ $this->sharingBackend = new Backend($this->db, 'addressbook');
}
/**
- * Returns the list of addressbooks for a specific user.
+ * Returns the list of address books for a specific user.
*
* Every addressbook should have the following properties:
* id - an arbitrary unique id
@@ -61,7 +103,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
$result = $query->execute();
while($row = $result->fetch()) {
- $addressBooks[] = [
+ $addressBooks[$row['id']] = [
'id' => $row['id'],
'uri' => $row['uri'],
'principaluri' => $row['principaluri'],
@@ -73,7 +115,96 @@ class CardDavBackend implements BackendInterface, SyncSupport {
}
$result->closeCursor();
- return $addressBooks;
+ // query for shared calendars
+ $principals = $this->principalBackend->getGroupMembership($principalUri);
+ $principals[]= $principalUri;
+
+ $query = $this->db->getQueryBuilder();
+ $result = $query->select(['a.id', 'a.uri', 'a.displayname', 'a.principaluri', 'a.description', 'a.synctoken', 's.access'])
+ ->from('dav_shares', 's')
+ ->join('s', 'addressbooks', 'a', $query->expr()->eq('s.resourceid', 'a.id'))
+ ->where($query->expr()->in('s.principaluri', $query->createParameter('principaluri')))
+ ->andWhere($query->expr()->eq('s.type', $query->createParameter('type')))
+ ->setParameter('type', 'addressbook')
+ ->setParameter('principaluri', $principals, IQueryBuilder::PARAM_STR_ARRAY)
+ ->execute();
+
+ while($row = $result->fetch()) {
+ list(, $name) = URLUtil::splitPath($row['principaluri']);
+ $uri = $row['uri'] . '_shared_by_' . $name;
+ $displayName = $row['displayname'] . "($name)";
+ $addressBooks[$row['id']] = [
+ 'id' => $row['id'],
+ 'uri' => $uri,
+ 'principaluri' => $principalUri,
+ '{DAV:}displayname' => $displayName,
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
+ '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
+ '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $row['principaluri'],
+ '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only' => $row['access'] === self::ACCESS_READ,
+ ];
+ }
+ $result->closeCursor();
+
+ return array_values($addressBooks);
+ }
+
+ /**
+ * @param int $addressBookId
+ */
+ public function getAddressBookById($addressBookId) {
+ $query = $this->db->getQueryBuilder();
+ $result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
+ ->from('addressbooks')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId)))
+ ->execute();
+
+ $row = $result->fetch();
+ $result->closeCursor();
+ if ($row === false) {
+ return null;
+ }
+
+ return [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $row['principaluri'],
+ '{DAV:}displayname' => $row['displayname'],
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
+ '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
+ ];
+ }
+
+ /**
+ * @param $addressBookUri
+ * @return array|null
+ */
+ public function getAddressBooksByUri($principal, $addressBookUri) {
+ $query = $this->db->getQueryBuilder();
+ $result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
+ ->from('addressbooks')
+ ->where($query->expr()->eq('uri', $query->createNamedParameter($addressBookUri)))
+ ->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($principal)))
+ ->setMaxResults(1)
+ ->execute();
+
+ $row = $result->fetch();
+ $result->closeCursor();
+ if ($row === false) {
+ return null;
+ }
+
+ return [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $row['principaluri'],
+ '{DAV:}displayname' => $row['displayname'],
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
+ '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
+ ];
}
/**
@@ -86,7 +217,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* Calling the handle method is like telling the PropPatch object "I
* promise I can handle updating this property".
*
- * Read the PropPatch documenation for more info and examples.
+ * Read the PropPatch documentation for more info and examples.
*
* @param string $addressBookId
* @param \Sabre\DAV\PropPatch $propPatch
@@ -134,6 +265,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @param string $principalUri
* @param string $url Just the 'basename' of the url.
* @param array $properties
+ * @return int
* @throws BadRequest
*/
function createAddressBook($principalUri, $url, array $properties) {
@@ -177,6 +309,8 @@ class CardDavBackend implements BackendInterface, SyncSupport {
])
->setParameters($values)
->execute();
+
+ return $query->getLastInsertId();
}
/**
@@ -201,6 +335,13 @@ class CardDavBackend implements BackendInterface, SyncSupport {
->where($query->expr()->eq('id', $query->createParameter('id')))
->setParameter('id', $addressBookId)
->execute();
+
+ $this->sharingBackend->deleteAllShares($addressBookId);
+
+ $query->delete($this->dbCardsPropertiesTable)
+ ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
+ ->execute();
+
}
/**
@@ -281,7 +422,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* If the backend supports this, it may allow for some speed-ups.
*
* @param mixed $addressBookId
- * @param array $uris
+ * @param string[] $uris
* @return array
*/
function getMultipleCards($addressBookId, array $uris) {
@@ -290,7 +431,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
->from('cards')
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
->andWhere($query->expr()->in('uri', $query->createParameter('uri')))
- ->setParameter('uri', $uris, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
+ ->setParameter('uri', $uris, IQueryBuilder::PARAM_STR_ARRAY);
$cards = [];
@@ -328,7 +469,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
- * @return string|null
+ * @return string
*/
function createCard($addressBookId, $cardUri, $cardData) {
$etag = md5($cardData);
@@ -336,7 +477,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
$query = $this->db->getQueryBuilder();
$query->insert('cards')
->values([
- 'carddata' => $query->createNamedParameter($cardData),
+ 'carddata' => $query->createNamedParameter($cardData, \PDO::PARAM_LOB),
'uri' => $query->createNamedParameter($cardUri),
'lastmodified' => $query->createNamedParameter(time()),
'addressbookid' => $query->createNamedParameter($addressBookId),
@@ -346,6 +487,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
->execute();
$this->addChange($addressBookId, $cardUri, 1);
+ $this->updateProperties($addressBookId, $cardUri, $cardData);
return '"' . $etag . '"';
}
@@ -373,7 +515,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
- * @return string|null
+ * @return string
*/
function updateCard($addressBookId, $cardUri, $cardData) {
@@ -389,6 +531,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
->execute();
$this->addChange($addressBookId, $cardUri, 2);
+ $this->updateProperties($addressBookId, $cardUri, $cardData);
return '"' . $etag . '"';
}
@@ -401,6 +544,11 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @return bool
*/
function deleteCard($addressBookId, $cardUri) {
+ try {
+ $cardId = $this->getCardId($cardUri);
+ } catch (\InvalidArgumentException $e) {
+ $cardId = null;
+ }
$query = $this->db->getQueryBuilder();
$ret = $query->delete('cards')
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
@@ -409,7 +557,14 @@ class CardDavBackend implements BackendInterface, SyncSupport {
$this->addChange($addressBookId, $cardUri, 3);
- return $ret === 1;
+ if ($ret === 1) {
+ if ($cardId !== null) {
+ $this->purgeProperties($addressBookId, $cardId);
+ }
+ return true;
+ }
+
+ return false;
}
/**
@@ -561,4 +716,207 @@ class CardDavBackend implements BackendInterface, SyncSupport {
return $cardData;
}
+ /**
+ * @param IShareable $shareable
+ * @param string[] $add
+ * @param string[] $remove
+ */
+ public function updateShares(IShareable $shareable, $add, $remove) {
+ $this->sharingBackend->updateShares($shareable, $add, $remove);
+ }
+
+ /**
+ * search contact
+ *
+ * @param int $addressBookId
+ * @param string $pattern which should match within the $searchProperties
+ * @param array $searchProperties defines the properties within the query pattern should match
+ * @return array an array of contacts which are arrays of key-value-pairs
+ */
+ public function search($addressBookId, $pattern, $searchProperties) {
+ $query = $this->db->getQueryBuilder();
+ $query2 = $this->db->getQueryBuilder();
+ $query2->selectDistinct('cp.cardid')->from($this->dbCardsPropertiesTable, 'cp');
+ foreach ($searchProperties as $property) {
+ $query2->orWhere(
+ $query2->expr()->andX(
+ $query2->expr()->eq('cp.name', $query->createNamedParameter($property)),
+ $query2->expr()->like('cp.value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%'))
+ )
+ );
+ }
+ $query2->andWhere($query2->expr()->eq('cp.addressbookid', $query->createNamedParameter($addressBookId)));
+
+ $query->select('c.carddata')->from($this->dbCardsTable, 'c')
+ ->where($query->expr()->in('c.id', $query->createFunction($query2->getSQL())));
+
+ $result = $query->execute();
+ $cards = $result->fetchAll();
+
+ $result->closeCursor();
+
+ return array_map(function($array) {return $this->readBlob($array['carddata']);}, $cards);
+
+ }
+
+ /**
+ * get URI from a given contact
+ *
+ * @param int $id
+ * @return string
+ */
+ public function getCardUri($id) {
+ $query = $this->db->getQueryBuilder();
+ $query->select('uri')->from($this->dbCardsTable)
+ ->where($query->expr()->eq('id', $query->createParameter('id')))
+ ->setParameter('id', $id);
+
+ $result = $query->execute();
+ $uri = $result->fetch();
+ $result->closeCursor();
+
+ if (!isset($uri['uri'])) {
+ throw new \InvalidArgumentException('Card does not exists: ' . $id);
+ }
+
+ return $uri['uri'];
+ }
+
+ /**
+ * return contact with the given URI
+ *
+ * @param string $uri
+ * @returns array
+ */
+ public function getContact($uri) {
+ $result = [];
+ $query = $this->db->getQueryBuilder();
+ $query->select('*')->from($this->dbCardsTable)
+ ->where($query->expr()->eq('uri', $query->createParameter('uri')))
+ ->setParameter('uri', $uri);
+ $queryResult = $query->execute();
+ $contact = $queryResult->fetch();
+ $queryResult->closeCursor();
+
+ if (is_array($contact)) {
+ $result = $contact;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the list of people whom this address book is shared with.
+ *
+ * Every element in this array should have the following properties:
+ * * href - Often a mailto: address
+ * * commonName - Optional, for example a first + last name
+ * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
+ * * readOnly - boolean
+ * * summary - Optional, a description for the share
+ *
+ * @return array
+ */
+ public function getShares($addressBookId) {
+ return $this->sharingBackend->getShares($addressBookId);
+ }
+
+ /**
+ * update properties table
+ *
+ * @param int $addressBookId
+ * @param string $cardUri
+ * @param string $vCardSerialized
+ */
+ protected function updateProperties($addressBookId, $cardUri, $vCardSerialized) {
+ $cardId = $this->getCardId($cardUri);
+ $vCard = $this->readCard($vCardSerialized);
+
+ $this->purgeProperties($addressBookId, $cardId);
+
+ $query = $this->db->getQueryBuilder();
+ $query->insert($this->dbCardsPropertiesTable)
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter($addressBookId),
+ 'cardid' => $query->createNamedParameter($cardId),
+ 'name' => $query->createParameter('name'),
+ 'value' => $query->createParameter('value'),
+ 'preferred' => $query->createParameter('preferred')
+ ]
+ );
+
+ foreach ($vCard->children as $property) {
+ if(!in_array($property->name, self::$indexProperties)) {
+ continue;
+ }
+ $preferred = 0;
+ foreach($property->parameters as $parameter) {
+ if ($parameter->name == 'TYPE' && strtoupper($parameter->getValue()) == 'PREF') {
+ $preferred = 1;
+ break;
+ }
+ }
+ $query->setParameter('name', $property->name);
+ $query->setParameter('value', substr($property->getValue(), 0, 254));
+ $query->setParameter('preferred', $preferred);
+ $query->execute();
+ }
+ }
+
+ /**
+ * read vCard data into a vCard object
+ *
+ * @param string $cardData
+ * @return VCard
+ */
+ protected function readCard($cardData) {
+ return Reader::read($cardData);
+ }
+
+ /**
+ * delete all properties from a given card
+ *
+ * @param int $addressBookId
+ * @param int $cardId
+ */
+ protected function purgeProperties($addressBookId, $cardId) {
+ $query = $this->db->getQueryBuilder();
+ $query->delete($this->dbCardsPropertiesTable)
+ ->where($query->expr()->eq('cardid', $query->createNamedParameter($cardId)))
+ ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
+ $query->execute();
+ }
+
+ /**
+ * get ID from a given contact
+ *
+ * @param string $uri
+ * @return int
+ */
+ protected function getCardId($uri) {
+ $query = $this->db->getQueryBuilder();
+ $query->select('id')->from($this->dbCardsTable)
+ ->where($query->expr()->eq('uri', $query->createNamedParameter($uri)));
+
+ $result = $query->execute();
+ $cardIds = $result->fetch();
+ $result->closeCursor();
+
+ if (!isset($cardIds['id'])) {
+ throw new \InvalidArgumentException('Card does not exists: ' . $uri);
+ }
+
+ return (int)$cardIds['id'];
+ }
+
+ /**
+ * For shared address books the sharee is set in the ACL of the address book
+ * @param $addressBookId
+ * @param $acl
+ * @return array
+ */
+ public function applyShareAcl($addressBookId, $acl) {
+ return $this->sharingBackend->applyShareAcl($addressBookId, $acl);
+ }
}
diff --git a/apps/dav/lib/carddav/contactsmanager.php b/apps/dav/lib/carddav/contactsmanager.php
new file mode 100644
index 00000000000..7900c6ccae0
--- /dev/null
+++ b/apps/dav/lib/carddav/contactsmanager.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\CardDAV;
+
+use OCP\Contacts\IManager;
+
+class ContactsManager {
+
+ /**
+ * ContactsManager constructor.
+ *
+ * @param CardDavBackend $backend
+ */
+ public function __construct(CardDavBackend $backend) {
+ $this->backend = $backend;
+ }
+
+ /**
+ * @param IManager $cm
+ * @param string $userId
+ */
+ public function setupContactsProvider(IManager $cm, $userId) {
+ $addressBooks = $this->backend->getAddressBooksForUser("principals/users/$userId");
+ $this->register($cm, $addressBooks);
+ $addressBooks = $this->backend->getAddressBooksForUser("principals/system/system");
+ $this->register($cm, $addressBooks);
+ }
+
+ /**
+ * @param IManager $cm
+ * @param $addressBooks
+ */
+ private function register(IManager $cm, $addressBooks) {
+ foreach ($addressBooks as $addressBookInfo) {
+ $addressBook = new \OCA\DAV\CardDAV\AddressBook($this->backend, $addressBookInfo);
+ $cm->registerAddressBook(
+ new AddressBookImpl(
+ $addressBook,
+ $addressBookInfo,
+ $this->backend
+ )
+ );
+ }
+ }
+
+}
diff --git a/apps/dav/lib/carddav/converter.php b/apps/dav/lib/carddav/converter.php
new file mode 100644
index 00000000000..c8d9b94c267
--- /dev/null
+++ b/apps/dav/lib/carddav/converter.php
@@ -0,0 +1,171 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\CardDAV;
+
+use OCP\IImage;
+use OCP\IUser;
+use Sabre\VObject\Component\VCard;
+use Sabre\VObject\Property\Text;
+
+class Converter {
+
+ /**
+ * @param IUser $user
+ * @return VCard
+ */
+ public function createCardFromUser(IUser $user) {
+
+ $uid = $user->getUID();
+ $displayName = $user->getDisplayName();
+ $displayName = empty($displayName ) ? $uid : $displayName;
+ $emailAddress = $user->getEMailAddress();
+ $cloudId = $user->getCloudId();
+ $image = $this->getAvatarImage($user);
+
+ $vCard = new VCard();
+ $vCard->add(new Text($vCard, 'UID', $uid));
+ if (!empty($displayName)) {
+ $vCard->add(new Text($vCard, 'FN', $displayName));
+ $vCard->add(new Text($vCard, 'N', $this->splitFullName($displayName)));
+ }
+ if (!empty($emailAddress)) {
+ $vCard->add(new Text($vCard, 'EMAIL', $emailAddress, ['TYPE' => 'OTHER']));
+ }
+ if (!empty($cloudId)) {
+ $vCard->add(new Text($vCard, 'CLOUD', $cloudId));
+ }
+ if ($image) {
+ $vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]);
+ }
+ $vCard->validate();
+
+ return $vCard;
+ }
+
+ /**
+ * @param VCard $vCard
+ * @param IUser $user
+ * @return bool
+ */
+ public function updateCard(VCard $vCard, IUser $user) {
+ $uid = $user->getUID();
+ $displayName = $user->getDisplayName();
+ $displayName = empty($displayName ) ? $uid : $displayName;
+ $emailAddress = $user->getEMailAddress();
+ $cloudId = $user->getCloudId();
+ $image = $this->getAvatarImage($user);
+
+ $updated = false;
+ if($this->propertyNeedsUpdate($vCard, 'FN', $displayName)) {
+ $vCard->FN = new Text($vCard, 'FN', $displayName);
+ unset($vCard->N);
+ $vCard->add(new Text($vCard, 'N', $this->splitFullName($displayName)));
+ $updated = true;
+ }
+ if($this->propertyNeedsUpdate($vCard, 'EMAIL', $emailAddress)) {
+ $vCard->EMAIL = new Text($vCard, 'EMAIL', $emailAddress);
+ $updated = true;
+ }
+ if($this->propertyNeedsUpdate($vCard, 'CLOUD', $cloudId)) {
+ $vCard->CLOUD = new Text($vCard, 'CLOUD', $cloudId);
+ $updated = true;
+ }
+
+ if($this->propertyNeedsUpdate($vCard, 'PHOTO', $image)) {
+ $vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]);
+ $updated = true;
+ }
+
+ if (empty($emailAddress) && !is_null($vCard->EMAIL)) {
+ unset($vCard->EMAIL);
+ $updated = true;
+ }
+ if (empty($cloudId) && !is_null($vCard->CLOUD)) {
+ unset($vCard->CLOUD);
+ $updated = true;
+ }
+ if (empty($image) && !is_null($vCard->PHOTO)) {
+ unset($vCard->PHOTO);
+ $updated = true;
+ }
+
+ return $updated;
+ }
+
+ /**
+ * @param VCard $vCard
+ * @param string $name
+ * @param string|IImage $newValue
+ * @return bool
+ */
+ private function propertyNeedsUpdate(VCard $vCard, $name, $newValue) {
+ if (is_null($newValue)) {
+ return false;
+ }
+ $value = $vCard->__get($name);
+ if (!is_null($value)) {
+ $value = $value->getValue();
+ $newValue = $newValue instanceof IImage ? $newValue->data() : $newValue;
+
+ return $value !== $newValue;
+ }
+ return true;
+ }
+
+ /**
+ * @param string $fullName
+ * @return string[]
+ */
+ public function splitFullName($fullName) {
+ // Very basic western style parsing. I'm not gonna implement
+ // https://github.com/android/platform_packages_providers_contactsprovider/blob/master/src/com/android/providers/contacts/NameSplitter.java ;)
+
+ $elements = explode(' ', $fullName);
+ $result = ['', '', '', '', ''];
+ if (count($elements) > 2) {
+ $result[0] = implode(' ', array_slice($elements, count($elements)-1));
+ $result[1] = $elements[0];
+ $result[2] = implode(' ', array_slice($elements, 1, count($elements)-2));
+ } elseif (count($elements) === 2) {
+ $result[0] = $elements[1];
+ $result[1] = $elements[0];
+ } else {
+ $result[0] = $elements[0];
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param IUser $user
+ * @return null|IImage
+ */
+ private function getAvatarImage(IUser $user) {
+ try {
+ $image = $user->getAvatarImage(-1);
+ return $image;
+ } catch (\Exception $ex) {
+ return null;
+ }
+ }
+
+}
diff --git a/apps/dav/lib/carddav/plugin.php b/apps/dav/lib/carddav/plugin.php
new file mode 100644
index 00000000000..4acc1037b52
--- /dev/null
+++ b/apps/dav/lib/carddav/plugin.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\CardDAV;
+
+use Sabre\HTTP\URLUtil;
+
+class Plugin extends \Sabre\CardDAV\Plugin {
+
+ /**
+ * Returns the addressbook home for a given principal
+ *
+ * @param string $principal
+ * @return string
+ */
+ protected function getAddressbookHomeForPrincipal($principal) {
+
+ if (strrpos($principal, 'principals/users', -strlen($principal)) !== FALSE) {
+ list(, $principalId) = URLUtil::splitPath($principal);
+ return self::ADDRESSBOOK_ROOT . '/users/' . $principalId;
+ }
+ if (strrpos($principal, 'principals/system', -strlen($principal)) !== FALSE) {
+ list(, $principalId) = URLUtil::splitPath($principal);
+ return self::ADDRESSBOOK_ROOT . '/system/' . $principalId;
+ }
+
+ throw new \LogicException('This is not supposed to happen');
+ }
+}
diff --git a/apps/dav/lib/carddav/syncjob.php b/apps/dav/lib/carddav/syncjob.php
new file mode 100644
index 00000000000..0554af6fbf1
--- /dev/null
+++ b/apps/dav/lib/carddav/syncjob.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\CardDAV;
+
+use OC\BackgroundJob\TimedJob;
+use OCA\Dav\AppInfo\Application;
+
+class SyncJob extends TimedJob {
+
+ public function __construct() {
+ // Run once a day
+ $this->setInterval(24 * 60 * 60);
+ }
+
+ protected function run($argument) {
+ $app = new Application();
+ /** @var SyncService $ss */
+ $ss = $app->getSyncService();
+ $ss->syncInstance();
+ }
+}
diff --git a/apps/dav/lib/carddav/syncservice.php b/apps/dav/lib/carddav/syncservice.php
new file mode 100644
index 00000000000..4b5907620e6
--- /dev/null
+++ b/apps/dav/lib/carddav/syncservice.php
@@ -0,0 +1,265 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\CardDAV;
+
+use OCP\IUser;
+use OCP\IUserManager;
+use Sabre\DAV\Client;
+use Sabre\DAV\Xml\Response\MultiStatus;
+use Sabre\DAV\Xml\Service;
+use Sabre\VObject\Reader;
+
+class SyncService {
+
+ /** @var CardDavBackend */
+ private $backend;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var array */
+ private $localSystemAddressBook;
+
+ public function __construct(CardDavBackend $backend, IUserManager $userManager) {
+ $this->backend = $backend;
+ $this->userManager = $userManager;
+ }
+
+ /**
+ * @param string $url
+ * @param string $userName
+ * @param string $sharedSecret
+ * @param string $syncToken
+ * @param int $targetBookId
+ * @param string $targetPrincipal
+ * @param array $targetProperties
+ * @return string
+ */
+ public function syncRemoteAddressBook($url, $userName, $sharedSecret, $syncToken, $targetBookId, $targetPrincipal, $targetProperties) {
+ // 1. create addressbook
+ $book = $this->ensureSystemAddressBookExists($targetPrincipal, $targetBookId, $targetProperties);
+ $addressBookId = $book['id'];
+
+ // 2. query changes
+ $response = $this->requestSyncReport($url, $userName, $sharedSecret, $syncToken);
+
+ // 3. apply changes
+ // TODO: use multi-get for download
+ foreach ($response['response'] as $resource => $status) {
+ $cardUri = basename($resource);
+ if (isset($status[200])) {
+ $vCard = $this->download($url, $sharedSecret, $resource);
+ $existingCard = $this->backend->getCard($addressBookId, $cardUri);
+ if ($existingCard === false) {
+ $this->backend->createCard($addressBookId, $cardUri, $vCard['body']);
+ } else {
+ $this->backend->updateCard($addressBookId, $cardUri, $vCard['body']);
+ }
+ } else {
+ $this->backend->deleteCard($addressBookId, $cardUri);
+ }
+ }
+
+ return $response['token'];
+ }
+
+ /**
+ * @param string $principal
+ * @param string $id
+ * @param array $properties
+ * @return array|null
+ * @throws \Sabre\DAV\Exception\BadRequest
+ */
+ public function ensureSystemAddressBookExists($principal, $id, $properties) {
+ $book = $this->backend->getAddressBooksByUri($principal, $id);
+ if (!is_null($book)) {
+ return $book;
+ }
+ $this->backend->createAddressBook($principal, $id, $properties);
+
+ return $this->backend->getAddressBooksByUri($principal, $id);
+ }
+
+ /**
+ * @param string $url
+ * @param string $userName
+ * @param string $sharedSecret
+ * @param string $syncToken
+ * @return array
+ */
+ protected function requestSyncReport($url, $userName, $sharedSecret, $syncToken) {
+ $settings = [
+ 'baseUri' => $url . '/',
+ 'userName' => $userName,
+ 'password' => $sharedSecret,
+ ];
+ $client = new Client($settings);
+ $client->setThrowExceptions(true);
+
+ $addressBookUrl = "remote.php/dav/addressbooks/system/system/system";
+ $body = $this->buildSyncCollectionRequestBody($syncToken);
+
+ $response = $client->request('REPORT', $addressBookUrl, $body, [
+ 'Content-Type' => 'application/xml'
+ ]);
+
+ $result = $this->parseMultiStatus($response['body']);
+
+ return $result;
+ }
+
+ /**
+ * @param string $url
+ * @param string $sharedSecret
+ * @param string $resourcePath
+ * @return array
+ */
+ protected function download($url, $sharedSecret, $resourcePath) {
+ $settings = [
+ 'baseUri' => $url,
+ 'userName' => 'system',
+ 'password' => $sharedSecret,
+ ];
+ $client = new Client($settings);
+ $client->setThrowExceptions(true);
+
+ $response = $client->request('GET', $resourcePath);
+ return $response;
+ }
+
+ /**
+ * @param string|null $syncToken
+ * @return string
+ */
+ private function buildSyncCollectionRequestBody($syncToken) {
+
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+ $dom->formatOutput = true;
+ $root = $dom->createElementNS('DAV:', 'd:sync-collection');
+ $sync = $dom->createElement('d:sync-token', $syncToken);
+ $prop = $dom->createElement('d:prop');
+ $cont = $dom->createElement('d:getcontenttype');
+ $etag = $dom->createElement('d:getetag');
+
+ $prop->appendChild($cont);
+ $prop->appendChild($etag);
+ $root->appendChild($sync);
+ $root->appendChild($prop);
+ $dom->appendChild($root);
+ $body = $dom->saveXML();
+
+ return $body;
+ }
+
+ /**
+ * @param string $body
+ * @return array
+ * @throws \Sabre\Xml\ParseException
+ */
+ private function parseMultiStatus($body) {
+ $xml = new Service();
+
+ /** @var MultiStatus $multiStatus */
+ $multiStatus = $xml->expect('{DAV:}multistatus', $body);
+
+ $result = [];
+ foreach ($multiStatus->getResponses() as $response) {
+ $result[$response->getHref()] = $response->getResponseProperties();
+ }
+
+ return ['response' => $result, 'token' => $multiStatus->getSyncToken()];
+ }
+
+ /**
+ * @param IUser $user
+ */
+ public function updateUser($user) {
+ $systemAddressBook = $this->getLocalSystemAddressBook();
+ $addressBookId = $systemAddressBook['id'];
+ $converter = new Converter();
+ $name = $user->getBackendClassName();
+ $userId = $user->getUID();
+
+ $cardId = "$name:$userId.vcf";
+ $card = $this->backend->getCard($addressBookId, $cardId);
+ if ($card === false) {
+ $vCard = $converter->createCardFromUser($user);
+ $this->backend->createCard($addressBookId, $cardId, $vCard->serialize());
+ } else {
+ $vCard = Reader::read($card['carddata']);
+ if ($converter->updateCard($vCard, $user)) {
+ $this->backend->updateCard($addressBookId, $cardId, $vCard->serialize());
+ }
+ }
+ }
+
+ /**
+ * @param IUser|string $userOrCardId
+ */
+ public function deleteUser($userOrCardId) {
+ $systemAddressBook = $this->getLocalSystemAddressBook();
+ if ($userOrCardId instanceof IUser){
+ $name = $userOrCardId->getBackendClassName();
+ $userId = $userOrCardId->getUID();
+
+ $userOrCardId = "$name:$userId.vcf";
+ }
+ $this->backend->deleteCard($systemAddressBook['id'], $userOrCardId);
+ }
+
+ /**
+ * @return array|null
+ */
+ public function getLocalSystemAddressBook() {
+ if (is_null($this->localSystemAddressBook)) {
+ $systemPrincipal = "principals/system/system";
+ $this->localSystemAddressBook = $this->ensureSystemAddressBookExists($systemPrincipal, 'system', [
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance'
+ ]);
+ }
+
+ return $this->localSystemAddressBook;
+ }
+
+ public function syncInstance(\Closure $progressCallback = null) {
+ $systemAddressBook = $this->getLocalSystemAddressBook();
+ $this->userManager->callForAllUsers(function($user) use ($systemAddressBook, $progressCallback) {
+ $this->updateUser($user);
+ if (!is_null($progressCallback)) {
+ $progressCallback();
+ }
+ });
+
+ // remove no longer existing
+ $allCards = $this->backend->getCards($systemAddressBook['id']);
+ foreach($allCards as $card) {
+ $vCard = Reader::read($card['carddata']);
+ $uid = $vCard->UID->getValue();
+ // load backend and see if user exists
+ if (!$this->userManager->userExists($uid)) {
+ $this->deleteUser($card['uri']);
+ }
+ }
+ }
+
+
+}
diff --git a/apps/dav/lib/carddav/useraddressbooks.php b/apps/dav/lib/carddav/useraddressbooks.php
new file mode 100644
index 00000000000..734e3829e69
--- /dev/null
+++ b/apps/dav/lib/carddav/useraddressbooks.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\CardDAV;
+
+class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome {
+
+ /**
+ * Returns a list of addressbooks
+ *
+ * @return array
+ */
+ function getChildren() {
+
+ $addressBooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri);
+ $objects = [];
+ foreach($addressBooks as $addressBook) {
+ $objects[] = new AddressBook($this->carddavBackend, $addressBook);
+ }
+ return $objects;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ function getACL() {
+
+ $acl = parent::getACL();
+ if ($this->principalUri === 'principals/system/system') {
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => '{DAV:}authenticated',
+ 'protected' => true,
+ ];
+ }
+
+ return $acl;
+ }
+
+}
diff --git a/apps/dav/lib/comments/commentnode.php b/apps/dav/lib/comments/commentnode.php
new file mode 100644
index 00000000000..d3cd53bceb1
--- /dev/null
+++ b/apps/dav/lib/comments/commentnode.php
@@ -0,0 +1,254 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Comments;
+
+
+use OCP\Comments\IComment;
+use OCP\Comments\ICommentsManager;
+use OCP\ILogger;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\MethodNotAllowed;
+use Sabre\DAV\PropPatch;
+
+class CommentNode implements \Sabre\DAV\INode, \Sabre\DAV\IProperties {
+ const NS_OWNCLOUD = 'http://owncloud.org/ns';
+
+ const PROPERTY_NAME_UNREAD = '{http://owncloud.org/ns}isUnread';
+ const PROPERTY_NAME_MESSAGE = '{http://owncloud.org/ns}message';
+ const PROPERTY_NAME_ACTOR_DISPLAYNAME = '{http://owncloud.org/ns}actorDisplayName';
+
+ /** @var IComment */
+ public $comment;
+
+ /** @var ICommentsManager */
+ protected $commentsManager;
+
+ /** @var ILogger */
+ protected $logger;
+
+ /** @var array list of properties with key being their name and value their setter */
+ protected $properties = [];
+
+ /** @var IUserManager */
+ protected $userManager;
+
+ /** @var IUserSession */
+ protected $userSession;
+
+ /**
+ * CommentNode constructor.
+ *
+ * @param ICommentsManager $commentsManager
+ * @param IComment $comment
+ * @param IUserManager $userManager
+ * @param IUserSession $userSession
+ * @param ILogger $logger
+ */
+ public function __construct(
+ ICommentsManager $commentsManager,
+ IComment $comment,
+ IUserManager $userManager,
+ IUserSession $userSession,
+ ILogger $logger
+ ) {
+ $this->commentsManager = $commentsManager;
+ $this->comment = $comment;
+ $this->logger = $logger;
+
+ $methods = get_class_methods($this->comment);
+ $methods = array_filter($methods, function($name){
+ return strpos($name, 'get') === 0;
+ });
+ foreach($methods as $getter) {
+ $name = '{'.self::NS_OWNCLOUD.'}' . lcfirst(substr($getter, 3));
+ $this->properties[$name] = $getter;
+ }
+ $this->userManager = $userManager;
+ $this->userSession = $userSession;
+ }
+
+ /**
+ * returns a list of all possible property names
+ *
+ * @return array
+ */
+ static public function getPropertyNames() {
+ return [
+ '{http://owncloud.org/ns}id',
+ '{http://owncloud.org/ns}parentId',
+ '{http://owncloud.org/ns}topmostParentId',
+ '{http://owncloud.org/ns}childrenCount',
+ '{http://owncloud.org/ns}verb',
+ '{http://owncloud.org/ns}actorType',
+ '{http://owncloud.org/ns}actorId',
+ '{http://owncloud.org/ns}creationDateTime',
+ '{http://owncloud.org/ns}latestChildDateTime',
+ '{http://owncloud.org/ns}objectType',
+ '{http://owncloud.org/ns}objectId',
+ // re-used property names are defined as constants
+ self::PROPERTY_NAME_MESSAGE,
+ self::PROPERTY_NAME_ACTOR_DISPLAYNAME,
+ self::PROPERTY_NAME_UNREAD
+ ];
+ }
+
+ protected function checkWriteAccessOnComment() {
+ $user = $this->userSession->getUser();
+ if( $this->comment->getActorType() !== 'users'
+ || is_null($user)
+ || $this->comment->getActorId() !== $user->getUID()
+ ) {
+ throw new Forbidden('Only authors are allowed to edit their comment.');
+ }
+ }
+
+ /**
+ * Deleted the current node
+ *
+ * @return void
+ */
+ function delete() {
+ $this->checkWriteAccessOnComment();
+ $this->commentsManager->delete($this->comment->getId());
+ }
+
+ /**
+ * Returns the name of the node.
+ *
+ * This is used to generate the url.
+ *
+ * @return string
+ */
+ function getName() {
+ return $this->comment->getId();
+ }
+
+ /**
+ * Renames the node
+ *
+ * @param string $name The new name
+ * @throws MethodNotAllowed
+ */
+ function setName($name) {
+ throw new MethodNotAllowed();
+ }
+
+ /**
+ * Returns the last modification time, as a unix timestamp
+ *
+ * @return int
+ */
+ function getLastModified() {
+ return null;
+ }
+
+ /**
+ * update the comment's message
+ *
+ * @param $propertyValue
+ * @return bool
+ * @throws Forbidden
+ */
+ public function updateComment($propertyValue) {
+ $this->checkWriteAccessOnComment();
+ try {
+ $this->comment->setMessage($propertyValue);
+ $this->commentsManager->save($this->comment);
+ return true;
+ } catch (\Exception $e) {
+ $this->logger->logException($e, ['app' => 'dav/comments']);
+ return false;
+ }
+ }
+
+ /**
+ * Updates properties on this node.
+ *
+ * This method received a PropPatch object, which contains all the
+ * information about the update.
+ *
+ * To update specific properties, call the 'handle' method on this object.
+ * Read the PropPatch documentation for more information.
+ *
+ * @param PropPatch $propPatch
+ * @return void
+ */
+ function propPatch(PropPatch $propPatch) {
+ // other properties than 'message' are read only
+ $propPatch->handle(self::PROPERTY_NAME_MESSAGE, [$this, 'updateComment']);
+ }
+
+ /**
+ * Returns a list of properties for this nodes.
+ *
+ * The properties list is a list of propertynames the client requested,
+ * encoded in clark-notation {xmlnamespace}tagname
+ *
+ * If the array is empty, it means 'all properties' were requested.
+ *
+ * Note that it's fine to liberally give properties back, instead of
+ * conforming to the list of requested properties.
+ * The Server class will filter out the extra.
+ *
+ * @param array $properties
+ * @return array
+ */
+ function getProperties($properties) {
+ $properties = array_keys($this->properties);
+
+ $result = [];
+ foreach($properties as $property) {
+ $getter = $this->properties[$property];
+ if(method_exists($this->comment, $getter)) {
+ $result[$property] = $this->comment->$getter();
+ }
+ }
+
+ if($this->comment->getActorType() === 'users') {
+ $user = $this->userManager->get($this->comment->getActorId());
+ $displayName = is_null($user) ? null : $user->getDisplayName();
+ $result[self::PROPERTY_NAME_ACTOR_DISPLAYNAME] = $displayName;
+ }
+
+ $unread = null;
+ $user = $this->userSession->getUser();
+ if(!is_null($user)) {
+ $readUntil = $this->commentsManager->getReadMark(
+ $this->comment->getObjectType(),
+ $this->comment->getObjectId(),
+ $user
+ );
+ if(is_null($readUntil)) {
+ $unread = 'true';
+ } else {
+ $unread = $this->comment->getCreationDateTime() > $readUntil;
+ // re-format for output
+ $unread = $unread ? 'true' : 'false';
+ }
+ }
+ $result[self::PROPERTY_NAME_UNREAD] = $unread;
+
+ return $result;
+ }
+}
diff --git a/apps/dav/lib/comments/commentsplugin.php b/apps/dav/lib/comments/commentsplugin.php
new file mode 100644
index 00000000000..282c14df1e8
--- /dev/null
+++ b/apps/dav/lib/comments/commentsplugin.php
@@ -0,0 +1,245 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Comments;
+
+use OCP\Comments\IComment;
+use OCP\Comments\ICommentsManager;
+use OCP\IUserSession;
+use Sabre\DAV\Exception\BadRequest;
+use Sabre\DAV\Exception\ReportNotSupported;
+use Sabre\DAV\Exception\UnsupportedMediaType;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Server;
+use Sabre\DAV\ServerPlugin;
+use Sabre\DAV\Xml\Element\Response;
+use Sabre\DAV\Xml\Response\MultiStatus;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
+use Sabre\Xml\Writer;
+
+/**
+ * Sabre plugin to handle comments:
+ */
+class CommentsPlugin extends ServerPlugin {
+ // namespace
+ const NS_OWNCLOUD = 'http://owncloud.org/ns';
+
+ const REPORT_NAME = '{http://owncloud.org/ns}filter-comments';
+ const REPORT_PARAM_LIMIT = '{http://owncloud.org/ns}limit';
+ const REPORT_PARAM_OFFSET = '{http://owncloud.org/ns}offset';
+ const REPORT_PARAM_TIMESTAMP = '{http://owncloud.org/ns}datetime';
+
+ /** @var ICommentsManager */
+ protected $commentsManager;
+
+ /** @var \Sabre\DAV\Server $server */
+ private $server;
+
+ /** @var \OCP\IUserSession */
+ protected $userSession;
+
+ /**
+ * Comments plugin
+ *
+ * @param ICommentsManager $commentsManager
+ * @param IUserSession $userSession
+ */
+ public function __construct(ICommentsManager $commentsManager, IUserSession $userSession) {
+ $this->commentsManager = $commentsManager;
+ $this->userSession = $userSession;
+ }
+
+ /**
+ * This initializes the plugin.
+ *
+ * This function is called by Sabre\DAV\Server, after
+ * addPlugin is called.
+ *
+ * This method should set up the required event subscriptions.
+ *
+ * @param Server $server
+ * @return void
+ */
+ function initialize(Server $server) {
+ $this->server = $server;
+ if(strpos($this->server->getRequestUri(), 'comments/') !== 0) {
+ return;
+ }
+
+ $this->server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
+
+ $this->server->xml->classMap['DateTime'] = function(Writer $writer, \DateTime $value) {
+ $writer->write(\Sabre\HTTP\toDate($value));
+ };
+
+ $this->server->on('report', [$this, 'onReport']);
+ $this->server->on('method:POST', [$this, 'httpPost']);
+ }
+
+ /**
+ * POST operation on Comments collections
+ *
+ * @param RequestInterface $request request object
+ * @param ResponseInterface $response response object
+ * @return null|false
+ */
+ public function httpPost(RequestInterface $request, ResponseInterface $response) {
+ $path = $request->getPath();
+ $node = $this->server->tree->getNodeForPath($path);
+ if (!$node instanceof EntityCollection) {
+ return null;
+ }
+
+ $data = $request->getBodyAsString();
+ $comment = $this->createComment(
+ $node->getName(),
+ $node->getId(),
+ $data,
+ $request->getHeader('Content-Type')
+ );
+ $url = $request->getUrl() . '/' . urlencode($comment->getId());
+
+ $response->setHeader('Content-Location', $url);
+
+ // created
+ $response->setStatus(201);
+ return false;
+ }
+
+ /**
+ * Returns a list of reports this plugin supports.
+ *
+ * This will be used in the {DAV:}supported-report-set property.
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getSupportedReportSet($uri) {
+ return [self::REPORT_NAME];
+ }
+
+ /**
+ * REPORT operations to look for comments
+ *
+ * @param string $reportName
+ * @param [] $report
+ * @param string $uri
+ * @return bool
+ * @throws NotFound
+ * @throws ReportNotSupported
+ */
+ public function onReport($reportName, $report, $uri) {
+ $node = $this->server->tree->getNodeForPath($uri);
+ if(!$node instanceof EntityCollection || $reportName !== self::REPORT_NAME) {
+ throw new ReportNotSupported();
+ }
+ $args = ['limit' => 0, 'offset' => 0, 'datetime' => null];
+ $acceptableParameters = [
+ $this::REPORT_PARAM_LIMIT,
+ $this::REPORT_PARAM_OFFSET,
+ $this::REPORT_PARAM_TIMESTAMP
+ ];
+ $ns = '{' . $this::NS_OWNCLOUD . '}';
+ foreach($report as $parameter) {
+ if(!in_array($parameter['name'], $acceptableParameters) || empty($parameter['value'])) {
+ continue;
+ }
+ $args[str_replace($ns, '', $parameter['name'])] = $parameter['value'];
+ }
+
+ if(!is_null($args['datetime'])) {
+ $args['datetime'] = new \DateTime($args['datetime']);
+ }
+
+ $results = $node->findChildren($args['limit'], $args['offset'], $args['datetime']);
+
+ $responses = [];
+ foreach($results as $node) {
+ $nodePath = $this->server->getRequestUri() . '/' . $node->comment->getId();
+ $resultSet = $this->server->getPropertiesForPath($nodePath, CommentNode::getPropertyNames());
+ if(isset($resultSet[0]) && isset($resultSet[0][200])) {
+ $responses[] = new Response(
+ $this->server->getBaseUri() . $nodePath,
+ [200 => $resultSet[0][200]],
+ 200
+ );
+ }
+
+ }
+
+ $xml = $this->server->xml->write(
+ '{DAV:}multistatus',
+ new MultiStatus($responses)
+ );
+
+ $this->server->httpResponse->setStatus(207);
+ $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
+ $this->server->httpResponse->setBody($xml);
+
+ return false;
+ }
+
+ /**
+ * Creates a new comment
+ *
+ * @param string $objectType e.g. "files"
+ * @param string $objectId e.g. the file id
+ * @param string $data JSON encoded string containing the properties of the tag to create
+ * @param string $contentType content type of the data
+ * @return IComment newly created comment
+ *
+ * @throws BadRequest if a field was missing
+ * @throws UnsupportedMediaType if the content type is not supported
+ */
+ private function createComment($objectType, $objectId, $data, $contentType = 'application/json') {
+ if (explode(';', $contentType)[0] === 'application/json') {
+ $data = json_decode($data, true);
+ } else {
+ throw new UnsupportedMediaType();
+ }
+
+ $actorType = $data['actorType'];
+ $actorId = null;
+ if($actorType === 'users') {
+ $user = $this->userSession->getUser();
+ if(!is_null($user)) {
+ $actorId = $user->getUID();
+ }
+ }
+ if(is_null($actorId)) {
+ throw new BadRequest('Invalid actor "' . $actorType .'"');
+ }
+
+ try {
+ $comment = $this->commentsManager->create($actorType, $actorId, $objectType, $objectId);
+ $comment->setMessage($data['message']);
+ $comment->setVerb($data['verb']);
+ $this->commentsManager->save($comment);
+ return $comment;
+ } catch (\InvalidArgumentException $e) {
+ throw new BadRequest('Invalid input values', 0, $e);
+ }
+ }
+
+
+
+}
diff --git a/apps/dav/lib/comments/entitycollection.php b/apps/dav/lib/comments/entitycollection.php
new file mode 100644
index 00000000000..a55a18c00c0
--- /dev/null
+++ b/apps/dav/lib/comments/entitycollection.php
@@ -0,0 +1,199 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Comments;
+
+use OCP\Comments\ICommentsManager;
+use OCP\Files\Folder;
+use OCP\ILogger;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\PropPatch;
+
+/**
+ * Class EntityCollection
+ *
+ * this represents a specific holder of comments, identified by an entity type
+ * (class member $name) and an entity id (class member $id).
+ *
+ * @package OCA\DAV\Comments
+ */
+class EntityCollection extends RootCollection implements \Sabre\DAV\IProperties {
+ const PROPERTY_NAME_READ_MARKER = '{http://owncloud.org/ns}readMarker';
+
+ /** @var Folder */
+ protected $fileRoot;
+
+ /** @var string */
+ protected $id;
+
+ /** @var ILogger */
+ protected $logger;
+
+ /**
+ * @param string $id
+ * @param string $name
+ * @param ICommentsManager $commentsManager
+ * @param Folder $fileRoot
+ * @param IUserManager $userManager
+ * @param IUserSession $userSession
+ * @param ILogger $logger
+ */
+ public function __construct(
+ $id,
+ $name,
+ ICommentsManager $commentsManager,
+ Folder $fileRoot,
+ IUserManager $userManager,
+ IUserSession $userSession,
+ ILogger $logger
+ ) {
+ foreach(['id', 'name'] as $property) {
+ $$property = trim($$property);
+ if(empty($$property) || !is_string($$property)) {
+ throw new \InvalidArgumentException('"' . $property . '" parameter must be non-empty string');
+ }
+ }
+ $this->id = $id;
+ $this->name = $name;
+ $this->commentsManager = $commentsManager;
+ $this->fileRoot = $fileRoot;
+ $this->logger = $logger;
+ $this->userManager = $userManager;
+ $this->userSession = $userSession;
+ }
+
+ /**
+ * returns the ID of this entity
+ *
+ * @return string
+ */
+ public function getId() {
+ return $this->id;
+ }
+
+ /**
+ * Returns a specific child node, referenced by its name
+ *
+ * This method must throw Sabre\DAV\Exception\NotFound if the node does not
+ * exist.
+ *
+ * @param string $name
+ * @return \Sabre\DAV\INode
+ * @throws NotFound
+ */
+ function getChild($name) {
+ try {
+ $comment = $this->commentsManager->get($name);
+ return new CommentNode(
+ $this->commentsManager,
+ $comment,
+ $this->userManager,
+ $this->userSession,
+ $this->logger
+ );
+ } catch (\OCP\Comments\NotFoundException $e) {
+ throw new NotFound();
+ }
+ }
+
+ /**
+ * Returns an array with all the child nodes
+ *
+ * @return \Sabre\DAV\INode[]
+ */
+ function getChildren() {
+ return $this->findChildren();
+ }
+
+ /**
+ * Returns an array of comment nodes. Result can be influenced by offset,
+ * limit and date time parameters.
+ *
+ * @param int $limit
+ * @param int $offset
+ * @param \DateTime|null $datetime
+ * @return CommentNode[]
+ */
+ function findChildren($limit = 0, $offset = 0, \DateTime $datetime = null) {
+ $comments = $this->commentsManager->getForObject($this->name, $this->id, $limit, $offset, $datetime);
+ $result = [];
+ foreach($comments as $comment) {
+ $result[] = new CommentNode(
+ $this->commentsManager,
+ $comment,
+ $this->userManager,
+ $this->userSession,
+ $this->logger
+ );
+ }
+ return $result;
+ }
+
+ /**
+ * Checks if a child-node with the specified name exists
+ *
+ * @param string $name
+ * @return bool
+ */
+ function childExists($name) {
+ try {
+ $this->commentsManager->get($name);
+ return true;
+ } catch (\OCP\Comments\NotFoundException $e) {
+ return false;
+ }
+ }
+
+ /**
+ * Sets the read marker to the specified date for the logged in user
+ *
+ * @param \DateTime $value
+ * @return bool
+ */
+ public function setReadMarker($value) {
+ $dateTime = new \DateTime($value);
+ $user = $this->userSession->getUser();
+ $this->commentsManager->setReadMark($this->name, $this->id, $dateTime, $user);
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function propPatch(PropPatch $propPatch) {
+ $propPatch->handle(self::PROPERTY_NAME_READ_MARKER, [$this, 'setReadMarker']);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function getProperties($properties) {
+ $marker = null;
+ $user = $this->userSession->getUser();
+ if(!is_null($user)) {
+ $marker = $this->commentsManager->getReadMark($this->name, $this->id, $user);
+ }
+ return [self::PROPERTY_NAME_READ_MARKER => $marker];
+ }
+}
+
diff --git a/apps/dav/lib/comments/entitytypecollection.php b/apps/dav/lib/comments/entitytypecollection.php
new file mode 100644
index 00000000000..6bc42484207
--- /dev/null
+++ b/apps/dav/lib/comments/entitytypecollection.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Comments;
+
+use OCP\Comments\ICommentsManager;
+use OCP\Files\Folder;
+use OCP\ILogger;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Sabre\DAV\Exception\MethodNotAllowed;
+use Sabre\DAV\Exception\NotFound;
+
+/**
+ * Class EntityTypeCollection
+ *
+ * This is collection on the type of things a user can leave comments on, for
+ * example: 'files'.
+ *
+ * Its children are instances of EntityCollection (representing a specific
+ * object, for example the file by id).
+ *
+ * @package OCA\DAV\Comments
+ */
+class EntityTypeCollection extends RootCollection {
+ /** @var Folder */
+ protected $fileRoot;
+
+ /** @var ILogger */
+ protected $logger;
+
+ /**
+ * @param string $name
+ * @param ICommentsManager $commentsManager
+ * @param Folder $fileRoot
+ * @param IUserManager $userManager
+ * @param IUserSession $userSession
+ * @param ILogger $logger
+ */
+ public function __construct(
+ $name,
+ ICommentsManager $commentsManager,
+ Folder $fileRoot,
+ IUserManager $userManager,
+ IUserSession $userSession,
+ ILogger $logger
+ ) {
+ $name = trim($name);
+ if(empty($name) || !is_string($name)) {
+ throw new \InvalidArgumentException('"name" parameter must be non-empty string');
+ }
+ $this->name = $name;
+ $this->commentsManager = $commentsManager;
+ $this->fileRoot = $fileRoot;
+ $this->logger = $logger;
+ $this->userManager = $userManager;
+ $this->userSession = $userSession;
+ }
+
+ /**
+ * Returns a specific child node, referenced by its name
+ *
+ * This method must throw Sabre\DAV\Exception\NotFound if the node does not
+ * exist.
+ *
+ * @param string $name
+ * @return \Sabre\DAV\INode
+ * @throws NotFound
+ */
+ function getChild($name) {
+ if(!$this->childExists($name)) {
+ throw new NotFound('Entity does not exist or is not available');
+ }
+ return new EntityCollection(
+ $name,
+ $this->name,
+ $this->commentsManager,
+ $this->fileRoot,
+ $this->userManager,
+ $this->userSession,
+ $this->logger
+ );
+ }
+
+ /**
+ * Returns an array with all the child nodes
+ *
+ * @return \Sabre\DAV\INode[]
+ * @throws MethodNotAllowed
+ */
+ function getChildren() {
+ throw new MethodNotAllowed('No permission to list folder contents');
+ }
+
+ /**
+ * Checks if a child-node with the specified name exists
+ *
+ * @param string $name
+ * @return bool
+ */
+ function childExists($name) {
+ $nodes = $this->fileRoot->getById(intval($name));
+ return !empty($nodes);
+ }
+
+
+}
diff --git a/apps/dav/lib/comments/rootcollection.php b/apps/dav/lib/comments/rootcollection.php
new file mode 100644
index 00000000000..cda666f7162
--- /dev/null
+++ b/apps/dav/lib/comments/rootcollection.php
@@ -0,0 +1,205 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Comments;
+
+use OCP\Comments\ICommentsManager;
+use OCP\Files\IRootFolder;
+use OCP\ILogger;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Sabre\DAV\Exception\NotAuthenticated;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\ICollection;
+
+class RootCollection implements ICollection {
+
+ /** @var EntityTypeCollection[] */
+ private $entityTypeCollections = [];
+
+ /** @var ICommentsManager */
+ protected $commentsManager;
+
+ /** @var string */
+ protected $name = 'comments';
+
+ /** @var ILogger */
+ protected $logger;
+
+ /** @var IUserManager */
+ protected $userManager;
+ /**
+ * @var IUserSession
+ */
+ protected $userSession;
+ /**
+ * @var IRootFolder
+ */
+ protected $rootFolder;
+
+ /**
+ * @param ICommentsManager $commentsManager
+ * @param IUserManager $userManager
+ * @param IUserSession $userSession
+ * @param IRootFolder $rootFolder
+ * @param ILogger $logger
+ */
+ public function __construct(
+ ICommentsManager $commentsManager,
+ IUserManager $userManager,
+ IUserSession $userSession,
+ IRootFolder $rootFolder,
+ ILogger $logger)
+ {
+ $this->commentsManager = $commentsManager;
+ $this->logger = $logger;
+ $this->userManager = $userManager;
+ $this->userSession = $userSession;
+ $this->rootFolder = $rootFolder;
+ }
+
+ /**
+ * initializes the collection. At this point of time, we need the logged in
+ * user. Since it is not the case when the instance is created, we cannot
+ * have this in the constructor.
+ *
+ * @throws NotAuthenticated
+ */
+ protected function initCollections() {
+ if(!empty($this->entityTypeCollections)) {
+ return;
+ }
+ $user = $this->userSession->getUser();
+ if(is_null($user)) {
+ throw new NotAuthenticated();
+ }
+ $userFolder = $this->rootFolder->getUserFolder($user->getUID());
+ $this->entityTypeCollections['files'] = new EntityTypeCollection(
+ 'files',
+ $this->commentsManager,
+ $userFolder,
+ $this->userManager,
+ $this->userSession,
+ $this->logger
+ );
+ }
+
+ /**
+ * Creates a new file in the directory
+ *
+ * @param string $name Name of the file
+ * @param resource|string $data Initial payload
+ * @return null|string
+ * @throws Forbidden
+ */
+ function createFile($name, $data = null) {
+ throw new Forbidden('Cannot create comments by id');
+ }
+
+ /**
+ * Creates a new subdirectory
+ *
+ * @param string $name
+ * @throws Forbidden
+ */
+ function createDirectory($name) {
+ throw new Forbidden('Permission denied to create collections');
+ }
+
+ /**
+ * Returns a specific child node, referenced by its name
+ *
+ * This method must throw Sabre\DAV\Exception\NotFound if the node does not
+ * exist.
+ *
+ * @param string $name
+ * @return \Sabre\DAV\INode
+ * @throws NotFound
+ */
+ function getChild($name) {
+ $this->initCollections();
+ if(isset($this->entityTypeCollections[$name])) {
+ return $this->entityTypeCollections[$name];
+ }
+ throw new NotFound('Entity type "' . $name . '" not found."');
+ }
+
+ /**
+ * Returns an array with all the child nodes
+ *
+ * @return \Sabre\DAV\INode[]
+ */
+ function getChildren() {
+ $this->initCollections();
+ return $this->entityTypeCollections;
+ }
+
+ /**
+ * Checks if a child-node with the specified name exists
+ *
+ * @param string $name
+ * @return bool
+ */
+ function childExists($name) {
+ $this->initCollections();
+ return isset($this->entityTypeCollections[$name]);
+ }
+
+ /**
+ * Deleted the current node
+ *
+ * @throws Forbidden
+ */
+ function delete() {
+ throw new Forbidden('Permission denied to delete this collection');
+ }
+
+ /**
+ * Returns the name of the node.
+ *
+ * This is used to generate the url.
+ *
+ * @return string
+ */
+ function getName() {
+ return $this->name;
+ }
+
+ /**
+ * Renames the node
+ *
+ * @param string $name The new name
+ * @throws Forbidden
+ */
+ function setName($name) {
+ throw new Forbidden('Permission denied to rename this collection');
+ }
+
+ /**
+ * Returns the last modification time, as a unix timestamp
+ *
+ * @return int
+ */
+ function getLastModified() {
+ return null;
+ }
+}
diff --git a/apps/dav/lib/connector/publicauth.php b/apps/dav/lib/connector/publicauth.php
index f37be41402a..3d800e88004 100644
--- a/apps/dav/lib/connector/publicauth.php
+++ b/apps/dav/lib/connector/publicauth.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/appenabledplugin.php b/apps/dav/lib/connector/sabre/appenabledplugin.php
index e70512d0fd1..cb061d6a309 100644
--- a/apps/dav/lib/connector/sabre/appenabledplugin.php
+++ b/apps/dav/lib/connector/sabre/appenabledplugin.php
@@ -2,9 +2,10 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/auth.php b/apps/dav/lib/connector/sabre/auth.php
index 39a7df31b7f..cc679e44dbe 100644
--- a/apps/dav/lib/connector/sabre/auth.php
+++ b/apps/dav/lib/connector/sabre/auth.php
@@ -2,16 +2,16 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
- * @author Christian Seiler <christian@iwakd.de>
* @author Jakob Sack <mail@jakobsack.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Markus Goetz <markus@woboq.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,6 +35,8 @@ use OCP\IUserSession;
use Sabre\DAV\Auth\Backend\AbstractBasic;
use Sabre\DAV\Exception\NotAuthenticated;
use Sabre\DAV\Exception\ServiceUnavailable;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
class Auth extends AbstractBasic {
const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND';
@@ -52,6 +54,7 @@ class Auth extends AbstractBasic {
IUserSession $userSession) {
$this->session = $session;
$this->userSession = $userSession;
+ $this->principalPrefix = 'principals/users/';
}
/**
@@ -65,7 +68,7 @@ class Auth extends AbstractBasic {
* @param string $username
* @return bool
*/
- protected function isDavAuthenticated($username) {
+ public function isDavAuthenticated($username) {
return !is_null($this->session->get(self::DAV_AUTHENTICATED)) &&
$this->session->get(self::DAV_AUTHENTICATED) === $username;
}
@@ -122,22 +125,15 @@ class Auth extends AbstractBasic {
}
/**
- * Override function here. We want to cache authentication cookies
- * in the syncing client to avoid HTTP-401 roundtrips.
- * If the sync client supplies the cookies, then OC_User::isLoggedIn()
- * will return true and we can see this WebDAV request as already authenticated,
- * even if there are no HTTP Basic Auth headers.
- * In other case, just fallback to the parent implementation.
- *
- * @param \Sabre\DAV\Server $server
- * @param string $realm
- * @return bool
- * @throws ServiceUnavailable
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ * @return array
* @throws NotAuthenticated
+ * @throws ServiceUnavailable
*/
- public function authenticate(\Sabre\DAV\Server $server, $realm) {
+ function check(RequestInterface $request, ResponseInterface $response) {
try {
- $result = $this->auth($server, $realm);
+ $result = $this->auth($request, $response);
return $result;
} catch (NotAuthenticated $e) {
throw $e;
@@ -149,21 +145,31 @@ class Auth extends AbstractBasic {
}
/**
- * @param \Sabre\DAV\Server $server
- * @param $realm
- * @return bool
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ * @return array
*/
- private function auth(\Sabre\DAV\Server $server, $realm) {
+ private function auth(RequestInterface $request, ResponseInterface $response) {
if (\OC_User::handleApacheAuth() ||
- ($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED)))
+ //Fix for broken webdav clients
+ ($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED))) ||
+ //Well behaved clients that only send the cookie are allowed
+ ($this->userSession->isLoggedIn() && $this->session->get(self::DAV_AUTHENTICATED) === $this->userSession->getUser()->getUID() && $request->getHeader('Authorization') === null)
) {
$user = $this->userSession->getUser()->getUID();
\OC_Util::setupFS($user);
$this->currentUser = $user;
$this->session->close();
- return true;
+ return [true, $this->principalPrefix . $user];
+ }
+
+ if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) {
+ // do not re-authenticate over ajax, use dummy auth name to prevent browser popup
+ $response->addHeader('WWW-Authenticate','DummyBasic realm="' . $this->realm . '"');
+ $response->setStatus(401);
+ throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
}
- return parent::authenticate($server, $realm);
+ return parent::check($request, $response);
}
}
diff --git a/apps/dav/lib/connector/sabre/blocklegacyclientplugin.php b/apps/dav/lib/connector/sabre/blocklegacyclientplugin.php
index ed61f43a536..70d19cb7f2a 100644
--- a/apps/dav/lib/connector/sabre/blocklegacyclientplugin.php
+++ b/apps/dav/lib/connector/sabre/blocklegacyclientplugin.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/commentpropertiesplugin.php b/apps/dav/lib/connector/sabre/commentpropertiesplugin.php
new file mode 100644
index 00000000000..a8d5f771122
--- /dev/null
+++ b/apps/dav/lib/connector/sabre/commentpropertiesplugin.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Connector\Sabre;
+
+use OCP\Comments\ICommentsManager;
+use OCP\IUserSession;
+use Sabre\DAV\PropFind;
+use Sabre\DAV\ServerPlugin;
+
+class CommentPropertiesPlugin extends ServerPlugin {
+
+ const PROPERTY_NAME_HREF = '{http://owncloud.org/ns}comments-href';
+ const PROPERTY_NAME_COUNT = '{http://owncloud.org/ns}comments-count';
+ const PROPERTY_NAME_UNREAD = '{http://owncloud.org/ns}comments-unread';
+
+ /** @var \Sabre\DAV\Server */
+ protected $server;
+
+ /** @var ICommentsManager */
+ private $commentsManager;
+
+ /** @var IUserSession */
+ private $userSession;
+
+ public function __construct(ICommentsManager $commentsManager, IUserSession $userSession) {
+ $this->commentsManager = $commentsManager;
+ $this->userSession = $userSession;
+ }
+
+ /**
+ * This initializes the plugin.
+ *
+ * This function is called by Sabre\DAV\Server, after
+ * addPlugin is called.
+ *
+ * This method should set up the required event subscriptions.
+ *
+ * @param \Sabre\DAV\Server $server
+ * @return void
+ */
+ function initialize(\Sabre\DAV\Server $server) {
+ $this->server = $server;
+ $this->server->on('propFind', array($this, 'handleGetProperties'));
+ }
+
+ /**
+ * Adds tags and favorites properties to the response,
+ * if requested.
+ *
+ * @param PropFind $propFind
+ * @param \Sabre\DAV\INode $node
+ * @return void
+ */
+ public function handleGetProperties(
+ PropFind $propFind,
+ \Sabre\DAV\INode $node
+ ) {
+ if (!($node instanceof File) && !($node instanceof Directory)) {
+ return;
+ }
+
+ $propFind->handle(self::PROPERTY_NAME_COUNT, function() use ($node) {
+ return $this->commentsManager->getNumberOfCommentsForObject('files', strval($node->getId()));
+ });
+
+ $propFind->handle(self::PROPERTY_NAME_HREF, function() use ($node) {
+ return $this->getCommentsLink($node);
+ });
+
+ $propFind->handle(self::PROPERTY_NAME_UNREAD, function() use ($node) {
+ return $this->getUnreadCount($node);
+ });
+ }
+
+ /**
+ * returns a reference to the comments node
+ *
+ * @param Node $node
+ * @return mixed|string
+ */
+ public function getCommentsLink(Node $node) {
+ $href = $this->server->getBaseUri();
+ $entryPoint = strrpos($href, '/webdav/');
+ if($entryPoint === false) {
+ // in case we end up somewhere else, unexpectedly.
+ return null;
+ }
+ $href = substr_replace($href, '/dav/', $entryPoint);
+ $href .= 'comments/files/' . rawurldecode($node->getId());
+ return $href;
+ }
+
+ /**
+ * returns the number of unread comments for the currently logged in user
+ * on the given file or directory node
+ *
+ * @param Node $node
+ * @return Int|null
+ */
+ public function getUnreadCount(Node $node) {
+ $user = $this->userSession->getUser();
+ if(is_null($user)) {
+ return null;
+ }
+
+ $lastRead = $this->commentsManager->getReadMark('files', strval($node->getId()), $user);
+
+ return $this->commentsManager->getNumberOfCommentsForObject('files', strval($node->getId()), $lastRead);
+ }
+
+}
diff --git a/apps/dav/lib/connector/sabre/copyetagheaderplugin.php b/apps/dav/lib/connector/sabre/copyetagheaderplugin.php
index b33b208adad..49b6a7b2de7 100644
--- a/apps/dav/lib/connector/sabre/copyetagheaderplugin.php
+++ b/apps/dav/lib/connector/sabre/copyetagheaderplugin.php
@@ -1,8 +1,9 @@
<?php
/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/custompropertiesbackend.php b/apps/dav/lib/connector/sabre/custompropertiesbackend.php
index ff35476319f..5946c9910d4 100644
--- a/apps/dav/lib/connector/sabre/custompropertiesbackend.php
+++ b/apps/dav/lib/connector/sabre/custompropertiesbackend.php
@@ -4,7 +4,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/directory.php b/apps/dav/lib/connector/sabre/directory.php
index 8c736ea0108..0119879a171 100644
--- a/apps/dav/lib/connector/sabre/directory.php
+++ b/apps/dav/lib/connector/sabre/directory.php
@@ -10,7 +10,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,8 +28,10 @@
*/
namespace OCA\DAV\Connector\Sabre;
+use OCA\DAV\Connector\Sabre\Exception\Forbidden;
use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
use OCA\DAV\Connector\Sabre\Exception\FileLocked;
+use OCP\Files\ForbiddenException;
use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
use Sabre\DAV\Exception\Locked;
@@ -52,6 +54,23 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
private $quotaInfo;
/**
+ * @var ObjectTree|null
+ */
+ private $tree;
+
+ /**
+ * Sets up the node, expects a full path name
+ *
+ * @param \OC\Files\View $view
+ * @param \OCP\Files\FileInfo $info
+ * @param ObjectTree|null $tree
+ */
+ public function __construct($view, $info, $tree = null) {
+ parent::__construct($view, $info);
+ $this->tree = $tree;
+ }
+
+ /**
* Creates a new file in the directory
*
* Data will either be supplied as a stream resource, or in certain cases
@@ -117,6 +136,8 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
} catch (\OCP\Files\InvalidPathException $ex) {
throw new InvalidPath($ex->getMessage());
+ } catch (ForbiddenException $ex) {
+ throw new Forbidden($ex->getMessage(), $ex->getRetry());
} catch (LockedException $e) {
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
@@ -146,6 +167,8 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
} catch (\OCP\Files\InvalidPathException $ex) {
throw new InvalidPath($ex->getMessage());
+ } catch (ForbiddenException $ex) {
+ throw new Forbidden($ex->getMessage(), $ex->getRetry());
} catch (LockedException $e) {
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
@@ -179,10 +202,13 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
}
if ($info['mimetype'] == 'httpd/unix-directory') {
- $node = new \OCA\DAV\Connector\Sabre\Directory($this->fileView, $info);
+ $node = new \OCA\DAV\Connector\Sabre\Directory($this->fileView, $info, $this->tree);
} else {
$node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info);
}
+ if ($this->tree) {
+ $this->tree->cacheNode($node);
+ }
return $node;
}
@@ -247,6 +273,8 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
// assume it wasn't possible to remove due to permission issue
throw new \Sabre\DAV\Exception\Forbidden();
}
+ } catch (ForbiddenException $ex) {
+ throw new Forbidden($ex->getMessage(), $ex->getRetry());
} catch (LockedException $e) {
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
diff --git a/apps/dav/lib/connector/sabre/dummygetresponseplugin.php b/apps/dav/lib/connector/sabre/dummygetresponseplugin.php
index 7c7a332fedd..b10d5aaab36 100644
--- a/apps/dav/lib/connector/sabre/dummygetresponseplugin.php
+++ b/apps/dav/lib/connector/sabre/dummygetresponseplugin.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/exception/entitytoolarge.php b/apps/dav/lib/connector/sabre/exception/entitytoolarge.php
index f5a7aa99c6d..d16e93bb637 100644
--- a/apps/dav/lib/connector/sabre/exception/entitytoolarge.php
+++ b/apps/dav/lib/connector/sabre/exception/entitytoolarge.php
@@ -4,7 +4,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/exception/filelocked.php b/apps/dav/lib/connector/sabre/exception/filelocked.php
index 1e1585edbda..03ced0e81e2 100644
--- a/apps/dav/lib/connector/sabre/exception/filelocked.php
+++ b/apps/dav/lib/connector/sabre/exception/filelocked.php
@@ -3,9 +3,10 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Owen Winkler <a_github@midnightcircus.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/exception/forbidden.php b/apps/dav/lib/connector/sabre/exception/forbidden.php
new file mode 100644
index 00000000000..f2467e6b298
--- /dev/null
+++ b/apps/dav/lib/connector/sabre/exception/forbidden.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Connector\Sabre\Exception;
+
+class Forbidden extends \Sabre\DAV\Exception\Forbidden {
+
+ const NS_OWNCLOUD = 'http://owncloud.org/ns';
+
+ /**
+ * @var bool
+ */
+ private $retry;
+
+ /**
+ * @param string $message
+ * @param bool $retry
+ * @param \Exception $previous
+ */
+ public function __construct($message, $retry = false, \Exception $previous = null) {
+ parent::__construct($message, 0, $previous);
+ $this->retry = $retry;
+ }
+
+ /**
+ * This method allows the exception to include additional information
+ * into the WebDAV error response
+ *
+ * @param \Sabre\DAV\Server $server
+ * @param \DOMElement $errorNode
+ * @return void
+ */
+ public function serialize(\Sabre\DAV\Server $server,\DOMElement $errorNode) {
+
+ // set ownCloud namespace
+ $errorNode->setAttribute('xmlns:o', self::NS_OWNCLOUD);
+
+ // adding the retry node
+ $error = $errorNode->ownerDocument->createElementNS('o:','o:retry', var_export($this->retry, true));
+ $errorNode->appendChild($error);
+
+ // adding the message node
+ $error = $errorNode->ownerDocument->createElementNS('o:','o:reason', $this->getMessage());
+ $errorNode->appendChild($error);
+ }
+}
diff --git a/apps/dav/lib/connector/sabre/exception/invalidpath.php b/apps/dav/lib/connector/sabre/exception/invalidpath.php
index 608e427a5aa..7951a0a89b7 100644
--- a/apps/dav/lib/connector/sabre/exception/invalidpath.php
+++ b/apps/dav/lib/connector/sabre/exception/invalidpath.php
@@ -2,7 +2,7 @@
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/exception/unsupportedmediatype.php b/apps/dav/lib/connector/sabre/exception/unsupportedmediatype.php
index 96b9b8332de..99e3c222c75 100644
--- a/apps/dav/lib/connector/sabre/exception/unsupportedmediatype.php
+++ b/apps/dav/lib/connector/sabre/exception/unsupportedmediatype.php
@@ -4,7 +4,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/exceptionloggerplugin.php b/apps/dav/lib/connector/sabre/exceptionloggerplugin.php
index 64ec5cfda82..b514a917556 100644
--- a/apps/dav/lib/connector/sabre/exceptionloggerplugin.php
+++ b/apps/dav/lib/connector/sabre/exceptionloggerplugin.php
@@ -5,7 +5,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/fakelockerplugin.php b/apps/dav/lib/connector/sabre/fakelockerplugin.php
index 493d3b0ade4..f585a74444f 100644
--- a/apps/dav/lib/connector/sabre/fakelockerplugin.php
+++ b/apps/dav/lib/connector/sabre/fakelockerplugin.php
@@ -1,8 +1,10 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,9 +24,9 @@
namespace OCA\DAV\Connector\Sabre;
use Sabre\DAV\Locks\LockInfo;
-use Sabre\DAV\Property\LockDiscovery;
-use Sabre\DAV\Property\SupportedLock;
use Sabre\DAV\ServerPlugin;
+use Sabre\DAV\Xml\Property\LockDiscovery;
+use Sabre\DAV\Xml\Property\SupportedLock;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
use Sabre\DAV\PropFind;
@@ -59,7 +61,7 @@ class FakeLockerPlugin extends ServerPlugin {
* Indicate that we support LOCK and UNLOCK
*
* @param string $path
- * @return array
+ * @return string[]
*/
public function getHTTPMethods($path) {
return [
@@ -71,7 +73,7 @@ class FakeLockerPlugin extends ServerPlugin {
/**
* Indicate that we support locking
*
- * @return array
+ * @return integer[]
*/
function getFeatures() {
return [2];
@@ -122,12 +124,6 @@ class FakeLockerPlugin extends ServerPlugin {
*/
public function fakeLockProvider(RequestInterface $request,
ResponseInterface $response) {
- $dom = new \DOMDocument('1.0', 'utf-8');
- $prop = $dom->createElementNS('DAV:', 'd:prop');
- $dom->appendChild($prop);
-
- $lockDiscovery = $dom->createElementNS('DAV:', 'd:lockdiscovery');
- $prop->appendChild($lockDiscovery);
$lockInfo = new LockInfo();
$lockInfo->token = md5($request->getPath());
@@ -135,10 +131,12 @@ class FakeLockerPlugin extends ServerPlugin {
$lockInfo->depth = \Sabre\DAV\Server::DEPTH_INFINITY;
$lockInfo->timeout = 1800;
- $lockObj = new LockDiscovery([$lockInfo]);
- $lockObj->serialize($this->server, $lockDiscovery);
+ $body = $this->server->xml->write('{DAV:}prop', [
+ '{DAV:}lockdiscovery' =>
+ new LockDiscovery([$lockInfo])
+ ]);
- $response->setBody($dom->saveXML());
+ $response->setBody($body);
return false;
}
diff --git a/apps/dav/lib/connector/sabre/file.php b/apps/dav/lib/connector/sabre/file.php
index 961532daf50..be313a91e8c 100644
--- a/apps/dav/lib/connector/sabre/file.php
+++ b/apps/dav/lib/connector/sabre/file.php
@@ -3,17 +3,18 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
* @author Jakob Sack <mail@jakobsack.de>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Owen Winkler <a_github@midnightcircus.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,9 +36,11 @@ namespace OCA\DAV\Connector\Sabre;
use OC\Files\Filesystem;
use OCA\DAV\Connector\Sabre\Exception\EntityTooLarge;
use OCA\DAV\Connector\Sabre\Exception\FileLocked;
+use OCA\DAV\Connector\Sabre\Exception\Forbidden as DAVForbiddenException;
use OCA\DAV\Connector\Sabre\Exception\UnsupportedMediaType;
use OCP\Encryption\Exceptions\GenericEncryptionException;
use OCP\Files\EntityTooLargeException;
+use OCP\Files\ForbiddenException;
use OCP\Files\InvalidContentException;
use OCP\Files\InvalidPathException;
use OCP\Files\LockNotAcquiredException;
@@ -127,9 +130,17 @@ 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('Could not write file contents');
}
- list($count,) = \OC_Helper::streamCopy($data, $target);
+ list($count, $result) = \OC_Helper::streamCopy($data, $target);
fclose($target);
+ if($result === false) {
+ $expected = -1;
+ if (isset($_SERVER['CONTENT_LENGTH'])) {
+ $expected = $_SERVER['CONTENT_LENGTH'];
+ }
+ throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: '. $expected .' )');
+ }
+
// if content length is sent by client:
// double check if the file was fully received
// compare expected and actual size
@@ -175,6 +186,8 @@ class File extends Node implements IFile {
\OCP\Util::writeLog('webdav', 'renaming part file to final file failed', \OCP\Util::ERROR);
throw new Exception('Could not rename part file to final file');
}
+ } catch (ForbiddenException $ex) {
+ throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
} catch (\Exception $e) {
$partStorage->unlink($internalPartPath);
$this->convertToSabreException($e);
@@ -188,7 +201,7 @@ class File extends Node implements IFile {
}
// since we skipped the view we need to scan and emit the hooks ourselves
- $this->fileView->getUpdater()->update($this->path);
+ $storage->getUpdater()->update($internalPath);
if ($view) {
$this->emitPostHooks($exists);
@@ -201,7 +214,13 @@ class File extends Node implements IFile {
header('X-OC-MTime: accepted');
}
}
+
+ if (isset($request->server['HTTP_OC_CHECKSUM'])) {
+ $checksum = trim($request->server['HTTP_OC_CHECKSUM']);
+ $this->fileView->putFileInfo($this->path, ['checksum' => $checksum]);
+ }
$this->refreshInfo();
+
} catch (StorageNotAvailableException $e) {
throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
}
@@ -209,6 +228,9 @@ class File extends Node implements IFile {
return '"' . $this->info->getEtag() . '"';
}
+ /**
+ * @param string $path
+ */
private function emitPreHooks($exists, $path = null) {
if (is_null($path)) {
$path = $this->path;
@@ -234,6 +256,9 @@ class File extends Node implements IFile {
return $run;
}
+ /**
+ * @param string $path
+ */
private function emitPostHooks($exists, $path = null) {
if (is_null($path)) {
$path = $this->path;
@@ -256,7 +281,7 @@ class File extends Node implements IFile {
/**
* Returns the data
*
- * @return string|resource
+ * @return resource
* @throws Forbidden
* @throws ServiceUnavailable
*/
@@ -273,6 +298,8 @@ class File extends Node implements IFile {
throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
} catch (StorageNotAvailableException $e) {
throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
+ } catch (ForbiddenException $ex) {
+ throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
} catch (LockedException $e) {
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
@@ -296,6 +323,8 @@ class File extends Node implements IFile {
}
} catch (StorageNotAvailableException $e) {
throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
+ } catch (ForbiddenException $ex) {
+ throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
} catch (LockedException $e) {
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
@@ -306,7 +335,7 @@ class File extends Node implements IFile {
*
* If null is returned, we'll assume application/octet-stream
*
- * @return mixed
+ * @return string
*/
public function getContentType() {
$mimeType = $this->info->getMimetype();
@@ -315,7 +344,7 @@ class File extends Node implements IFile {
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
return $mimeType;
}
- return \OC_Helper::getSecureMimeType($mimeType);
+ return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
}
/**
@@ -424,7 +453,7 @@ class File extends Node implements IFile {
$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
// since we skipped the view we need to scan and emit the hooks ourselves
- $this->fileView->getUpdater()->update($targetPath);
+ $targetStorage->getUpdater()->update($targetInternalPath);
$this->emitPostHooks($exists, $targetPath);
@@ -474,6 +503,10 @@ class File extends Node implements IFile {
// a more general case - due to whatever reason the content could not be written
throw new Forbidden($e->getMessage(), 0, $e);
}
+ if ($e instanceof ForbiddenException) {
+ // the path for the file was forbidden
+ throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e);
+ }
if ($e instanceof EntityTooLargeException) {
// the file is too big to be stored
throw new EntityTooLarge($e->getMessage(), 0, $e);
@@ -501,4 +534,13 @@ class File extends Node implements IFile {
throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
}
+
+ /**
+ * Get the checksum for this file
+ *
+ * @return string
+ */
+ public function getChecksum() {
+ return $this->info->getChecksum();
+ }
}
diff --git a/apps/dav/lib/connector/sabre/filesplugin.php b/apps/dav/lib/connector/sabre/filesplugin.php
index 00d5d2cd725..82d00014905 100644
--- a/apps/dav/lib/connector/sabre/filesplugin.php
+++ b/apps/dav/lib/connector/sabre/filesplugin.php
@@ -3,11 +3,12 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,12 +32,14 @@ use \Sabre\DAV\PropFind;
use \Sabre\DAV\PropPatch;
use \Sabre\HTTP\RequestInterface;
use \Sabre\HTTP\ResponseInterface;
+use OCP\Files\StorageNotAvailableException;
class FilesPlugin extends \Sabre\DAV\ServerPlugin {
// namespace
const NS_OWNCLOUD = 'http://owncloud.org/ns';
const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
+ const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid';
const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
@@ -44,6 +47,7 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id';
const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name';
+ const CHECKSUM_PROPERTYNAME = '{http://owncloud.org/ns}checksum';
/**
* Reference to main server object
@@ -96,13 +100,15 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
*/
public function initialize(\Sabre\DAV\Server $server) {
- $server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc';
+ $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
$server->protectedProperties[] = self::FILEID_PROPERTYNAME;
+ $server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME;
$server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
$server->protectedProperties[] = self::SIZE_PROPERTYNAME;
$server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
$server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME;
$server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME;
+ $server->protectedProperties[] = self::CHECKSUM_PROPERTYNAME;
// normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
$allowedProperties = ['{DAV:}getetag'];
@@ -114,6 +120,7 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
$this->server->on('afterBind', array($this, 'sendFileIdHeader'));
$this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
$this->server->on('afterMethod:GET', [$this,'httpGet']);
+ $this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
$this->server->on('afterResponse', function($request, ResponseInterface $response) {
$body = $response->getBody();
if (is_resource($body)) {
@@ -147,8 +154,34 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
}
/**
- * Plugin that adds a 'Content-Disposition: attachment' header to all files
- * delivered by SabreDAV.
+ * This sets a cookie to be able to recognize the start of the download
+ * the content must not be longer than 32 characters and must only contain
+ * alphanumeric characters
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ */
+ function handleDownloadToken(RequestInterface $request, ResponseInterface $response) {
+ $queryParams = $request->getQueryParameters();
+
+ /**
+ * this sets a cookie to be able to recognize the start of the download
+ * the content must not be longer than 32 characters and must only contain
+ * alphanumeric characters
+ */
+ if (isset($queryParams['downloadStartSecret'])) {
+ $token = $queryParams['downloadStartSecret'];
+ if (!isset($token[32])
+ && preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) {
+ // FIXME: use $response->setHeader() instead
+ setcookie('ocDownloadStarted', $token, time() + 20, '/');
+ }
+ }
+ }
+
+ /**
+ * Add headers to file download
+ *
* @param RequestInterface $request
* @param ResponseInterface $response
*/
@@ -157,7 +190,15 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
$node = $this->tree->getNodeForPath($request->getPath());
if (!($node instanceof IFile)) return;
+ // adds a 'Content-Disposition: attachment' header
$response->addHeader('Content-Disposition', 'attachment');
+
+ //Add OC-Checksum header
+ /** @var $node File */
+ $checksum = $node->getChecksum();
+ if ($checksum !== null) {
+ $response->addHeader('OC-Checksum', $checksum);
+ }
}
/**
@@ -175,6 +216,10 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
return $node->getFileId();
});
+ $propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) {
+ return $node->getInternalFileId();
+ });
+
$propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
$perms = $node->getDavPermissions();
if ($this->isPublic) {
@@ -192,12 +237,26 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
$propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
/** @var $node \OCA\DAV\Connector\Sabre\File */
- $directDownloadUrl = $node->getDirectDownload();
- if (isset($directDownloadUrl['url'])) {
- return $directDownloadUrl['url'];
+ try {
+ $directDownloadUrl = $node->getDirectDownload();
+ if (isset($directDownloadUrl['url'])) {
+ return $directDownloadUrl['url'];
+ }
+ } catch (StorageNotAvailableException $e) {
+ return false;
}
return false;
});
+
+ $propFind->handle(self::CHECKSUM_PROPERTYNAME, function() use ($node) {
+ $checksum = $node->getChecksum();
+
+ if ($checksum === null) {
+ return '';
+ }
+ return $checksum;
+ });
+
}
if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) {
diff --git a/apps/dav/lib/connector/sabre/listenerplugin.php b/apps/dav/lib/connector/sabre/listenerplugin.php
deleted file mode 100644
index d537d0577c6..00000000000
--- a/apps/dav/lib/connector/sabre/listenerplugin.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\DAV\Connector\Sabre;
-
-use OCP\AppFramework\Http;
-use OCP\SabrePluginEvent;
-use OCP\SabrePluginException;
-use Sabre\DAV\ServerPlugin;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-
-class ListenerPlugin extends ServerPlugin {
- /** @var EventDispatcherInterface */
- protected $dispatcher;
-
- /**
- * @param EventDispatcherInterface $dispatcher
- */
- public function __construct(EventDispatcherInterface $dispatcher) {
- $this->dispatcher = $dispatcher;
- }
-
- /**
- * This initialize the plugin
- *
- * @param \Sabre\DAV\Server $server
- */
- public function initialize(\Sabre\DAV\Server $server) {
- $server->on('beforeMethod', array($this, 'emitListener'), 15);
- }
-
- /**
- * This method is called before any HTTP method and returns http status code 503
- * in case the system is in maintenance mode.
- *
- * @return bool
- * @throws \Exception
- */
- public function emitListener() {
- $event = new SabrePluginEvent();
-
- $this->dispatcher->dispatch('OCA\DAV\Connector\Sabre::beforeMethod', $event);
-
- if ($event->getStatusCode() !== Http::STATUS_OK) {
- throw new SabrePluginException($event->getMessage(), $event->getStatusCode());
- }
-
- return true;
- }
-}
diff --git a/apps/dav/lib/connector/sabre/lockplugin.php b/apps/dav/lib/connector/sabre/lockplugin.php
index 5840e59854c..ff4e1dc01bb 100644
--- a/apps/dav/lib/connector/sabre/lockplugin.php
+++ b/apps/dav/lib/connector/sabre/lockplugin.php
@@ -1,8 +1,10 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,7 +29,6 @@ use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\ServerPlugin;
-use Sabre\DAV\Tree;
use Sabre\HTTP\RequestInterface;
class LockPlugin extends ServerPlugin {
@@ -39,18 +40,6 @@ class LockPlugin extends ServerPlugin {
private $server;
/**
- * @var \Sabre\DAV\Tree
- */
- private $tree;
-
- /**
- * @param \Sabre\DAV\Tree $tree tree
- */
- public function __construct(Tree $tree) {
- $this->tree = $tree;
- }
-
- /**
* {@inheritdoc}
*/
public function initialize(\Sabre\DAV\Server $server) {
@@ -66,7 +55,7 @@ class LockPlugin extends ServerPlugin {
return;
}
try {
- $node = $this->tree->getNodeForPath($request->getPath());
+ $node = $this->server->tree->getNodeForPath($request->getPath());
} catch (NotFound $e) {
return;
}
@@ -84,7 +73,7 @@ class LockPlugin extends ServerPlugin {
return;
}
try {
- $node = $this->tree->getNodeForPath($request->getPath());
+ $node = $this->server->tree->getNodeForPath($request->getPath());
} catch (NotFound $e) {
return;
}
diff --git a/apps/dav/lib/connector/sabre/maintenanceplugin.php b/apps/dav/lib/connector/sabre/maintenanceplugin.php
index b9b261fbe05..6e9a5930b78 100644
--- a/apps/dav/lib/connector/sabre/maintenanceplugin.php
+++ b/apps/dav/lib/connector/sabre/maintenanceplugin.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/node.php b/apps/dav/lib/connector/sabre/node.php
index ae7dd51fc94..64e9ec9d2b7 100644
--- a/apps/dav/lib/connector/sabre/node.php
+++ b/apps/dav/lib/connector/sabre/node.php
@@ -8,10 +8,11 @@
* @author Markus Goetz <markus@woboq.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -178,7 +179,7 @@ abstract class Node implements \Sabre\DAV\INode {
/**
* Returns the size of the node, in bytes
*
- * @return int|float
+ * @return integer
*/
public function getSize() {
return $this->info->getSize();
@@ -207,7 +208,14 @@ abstract class Node implements \Sabre\DAV\INode {
}
/**
- * @return string|null
+ * @return integer
+ */
+ public function getInternalFileId() {
+ return $this->info->getId();
+ }
+
+ /**
+ * @return string
*/
public function getDavPermissions() {
$p = '';
diff --git a/apps/dav/lib/connector/sabre/objecttree.php b/apps/dav/lib/connector/sabre/objecttree.php
index 80c0ef74610..a1796136c4e 100644
--- a/apps/dav/lib/connector/sabre/objecttree.php
+++ b/apps/dav/lib/connector/sabre/objecttree.php
@@ -1,12 +1,13 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,10 +26,12 @@
namespace OCA\DAV\Connector\Sabre;
+use OCA\DAV\Connector\Sabre\Exception\Forbidden;
use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
use OCA\DAV\Connector\Sabre\Exception\FileLocked;
use OC\Files\FileInfo;
use OC\Files\Mount\MoveableMount;
+use OCP\Files\ForbiddenException;
use OCP\Files\StorageInvalidException;
use OCP\Files\StorageNotAvailableException;
use OCP\Lock\LockedException;
@@ -91,6 +94,10 @@ class ObjectTree extends \Sabre\DAV\Tree {
return $path;
}
+ public function cacheNode(Node $node) {
+ $this->cache[trim($node->getPath(), '/')] = $node;
+ }
+
/**
* Returns the INode object for the requested path
*
@@ -105,6 +112,11 @@ class ObjectTree extends \Sabre\DAV\Tree {
}
$path = trim($path, '/');
+
+ if (isset($this->cache[$path])) {
+ return $this->cache[$path];
+ }
+
if ($path) {
try {
$this->fileView->verifyPath($path, basename($path));
@@ -113,10 +125,6 @@ class ObjectTree extends \Sabre\DAV\Tree {
}
}
- if (isset($this->cache[$path])) {
- return $this->cache[$path];
- }
-
// Is it the root node?
if (!strlen($path)) {
return $this->rootNode;
@@ -132,9 +140,8 @@ class ObjectTree extends \Sabre\DAV\Tree {
/**
* @var \OC\Files\Storage\Storage $storage
*/
- $scanner = $storage->getScanner($internalPath);
// get data directly
- $data = $scanner->getData($internalPath);
+ $data = $storage->getMetaData($internalPath);
$info = new FileInfo($absPath, $storage, $internalPath, $data, $mount);
} else {
$info = null;
@@ -160,7 +167,7 @@ class ObjectTree extends \Sabre\DAV\Tree {
}
if ($info->getType() === 'dir') {
- $node = new \OCA\DAV\Connector\Sabre\Directory($this->fileView, $info);
+ $node = new \OCA\DAV\Connector\Sabre\Directory($this->fileView, $info, $this);
} else {
$node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info);
}
@@ -188,7 +195,7 @@ class ObjectTree extends \Sabre\DAV\Tree {
$targetNodeExists = $this->nodeExists($destinationPath);
$sourceNode = $this->getNodeForPath($sourcePath);
if ($sourceNode instanceof \Sabre\DAV\ICollection && $targetNodeExists) {
- throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode . ', target exists');
+ throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode->getName() . ', target exists');
}
list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($sourcePath);
list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destinationPath);
@@ -235,6 +242,8 @@ class ObjectTree extends \Sabre\DAV\Tree {
}
} catch (StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
+ } catch (ForbiddenException $ex) {
+ throw new Forbidden($ex->getMessage(), $ex->getRetry());
} catch (LockedException $e) {
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
@@ -274,6 +283,8 @@ class ObjectTree extends \Sabre\DAV\Tree {
$this->fileView->copy($source, $destination);
} catch (StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
+ } catch (ForbiddenException $ex) {
+ throw new Forbidden($ex->getMessage(), $ex->getRetry());
} catch (LockedException $e) {
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
diff --git a/apps/dav/lib/connector/sabre/principal.php b/apps/dav/lib/connector/sabre/principal.php
index 35215e1f63c..5f02d1271df 100644
--- a/apps/dav/lib/connector/sabre/principal.php
+++ b/apps/dav/lib/connector/sabre/principal.php
@@ -1,17 +1,16 @@
<?php
/**
* @author Bart Visscher <bartv@thisnet.nl>
- * @author Felix Moeller <mail@felixmoeller.de>
* @author Jakob Sack <mail@jakobsack.de>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Sebastian Döll <sebastian.doell@libasys.de>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,24 +29,29 @@
namespace OCA\DAV\Connector\Sabre;
+use OCP\IGroup;
+use OCP\IGroupManager;
+use OCP\IUser;
use OCP\IUserManager;
-use OCP\IConfig;
+use Sabre\DAV\Exception;
use \Sabre\DAV\PropPatch;
+use Sabre\DAVACL\PrincipalBackend\BackendInterface;
+use Sabre\HTTP\URLUtil;
+
+class Principal implements BackendInterface {
-class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
- /** @var IConfig */
- private $config;
/** @var IUserManager */
private $userManager;
+ /** @var IGroupManager */
+ private $groupManager;
+
/**
- * @param IConfig $config
* @param IUserManager $userManager
*/
- public function __construct(IConfig $config,
- IUserManager $userManager) {
- $this->config = $config;
+ public function __construct(IUserManager $userManager, IGroupManager $groupManager) {
$this->userManager = $userManager;
+ $this->groupManager = $groupManager;
}
/**
@@ -66,20 +70,9 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
public function getPrincipalsByPrefix($prefixPath) {
$principals = [];
- if ($prefixPath === 'principals') {
+ if ($prefixPath === 'principals/users') {
foreach($this->userManager->search('') as $user) {
-
- $principal = [
- 'uri' => 'principals/' . $user->getUID(),
- '{DAV:}displayname' => $user->getUID(),
- ];
-
- $email = $this->config->getUserValue($user->getUID(), 'settings', 'email');
- if(!empty($email)) {
- $principal['{http://sabredav.org/ns}email-address'] = $email;
- }
-
- $principals[] = $principal;
+ $principals[] = $this->userToPrincipal($user);
}
}
@@ -95,21 +88,18 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
* @return array
*/
public function getPrincipalByPath($path) {
- list($prefix, $name) = explode('/', $path);
+ $elements = explode('/', $path);
+ if ($elements[0] !== 'principals') {
+ return null;
+ }
+ if ($elements[1] !== 'users') {
+ return null;
+ }
+ $name = $elements[2];
$user = $this->userManager->get($name);
- if ($prefix === 'principals' && !is_null($user)) {
- $principal = [
- 'uri' => 'principals/' . $user->getUID(),
- '{DAV:}displayname' => $user->getUID(),
- ];
-
- $email = $this->config->getUserValue($user->getUID(), 'settings', 'email');
- if($email) {
- $principal['{http://sabredav.org/ns}email-address'] = $email;
- }
-
- return $principal;
+ if (!is_null($user)) {
+ return $this->userToPrincipal($user);
}
return null;
@@ -120,13 +110,13 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
*
* @param string $principal
* @return string[]
- * @throws \Sabre\DAV\Exception
+ * @throws Exception
*/
public function getGroupMemberSet($principal) {
// TODO: for now the group principal has only one member, the user itself
$principal = $this->getPrincipalByPath($principal);
if (!$principal) {
- throw new \Sabre\DAV\Exception('Principal not found');
+ throw new Exception('Principal not found');
}
return [$principal['uri']];
@@ -137,29 +127,28 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
*
* @param string $principal
* @return array
- * @throws \Sabre\DAV\Exception
+ * @throws Exception
*/
public function getGroupMembership($principal) {
- list($prefix, $name) = \Sabre\HTTP\URLUtil::splitPath($principal);
+ list($prefix, $name) = URLUtil::splitPath($principal);
- $group_membership = array();
- if ($prefix === 'principals') {
- $principal = $this->getPrincipalByPath($principal);
- if (!$principal) {
- throw new \Sabre\DAV\Exception('Principal not found');
+ if ($prefix === 'principals/users') {
+ $user = $this->userManager->get($name);
+ if (!$user) {
+ throw new Exception('Principal not found');
}
- // TODO: for now the user principal has only its own groups
- return array(
- 'principals/'.$name.'/calendar-proxy-read',
- 'principals/'.$name.'/calendar-proxy-write',
- // The addressbook groups are not supported in Sabre,
- // see http://groups.google.com/group/sabredav-discuss/browse_thread/thread/ef2fa9759d55f8c#msg_5720afc11602e753
- //'principals/'.$name.'/addressbook-proxy-read',
- //'principals/'.$name.'/addressbook-proxy-write',
- );
+ $groups = $this->groupManager->getUserGroups($user);
+ $groups = array_map(function($group) {
+ /** @var IGroup $group */
+ return 'principals/groups/' . $group->getGID();
+ }, $groups);
+
+ $groups[]= 'principals/users/'.$name.'/calendar-proxy-read';
+ $groups[]= 'principals/users/'.$name.'/calendar-proxy-write';
+ return $groups;
}
- return $group_membership;
+ return [];
}
/**
@@ -168,11 +157,11 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
* The principals should be passed as a list of uri's.
*
* @param string $principal
- * @param array $members
- * @throws \Sabre\DAV\Exception
+ * @param string[] $members
+ * @throws Exception
*/
public function setGroupMemberSet($principal, array $members) {
- throw new \Sabre\DAV\Exception('Setting members of the group is not supported yet');
+ throw new Exception('Setting members of the group is not supported yet');
}
/**
@@ -202,4 +191,25 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
function findByUri($uri, $principalPrefix) {
return '';
}
+
+ /**
+ * @param IUser $user
+ * @return array
+ */
+ protected function userToPrincipal($user) {
+ $userId = $user->getUID();
+ $displayName = $user->getDisplayName();
+ $principal = [
+ 'uri' => "principals/users/$userId",
+ '{DAV:}displayname' => is_null($displayName) ? $userId : $displayName,
+ ];
+
+ $email = $user->getEMailAddress();
+ if (!empty($email)) {
+ $principal['{http://sabredav.org/ns}email-address'] = $email;
+ return $principal;
+ }
+ return $principal;
+ }
+
}
diff --git a/apps/dav/lib/connector/sabre/quotaplugin.php b/apps/dav/lib/connector/sabre/quotaplugin.php
index 8340d489dc0..a02827da499 100644
--- a/apps/dav/lib/connector/sabre/quotaplugin.php
+++ b/apps/dav/lib/connector/sabre/quotaplugin.php
@@ -3,13 +3,13 @@
* @author Felix Moeller <mail@felixmoeller.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author scambra <sergio@entrecables.com>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/server.php b/apps/dav/lib/connector/sabre/server.php
index eafe1b537f8..421fc64422d 100644
--- a/apps/dav/lib/connector/sabre/server.php
+++ b/apps/dav/lib/connector/sabre/server.php
@@ -5,7 +5,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/lib/connector/sabre/serverfactory.php b/apps/dav/lib/connector/sabre/serverfactory.php
index a33acc9f00b..fa4fda46870 100644
--- a/apps/dav/lib/connector/sabre/serverfactory.php
+++ b/apps/dav/lib/connector/sabre/serverfactory.php
@@ -1,9 +1,11 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,8 +32,6 @@ use OCP\IRequest;
use OCP\ITagManager;
use OCP\IUserSession;
use Sabre\DAV\Auth\Backend\BackendInterface;
-use Sabre\DAV\Locks\Plugin;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class ServerFactory {
/** @var IConfig */
@@ -46,8 +46,6 @@ class ServerFactory {
private $mountManager;
/** @var ITagManager */
private $tagManager;
- /** @var EventDispatcherInterface */
- private $dispatcher;
/** @var IRequest */
private $request;
@@ -58,7 +56,6 @@ class ServerFactory {
* @param IUserSession $userSession
* @param IMountManager $mountManager
* @param ITagManager $tagManager
- * @param EventDispatcherInterface $dispatcher
* @param IRequest $request
*/
public function __construct(
@@ -68,7 +65,6 @@ class ServerFactory {
IUserSession $userSession,
IMountManager $mountManager,
ITagManager $tagManager,
- EventDispatcherInterface $dispatcher,
IRequest $request
) {
$this->config = $config;
@@ -77,7 +73,6 @@ class ServerFactory {
$this->userSession = $userSession;
$this->mountManager = $mountManager;
$this->tagManager = $tagManager;
- $this->dispatcher = $dispatcher;
$this->request = $request;
}
@@ -107,11 +102,13 @@ class ServerFactory {
// FIXME: The following line is a workaround for legacy components relying on being able to send a GET to /
$server->addPlugin(new \OCA\DAV\Connector\Sabre\DummyGetResponsePlugin());
$server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $this->logger));
- $server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin($objectTree));
- $server->addPlugin(new \OCA\DAV\Connector\Sabre\ListenerPlugin($this->dispatcher));
- // Finder on OS X requires Class 2 WebDAV support (locking), since we do
- // not provide locking we emulate it using a fake locking plugin.
- if($this->request->isUserAgent(['/WebDAVFS/'])) {
+ $server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin());
+ // Some WebDAV clients do require Class 2 WebDAV support (locking), since
+ // we do not provide locking we emulate it using a fake locking plugin.
+ if($this->request->isUserAgent([
+ '/WebDAVFS/',
+ '/Microsoft Office OneNote 2013/',
+ ])) {
$server->addPlugin(new \OCA\DAV\Connector\Sabre\FakeLockerPlugin());
}
@@ -126,7 +123,7 @@ class ServerFactory {
// Create ownCloud Dir
if ($rootInfo->getType() === 'dir') {
- $root = new \OCA\DAV\Connector\Sabre\Directory($view, $rootInfo);
+ $root = new \OCA\DAV\Connector\Sabre\Directory($view, $rootInfo, $objectTree);
} else {
$root = new \OCA\DAV\Connector\Sabre\File($view, $rootInfo);
}
@@ -137,6 +134,7 @@ class ServerFactory {
if($this->userSession->isLoggedIn()) {
$server->addPlugin(new \OCA\DAV\Connector\Sabre\TagsPlugin($objectTree, $this->tagManager));
+ $server->addPlugin(new \OCA\DAV\Connector\Sabre\CommentPropertiesPlugin(\OC::$server->getCommentsManager(), $this->userSession));
// custom properties plugin must be the last one
$server->addPlugin(
new \Sabre\DAV\PropertyStorage\Plugin(
diff --git a/apps/dav/lib/connector/sabre/taglist.php b/apps/dav/lib/connector/sabre/taglist.php
index 177cc23e805..5c1cd8b4f1d 100644
--- a/apps/dav/lib/connector/sabre/taglist.php
+++ b/apps/dav/lib/connector/sabre/taglist.php
@@ -1,9 +1,10 @@
<?php
/**
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,82 +23,98 @@
namespace OCA\DAV\Connector\Sabre;
-use Sabre\DAV;
+use Sabre\Xml\Element;
+use Sabre\Xml\Reader;
+use Sabre\Xml\Writer;
/**
* TagList property
*
* This property contains multiple "tag" elements, each containing a tag name.
*/
-class TagList extends DAV\Property {
+class TagList implements Element {
const NS_OWNCLOUD = 'http://owncloud.org/ns';
- /**
- * tags
- *
- * @var array
- */
- private $tags;
-
- /**
- * @param array $tags
- */
- public function __construct(array $tags) {
- $this->tags = $tags;
- }
-
- /**
- * Returns the tags
- *
- * @return array
- */
- public function getTags() {
-
- return $this->tags;
-
- }
-
- /**
- * Serializes this property.
- *
- * @param DAV\Server $server
- * @param \DOMElement $dom
- * @return void
- */
- public function serialize(DAV\Server $server,\DOMElement $dom) {
-
- $prefix = $server->xmlNamespaces[self::NS_OWNCLOUD];
-
- foreach($this->tags as $tag) {
-
- $elem = $dom->ownerDocument->createElement($prefix . ':tag');
- $elem->appendChild($dom->ownerDocument->createTextNode($tag));
-
- $dom->appendChild($elem);
- }
-
- }
-
- /**
- * Unserializes this property from a DOM Element
- *
- * This method returns an instance of this class.
- * It will only decode tag values.
- *
- * @param \DOMElement $dom
- * @param array $propertyMap
- * @return \OCA\DAV\Connector\Sabre\TagList
- */
- static function unserialize(\DOMElement $dom, array $propertyMap) {
-
- $tags = array();
- foreach($dom->childNodes as $child) {
- if (DAV\XMLUtil::toClarkNotation($child)==='{' . self::NS_OWNCLOUD . '}tag') {
- $tags[] = $child->textContent;
- }
- }
- return new self($tags);
-
- }
-
+ /**
+ * tags
+ *
+ * @var array
+ */
+ private $tags;
+
+ /**
+ * @param array $tags
+ */
+ public function __construct(array $tags) {
+ $this->tags = $tags;
+ }
+
+ /**
+ * Returns the tags
+ *
+ * @return array
+ */
+ public function getTags() {
+
+ return $this->tags;
+
+ }
+
+ /**
+ * The deserialize method is called during xml parsing.
+ *
+ * This method is called statictly, this is because in theory this method
+ * may be used as a type of constructor, or factory method.
+ *
+ * Often you want to return an instance of the current class, but you are
+ * free to return other data as well.
+ *
+ * You are responsible for advancing the reader to the next element. Not
+ * doing anything will result in a never-ending loop.
+ *
+ * If you just want to skip parsing for this element altogether, you can
+ * just call $reader->next();
+ *
+ * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
+ * the next element.
+ *
+ * @param Reader $reader
+ * @return mixed
+ */
+ static function xmlDeserialize(Reader $reader) {
+ $tags = [];
+
+ foreach ($reader->parseInnerTree() as $elem) {
+ if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}tag') {
+ $tags[] = $elem['value'];
+ }
+ }
+ return new self($tags);
+ }
+
+ /**
+ * The xmlSerialize metod is called during xml writing.
+ *
+ * Use the $writer argument to write its own xml serialization.
+ *
+ * An important note: do _not_ create a parent element. Any element
+ * implementing XmlSerializble should only ever write what's considered
+ * its 'inner xml'.
+ *
+ * The parent of the current element is responsible for writing a
+ * containing element.
+ *
+ * This allows serializers to be re-used for different element names.
+ *
+ * If you are opening new elements, you must also close them again.
+ *
+ * @param Writer $writer
+ * @return void
+ */
+ function xmlSerialize(Writer $writer) {
+
+ foreach ($this->tags as $tag) {
+ $writer->writeElement('{' . self::NS_OWNCLOUD . '}tag', $tag);
+ }
+ }
}
diff --git a/apps/dav/lib/connector/sabre/tagsplugin.php b/apps/dav/lib/connector/sabre/tagsplugin.php
index 2f5937da25a..dfc1a2dd95d 100644
--- a/apps/dav/lib/connector/sabre/tagsplugin.php
+++ b/apps/dav/lib/connector/sabre/tagsplugin.php
@@ -1,8 +1,9 @@
<?php
/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -107,8 +108,8 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin
*/
public function initialize(\Sabre\DAV\Server $server) {
- $server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc';
- $server->propertyMap[self::TAGS_PROPERTYNAME] = 'OCA\\DAV\\Connector\\Sabre\\TagList';
+ $server->xml->namespacesMap[self::NS_OWNCLOUD] = 'oc';
+ $server->xml->elementMap[self::TAGS_PROPERTYNAME] = 'OCA\\DAV\\Connector\\Sabre\\TagList';
$this->server = $server;
$this->server->on('propFind', array($this, 'handleGetProperties'));
diff --git a/apps/dav/lib/dav/groupprincipalbackend.php b/apps/dav/lib/dav/groupprincipalbackend.php
new file mode 100644
index 00000000000..34c00b7927e
--- /dev/null
+++ b/apps/dav/lib/dav/groupprincipalbackend.php
@@ -0,0 +1,171 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\DAV;
+
+use OCP\IGroup;
+use OCP\IGroupManager;
+use Sabre\DAV\Exception;
+use \Sabre\DAV\PropPatch;
+use Sabre\DAVACL\PrincipalBackend\BackendInterface;
+
+class GroupPrincipalBackend implements BackendInterface {
+
+ const PRINCIPAL_PREFIX = 'principals/groups';
+
+ /** @var IGroupManager */
+ private $groupManager;
+
+ /**
+ * @param IGroupManager $IGroupManager
+ */
+ public function __construct(IGroupManager $IGroupManager) {
+ $this->groupManager = $IGroupManager;
+ }
+
+ /**
+ * Returns a list of principals based on a prefix.
+ *
+ * This prefix will often contain something like 'principals'. You are only
+ * expected to return principals that are in this base path.
+ *
+ * You are expected to return at least a 'uri' for every user, you can
+ * return any additional properties if you wish so. Common properties are:
+ * {DAV:}displayname
+ *
+ * @param string $prefixPath
+ * @return string[]
+ */
+ public function getPrincipalsByPrefix($prefixPath) {
+ $principals = [];
+
+ if ($prefixPath === self::PRINCIPAL_PREFIX) {
+ foreach($this->groupManager->search('') as $user) {
+ $principals[] = $this->groupToPrincipal($user);
+ }
+ }
+
+ return $principals;
+ }
+
+ /**
+ * Returns a specific principal, specified by it's path.
+ * The returned structure should be the exact same as from
+ * getPrincipalsByPrefix.
+ *
+ * @param string $path
+ * @return array
+ */
+ public function getPrincipalByPath($path) {
+ $elements = explode('/', $path);
+ if ($elements[0] !== 'principals') {
+ return null;
+ }
+ if ($elements[1] !== 'groups') {
+ return null;
+ }
+ $name = $elements[2];
+ $user = $this->groupManager->get($name);
+
+ if (!is_null($user)) {
+ return $this->groupToPrincipal($user);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the list of members for a group-principal
+ *
+ * @param string $principal
+ * @return string[]
+ * @throws Exception
+ */
+ public function getGroupMemberSet($principal) {
+ // TODO: implement if we want that
+ return [];
+ }
+
+ /**
+ * Returns the list of groups a principal is a member of
+ *
+ * @param string $principal
+ * @return array
+ * @throws Exception
+ */
+ public function getGroupMembership($principal) {
+ return [];
+ }
+
+ /**
+ * Updates the list of group members for a group principal.
+ *
+ * The principals should be passed as a list of uri's.
+ *
+ * @param string $principal
+ * @param string[] $members
+ * @throws Exception
+ */
+ public function setGroupMemberSet($principal, array $members) {
+ throw new Exception('Setting members of the group is not supported yet');
+ }
+
+ /**
+ * @param string $path
+ * @param PropPatch $propPatch
+ * @return int
+ */
+ function updatePrincipal($path, PropPatch $propPatch) {
+ return 0;
+ }
+
+ /**
+ * @param string $prefixPath
+ * @param array $searchProperties
+ * @param string $test
+ * @return array
+ */
+ function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
+ return [];
+ }
+
+ /**
+ * @param string $uri
+ * @param string $principalPrefix
+ * @return string
+ */
+ function findByUri($uri, $principalPrefix) {
+ return '';
+ }
+
+ /**
+ * @param IGroup $group
+ * @return array
+ */
+ protected function groupToPrincipal($group) {
+ $groupId = $group->getGID();
+ $principal = [
+ 'uri' => "principals/groups/$groupId",
+ '{DAV:}displayname' => $groupId,
+ ];
+
+ return $principal;
+ }
+}
diff --git a/apps/dav/lib/dav/sharing/backend.php b/apps/dav/lib/dav/sharing/backend.php
new file mode 100644
index 00000000000..0b28891fbc4
--- /dev/null
+++ b/apps/dav/lib/dav/sharing/backend.php
@@ -0,0 +1,194 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\DAV\Sharing;
+
+use OCP\IDBConnection;
+
+class Backend {
+
+ /** @var IDBConnection */
+ private $db;
+
+ const ACCESS_OWNER = 1;
+ const ACCESS_READ_WRITE = 2;
+ const ACCESS_READ = 3;
+
+ /** @var string */
+ private $resourceType;
+
+ /**
+ * CardDavBackend constructor.
+ *
+ * @param IDBConnection $db
+ */
+ public function __construct(IDBConnection $db, $resourceType) {
+ $this->db = $db;
+ $this->resourceType = $resourceType;
+ }
+
+ /**
+ * @param IShareable $shareable
+ * @param string[] $add
+ * @param string[] $remove
+ */
+ public function updateShares($shareable, $add, $remove) {
+ foreach($add as $element) {
+ $this->shareWith($shareable, $element);
+ }
+ foreach($remove as $element) {
+ $this->unshare($shareable, $element);
+ }
+ }
+
+ /**
+ * @param IShareable $shareable
+ * @param string $element
+ */
+ private function shareWith($shareable, $element) {
+ $user = $element['href'];
+ $parts = explode(':', $user, 2);
+ if ($parts[0] !== 'principal') {
+ return;
+ }
+
+ // don't share with owner
+ if ($shareable->getOwner() === $parts[1]) {
+ return;
+ }
+
+ // remove the share if it already exists
+ $this->unshare($shareable, $element['href']);
+ $access = self::ACCESS_READ;
+ if (isset($element['readOnly'])) {
+ $access = $element['readOnly'] ? self::ACCESS_READ : self::ACCESS_READ_WRITE;
+ }
+
+ $query = $this->db->getQueryBuilder();
+ $query->insert('dav_shares')
+ ->values([
+ 'principaluri' => $query->createNamedParameter($parts[1]),
+ 'type' => $query->createNamedParameter($this->resourceType),
+ 'access' => $query->createNamedParameter($access),
+ 'resourceid' => $query->createNamedParameter($shareable->getResourceId())
+ ]);
+ $query->execute();
+ }
+
+ /**
+ * @param $resourceId
+ */
+ public function deleteAllShares($resourceId) {
+ $query = $this->db->getQueryBuilder();
+ $query->delete('dav_shares')
+ ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId)))
+ ->andWhere($query->expr()->eq('type', $query->createNamedParameter($this->resourceType)))
+ ->execute();
+ }
+
+ /**
+ * @param IShareable $shareable
+ * @param string $element
+ */
+ private function unshare($shareable, $element) {
+ $parts = explode(':', $element, 2);
+ if ($parts[0] !== 'principal') {
+ return;
+ }
+
+ // don't share with owner
+ if ($shareable->getOwner() === $parts[1]) {
+ return;
+ }
+
+ $query = $this->db->getQueryBuilder();
+ $query->delete('dav_shares')
+ ->where($query->expr()->eq('resourceid', $query->createNamedParameter($shareable->getResourceId())))
+ ->andWhere($query->expr()->eq('type', $query->createNamedParameter($this->resourceType)))
+ ->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($parts[1])))
+ ;
+ $query->execute();
+ }
+
+ /**
+ * Returns the list of people whom this resource is shared with.
+ *
+ * Every element in this array should have the following properties:
+ * * href - Often a mailto: address
+ * * commonName - Optional, for example a first + last name
+ * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
+ * * readOnly - boolean
+ * * summary - Optional, a description for the share
+ *
+ * @return array
+ */
+ public function getShares($resourceId) {
+ $query = $this->db->getQueryBuilder();
+ $result = $query->select(['principaluri', 'access'])
+ ->from('dav_shares')
+ ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId)))
+ ->andWhere($query->expr()->eq('type', $query->createNamedParameter($this->resourceType)))
+ ->execute();
+
+ $shares = [];
+ while($row = $result->fetch()) {
+ $shares[]= [
+ 'href' => "principal:${row['principaluri']}",
+// 'commonName' => isset($p['{DAV:}displayname']) ? $p['{DAV:}displayname'] : '',
+ 'status' => 1,
+ 'readOnly' => ($row['access'] == self::ACCESS_READ),
+ '{'.\OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD.'}principal' => $row['principaluri']
+ ];
+ }
+
+ return $shares;
+ }
+
+ /**
+ * For shared resources the sharee is set in the ACL of the resource
+ *
+ * @param int $resourceId
+ * @param array $acl
+ * @return array
+ */
+ public function applyShareAcl($resourceId, $acl) {
+
+ $shares = $this->getShares($resourceId);
+ foreach ($shares as $share) {
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'],
+ 'protected' => true,
+ ];
+ if (!$share['readOnly']) {
+ $acl[] = [
+ 'privilege' => '{DAV:}write',
+ 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'],
+ 'protected' => true,
+ ];
+ }
+ }
+ return $acl;
+ }
+}
diff --git a/apps/dav/lib/dav/sharing/ishareable.php b/apps/dav/lib/dav/sharing/ishareable.php
new file mode 100644
index 00000000000..f6b6bfa8862
--- /dev/null
+++ b/apps/dav/lib/dav/sharing/ishareable.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\DAV\Sharing;
+use Sabre\DAV\INode;
+
+/**
+ * This interface represents a dav resource that can be shared with other users.
+ *
+ */
+interface IShareable extends INode {
+
+ /**
+ * Updates the list of shares.
+ *
+ * The first array is a list of people that are to be added to the
+ * resource.
+ *
+ * Every element in the add array has the following properties:
+ * * href - A url. Usually a mailto: address
+ * * commonName - Usually a first and last name, or false
+ * * summary - A description of the share, can also be false
+ * * readOnly - A boolean value
+ *
+ * Every element in the remove array is just the address string.
+ *
+ * @param array $add
+ * @param array $remove
+ * @return void
+ */
+ function updateShares(array $add, array $remove);
+
+ /**
+ * Returns the list of people whom this resource is shared with.
+ *
+ * Every element in this array should have the following properties:
+ * * href - Often a mailto: address
+ * * commonName - Optional, for example a first + last name
+ * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
+ * * readOnly - boolean
+ * * summary - Optional, a description for the share
+ *
+ * @return array
+ */
+ function getShares();
+
+ /**
+ * @return int
+ */
+ public function getResourceId();
+
+ /**
+ * @return string
+ */
+ public function getOwner();
+
+} \ No newline at end of file
diff --git a/apps/dav/lib/dav/sharing/plugin.php b/apps/dav/lib/dav/sharing/plugin.php
new file mode 100644
index 00000000000..f6e2cceebd9
--- /dev/null
+++ b/apps/dav/lib/dav/sharing/plugin.php
@@ -0,0 +1,218 @@
+<?php
+/**
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\DAV\Sharing;
+
+use OCA\DAV\Connector\Sabre\Auth;
+use OCA\DAV\DAV\Sharing\Xml\Invite;
+use OCP\IRequest;
+use Sabre\DAV\Exception\BadRequest;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\INode;
+use Sabre\DAV\PropFind;
+use Sabre\DAV\Server;
+use Sabre\DAV\ServerPlugin;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
+
+class Plugin extends ServerPlugin {
+
+ const NS_OWNCLOUD = 'http://owncloud.org/ns';
+
+ /** @var Auth */
+ private $auth;
+
+ /** @var IRequest */
+ private $request;
+
+ /**
+ * Plugin constructor.
+ *
+ * @param Auth $authBackEnd
+ * @param IRequest $request
+ */
+ public function __construct(Auth $authBackEnd, IRequest $request) {
+ $this->auth = $authBackEnd;
+ $this->request = $request;
+ }
+
+ /**
+ * Reference to SabreDAV server object.
+ *
+ * @var \Sabre\DAV\Server
+ */
+ protected $server;
+
+ /**
+ * This method should return a list of server-features.
+ *
+ * This is for example 'versioning' and is added to the DAV: header
+ * in an OPTIONS response.
+ *
+ * @return string[]
+ */
+ function getFeatures() {
+ return ['oc-resource-sharing'];
+ }
+
+ /**
+ * Returns a plugin name.
+ *
+ * Using this name other plugins will be able to access other plugins
+ * using Sabre\DAV\Server::getPlugin
+ *
+ * @return string
+ */
+ function getPluginName() {
+ return 'oc-resource-sharing';
+ }
+
+ /**
+ * This initializes the plugin.
+ *
+ * This function is called by Sabre\DAV\Server, after
+ * addPlugin is called.
+ *
+ * This method should set up the required event subscriptions.
+ *
+ * @param Server $server
+ * @return void
+ */
+ function initialize(Server $server) {
+ $this->server = $server;
+ $this->server->xml->elementMap['{' . Plugin::NS_OWNCLOUD . '}share'] = 'OCA\\DAV\\DAV\\Sharing\\Xml\\ShareRequest';
+ $this->server->xml->elementMap['{' . Plugin::NS_OWNCLOUD . '}invite'] = 'OCA\\DAV\\DAV\\Sharing\\Xml\\Invite';
+
+ $this->server->on('method:POST', [$this, 'httpPost']);
+ $this->server->on('propFind', [$this, 'propFind']);
+ }
+
+ /**
+ * We intercept this to handle POST requests on a dav resource.
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ * @return null|false
+ */
+ function httpPost(RequestInterface $request, ResponseInterface $response) {
+
+ $path = $request->getPath();
+
+ // Only handling xml
+ $contentType = $request->getHeader('Content-Type');
+ if (strpos($contentType, 'application/xml') === false && strpos($contentType, 'text/xml') === false)
+ return;
+
+ // Making sure the node exists
+ try {
+ $node = $this->server->tree->getNodeForPath($path);
+ } catch (NotFound $e) {
+ return;
+ }
+
+ // CSRF protection
+ $this->protectAgainstCSRF();
+
+ $requestBody = $request->getBodyAsString();
+
+ // If this request handler could not deal with this POST request, it
+ // will return 'null' and other plugins get a chance to handle the
+ // request.
+ //
+ // However, we already requested the full body. This is a problem,
+ // because a body can only be read once. This is why we preemptively
+ // re-populated the request body with the existing data.
+ $request->setBody($requestBody);
+
+ $message = $this->server->xml->parse($requestBody, $request->getUrl(), $documentType);
+
+ switch ($documentType) {
+
+ // Dealing with the 'share' document, which modified invitees on a
+ // calendar.
+ case '{' . self::NS_OWNCLOUD . '}share' :
+
+ // We can only deal with IShareableCalendar objects
+ if (!$node instanceof IShareable) {
+ return;
+ }
+
+ $this->server->transactionType = 'post-oc-resource-share';
+
+ // Getting ACL info
+ $acl = $this->server->getPlugin('acl');
+
+ // If there's no ACL support, we allow everything
+ if ($acl) {
+ /** @var \Sabre\DAVACL\Plugin $acl */
+ $acl->checkPrivileges($path, '{DAV:}write');
+ }
+
+ $node->updateShares($message->set, $message->remove);
+
+ $response->setStatus(200);
+ // Adding this because sending a response body may cause issues,
+ // and I wanted some type of indicator the response was handled.
+ $response->setHeader('X-Sabre-Status', 'everything-went-well');
+
+ // Breaking the event chain
+ return false;
+ }
+ }
+
+ /**
+ * This event is triggered when properties are requested for a certain
+ * node.
+ *
+ * This allows us to inject any properties early.
+ *
+ * @param PropFind $propFind
+ * @param INode $node
+ * @return void
+ */
+ function propFind(PropFind $propFind, INode $node) {
+ if ($node instanceof IShareable) {
+
+ $propFind->handle('{' . Plugin::NS_OWNCLOUD . '}invite', function() use ($node) {
+ return new Invite(
+ $node->getShares()
+ );
+ });
+
+ }
+ }
+
+ private function protectAgainstCSRF() {
+ $user = $this->auth->getCurrentUser();
+ if ($this->auth->isDavAuthenticated($user)) {
+ return true;
+ }
+
+ if ($this->request->passesCSRFCheck()) {
+ return true;
+ }
+
+ throw new BadRequest();
+ }
+
+
+}
diff --git a/apps/dav/lib/dav/sharing/xml/invite.php b/apps/dav/lib/dav/sharing/xml/invite.php
new file mode 100644
index 00000000000..659f95d8074
--- /dev/null
+++ b/apps/dav/lib/dav/sharing/xml/invite.php
@@ -0,0 +1,149 @@
+<?php
+
+namespace OCA\DAV\DAV\Sharing\Xml;
+
+use OCA\DAV\DAV\Sharing\Plugin;
+use Sabre\Xml\Writer;
+use Sabre\Xml\XmlSerializable;
+
+/**
+ * Invite property
+ *
+ * This property encodes the 'invite' property, as defined by
+ * the 'caldav-sharing-02' spec, in the http://calendarserver.org/ns/
+ * namespace.
+ *
+ * @see https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-sharing-02.txt
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Invite implements XmlSerializable {
+
+ /**
+ * The list of users a calendar has been shared to.
+ *
+ * @var array
+ */
+ protected $users;
+
+ /**
+ * The organizer contains information about the person who shared the
+ * object.
+ *
+ * @var array
+ */
+ protected $organizer;
+
+ /**
+ * Creates the property.
+ *
+ * Users is an array. Each element of the array has the following
+ * properties:
+ *
+ * * href - Often a mailto: address
+ * * commonName - Optional, for example a first and lastname for a user.
+ * * status - One of the SharingPlugin::STATUS_* constants.
+ * * readOnly - true or false
+ * * summary - Optional, description of the share
+ *
+ * The organizer key is optional to specify. It's only useful when a
+ * 'sharee' requests the sharing information.
+ *
+ * The organizer may have the following properties:
+ * * href - Often a mailto: address.
+ * * commonName - Optional human-readable name.
+ * * firstName - Optional first name.
+ * * lastName - Optional last name.
+ *
+ * If you wonder why these two structures are so different, I guess a
+ * valid answer is that the current spec is still a draft.
+ *
+ * @param array $users
+ */
+ function __construct(array $users, array $organizer = null) {
+
+ $this->users = $users;
+ $this->organizer = $organizer;
+
+ }
+
+ /**
+ * Returns the list of users, as it was passed to the constructor.
+ *
+ * @return array
+ */
+ function getValue() {
+
+ return $this->users;
+
+ }
+
+ /**
+ * The xmlSerialize metod is called during xml writing.
+ *
+ * Use the $writer argument to write its own xml serialization.
+ *
+ * An important note: do _not_ create a parent element. Any element
+ * implementing XmlSerializble should only ever write what's considered
+ * its 'inner xml'.
+ *
+ * The parent of the current element is responsible for writing a
+ * containing element.
+ *
+ * This allows serializers to be re-used for different element names.
+ *
+ * If you are opening new elements, you must also close them again.
+ *
+ * @param Writer $writer
+ * @return void
+ */
+ function xmlSerialize(Writer $writer) {
+
+ $cs = '{' . Plugin::NS_OWNCLOUD . '}';
+
+ if (!is_null($this->organizer)) {
+
+ $writer->startElement($cs . 'organizer');
+ $writer->writeElement('{DAV:}href', $this->organizer['href']);
+
+ if (isset($this->organizer['commonName']) && $this->organizer['commonName']) {
+ $writer->writeElement($cs . 'common-name', $this->organizer['commonName']);
+ }
+ if (isset($this->organizer['firstName']) && $this->organizer['firstName']) {
+ $writer->writeElement($cs . 'first-name', $this->organizer['firstName']);
+ }
+ if (isset($this->organizer['lastName']) && $this->organizer['lastName']) {
+ $writer->writeElement($cs . 'last-name', $this->organizer['lastName']);
+ }
+ $writer->endElement(); // organizer
+
+ }
+
+ foreach ($this->users as $user) {
+
+ $writer->startElement($cs . 'user');
+ $writer->writeElement('{DAV:}href', $user['href']);
+ if (isset($user['commonName']) && $user['commonName']) {
+ $writer->writeElement($cs . 'common-name', $user['commonName']);
+ }
+ $writer->writeElement($cs . 'invite-accepted');
+
+ $writer->startElement($cs . 'access');
+ if ($user['readOnly']) {
+ $writer->writeElement($cs . 'read');
+ } else {
+ $writer->writeElement($cs . 'read-write');
+ }
+ $writer->endElement(); // access
+
+ if (isset($user['summary']) && $user['summary']) {
+ $writer->writeElement($cs . 'summary', $user['summary']);
+ }
+
+ $writer->endElement(); //user
+
+ }
+
+ }
+}
diff --git a/apps/dav/lib/dav/sharing/xml/sharerequest.php b/apps/dav/lib/dav/sharing/xml/sharerequest.php
new file mode 100644
index 00000000000..776fb446b6c
--- /dev/null
+++ b/apps/dav/lib/dav/sharing/xml/sharerequest.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\DAV\Sharing\Xml;
+
+use OCA\DAV\DAV\Sharing\Plugin;
+use Sabre\Xml\Reader;
+use Sabre\Xml\XmlDeserializable;
+
+class ShareRequest implements XmlDeserializable {
+
+ public $set = [];
+
+ public $remove = [];
+
+ /**
+ * Constructor
+ *
+ * @param array $set
+ * @param array $remove
+ */
+ function __construct(array $set, array $remove) {
+
+ $this->set = $set;
+ $this->remove = $remove;
+
+ }
+
+ static function xmlDeserialize(Reader $reader) {
+
+ $elements = $reader->parseInnerTree([
+ '{' . Plugin::NS_OWNCLOUD. '}set' => 'Sabre\\Xml\\Element\\KeyValue',
+ '{' . Plugin::NS_OWNCLOUD . '}remove' => 'Sabre\\Xml\\Element\\KeyValue',
+ ]);
+
+ $set = [];
+ $remove = [];
+
+ foreach ($elements as $elem) {
+ switch ($elem['name']) {
+
+ case '{' . Plugin::NS_OWNCLOUD . '}set' :
+ $sharee = $elem['value'];
+
+ $sumElem = '{' . Plugin::NS_OWNCLOUD . '}summary';
+ $commonName = '{' . Plugin::NS_OWNCLOUD . '}common-name';
+
+ $set[] = [
+ 'href' => $sharee['{DAV:}href'],
+ 'commonName' => isset($sharee[$commonName]) ? $sharee[$commonName] : null,
+ 'summary' => isset($sharee[$sumElem]) ? $sharee[$sumElem] : null,
+ 'readOnly' => !array_key_exists('{' . Plugin::NS_OWNCLOUD . '}read-write', $sharee),
+ ];
+ break;
+
+ case '{' . Plugin::NS_OWNCLOUD . '}remove' :
+ $remove[] = $elem['value']['{DAV:}href'];
+ break;
+
+ }
+ }
+
+ return new self($set, $remove);
+
+ }
+
+}
diff --git a/apps/dav/lib/dav/systemprincipalbackend.php b/apps/dav/lib/dav/systemprincipalbackend.php
new file mode 100644
index 00000000000..8001ec4e6c6
--- /dev/null
+++ b/apps/dav/lib/dav/systemprincipalbackend.php
@@ -0,0 +1,179 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\DAV;
+
+use Sabre\DAVACL\PrincipalBackend\AbstractBackend;
+use Sabre\HTTP\URLUtil;
+
+class SystemPrincipalBackend extends AbstractBackend {
+
+ /**
+ * Returns a list of principals based on a prefix.
+ *
+ * This prefix will often contain something like 'principals'. You are only
+ * expected to return principals that are in this base path.
+ *
+ * You are expected to return at least a 'uri' for every user, you can
+ * return any additional properties if you wish so. Common properties are:
+ * {DAV:}displayname
+ * {http://sabredav.org/ns}email-address - This is a custom SabreDAV
+ * field that's actually injected in a number of other properties. If
+ * you have an email address, use this property.
+ *
+ * @param string $prefixPath
+ * @return array
+ */
+ function getPrincipalsByPrefix($prefixPath) {
+ $principals = [];
+
+ if ($prefixPath === 'principals/system') {
+ $principals[] = [
+ 'uri' => 'principals/system/system',
+ '{DAV:}displayname' => 'system',
+ ];
+ }
+
+ return $principals;
+ }
+
+ /**
+ * Returns a specific principal, specified by it's path.
+ * The returned structure should be the exact same as from
+ * getPrincipalsByPrefix.
+ *
+ * @param string $path
+ * @return array
+ */
+ function getPrincipalByPath($path) {
+
+ if ($path === 'principals/system/system') {
+ $principal = [
+ 'uri' => 'principals/system/system',
+ '{DAV:}displayname' => 'system',
+ ];
+ return $principal;
+ }
+
+ return null;
+ }
+
+ /**
+ * Updates one ore more webdav properties on a principal.
+ *
+ * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+ * To do the actual updates, you must tell this object which properties
+ * you're going to process with the handle() method.
+ *
+ * Calling the handle method is like telling the PropPatch object "I
+ * promise I can handle updating this property".
+ *
+ * Read the PropPatch documentation for more info and examples.
+ *
+ * @param string $path
+ * @param \Sabre\DAV\PropPatch $propPatch
+ * @return void
+ */
+ function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) {
+ }
+
+ /**
+ * This method is used to search for principals matching a set of
+ * properties.
+ *
+ * This search is specifically used by RFC3744's principal-property-search
+ * REPORT.
+ *
+ * The actual search should be a unicode-non-case-sensitive search. The
+ * keys in searchProperties are the WebDAV property names, while the values
+ * are the property values to search on.
+ *
+ * By default, if multiple properties are submitted to this method, the
+ * various properties should be combined with 'AND'. If $test is set to
+ * 'anyof', it should be combined using 'OR'.
+ *
+ * This method should simply return an array with full principal uri's.
+ *
+ * If somebody attempted to search on a property the backend does not
+ * support, you should simply return 0 results.
+ *
+ * You can also just return 0 results if you choose to not support
+ * searching at all, but keep in mind that this may stop certain features
+ * from working.
+ *
+ * @param string $prefixPath
+ * @param array $searchProperties
+ * @param string $test
+ * @return array
+ */
+ function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
+ return [];
+ }
+
+ /**
+ * Returns the list of members for a group-principal
+ *
+ * @param string $principal
+ * @return array
+ */
+ function getGroupMemberSet($principal) {
+ // TODO: for now the group principal has only one member, the user itself
+ $principal = $this->getPrincipalByPath($principal);
+ if (!$principal) {
+ throw new \Sabre\DAV\Exception('Principal not found');
+ }
+
+ return [$principal['uri']];
+ }
+
+ /**
+ * Returns the list of groups a principal is a member of
+ *
+ * @param string $principal
+ * @return array
+ */
+ function getGroupMembership($principal) {
+ list($prefix, $name) = URLUtil::splitPath($principal);
+
+ if ($prefix === 'principals/system') {
+ $principal = $this->getPrincipalByPath($principal);
+ if (!$principal) {
+ throw new \Sabre\DAV\Exception('Principal not found');
+ }
+
+ return [];
+ }
+ return [];
+ }
+
+ /**
+ * Updates the list of group members for a group principal.
+ *
+ * The principals should be passed as a list of uri's.
+ *
+ * @param string $principal
+ * @param array $members
+ * @return void
+ */
+ function setGroupMemberSet($principal, array $members) {
+ throw new \Sabre\DAV\Exception('Setting members of the group is not supported yet');
+ }
+}
diff --git a/apps/dav/lib/files/custompropertiesbackend.php b/apps/dav/lib/files/custompropertiesbackend.php
index 83776997a52..aa541f88dad 100644
--- a/apps/dav/lib/files/custompropertiesbackend.php
+++ b/apps/dav/lib/files/custompropertiesbackend.php
@@ -1,11 +1,8 @@
<?php
/**
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -44,7 +41,6 @@ class CustomPropertiesBackend implements BackendInterface {
'{DAV:}getetag',
'{DAV:}quota-used-bytes',
'{DAV:}quota-available-bytes',
- '{DAV:}quota-available-bytes',
'{http://owncloud.org/ns}permissions',
'{http://owncloud.org/ns}downloadURL',
'{http://owncloud.org/ns}dDC',
diff --git a/apps/dav/lib/files/fileshome.php b/apps/dav/lib/files/fileshome.php
index 5e145a2b002..d56b95881c3 100644
--- a/apps/dav/lib/files/fileshome.php
+++ b/apps/dav/lib/files/fileshome.php
@@ -1,5 +1,23 @@
<?php
-
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV\Files;
use OCA\DAV\Connector\Sabre\Directory;
diff --git a/apps/dav/lib/files/rootcollection.php b/apps/dav/lib/files/rootcollection.php
index bbe3c784a53..63328aac8e3 100644
--- a/apps/dav/lib/files/rootcollection.php
+++ b/apps/dav/lib/files/rootcollection.php
@@ -1,5 +1,23 @@
<?php
-
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV\Files;
use Sabre\DAVACL\AbstractPrincipalCollection;
diff --git a/apps/dav/lib/hookmanager.php b/apps/dav/lib/hookmanager.php
new file mode 100644
index 00000000000..d2199bec598
--- /dev/null
+++ b/apps/dav/lib/hookmanager.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV;
+
+use OCA\DAV\CardDAV\SyncService;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\Util;
+
+class HookManager {
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var SyncService */
+ private $syncService;
+
+ /** @var IUser[] */
+ private $usersToDelete;
+
+ public function __construct(IUserManager $userManager, SyncService $syncService) {
+ $this->userManager = $userManager;
+ $this->syncService = $syncService;
+ }
+
+ public function setup() {
+ Util::connectHook('OC_User',
+ 'post_createUser',
+ $this,
+ 'postCreateUser');
+ Util::connectHook('OC_User',
+ 'pre_deleteUser',
+ $this,
+ 'preDeleteUser');
+ Util::connectHook('OC_User',
+ 'post_deleteUser',
+ $this,
+ 'postDeleteUser');
+ Util::connectHook('OC_User',
+ 'changeUser',
+ $this,
+ 'changeUser');
+ }
+
+ public function postCreateUser($params) {
+ $user = $this->userManager->get($params['uid']);
+ $this->syncService->updateUser($user);
+ }
+
+ public function preDeleteUser($params) {
+ $this->usersToDelete[$params['uid']] = $this->userManager->get($params['uid']);
+ }
+
+ public function postDeleteUser($params) {
+ $uid = $params['uid'];
+ if (isset($this->usersToDelete[$uid])){
+ $this->syncService->deleteUser($this->usersToDelete[$uid]);
+ }
+ }
+
+ public function changeUser($params) {
+ $user = $params['user'];
+ $this->syncService->updateUser($user);
+ }
+}
diff --git a/apps/dav/lib/migration/addressbookadapter.php b/apps/dav/lib/migration/addressbookadapter.php
new file mode 100644
index 00000000000..ef7b00188fb
--- /dev/null
+++ b/apps/dav/lib/migration/addressbookadapter.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace OCA\Dav\Migration;
+
+use OCP\IDBConnection;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class AddressBookAdapter {
+
+ /** @var \OCP\IDBConnection */
+ protected $dbConnection;
+
+ /** @var string */
+ private $sourceBookTable;
+
+ /** @var string */
+ private $sourceCardsTable;
+
+ /**
+ * @param IDBConnection $dbConnection
+ * @param string $sourceBookTable
+ * @param string $sourceCardsTable
+ */
+ function __construct(IDBConnection $dbConnection,
+ $sourceBookTable = 'contacts_addressbooks',
+ $sourceCardsTable = 'contacts_cards') {
+ $this->dbConnection = $dbConnection;
+ $this->sourceBookTable = $sourceBookTable;
+ $this->sourceCardsTable = $sourceCardsTable;
+ }
+
+ /**
+ * @param string $user
+ * @param \Closure $callBack
+ */
+ public function foreachBook($user, \Closure $callBack) {
+ // get all addressbooks of that user
+ $query = $this->dbConnection->getQueryBuilder();
+ $stmt = $query->select('*')->from($this->sourceBookTable)
+ ->where($query->expr()->eq('userid', $query->createNamedParameter($user)))
+ ->execute();
+
+ while($row = $stmt->fetch()) {
+ $callBack($row);
+ }
+ }
+
+ public function setup() {
+ if (!$this->dbConnection->tableExists($this->sourceBookTable)) {
+ throw new \DomainException('Contacts tables are missing. Nothing to do.');
+ }
+ }
+
+ /**
+ * @param int $addressBookId
+ * @param \Closure $callBack
+ */
+ public function foreachCard($addressBookId, \Closure $callBack) {
+ $query = $this->dbConnection->getQueryBuilder();
+ $stmt = $query->select('*')->from($this->sourceCardsTable)
+ ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
+ ->execute();
+
+ while($row = $stmt->fetch()) {
+ $callBack($row);
+ }
+ }
+
+ /**
+ * @param int $addressBookId
+ * @return array
+ */
+ public function getShares($addressBookId) {
+ $query = $this->dbConnection->getQueryBuilder();
+ $shares = $query->select('*')->from('share')
+ ->where($query->expr()->eq('item_source', $query->createNamedParameter($addressBookId)))
+ ->andWhere($query->expr()->eq('item_type', $query->expr()->literal('addressbook')))
+ ->andWhere($query->expr()->in('share_type', [ $query->expr()->literal(0), $query->expr()->literal(1)]))
+ ->execute()
+ ->fetchAll();
+
+ return $shares;
+ }
+}
diff --git a/apps/dav/lib/migration/migrateaddressbooks.php b/apps/dav/lib/migration/migrateaddressbooks.php
new file mode 100644
index 00000000000..0dad6495691
--- /dev/null
+++ b/apps/dav/lib/migration/migrateaddressbooks.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace OCA\Dav\Migration;
+
+use OCA\DAV\CardDAV\AddressBook;
+use OCA\DAV\CardDAV\CardDavBackend;
+use Sabre\CardDAV\Plugin;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class MigrateAddressbooks {
+
+ /** @var AddressBookAdapter */
+ protected $adapter;
+
+ /** @var CardDavBackend */
+ private $backend;
+
+ /**
+ * @param AddressBookAdapter $adapter
+ * @param CardDavBackend $backend
+ */
+ function __construct(AddressBookAdapter $adapter,
+ CardDavBackend $backend
+ ) {
+ $this->adapter = $adapter;
+ $this->backend = $backend;
+ }
+
+ /**
+ * @param string $user
+ */
+ public function migrateForUser($user) {
+
+ $this->adapter->foreachBook($user, function($book) use ($user) {
+ $principal = "principals/users/$user";
+ $knownBooks = $this->backend->getAddressBooksByUri($principal, $book['uri']);
+ if (!is_null($knownBooks)) {
+ return;
+ }
+
+ $newId = $this->backend->createAddressBook($principal, $book['uri'], [
+ '{DAV:}displayname' => $book['displayname'],
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $book['description']
+ ]);
+
+ $this->migrateBook($book['id'], $newId);
+ $this->migrateShares($book['id'], $newId);
+ });
+ }
+
+ public function setup() {
+ $this->adapter->setup();
+ }
+
+ /**
+ * @param int $addressBookId
+ * @param int $newAddressBookId
+ */
+ private function migrateBook($addressBookId, $newAddressBookId) {
+ $this->adapter->foreachCard($addressBookId, function($card) use ($newAddressBookId) {
+ $this->backend->createCard($newAddressBookId, $card['uri'], $card['carddata']);
+ });
+ }
+
+ /**
+ * @param int $addressBookId
+ * @param int $newAddressBookId
+ */
+ private function migrateShares($addressBookId, $newAddressBookId) {
+ $shares =$this->adapter->getShares($addressBookId);
+ if (empty($shares)) {
+ return;
+ }
+
+ $add = array_map(function($s) {
+ $prefix = 'principal:principals/users/';
+ if ($s['share_type'] === 1) {
+ $prefix = 'principal:principals/groups/';
+ }
+ return [
+ 'href' => $prefix . $s['share_with']
+ ];
+ }, $shares);
+
+ $newAddressBook = $this->backend->getAddressBookById($newAddressBookId);
+ $book = new AddressBook($this->backend, $newAddressBook);
+ $this->backend->updateShares($book, $add, []);
+ }
+}
diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php
index 850180d8481..2a8f63a2270 100644
--- a/apps/dav/lib/rootcollection.php
+++ b/apps/dav/lib/rootcollection.php
@@ -1,37 +1,105 @@
<?php
-
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV;
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\CalDAV\CalendarRoot;
+use OCA\DAV\CardDAV\AddressBookRoot;
use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\Connector\Sabre\Principal;
+use OCA\DAV\DAV\GroupPrincipalBackend;
+use OCA\DAV\DAV\SystemPrincipalBackend;
use Sabre\CalDAV\Principal\Collection;
-use Sabre\CardDAV\AddressBookRoot;
use Sabre\DAV\SimpleCollection;
class RootCollection extends SimpleCollection {
public function __construct() {
$config = \OC::$server->getConfig();
- $principalBackend = new Principal(
- $config,
- \OC::$server->getUserManager()
+ $db = \OC::$server->getDatabaseConnection();
+ $userPrincipalBackend = new Principal(
+ \OC::$server->getUserManager(),
+ \OC::$server->getGroupManager()
+ );
+ $groupPrincipalBackend = new GroupPrincipalBackend(
+ \OC::$server->getGroupManager()
);
// as soon as debug mode is enabled we allow listing of principals
$disableListing = !$config->getSystemValue('debug', false);
// setup the first level of the dav tree
- $principalCollection = new Collection($principalBackend);
- $principalCollection->disableListing = $disableListing;
- $filesCollection = new Files\RootCollection($principalBackend);
+ $userPrincipals = new Collection($userPrincipalBackend, 'principals/users');
+ $userPrincipals->disableListing = $disableListing;
+ $groupPrincipals = new Collection($groupPrincipalBackend, 'principals/groups');
+ $groupPrincipals->disableListing = $disableListing;
+ $systemPrincipals = new Collection(new SystemPrincipalBackend(), 'principals/system');
+ $systemPrincipals->disableListing = $disableListing;
+ $filesCollection = new Files\RootCollection($userPrincipalBackend, 'principals/users');
$filesCollection->disableListing = $disableListing;
- $cardDavBackend = new CardDavBackend(\OC::$server->getDatabaseConnection());
- $addressBookRoot = new AddressBookRoot($principalBackend, $cardDavBackend);
- $addressBookRoot->disableListing = $disableListing;
+ $caldavBackend = new CalDavBackend($db, $userPrincipalBackend);
+ $calendarRoot = new CalendarRoot($userPrincipalBackend, $caldavBackend, 'principals/users');
+ $calendarRoot->disableListing = $disableListing;
+
+ $systemTagCollection = new SystemTag\SystemTagsByIdCollection(
+ \OC::$server->getSystemTagManager(),
+ \OC::$server->getUserSession(),
+ \OC::$server->getGroupManager()
+ );
+ $systemTagRelationsCollection = new SystemTag\SystemTagsRelationsCollection(
+ \OC::$server->getSystemTagManager(),
+ \OC::$server->getSystemTagObjectMapper(),
+ \OC::$server->getUserSession(),
+ \OC::$server->getGroupManager(),
+ \OC::$server->getRootFolder()
+ );
+ $commentsCollection = new Comments\RootCollection(
+ \OC::$server->getCommentsManager(),
+ \OC::$server->getUserManager(),
+ \OC::$server->getUserSession(),
+ \OC::$server->getRootFolder(),
+ \OC::$server->getLogger()
+ );
+
+ $usersCardDavBackend = new CardDavBackend($db, $userPrincipalBackend);
+ $usersAddressBookRoot = new AddressBookRoot($userPrincipalBackend, $usersCardDavBackend, 'principals/users');
+ $usersAddressBookRoot->disableListing = $disableListing;
+
+ $systemCardDavBackend = new CardDavBackend($db, $userPrincipalBackend);
+ $systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, 'principals/system');
+ $systemAddressBookRoot->disableListing = $disableListing;
$children = [
- $principalCollection,
- $filesCollection,
- $addressBookRoot,
+ new SimpleCollection('principals', [
+ $userPrincipals,
+ $groupPrincipals,
+ $systemPrincipals]),
+ $filesCollection,
+ $calendarRoot,
+ new SimpleCollection('addressbooks', [
+ $usersAddressBookRoot,
+ $systemAddressBookRoot]),
+ $systemTagCollection,
+ $systemTagRelationsCollection,
+ $commentsCollection,
];
parent::__construct('root', $children);
diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php
index 395544761ab..3bf8e155082 100644
--- a/apps/dav/lib/server.php
+++ b/apps/dav/lib/server.php
@@ -1,13 +1,35 @@
<?php
-
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV;
+use OCA\DAV\CalDAV\Schedule\IMipPlugin;
+use OCA\DAV\Connector\FedAuth;
use OCA\DAV\Connector\Sabre\Auth;
use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin;
use OCA\DAV\Files\CustomPropertiesBackend;
use OCP\IRequest;
+use OCP\SabrePluginEvent;
use Sabre\DAV\Auth\Plugin;
-use Sabre\HTTP\Util;
class Server {
@@ -17,6 +39,10 @@ class Server {
public function __construct(IRequest $request, $baseUri) {
$this->request = $request;
$this->baseUri = $baseUri;
+ $logger = \OC::$server->getLogger();
+ $mailer = \OC::$server->getMailer();
+ $dispatcher = \OC::$server->getEventDispatcher();
+
$root = new RootCollection();
$this->server = new \OCA\DAV\Connector\Sabre\Server($root);
@@ -31,15 +57,50 @@ class Server {
$this->server->setBaseUri($this->baseUri);
$this->server->addPlugin(new BlockLegacyClientPlugin(\OC::$server->getConfig()));
- $this->server->addPlugin(new Plugin($authBackend, 'ownCloud'));
+ $authPlugin = new Plugin($authBackend, 'ownCloud');
+ $this->server->addPlugin($authPlugin);
+
+ // allow setup of additional auth backends
+ $event = new SabrePluginEvent($this->server);
+ $dispatcher->dispatch('OCA\DAV\Connector\Sabre::authInit', $event);
+
+ $this->server->addPlugin(new \OCA\DAV\Connector\Sabre\DummyGetResponsePlugin());
+ $this->server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $logger));
+ $this->server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin());
+ $this->server->addPlugin(new \Sabre\DAV\Sync\Plugin());
- $this->server->addPlugin(new \Sabre\DAVACL\Plugin());
+ // acl
+ $acl = new \Sabre\DAVACL\Plugin();
+ $acl->defaultUsernamePath = 'principals/users';
+ $this->server->addPlugin($acl);
- $this->server->addPlugin(new \Sabre\CardDAV\Plugin());
+ // calendar plugins
+ $this->server->addPlugin(new \Sabre\CalDAV\Plugin());
+ $this->server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
+ $this->server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
+ $this->server->addPlugin(new IMipPlugin($mailer, $logger));
+ $this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
+ $this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin());
+ $this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest()));
+
+ // addressbook plugins
+ $this->server->addPlugin(new \OCA\DAV\CardDAV\Plugin());
+
+ // system tags plugins
+ $this->server->addPlugin(new \OCA\DAV\SystemTag\SystemTagPlugin(\OC::$server->getSystemTagManager()));
+
+ // comments plugin
+ $this->server->addPlugin(new \OCA\DAV\Comments\CommentsPlugin(
+ \OC::$server->getCommentsManager(),
+ \OC::$server->getUserSession()
+ ));
- // Finder on OS X requires Class 2 WebDAV support (locking), since we do
- // not provide locking we emulate it using a fake locking plugin.
- if($request->isUserAgent(['/WebDAVFS/'])) {
+ // Some WebDAV clients do require Class 2 WebDAV support (locking), since
+ // we do not provide locking we emulate it using a fake locking plugin.
+ if($request->isUserAgent([
+ '/WebDAVFS/',
+ '/Microsoft Office OneNote 2013/',
+ ])) {
$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\FakeLockerPlugin());
}
diff --git a/apps/dav/lib/systemtag/systemtagmappingnode.php b/apps/dav/lib/systemtag/systemtagmappingnode.php
new file mode 100644
index 00000000000..bb2936c13dc
--- /dev/null
+++ b/apps/dav/lib/systemtag/systemtagmappingnode.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\SystemTag;
+
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Exception\Forbidden;
+
+use OCP\SystemTag\ISystemTag;
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ISystemTagObjectMapper;
+use OCP\SystemTag\TagNotFoundException;
+
+/**
+ * Mapping node for system tag to object id
+ */
+class SystemTagMappingNode extends SystemTagNode {
+
+ /**
+ * @var ISystemTagObjectMapper
+ */
+ private $tagMapper;
+
+ /**
+ * @var string
+ */
+ private $objectId;
+
+ /**
+ * @var string
+ */
+ private $objectType;
+
+ /**
+ * Sets up the node, expects a full path name
+ *
+ * @param ISystemTag $tag system tag
+ * @param string $objectId
+ * @param string $objectType
+ * @param bool $isAdmin whether to allow permissions for admin
+ * @param ISystemTagManager $tagManager
+ * @param ISystemTagObjectMapper $tagMapper
+ */
+ public function __construct(
+ ISystemTag $tag,
+ $objectId,
+ $objectType,
+ $isAdmin,
+ ISystemTagManager $tagManager,
+ ISystemTagObjectMapper $tagMapper
+ ) {
+ $this->objectId = $objectId;
+ $this->objectType = $objectType;
+ $this->tagMapper = $tagMapper;
+ parent::__construct($tag, $isAdmin, $tagManager);
+ }
+
+ /**
+ * Returns the object id of the relationship
+ *
+ * @return string object id
+ */
+ public function getObjectId() {
+ return $this->objectId;
+ }
+
+ /**
+ * Returns the object type of the relationship
+ *
+ * @return string object type
+ */
+ public function getObjectType() {
+ return $this->objectType;
+ }
+
+ /**
+ * Delete tag to object association
+ */
+ public function delete() {
+ try {
+ if (!$this->isAdmin) {
+ if (!$this->tag->isUserVisible()) {
+ throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found');
+ }
+ if (!$this->tag->isUserAssignable()) {
+ throw new Forbidden('No permission to unassign tag ' . $this->tag->getId());
+ }
+ }
+ $this->tagMapper->unassignTags($this->objectId, $this->objectType, $this->tag->getId());
+ } catch (TagNotFoundException $e) {
+ // can happen if concurrent deletion occurred
+ throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e);
+ }
+ }
+}
diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php
new file mode 100644
index 00000000000..ecdb39a762c
--- /dev/null
+++ b/apps/dav/lib/systemtag/systemtagnode.php
@@ -0,0 +1,160 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\SystemTag;
+
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Exception\MethodNotAllowed;
+use Sabre\DAV\Exception\Conflict;
+
+use OCP\SystemTag\ISystemTag;
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\TagNotFoundException;
+use OCP\SystemTag\TagAlreadyExistsException;
+
+/**
+ * DAV node representing a system tag, with the name being the tag id.
+ */
+class SystemTagNode implements \Sabre\DAV\INode {
+
+ /**
+ * @var ISystemTag
+ */
+ protected $tag;
+
+ /**
+ * @var ISystemTagManager
+ */
+ protected $tagManager;
+
+ /**
+ * Whether to allow permissions for admins
+ *
+ * @var bool
+ */
+ protected $isAdmin;
+
+ /**
+ * Sets up the node, expects a full path name
+ *
+ * @param ISystemTag $tag system tag
+ * @param bool $isAdmin whether to allow operations for admins
+ * @param ISystemTagManager $tagManager
+ */
+ public function __construct(ISystemTag $tag, $isAdmin, ISystemTagManager $tagManager) {
+ $this->tag = $tag;
+ $this->isAdmin = $isAdmin;
+ $this->tagManager = $tagManager;
+ }
+
+ /**
+ * Returns the id of the tag
+ *
+ * @return string
+ */
+ public function getName() {
+ return $this->tag->getId();
+ }
+
+ /**
+ * Returns the system tag represented by this node
+ *
+ * @return ISystemTag system tag
+ */
+ public function getSystemTag() {
+ return $this->tag;
+ }
+
+ /**
+ * Renames the node
+ *
+ * @param string $name The new name
+ *
+ * @throws MethodNotAllowed not allowed to rename node
+ */
+ public function setName($name) {
+ throw new MethodNotAllowed();
+ }
+
+ /**
+ * Update tag
+ *
+ * @param string $name new tag name
+ * @param bool $userVisible user visible
+ * @param bool $userAssignable user assignable
+ * @throws NotFound whenever the given tag id does not exist
+ * @throws Conflict whenever a tag already exists with the given attributes
+ */
+ public function update($name, $userVisible, $userAssignable) {
+ try {
+ if (!$this->isAdmin) {
+ if (!$this->tag->isUserVisible()) {
+ throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
+ }
+ if (!$this->tag->isUserAssignable()) {
+ throw new Forbidden('No permission to update tag ' . $this->tag->getId());
+ }
+
+ // only renaming is allowed for regular users
+ if ($userVisible !== $this->tag->isUserVisible()
+ || $userAssignable !== $this->tag->isUserAssignable()
+ ) {
+ throw new Forbidden('No permission to update permissions for tag ' . $this->tag->getId());
+ }
+ }
+ $this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable);
+ } catch (TagNotFoundException $e) {
+ throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist');
+ } catch (TagAlreadyExistsException $e) {
+ throw new Conflict(
+ 'Tag with the properties "' . $name . '", ' .
+ $userVisible . ', ' . $userAssignable . ' already exists'
+ );
+ }
+ }
+
+ /**
+ * Returns null, not supported
+ *
+ */
+ public function getLastModified() {
+ return null;
+ }
+
+ public function delete() {
+ try {
+ if (!$this->isAdmin) {
+ if (!$this->tag->isUserVisible()) {
+ throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found');
+ }
+ if (!$this->tag->isUserAssignable()) {
+ throw new Forbidden('No permission to delete tag ' . $this->tag->getId());
+ }
+ }
+ $this->tagManager->deleteTags($this->tag->getId());
+ } catch (TagNotFoundException $e) {
+ // can happen if concurrent deletion occurred
+ throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e);
+ }
+ }
+}
diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php
new file mode 100644
index 00000000000..3348b431c47
--- /dev/null
+++ b/apps/dav/lib/systemtag/systemtagplugin.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\SystemTag;
+
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\PropFind;
+use Sabre\DAV\PropPatch;
+use Sabre\DAV\Exception\BadRequest;
+use Sabre\DAV\Exception\UnsupportedMediaType;
+use Sabre\DAV\Exception\Conflict;
+
+use OCP\SystemTag\ISystemTag;
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\TagAlreadyExistsException;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
+
+/**
+ * Sabre plugin to handle system tags:
+ *
+ * - makes it possible to create new tags with POST operation
+ * - get/set Webdav properties for tags
+ *
+ */
+class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
+
+ // namespace
+ const NS_OWNCLOUD = 'http://owncloud.org/ns';
+ const ID_PROPERTYNAME = '{http://owncloud.org/ns}id';
+ const DISPLAYNAME_PROPERTYNAME = '{http://owncloud.org/ns}display-name';
+ const USERVISIBLE_PROPERTYNAME = '{http://owncloud.org/ns}user-visible';
+ const USERASSIGNABLE_PROPERTYNAME = '{http://owncloud.org/ns}user-assignable';
+
+ /**
+ * @var \Sabre\DAV\Server $server
+ */
+ private $server;
+
+ /**
+ * @var ISystemTagManager
+ */
+ protected $tagManager;
+
+ /**
+ * System tags plugin
+ *
+ * @param ISystemTagManager $tagManager tag manager
+ */
+ public function __construct(ISystemTagManager $tagManager) {
+ $this->tagManager = $tagManager;
+ }
+
+ /**
+ * This initializes the plugin.
+ *
+ * This function is called by \Sabre\DAV\Server, after
+ * addPlugin is called.
+ *
+ * This method should set up the required event subscriptions.
+ *
+ * @param \Sabre\DAV\Server $server
+ * @return void
+ */
+ public function initialize(\Sabre\DAV\Server $server) {
+
+ $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
+
+ $server->protectedProperties[] = self::ID_PROPERTYNAME;
+
+ $server->on('propFind', array($this, 'handleGetProperties'));
+ $server->on('propPatch', array($this, 'handleUpdateProperties'));
+ $server->on('method:POST', [$this, 'httpPost']);
+
+ $this->server = $server;
+ }
+
+ /**
+ * POST operation on system tag collections
+ *
+ * @param RequestInterface $request request object
+ * @param ResponseInterface $response response object
+ * @return null|false
+ */
+ public function httpPost(RequestInterface $request, ResponseInterface $response) {
+ $path = $request->getPath();
+
+ // Making sure the node exists
+ $node = $this->server->tree->getNodeForPath($path);
+ if ($node instanceof SystemTagsByIdCollection || $node instanceof SystemTagsObjectMappingCollection) {
+ $data = $request->getBodyAsString();
+
+ $tag = $this->createTag($data, $request->getHeader('Content-Type'));
+
+ if ($node instanceof SystemTagsObjectMappingCollection) {
+ // also add to collection
+ $node->createFile($tag->getId());
+ $url = $request->getBaseUrl() . 'systemtags/';
+ } else {
+ $url = $request->getUrl();
+ }
+
+ if ($url[strlen($url) - 1] !== '/') {
+ $url .= '/';
+ }
+
+ $response->setHeader('Content-Location', $url . $tag->getId());
+
+ // created
+ $response->setStatus(201);
+ return false;
+ }
+ }
+
+ /**
+ * Creates a new tag
+ *
+ * @param string $data JSON encoded string containing the properties of the tag to create
+ * @param string $contentType content type of the data
+ * @return ISystemTag newly created system tag
+ *
+ * @throws BadRequest if a field was missing
+ * @throws Conflict if a tag with the same properties already exists
+ * @throws UnsupportedMediaType if the content type is not supported
+ */
+ private function createTag($data, $contentType = 'application/json') {
+ if (explode(';', $contentType)[0] === 'application/json') {
+ $data = json_decode($data, true);
+ } else {
+ throw new UnsupportedMediaType();
+ }
+
+ if (!isset($data['name'])) {
+ throw new BadRequest('Missing "name" attribute');
+ }
+
+ $tagName = $data['name'];
+ $userVisible = true;
+ $userAssignable = true;
+
+ if (isset($data['userVisible'])) {
+ $userVisible = (bool)$data['userVisible'];
+ }
+
+ if (isset($data['userAssignable'])) {
+ $userAssignable = (bool)$data['userAssignable'];
+ }
+ try {
+ return $this->tagManager->createTag($tagName, $userVisible, $userAssignable);
+ } catch (TagAlreadyExistsException $e) {
+ throw new Conflict('Tag already exists', 0, $e);
+ }
+ }
+
+
+ /**
+ * Retrieves system tag properties
+ *
+ * @param PropFind $propFind
+ * @param \Sabre\DAV\INode $node
+ */
+ public function handleGetProperties(
+ PropFind $propFind,
+ \Sabre\DAV\INode $node
+ ) {
+ if (!($node instanceof SystemTagNode)) {
+ return;
+ }
+
+ $propFind->handle(self::ID_PROPERTYNAME, function() use ($node) {
+ return $node->getSystemTag()->getId();
+ });
+
+ $propFind->handle(self::DISPLAYNAME_PROPERTYNAME, function() use ($node) {
+ return $node->getSystemTag()->getName();
+ });
+
+ $propFind->handle(self::USERVISIBLE_PROPERTYNAME, function() use ($node) {
+ return $node->getSystemTag()->isUserVisible() ? 'true' : 'false';
+ });
+
+ $propFind->handle(self::USERASSIGNABLE_PROPERTYNAME, function() use ($node) {
+ return $node->getSystemTag()->isUserAssignable() ? 'true' : 'false';
+ });
+ }
+
+ /**
+ * Updates tag attributes
+ *
+ * @param string $path
+ * @param PropPatch $propPatch
+ *
+ * @return void
+ */
+ public function handleUpdateProperties($path, PropPatch $propPatch) {
+ $propPatch->handle([
+ self::DISPLAYNAME_PROPERTYNAME,
+ self::USERVISIBLE_PROPERTYNAME,
+ self::USERASSIGNABLE_PROPERTYNAME,
+ ], function($props) use ($path) {
+ $node = $this->server->tree->getNodeForPath($path);
+ if (!($node instanceof SystemTagNode)) {
+ return;
+ }
+
+ $tag = $node->getSystemTag();
+ $name = $tag->getName();
+ $userVisible = $tag->isUserVisible();
+ $userAssignable = $tag->isUserAssignable();
+
+ if (isset($props[self::DISPLAYNAME_PROPERTYNAME])) {
+ $name = $props[self::DISPLAYNAME_PROPERTYNAME];
+ }
+
+ if (isset($props[self::USERVISIBLE_PROPERTYNAME])) {
+ $propValue = $props[self::USERVISIBLE_PROPERTYNAME];
+ $userVisible = ($propValue !== 'false' && $propValue !== '0');
+ }
+
+ if (isset($props[self::USERASSIGNABLE_PROPERTYNAME])) {
+ $propValue = $props[self::USERASSIGNABLE_PROPERTYNAME];
+ $userAssignable = ($propValue !== 'false' && $propValue !== '0');
+ }
+
+ $node->update($name, $userVisible, $userAssignable);
+ return true;
+ });
+ }
+}
diff --git a/apps/dav/lib/systemtag/systemtagsbyidcollection.php b/apps/dav/lib/systemtag/systemtagsbyidcollection.php
new file mode 100644
index 00000000000..52d4a143b41
--- /dev/null
+++ b/apps/dav/lib/systemtag/systemtagsbyidcollection.php
@@ -0,0 +1,177 @@
+<?php
+/**
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\SystemTag;
+
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Exception\BadRequest;
+use Sabre\DAV\ICollection;
+
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ISystemTag;
+use OCP\SystemTag\TagNotFoundException;
+use OCP\IGroupManager;
+use OCP\IUserSession;
+
+class SystemTagsByIdCollection implements ICollection {
+
+ /**
+ * @var ISystemTagManager
+ */
+ private $tagManager;
+
+ /**
+ * @var IGroupManager
+ */
+ private $groupManager;
+
+ /**
+ * @var IUserSession
+ */
+ private $userSession;
+
+ /**
+ * SystemTagsByIdCollection constructor.
+ *
+ * @param ISystemTagManager $tagManager
+ * @param IUserSession $userSession
+ * @param IGroupManager $groupManager
+ */
+ public function __construct(
+ ISystemTagManager $tagManager,
+ IUserSession $userSession,
+ IGroupManager $groupManager
+ ) {
+ $this->tagManager = $tagManager;
+ $this->userSession = $userSession;
+ $this->groupManager = $groupManager;
+ }
+
+ /**
+ * Returns whether the currently logged in user is an administrator
+ */
+ private function isAdmin() {
+ $user = $this->userSession->getUser();
+ if ($user !== null) {
+ return $this->groupManager->isAdmin($user->getUID());
+ }
+ return false;
+ }
+
+ /**
+ * @param string $name
+ * @param resource|string $data Initial payload
+ * @throws Forbidden
+ */
+ function createFile($name, $data = null) {
+ throw new Forbidden('Cannot create tags by id');
+ }
+
+ /**
+ * @param string $name
+ */
+ function createDirectory($name) {
+ throw new Forbidden('Permission denied to create collections');
+ }
+
+ /**
+ * @param string $name
+ */
+ function getChild($name) {
+ try {
+ $tag = $this->tagManager->getTagsByIds([$name]);
+ $tag = current($tag);
+ if (!$this->isAdmin() && !$tag->isUserVisible()) {
+ throw new NotFound('Tag with id ' . $name . ' not found');
+ }
+ return $this->makeNode($tag);
+ } catch (\InvalidArgumentException $e) {
+ throw new BadRequest('Invalid tag id', 0, $e);
+ } catch (TagNotFoundException $e) {
+ throw new NotFound('Tag with id ' . $name . ' not found', 0, $e);
+ }
+ }
+
+ function getChildren() {
+ $visibilityFilter = true;
+ if ($this->isAdmin()) {
+ $visibilityFilter = null;
+ }
+
+ $tags = $this->tagManager->getAllTags($visibilityFilter);
+ return array_map(function($tag) {
+ return $this->makeNode($tag);
+ }, $tags);
+ }
+
+ /**
+ * @param string $name
+ */
+ function childExists($name) {
+ try {
+ $tag = $this->tagManager->getTagsByIds([$name]);
+ $tag = current($tag);
+ if (!$this->isAdmin() && !$tag->isUserVisible()) {
+ return false;
+ }
+ return true;
+ } catch (\InvalidArgumentException $e) {
+ throw new BadRequest('Invalid tag id', 0, $e);
+ } catch (TagNotFoundException $e) {
+ return false;
+ }
+ }
+
+ function delete() {
+ throw new Forbidden('Permission denied to delete this collection');
+ }
+
+ function getName() {
+ return 'systemtags';
+ }
+
+ function setName($name) {
+ throw new Forbidden('Permission denied to rename this collection');
+ }
+
+ /**
+ * Returns the last modification time, as a unix timestamp
+ *
+ * @return int
+ */
+ function getLastModified() {
+ return null;
+ }
+
+ /**
+ * Create a sabre node for the given system tag
+ *
+ * @param ISystemTag $tag
+ *
+ * @return SystemTagNode
+ */
+ private function makeNode(ISystemTag $tag) {
+ return new SystemTagNode($tag, $this->isAdmin(), $this->tagManager);
+ }
+}
diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php
new file mode 100644
index 00000000000..eb75ed06393
--- /dev/null
+++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php
@@ -0,0 +1,201 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\SystemTag;
+
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Exception\BadRequest;
+use Sabre\DAV\Exception\PreconditionFailed;
+use Sabre\DAV\ICollection;
+
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ISystemTagObjectMapper;
+use OCP\SystemTag\ISystemTag;
+use OCP\SystemTag\TagNotFoundException;
+
+/**
+ * Collection containing tags by object id
+ */
+class SystemTagsObjectMappingCollection implements ICollection {
+
+ /**
+ * @var string
+ */
+ private $objectId;
+
+ /**
+ * @var string
+ */
+ private $objectType;
+
+ /**
+ * @var ISystemTagManager
+ */
+ private $tagManager;
+
+ /**
+ * @var ISystemTagObjectMapper
+ */
+ private $tagMapper;
+
+ /**
+ * Whether to return results only visible for admins
+ *
+ * @var bool
+ */
+ private $isAdmin;
+
+
+ /**
+ * Constructor
+ *
+ * @param string $objectId object id
+ * @param string $objectType object type
+ * @param bool $isAdmin whether to return results visible only for admins
+ * @param ISystemTagManager $tagManager
+ * @param ISystemTagObjectMapper $tagMapper
+ */
+ public function __construct($objectId, $objectType, $isAdmin, $tagManager, $tagMapper) {
+ $this->tagManager = $tagManager;
+ $this->tagMapper = $tagMapper;
+ $this->objectId = $objectId;
+ $this->objectType = $objectType;
+ $this->isAdmin = $isAdmin;
+ }
+
+ function createFile($tagId, $data = null) {
+ try {
+ if (!$this->isAdmin) {
+ $tag = $this->tagManager->getTagsByIds($tagId);
+ $tag = current($tag);
+ if (!$tag->isUserVisible()) {
+ throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
+ }
+ if (!$tag->isUserAssignable()) {
+ throw new Forbidden('No permission to assign tag ' . $tag->getId());
+ }
+ }
+ $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId);
+ } catch (TagNotFoundException $e) {
+ throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
+ }
+ }
+
+ function createDirectory($name) {
+ throw new Forbidden('Permission denied to create collections');
+ }
+
+ function getChild($tagId) {
+ try {
+ if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) {
+ $tag = $this->tagManager->getTagsByIds([$tagId]);
+ $tag = current($tag);
+ if ($this->isAdmin || $tag->isUserVisible()) {
+ return $this->makeNode($tag);
+ }
+ }
+ throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId);
+ } catch (\InvalidArgumentException $e) {
+ throw new BadRequest('Invalid tag id', 0, $e);
+ } catch (TagNotFoundException $e) {
+ throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e);
+ }
+ }
+
+ function getChildren() {
+ $tagIds = current($this->tagMapper->getTagIdsForObjects([$this->objectId], $this->objectType));
+ if (empty($tagIds)) {
+ return [];
+ }
+ $tags = $this->tagManager->getTagsByIds($tagIds);
+ if (!$this->isAdmin) {
+ // filter out non-visible tags
+ $tags = array_filter($tags, function($tag) {
+ return $tag->isUserVisible();
+ });
+ }
+ return array_values(array_map(function($tag) {
+ return $this->makeNode($tag);
+ }, $tags));
+ }
+
+ function childExists($tagId) {
+ try {
+ $result = ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true));
+ if ($this->isAdmin || !$result) {
+ return $result;
+ }
+
+ // verify if user is allowed to see this tag
+ $tag = $this->tagManager->getTagsByIds($tagId);
+ $tag = current($tag);
+ if (!$tag->isUserVisible()) {
+ return false;
+ }
+ return true;
+ } catch (\InvalidArgumentException $e) {
+ throw new BadRequest('Invalid tag id', 0, $e);
+ } catch (TagNotFoundException $e) {
+ return false;
+ }
+ }
+
+ function delete() {
+ throw new Forbidden('Permission denied to delete this collection');
+ }
+
+ function getName() {
+ return $this->objectId;
+ }
+
+ function setName($name) {
+ throw new Forbidden('Permission denied to rename this collection');
+ }
+
+ /**
+ * Returns the last modification time, as a unix timestamp
+ *
+ * @return int
+ */
+ function getLastModified() {
+ return null;
+ }
+
+ /**
+ * Create a sabre node for the mapping of the
+ * given system tag to the collection's object
+ *
+ * @param ISystemTag $tag
+ *
+ * @return SystemTagNode
+ */
+ private function makeNode(ISystemTag $tag) {
+ return new SystemTagMappingNode(
+ $tag,
+ $this->objectId,
+ $this->objectType,
+ $this->isAdmin,
+ $this->tagManager,
+ $this->tagMapper
+ );
+ }
+}
diff --git a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php
new file mode 100644
index 00000000000..93cc7561928
--- /dev/null
+++ b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\SystemTag;
+
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\MethodNotAllowed;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\ICollection;
+
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ISystemTagObjectMapper;
+use OCP\IUserSession;
+use OCP\IGroupManager;
+use OCP\Files\IRootFolder;
+
+/**
+ * Collection containing object ids by object type
+ */
+class SystemTagsObjectTypeCollection implements ICollection {
+
+ /**
+ * @var string
+ */
+ private $objectType;
+
+ /**
+ * @var ISystemTagManager
+ */
+ private $tagManager;
+
+ /**
+ * @var ISystemTagObjectMapper
+ */
+ private $tagMapper;
+
+ /**
+ * @var IGroupManager
+ */
+ private $groupManager;
+
+ /**
+ * @var IUserSession
+ */
+ private $userSession;
+
+ /**
+ * @var IRootFolder
+ **/
+ protected $fileRoot;
+
+ /**
+ * Constructor
+ *
+ * @param string $objectType object type
+ * @param ISystemTagManager $tagManager
+ * @param ISystemTagObjectMapper $tagMapper
+ * @param IUserSession $userSession
+ * @param IGroupManager $groupManager
+ * @param IRootFolder $fileRoot
+ */
+ public function __construct(
+ $objectType,
+ ISystemTagManager $tagManager,
+ ISystemTagObjectMapper $tagMapper,
+ IUserSession $userSession,
+ IGroupManager $groupManager,
+ IRootFolder $fileRoot
+ ) {
+ $this->tagManager = $tagManager;
+ $this->tagMapper = $tagMapper;
+ $this->objectType = $objectType;
+ $this->userSession = $userSession;
+ $this->groupManager = $groupManager;
+ $this->fileRoot = $fileRoot;
+ }
+
+ /**
+ * Returns whether the currently logged in user is an administrator
+ */
+ private function isAdmin() {
+ $user = $this->userSession->getUser();
+ if ($user !== null) {
+ return $this->groupManager->isAdmin($user->getUID());
+ }
+ return false;
+ }
+
+ /**
+ * @param string $name
+ * @param resource|string $data Initial payload
+ * @throws Forbidden
+ */
+ function createFile($name, $data = null) {
+ throw new Forbidden('Permission denied to create nodes');
+ }
+
+ /**
+ * @param string $name
+ */
+ function createDirectory($name) {
+ throw new Forbidden('Permission denied to create collections');
+ }
+
+ /**
+ * @param string $objectId
+ */
+ function getChild($objectId) {
+ // make sure the object exists and is reachable
+ if(!$this->childExists($objectId)) {
+ throw new NotFound('Entity does not exist or is not available');
+ }
+ return new SystemTagsObjectMappingCollection(
+ $objectId,
+ $this->objectType,
+ $this->isAdmin(),
+ $this->tagManager,
+ $this->tagMapper
+ );
+ }
+
+ function getChildren() {
+ // do not list object ids
+ throw new MethodNotAllowed();
+ }
+
+ /**
+ * @param string $name
+ */
+ function childExists($name) {
+ // TODO: make this more abstract
+ if ($this->objectType === 'files') {
+ // make sure the object is reachable for the current user
+ $userId = $this->userSession->getUser()->getUID();
+ $nodes = $this->fileRoot->getUserFolder($userId)->getById(intval($name));
+ return !empty($nodes);
+ }
+ return true;
+ }
+
+ function delete() {
+ throw new Forbidden('Permission denied to delete this collection');
+ }
+
+ function getName() {
+ return $this->objectType;
+ }
+
+ /**
+ * @param string $name
+ */
+ function setName($name) {
+ throw new Forbidden('Permission denied to rename this collection');
+ }
+
+ /**
+ * Returns the last modification time, as a unix timestamp
+ *
+ * @return int
+ */
+ function getLastModified() {
+ return null;
+ }
+}
diff --git a/apps/dav/lib/systemtag/systemtagsrelationscollection.php b/apps/dav/lib/systemtag/systemtagsrelationscollection.php
new file mode 100644
index 00000000000..6af4edfc1ab
--- /dev/null
+++ b/apps/dav/lib/systemtag/systemtagsrelationscollection.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\SystemTag;
+
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ISystemTagObjectMapper;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\SimpleCollection;
+use OCP\IUserSession;
+use OCP\IGroupManager;
+use OCP\Files\IRootFolder;
+
+class SystemTagsRelationsCollection extends SimpleCollection {
+
+ /**
+ * SystemTagsRelationsCollection constructor.
+ *
+ * @param ISystemTagManager $tagManager
+ * @param ISystemTagObjectMapper $tagMapper
+ * @param IUserSession $userSession
+ * @param IGroupManager $groupManager
+ * @param IRootFolder $fileRoot
+ */
+ public function __construct(
+ ISystemTagManager $tagManager,
+ ISystemTagObjectMapper $tagMapper,
+ IUserSession $userSession,
+ IGroupManager $groupManager,
+ IRootFolder $fileRoot
+ ) {
+ $children = [
+ new SystemTagsObjectTypeCollection(
+ 'files',
+ $tagManager,
+ $tagMapper,
+ $userSession,
+ $groupManager,
+ $fileRoot
+ ),
+ ];
+
+ parent::__construct('root', $children);
+ }
+
+ function getName() {
+ return 'systemtags-relations';
+ }
+
+ function setName($name) {
+ throw new Forbidden('Permission denied to rename this collection');
+ }
+
+}
diff --git a/apps/dav/tests/misc/sharing.xml b/apps/dav/tests/misc/sharing.xml
new file mode 100644
index 00000000000..8771256ce79
--- /dev/null
+++ b/apps/dav/tests/misc/sharing.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" ?>
+ <CS:share xmlns:D="DAV:" xmlns:CS="urn:ietf:params:xml:ns:carddav">
+ <CS:set>
+ <D:href>principal:principals/admin</D:href>
+ <CS:read-write />
+ </CS:set>
+ </CS:share>
diff --git a/apps/dav/tests/travis/carddavtester.sh b/apps/dav/tests/travis/caldav/install.sh
index a128872f42a..9688ec660de 100644
--- a/apps/dav/tests/travis/carddavtester.sh
+++ b/apps/dav/tests/travis/caldav/install.sh
@@ -3,10 +3,6 @@ SCRIPT=`realpath $0`
SCRIPTPATH=`dirname $SCRIPT`
-# start the server
-php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../.." &
-
-
if [ ! -f CalDAVTester/run.py ]; then
cd "$SCRIPTPATH"
git clone https://github.com/DeepDiver1975/CalDAVTester.git
@@ -16,13 +12,10 @@ if [ ! -f CalDAVTester/run.py ]; then
fi
# create test user
-cd "$SCRIPTPATH/../../../../"
+cd "$SCRIPTPATH/../../../../../"
OC_PASS=user01 php occ user:add --password-from-env user01
+php occ dav:create-calendar user01 calendar
+php occ dav:create-calendar user01 shared
OC_PASS=user02 php occ user:add --password-from-env user02
-cd "$SCRIPTPATH/../../../../"
-
-# run the tests
-cd "$SCRIPTPATH/CalDAVTester"
-PYTHONPATH="$SCRIPTPATH/pycalendar/src" python testcaldav.py --print-details-onfail -s "$SCRIPTPATH/caldavtest/config/serverinfo.xml" -o cdt.txt \
- "$SCRIPTPATH/caldavtest/tests/CardDAV/current-user-principal.xml"
-
+php occ dav:create-calendar user02 calendar
+cd "$SCRIPTPATH/../../../../../"
diff --git a/apps/dav/tests/travis/caldav/script.sh b/apps/dav/tests/travis/caldav/script.sh
new file mode 100644
index 00000000000..aa5fc732922
--- /dev/null
+++ b/apps/dav/tests/travis/caldav/script.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+SCRIPT=`realpath $0`
+SCRIPTPATH=`dirname $SCRIPT`
+
+# start the server
+php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../../.." &
+
+sleep 30
+
+# run the tests
+cd "$SCRIPTPATH/CalDAVTester"
+PYTHONPATH="$SCRIPTPATH/pycalendar/src" python testcaldav.py --print-details-onfail --basedir "$SCRIPTPATH/../caldavtest/" -o cdt.txt \
+ "CalDAV/sharing-calendars.xml"
+
+RESULT=$?
+
+tail "$/../../../../../data-autotest/owncloud.log"
+
+exit $RESULT
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/current-user-principal/1.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/current-user-principal/1.xml
new file mode 100644
index 00000000000..77a67c110df
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/current-user-principal/1.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propfind xmlns:D="DAV:">
+ <D:prop>
+ <D:current-user-principal/>
+ </D:prop>
+</D:propfind>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/1.txt b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/1.txt
new file mode 100644
index 00000000000..2d0a3641ac4
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/1.txt
@@ -0,0 +1,32 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Eastern
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20051222T205953Z
+CREATED:20060101T150000Z
+DTSTART;TZID=US/Eastern:$now.year.1:0101T100000
+DURATION:PT1H
+SUMMARY:event 1
+UID:54E181BC7CCC373042B28842@ninevah.local
+CATEGORIES:cool
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/1.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/1.xml
new file mode 100644
index 00000000000..676679bdd85
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/1.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:mkcol xmlns:D="DAV:"
+ xmlns:E="urn:ietf:params:xml:ns:caldav">
+ <D:set>
+ <D:prop>
+ <D:resourcetype>
+ <D:collection/>
+ <E:calendar/>
+ </D:resourcetype>
+ <D:displayname>Special Resource</D:displayname>
+ </D:prop>
+ </D:set>
+</D:mkcol>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/2.txt b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/2.txt
new file mode 100644
index 00000000000..67de0524ec3
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/2.txt
@@ -0,0 +1,33 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Mountain
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:MDT
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0600
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:MST
+TZOFFSETFROM:-0600
+TZOFFSETTO:-0700
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20051222T210052Z
+CREATED:20060101T160000Z
+DTSTART;TZID=US/Mountain:$now.year.1:0101T110000
+DURATION:PT1H
+SUMMARY:event 2
+DESCRIPTION:Some notes
+UID:9A6519F71822CD45840C3440@ninevah.local
+CATEGORIES:cool,hot
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/3.txt b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/3.txt
new file mode 100644
index 00000000000..bfdc0dbd116
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/3.txt
@@ -0,0 +1,34 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20051222T210146Z
+CREATED:20060101T210000Z
+DTSTART;TZID=US/Pacific:$now.year.1:0101T130000
+DURATION:PT1H
+LAST-MODIFIED:20051222T210203Z
+SEQUENCE:1
+SUMMARY:event 3
+UID:DB3F97EF10A051730E2F752E@ninevah.local
+CATEGORIES:hot
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/4.txt b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/4.txt
new file mode 100644
index 00000000000..be223854641
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/4.txt
@@ -0,0 +1,39 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Eastern
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20051222T210310Z
+CREATED:20060101T230000Z
+DTSTART;TZID=US/Eastern:$now.year.1:0101T180000
+DURATION:PT1H
+SUMMARY:event 4
+UID:A3217B429B4D2FF2DC2EEE66@ninevah.local
+CATEGORIES:cool
+CATEGORIES:hot
+BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT1H
+REPEAT:5
+DURATION:PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/5.txt b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/5.txt
new file mode 100644
index 00000000000..e1d701e2698
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/5.txt
@@ -0,0 +1,38 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Eastern
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20051222T210412Z
+CREATED:20060102T150000Z
+DTSTART;TZID=US/Eastern:$now.year.1:0102T100000
+DURATION:PT1H
+RRULE:FREQ=DAILY;COUNT=5
+SUMMARY:event 5
+UID:945113826375CBB89184DC36@ninevah.local
+CATEGORIES:cool,hot
+CATEGORIES:warm
+BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/6.txt b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/6.txt
new file mode 100644
index 00000000000..ecabe13a707
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/put/6.txt
@@ -0,0 +1,48 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Eastern
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20051222T210507Z
+CREATED:20060102T190000Z
+DTSTART;TZID=US/Eastern:$now.year.1:0102T140000
+DURATION:PT1H
+RRULE:FREQ=DAILY;COUNT=5
+SUMMARY:event 6
+UID:F5B811E00073B22BA6B87551@ninevah.local
+CATEGORIES:warm,hot
+CATEGORIES:cool
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20051222T210507Z
+UID:F5B811E00073B22BA6B87551@ninevah.local
+RECURRENCE-ID;TZID=US/Eastern:$now.year.1:0104T140000
+CREATED:20060102T190000Z
+DTSTART;TZID=US/Eastern:$now.year.1:0104T160000
+DURATION:PT1H
+SUMMARY:event 6 changed
+DESCRIPTION:Some notes
+BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/1.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/1.xml
new file mode 100644
index 00000000000..4c54b88fd0c
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/1.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propfind xmlns:D="DAV:">
+ <D:prop>
+ <D:supported-report-set/>
+ <D:sync-token/>
+ </D:prop>
+</D:propfind>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/10.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/10.xml
new file mode 100644
index 00000000000..b20b6d645a5
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/10.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token/>
+<D:sync-level>bogus</D:sync-level>
+<D:prop/>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/11.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/11.xml
new file mode 100644
index 00000000000..c7706328d5a
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/11.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token>null</D:sync-token>
+<D:prop>
+<D:getetag/>
+</D:prop>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/2.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/2.xml
new file mode 100644
index 00000000000..99ee3dbb0e0
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/2.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token/>
+<D:prop/>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/21.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/21.xml
new file mode 100644
index 00000000000..7a851c80c9a
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/21.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token/>
+<D:sync-level>0</D:sync-level>
+<D:limit><D:nresults>10</D:nresults></D:limit>
+<D:prop/>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/3.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/3.xml
new file mode 100644
index 00000000000..9cb886b8133
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/3.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token>$synctoken1:</D:sync-token>
+<D:prop/>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/4.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/4.xml
new file mode 100644
index 00000000000..e0d0baf4a7f
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/4.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token>$synctoken2:</D:sync-token>
+<D:prop/>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/5.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/5.xml
new file mode 100644
index 00000000000..4469bb434fc
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/5.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token/>
+<D:prop>
+<D:getcontenttype/>
+<D:getetag/>
+</D:prop>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/6.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/6.xml
new file mode 100644
index 00000000000..05b7198eb6e
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/6.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token>$synctoken1:</D:sync-token>
+<D:prop>
+<D:getcontenttype/>
+<D:getetag/>
+</D:prop>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/7.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/7.xml
new file mode 100644
index 00000000000..575b2f673d7
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/7.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token>$synctoken2:</D:sync-token>
+<D:prop>
+<D:getcontenttype/>
+<D:getetag/>
+</D:prop>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/8.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/8.xml
new file mode 100644
index 00000000000..6badc4143cf
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/reports/sync/8.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token/>
+<D:sync-level>1</D:sync-level>
+<D:prop/>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/1.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/1.xml
new file mode 100644
index 00000000000..3bcf9dc47f9
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/1.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<CS:share xmlns:D="DAV:" xmlns:CS="http://owncloud.org/ns">
+ <CS:set>
+ <D:href>principal:principals/users/user02</D:href>
+ <CS:summary>My Shared Calendar</CS:summary>
+ <CS:read-write/>
+ </CS:set>
+</CS:share>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/4.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/4.xml
new file mode 100644
index 00000000000..fd0f248bb31
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/4.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propfind xmlns:D="DAV:">
+<D:prop>
+<D:resourcetype/>
+<D:owner/>
+<D:current-user-privilege-set/>
+</D:prop>
+</D:propfind>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.ics
new file mode 100644
index 00000000000..ae21adac8b2
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.ics
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+LAST-MODIFIED:20040110T032845Z
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:$uid1:
+DTSTART;TZID=US/Eastern:$now.year.1:0101T100000
+DURATION:PT1H
+DTSTAMP:20051222T205953Z
+SUMMARY:event 1
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.xml
new file mode 100644
index 00000000000..4862ed195f8
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propfind xmlns:D="DAV:" xmlns:CS="http://owncloud.org/ns">
+<D:prop>
+<CS:invite/>
+</D:prop>
+</D:propfind>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/6.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/6.ics
new file mode 100644
index 00000000000..145f5f14c7b
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/6.ics
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+LAST-MODIFIED:20040110T032845Z
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:$uid1:
+DTSTART;TZID=US/Eastern:$now.year.1:0101T100000
+DURATION:PT4H
+DTSTAMP:20051222T205953Z
+SUMMARY:event 4
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/7.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/7.ics
new file mode 100644
index 00000000000..c4e816210df
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/7.ics
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+LAST-MODIFIED:20040110T032845Z
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:$uid2:
+DTSTART;TZID=US/Eastern:$now.year.1:0201T100000
+DURATION:PT1H
+DTSTAMP:20051222T205953Z
+SUMMARY:event 7
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/8.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/8.ics
new file mode 100644
index 00000000000..2da72d2f601
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/8.ics
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+LAST-MODIFIED:20040110T032845Z
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:$uid2:
+DTSTART;TZID=US/Eastern:$now.year.1:0201T100000
+DURATION:PT7H
+DTSTAMP:20051222T205953Z
+SUMMARY:event 7-1
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/9.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/9.ics
new file mode 100644
index 00000000000..dfc21bb9c5b
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/9.ics
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+LAST-MODIFIED:20040110T032845Z
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:$uid3:
+DTSTART;TZID=US/Eastern:$now.year.1:0201T100000
+DURATION:PT7H
+DTSTAMP:20051222T205953Z
+SUMMARY:event 9.ics
+END:VEVENT
+END:VCALENDAR
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/1.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/1.xml
new file mode 100644
index 00000000000..20d2ebf4cfc
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/1.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<CS:share xmlns:D="DAV:" xmlns:CS="http://owncloud.org/ns">
+ <CS:set>
+ <D:href>principal:principals/users/user02</D:href>
+ <CS:summary>My Shared Calendar</CS:summary>
+ <CS:read-write/>
+ </CS:set>
+</CS:share>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/4.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/4.xml
new file mode 100644
index 00000000000..fd0f248bb31
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/4.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propfind xmlns:D="DAV:">
+<D:prop>
+<D:resourcetype/>
+<D:owner/>
+<D:current-user-privilege-set/>
+</D:prop>
+</D:propfind>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/6.vcf b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/6.vcf
new file mode 100644
index 00000000000..6b53f8ba3bf
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/6.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;TYPE=INTERNET,WORK,pref:lthompson@example.com
+TEL;TYPE=WORK,pref:1-555-555-5555
+TEL;TYPE=CELL:1-555-555-5555
+ITEM1.ADR;TYPE=WORK,pref:;;2 Lag;Elk Forest;California;99999;USA
+ITEM1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
+END:VCARD
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/7.vcf b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/7.vcf
new file mode 100644
index 00000000000..27fdb9fae5f
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/7.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;TYPE=INTERNET,WORK,pref:lthompson@example.net
+TEL;TYPE=WORK,pref:1-555-555-5555
+TEL;TYPE=CELL:1-555-555-6666
+ITEM1.ADR;TYPE=WORK,pref:;;2 Lag;Elk Forest;California;99999;USA
+ITEM1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
+END:VCARD
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/8.vcf b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/8.vcf
new file mode 100644
index 00000000000..9188fdd913c
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/8.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Miller;Default;;;
+FN:Default Miller
+EMAIL;TYPE=INTERNET,WORK,pref:lthompson@example.com
+TEL;TYPE=WORK,pref:1-555-555-5555
+TEL;TYPE=CELL:1-555-555-5555
+ITEM1.ADR;TYPE=WORK,pref:;;2 Lag;Elk Forest;California;99999;USA
+ITEM1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
+END:VCARD
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/9.vcf b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/9.vcf
new file mode 100644
index 00000000000..1ca0a36ca4c
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/sharing/read-write/9.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Smith;Default;;;
+FN:Default Smith
+EMAIL;TYPE=INTERNET,WORK,pref:lthompson@example.com
+TEL;TYPE=WORK,pref:1-555-555-5555
+TEL;TYPE=CELL:1-555-555-5555
+ITEM1.ADR;TYPE=WORK,pref:;;2 Lag;Elk Forest;California;99999;USA
+ITEM1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
+END:VCARD
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vcurrent-user-principal/1.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vcurrent-user-principal/1.xml
new file mode 100644
index 00000000000..dffedc6880d
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vcurrent-user-principal/1.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propfind xmlns:D="DAV:">
+<D:prop>
+<D:current-user-principal/>
+</D:prop>
+</D:propfind>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/1.vcf b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/1.vcf
new file mode 100644
index 00000000000..2121c65f1f4
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/1.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson@example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-555-555-5555
+item1.ADR;type=WORK;type=pref:;;2 Lag;Elk Forest;California;99999;USA
+item1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
+END:VCARD
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/2.vcf b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/2.vcf
new file mode 100644
index 00000000000..390a3d8ae69
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/2.vcf
@@ -0,0 +1,17 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Contact;Mulberry;;;
+FN:Mulberry Contact
+NICKNAME:mulberry
+ORG:Apple Inc.;
+EMAIL;type=INTERNET;type=WORK;type=pref:mulberry_contact@example.com
+TEL;type=HOME;type=pref:555-555-5555
+TEL;type=WORK:555-555-5555
+TEL;type=WORK;type=FAX:555-555-5555
+item1.ADR;type=WORK;type=pref:;;1 Infinite Circle;Exampletino\, CA 99999;USA;;
+item1.X-ABADR:us
+NOTE:This is a contact created in Mulberry.
+item2.URL;type=pref:http://www.example.com/~magic
+item2.X-ABLabel:_$!<HomePage>!$_
+UID:782DAAF92CB1ED1BC155CDB3@D76FAF7B10D9E8D2D41F779D
+END:VCARD
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/3.vcf b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/3.vcf
new file mode 100644
index 00000000000..37c3b81bdcf
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/put/3.vcf
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Kawado;Saeko;;;
+FN:Snow Leopard
+ORG:Snow Leopard;
+EMAIL;type=INTERNET;type=WORK;type=pref:snowleopard_apple@example.com
+TEL;type=WORK;type=pref:555-555-5555
+item1.ADR;type=WORK;type=pref:;;2 Fidel Ave. Suite 1;Mountain Top;CA;99999;USA
+item1.X-ABADR:us
+X-ABShowAs:COMPANY
+UID:FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1:ABPerson
+END:VCARD
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/sync/1.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/sync/1.xml
new file mode 100644
index 00000000000..7f454b38900
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/sync/1.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propfind xmlns:D="DAV:">
+<D:prop>
+<D:supported-report-set/>
+<D:sync-token/>
+</D:prop>
+</D:propfind>
diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/sync/2.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/sync/2.xml
new file mode 100644
index 00000000000..99ee3dbb0e0
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/data/Resource/CardDAV/vreports/sync/2.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:sync-collection xmlns:D="DAV:">
+<D:sync-token/>
+<D:prop/>
+</D:sync-collection>
diff --git a/apps/dav/tests/travis/caldavtest/config/serverinfo.dtd b/apps/dav/tests/travis/caldavtest/serverinfo.dtd
index d642f4f90cd..d642f4f90cd 100644
--- a/apps/dav/tests/travis/caldavtest/config/serverinfo.dtd
+++ b/apps/dav/tests/travis/caldavtest/serverinfo.dtd
diff --git a/apps/dav/tests/travis/caldavtest/config/serverinfo.xml b/apps/dav/tests/travis/caldavtest/serverinfo.xml
index b85a8639e4e..c3ba99ee03d 100644
--- a/apps/dav/tests/travis/caldavtest/config/serverinfo.xml
+++ b/apps/dav/tests/travis/caldavtest/serverinfo.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE serverinfo SYSTEM
- "/home/deepdiver/Development/ownCloud/master/apps/dav/tests/travis/caldavtest/config/serverinfo.dtd">
+ "/home/deepdiver/Development/ownCloud/master/apps/dav/tests/travis/caldavtest/serverinfo.dtd">
<!--
Copyright (c) 2006-2015 Apple Inc. All rights reserved.
@@ -64,7 +64,7 @@
<feature>resource-id</feature> <!-- WebDAV BIND DAV:resource-id property -->
<feature>sync-report</feature> <!-- WebDAV collection sync REPORT -->
<!-- <feature>sync-report-limit</feature> --> <!-- WebDAV collection sync REPORT DAV:limit support -->
- <feature>sync-report-home</feature> <!-- WebDAV collection sync REPORT on Homes -->
+ <!--<feature>sync-report-home</feature> &lt;!&ndash; WebDAV collection sync REPORT on Homes &ndash;&gt;-->
<feature>sync-report-config-token</feature> <!-- Sync REPORT token includes configuration component -->
<feature>well-known</feature> <!-- well-known feature -->
@@ -482,7 +482,7 @@
</substitution>
<substitution>
<key>$principaluri%d:</key>
- <value>$principalcollection:$userid%d:/</value>
+ <value>$principals_users:$userid%d:/</value>
</substitution>
<substitution>
<key>$principal%dnoslash:</key>
@@ -492,7 +492,7 @@
<!-- relative path to user calendar home-->
<substitution>
<key>$calendarhome%d:</key>
- <value>$calendars_uids:$userguid%d:</value>
+ <value>$calendars:$userid%d:</value>
</substitution>
<!-- relative path to user alternate calendar home-->
<substitution>
@@ -569,7 +569,7 @@
<!-- relative path to user addressbook home-->
<substitution>
<key>$addressbookhome%d:</key>
- <value>$addressbooks_uids:$userguid%d:</value>
+ <value>$addressbooks:users/$userid%d:</value>
</substitution>
<!-- relative path to user addressbook-->
<substitution>
diff --git a/apps/dav/tests/travis/caldavtest/tests/CalDAV/current-user-principal.xml b/apps/dav/tests/travis/caldavtest/tests/CalDAV/current-user-principal.xml
new file mode 100644
index 00000000000..d01058fee0a
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/tests/CalDAV/current-user-principal.xml
@@ -0,0 +1,151 @@
+<?xml version="1.0" standalone="no"?>
+
+<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd">
+
+<!--
+ Copyright (c) 2006-2015 Apple Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<caldavtest>
+ <description>Test DAV:current-user-principal support</description>
+
+ <require-feature>
+ <feature>caldav</feature>
+ <feature>current-user-principal</feature>
+ </require-feature>
+
+ <start/>
+
+ <test-suite name='Check for the property on /'>
+ <require-feature>
+ <feature>own-root</feature>
+ </require-feature>
+ <test name='1'>
+ <description>Check for authenticated property on /</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$root:</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value><![CDATA[{DAV:}current-user-principal$<href xmlns="DAV:">$principaluri1:</href>]]></value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3'>
+ <description>Check for authenticated property on / (user02)</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$root:</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value><![CDATA[{DAV:}current-user-principal$<href xmlns="DAV:">$principaluri2:</href>]]></value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='Check for the property on /principals/'>
+ <test name='1'>
+ <description>Check for authenticated property on /</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$principalcollection:</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value><![CDATA[{DAV:}current-user-principal$<href xmlns="DAV:">$principaluri1:</href>]]></value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='2'>
+ <description>Check for unauthenticated property on /</description>
+ <request auth="no">
+ <method>PROPFIND</method>
+ <ruri>$principals_users:</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>401</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3'>
+ <description>Check for authenticated property on / (user02)</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$principalcollection:</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value><![CDATA[{DAV:}current-user-principal$<href xmlns="DAV:">$principaluri2:</href>]]></value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <end/>
+</caldavtest>
diff --git a/apps/dav/tests/travis/caldavtest/tests/CalDAV/sharing-calendars.xml b/apps/dav/tests/travis/caldavtest/tests/CalDAV/sharing-calendars.xml
new file mode 100644
index 00000000000..334fa561aec
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/tests/CalDAV/sharing-calendars.xml
@@ -0,0 +1,589 @@
+<?xml version="1.0" standalone="no"?>
+
+<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd">
+
+<!--
+ Copyright (c) 2006-2015 Apple Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<caldavtest>
+ <description>Test calendar sharing calendars</description>
+
+ <require-feature>
+ <feature>caldav</feature>
+ <feature>shared-calendars</feature>
+ </require-feature>
+
+ <start>
+ <!--
+ <request user="$userid1:" pswd="$pswd1:">
+ <method>DELETEALL</method>
+ <ruri>$notificationpath1:/</ruri>
+ </request>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>DELETEALL</method>
+ <ruri>$notificationpath2:/</ruri>
+ </request>
+ <request end-delete="yes">
+ <method>MKCALENDAR</method>
+ <ruri>$calendarhome1:/shared/</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>PROPPATCH</method>
+ <ruri>$calendarhome1:/shared/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/Common/PROPPATCH/calendar-transp-opaque.xml</filepath>
+ </data>
+ </request>
+ -->
+ </start>
+
+ <test-suite name='Read-write calendar'>
+ <test name='1'>
+ <description>POST invitation</description>
+ <request>
+ <method>POST</method>
+ <ruri>$calendarhome1:/shared/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>Shared calendar exists</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$calendarhome1:/shared/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:caldav}calendar</value>
+ <!-- value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value -->
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ <!-- value>$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}transparent</value -->
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4a'>
+ <description>Shared calendar exists Depth:1</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$calendarhome2:</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>parent</name>
+ <value>$multistatus-response-prefix:[^{DAV:}href=$calendarhome2:/shared_shared_by_user01/]</value>
+ </arg>
+ <arg>
+ <name>exists</name>
+ <value>$verify-response-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-response-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-response-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:caldav}calendar</value>
+ <!-- value>$verify-response-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value -->
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ <!-- value>$verify-response-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}transparent</value -->
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='5'>
+ <description>Original calendar unchanged</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$calendarhome1:/shared/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <!--<value>$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}opaque</value>-->
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='5a'>
+ <description>Invite propfind returns sharees</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$calendarhome1:/shared/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{http://owncloud.org/ns}invite/{http://owncloud.org/ns}user/{DAV:}href</value>
+ <value>$verify-property-prefix:/{http://owncloud.org/ns}invite/{http://owncloud.org/ns}user/{http://owncloud.org/ns}invite-accepted</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='6'>
+ <description>Sharee creates event</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PUT</method>
+ <ruri>$calendarhome1:/shared/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/5.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='7'>
+ <description>Sharer sees event</description>
+ <request>
+ <method>GET</method>
+ <ruri>$calendarhome1:/shared/1.ics</ruri>
+ <verify>
+ <callback>calendarDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CalDAV/sharing/calendars/read-write/5.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='8'>
+ <description>Sharer changes event</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/shared/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/6.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='9'>
+ <description>Sharee sees changed event</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>GET</method>
+ <ruri>$calendarhome1:/shared/1.ics</ruri>
+ <verify>
+ <callback>calendarDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CalDAV/sharing/calendars/read-write/6.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='10'>
+ <description>Sharer creates event</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/shared/2.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/7.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='11'>
+ <description>Sharee sees new event</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>GET</method>
+ <ruri>$calendarhome1:/shared/2.ics</ruri>
+ <verify>
+ <callback>calendarDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CalDAV/sharing/calendars/read-write/7.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='12'>
+ <description>Sharee changes event</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PUT</method>
+ <ruri>$calendarhome1:/shared/2.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/8.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='13'>
+ <description>Sharer sees changed event</description>
+ <request>
+ <method>GET</method>
+ <ruri>$calendarhome1:/shared/2.ics</ruri>
+ <verify>
+ <callback>calendarDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CalDAV/sharing/calendars/read-write/8.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='14'>
+ <description>Un-share by delete</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>DELETE</method>
+ <ruri>$calendarhome2:/shared_shared_by_user01/</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='15'>
+ <description>Original calendar still exists</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$calendarhome1:/shared/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:caldav}calendar</value>
+ <!-- value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value -->
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ <!-- value>$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}transparent</value -->
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='16'>
+ <description>Shared calendar no longer exists Depth:1</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$calendarhome2:</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>notexists</name>
+ <value>$multistatus-response-prefix:[^{DAV:}href=$calendarhome2:/shared_shared_by_user01/]</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <!--
+ <test-suite name='Default calendar cannot be shared calendar'>
+ <test name='1'>
+ <description>Set property on Inbox</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPPATCH</method>
+ <ruri>$inboxpath2:/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/defaultcalendar/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>badprops</name>
+ <value>{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='2'>
+ <description>Verify property on inbox</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$inboxpath2:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/defaultcalendar/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value><![CDATA[{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL$<href xmlns="DAV:">$calendarpath2:</href>]]></value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='Change to read-only calendar'>
+ <test name='1'>
+ <description>POST invitation</description>
+ <request>
+ <method>POST</method>
+ <ruri>$calendarhome1:/shared/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-only/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='2'>
+ <description>Check Sharee notification collection</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>WAITCOUNT 1</method>
+ <ruri>$notificationpath2:/</ruri>
+ </request>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>GETNEW</method>
+ <ruri>$notificationpath2:/</ruri>
+ <verify>
+ <callback>xmlDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CalDAV/sharing/calendars/read-only/2.xml</value>
+ </arg>
+ <arg>
+ <name>filter</name>
+ <value>{http://calendarserver.org/ns/}dtstamp</value>
+ <value>{http://calendarserver.org/ns/}uid</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>{http://calendarserver.org/ns/}invite-notification/{http://calendarserver.org/ns/}uid</name>
+ <variable>$inviteuid:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>Sharee replies ACCEPTED</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>POST</method>
+ <ruri>$calendarhome2:/</ruri>
+ <data>
+ <content-type>application/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-only/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ <grabelement>
+ <name>{DAV:}href</name>
+ <variable>$sharedcalendar:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='4'>
+ <description>Shared calendar exists</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$sharedcalendar:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-only/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='5'>
+ <description>Create event</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PUT</method>
+ <ruri>$sharedcalendar:/3.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-only/5.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>403</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='6'>
+ <description>Sharer creates event</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/shared/4.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-only/6.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='7'>
+ <description>Sharee sees new event</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>GET</method>
+ <ruri>$sharedcalendar:/4.ics</ruri>
+ <verify>
+ <callback>calendarDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CalDAV/sharing/calendars/read-only/6.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='8'>
+ <description>Sharee cannot change event</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PUT</method>
+ <ruri>$sharedcalendar:/4.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/sharing/calendars/read-only/7.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>403</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+-->
+
+ <end>
+ <!--
+ <request user="$useradmin:" pswd="$pswdadmin:">
+ <method>DELETEALL</method>
+ <ruri>$notificationpath1:/</ruri>
+ <ruri>$notificationpath2:/</ruri>
+ <ruri>$notificationpath3:/</ruri>
+ <ruri>$notificationpath4:/</ruri>
+ </request>
+ -->
+ </end>
+
+</caldavtest>
diff --git a/apps/dav/tests/travis/caldavtest/tests/CalDAV/sync-report.xml b/apps/dav/tests/travis/caldavtest/tests/CalDAV/sync-report.xml
new file mode 100644
index 00000000000..cf4fcde251f
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/tests/CalDAV/sync-report.xml
@@ -0,0 +1,3329 @@
+<?xml version="1.0" standalone="no"?>
+
+<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd">
+
+<!--
+ Copyright (c) 2006-2015 Apple Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<caldavtest>
+ <require-feature>
+ <feature>caldav</feature>
+ <feature>sync-report</feature>
+ </require-feature>
+
+ <start>
+ <request end-delete="yes">
+ <method>MKCOL</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <data>
+ <content-type>application/xml; charset="utf-8"</content-type>
+ <filepath>Resource/CalDAV/reports/put/1.xml</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar1/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/1.txt</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar1/2.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/2.txt</filepath>
+ </data>
+ </request>
+ <request end-delete="yes">
+ <method>MKCOL</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <data>
+ <content-type>application/xml; charset="utf-8"</content-type>
+ <filepath>Resource/CalDAV/reports/put/1.xml</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar2/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/4.txt</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar2/2.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/5.txt</filepath>
+ </data>
+ </request>
+ </start>
+
+ <test-suite name='support-report-set/sync-token property'>
+ <test name='1'>
+ <description>Not on calendars</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$calendars:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}supported-report-set/{DAV:}supported-report/{DAV:}report/{DAV:}sync-collection</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}supported-report-set</value>
+ </arg>
+ <arg>
+ <name>badprops</name>
+ <value>{DAV:}sync-token</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3'>
+ <description>On calendar</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}supported-report-set/{DAV:}supported-report/{DAV:}report/{DAV:}sync-collection</value>
+ <!--<value>$verify-property-prefix:/{DAV:}sync-token[+data:,]</value>-->
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}supported-report-set</value>
+ <value>{DAV:}sync-token</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - sync-level'>
+ <test name='1'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:1, depth:0</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar2/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='2'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:1, depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar2/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:1, depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar2/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:infinity, depth:0</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/9.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar1/1.ics</value>
+ <value>synccalendar1/2.ics</value>
+ <value>synccalendar2/</value>
+ <value>synccalendar2/1.ics</value>
+ <value>synccalendar2/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='5'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:infinity, depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/9.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar1/1.ics</value>
+ <value>synccalendar1/2.ics</value>
+ <value>synccalendar2/</value>
+ <value>synccalendar2/1.ics</value>
+ <value>synccalendar2/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='6'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:infinity, depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/9.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar1/1.ics</value>
+ <value>synccalendar1/2.ics</value>
+ <value>synccalendar2/</value>
+ <value>synccalendar2/1.ics</value>
+ <value>synccalendar2/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='7'>
+ <description>sync-level:1, depth:0</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='8'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:1, depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='9'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:1, depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='10'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:infinity, depth:0</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/9.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='11'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:infinity, depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/9.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='12'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>sync-level:infinity, depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/9.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - empty token - no props'>
+ <test name='1'>
+ <description>initial query - calendar collection depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='2'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>initial query - home depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar2/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>initial query - home depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar1/1.ics</value>
+ <value>synccalendar1/2.ics</value>
+ <value>synccalendar2/</value>
+ <value>synccalendar2/1.ics</value>
+ <value>synccalendar2/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>add new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar1/3.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/3.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='5'>
+ <description>new resource - calendar collection depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ <value>3.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='6'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>new resource - home depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar2/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='7'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>new resource - home depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar1/1.ics</value>
+ <value>synccalendar1/2.ics</value>
+ <value>synccalendar1/3.ics</value>
+ <value>synccalendar2/</value>
+ <value>synccalendar2/1.ics</value>
+ <value>synccalendar2/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='8'>
+ <description>remove new resource</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar1/3.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='9'>
+ <description>remove new resource - calendar collection depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='10'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>remove new resource - home depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar2/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='11'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>remove new resource - home depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar1/1.ics</value>
+ <value>synccalendar1/2.ics</value>
+ <value>synccalendar2/</value>
+ <value>synccalendar2/1.ics</value>
+ <value>synccalendar2/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='12'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar1/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/1.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='13'>
+ <description>changed resource - calendar collection depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='14'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>changed resource - home depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar2/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='15'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>changed resource - home depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar1/</value>
+ <value>synccalendar1/1.ics</value>
+ <value>synccalendar1/2.ics</value>
+ <value>synccalendar2/</value>
+ <value>synccalendar2/1.ics</value>
+ <value>synccalendar2/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - no props - calendar depth:1'>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar1/3.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/3.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>3.ics</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar1/3.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>3.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>3.ics</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='5'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar1/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/1.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - empty token - props'>
+ <test name='1'>
+ <description>initial query</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='2'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar2/3.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/6.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ <value>3.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3'>
+ <description>remove resource new resource</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar2/3.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar2/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/4.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - props'>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ <value>2.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar2/3.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/6.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>3.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar2/3.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>3.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/7.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>3.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='5'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar2/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/4.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - no props - home depth:infinity'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>Initialize</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ </request>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ </request>
+ <request end-delete="yes">
+ <method>MKCALENDAR</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar3/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/7.txt</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar3/2.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/8.txt</filepath>
+ </data>
+ </request>
+ <request end-delete="yes">
+ <method>MKCALENDAR</method>
+ <ruri>$calendarhome1:/synccalendar4/</ruri>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar4/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/10.txt</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar4/2.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/11.txt</filepath>
+ </data>
+ </request>
+ </test>
+ <test name='2'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar3/1.ics</value>
+ <value>synccalendar3/2.ics</value>
+ <value>synccalendar4/</value>
+ <value>synccalendar4/1.ics</value>
+ <value>synccalendar4/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar3/3.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/9.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ <value>synccalendar3/3.ics</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar3/3.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>synccalendar3/3.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='5'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>synccalendar3/3.ics</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar3/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/7.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ <value>synccalendar3/1.ics</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='7'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - props - home depth:infinity'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar3/1.ics</value>
+ <value>synccalendar3/2.ics</value>
+ <value>synccalendar4/</value>
+ <value>synccalendar4/1.ics</value>
+ <value>synccalendar4/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>ignore</name>
+ <value>$calendarhome1:/$outbox:/</value>
+ <value>$calendarhome1:/$freebusy:</value>
+ <value>$calendarhome1:/$notification:/</value>
+ <value>$calendarhome1:/$dropbox:/</value>
+ </arg>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar4/3.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/12.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar4/</value>
+ <value>synccalendar4/3.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar4/3.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar4/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>synccalendar4/3.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/7.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar4/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>synccalendar4/3.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>count</name>
+ <value>2</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='5'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar4/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/10.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar4/</value>
+ <value>synccalendar4/1.ics</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - delete/create calendar - home depth:infinity'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar3/1.ics</value>
+ <value>synccalendar3/2.ics</value>
+ <value>synccalendar4/</value>
+ <value>synccalendar4/1.ics</value>
+ <value>synccalendar4/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>remove resource then calendar</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar3/1.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>add calendar - test last sync</description>
+ <request>
+ <method>MKCALENDAR</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>add calendar - test previous sync</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - no props - home depth:1'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>Initialize</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar1/</ruri>
+ </request>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar2/</ruri>
+ </request>
+ <request end-delete="yes">
+ <method>MKCALENDAR</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar3/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/7.txt</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar3/2.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/8.txt</filepath>
+ </data>
+ </request>
+ <request end-delete="yes">
+ <method>MKCALENDAR</method>
+ <ruri>$calendarhome1:/synccalendar4/</ruri>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar4/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/10.txt</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar4/2.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/11.txt</filepath>
+ </data>
+ </request>
+ </test>
+ <test name='2'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar4/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar3/3.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/9.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar3/3.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='5'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/13.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar3/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/7.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='7'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - props - home depth:1'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/14.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar4/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>ignore</name>
+ <value>$calendarhome1:/$outbox:/</value>
+ <value>$calendarhome1:/$freebusy:</value>
+ <value>$calendarhome1:/$notification:/</value>
+ <value>$calendarhome1:/$dropbox:/</value>
+ </arg>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar4/3.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/12.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/15.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar4/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar4/3.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/15.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar4/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/16.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar4/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>count</name>
+ <value>1</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='5'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$calendarhome1:/synccalendar4/1.ics</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/put/10.txt</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/15.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar4/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/15.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - delete/create calendar - home depth:1'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar4/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>remove resource then calendar</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar3/1.ics</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELETE</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>add calendar - test last sync</description>
+ <request>
+ <method>MKCALENDAR</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/13.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>add calendar - test previous sync</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - valid token'>
+ <test name='1'>
+ <description>initial query</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/11.xml</filepath>
+ </data>
+ <verify>
+ <callback>prepostcondition</callback>
+ <arg>
+ <name>error</name>
+ <value>{DAV:}valid-sync-token</value>
+ </arg>
+ <arg>
+ <name>ignoreextras</name>
+ <value>{http://sabredav.org/ns}message</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='calendar webdav property change - home depth:infinity'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar4/</value>
+ <value>synccalendar4/1.ics</value>
+ <value>synccalendar4/2.ics</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>Change a property</description>
+ <request>
+ <method>PROPPATCH</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/17.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>/{DAV:}multistatus/{DAV:}sync-token[!$synctoken1:]</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>Remove a property</description>
+ <request>
+ <method>PROPPATCH</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/18.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>/{DAV:}multistatus/{DAV:}sync-token[!$synctoken1:]</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='calendar webdav property change - home depth:1'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar4/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>Change a property</description>
+ <request>
+ <method>PROPPATCH</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/17.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>/{DAV:}multistatus/{DAV:}sync-token[!$synctoken1:]</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>Remove a property</description>
+ <request>
+ <method>PROPPATCH</method>
+ <ruri>$calendarhome1:/synccalendar3/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/18.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>synccalendar3/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>/{DAV:}multistatus/{DAV:}sync-token[!$synctoken1:]</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+
+ <test-suite name='default calendar property change - home depth:1'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/8.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar4/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>Change property on Inbox</description>
+ <request>
+ <method>PROPPATCH</method>
+ <ruri>$inboxpath1:/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/19.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL</value>
+ </arg>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$inbox:/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>/{DAV:}multistatus/{DAV:}sync-token[!$synctoken1:]</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>Reset the property</description>
+ <request>
+ <method>PROPPATCH</method>
+ <ruri>$inboxpath1:/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/20.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL</value>
+ </arg>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/12.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$inbox:/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>/{DAV:}multistatus/{DAV:}sync-token[!$synctoken1:]</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+
+ <test-suite name='schedule-calendar-transp in response - home depth:1'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/22.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_home_items_initial_sync:</value>
+ <value>synccalendar3/</value>
+ <value>synccalendar4/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$dropbox:/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>dataString</callback>
+ <arg>
+ <name>contains</name>
+ <value>opaque</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>Change property on calendar</description>
+ <request>
+ <method>PROPPATCH</method>
+ <ruri>$calendarpath1:/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/Common/PROPPATCH/calendar-transp-transparent.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp</value>
+ </arg>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/23.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar:/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>/{DAV:}multistatus/{DAV:}sync-token[!$synctoken1:]</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>dataString</callback>
+ <arg>
+ <name>contains</name>
+ <value>transparent</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>Reset the property</description>
+ <request>
+ <method>PROPPATCH</method>
+ <ruri>$calendarpath1:/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/Common/PROPPATCH/calendar-transp-opaque.xml</filepath>
+ </data>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp</value>
+ </arg>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/23.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar:/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>/{DAV:}multistatus/{DAV:}sync-token[!$synctoken1:]</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>dataString</callback>
+ <arg>
+ <name>contains</name>
+ <value>opaque</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+
+
+ <test-suite name='Prefer:return=minimal - home depth:1'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - no minimal</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/24.xml</filepath>
+ </data>
+ <verify>
+ <callback>dataString</callback>
+ <arg>
+ <name>contains</name>
+ <value>foobar</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='2'>
+ <description>initial query - with minimal</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$calendarhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <header>
+ <name>Prefer</name>
+ <value>return=minimal</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CalDAV/reports/sync/24.xml</filepath>
+ </data>
+ <verify>
+ <callback>dataString</callback>
+ <arg>
+ <name>notcontains</name>
+ <value>foobar</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <end/>
+
+</caldavtest>
diff --git a/apps/dav/tests/travis/caldavtest/tests/CardDAV/sharing-addressbooks.xml b/apps/dav/tests/travis/caldavtest/tests/CardDAV/sharing-addressbooks.xml
new file mode 100644
index 00000000000..84ee6265017
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/tests/CardDAV/sharing-addressbooks.xml
@@ -0,0 +1,309 @@
+<?xml version="1.0" standalone="no"?>
+
+<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd">
+
+<caldavtest>
+ <description>Test addressbook sharing</description>
+
+ <require-feature>
+ <feature>carddav</feature>
+ </require-feature>
+
+ <start>
+ </start>
+
+ <test-suite name='Read-write addressbook'>
+ <test name='1'>
+ <description>POST invitation</description>
+ <request>
+ <method>POST</method>
+ <ruri>$addressbookpath1:</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>Shared addressbook exists</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+
+ <test name='4a'>
+ <description>Shared calendar exists Depth:1</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$addressbookhome2:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>parent</name>
+ <value>$multistatus-response-prefix:[^{DAV:}href=$addressbookhome2:/addressbook_shared_by_user01/]</value>
+ </arg>
+ <arg>
+ <name>exists</name>
+ <!--<value>$verify-response-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>-->
+ <value>$verify-response-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-response-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+
+ <test name='5'>
+ <description>Original calendar unchanged</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$addressbookpath1:</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+
+ <test name='6'>
+ <description>Sharee creates contact</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/6.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+
+ <test name='7'>
+ <description>Sharer sees contact</description>
+ <request>
+ <method>GET</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/read-write/6.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+
+ <test name='8'>
+ <description>Sharer changes contact</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/7.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+
+ <test name='9'>
+ <description>Sharee sees changed contact</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>GET</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/read-write/7.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+
+ <test name='10'>
+ <description>Sharer creates event</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/8.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='11'>
+ <description>Sharee sees new event</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>GET</method>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/read-write/8.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='12'>
+ <description>Sharee changes event</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/9.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='13'>
+ <description>Sharer sees changed event</description>
+ <request>
+ <method>GET</method>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/read-write/9.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='14'>
+ <description>Un-share by delete</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>DELETE</method>
+ <ruri>$addressbookhome2:/addressbook_shared_by_user01/</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='15'>
+ <description>Original address book still exists</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$addressbookhome1:/addressbook/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify> </request>
+ </test>
+ <test name='16'>
+ <description>Shared calendar no longer exists Depth:1</description>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>PROPFIND</method>
+ <ruri>$addressbookhome2:</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>notexists</name>
+ <value>$multistatus-response-prefix:[^{DAV:}href=$addressbookhome2:/addressbook_shared_by_user01/]</value>
+ </arg>
+ </verify>
+ </request>
+ </test> </test-suite>
+
+ <end>
+ </end>
+
+</caldavtest>
diff --git a/apps/dav/tests/travis/caldavtest/tests/CardDAV/sync-report.xml b/apps/dav/tests/travis/caldavtest/tests/CardDAV/sync-report.xml
new file mode 100644
index 00000000000..ffa6662981c
--- /dev/null
+++ b/apps/dav/tests/travis/caldavtest/tests/CardDAV/sync-report.xml
@@ -0,0 +1,1602 @@
+<?xml version="1.0" standalone="no"?>
+
+<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd">
+
+<!--
+ Copyright (c) 2006-2015 Apple Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<caldavtest>
+ <require-feature>
+ <feature>carddav</feature>
+ <feature>sync-report</feature>
+ </require-feature>
+
+ <start>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/2.vcf</filepath>
+ </data>
+ </request>
+ </start>
+
+ <test-suite name='support-report-set'>
+ <test name='1'>
+ <description>Not on addressbooks</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$addressbooks:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}supported-report-set/{DAV:}supported-report/{DAV:}report/{DAV:}sync-collection</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}supported-report-set</value>
+ </arg>
+ <arg>
+ <name>badprops</name>
+ <value>{DAV:}sync-token</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <!--
+ original test2 has been removed since we do not support sync support on addressbooks home
+ -->
+ <test name='3'>
+ <description>On addressbook</description>
+ <request>
+ <method>PROPFIND</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/1.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}supported-report-set/{DAV:}supported-report/{DAV:}report/{DAV:}sync-collection</value>
+ <!-- verification below does not match -->
+ <!-- value>$verify-property-prefix:/{DAV:}sync-token[+data:,]</value -->
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}supported-report-set</value>
+ <value>{DAV:}sync-token</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - empty token - no props'>
+ <test name='1'>
+ <description>initial query - addressbook depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <!-- no sync on addressbook level -->
+ <!-- value>$calendar_sync_extra_items:</value -->
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <!-- test 2 and 3 require sync support on addressbook collection -->
+ <test name='4'>
+ <description>add new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='5'>
+ <description>new resource - addressbook depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <!-- no sync on addressbook level -->
+ <!-- value>$calendar_sync_extra_items:</value -->
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ <value>3.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <!-- test name='6'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>new resource - home depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>$addressbook:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='7'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>new resource - home depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
+ <value>$addressbook:/3.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test -->
+ <test name='8'>
+ <description>remove new resource</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='9'>
+ <description>remove new resource - addressbook depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <!-- no sync on addressbook level -->
+ <!--<value>$calendar_sync_extra_items:</value>-->
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <!--test name='10'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>remove new resource - home depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>$addressbook:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='11'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>remove new resource - home depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='12'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='13'>
+ <description>changed resource - addressbook depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='14'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>changed resource - home depth:1</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>$addressbook:/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='15'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <description>changed resource - home depth:infinity</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ -->
+ </test-suite>
+
+ <!--
+ <test-suite name='simple reports - diff token - no props'>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>3.vcf</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>3.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>3.vcf</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='5'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.vcf</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - empty token - props'>
+ <test name='1'>
+ <description>initial query</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='2'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ <value>3.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3'>
+ <description>remove resource new resource</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - props'>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>1.vcf</value>
+ <value>2.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>3.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>3.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/7.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>3.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='5'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>1.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - no props - home depth:infinity'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>Initialize</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
+ </data>
+ </request>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/2.vcf</filepath>
+ </data>
+ </request>
+ </test>
+ <test name='2'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/3.vcf</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$addressbook:/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$addressbook:/3.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='5'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$addressbook:/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$addressbook:/3.vcf</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/1.vcf</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='7'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - props - home depth:infinity'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/5.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$calendar_sync_extra_items:</value>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>new resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/3.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>remove resource (treated as new)</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$addressbook:/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$addressbook:/3.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>ignore</name>
+ <value>$addressbookpath1:/</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>ignore</name>
+ <value>$addressbookpath1:/3.vcf</value>
+ </arg>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>remove resource (treated as old)</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/7.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$addressbook:/</value>
+ </arg>
+ <arg>
+ <name>badhrefs</name>
+ <value>$addressbook:/3.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>count</name>
+ <value>2</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='5'>
+ <description>changed resource</description>
+ <request>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/1.vcf</value>
+ </arg>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6'>
+ <description>no change</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ </verify>
+ <verify>
+ <callback>propfindItems</callback>
+ <arg>
+ <name>okprops</name>
+ <value>{DAV:}getcontenttype</value>
+ <value>{DAV:}getetag</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='simple reports - diff token - delete/create addressbook - home depth:infinity' ignore='yes'>
+ <require-feature>
+ <feature>sync-report-home</feature>
+ </require-feature>
+ <test name='1'>
+ <description>initial query - grab token</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/2.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>$addressbook:/</value>
+ <value>syncaddressbook3/</value>
+ <value>syncaddressbook3/1.vcf</value>
+ <value>syncaddressbook3/2.vcf</value>
+ <value>syncaddressbook4/</value>
+ <value>syncaddressbook4/1.vcf</value>
+ <value>syncaddressbook4/2.vcf</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='2'>
+ <description>remove resource then addressbook</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookhome1:/syncaddressbook3/1.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookhome1:/syncaddressbook3/</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>badhrefs</name>
+ <value>syncaddressbook3/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken2:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='3'>
+ <description>add addressbook - test last sync</description>
+ <request end-delete="yes">
+ <method>MKCOL</method>
+ <ruri>$addressbookhome1:/syncaddressbook3/</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
+ </data>
+ </request>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>syncaddressbook3/</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4'>
+ <description>add addressbook - test previous sync</description>
+ <request>
+ <method>REPORT</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>infinity</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/vreports/sync/3.xml</filepath>
+ </data>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>okhrefs</name>
+ <value>syncaddressbook3/</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>/{DAV:}multistatus/{DAV:}sync-token</name>
+ <variable>$synctoken1:</variable>
+ </grabelement>
+ </request>
+ </test>
+ </test-suite>
+-->
+
+ <end>
+ <request user="$useradmin:" pswd="$pswdadmin:">
+ <method>DELETEALL</method>
+ <ruri>$addressbookhome1:/</ruri>
+ <ruri>$addressbookhome2:/</ruri>
+ <ruri>$notificationpath1:/</ruri>
+ <ruri>$notificationpath2:/</ruri>
+ </request>
+ </end>
+
+</caldavtest>
diff --git a/apps/dav/tests/travis/carddav/install.sh b/apps/dav/tests/travis/carddav/install.sh
new file mode 100644
index 00000000000..fa5d141ce0d
--- /dev/null
+++ b/apps/dav/tests/travis/carddav/install.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+SCRIPT=`realpath $0`
+SCRIPTPATH=`dirname $SCRIPT`
+
+
+if [ ! -f CalDAVTester/run.py ]; then
+ cd "$SCRIPTPATH"
+ git clone https://github.com/DeepDiver1975/CalDAVTester.git
+ cd "$SCRIPTPATH/CalDAVTester"
+ python run.py -s
+ cd "$SCRIPTPATH"
+fi
+
+# create test user
+cd "$SCRIPTPATH/../../../../../"
+OC_PASS=user01 php occ user:add --password-from-env user01
+php occ dav:create-addressbook user01 addressbook
+OC_PASS=user02 php occ user:add --password-from-env user02
+php occ dav:create-addressbook user02 addressbook
+cd "$SCRIPTPATH/../../../../../"
diff --git a/apps/dav/tests/travis/carddav/script.sh b/apps/dav/tests/travis/carddav/script.sh
new file mode 100644
index 00000000000..a8bd9f11b38
--- /dev/null
+++ b/apps/dav/tests/travis/carddav/script.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+SCRIPT=`realpath $0`
+SCRIPTPATH=`dirname $SCRIPT`
+
+# start the server
+php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../../.." &
+
+sleep 30
+
+# run the tests
+cd "$SCRIPTPATH/CalDAVTester"
+PYTHONPATH="$SCRIPTPATH/pycalendar/src" python testcaldav.py --print-details-onfail --basedir "$SCRIPTPATH/../caldavtest/" -o cdt.txt \
+ "CardDAV/current-user-principal.xml" \
+ "CardDAV/sync-report.xml" \
+ "CardDAV/sharing-addressbooks.xml"
+
+
+RESULT=$?
+
+tail "$/../../../../../data-autotest/owncloud.log"
+
+exit $RESULT
diff --git a/apps/dav/tests/travis/litmus-v1.sh b/apps/dav/tests/travis/litmus-v1/install.sh
index ab0690f392e..0ee2cb08d82 100644
--- a/apps/dav/tests/travis/litmus-v1.sh
+++ b/apps/dav/tests/travis/litmus-v1/install.sh
@@ -1,11 +1,4 @@
#!/usr/bin/env bash
-SCRIPT=`realpath $0`
-SCRIPTPATH=`dirname $SCRIPT`
-
-
-# start the server
-php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../.." &
-
# compile litmus
if [ ! -f /tmp/litmus/litmus-0.13.tar.gz ]; then
@@ -17,7 +10,3 @@ if [ ! -f /tmp/litmus/litmus-0.13.tar.gz ]; then
./configure
make
fi
-
-# run the tests
-cd /tmp/litmus/litmus-0.13
-make URL=http://127.0.0.1:8888/remote.php/webdav CREDS="admin admin" TESTS="basic copymove props locks" check
diff --git a/apps/dav/tests/travis/litmus-v1/script.sh b/apps/dav/tests/travis/litmus-v1/script.sh
new file mode 100644
index 00000000000..cba305683b2
--- /dev/null
+++ b/apps/dav/tests/travis/litmus-v1/script.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+SCRIPT=`realpath $0`
+SCRIPTPATH=`dirname $SCRIPT`
+
+
+# start the server
+php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../../.." &
+
+sleep 30
+
+# run the tests
+cd /tmp/litmus/litmus-0.13
+make URL=http://127.0.0.1:8888/remote.php/webdav CREDS="admin admin" TESTS="basic copymove props locks" check
diff --git a/apps/dav/tests/travis/litmus-v2.sh b/apps/dav/tests/travis/litmus-v2/install.sh
index 892ad327d3b..0ee2cb08d82 100644
--- a/apps/dav/tests/travis/litmus-v2.sh
+++ b/apps/dav/tests/travis/litmus-v2/install.sh
@@ -1,11 +1,4 @@
#!/usr/bin/env bash
-SCRIPT=`realpath $0`
-SCRIPTPATH=`dirname $SCRIPT`
-
-
-# start the server
-php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../.." &
-
# compile litmus
if [ ! -f /tmp/litmus/litmus-0.13.tar.gz ]; then
@@ -17,7 +10,3 @@ if [ ! -f /tmp/litmus/litmus-0.13.tar.gz ]; then
./configure
make
fi
-
-# run the tests
-cd /tmp/litmus/litmus-0.13
-make URL=http://127.0.0.1:8888/remote.php/dav/files/admin CREDS="admin admin" TESTS="basic copymove props locks" check
diff --git a/apps/dav/tests/travis/litmus-v2/script.sh b/apps/dav/tests/travis/litmus-v2/script.sh
new file mode 100644
index 00000000000..966ed5a2052
--- /dev/null
+++ b/apps/dav/tests/travis/litmus-v2/script.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+SCRIPT=`realpath $0`
+SCRIPTPATH=`dirname $SCRIPT`
+
+
+# start the server
+php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../../.." &
+
+sleep 30
+
+# run the tests
+cd /tmp/litmus/litmus-0.13
+make URL=http://127.0.0.1:8888/remote.php/dav/files/admin CREDS="admin admin" TESTS="basic copymove props locks" check
diff --git a/apps/dav/tests/unit/appinfo/applicationtest.php b/apps/dav/tests/unit/appinfo/applicationtest.php
new file mode 100644
index 00000000000..7f533a185df
--- /dev/null
+++ b/apps/dav/tests/unit/appinfo/applicationtest.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\AppInfo;
+
+use OCA\Dav\AppInfo\Application;
+use OCP\Contacts\IManager;
+use Test\TestCase;
+
+/**
+ * Class ApplicationTest
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit\AppInfo
+ */
+class ApplicationTest extends TestCase {
+ public function test() {
+ $app = new Application();
+ $c = $app->getContainer();
+
+ // assert service instances in the container are properly setup
+ $s = $c->query('ContactsManager');
+ $this->assertInstanceOf('OCA\DAV\CardDAV\ContactsManager', $s);
+ $s = $c->query('CardDavBackend');
+ $this->assertInstanceOf('OCA\DAV\CardDAV\CardDavBackend', $s);
+ }
+
+ public function testContactsManagerSetup() {
+ $app = new Application();
+ $c = $app->getContainer();
+ $c->registerService('CardDavBackend', function($c) {
+ $service = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock();
+ $service->method('getAddressBooksForUser')->willReturn([]);
+ return $service;
+ });
+
+ // assert setupContactsProvider() is proper
+ /** @var IManager | \PHPUnit_Framework_MockObject_MockObject $cm */
+ $cm = $this->getMockBuilder('OCP\Contacts\IManager')->disableOriginalConstructor()->getMock();
+ $app->setupContactsProvider($cm, 'xxx');
+ $this->assertTrue(true);
+ }
+}
diff --git a/apps/dav/tests/unit/bootstrap.php b/apps/dav/tests/unit/bootstrap.php
index 28f6b971dec..f6733bc7a3e 100644
--- a/apps/dav/tests/unit/bootstrap.php
+++ b/apps/dav/tests/unit/bootstrap.php
@@ -1,6 +1,26 @@
<?php
-
-define('PHPUNIT_RUN', 1);
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+if (!defined('PHPUNIT_RUN')) {
+ define('PHPUNIT_RUN', 1);
+}
require_once __DIR__.'/../../../../lib/base.php';
diff --git a/apps/dav/tests/unit/caldav/caldavbackendtest.php b/apps/dav/tests/unit/caldav/caldavbackendtest.php
new file mode 100644
index 00000000000..aece738166a
--- /dev/null
+++ b/apps/dav/tests/unit/caldav/caldavbackendtest.php
@@ -0,0 +1,476 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace Tests\Connector\Sabre;
+
+use DateTime;
+use DateTimeZone;
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\CalDAV\Calendar;
+use OCA\DAV\Connector\Sabre\Principal;
+use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
+use Sabre\DAV\PropPatch;
+use Sabre\DAV\Xml\Property\Href;
+use Sabre\DAVACL\IACL;
+use Test\TestCase;
+
+/**
+ * Class CalDavBackendTest
+ *
+ * @group DB
+ *
+ * @package Tests\Connector\Sabre
+ */
+class CalDavBackendTest extends TestCase {
+
+ /** @var CalDavBackend */
+ private $backend;
+
+ /** @var Principal | \PHPUnit_Framework_MockObject_MockObject */
+ private $principal;
+
+ const UNIT_TEST_USER = 'principals/users/caldav-unit-test';
+ const UNIT_TEST_USER1 = 'principals/users/caldav-unit-test1';
+ const UNIT_TEST_GROUP = 'principals/groups/caldav-unit-test-group';
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal')
+ ->disableOriginalConstructor()
+ ->setMethods(['getPrincipalByPath', 'getGroupMembership'])
+ ->getMock();
+ $this->principal->method('getPrincipalByPath')
+ ->willReturn([
+ 'uri' => 'principals/best-friend'
+ ]);
+ $this->principal->method('getGroupMembership')
+ ->withAnyParameters()
+ ->willReturn([self::UNIT_TEST_GROUP]);
+
+ $db = \OC::$server->getDatabaseConnection();
+ $this->backend = new CalDavBackend($db, $this->principal);
+
+ $this->tearDown();
+ }
+
+ public function tearDown() {
+ parent::tearDown();
+
+ if (is_null($this->backend)) {
+ return;
+ }
+ $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
+ foreach ($books as $book) {
+ $this->backend->deleteCalendar($book['id']);
+ }
+ $subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
+ foreach ($subscriptions as $subscription) {
+ $this->backend->deleteSubscription($subscription['id']);
+ }
+ }
+
+ public function testCalendarOperations() {
+
+ $calendarId = $this->createTestCalendar();
+
+ // update it's display name
+ $patch = new PropPatch([
+ '{DAV:}displayname' => 'Unit test',
+ '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar used for unit testing'
+ ]);
+ $this->backend->updateCalendar($calendarId, $patch);
+ $patch->commit();
+ $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
+ $this->assertEquals('Unit test', $books[0]['{DAV:}displayname']);
+ $this->assertEquals('Calendar used for unit testing', $books[0]['{urn:ietf:params:xml:ns:caldav}calendar-description']);
+
+ // delete the address book
+ $this->backend->deleteCalendar($books[0]['id']);
+ $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(0, count($books));
+ }
+
+ public function providesSharingData() {
+ return [
+ [true, true, true, false, [
+ [
+ 'href' => 'principal:' . self::UNIT_TEST_USER1,
+ 'readOnly' => false
+ ],
+ [
+ 'href' => 'principal:' . self::UNIT_TEST_GROUP,
+ 'readOnly' => true
+ ]
+ ]],
+ [true, false, false, false, [
+ [
+ 'href' => 'principal:' . self::UNIT_TEST_USER1,
+ 'readOnly' => true
+ ],
+ ]],
+
+ ];
+ }
+
+ /**
+ * @dataProvider providesSharingData
+ */
+ public function testCalendarSharing($userCanRead, $userCanWrite, $groupCanRead, $groupCanWrite, $add) {
+
+ $calendarId = $this->createTestCalendar();
+ $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
+ $calendar = new Calendar($this->backend, $books[0]);
+ $this->backend->updateShares($calendar, $add, []);
+ $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER1);
+ $this->assertEquals(1, count($books));
+ $calendar = new Calendar($this->backend, $books[0]);
+ $acl = $calendar->getACL();
+ $this->assertAcl(self::UNIT_TEST_USER, '{DAV:}read', $acl);
+ $this->assertAcl(self::UNIT_TEST_USER, '{DAV:}write', $acl);
+ $this->assertAccess($userCanRead, self::UNIT_TEST_USER1, '{DAV:}read', $acl);
+ $this->assertAccess($userCanWrite, self::UNIT_TEST_USER1, '{DAV:}write', $acl);
+ $this->assertAccess($groupCanRead, self::UNIT_TEST_GROUP, '{DAV:}read', $acl);
+ $this->assertAccess($groupCanWrite, self::UNIT_TEST_GROUP, '{DAV:}write', $acl);
+ $this->assertEquals(self::UNIT_TEST_USER, $calendar->getOwner());
+
+ // test acls on the child
+ $uri = $this->getUniqueID('calobj');
+ $calData = <<<'EOD'
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:ownCloud Calendar
+BEGIN:VEVENT
+CREATED;VALUE=DATE-TIME:20130910T125139Z
+UID:47d15e3ec8
+LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z
+DTSTAMP;VALUE=DATE-TIME:20130910T125139Z
+SUMMARY:Test Event
+DTSTART;VALUE=DATE-TIME:20130912T130000Z
+DTEND;VALUE=DATE-TIME:20130912T140000Z
+CLASS:PUBLIC
+END:VEVENT
+END:VCALENDAR
+EOD;
+
+ $this->backend->createCalendarObject($calendarId, $uri, $calData);
+
+ /** @var IACL $child */
+ $child = $calendar->getChild($uri);
+ $acl = $child->getACL();
+ $this->assertAcl(self::UNIT_TEST_USER, '{DAV:}read', $acl);
+ $this->assertAcl(self::UNIT_TEST_USER, '{DAV:}write', $acl);
+ $this->assertAccess($userCanRead, self::UNIT_TEST_USER1, '{DAV:}read', $acl);
+ $this->assertAccess($userCanWrite, self::UNIT_TEST_USER1, '{DAV:}write', $acl);
+ $this->assertAccess($groupCanRead, self::UNIT_TEST_GROUP, '{DAV:}read', $acl);
+ $this->assertAccess($groupCanWrite, self::UNIT_TEST_GROUP, '{DAV:}write', $acl);
+
+ // delete the address book
+ $this->backend->deleteCalendar($books[0]['id']);
+ $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(0, count($books));
+ }
+
+ public function testCalendarObjectsOperations() {
+
+ $calendarId = $this->createTestCalendar();
+
+ // create a card
+ $uri = $this->getUniqueID('calobj');
+ $calData = <<<'EOD'
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:ownCloud Calendar
+BEGIN:VEVENT
+CREATED;VALUE=DATE-TIME:20130910T125139Z
+UID:47d15e3ec8
+LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z
+DTSTAMP;VALUE=DATE-TIME:20130910T125139Z
+SUMMARY:Test Event
+DTSTART;VALUE=DATE-TIME:20130912T130000Z
+DTEND;VALUE=DATE-TIME:20130912T140000Z
+CLASS:PUBLIC
+END:VEVENT
+END:VCALENDAR
+EOD;
+
+ $this->backend->createCalendarObject($calendarId, $uri, $calData);
+
+ // get all the cards
+ $calendarObjects = $this->backend->getCalendarObjects($calendarId);
+ $this->assertEquals(1, count($calendarObjects));
+ $this->assertEquals($calendarId, $calendarObjects[0]['calendarid']);
+
+ // get the cards
+ $calendarObject = $this->backend->getCalendarObject($calendarId, $uri);
+ $this->assertNotNull($calendarObject);
+ $this->assertArrayHasKey('id', $calendarObject);
+ $this->assertArrayHasKey('uri', $calendarObject);
+ $this->assertArrayHasKey('lastmodified', $calendarObject);
+ $this->assertArrayHasKey('etag', $calendarObject);
+ $this->assertArrayHasKey('size', $calendarObject);
+ $this->assertEquals($calData, $calendarObject['calendardata']);
+
+ // update the card
+ $calData = <<<'EOD'
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:ownCloud Calendar
+BEGIN:VEVENT
+CREATED;VALUE=DATE-TIME:20130910T125139Z
+UID:47d15e3ec8
+LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z
+DTSTAMP;VALUE=DATE-TIME:20130910T125139Z
+SUMMARY:Test Event
+DTSTART;VALUE=DATE-TIME:20130912T130000Z
+DTEND;VALUE=DATE-TIME:20130912T140000Z
+END:VEVENT
+END:VCALENDAR
+EOD;
+ $this->backend->updateCalendarObject($calendarId, $uri, $calData);
+ $calendarObject = $this->backend->getCalendarObject($calendarId, $uri);
+ $this->assertEquals($calData, $calendarObject['calendardata']);
+
+ // delete the card
+ $this->backend->deleteCalendarObject($calendarId, $uri);
+ $calendarObjects = $this->backend->getCalendarObjects($calendarId);
+ $this->assertEquals(0, count($calendarObjects));
+ }
+
+ public function testMultiCalendarObjects() {
+
+ $calendarId = $this->createTestCalendar();
+
+ // create an event
+ $calData = <<<'EOD'
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:ownCloud Calendar
+BEGIN:VEVENT
+CREATED;VALUE=DATE-TIME:20130910T125139Z
+UID:47d15e3ec8
+LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z
+DTSTAMP;VALUE=DATE-TIME:20130910T125139Z
+SUMMARY:Test Event
+DTSTART;VALUE=DATE-TIME:20130912T130000Z
+DTEND;VALUE=DATE-TIME:20130912T140000Z
+CLASS:PUBLIC
+END:VEVENT
+END:VCALENDAR
+EOD;
+ $uri0 = $this->getUniqueID('card');
+ $this->backend->createCalendarObject($calendarId, $uri0, $calData);
+ $uri1 = $this->getUniqueID('card');
+ $this->backend->createCalendarObject($calendarId, $uri1, $calData);
+ $uri2 = $this->getUniqueID('card');
+ $this->backend->createCalendarObject($calendarId, $uri2, $calData);
+
+ // get all the cards
+ $calendarObjects = $this->backend->getCalendarObjects($calendarId);
+ $this->assertEquals(3, count($calendarObjects));
+
+ // get the cards
+ $calendarObjects = $this->backend->getMultipleCalendarObjects($calendarId, [$uri1, $uri2]);
+ $this->assertEquals(2, count($calendarObjects));
+ foreach($calendarObjects as $card) {
+ $this->assertArrayHasKey('id', $card);
+ $this->assertArrayHasKey('uri', $card);
+ $this->assertArrayHasKey('lastmodified', $card);
+ $this->assertArrayHasKey('etag', $card);
+ $this->assertArrayHasKey('size', $card);
+ $this->assertEquals($calData, $card['calendardata']);
+ }
+
+ // delete the card
+ $this->backend->deleteCalendarObject($calendarId, $uri0);
+ $this->backend->deleteCalendarObject($calendarId, $uri1);
+ $this->backend->deleteCalendarObject($calendarId, $uri2);
+ $calendarObjects = $this->backend->getCalendarObjects($calendarId);
+ $this->assertEquals(0, count($calendarObjects));
+ }
+
+ /**
+ * @dataProvider providesCalendarQueryParameters
+ */
+ public function testCalendarQuery($expectedEventsInResult, $propFilters, $compFilter) {
+ $calendarId = $this->createTestCalendar();
+ $events = [];
+ $events[0] = $this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z');
+ $events[1] = $this->createEvent($calendarId, '20130912T150000Z', '20130912T170000Z');
+ $events[2] = $this->createEvent($calendarId, '20130912T173000Z', '20130912T220000Z');
+
+ $result = $this->backend->calendarQuery($calendarId, [
+ 'name' => '',
+ 'prop-filters' => $propFilters,
+ 'comp-filters' => $compFilter
+ ]);
+
+ $expectedEventsInResult = array_map(function($index) use($events) {
+ return $events[$index];
+ }, $expectedEventsInResult);
+ $this->assertEquals($expectedEventsInResult, $result, '', 0.0, 10, true);
+ }
+
+ public function testGetCalendarObjectByUID() {
+ $calendarId = $this->createTestCalendar();
+ $this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z');
+
+ $co = $this->backend->getCalendarObjectByUID(self::UNIT_TEST_USER, '47d15e3ec8');
+ $this->assertNotNull($co);
+ }
+
+ public function providesCalendarQueryParameters() {
+ return [
+ 'all' => [[0, 1, 2], [], []],
+ 'only-todos' => [[], ['name' => 'VTODO'], []],
+ 'only-events' => [[0, 1, 2], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => null, 'end' => null], 'prop-filters' => []]],],
+ 'start' => [[1, 2], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => new DateTime('2013-09-12 14:00:00', new DateTimeZone('UTC')), 'end' => null], 'prop-filters' => []]],],
+ 'end' => [[0], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => null, 'end' => new DateTime('2013-09-12 14:00:00', new DateTimeZone('UTC'))], 'prop-filters' => []]],],
+ ];
+ }
+
+ private function createTestCalendar() {
+ $this->backend->createCalendar(self::UNIT_TEST_USER, 'Example', [
+ '{http://apple.com/ns/ical/}calendar-color' => '#1C4587FF'
+ ]);
+ $calendars = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($calendars));
+ $this->assertEquals(self::UNIT_TEST_USER, $calendars[0]['principaluri']);
+ /** @var SupportedCalendarComponentSet $components */
+ $components = $calendars[0]['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'];
+ $this->assertEquals(['VEVENT','VTODO'], $components->getValue());
+ $color = $calendars[0]['{http://apple.com/ns/ical/}calendar-color'];
+ $this->assertEquals('#1C4587FF', $color);
+ $this->assertEquals('Example', $calendars[0]['uri']);
+ $this->assertEquals('Example', $calendars[0]['{DAV:}displayname']);
+ $calendarId = $calendars[0]['id'];
+
+ return $calendarId;
+ }
+
+ private function createEvent($calendarId, $start = '20130912T130000Z', $end = '20130912T140000Z') {
+
+ $calData = <<<EOD
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:ownCloud Calendar
+BEGIN:VEVENT
+CREATED;VALUE=DATE-TIME:20130910T125139Z
+UID:47d15e3ec8
+LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z
+DTSTAMP;VALUE=DATE-TIME:20130910T125139Z
+SUMMARY:Test Event
+DTSTART;VALUE=DATE-TIME:$start
+DTEND;VALUE=DATE-TIME:$end
+CLASS:PUBLIC
+END:VEVENT
+END:VCALENDAR
+EOD;
+ $uri0 = $this->getUniqueID('event');
+ $this->backend->createCalendarObject($calendarId, $uri0, $calData);
+
+ return $uri0;
+ }
+
+ public function testSyncSupport() {
+ $calendarId = $this->createTestCalendar();
+
+ // fist call without synctoken
+ $changes = $this->backend->getChangesForCalendar($calendarId, '', 1);
+ $syncToken = $changes['syncToken'];
+
+ // add a change
+ $event = $this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z');
+
+ // look for changes
+ $changes = $this->backend->getChangesForCalendar($calendarId, $syncToken, 1);
+ $this->assertEquals($event, $changes['added'][0]);
+ }
+
+ public function testSubscriptions() {
+ $id = $this->backend->createSubscription(self::UNIT_TEST_USER, 'Subscription', [
+ '{http://calendarserver.org/ns/}source' => new Href('test-source')
+ ]);
+
+ $subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($subscriptions));
+ $this->assertEquals($id, $subscriptions[0]['id']);
+
+ $patch = new PropPatch([
+ '{DAV:}displayname' => 'Unit test',
+ ]);
+ $this->backend->updateSubscription($id, $patch);
+ $patch->commit();
+
+ $subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($subscriptions));
+ $this->assertEquals($id, $subscriptions[0]['id']);
+ $this->assertEquals('Unit test', $subscriptions[0]['{DAV:}displayname']);
+
+ $this->backend->deleteSubscription($id);
+ $subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(0, count($subscriptions));
+ }
+
+ public function testScheduling() {
+ $this->backend->createSchedulingObject(self::UNIT_TEST_USER, 'Sample Schedule', '');
+
+ $sos = $this->backend->getSchedulingObjects(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($sos));
+
+ $so = $this->backend->getSchedulingObject(self::UNIT_TEST_USER, 'Sample Schedule');
+ $this->assertNotNull($so);
+
+ $this->backend->deleteSchedulingObject(self::UNIT_TEST_USER, 'Sample Schedule');
+
+ $sos = $this->backend->getSchedulingObjects(self::UNIT_TEST_USER);
+ $this->assertEquals(0, count($sos));
+ }
+
+ private function assertAcl($principal, $privilege, $acl) {
+ foreach($acl as $a) {
+ if ($a['principal'] === $principal && $a['privilege'] === $privilege) {
+ $this->assertTrue(true);
+ return;
+ }
+ }
+ $this->fail("ACL does not contain $principal / $privilege");
+ }
+
+ private function assertNotAcl($principal, $privilege, $acl) {
+ foreach($acl as $a) {
+ if ($a['principal'] === $principal && $a['privilege'] === $privilege) {
+ $this->fail("ACL contains $principal / $privilege");
+ return;
+ }
+ }
+ $this->assertTrue(true);
+ }
+
+ private function assertAccess($shouldHaveAcl, $principal, $privilege, $acl) {
+ if ($shouldHaveAcl) {
+ $this->assertAcl($principal, $privilege, $acl);
+ } else {
+ $this->assertNotAcl($principal, $privilege, $acl);
+ }
+ }
+}
diff --git a/apps/dav/tests/unit/caldav/calendartest.php b/apps/dav/tests/unit/caldav/calendartest.php
new file mode 100644
index 00000000000..93b3f4bff8c
--- /dev/null
+++ b/apps/dav/tests/unit/caldav/calendartest.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\CalDAV;
+
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\CalDAV\Calendar;
+use Test\TestCase;
+
+class CalendarTest extends TestCase {
+
+ public function testDelete() {
+ /** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */
+ $backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock();
+ $backend->expects($this->once())->method('updateShares');
+ $backend->method('getShares')->willReturn([
+ ['href' => 'principal:user2']
+ ]);
+ $calendarInfo = [
+ '{http://owncloud.org/ns}owner-principal' => 'user1',
+ 'principaluri' => 'user2',
+ 'id' => 666
+ ];
+ $c = new Calendar($backend, $calendarInfo);
+ $c->delete();
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testDeleteFromGroup() {
+ /** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */
+ $backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock();
+ $backend->expects($this->never())->method('updateShares');
+ $backend->method('getShares')->willReturn([
+ ['href' => 'principal:group2']
+ ]);
+ $calendarInfo = [
+ '{http://owncloud.org/ns}owner-principal' => 'user1',
+ 'principaluri' => 'user2',
+ 'id' => 666
+ ];
+ $c = new Calendar($backend, $calendarInfo);
+ $c->delete();
+ }
+}
diff --git a/apps/dav/tests/unit/caldav/schedule/imipplugintest.php b/apps/dav/tests/unit/caldav/schedule/imipplugintest.php
new file mode 100644
index 00000000000..fcbf4fde04c
--- /dev/null
+++ b/apps/dav/tests/unit/caldav/schedule/imipplugintest.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\CalDAV\Schedule;
+
+use OC\Mail\Mailer;
+use OCA\DAV\CalDAV\Schedule\IMipPlugin;
+use OCP\ILogger;
+use Sabre\VObject\Component\VCalendar;
+use Sabre\VObject\ITip\Message;
+use Test\TestCase;
+
+class IMipPluginTest extends TestCase {
+
+ public function testDelivery() {
+ $mailMessage = new \OC\Mail\Message(new \Swift_Message());
+ /** @var Mailer | \PHPUnit_Framework_MockObject_MockObject $mailer */
+ $mailer = $this->getMockBuilder('OC\Mail\Mailer')->disableOriginalConstructor()->getMock();
+ $mailer->method('createMessage')->willReturn($mailMessage);
+ $mailer->expects($this->once())->method('send');
+ /** @var ILogger | \PHPUnit_Framework_MockObject_MockObject $logger */
+ $logger = $this->getMockBuilder('OC\Log')->disableOriginalConstructor()->getMock();
+
+ $plugin = new IMipPlugin($mailer, $logger);
+ $message = new Message();
+ $message->method = 'REQUEST';
+ $message->message = new VCalendar();
+ $message->message->add('VEVENT', [
+ 'UID' => $message->uid,
+ 'SEQUENCE' => $message->sequence,
+ 'SUMMARY' => 'Fellowship meeting',
+ ]);
+ $message->sender = 'mailto:gandalf@wiz.ard';
+ $message->recipient = 'mailto:frodo@hobb.it';
+
+ $plugin->schedule($message);
+ $this->assertEquals('1.1', $message->getScheduleStatus());
+ $this->assertEquals('Fellowship meeting', $mailMessage->getSubject());
+ $this->assertEquals(['frodo@hobb.it' => null], $mailMessage->getTo());
+ $this->assertEquals(['gandalf@wiz.ard' => null], $mailMessage->getReplyTo());
+ $this->assertEquals('text/calendar; charset=UTF-8; method=REQUEST', $mailMessage->getSwiftMessage()->getContentType());
+ }
+
+ public function testFailedDelivery() {
+ $mailMessage = new \OC\Mail\Message(new \Swift_Message());
+ /** @var Mailer | \PHPUnit_Framework_MockObject_MockObject $mailer */
+ $mailer = $this->getMockBuilder('OC\Mail\Mailer')->disableOriginalConstructor()->getMock();
+ $mailer->method('createMessage')->willReturn($mailMessage);
+ $mailer->method('send')->willThrowException(new \Exception());
+ /** @var ILogger | \PHPUnit_Framework_MockObject_MockObject $logger */
+ $logger = $this->getMockBuilder('OC\Log')->disableOriginalConstructor()->getMock();
+
+ $plugin = new IMipPlugin($mailer, $logger);
+ $message = new Message();
+ $message->method = 'REQUEST';
+ $message->message = new VCalendar();
+ $message->message->add('VEVENT', [
+ 'UID' => $message->uid,
+ 'SEQUENCE' => $message->sequence,
+ 'SUMMARY' => 'Fellowship meeting',
+ ]);
+ $message->sender = 'mailto:gandalf@wiz.ard';
+ $message->recipient = 'mailto:frodo@hobb.it';
+
+ $plugin->schedule($message);
+ $this->assertEquals('5.0', $message->getScheduleStatus());
+ $this->assertEquals('Fellowship meeting', $mailMessage->getSubject());
+ $this->assertEquals(['frodo@hobb.it' => null], $mailMessage->getTo());
+ $this->assertEquals(['gandalf@wiz.ard' => null], $mailMessage->getReplyTo());
+ $this->assertEquals('text/calendar; charset=UTF-8; method=REQUEST', $mailMessage->getSwiftMessage()->getContentType());
+ }
+
+}
diff --git a/apps/dav/tests/unit/carddav/addressbookimpltest.php b/apps/dav/tests/unit/carddav/addressbookimpltest.php
new file mode 100644
index 00000000000..ff7b982abd4
--- /dev/null
+++ b/apps/dav/tests/unit/carddav/addressbookimpltest.php
@@ -0,0 +1,287 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\DAV\Tests\Unit\CardDAV;
+
+
+use OCA\DAV\CardDAV\AddressBook;
+use OCA\DAV\CardDAV\AddressBookImpl;
+use OCA\DAV\CardDAV\CardDavBackend;
+use Sabre\VObject\Component\VCard;
+use Sabre\VObject\Property\Text;
+use Test\TestCase;
+
+class AddressBookImplTest extends TestCase {
+
+ /** @var AddressBookImpl */
+ private $addressBookImpl;
+
+ /** @var array */
+ private $addressBookInfo;
+
+ /** @var AddressBook | \PHPUnit_Framework_MockObject_MockObject */
+ private $addressBook;
+
+ /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject */
+ private $backend;
+
+ /** @var VCard | \PHPUnit_Framework_MockObject_MockObject */
+ private $vCard;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->addressBookInfo = [
+ 'id' => 42,
+ '{DAV:}displayname' => 'display name'
+ ];
+ $this->addressBook = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBook')
+ ->disableOriginalConstructor()->getMock();
+ $this->backend = $this->getMockBuilder('\OCA\DAV\CardDAV\CardDavBackend')
+ ->disableOriginalConstructor()->getMock();
+ $this->vCard = $this->getMock('Sabre\VObject\Component\VCard');
+
+ $this->addressBookImpl = new AddressBookImpl(
+ $this->addressBook,
+ $this->addressBookInfo,
+ $this->backend
+ );
+ }
+
+ public function testGetKey() {
+ $this->assertSame($this->addressBookInfo['id'],
+ $this->addressBookImpl->getKey());
+ }
+
+ public function testGetDisplayName() {
+ $this->assertSame($this->addressBookInfo['{DAV:}displayname'],
+ $this->addressBookImpl->getDisplayName());
+ }
+
+ public function testSearch() {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
+ $addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
+ ->setConstructorArgs(
+ [
+ $this->addressBook,
+ $this->addressBookInfo,
+ $this->backend
+ ]
+ )
+ ->setMethods(['vCard2Array', 'readCard'])
+ ->getMock();
+
+ $pattern = 'pattern';
+ $searchProperties = 'properties';
+
+ $this->backend->expects($this->once())->method('search')
+ ->with($this->addressBookInfo['id'], $pattern, $searchProperties)
+ ->willReturn(
+ [
+ 'cardData1',
+ 'cardData2'
+ ]
+ );
+
+ $addressBookImpl->expects($this->exactly(2))->method('readCard')
+ ->willReturn($this->vCard);
+ $addressBookImpl->expects($this->exactly(2))->method('vCard2Array')
+ ->with($this->vCard)->willReturn('vCard');
+
+ $result = $addressBookImpl->search($pattern, $searchProperties, []);
+ $this->assertTrue((is_array($result)));
+ $this->assertSame(2, count($result));
+ }
+
+ /**
+ * @dataProvider dataTestCreate
+ *
+ * @param array $properties
+ */
+ public function testCreate($properties) {
+
+ $uid = 'uid';
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
+ $addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
+ ->setConstructorArgs(
+ [
+ $this->addressBook,
+ $this->addressBookInfo,
+ $this->backend
+ ]
+ )
+ ->setMethods(['vCard2Array', 'createUid', 'createEmptyVCard'])
+ ->getMock();
+
+ $addressBookImpl->expects($this->once())->method('createUid')
+ ->willReturn($uid);
+ $addressBookImpl->expects($this->once())->method('createEmptyVCard')
+ ->with($uid)->willReturn($this->vCard);
+ $this->vCard->expects($this->exactly(count($properties)))
+ ->method('createProperty');
+ $this->backend->expects($this->once())->method('createCard');
+ $this->backend->expects($this->never())->method('updateCard');
+ $this->backend->expects($this->never())->method('getCard');
+ $addressBookImpl->expects($this->once())->method('vCard2Array')
+ ->with($this->vCard)->willReturn(true);
+
+ $this->assertTrue($addressBookImpl->createOrUpdate($properties));
+ }
+
+ public function dataTestCreate() {
+ return [
+ [[]],
+ [['FN' => 'John Doe']]
+ ];
+ }
+
+ public function testUpdate() {
+
+ $uid = 'uid';
+ $properties = ['UID' => $uid, 'FN' => 'John Doe'];
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
+ $addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
+ ->setConstructorArgs(
+ [
+ $this->addressBook,
+ $this->addressBookInfo,
+ $this->backend
+ ]
+ )
+ ->setMethods(['vCard2Array', 'createUid', 'createEmptyVCard', 'readCard'])
+ ->getMock();
+
+ $addressBookImpl->expects($this->never())->method('createUid');
+ $addressBookImpl->expects($this->never())->method('createEmptyVCard');
+ $this->backend->expects($this->once())->method('getCard')
+ ->with($this->addressBookInfo['id'], $uid . '.vcf')
+ ->willReturn(['carddata' => 'data']);
+ $addressBookImpl->expects($this->once())->method('readCard')
+ ->with('data')->willReturn($this->vCard);
+ $this->vCard->expects($this->exactly(count($properties)))
+ ->method('createProperty');
+ $this->backend->expects($this->never())->method('createCard');
+ $this->backend->expects($this->once())->method('updateCard');
+ $addressBookImpl->expects($this->once())->method('vCard2Array')
+ ->with($this->vCard)->willReturn(true);
+
+ $this->assertTrue($addressBookImpl->createOrUpdate($properties));
+ }
+
+ /**
+ * @dataProvider dataTestGetPermissions
+ *
+ * @param array $permissions
+ * @param int $expected
+ */
+ public function testGetPermissions($permissions, $expected) {
+ $this->addressBook->expects($this->once())->method('getACL')
+ ->willReturn($permissions);
+
+ $this->assertSame($expected,
+ $this->addressBookImpl->getPermissions()
+ );
+ }
+
+ public function dataTestGetPermissions() {
+ return [
+ [[], 0],
+ [[['privilege' => '{DAV:}read']], 1],
+ [[['privilege' => '{DAV:}write']], 6],
+ [[['privilege' => '{DAV:}all']], 31],
+ [[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 7],
+ [[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}all']], 31],
+ [[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}write']], 31],
+ [[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write'],['privilege' => '{DAV:}all']], 31],
+ [[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 31],
+ ];
+ }
+
+ public function testDelete() {
+ $cardId = 1;
+ $cardUri = 'cardUri';
+ $this->backend->expects($this->once())->method('getCardUri')
+ ->with($cardId)->willReturn($cardUri);
+ $this->backend->expects($this->once())->method('deleteCard')
+ ->with($this->addressBookInfo['id'], $cardUri)
+ ->willReturn(true);
+
+ $this->assertTrue($this->addressBookImpl->delete($cardId));
+ }
+
+ public function testReadCard() {
+ $vCard = new VCard();
+ $vCard->add(new Text($vCard, 'UID', 'uid'));
+ $vCardSerialized = $vCard->serialize();
+
+ $result = $this->invokePrivate($this->addressBookImpl, 'readCard', [$vCardSerialized]);
+ $resultSerialized = $result->serialize();
+
+ $this->assertSame($vCardSerialized, $resultSerialized);
+ }
+
+ public function testCreateUid() {
+ /** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
+ $addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
+ ->setConstructorArgs(
+ [
+ $this->addressBook,
+ $this->addressBookInfo,
+ $this->backend
+ ]
+ )
+ ->setMethods(['getUid'])
+ ->getMock();
+
+ $addressBookImpl->expects($this->at(0))->method('getUid')->willReturn('uid0');
+ $addressBookImpl->expects($this->at(1))->method('getUid')->willReturn('uid1');
+
+ // simulate that 'uid0' already exists, so the second uid will be returned
+ $this->backend->expects($this->exactly(2))->method('getContact')
+ ->willReturnCallback(
+ function($uid) {
+ return ($uid === 'uid0.vcf');
+ }
+ );
+
+ $this->assertSame('uid1',
+ $this->invokePrivate($addressBookImpl, 'createUid', [])
+ );
+
+ }
+
+ public function testCreateEmptyVCard() {
+ $uid = 'uid';
+ $expectedVCard = new VCard();
+ $expectedVCard->add(new Text($expectedVCard, 'UID', $uid));
+ $expectedVCardSerialized = $expectedVCard->serialize();
+
+ $result = $this->invokePrivate($this->addressBookImpl, 'createEmptyVCard', [$uid]);
+ $resultSerialized = $result->serialize();
+
+ $this->assertSame($expectedVCardSerialized, $resultSerialized);
+ }
+
+}
diff --git a/apps/dav/tests/unit/carddav/addressbooktest.php b/apps/dav/tests/unit/carddav/addressbooktest.php
new file mode 100644
index 00000000000..d714fc71679
--- /dev/null
+++ b/apps/dav/tests/unit/carddav/addressbooktest.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\CardDAV;
+
+use OCA\DAV\CardDAV\AddressBook;
+use OCA\DAV\CardDAV\CardDavBackend;
+use Test\TestCase;
+
+class AddressBookTest extends TestCase {
+
+ public function testDelete() {
+ /** @var \PHPUnit_Framework_MockObject_MockObject | CardDavBackend $backend */
+ $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock();
+ $backend->expects($this->once())->method('updateShares');
+ $backend->method('getShares')->willReturn([
+ ['href' => 'principal:user2']
+ ]);
+ $calendarInfo = [
+ '{http://owncloud.org/ns}owner-principal' => 'user1',
+ 'principaluri' => 'user2',
+ 'id' => 666
+ ];
+ $c = new AddressBook($backend, $calendarInfo);
+ $c->delete();
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testDeleteFromGroup() {
+ /** @var \PHPUnit_Framework_MockObject_MockObject | CardDavBackend $backend */
+ $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock();
+ $backend->expects($this->never())->method('updateShares');
+ $backend->method('getShares')->willReturn([
+ ['href' => 'principal:group2']
+ ]);
+ $calendarInfo = [
+ '{http://owncloud.org/ns}owner-principal' => 'user1',
+ 'principaluri' => 'user2',
+ 'id' => 666
+ ];
+ $c = new AddressBook($backend, $calendarInfo);
+ $c->delete();
+ }
+}
diff --git a/apps/dav/tests/unit/carddav/carddavbackendtest.php b/apps/dav/tests/unit/carddav/carddavbackendtest.php
index 79ef36d8097..86bc26b4c0d 100644
--- a/apps/dav/tests/unit/carddav/carddavbackendtest.php
+++ b/apps/dav/tests/unit/carddav/carddavbackendtest.php
@@ -1,8 +1,10 @@
<?php
/**
- * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,23 +22,69 @@
*/
namespace OCA\DAV\Tests\Unit\CardDAV;
+use InvalidArgumentException;
+use OCA\DAV\CardDAV\AddressBook;
use OCA\DAV\CardDAV\CardDavBackend;
+use OCA\DAV\Connector\Sabre\Principal;
+use OCP\IDBConnection;
use Sabre\DAV\PropPatch;
+use Sabre\VObject\Component\VCard;
+use Sabre\VObject\Property\Text;
use Test\TestCase;
+/**
+ * Class CardDavBackendTest
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit\CardDAV
+ */
class CardDavBackendTest extends TestCase {
/** @var CardDavBackend */
private $backend;
- const UNIT_TEST_USER = 'carddav-unit-test';
+ /** @var Principal | \PHPUnit_Framework_MockObject_MockObject */
+ private $principal;
+ /** @var IDBConnection */
+ private $db;
+
+ /** @var string */
+ private $dbCardsTable = 'cards';
+
+ /** @var string */
+ private $dbCardsPropertiesTable = 'cards_properties';
+
+ const UNIT_TEST_USER = 'principals/users/carddav-unit-test';
+ const UNIT_TEST_USER1 = 'principals/users/carddav-unit-test1';
+ const UNIT_TEST_GROUP = 'principals/groups/carddav-unit-test-group';
public function setUp() {
parent::setUp();
- $db = \OC::$server->getDatabaseConnection();
- $this->backend = new CardDavBackend($db);
+ $this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal')
+ ->disableOriginalConstructor()
+ ->setMethods(['getPrincipalByPath', 'getGroupMembership'])
+ ->getMock();
+ $this->principal->method('getPrincipalByPath')
+ ->willReturn([
+ 'uri' => 'principals/best-friend'
+ ]);
+ $this->principal->method('getGroupMembership')
+ ->withAnyParameters()
+ ->willReturn([self::UNIT_TEST_GROUP]);
+
+ $this->db = \OC::$server->getDatabaseConnection();
+
+ $this->backend = new CardDavBackend($this->db, $this->principal);
+
+ // start every test with a empty cards_properties and cards table
+ $query = $this->db->getQueryBuilder();
+ $query->delete('cards_properties')->execute();
+ $query = $this->db->getQueryBuilder();
+ $query->delete('cards')->execute();
+
$this->tearDown();
}
@@ -80,24 +128,56 @@ class CardDavBackendTest extends TestCase {
$this->assertEquals(0, count($books));
}
- public function testCardOperations() {
- // create a new address book
+ public function testAddressBookSharing() {
+
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
$this->assertEquals(1, count($books));
+ $addressBook = new AddressBook($this->backend, $books[0]);
+ $this->backend->updateShares($addressBook, [
+ [
+ 'href' => 'principal:' . self::UNIT_TEST_USER1,
+ ],
+ [
+ 'href' => 'principal:' . self::UNIT_TEST_GROUP,
+ ]
+ ], []);
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
+ $this->assertEquals(1, count($books));
+
+ // delete the address book
+ $this->backend->deleteAddressBook($books[0]['id']);
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(0, count($books));
+ }
+
+ public function testCardOperations() {
+
+ /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $backend */
+ $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
+ ->setConstructorArgs([$this->db, $this->principal])
+ ->setMethods(['updateProperties', 'purgeProperties'])->getMock();
+
+ // create a new address book
+ $backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
+ $books = $backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
$bookId = $books[0]['id'];
- // create a card
$uri = $this->getUniqueID('card');
- $this->backend->createCard($bookId, $uri, '');
+ // updateProperties is expected twice, once for createCard and once for updateCard
+ $backend->expects($this->at(0))->method('updateProperties')->with($bookId, $uri, '');
+ $backend->expects($this->at(1))->method('updateProperties')->with($bookId, $uri, '***');
+ // create a card
+ $backend->createCard($bookId, $uri, '');
// get all the cards
- $cards = $this->backend->getCards($bookId);
+ $cards = $backend->getCards($bookId);
$this->assertEquals(1, count($cards));
$this->assertEquals('', $cards[0]['carddata']);
// get the cards
- $card = $this->backend->getCard($bookId, $uri);
+ $card = $backend->getCard($bookId, $uri);
$this->assertNotNull($card);
$this->assertArrayHasKey('id', $card);
$this->assertArrayHasKey('uri', $card);
@@ -107,17 +187,23 @@ class CardDavBackendTest extends TestCase {
$this->assertEquals('', $card['carddata']);
// update the card
- $this->backend->updateCard($bookId, $uri, '***');
- $card = $this->backend->getCard($bookId, $uri);
+ $backend->updateCard($bookId, $uri, '***');
+ $card = $backend->getCard($bookId, $uri);
$this->assertEquals('***', $card['carddata']);
// delete the card
- $this->backend->deleteCard($bookId, $uri);
- $cards = $this->backend->getCards($bookId);
+ $backend->expects($this->once())->method('purgeProperties')->with($bookId, $card['id']);
+ $backend->deleteCard($bookId, $uri);
+ $cards = $backend->getCards($bookId);
$this->assertEquals(0, count($cards));
}
public function testMultiCard() {
+
+ $this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
+ ->setConstructorArgs([$this->db, $this->principal])
+ ->setMethods(['updateProperties'])->getMock();
+
// create a new address book
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
@@ -159,7 +245,53 @@ class CardDavBackendTest extends TestCase {
$this->assertEquals(0, count($cards));
}
+ public function testDeleteWithoutCard() {
+
+ $this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
+ ->setConstructorArgs([$this->db, $this->principal])
+ ->setMethods([
+ 'getCardId',
+ 'addChange',
+ 'purgeProperties',
+ 'updateProperties',
+ ])
+ ->getMock();
+
+ // create a new address book
+ $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
+
+ $bookId = $books[0]['id'];
+ $uri = $this->getUniqueID('card');
+
+ // create a new address book
+ $this->backend->expects($this->once())
+ ->method('getCardId')
+ ->with($uri)
+ ->willThrowException(new \InvalidArgumentException());
+ $this->backend->expects($this->exactly(2))
+ ->method('addChange')
+ ->withConsecutive(
+ [$bookId, $uri, 1],
+ [$bookId, $uri, 3]
+ );
+ $this->backend->expects($this->never())
+ ->method('purgeProperties');
+
+ // create a card
+ $this->backend->createCard($bookId, $uri, '');
+
+ // delete the card
+ $this->assertTrue($this->backend->deleteCard($bookId, $uri));
+ }
+
public function testSyncSupport() {
+
+ $this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
+ ->setConstructorArgs([$this->db, $this->principal])
+ ->setMethods(['updateProperties'])->getMock();
+
// create a new address book
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
@@ -178,4 +310,303 @@ class CardDavBackendTest extends TestCase {
$changes = $this->backend->getChangesForAddressBook($bookId, $syncToken, 1);
$this->assertEquals($uri0, $changes['added'][0]);
}
+
+ public function testSharing() {
+ $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
+
+ $exampleBook = new AddressBook($this->backend, $books[0]);
+ $this->backend->updateShares($exampleBook, [['href' => 'principal:principals/best-friend']], []);
+
+ $shares = $this->backend->getShares($exampleBook->getResourceId());
+ $this->assertEquals(1, count($shares));
+
+ // adding the same sharee again has no effect
+ $this->backend->updateShares($exampleBook, [['href' => 'principal:principals/best-friend']], []);
+
+ $shares = $this->backend->getShares($exampleBook->getResourceId());
+ $this->assertEquals(1, count($shares));
+
+ $books = $this->backend->getAddressBooksForUser('principals/best-friend');
+ $this->assertEquals(1, count($books));
+
+ $this->backend->updateShares($exampleBook, [], ['principal:principals/best-friend']);
+
+ $shares = $this->backend->getShares($exampleBook->getResourceId());
+ $this->assertEquals(0, count($shares));
+
+ $books = $this->backend->getAddressBooksForUser('principals/best-friend');
+ $this->assertEquals(0, count($books));
+ }
+
+ public function testUpdateProperties() {
+
+ $bookId = 42;
+ $cardUri = 'card-uri';
+ $cardId = 2;
+
+ $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
+ ->setConstructorArgs([$this->db, $this->principal])
+ ->setMethods(['getCardId'])->getMock();
+
+ $backend->expects($this->any())->method('getCardId')->willReturn($cardId);
+
+ // add properties for new vCard
+ $vCard = new VCard();
+ $vCard->add(new Text($vCard, 'UID', $cardUri));
+ $vCard->add(new Text($vCard, 'FN', 'John Doe'));
+ $this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
+
+ $query = $this->db->getQueryBuilder();
+ $result = $query->select('*')->from('cards_properties')->execute()->fetchAll();
+
+ $this->assertSame(2, count($result));
+
+ $this->assertSame('UID', $result[0]['name']);
+ $this->assertSame($cardUri, $result[0]['value']);
+ $this->assertSame($bookId, (int)$result[0]['addressbookid']);
+ $this->assertSame($cardId, (int)$result[0]['cardid']);
+
+ $this->assertSame('FN', $result[1]['name']);
+ $this->assertSame('John Doe', $result[1]['value']);
+ $this->assertSame($bookId, (int)$result[1]['addressbookid']);
+ $this->assertSame($cardId, (int)$result[1]['cardid']);
+
+ // update properties for existing vCard
+ $vCard = new VCard();
+ $vCard->add(new Text($vCard, 'FN', 'John Doe'));
+ $this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
+
+ $query = $this->db->getQueryBuilder();
+ $result = $query->select('*')->from('cards_properties')->execute()->fetchAll();
+
+ $this->assertSame(1, count($result));
+
+ $this->assertSame('FN', $result[0]['name']);
+ $this->assertSame('John Doe', $result[0]['value']);
+ $this->assertSame($bookId, (int)$result[0]['addressbookid']);
+ $this->assertSame($cardId, (int)$result[0]['cardid']);
+ }
+
+ public function testPurgeProperties() {
+
+ $query = $this->db->getQueryBuilder();
+ $query->insert('cards_properties')
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter(1),
+ 'cardid' => $query->createNamedParameter(1),
+ 'name' => $query->createNamedParameter('name1'),
+ 'value' => $query->createNamedParameter('value1'),
+ 'preferred' => $query->createNamedParameter(0)
+ ]
+ );
+ $query->execute();
+
+ $query = $this->db->getQueryBuilder();
+ $query->insert('cards_properties')
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter(1),
+ 'cardid' => $query->createNamedParameter(2),
+ 'name' => $query->createNamedParameter('name2'),
+ 'value' => $query->createNamedParameter('value2'),
+ 'preferred' => $query->createNamedParameter(0)
+ ]
+ );
+ $query->execute();
+
+ $this->invokePrivate($this->backend, 'purgeProperties', [1, 1]);
+
+ $query = $this->db->getQueryBuilder();
+ $result = $query->select('*')->from('cards_properties')->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame(1 ,(int)$result[0]['addressbookid']);
+ $this->assertSame(2 ,(int)$result[0]['cardid']);
+
+ }
+
+ public function testGetCardId() {
+ $query = $this->db->getQueryBuilder();
+
+ $query->insert('cards')
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter(1),
+ 'carddata' => $query->createNamedParameter(''),
+ 'uri' => $query->createNamedParameter('uri'),
+ 'lastmodified' => $query->createNamedParameter(4738743),
+ 'etag' => $query->createNamedParameter('etag'),
+ 'size' => $query->createNamedParameter(120)
+ ]
+ );
+ $query->execute();
+ $id = $query->getLastInsertId();
+
+ $this->assertSame($id,
+ $this->invokePrivate($this->backend, 'getCardId', ['uri']));
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testGetCardIdFailed() {
+ $this->invokePrivate($this->backend, 'getCardId', ['uri']);
+ }
+
+ /**
+ * @dataProvider dataTestSearch
+ *
+ * @param string $pattern
+ * @param array $properties
+ * @param array $expected
+ */
+ public function testSearch($pattern, $properties, $expected) {
+ /** @var VCard $vCards */
+ $vCards = [];
+ $vCards[0] = new VCard();
+ $vCards[0]->add(new Text($vCards[0], 'UID', 'uid'));
+ $vCards[0]->add(new Text($vCards[0], 'FN', 'John Doe'));
+ $vCards[0]->add(new Text($vCards[0], 'CLOUD', 'john@owncloud.org'));
+ $vCards[1] = new VCard();
+ $vCards[1]->add(new Text($vCards[1], 'UID', 'uid'));
+ $vCards[1]->add(new Text($vCards[1], 'FN', 'John M. Doe'));
+
+ $vCardIds = [];
+ $query = $this->db->getQueryBuilder();
+ for($i=0; $i<2; $i++) {
+ $query->insert($this->dbCardsTable)
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter(0),
+ 'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), \PDO::PARAM_LOB),
+ 'uri' => $query->createNamedParameter('uri' . $i),
+ 'lastmodified' => $query->createNamedParameter(time()),
+ 'etag' => $query->createNamedParameter('etag' . $i),
+ 'size' => $query->createNamedParameter(120),
+ ]
+ );
+ $query->execute();
+ $vCardIds[] = $query->getLastInsertId();
+ }
+
+ $query->insert($this->dbCardsPropertiesTable)
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter(0),
+ 'cardid' => $query->createNamedParameter($vCardIds[0]),
+ 'name' => $query->createNamedParameter('FN'),
+ 'value' => $query->createNamedParameter('John Doe'),
+ 'preferred' => $query->createNamedParameter(0)
+ ]
+ );
+ $query->execute();
+ $query->insert($this->dbCardsPropertiesTable)
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter(0),
+ 'cardid' => $query->createNamedParameter($vCardIds[0]),
+ 'name' => $query->createNamedParameter('CLOUD'),
+ 'value' => $query->createNamedParameter('John@owncloud.org'),
+ 'preferred' => $query->createNamedParameter(0)
+ ]
+ );
+ $query->execute();
+ $query->insert($this->dbCardsPropertiesTable)
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter(0),
+ 'cardid' => $query->createNamedParameter($vCardIds[1]),
+ 'name' => $query->createNamedParameter('FN'),
+ 'value' => $query->createNamedParameter('John M. Doe'),
+ 'preferred' => $query->createNamedParameter(0)
+ ]
+ );
+ $query->execute();
+
+ $result = $this->backend->search(0, $pattern, $properties);
+
+ // check result
+ $this->assertSame(count($expected), count($result));
+ $found = [];
+ foreach ($result as $r) {
+ foreach ($expected as $exp) {
+ if (strpos($r, $exp) > 0) {
+ $found[$exp] = true;
+ break;
+ }
+ }
+ }
+
+ $this->assertSame(count($expected), count($found));
+ }
+
+ public function dataTestSearch() {
+ return [
+ ['John', ['FN'], ['John Doe', 'John M. Doe']],
+ ['M. Doe', ['FN'], ['John M. Doe']],
+ ['Do', ['FN'], ['John Doe', 'John M. Doe']],
+ // check if duplicates are handled correctly
+ ['John', ['FN', 'CLOUD'], ['John Doe', 'John M. Doe']],
+ ];
+ }
+
+ public function testGetCardUri() {
+ $query = $this->db->getQueryBuilder();
+ $query->insert($this->dbCardsTable)
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter(1),
+ 'carddata' => $query->createNamedParameter('carddata', \PDO::PARAM_LOB),
+ 'uri' => $query->createNamedParameter('uri'),
+ 'lastmodified' => $query->createNamedParameter(5489543),
+ 'etag' => $query->createNamedParameter('etag'),
+ 'size' => $query->createNamedParameter(120),
+ ]
+ );
+ $query->execute();
+
+ $id = $query->getLastInsertId();
+
+ $this->assertSame('uri', $this->backend->getCardUri($id));
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testGetCardUriFailed() {
+ $this->backend->getCardUri(1);
+ }
+
+ public function testGetContact() {
+ $query = $this->db->getQueryBuilder();
+ for($i=0; $i<2; $i++) {
+ $query->insert($this->dbCardsTable)
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter($i),
+ 'carddata' => $query->createNamedParameter('carddata' . $i, \PDO::PARAM_LOB),
+ 'uri' => $query->createNamedParameter('uri' . $i),
+ 'lastmodified' => $query->createNamedParameter(5489543),
+ 'etag' => $query->createNamedParameter('etag' . $i),
+ 'size' => $query->createNamedParameter(120),
+ ]
+ );
+ $query->execute();
+ }
+
+ $result = $this->backend->getContact('uri0');
+ $this->assertSame(7, count($result));
+ $this->assertSame(0, (int)$result['addressbookid']);
+ $this->assertSame('uri0', $result['uri']);
+ $this->assertSame(5489543, (int)$result['lastmodified']);
+ $this->assertSame('etag0', $result['etag']);
+ $this->assertSame(120, (int)$result['size']);
+ }
+
+ public function testGetContactFail() {
+ $this->assertEmpty($this->backend->getContact('uri'));
+ }
+
}
diff --git a/apps/dav/tests/unit/carddav/contactsmanagertest.php b/apps/dav/tests/unit/carddav/contactsmanagertest.php
new file mode 100644
index 00000000000..5a384550df5
--- /dev/null
+++ b/apps/dav/tests/unit/carddav/contactsmanagertest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\CardDAV;
+
+use OCA\DAV\CardDAV\CardDavBackend;
+use OCA\DAV\CardDAV\ContactsManager;
+use OCP\Contacts\IManager;
+use Test\TestCase;
+
+class ContactsManagerTest extends TestCase {
+ public function test() {
+ /** @var IManager | \PHPUnit_Framework_MockObject_MockObject $cm */
+ $cm = $this->getMockBuilder('OCP\Contacts\IManager')->disableOriginalConstructor()->getMock();
+ $cm->expects($this->exactly(2))->method('registerAddressBook');
+ /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $backEnd */
+ $backEnd = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock();
+ $backEnd->method('getAddressBooksForUser')->willReturn([
+ []
+ ]);
+
+ $app = new ContactsManager($backEnd);
+ $app->setupContactsProvider($cm, 'user01');
+ }
+}
diff --git a/apps/dav/tests/unit/carddav/convertertest.php b/apps/dav/tests/unit/carddav/convertertest.php
new file mode 100644
index 00000000000..ba71b75686a
--- /dev/null
+++ b/apps/dav/tests/unit/carddav/convertertest.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit;
+
+use OCA\DAV\CardDAV\Converter;
+use Test\TestCase;
+
+class ConverterTests extends TestCase {
+
+ /**
+ * @dataProvider providesNewUsers
+ */
+ public function testCreation($expectedVCard, $displayName = null, $eMailAddress = null, $cloudId = null) {
+ $user = $this->getUserMock($displayName, $eMailAddress, $cloudId);
+
+ $converter = new Converter();
+ $vCard = $converter->createCardFromUser($user);
+ $cardData = $vCard->serialize();
+
+ $this->assertEquals($expectedVCard, $cardData);
+ }
+
+ public function providesNewUsers() {
+ return [
+ ["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nPHOTO;ENCODING=b;TYPE=JPEG:MTIzNDU2Nzg5\r\nEND:VCARD\r\n"],
+ ["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:Dr. Foo Bar\r\nN:Bar;Dr.;Foo;;\r\nPHOTO;ENCODING=b;TYPE=JPEG:MTIzNDU2Nzg5\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
+ ["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:Dr. Foo Bar\r\nN:Bar;Dr.;Foo;;\r\nEMAIL;TYPE=OTHER:foo@bar.net\r\nPHOTO;ENCODING=b;TYPE=JPEG:MTIzNDU2Nzg5\r\nEND:VCARD\r\n", "Dr. Foo Bar", "foo@bar.net"],
+ ["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:Dr. Foo Bar\r\nN:Bar;Dr.;Foo;;\r\nCLOUD:foo@bar.net\r\nPHOTO;ENCODING=b;TYPE=JPEG:MTIzNDU2Nzg5\r\nEND:VCARD\r\n", "Dr. Foo Bar", null, "foo@bar.net"],
+ ];
+ }
+
+ /**
+ * @dataProvider providesNewUsers
+ */
+ public function testUpdateOfUnchangedUser($expectedVCard, $displayName = null, $eMailAddress = null, $cloudId = null) {
+ $user = $this->getUserMock($displayName, $eMailAddress, $cloudId);
+
+ $converter = new Converter();
+ $vCard = $converter->createCardFromUser($user);
+ $updated = $converter->updateCard($vCard, $user);
+ $this->assertFalse($updated);
+ $cardData = $vCard->serialize();
+
+ $this->assertEquals($expectedVCard, $cardData);
+ }
+
+ /**
+ * @dataProvider providesUsersForUpdateOfRemovedElement
+ */
+ public function testUpdateOfRemovedElement($expectedVCard, $displayName = null, $eMailAddress = null, $cloudId = null) {
+ $user = $this->getUserMock($displayName, $eMailAddress, $cloudId);
+
+ $converter = new Converter();
+ $vCard = $converter->createCardFromUser($user);
+
+ $user1 = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock();
+ $user1->method('getUID')->willReturn('12345');
+ $user1->method('getDisplayName')->willReturn(null);
+ $user1->method('getEMailAddress')->willReturn(null);
+ $user1->method('getCloudId')->willReturn(null);
+ $user1->method('getAvatarImage')->willReturn(null);
+
+ $updated = $converter->updateCard($vCard, $user1);
+ $this->assertTrue($updated);
+ $cardData = $vCard->serialize();
+
+ $this->assertEquals($expectedVCard, $cardData);
+ }
+
+ public function providesUsersForUpdateOfRemovedElement() {
+ return [
+ ["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
+ ["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar", "foo@bar.net"],
+ ["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar", null, "foo@bar.net"],
+ ];
+ }
+
+ /**
+ * @dataProvider providesNames
+ * @param $expected
+ * @param $fullName
+ */
+ public function testNameSplitter($expected, $fullName) {
+
+ $converter = new Converter();
+ $r = $converter->splitFullName($fullName);
+ $r = implode(';', $r);
+ $this->assertEquals($expected, $r);
+ }
+
+ public function providesNames() {
+ return [
+ ['Sauron;;;;', 'Sauron'],
+ ['Baggins;Bilbo;;;', 'Bilbo Baggins'],
+ ['Tolkien;John;Ronald Reuel;;', 'John Ronald Reuel Tolkien'],
+ ];
+ }
+
+ /**
+ * @param $displayName
+ * @param $eMailAddress
+ * @param $cloudId
+ * @return \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected function getUserMock($displayName, $eMailAddress, $cloudId) {
+ $image0 = $this->getMockBuilder('OCP\IImage')->disableOriginalConstructor()->getMock();
+ $image0->method('mimeType')->willReturn('JPEG');
+ $image0->method('data')->willReturn('123456789');
+ $user = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock();
+ $user->method('getUID')->willReturn('12345');
+ $user->method('getDisplayName')->willReturn($displayName);
+ $user->method('getEMailAddress')->willReturn($eMailAddress);
+ $user->method('getCloudId')->willReturn($cloudId);
+ $user->method('getAvatarImage')->willReturn($image0);
+ return $user;
+ }
+}
diff --git a/apps/dav/tests/unit/carddav/sharing/plugintest.php b/apps/dav/tests/unit/carddav/sharing/plugintest.php
new file mode 100644
index 00000000000..f7159c2d22d
--- /dev/null
+++ b/apps/dav/tests/unit/carddav/sharing/plugintest.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\CardDAV;
+
+
+use OCA\DAV\DAV\Sharing\IShareable;
+use OCA\DAV\DAV\Sharing\Plugin;
+use OCA\DAV\Connector\Sabre\Auth;
+use OCP\IRequest;
+use Sabre\DAV\Server;
+use Sabre\DAV\SimpleCollection;
+use Sabre\HTTP\Request;
+use Sabre\HTTP\Response;
+use Test\TestCase;
+
+class PluginTest extends TestCase {
+
+ /** @var Plugin */
+ private $plugin;
+ /** @var Server */
+ private $server;
+ /** @var IShareable | \PHPUnit_Framework_MockObject_MockObject */
+ private $book;
+
+ public function setUp() {
+ parent::setUp();
+
+ /** @var Auth | \PHPUnit_Framework_MockObject_MockObject $authBackend */
+ $authBackend = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Auth')->disableOriginalConstructor()->getMock();
+ $authBackend->method('isDavAuthenticated')->willReturn(true);
+
+ /** @var IRequest $request */
+ $request = $this->getMockBuilder('OCP\IRequest')->disableOriginalConstructor()->getMock();
+ $this->plugin = new Plugin($authBackend, $request);
+
+ $root = new SimpleCollection('root');
+ $this->server = new \Sabre\DAV\Server($root);
+ /** @var SimpleCollection $node */
+ $this->book = $this->getMockBuilder('OCA\DAV\DAV\Sharing\IShareable')->disableOriginalConstructor()->getMock();
+ $this->book->method('getName')->willReturn('addressbook1.vcf');
+ $root->addChild($this->book);
+ $this->plugin->initialize($this->server);
+ }
+
+ public function testSharing() {
+
+ $this->book->expects($this->once())->method('updateShares')->with([[
+ 'href' => 'principal:principals/admin',
+ 'commonName' => null,
+ 'summary' => null,
+ 'readOnly' => false
+ ]], ['mailto:wilfredo@example.com']);
+
+ // setup request
+ $request = new Request();
+ $request->addHeader('Content-Type', 'application/xml');
+ $request->setUrl('addressbook1.vcf');
+ $request->setBody('<?xml version="1.0" encoding="utf-8" ?><CS:share xmlns:D="DAV:" xmlns:CS="http://owncloud.org/ns"><CS:set><D:href>principal:principals/admin</D:href><CS:read-write/></CS:set> <CS:remove><D:href>mailto:wilfredo@example.com</D:href></CS:remove></CS:share>');
+ $response = new Response();
+ $this->plugin->httpPost($request, $response);
+ }
+}
diff --git a/apps/dav/tests/unit/carddav/syncservicetest.php b/apps/dav/tests/unit/carddav/syncservicetest.php
new file mode 100644
index 00000000000..a6af98f7e8c
--- /dev/null
+++ b/apps/dav/tests/unit/carddav/syncservicetest.php
@@ -0,0 +1,138 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\CardDAV;
+
+use OCP\IUser;
+use OCP\IUserManager;
+use Test\TestCase;
+
+class SyncServiceTest extends TestCase {
+ public function testEmptySync() {
+ $backend = $this->getBackendMock(0, 0, 0);
+
+ $ss = $this->getSyncServiceMock($backend, []);
+ $return = $ss->syncRemoteAddressBook('', 'system', '1234567890', null, '1', 'principals/system/system', []);
+ $this->assertEquals('sync-token-1', $return);
+ }
+
+ public function testSyncWithNewElement() {
+ $backend = $this->getBackendMock(1, 0, 0);
+ $backend->method('getCard')->willReturn(false);
+
+ $ss = $this->getSyncServiceMock($backend, ['0' => [200 => '']]);
+ $return = $ss->syncRemoteAddressBook('', 'system', '1234567890', null, '1', 'principals/system/system', []);
+ $this->assertEquals('sync-token-1', $return);
+ }
+
+ public function testSyncWithUpdatedElement() {
+ $backend = $this->getBackendMock(0, 1, 0);
+ $backend->method('getCard')->willReturn(true);
+
+ $ss = $this->getSyncServiceMock($backend, ['0' => [200 => '']]);
+ $return = $ss->syncRemoteAddressBook('', 'system', '1234567890', null, '1', 'principals/system/system', []);
+ $this->assertEquals('sync-token-1', $return);
+ }
+
+ public function testSyncWithDeletedElement() {
+ $backend = $this->getBackendMock(0, 0, 1);
+
+ $ss = $this->getSyncServiceMock($backend, ['0' => [404 => '']]);
+ $return = $ss->syncRemoteAddressBook('', 'system', '1234567890', null, '1', 'principals/system/system', []);
+ $this->assertEquals('sync-token-1', $return);
+ }
+
+ public function testEnsureSystemAddressBookExists() {
+ /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $backend */
+ $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDAVBackend')->disableOriginalConstructor()->getMock();
+ $backend->expects($this->exactly(1))->method('createAddressBook');
+ $backend->expects($this->at(0))->method('getAddressBooksByUri')->willReturn(null);
+ $backend->expects($this->at(1))->method('getAddressBooksByUri')->willReturn([]);
+
+ /** @var IUserManager $userManager */
+ $userManager = $this->getMockBuilder('OCP\IUserManager')->disableOriginalConstructor()->getMock();
+ $ss = new SyncService($backend, $userManager);
+ $book = $ss->ensureSystemAddressBookExists('principals/users/adam', 'contacts', []);
+ }
+
+ public function testUpdateAndDeleteUser() {
+ /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $backend */
+ $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDAVBackend')->disableOriginalConstructor()->getMock();
+
+ $backend->expects($this->once())->method('createCard');
+ $backend->expects($this->once())->method('updateCard');
+ $backend->expects($this->once())->method('deleteCard');
+
+ $backend->method('getCard')->willReturnOnConsecutiveCalls(false, [
+ 'carddata' => "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.8//EN\r\nUID:test-user\r\nFN:test-user\r\nN:test-user;;;;\r\nEND:VCARD\r\n\r\n"
+ ]);
+
+ /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject $userManager */
+ $userManager = $this->getMockBuilder('OCP\IUserManager')->disableOriginalConstructor()->getMock();
+
+ /** @var IUser | \PHPUnit_Framework_MockObject_MockObject $user */
+ $user = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock();
+ $user->method('getBackendClassName')->willReturn('unittest');
+ $user->method('getUID')->willReturn('test-user');
+
+ $ss = new SyncService($backend, $userManager);
+ $ss->updateUser($user);
+
+ $user->method('getDisplayName')->willReturn('A test user for unit testing');
+
+ $ss->updateUser($user);
+
+ $ss->deleteUser($user);
+ }
+
+ /**
+ * @param int $createCount
+ * @param int $updateCount
+ * @param int $deleteCount
+ * @return \PHPUnit_Framework_MockObject_MockObject
+ */
+ private function getBackendMock($createCount, $updateCount, $deleteCount) {
+ $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDAVBackend')->disableOriginalConstructor()->getMock();
+ $backend->expects($this->exactly($createCount))->method('createCard');
+ $backend->expects($this->exactly($updateCount))->method('updateCard');
+ $backend->expects($this->exactly($deleteCount))->method('deleteCard');
+ return $backend;
+ }
+
+ /**
+ * @param $backend
+ * @param $response
+ * @return SyncService|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private function getSyncServiceMock($backend, $response) {
+ $userManager = $this->getMockBuilder('OCP\IUserManager')->disableOriginalConstructor()->getMock();
+ /** @var SyncService | \PHPUnit_Framework_MockObject_MockObject $ss */
+ $ss = $this->getMock('OCA\DAV\CardDAV\SyncService', ['ensureSystemAddressBookExists', 'requestSyncReport', 'download'], [$backend, $userManager]);
+ $ss->method('requestSyncReport')->withAnyParameters()->willReturn(['response' => $response, 'token' => 'sync-token-1']);
+ $ss->method('ensureSystemAddressBookExists')->willReturn(['id' => 1]);
+ $ss->method('download')->willReturn([
+ 'body' => '',
+ 'statusCode' => 200,
+ 'headers' => []
+ ]);
+ return $ss;
+ }
+
+}
diff --git a/apps/dav/tests/unit/comments/commentnode.php b/apps/dav/tests/unit/comments/commentnode.php
new file mode 100644
index 00000000000..8d1bf06ab60
--- /dev/null
+++ b/apps/dav/tests/unit/comments/commentnode.php
@@ -0,0 +1,420 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\Comments;
+
+use OCA\DAV\Comments\CommentNode;
+
+class CommentsNode extends \Test\TestCase {
+
+ protected $commentsManager;
+ protected $comment;
+ protected $node;
+ protected $userManager;
+ protected $logger;
+ protected $userSession;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->commentsManager = $this->getMock('\OCP\Comments\ICommentsManager');
+ $this->comment = $this->getMock('\OCP\Comments\IComment');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+ $this->userSession = $this->getMock('\OCP\IUserSession');
+ $this->logger = $this->getMock('\OCP\ILogger');
+
+ $this->node = new CommentNode(
+ $this->commentsManager,
+ $this->comment,
+ $this->userManager,
+ $this->userSession,
+ $this->logger
+ );
+ }
+
+ public function testDelete() {
+ $user = $this->getMock('\OCP\IUser');
+
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->comment->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue('19'));
+
+ $this->comment->expects($this->any())
+ ->method('getActorType')
+ ->will($this->returnValue('users'));
+
+ $this->comment->expects($this->any())
+ ->method('getActorId')
+ ->will($this->returnValue('alice'));
+
+ $this->commentsManager->expects($this->once())
+ ->method('delete')
+ ->with('19');
+
+ $this->node->delete();
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testDeleteForbidden() {
+ $user = $this->getMock('\OCP\IUser');
+
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('mallory'));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->comment->expects($this->never())
+ ->method('getId');
+
+ $this->comment->expects($this->any())
+ ->method('getActorType')
+ ->will($this->returnValue('users'));
+
+ $this->comment->expects($this->any())
+ ->method('getActorId')
+ ->will($this->returnValue('alice'));
+
+ $this->commentsManager->expects($this->never())
+ ->method('delete');
+
+ $this->node->delete();
+ }
+
+ public function testGetName() {
+ $id = '19';
+ $this->comment->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue($id));
+
+ $this->assertSame($this->node->getName(), $id);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\MethodNotAllowed
+ */
+ public function testSetName() {
+ $this->node->setName('666');
+ }
+
+ public function testGetLastModified() {
+ $this->assertSame($this->node->getLastModified(), null);
+ }
+
+ public function testUpdateComment() {
+ $msg = 'Hello Earth';
+
+ $user = $this->getMock('\OCP\IUser');
+
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->comment->expects($this->once())
+ ->method('setMessage')
+ ->with($msg);
+
+ $this->comment->expects($this->any())
+ ->method('getActorType')
+ ->will($this->returnValue('users'));
+
+ $this->comment->expects($this->any())
+ ->method('getActorId')
+ ->will($this->returnValue('alice'));
+
+ $this->commentsManager->expects($this->once())
+ ->method('save')
+ ->with($this->comment);
+
+ $this->assertTrue($this->node->updateComment($msg));
+ }
+
+ public function testUpdateCommentLogException() {
+ $msg = null;
+
+ $user = $this->getMock('\OCP\IUser');
+
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->comment->expects($this->once())
+ ->method('setMessage')
+ ->with($msg)
+ ->will($this->throwException(new \Exception('buh!')));
+
+ $this->comment->expects($this->any())
+ ->method('getActorType')
+ ->will($this->returnValue('users'));
+
+ $this->comment->expects($this->any())
+ ->method('getActorId')
+ ->will($this->returnValue('alice'));
+
+ $this->commentsManager->expects($this->never())
+ ->method('save');
+
+ $this->logger->expects($this->once())
+ ->method('logException');
+
+ $this->assertFalse($this->node->updateComment($msg));
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testUpdateForbiddenByUser() {
+ $msg = 'HaXX0r';
+
+ $user = $this->getMock('\OCP\IUser');
+
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('mallory'));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->comment->expects($this->never())
+ ->method('setMessage');
+
+ $this->comment->expects($this->any())
+ ->method('getActorType')
+ ->will($this->returnValue('users'));
+
+ $this->comment->expects($this->any())
+ ->method('getActorId')
+ ->will($this->returnValue('alice'));
+
+ $this->commentsManager->expects($this->never())
+ ->method('save');
+
+ $this->node->updateComment($msg);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testUpdateForbiddenByType() {
+ $msg = 'HaXX0r';
+
+ $user = $this->getMock('\OCP\IUser');
+
+ $user->expects($this->never())
+ ->method('getUID');
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->comment->expects($this->never())
+ ->method('setMessage');
+
+ $this->comment->expects($this->any())
+ ->method('getActorType')
+ ->will($this->returnValue('bots'));
+
+ $this->commentsManager->expects($this->never())
+ ->method('save');
+
+ $this->node->updateComment($msg);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testUpdateForbiddenByNotLoggedIn() {
+ $msg = 'HaXX0r';
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue(null));
+
+ $this->comment->expects($this->never())
+ ->method('setMessage');
+
+ $this->comment->expects($this->any())
+ ->method('getActorType')
+ ->will($this->returnValue('users'));
+
+ $this->commentsManager->expects($this->never())
+ ->method('save');
+
+ $this->node->updateComment($msg);
+ }
+
+ public function testPropPatch() {
+ $propPatch = $this->getMockBuilder('Sabre\DAV\PropPatch')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $propPatch->expects($this->once())
+ ->method('handle')
+ ->with('{http://owncloud.org/ns}message');
+
+ $this->node->propPatch($propPatch);
+ }
+
+ public function testGetProperties() {
+ $ns = '{http://owncloud.org/ns}';
+ $expected = [
+ $ns . 'id' => '123',
+ $ns . 'parentId' => '12',
+ $ns . 'topmostParentId' => '2',
+ $ns . 'childrenCount' => 3,
+ $ns . 'message' => 'such a nice file you have…',
+ $ns . 'verb' => 'comment',
+ $ns . 'actorType' => 'users',
+ $ns . 'actorId' => 'alice',
+ $ns . 'actorDisplayName' => 'Alice of Wonderland',
+ $ns . 'creationDateTime' => new \DateTime('2016-01-10 18:48:00'),
+ $ns . 'latestChildDateTime' => new \DateTime('2016-01-12 18:48:00'),
+ $ns . 'objectType' => 'files',
+ $ns . 'objectId' => '1848',
+ $ns . 'isUnread' => null,
+ ];
+
+ $this->comment->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue($expected[$ns . 'id']));
+
+ $this->comment->expects($this->once())
+ ->method('getParentId')
+ ->will($this->returnValue($expected[$ns . 'parentId']));
+
+ $this->comment->expects($this->once())
+ ->method('getTopmostParentId')
+ ->will($this->returnValue($expected[$ns . 'topmostParentId']));
+
+ $this->comment->expects($this->once())
+ ->method('getChildrenCount')
+ ->will($this->returnValue($expected[$ns . 'childrenCount']));
+
+ $this->comment->expects($this->once())
+ ->method('getMessage')
+ ->will($this->returnValue($expected[$ns . 'message']));
+
+ $this->comment->expects($this->once())
+ ->method('getVerb')
+ ->will($this->returnValue($expected[$ns . 'verb']));
+
+ $this->comment->expects($this->exactly(2))
+ ->method('getActorType')
+ ->will($this->returnValue($expected[$ns . 'actorType']));
+
+ $this->comment->expects($this->exactly(2))
+ ->method('getActorId')
+ ->will($this->returnValue($expected[$ns . 'actorId']));
+
+ $this->comment->expects($this->once())
+ ->method('getCreationDateTime')
+ ->will($this->returnValue($expected[$ns . 'creationDateTime']));
+
+ $this->comment->expects($this->once())
+ ->method('getLatestChildDateTime')
+ ->will($this->returnValue($expected[$ns . 'latestChildDateTime']));
+
+ $this->comment->expects($this->once())
+ ->method('getObjectType')
+ ->will($this->returnValue($expected[$ns . 'objectType']));
+
+ $this->comment->expects($this->once())
+ ->method('getObjectId')
+ ->will($this->returnValue($expected[$ns . 'objectId']));
+
+ $user = $this->getMockBuilder('\OCP\IUser')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user->expects($this->once())
+ ->method('getDisplayName')
+ ->will($this->returnValue($expected[$ns . 'actorDisplayName']));
+
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('alice')
+ ->will($this->returnValue($user));
+
+ $properties = $this->node->getProperties(null);
+
+ foreach($properties as $name => $value) {
+ $this->assertTrue(array_key_exists($name, $expected));
+ $this->assertSame($expected[$name], $value);
+ unset($expected[$name]);
+ }
+ $this->assertTrue(empty($expected));
+ }
+
+ public function readCommentProvider() {
+ $creationDT = new \DateTime('2016-01-19 18:48:00');
+ $diff = new \DateInterval('PT2H');
+ $readDT1 = clone $creationDT; $readDT1->sub($diff);
+ $readDT2 = clone $creationDT; $readDT2->add($diff);
+ return [
+ [$creationDT, $readDT1, 'true'],
+ [$creationDT, $readDT2, 'false'],
+ [$creationDT, null, 'true'],
+ ];
+ }
+
+ /**
+ * @dataProvider readCommentProvider
+ * @param $expected
+ */
+ public function testGetPropertiesUnreadProperty($creationDT, $readDT, $expected) {
+ $this->comment->expects($this->any())
+ ->method('getCreationDateTime')
+ ->will($this->returnValue($creationDT));
+
+ $this->commentsManager->expects($this->once())
+ ->method('getReadMark')
+ ->will($this->returnValue($readDT));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($this->getMock('\OCP\IUser')));
+
+ $properties = $this->node->getProperties(null);
+
+ $this->assertTrue(array_key_exists(CommentNode::PROPERTY_NAME_UNREAD, $properties));
+ $this->assertSame($properties[CommentNode::PROPERTY_NAME_UNREAD], $expected);
+ }
+}
diff --git a/apps/dav/tests/unit/comments/commentsplugin.php b/apps/dav/tests/unit/comments/commentsplugin.php
new file mode 100644
index 00000000000..bd0b56fc650
--- /dev/null
+++ b/apps/dav/tests/unit/comments/commentsplugin.php
@@ -0,0 +1,654 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\Comments;
+
+use OC\Comments\Comment;
+use OCA\DAV\Comments\CommentsPlugin as CommentsPluginImplementation;
+use Sabre\DAV\Exception\NotFound;
+
+class CommentsPlugin extends \Test\TestCase {
+ /** @var \Sabre\DAV\Server */
+ private $server;
+
+ /** @var \Sabre\DAV\Tree */
+ private $tree;
+
+ /** @var \OCP\Comments\ICommentsManager */
+ private $commentsManager;
+
+ /** @var \OCP\IUserSession */
+ private $userSession;
+
+ /** @var CommentsPluginImplementation */
+ private $plugin;
+
+ public function setUp() {
+ parent::setUp();
+ $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->server = $this->getMockBuilder('\Sabre\DAV\Server')
+ ->setConstructorArgs([$this->tree])
+ ->setMethods(['getRequestUri'])
+ ->getMock();
+
+ $this->commentsManager = $this->getMock('\OCP\Comments\ICommentsManager');
+ $this->userSession = $this->getMock('\OCP\IUserSession');
+
+ $this->plugin = new CommentsPluginImplementation($this->commentsManager, $this->userSession);
+ }
+
+ public function testCreateComment() {
+ $commentData = [
+ 'actorType' => 'users',
+ 'verb' => 'comment',
+ 'message' => 'my first comment',
+ ];
+
+ $comment = new Comment([
+ 'objectType' => 'files',
+ 'objectId' => '42',
+ 'actorType' => 'users',
+ 'actorId' => 'alice'
+ ] + $commentData);
+ $comment->setId('23');
+
+ $path = 'comments/files/42';
+
+ $requestData = json_encode($commentData);
+
+ $user = $this->getMock('OCP\IUser');
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $node = $this->getMockBuilder('\OCA\DAV\Comments\EntityCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('files'));
+ $node->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue('42'));
+
+ $this->commentsManager->expects($this->once())
+ ->method('create')
+ ->with('users', 'alice', 'files', '42')
+ ->will($this->returnValue($comment));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ // technically, this is a shortcut. Inbetween EntityTypeCollection would
+ // be returned, but doing it exactly right would not be really
+ // unit-testing like, as it would require to haul in a lot of other
+ // things.
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($node));
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/' . $path));
+
+ $request->expects($this->once())
+ ->method('getBodyAsString')
+ ->will($this->returnValue($requestData));
+
+ $request->expects($this->once())
+ ->method('getHeader')
+ ->with('Content-Type')
+ ->will($this->returnValue('application/json'));
+
+ $request->expects($this->once())
+ ->method('getUrl')
+ ->will($this->returnValue('http://example.com/dav/' . $path));
+
+ $response->expects($this->once())
+ ->method('setHeader')
+ ->with('Content-Location', 'http://example.com/dav/' . $path . '/23');
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotFound
+ */
+ public function testCreateCommentInvalidObject() {
+ $commentData = [
+ 'actorType' => 'users',
+ 'verb' => 'comment',
+ 'message' => 'my first comment',
+ ];
+
+ $comment = new Comment([
+ 'objectType' => 'files',
+ 'objectId' => '666',
+ 'actorType' => 'users',
+ 'actorId' => 'alice'
+ ] + $commentData);
+ $comment->setId('23');
+
+ $path = 'comments/files/666';
+
+ $user = $this->getMock('OCP\IUser');
+ $user->expects($this->never())
+ ->method('getUID');
+
+ $node = $this->getMockBuilder('\OCA\DAV\Comments\EntityCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->never())
+ ->method('getName');
+ $node->expects($this->never())
+ ->method('getId');
+
+ $this->commentsManager->expects($this->never())
+ ->method('create');
+
+ $this->userSession->expects($this->never())
+ ->method('getUser');
+
+ // technically, this is a shortcut. Inbetween EntityTypeCollection would
+ // be returned, but doing it exactly right would not be really
+ // unit-testing like, as it would require to haul in a lot of other
+ // things.
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->throwException(new \Sabre\DAV\Exception\NotFound()));
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/' . $path));
+
+ $request->expects($this->never())
+ ->method('getBodyAsString');
+
+ $request->expects($this->never())
+ ->method('getHeader')
+ ->with('Content-Type');
+
+ $request->expects($this->never())
+ ->method('getUrl');
+
+ $response->expects($this->never())
+ ->method('setHeader');
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\BadRequest
+ */
+ public function testCreateCommentInvalidActor() {
+ $commentData = [
+ 'actorType' => 'robots',
+ 'verb' => 'comment',
+ 'message' => 'my first comment',
+ ];
+
+ $comment = new Comment([
+ 'objectType' => 'files',
+ 'objectId' => '42',
+ 'actorType' => 'users',
+ 'actorId' => 'alice'
+ ] + $commentData);
+ $comment->setId('23');
+
+ $path = 'comments/files/42';
+
+ $requestData = json_encode($commentData);
+
+ $user = $this->getMock('OCP\IUser');
+ $user->expects($this->never())
+ ->method('getUID');
+
+ $node = $this->getMockBuilder('\OCA\DAV\Comments\EntityCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('files'));
+ $node->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue('42'));
+
+ $this->commentsManager->expects($this->never())
+ ->method('create');
+
+ $this->userSession->expects($this->never())
+ ->method('getUser');
+
+ // technically, this is a shortcut. Inbetween EntityTypeCollection would
+ // be returned, but doing it exactly right would not be really
+ // unit-testing like, as it would require to haul in a lot of other
+ // things.
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($node));
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/' . $path));
+
+ $request->expects($this->once())
+ ->method('getBodyAsString')
+ ->will($this->returnValue($requestData));
+
+ $request->expects($this->once())
+ ->method('getHeader')
+ ->with('Content-Type')
+ ->will($this->returnValue('application/json'));
+
+ $request->expects($this->never())
+ ->method('getUrl');
+
+ $response->expects($this->never())
+ ->method('setHeader');
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\UnsupportedMediaType
+ */
+ public function testCreateCommentUnsupportedMediaType() {
+ $commentData = [
+ 'actorType' => 'users',
+ 'verb' => 'comment',
+ 'message' => 'my first comment',
+ ];
+
+ $comment = new Comment([
+ 'objectType' => 'files',
+ 'objectId' => '42',
+ 'actorType' => 'users',
+ 'actorId' => 'alice'
+ ] + $commentData);
+ $comment->setId('23');
+
+ $path = 'comments/files/42';
+
+ $requestData = json_encode($commentData);
+
+ $user = $this->getMock('OCP\IUser');
+ $user->expects($this->never())
+ ->method('getUID');
+
+ $node = $this->getMockBuilder('\OCA\DAV\Comments\EntityCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('files'));
+ $node->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue('42'));
+
+ $this->commentsManager->expects($this->never())
+ ->method('create');
+
+ $this->userSession->expects($this->never())
+ ->method('getUser');
+
+ // technically, this is a shortcut. Inbetween EntityTypeCollection would
+ // be returned, but doing it exactly right would not be really
+ // unit-testing like, as it would require to haul in a lot of other
+ // things.
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($node));
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/' . $path));
+
+ $request->expects($this->once())
+ ->method('getBodyAsString')
+ ->will($this->returnValue($requestData));
+
+ $request->expects($this->once())
+ ->method('getHeader')
+ ->with('Content-Type')
+ ->will($this->returnValue('application/trumpscript'));
+
+ $request->expects($this->never())
+ ->method('getUrl');
+
+ $response->expects($this->never())
+ ->method('setHeader');
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\BadRequest
+ */
+ public function testCreateCommentInvalidPayload() {
+ $commentData = [
+ 'actorType' => 'users',
+ 'verb' => '',
+ 'message' => '',
+ ];
+
+ $comment = new Comment([
+ 'objectType' => 'files',
+ 'objectId' => '42',
+ 'actorType' => 'users',
+ 'actorId' => 'alice',
+ 'message' => 'dummy',
+ 'verb' => 'dummy'
+ ]);
+ $comment->setId('23');
+
+ $path = 'comments/files/42';
+
+ $requestData = json_encode($commentData);
+
+ $user = $this->getMock('OCP\IUser');
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $node = $this->getMockBuilder('\OCA\DAV\Comments\EntityCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('files'));
+ $node->expects($this->once())
+ ->method('getId')
+ ->will($this->returnValue('42'));
+
+ $this->commentsManager->expects($this->once())
+ ->method('create')
+ ->with('users', 'alice', 'files', '42')
+ ->will($this->returnValue($comment));
+
+ $this->commentsManager->expects($this->any())
+ ->method('setMessage')
+ ->with('')
+ ->will($this->throwException(new \InvalidArgumentException()));
+
+ $this->commentsManager->expects($this->any())
+ ->method('setVerb')
+ ->with('')
+ ->will($this->throwException(new \InvalidArgumentException()));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ // technically, this is a shortcut. Inbetween EntityTypeCollection would
+ // be returned, but doing it exactly right would not be really
+ // unit-testing like, as it would require to haul in a lot of other
+ // things.
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($node));
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/' . $path));
+
+ $request->expects($this->once())
+ ->method('getBodyAsString')
+ ->will($this->returnValue($requestData));
+
+ $request->expects($this->once())
+ ->method('getHeader')
+ ->with('Content-Type')
+ ->will($this->returnValue('application/json'));
+
+ $request->expects($this->never())
+ ->method('getUrl');
+
+ $response->expects($this->never())
+ ->method('setHeader');
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\ReportNotSupported
+ */
+ public function testOnReportInvalidNode() {
+ $path = 'totally/unrelated/13';
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($this->getMock('\Sabre\DAV\INode')));
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->onReport(CommentsPluginImplementation::REPORT_NAME, [], '/' . $path);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\ReportNotSupported
+ */
+ public function testOnReportInvalidReportName() {
+ $path = 'comments/files/42';
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($this->getMock('\Sabre\DAV\INode')));
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->onReport('{whoever}whatever', [], '/' . $path);
+ }
+
+ public function testOnReportDateTimeEmpty() {
+ $path = 'comments/files/42';
+
+ $parameters = [
+ [
+ 'name' => '{http://owncloud.org/ns}limit',
+ 'value' => 5,
+ ],
+ [
+ 'name' => '{http://owncloud.org/ns}offset',
+ 'value' => 10,
+ ],
+ [
+ 'name' => '{http://owncloud.org/ns}datetime',
+ 'value' => '',
+ ]
+ ];
+
+ $node = $this->getMockBuilder('\OCA\DAV\Comments\EntityCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->once())
+ ->method('findChildren')
+ ->with(5, 10, null)
+ ->will($this->returnValue([]));
+
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response->expects($this->once())
+ ->method('setHeader')
+ ->with('Content-Type', 'application/xml; charset=utf-8');
+
+ $response->expects($this->once())
+ ->method('setStatus')
+ ->with(207);
+
+ $response->expects($this->once())
+ ->method('setBody');
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($node));
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->server->httpResponse = $response;
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->onReport(CommentsPluginImplementation::REPORT_NAME, $parameters, '/' . $path);
+ }
+
+ public function testOnReport() {
+ $path = 'comments/files/42';
+
+ $parameters = [
+ [
+ 'name' => '{http://owncloud.org/ns}limit',
+ 'value' => 5,
+ ],
+ [
+ 'name' => '{http://owncloud.org/ns}offset',
+ 'value' => 10,
+ ],
+ [
+ 'name' => '{http://owncloud.org/ns}datetime',
+ 'value' => '2016-01-10 18:48:00',
+ ]
+ ];
+
+ $node = $this->getMockBuilder('\OCA\DAV\Comments\EntityCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->once())
+ ->method('findChildren')
+ ->with(5, 10, new \DateTime($parameters[2]['value']))
+ ->will($this->returnValue([]));
+
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response->expects($this->once())
+ ->method('setHeader')
+ ->with('Content-Type', 'application/xml; charset=utf-8');
+
+ $response->expects($this->once())
+ ->method('setStatus')
+ ->with(207);
+
+ $response->expects($this->once())
+ ->method('setBody');
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($node));
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+ $this->server->httpResponse = $response;
+ $this->plugin->initialize($this->server);
+
+ $this->plugin->onReport(CommentsPluginImplementation::REPORT_NAME, $parameters, '/' . $path);
+ }
+
+
+
+}
diff --git a/apps/dav/tests/unit/comments/entitycollection.php b/apps/dav/tests/unit/comments/entitycollection.php
new file mode 100644
index 00000000000..5bf155f12ba
--- /dev/null
+++ b/apps/dav/tests/unit/comments/entitycollection.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\Comments;
+
+class EntityCollection extends \Test\TestCase {
+
+ protected $commentsManager;
+ protected $folder;
+ protected $userManager;
+ protected $logger;
+ protected $collection;
+ protected $userSession;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->commentsManager = $this->getMock('\OCP\Comments\ICommentsManager');
+ $this->folder = $this->getMock('\OCP\Files\Folder');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+ $this->userSession = $this->getMock('\OCP\IUserSession');
+ $this->logger = $this->getMock('\OCP\ILogger');
+
+ $this->collection = new \OCA\DAV\Comments\EntityCollection(
+ '19',
+ 'files',
+ $this->commentsManager,
+ $this->folder,
+ $this->userManager,
+ $this->userSession,
+ $this->logger
+ );
+ }
+
+ public function testGetId() {
+ $this->assertSame($this->collection->getId(), '19');
+ }
+
+ public function testGetChild() {
+ $this->commentsManager->expects($this->once())
+ ->method('get')
+ ->with('55')
+ ->will($this->returnValue($this->getMock('\OCP\Comments\IComment')));
+
+ $node = $this->collection->getChild('55');
+ $this->assertTrue($node instanceof \OCA\DAV\Comments\CommentNode);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotFound
+ */
+ public function testGetChildException() {
+ $this->commentsManager->expects($this->once())
+ ->method('get')
+ ->with('55')
+ ->will($this->throwException(new \OCP\Comments\NotFoundException()));
+
+ $this->collection->getChild('55');
+ }
+
+ public function testGetChildren() {
+ $this->commentsManager->expects($this->once())
+ ->method('getForObject')
+ ->with('files', '19')
+ ->will($this->returnValue([$this->getMock('\OCP\Comments\IComment')]));
+
+ $result = $this->collection->getChildren();
+
+ $this->assertSame(count($result), 1);
+ $this->assertTrue($result[0] instanceof \OCA\DAV\Comments\CommentNode);
+ }
+
+ public function testFindChildren() {
+ $dt = new \DateTime('2016-01-10 18:48:00');
+ $this->commentsManager->expects($this->once())
+ ->method('getForObject')
+ ->with('files', '19', 5, 15, $dt)
+ ->will($this->returnValue([$this->getMock('\OCP\Comments\IComment')]));
+
+ $result = $this->collection->findChildren(5, 15, $dt);
+
+ $this->assertSame(count($result), 1);
+ $this->assertTrue($result[0] instanceof \OCA\DAV\Comments\CommentNode);
+ }
+
+ public function testChildExistsTrue() {
+ $this->assertTrue($this->collection->childExists('44'));
+ }
+
+ public function testChildExistsFalse() {
+ $this->commentsManager->expects($this->once())
+ ->method('get')
+ ->with('44')
+ ->will($this->throwException(new \OCP\Comments\NotFoundException()));
+
+ $this->assertFalse($this->collection->childExists('44'));
+ }
+}
diff --git a/apps/dav/tests/unit/comments/entitytypecollection.php b/apps/dav/tests/unit/comments/entitytypecollection.php
new file mode 100644
index 00000000000..f3aa2dbd71f
--- /dev/null
+++ b/apps/dav/tests/unit/comments/entitytypecollection.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\Comments;
+
+use OCA\DAV\Comments\EntityCollection as EntityCollectionImplemantation;
+
+class EntityTypeCollection extends \Test\TestCase {
+
+ protected $commentsManager;
+ protected $folder;
+ protected $userManager;
+ protected $logger;
+ protected $collection;
+ protected $userSession;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->commentsManager = $this->getMock('\OCP\Comments\ICommentsManager');
+ $this->folder = $this->getMock('\OCP\Files\Folder');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+ $this->userSession = $this->getMock('\OCP\IUserSession');
+ $this->logger = $this->getMock('\OCP\ILogger');
+
+ $this->collection = new \OCA\DAV\Comments\EntityTypeCollection(
+ 'files',
+ $this->commentsManager,
+ $this->folder,
+ $this->userManager,
+ $this->userSession,
+ $this->logger
+ );
+ }
+
+ public function testChildExistsYes() {
+ $this->folder->expects($this->once())
+ ->method('getById')
+ ->with('17')
+ ->will($this->returnValue([$this->getMock('\OCP\Files\Node')]));
+ $this->assertTrue($this->collection->childExists('17'));
+ }
+
+ public function testChildExistsNo() {
+ $this->folder->expects($this->once())
+ ->method('getById')
+ ->will($this->returnValue([]));
+ $this->assertFalse($this->collection->childExists('17'));
+ }
+
+ public function testGetChild() {
+ $this->folder->expects($this->once())
+ ->method('getById')
+ ->with('17')
+ ->will($this->returnValue([$this->getMock('\OCP\Files\Node')]));
+
+ $ec = $this->collection->getChild('17');
+ $this->assertTrue($ec instanceof EntityCollectionImplemantation);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotFound
+ */
+ public function testGetChildException() {
+ $this->folder->expects($this->once())
+ ->method('getById')
+ ->with('17')
+ ->will($this->returnValue([]));
+
+ $this->collection->getChild('17');
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\MethodNotAllowed
+ */
+ public function testGetChildren() {
+ $this->collection->getChildren();
+ }
+}
diff --git a/apps/dav/tests/unit/comments/rootcollection.php b/apps/dav/tests/unit/comments/rootcollection.php
new file mode 100644
index 00000000000..369006e7159
--- /dev/null
+++ b/apps/dav/tests/unit/comments/rootcollection.php
@@ -0,0 +1,160 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\Comments;
+
+use OCA\DAV\Comments\EntityTypeCollection as EntityTypeCollectionImplementation;
+
+class RootCollection extends \Test\TestCase {
+
+ protected $commentsManager;
+ protected $userManager;
+ protected $logger;
+ protected $collection;
+ protected $userSession;
+ protected $rootFolder;
+ protected $user;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->user = $this->getMock('\OCP\IUser');
+
+ $this->commentsManager = $this->getMock('\OCP\Comments\ICommentsManager');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+ $this->userSession = $this->getMock('\OCP\IUserSession');
+ $this->rootFolder = $this->getMock('\OCP\Files\IRootFolder');
+ $this->logger = $this->getMock('\OCP\ILogger');
+
+ $this->collection = new \OCA\DAV\Comments\RootCollection(
+ $this->commentsManager,
+ $this->userManager,
+ $this->userSession,
+ $this->rootFolder,
+ $this->logger
+ );
+ }
+
+ protected function prepareForInitCollections() {
+ $this->user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($this->user));
+
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('alice')
+ ->will($this->returnValue($this->getMock('\OCP\Files\Folder')));
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testCreateFile() {
+ $this->collection->createFile('foo');
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testCreateDirectory() {
+ $this->collection->createDirectory('foo');
+ }
+
+ public function testGetChild() {
+ $this->prepareForInitCollections();
+ $etc = $this->collection->getChild('files');
+ $this->assertTrue($etc instanceof EntityTypeCollectionImplementation);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotFound
+ */
+ public function testGetChildInvalid() {
+ $this->prepareForInitCollections();
+ $this->collection->getChild('robots');
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotAuthenticated
+ */
+ public function testGetChildNoAuth() {
+ $this->collection->getChild('files');
+ }
+
+ public function testGetChildren() {
+ $this->prepareForInitCollections();
+ $children = $this->collection->getChildren();
+ $this->assertFalse(empty($children));
+ foreach($children as $child) {
+ $this->assertTrue($child instanceof EntityTypeCollectionImplementation);
+ }
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotAuthenticated
+ */
+ public function testGetChildrenNoAuth() {
+ $this->collection->getChildren();
+ }
+
+ public function testChildExistsYes() {
+ $this->prepareForInitCollections();
+ $this->assertTrue($this->collection->childExists('files'));
+ }
+
+ public function testChildExistsNo() {
+ $this->prepareForInitCollections();
+ $this->assertFalse($this->collection->childExists('robots'));
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotAuthenticated
+ */
+ public function testChildExistsNoAuth() {
+ $this->collection->childExists('files');
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testDelete() {
+ $this->collection->delete();
+ }
+
+ public function testGetName() {
+ $this->assertSame('comments', $this->collection->getName());
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ */
+ public function testSetName() {
+ $this->collection->setName('foobar');
+ }
+
+ public function testGetLastModified() {
+ $this->assertSame(null, $this->collection->getLastModified());
+ }
+}
diff --git a/apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php b/apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php
index 3004c03b266..d02064531ab 100644
--- a/apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php
+++ b/apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php b/apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php
index d2d4a849a51..0ead617f461 100644
--- a/apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php
+++ b/apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/tests/unit/connector/sabre/FakeLockerPluginTest.php b/apps/dav/tests/unit/connector/sabre/FakeLockerPluginTest.php
index dfe8cc220a3..30d2bf41810 100644
--- a/apps/dav/tests/unit/connector/sabre/FakeLockerPluginTest.php
+++ b/apps/dav/tests/unit/connector/sabre/FakeLockerPluginTest.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,6 +22,7 @@
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use OCA\DAV\Connector\Sabre\FakeLockerPlugin;
+use Sabre\HTTP\Response;
use Test\TestCase;
/**
@@ -141,20 +143,19 @@ class FakeLockerPluginTest extends TestCase {
public function testFakeLockProvider() {
$request = $this->getMock('\Sabre\HTTP\RequestInterface');
- $response = $this->getMock('\Sabre\HTTP\ResponseInterface');
+ $response = new Response();
$server = $this->getMock('\Sabre\DAV\Server');
$this->fakeLockerPlugin->initialize($server);
$request->expects($this->exactly(2))
->method('getPath')
->will($this->returnValue('MyPath'));
- $response->expects($this->once())
- ->method('setBody')
- ->with('<?xml version="1.0" encoding="utf-8"?>
-<d:prop xmlns:d="DAV:"><d:lockdiscovery><d:activelock><d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:lockroot><d:href>MyPath</d:href></d:lockroot><d:depth>infinity</d:depth><d:timeout>Second-1800</d:timeout><d:locktoken><d:href>opaquelocktoken:fe4f7f2437b151fbcb4e9f5c8118c6b1</d:href></d:locktoken><d:owner/></d:activelock></d:lockdiscovery></d:prop>
-');
$this->assertSame(false, $this->fakeLockerPlugin->fakeLockProvider($request, $response));
+
+ $expectedXml = '<?xml version="1.0" encoding="utf-8"?><d:prop xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"><d:lockdiscovery><d:activelock><d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:lockroot><d:href>MyPath</d:href></d:lockroot><d:depth>infinity</d:depth><d:timeout>Second-1800</d:timeout><d:locktoken><d:href>opaquelocktoken:fe4f7f2437b151fbcb4e9f5c8118c6b1</d:href></d:locktoken><d:owner/></d:activelock></d:lockdiscovery></d:prop>';
+
+ $this->assertXmlStringEqualsXmlString($expectedXml, $response->getBody());
}
public function testFakeUnlockProvider() {
diff --git a/apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php b/apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php
index 34fa7f7eef9..dea1e64db1d 100644
--- a/apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php
+++ b/apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php
@@ -2,7 +2,7 @@
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/dav/tests/unit/connector/sabre/auth.php b/apps/dav/tests/unit/connector/sabre/auth.php
index d18747d732a..5ff736664f3 100644
--- a/apps/dav/tests/unit/connector/sabre/auth.php
+++ b/apps/dav/tests/unit/connector/sabre/auth.php
@@ -1,8 +1,11 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,6 +24,7 @@
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
+use OCP\IUser;
use Test\TestCase;
use OCP\ISession;
use OCP\IUserSession;
@@ -29,6 +33,7 @@ use OCP\IUserSession;
* Class Auth
*
* @package OCA\DAV\Connector\Sabre
+ * @group DB
*/
class Auth extends TestCase {
/** @var ISession */
@@ -249,9 +254,12 @@ class Auth extends TestCase {
}
public function testAuthenticateAlreadyLoggedIn() {
- $server = $this->getMockBuilder('\Sabre\DAV\Server')
- ->disableOriginalConstructor()
- ->getMock();
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
$this->userSession
->expects($this->once())
->method('isLoggedIn')
@@ -275,13 +283,10 @@ class Auth extends TestCase {
->expects($this->once())
->method('close');
- $this->assertTrue($this->auth->authenticate($server, 'TestRealm'));
+ $response = $this->auth->check($request, $response);
+ $this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response);
}
- /**
- * @expectedException \Sabre\DAV\Exception\NotAuthenticated
- * @expectedExceptionMessage No basic authentication headers were found
- */
public function testAuthenticateNoBasicAuthenticateHeadersProvided() {
$server = $this->getMockBuilder('\Sabre\DAV\Server')
->disableOriginalConstructor()
@@ -292,7 +297,69 @@ class Auth extends TestCase {
$server->httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
->disableOriginalConstructor()
->getMock();
- $this->auth->authenticate($server, 'TestRealm');
+ $response = $this->auth->check($server->httpRequest, $server->httpResponse);
+ $this->assertEquals([false, 'No \'Authorization: Basic\' header found. Either the client didn\'t send one, or the server is mis-configured'], $response);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotAuthenticated
+ * @expectedExceptionMessage Cannot authenticate over ajax calls
+ */
+ public function testAuthenticateNoBasicAuthenticateHeadersProvidedWithAjax() {
+ /** @var \Sabre\HTTP\RequestInterface $httpRequest */
+ $httpRequest = $this->getMockBuilder('\Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ /** @var \Sabre\HTTP\ResponseInterface $httpResponse */
+ $httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userSession
+ ->expects($this->any())
+ ->method('isLoggedIn')
+ ->will($this->returnValue(false));
+ $httpRequest
+ ->expects($this->once())
+ ->method('getHeader')
+ ->with('X-Requested-With')
+ ->will($this->returnValue('XMLHttpRequest'));
+ $this->auth->check($httpRequest, $httpResponse);
+ }
+
+ public function testAuthenticateNoBasicAuthenticateHeadersProvidedWithAjaxButUserIsStillLoggedIn() {
+ /** @var \Sabre\HTTP\RequestInterface $httpRequest */
+ $httpRequest = $this->getMockBuilder('\Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ /** @var \Sabre\HTTP\ResponseInterface $httpResponse */
+ $httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ /** @var IUser */
+ $user = $this->getMock('OCP\IUser');
+ $user->method('getUID')->willReturn('MyTestUser');
+ $this->userSession
+ ->expects($this->any())
+ ->method('isLoggedIn')
+ ->will($this->returnValue(true));
+ $this->userSession
+ ->expects($this->any())
+ ->method('getUser')
+ ->willReturn($user);
+ $this->session
+ ->expects($this->atLeastOnce())
+ ->method('get')
+ ->with('AUTHENTICATED_TO_DAV_BACKEND')
+ ->will($this->returnValue('MyTestUser'));
+ $httpRequest
+ ->expects($this->atLeastOnce())
+ ->method('getHeader')
+ ->with('Authorization')
+ ->will($this->returnValue(null));
+ $this->assertEquals(
+ [true, 'principals/users/MyTestUser'],
+ $this->auth->check($httpRequest, $httpResponse)
+ );
}
public function testAuthenticateValidCredentials() {
@@ -303,7 +370,12 @@ class Auth extends TestCase {
->disableOriginalConstructor()
->getMock();
$server->httpRequest
- ->expects($this->once())
+ ->expects($this->at(0))
+ ->method('getHeader')
+ ->with('X-Requested-With')
+ ->will($this->returnValue(null));
+ $server->httpRequest
+ ->expects($this->at(1))
->method('getHeader')
->with('Authorization')
->will($this->returnValue('basic dXNlcm5hbWU6cGFzc3dvcmQ='));
@@ -325,13 +397,10 @@ class Auth extends TestCase {
->expects($this->exactly(2))
->method('getUser')
->will($this->returnValue($user));
- $this->assertTrue($this->auth->authenticate($server, 'TestRealm'));
+ $response = $this->auth->check($server->httpRequest, $server->httpResponse);
+ $this->assertEquals([true, 'principals/users/username'], $response);
}
- /**
- * @expectedException \Sabre\DAV\Exception\NotAuthenticated
- * @expectedExceptionMessage Username or password does not match
- */
public function testAuthenticateInvalidCredentials() {
$server = $this->getMockBuilder('\Sabre\DAV\Server')
->disableOriginalConstructor()
@@ -340,7 +409,12 @@ class Auth extends TestCase {
->disableOriginalConstructor()
->getMock();
$server->httpRequest
- ->expects($this->once())
+ ->expects($this->at(0))
+ ->method('getHeader')
+ ->with('X-Requested-With')
+ ->will($this->returnValue(null));
+ $server->httpRequest
+ ->expects($this->at(1))
->method('getHeader')
->with('Authorization')
->will($this->returnValue('basic dXNlcm5hbWU6cGFzc3dvcmQ='));
@@ -352,6 +426,7 @@ class Auth extends TestCase {
->method('login')
->with('username', 'password')
->will($this->returnValue(false));
- $this->auth->authenticate($server, 'TestRealm');
+ $response = $this->auth->check($server->httpRequest, $server->httpResponse);
+ $this->assertEquals([false, 'Username or password was incorrect'], $response);
}
}
diff --git a/apps/dav/tests/unit/connector/sabre/commentpropertiesplugin.php b/apps/dav/tests/unit/connector/sabre/commentpropertiesplugin.php
new file mode 100644
index 00000000000..f915c83c4a7
--- /dev/null
+++ b/apps/dav/tests/unit/connector/sabre/commentpropertiesplugin.php
@@ -0,0 +1,148 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
+
+use \OCA\DAV\Connector\Sabre\CommentPropertiesPlugin as CommentPropertiesPluginImplementation;
+
+class CommentsPropertiesPlugin extends \Test\TestCase {
+
+ /** @var CommentPropertiesPluginImplementation */
+ protected $plugin;
+ protected $commentsManager;
+ protected $userSession;
+ protected $server;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->commentsManager = $this->getMock('\OCP\Comments\ICommentsManager');
+ $this->userSession = $this->getMock('\OCP\IUserSession');
+
+ $this->server = $this->getMockBuilder('\Sabre\DAV\Server')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->plugin = new CommentPropertiesPluginImplementation($this->commentsManager, $this->userSession);
+ $this->plugin->initialize($this->server);
+ }
+
+ public function nodeProvider() {
+ $mocks = [];
+ foreach(['\OCA\DAV\Connector\Sabre\File', '\OCA\DAV\Connector\Sabre\Directory', '\Sabre\DAV\INode'] as $class) {
+ $mocks[] = $this->getMockBuilder($class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ return [
+ [$mocks[0], true],
+ [$mocks[1], true],
+ [$mocks[2], false]
+ ];
+ }
+
+ /**
+ * @dataProvider nodeProvider
+ * @param $node
+ * @param $expectedSuccessful
+ */
+ public function testHandleGetProperties($node, $expectedSuccessful) {
+ $propFind = $this->getMockBuilder('\Sabre\DAV\PropFind')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ if($expectedSuccessful) {
+ $propFind->expects($this->exactly(3))
+ ->method('handle');
+ } else {
+ $propFind->expects($this->never())
+ ->method('handle');
+ }
+
+ $this->plugin->handleGetProperties($propFind, $node);
+ }
+
+ public function baseUriProvider() {
+ return [
+ ['owncloud/remote.php/webdav/', '4567', 'owncloud/remote.php/dav/comments/files/4567'],
+ ['owncloud/remote.php/wicked/', '4567', null]
+ ];
+ }
+
+ /**
+ * @dataProvider baseUriProvider
+ * @param $baseUri
+ * @param $fid
+ * @param $expectedHref
+ */
+ public function testGetCommentsLink($baseUri, $fid, $expectedHref) {
+ $node = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue($fid));
+
+ $this->server->expects($this->once())
+ ->method('getBaseUri')
+ ->will($this->returnValue($baseUri));
+
+ $href = $this->plugin->getCommentsLink($node);
+ $this->assertSame($expectedHref, $href);
+ }
+
+ public function userProvider() {
+ return [
+ [$this->getMock('\OCP\IUser')],
+ [null]
+ ];
+ }
+
+ /**
+ * @dataProvider userProvider
+ * @param $user
+ */
+ public function testGetUnreadCount($user) {
+ $node = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('4567'));
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->commentsManager->expects($this->any())
+ ->method('getNumberOfCommentsForObject')
+ ->will($this->returnValue(42));
+
+ $unread = $this->plugin->getUnreadCount($node);
+ if(is_null($user)) {
+ $this->assertNull($unread);
+ } else {
+ $this->assertSame($unread, 42);
+ }
+ }
+
+}
diff --git a/apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php b/apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php
index 74dd4edd8cf..7f6fb26e4d1 100644
--- a/apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php
+++ b/apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php
@@ -1,5 +1,24 @@
<?php
-
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
diff --git a/apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php b/apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php
index e1bcc996908..e0ba61e9134 100644
--- a/apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php
+++ b/apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php
@@ -1,5 +1,24 @@
<?php
-
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
@@ -8,6 +27,14 @@ namespace OCA\DAV\Tests\Unit\Connector\Sabre;
* later.
* See the COPYING-README file.
*/
+
+/**
+ * Class CustomPropertiesBackend
+ *
+ * @group DB
+ *
+ * @package Tests\Connector\Sabre
+ */
class CustomPropertiesBackend extends \Test\TestCase {
/**
diff --git a/apps/dav/tests/unit/connector/sabre/directory.php b/apps/dav/tests/unit/connector/sabre/directory.php
index 148a91d26db..317e089925b 100644
--- a/apps/dav/tests/unit/connector/sabre/directory.php
+++ b/apps/dav/tests/unit/connector/sabre/directory.php
@@ -1,14 +1,31 @@
<?php
-
/**
- * Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
+use OCP\Files\ForbiddenException;
+
class Directory extends \Test\TestCase {
/** @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject */
@@ -49,6 +66,25 @@ class Directory extends \Test\TestCase {
}
/**
+ * @expectedException \OCA\DAV\Connector\Sabre\Exception\Forbidden
+ */
+ public function testDeleteForbidden() {
+ // deletion allowed
+ $this->info->expects($this->once())
+ ->method('isDeletable')
+ ->will($this->returnValue(true));
+
+ // but fails
+ $this->view->expects($this->once())
+ ->method('rmdir')
+ ->with('sub')
+ ->willThrowException(new ForbiddenException('', true));
+
+ $dir = $this->getDir('sub');
+ $dir->delete();
+ }
+
+ /**
*
*/
public function testDeleteFolderWhenAllowed() {
diff --git a/apps/dav/tests/unit/connector/sabre/exception/forbiddentest.php b/apps/dav/tests/unit/connector/sabre/exception/forbiddentest.php
new file mode 100644
index 00000000000..36ea97df9f7
--- /dev/null
+++ b/apps/dav/tests/unit/connector/sabre/exception/forbiddentest.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\Connector\Sabre\Exception;
+
+use OCA\DAV\Connector\Sabre\Exception\Forbidden;
+
+class ForbiddenTest extends \Test\TestCase {
+
+ public function testSerialization() {
+
+ // create xml doc
+ $DOM = new \DOMDocument('1.0','utf-8');
+ $DOM->formatOutput = true;
+ $error = $DOM->createElementNS('DAV:','d:error');
+ $error->setAttribute('xmlns:s', \Sabre\DAV\Server::NS_SABREDAV);
+ $DOM->appendChild($error);
+
+ // serialize the exception
+ $message = "1234567890";
+ $retry = false;
+ $expectedXml = <<<EOD
+<?xml version="1.0" encoding="utf-8"?>
+<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:o="http://owncloud.org/ns">
+ <o:retry xmlns:o="o:">false</o:retry>
+ <o:reason xmlns:o="o:">1234567890</o:reason>
+</d:error>
+
+EOD;
+
+ $ex = new Forbidden($message, $retry);
+ $server = $this->getMock('Sabre\DAV\Server');
+ $ex->serialize($server, $error);
+
+ // assert
+ $xml = $DOM->saveXML();
+ $this->assertEquals($expectedXml, $xml);
+ }
+}
diff --git a/apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php b/apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php
index 19e82320d55..431a0484d65 100644
--- a/apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php
+++ b/apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php
@@ -1,15 +1,29 @@
<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV\Tests\Unit\Connector\Sabre\Exception;
use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
-/**
- * Copyright (c) 2015 Thomas Müller <deepdiver@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
class InvalidPathTest extends \Test\TestCase {
public function testSerialization() {
diff --git a/apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php b/apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php
index 0c364df012b..b76285be336 100644
--- a/apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php
@@ -1,10 +1,22 @@
<?php
-
/**
- * Copyright (c) 2015 Thomas Müller <deepdiver@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
diff --git a/apps/dav/tests/unit/connector/sabre/file.php b/apps/dav/tests/unit/connector/sabre/file.php
index 94dadf88fe4..c1c162f1373 100644
--- a/apps/dav/tests/unit/connector/sabre/file.php
+++ b/apps/dav/tests/unit/connector/sabre/file.php
@@ -1,18 +1,43 @@
<?php
/**
- * Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use OC\Files\Storage\Local;
+use OCP\Files\ForbiddenException;
use Test\HookHelper;
use OC\Files\Filesystem;
use OCP\Lock\ILockingProvider;
+/**
+ * Class File
+ *
+ * @group DB
+ *
+ * @package Test\Connector\Sabre
+ */
class File extends \Test\TestCase {
/**
@@ -40,6 +65,17 @@ class File extends \Test\TestCase {
parent::tearDown();
}
+ private function getMockStorage() {
+ $storage = $this->getMock('\OCP\Files\Storage');
+ $storage->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('home::someuser'));
+ return $storage;
+ }
+
+ /**
+ * @param string $string
+ */
private function getStream($string) {
$stream = fopen('php://temp', 'r+');
fwrite($stream, $string);
@@ -73,6 +109,10 @@ class File extends \Test\TestCase {
'Sabre\DAV\Exception\Forbidden'
],
[
+ new \OCP\Files\ForbiddenException('', true),
+ 'OCA\DAV\Connector\Sabre\Exception\Forbidden'
+ ],
+ [
new \OCP\Files\LockNotAcquiredException('/test.txt', 1),
'OCA\DAV\Connector\Sabre\Exception\FileLocked'
],
@@ -134,7 +174,7 @@ class File extends \Test\TestCase {
->method('getRelativePath')
->will($this->returnArgument(0));
- $info = new \OC\Files\FileInfo('/test.txt', null, null, array(
+ $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
@@ -194,7 +234,7 @@ class File extends \Test\TestCase {
$_SERVER['HTTP_OC_CHUNKED'] = true;
- $info = new \OC\Files\FileInfo('/test.txt-chunking-12345-2-0', null, null, [
+ $info = new \OC\Files\FileInfo('/test.txt-chunking-12345-2-0', $this->getMockStorage(), null, [
'permissions' => \OCP\Constants::PERMISSION_ALL
], null);
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
@@ -204,7 +244,7 @@ class File extends \Test\TestCase {
$this->assertNull($file->put('test data one'));
$file->releaseLock(ILockingProvider::LOCK_SHARED);
- $info = new \OC\Files\FileInfo('/test.txt-chunking-12345-2-1', null, null, [
+ $info = new \OC\Files\FileInfo('/test.txt-chunking-12345-2-1', $this->getMockStorage(), null, [
'permissions' => \OCP\Constants::PERMISSION_ALL
], null);
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
@@ -234,7 +274,7 @@ class File extends \Test\TestCase {
* @param string $path path to put the file into
* @param string $viewRoot root to use for the view
*
- * @return result of the PUT operaiton which is usually the etag
+ * @return null|string of the PUT operaiton which is usually the etag
*/
private function doPut($path, $viewRoot = null) {
$view = \OC\Files\Filesystem::getView();
@@ -246,7 +286,7 @@ class File extends \Test\TestCase {
$info = new \OC\Files\FileInfo(
$viewRoot . '/' . ltrim($path, '/'),
- null,
+ $this->getMockStorage(),
null,
['permissions' => \OCP\Constants::PERMISSION_ALL],
null
@@ -435,7 +475,7 @@ class File extends \Test\TestCase {
$_SERVER['CONTENT_LENGTH'] = 123456;
$_SERVER['REQUEST_METHOD'] = 'PUT';
- $info = new \OC\Files\FileInfo('/test.txt', null, null, array(
+ $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
@@ -468,7 +508,7 @@ class File extends \Test\TestCase {
// simulate situation where the target file is locked
$view->lockFile('/test.txt', ILockingProvider::LOCK_EXCLUSIVE);
- $info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt', null, null, array(
+ $info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt', $this->getMockStorage(), null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
@@ -503,7 +543,7 @@ class File extends \Test\TestCase {
$_SERVER['HTTP_OC_CHUNKED'] = true;
- $info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt-chunking-12345-2-0', null, null, [
+ $info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt-chunking-12345-2-0', $this->getMockStorage(), null, [
'permissions' => \OCP\Constants::PERMISSION_ALL
], null);
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
@@ -511,7 +551,7 @@ class File extends \Test\TestCase {
$this->assertNull($file->put('test data one'));
$file->releaseLock(ILockingProvider::LOCK_SHARED);
- $info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt-chunking-12345-2-1', null, null, [
+ $info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt-chunking-12345-2-1', $this->getMockStorage(), null, [
'permissions' => \OCP\Constants::PERMISSION_ALL
], null);
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
@@ -540,7 +580,7 @@ class File extends \Test\TestCase {
->method('getRelativePath')
->will($this->returnArgument(0));
- $info = new \OC\Files\FileInfo('/*', null, null, array(
+ $info = new \OC\Files\FileInfo('/*', $this->getMockStorage(), null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
@@ -576,7 +616,7 @@ class File extends \Test\TestCase {
->method('getRelativePath')
->will($this->returnArgument(0));
- $info = new \OC\Files\FileInfo('/*', null, null, array(
+ $info = new \OC\Files\FileInfo('/*', $this->getMockStorage(), null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
@@ -603,7 +643,7 @@ class File extends \Test\TestCase {
$_SERVER['CONTENT_LENGTH'] = 12345;
$_SERVER['REQUEST_METHOD'] = 'PUT';
- $info = new \OC\Files\FileInfo('/test.txt', null, null, array(
+ $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
@@ -639,7 +679,7 @@ class File extends \Test\TestCase {
->method('unlink')
->will($this->returnValue(true));
- $info = new \OC\Files\FileInfo('/test.txt', null, null, array(
+ $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
@@ -657,7 +697,7 @@ class File extends \Test\TestCase {
$view = $this->getMock('\OC\Files\View',
array());
- $info = new \OC\Files\FileInfo('/test.txt', null, null, array(
+ $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
'permissions' => 0
), null);
@@ -680,7 +720,30 @@ class File extends \Test\TestCase {
->method('unlink')
->will($this->returnValue(false));
- $info = new \OC\Files\FileInfo('/test.txt', null, null, array(
+ $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
+ 'permissions' => \OCP\Constants::PERMISSION_ALL
+ ), null);
+
+ $file = new \OCA\DAV\Connector\Sabre\File($view, $info);
+
+ // action
+ $file->delete();
+ }
+
+ /**
+ * @expectedException \OCA\DAV\Connector\Sabre\Exception\Forbidden
+ */
+ public function testDeleteThrowsWhenDeletionThrows() {
+ // setup
+ $view = $this->getMock('\OC\Files\View',
+ array());
+
+ // but fails
+ $view->expects($this->once())
+ ->method('unlink')
+ ->willThrowException(new ForbiddenException('', true));
+
+ $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
@@ -715,7 +778,7 @@ class File extends \Test\TestCase {
$path = 'test-locking.txt';
$info = new \OC\Files\FileInfo(
'/' . $this->user . '/files/' . $path,
- null,
+ $this->getMockStorage(),
null,
['permissions' => \OCP\Constants::PERMISSION_ALL],
null
@@ -827,7 +890,25 @@ class File extends \Test\TestCase {
->method('fopen')
->will($this->returnValue(false));
- $info = new \OC\Files\FileInfo('/test.txt', null, null, array(
+ $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
+ 'permissions' => \OCP\Constants::PERMISSION_ALL
+ ), null);
+
+ $file = new \OCA\DAV\Connector\Sabre\File($view, $info);
+
+ $file->get();
+ }
+
+ /**
+ * @expectedException \OCA\DAV\Connector\Sabre\Exception\Forbidden
+ */
+ public function testGetFopenThrows() {
+ $view = $this->getMock('\OC\Files\View', ['fopen'], array());
+ $view->expects($this->atLeastOnce())
+ ->method('fopen')
+ ->willThrowException(new ForbiddenException('', true));
+
+ $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
diff --git a/apps/dav/tests/unit/connector/sabre/filesplugin.php b/apps/dav/tests/unit/connector/sabre/filesplugin.php
index 55c8dd49e17..cbc847ebdb8 100644
--- a/apps/dav/tests/unit/connector/sabre/filesplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/filesplugin.php
@@ -1,7 +1,30 @@
<?php
-
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
+use OCP\Files\StorageNotAvailableException;
+
/**
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
@@ -11,6 +34,7 @@ namespace OCA\DAV\Tests\Unit\Connector\Sabre;
class FilesPlugin extends \Test\TestCase {
const GETETAG_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::GETETAG_PROPERTYNAME;
const FILEID_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::FILEID_PROPERTYNAME;
+ const INTERNAL_FILEID_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::INTERNAL_FILEID_PROPERTYNAME;
const SIZE_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::SIZE_PROPERTYNAME;
const PERMISSIONS_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::PERMISSIONS_PROPERTYNAME;
const LASTMODIFIED_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::LASTMODIFIED_PROPERTYNAME;
@@ -54,6 +78,9 @@ class FilesPlugin extends \Test\TestCase {
$this->plugin->initialize($this->server);
}
+ /**
+ * @param string $class
+ */
private function createTestNode($class) {
$node = $this->getMockBuilder($class)
->disableOriginalConstructor()
@@ -69,7 +96,10 @@ class FilesPlugin extends \Test\TestCase {
$node->expects($this->any())
->method('getFileId')
- ->will($this->returnValue(123));
+ ->will($this->returnValue('00000123instanceid'));
+ $node->expects($this->any())
+ ->method('getInternalFileId')
+ ->will($this->returnValue('123'));
$node->expects($this->any())
->method('getEtag')
->will($this->returnValue('"abc"'));
@@ -90,6 +120,7 @@ class FilesPlugin extends \Test\TestCase {
array(
self::GETETAG_PROPERTYNAME,
self::FILEID_PROPERTYNAME,
+ self::INTERNAL_FILEID_PROPERTYNAME,
self::SIZE_PROPERTYNAME,
self::PERMISSIONS_PROPERTYNAME,
self::DOWNLOADURL_PROPERTYNAME,
@@ -125,7 +156,8 @@ class FilesPlugin extends \Test\TestCase {
);
$this->assertEquals('"abc"', $propFind->get(self::GETETAG_PROPERTYNAME));
- $this->assertEquals(123, $propFind->get(self::FILEID_PROPERTYNAME));
+ $this->assertEquals('00000123instanceid', $propFind->get(self::FILEID_PROPERTYNAME));
+ $this->assertEquals('123', $propFind->get(self::INTERNAL_FILEID_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::SIZE_PROPERTYNAME));
$this->assertEquals('DWCKMSR', $propFind->get(self::PERMISSIONS_PROPERTYNAME));
$this->assertEquals('http://example.com/', $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
@@ -134,6 +166,29 @@ class FilesPlugin extends \Test\TestCase {
$this->assertEquals(array(self::SIZE_PROPERTYNAME), $propFind->get404Properties());
}
+ public function testGetPropertiesStorageNotAvailable() {
+ $node = $this->createTestNode('\OCA\DAV\Connector\Sabre\File');
+
+ $propFind = new \Sabre\DAV\PropFind(
+ '/dummyPath',
+ array(
+ self::DOWNLOADURL_PROPERTYNAME,
+ ),
+ 0
+ );
+
+ $node->expects($this->once())
+ ->method('getDirectDownload')
+ ->will($this->throwException(new StorageNotAvailableException()));
+
+ $this->plugin->handleGetProperties(
+ $propFind,
+ $node
+ );
+
+ $this->assertEquals(null, $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
+ }
+
public function testGetPublicPermissions() {
$this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin($this->tree, $this->view, true);
$this->plugin->initialize($this->server);
@@ -186,7 +241,7 @@ class FilesPlugin extends \Test\TestCase {
);
$this->assertEquals('"abc"', $propFind->get(self::GETETAG_PROPERTYNAME));
- $this->assertEquals(123, $propFind->get(self::FILEID_PROPERTYNAME));
+ $this->assertEquals('00000123instanceid', $propFind->get(self::FILEID_PROPERTYNAME));
$this->assertEquals(1025, $propFind->get(self::SIZE_PROPERTYNAME));
$this->assertEquals('DWCKMSR', $propFind->get(self::PERMISSIONS_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
diff --git a/apps/dav/tests/unit/connector/sabre/node.php b/apps/dav/tests/unit/connector/sabre/node.php
index cee64fb7dff..dfbd95bfad8 100644
--- a/apps/dav/tests/unit/connector/sabre/node.php
+++ b/apps/dav/tests/unit/connector/sabre/node.php
@@ -1,10 +1,24 @@
<?php
-
/**
- * Copyright (c) 2014 Thomas Müller <thomas.mueller@tmit.eu>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
diff --git a/apps/dav/tests/unit/connector/sabre/objecttree.php b/apps/dav/tests/unit/connector/sabre/objecttree.php
index 3a56404e552..e5e858ef17b 100644
--- a/apps/dav/tests/unit/connector/sabre/objecttree.php
+++ b/apps/dav/tests/unit/connector/sabre/objecttree.php
@@ -1,9 +1,26 @@
<?php
/**
- * Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
@@ -41,6 +58,13 @@ class TestDoubleFileView extends \OC\Files\View {
}
}
+/**
+ * Class ObjectTree
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit\Connector\Sabre
+ */
class ObjectTree extends \Test\TestCase {
/**
@@ -287,4 +311,45 @@ class ObjectTree extends \Test\TestCase {
$this->assertInstanceOf('\Sabre\DAV\INode', $tree->getNodeForPath($path));
}
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ * @expectedExceptionMessage Could not copy directory nameOfSourceNode, target exists
+ */
+ public function testFailingMove() {
+ $source = 'a/b';
+ $destination = 'b/b';
+ $updatables = array('a' => true, 'a/b' => true, 'b' => true, 'b/b' => false);
+ $deletables = array('a/b' => true);
+
+ $view = new TestDoubleFileView($updatables, $deletables);
+
+ $info = new FileInfo('', null, null, array(), null);
+
+ $rootDir = new \OCA\DAV\Connector\Sabre\Directory($view, $info);
+ $objectTree = $this->getMock('\OCA\DAV\Connector\Sabre\ObjectTree',
+ array('nodeExists', 'getNodeForPath'),
+ array($rootDir, $view));
+
+ $sourceNode = $this->getMockBuilder('\Sabre\DAV\ICollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $sourceNode->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('nameOfSourceNode'));
+
+ $objectTree->expects($this->once())
+ ->method('nodeExists')
+ ->with($this->identicalTo($destination))
+ ->will($this->returnValue(true));
+ $objectTree->expects($this->once())
+ ->method('getNodeForPath')
+ ->with($this->identicalTo($source))
+ ->will($this->returnValue($sourceNode));
+
+ /** @var $objectTree \OCA\DAV\Connector\Sabre\ObjectTree */
+ $mountManager = \OC\Files\Filesystem::getMountManager();
+ $objectTree->init($rootDir, $view, $mountManager);
+ $objectTree->move($source, $destination);
+ }
}
diff --git a/apps/dav/tests/unit/connector/sabre/principal.php b/apps/dav/tests/unit/connector/sabre/principal.php
index 2fbab124fb7..d6bc7cd405f 100644
--- a/apps/dav/tests/unit/connector/sabre/principal.php
+++ b/apps/dav/tests/unit/connector/sabre/principal.php
@@ -1,34 +1,50 @@
<?php
/**
- * @author Lukas Reschke
- * @copyright 2014 Lukas Reschke lukas@owncloud.com
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
*
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
+use OCP\IGroupManager;
use \Sabre\DAV\PropPatch;
use OCP\IUserManager;
-use OCP\IConfig;
+use Test\TestCase;
-class Principal extends \Test\TestCase {
- /** @var IUserManager */
+class Principal extends TestCase {
+ /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */
private $userManager;
- /** @var IConfig */
- private $config;
/** @var \OCA\DAV\Connector\Sabre\Principal */
private $connector;
+ /** @var IGroupManager | \PHPUnit_Framework_MockObject_MockObject */
+ private $groupManager;
public function setUp() {
$this->userManager = $this->getMockBuilder('\OCP\IUserManager')
->disableOriginalConstructor()->getMock();
- $this->config = $this->getMockBuilder('\OCP\IConfig')
+ $this->groupManager = $this->getMockBuilder('\OCP\IGroupManager')
->disableOriginalConstructor()->getMock();
- $this->connector = new \OCA\DAV\Connector\Sabre\Principal($this->config, $this->userManager);
+ $this->connector = new \OCA\DAV\Connector\Sabre\Principal(
+ $this->userManager,
+ $this->groupManager);
parent::setUp();
}
@@ -41,43 +57,45 @@ class Principal extends \Test\TestCase {
$fooUser = $this->getMockBuilder('\OC\User\User')
->disableOriginalConstructor()->getMock();
$fooUser
- ->expects($this->exactly(3))
- ->method('getUID')
- ->will($this->returnValue('foo'));
+ ->expects($this->exactly(1))
+ ->method('getUID')
+ ->will($this->returnValue('foo'));
+ $fooUser
+ ->expects($this->exactly(1))
+ ->method('getDisplayName')
+ ->will($this->returnValue('Dr. Foo-Bar'));
+ $fooUser
+ ->expects($this->exactly(1))
+ ->method('getEMailAddress')
+ ->will($this->returnValue(''));
$barUser = $this->getMockBuilder('\OC\User\User')
->disableOriginalConstructor()->getMock();
$barUser
- ->expects($this->exactly(3))
+ ->expects($this->exactly(1))
->method('getUID')
->will($this->returnValue('bar'));
+ $barUser
+ ->expects($this->exactly(1))
+ ->method('getEMailAddress')
+ ->will($this->returnValue('bar@owncloud.org'));
$this->userManager
->expects($this->once())
->method('search')
->with('')
->will($this->returnValue([$fooUser, $barUser]));
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('foo', 'settings', 'email')
- ->will($this->returnValue(''));
- $this->config
- ->expects($this->at(1))
- ->method('getUserValue')
- ->with('bar', 'settings', 'email')
- ->will($this->returnValue('bar@owncloud.org'));
$expectedResponse = [
0 => [
- 'uri' => 'principals/foo',
- '{DAV:}displayname' => 'foo'
+ 'uri' => 'principals/users/foo',
+ '{DAV:}displayname' => 'Dr. Foo-Bar'
],
1 => [
- 'uri' => 'principals/bar',
+ 'uri' => 'principals/users/bar',
'{DAV:}displayname' => 'bar',
'{http://sabredav.org/ns}email-address' => 'bar@owncloud.org'
]
];
- $response = $this->connector->getPrincipalsByPrefix('principals');
+ $response = $this->connector->getPrincipalsByPrefix('principals/users');
$this->assertSame($expectedResponse, $response);
}
@@ -88,7 +106,7 @@ class Principal extends \Test\TestCase {
->with('')
->will($this->returnValue([]));
- $response = $this->connector->getPrincipalsByPrefix('principals');
+ $response = $this->connector->getPrincipalsByPrefix('principals/users');
$this->assertSame([], $response);
}
@@ -96,7 +114,7 @@ class Principal extends \Test\TestCase {
$fooUser = $this->getMockBuilder('\OC\User\User')
->disableOriginalConstructor()->getMock();
$fooUser
- ->expects($this->exactly(3))
+ ->expects($this->exactly(1))
->method('getUID')
->will($this->returnValue('foo'));
$this->userManager
@@ -104,17 +122,12 @@ class Principal extends \Test\TestCase {
->method('get')
->with('foo')
->will($this->returnValue($fooUser));
- $this->config
- ->expects($this->once())
- ->method('getUserValue')
- ->with('foo', 'settings', 'email')
- ->will($this->returnValue(''));
$expectedResponse = [
- 'uri' => 'principals/foo',
+ 'uri' => 'principals/users/foo',
'{DAV:}displayname' => 'foo'
];
- $response = $this->connector->getPrincipalByPath('principals/foo');
+ $response = $this->connector->getPrincipalByPath('principals/users/foo');
$this->assertSame($expectedResponse, $response);
}
@@ -122,26 +135,25 @@ class Principal extends \Test\TestCase {
$fooUser = $this->getMockBuilder('\OC\User\User')
->disableOriginalConstructor()->getMock();
$fooUser
- ->expects($this->exactly(3))
- ->method('getUID')
- ->will($this->returnValue('foo'));
+ ->expects($this->exactly(1))
+ ->method('getEMailAddress')
+ ->will($this->returnValue('foo@owncloud.org'));
+ $fooUser
+ ->expects($this->exactly(1))
+ ->method('getUID')
+ ->will($this->returnValue('foo'));
$this->userManager
->expects($this->once())
->method('get')
->with('foo')
->will($this->returnValue($fooUser));
- $this->config
- ->expects($this->once())
- ->method('getUserValue')
- ->with('foo', 'settings', 'email')
- ->will($this->returnValue('foo@owncloud.org'));
$expectedResponse = [
- 'uri' => 'principals/foo',
+ 'uri' => 'principals/users/foo',
'{DAV:}displayname' => 'foo',
'{http://sabredav.org/ns}email-address' => 'foo@owncloud.org'
];
- $response = $this->connector->getPrincipalByPath('principals/foo');
+ $response = $this->connector->getPrincipalByPath('principals/users/foo');
$this->assertSame($expectedResponse, $response);
}
@@ -152,7 +164,7 @@ class Principal extends \Test\TestCase {
->with('foo')
->will($this->returnValue(null));
- $response = $this->connector->getPrincipalByPath('principals/foo');
+ $response = $this->connector->getPrincipalByPath('principals/users/foo');
$this->assertSame(null, $response);
}
@@ -160,7 +172,7 @@ class Principal extends \Test\TestCase {
$fooUser = $this->getMockBuilder('\OC\User\User')
->disableOriginalConstructor()->getMock();
$fooUser
- ->expects($this->exactly(3))
+ ->expects($this->exactly(1))
->method('getUID')
->will($this->returnValue('foo'));
$this->userManager
@@ -168,14 +180,9 @@ class Principal extends \Test\TestCase {
->method('get')
->with('foo')
->will($this->returnValue($fooUser));
- $this->config
- ->expects($this->once())
- ->method('getUserValue')
- ->with('foo', 'settings', 'email')
- ->will($this->returnValue('foo@owncloud.org'));
- $response = $this->connector->getGroupMemberSet('principals/foo');
- $this->assertSame(['principals/foo'], $response);
+ $response = $this->connector->getGroupMemberSet('principals/users/foo');
+ $this->assertSame(['principals/users/foo'], $response);
}
/**
@@ -189,32 +196,26 @@ class Principal extends \Test\TestCase {
->with('foo')
->will($this->returnValue(null));
- $this->connector->getGroupMemberSet('principals/foo');
+ $this->connector->getGroupMemberSet('principals/users/foo');
}
public function testGetGroupMembership() {
$fooUser = $this->getMockBuilder('\OC\User\User')
->disableOriginalConstructor()->getMock();
- $fooUser
- ->expects($this->exactly(3))
- ->method('getUID')
- ->will($this->returnValue('foo'));
$this->userManager
->expects($this->once())
->method('get')
->with('foo')
- ->will($this->returnValue($fooUser));
- $this->config
- ->expects($this->once())
- ->method('getUserValue')
- ->with('foo', 'settings', 'email')
- ->will($this->returnValue('foo@owncloud.org'));
+ ->willReturn($fooUser);
+ $this->groupManager
+ ->method('getUserGroups')
+ ->willReturn([]);
$expectedResponse = [
- 'principals/foo/calendar-proxy-read',
- 'principals/foo/calendar-proxy-write'
+ 'principals/users/foo/calendar-proxy-read',
+ 'principals/users/foo/calendar-proxy-write'
];
- $response = $this->connector->getGroupMembership('principals/foo');
+ $response = $this->connector->getGroupMembership('principals/users/foo');
$this->assertSame($expectedResponse, $response);
}
@@ -229,7 +230,7 @@ class Principal extends \Test\TestCase {
->with('foo')
->will($this->returnValue(null));
- $this->connector->getGroupMembership('principals/foo');
+ $this->connector->getGroupMembership('principals/users/foo');
}
/**
@@ -237,7 +238,7 @@ class Principal extends \Test\TestCase {
* @expectedExceptionMessage Setting members of the group is not supported yet
*/
public function testSetGroupMembership() {
- $this->connector->setGroupMemberSet('principals/foo', ['foo']);
+ $this->connector->setGroupMemberSet('principals/users/foo', ['foo']);
}
public function testUpdatePrincipal() {
@@ -245,6 +246,6 @@ class Principal extends \Test\TestCase {
}
public function testSearchPrincipals() {
- $this->assertSame([], $this->connector->searchPrincipals('principals', []));
+ $this->assertSame([], $this->connector->searchPrincipals('principals/users', []));
}
}
diff --git a/apps/dav/tests/unit/connector/sabre/quotaplugin.php b/apps/dav/tests/unit/connector/sabre/quotaplugin.php
index 470fd9cbf85..cc4339ecc1a 100644
--- a/apps/dav/tests/unit/connector/sabre/quotaplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/quotaplugin.php
@@ -1,5 +1,25 @@
<?php
-
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
* Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
diff --git a/apps/dav/tests/unit/connector/sabre/requesttest/auth.php b/apps/dav/tests/unit/connector/sabre/requesttest/auth.php
index 41b554d11db..b728a8f3bd8 100644
--- a/apps/dav/tests/unit/connector/sabre/requesttest/auth.php
+++ b/apps/dav/tests/unit/connector/sabre/requesttest/auth.php
@@ -1,14 +1,30 @@
<?php
/**
- * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
use Sabre\DAV\Auth\Backend\BackendInterface;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
class Auth implements BackendInterface {
/**
@@ -32,18 +48,35 @@ class Auth implements BackendInterface {
$this->password = $password;
}
-
/**
- * Authenticates the user based on the current request.
+ * When this method is called, the backend must check if authentication was
+ * successful.
+ *
+ * The returned value must be one of the following
+ *
+ * [true, "principals/username"]
+ * [false, "reason for failure"]
+ *
+ * If authentication was successful, it's expected that the authentication
+ * backend returns a so-called principal url.
+ *
+ * Examples of a principal url:
*
- * If authentication is successful, true must be returned.
- * If authentication fails, an exception must be thrown.
+ * principals/admin
+ * principals/user1
+ * principals/users/joe
+ * principals/uid/123457
*
- * @param \Sabre\DAV\Server $server
- * @param string $realm
- * @return bool
+ * If you don't use WebDAV ACL (RFC3744) we recommend that you simply
+ * return a string such as:
+ *
+ * principals/users/[username]
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ * @return array
*/
- function authenticate(\Sabre\DAV\Server $server, $realm) {
+ function check(RequestInterface $request, ResponseInterface $response) {
$userSession = \OC::$server->getUserSession();
$result = $userSession->login($this->user, $this->password);
if ($result) {
@@ -52,18 +85,33 @@ class Auth implements BackendInterface {
\OC_Util::setupFS($user);
//trigger creation of user home and /files folder
\OC::$server->getUserFolder($user);
+ return [true, "principals/$user"];
}
- return $result;
+ return [false, "login failed"];
}
/**
- * Returns information about the currently logged in username.
+ * This method is called when a user could not be authenticated, and
+ * authentication was required for the current request.
+ *
+ * This gives you the opportunity to set authentication headers. The 401
+ * status code will already be set.
+ *
+ * In this case of Basic Auth, this would for example mean that the
+ * following header needs to be set:
+ *
+ * $response->addHeader('WWW-Authenticate', 'Basic realm=SabreDAV');
*
- * If nobody is currently logged in, this method should return null.
+ * Keep in mind that in the case of multiple authentication backends, other
+ * WWW-Authenticate headers may already have been set, and you'll want to
+ * append your own WWW-Authenticate header instead of overwriting the
+ * existing one.
*
- * @return string|null
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ * @return void
*/
- function getCurrentUser() {
- return $this->user;
+ function challenge(RequestInterface $request, ResponseInterface $response) {
+ // TODO: Implement challenge() method.
}
}
diff --git a/apps/dav/tests/unit/connector/sabre/requesttest/downloadtest.php b/apps/dav/tests/unit/connector/sabre/requesttest/downloadtest.php
index 245deff3b31..3d047399a1f 100644
--- a/apps/dav/tests/unit/connector/sabre/requesttest/downloadtest.php
+++ b/apps/dav/tests/unit/connector/sabre/requesttest/downloadtest.php
@@ -1,9 +1,23 @@
<?php
/**
- * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
@@ -11,6 +25,13 @@ namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
use OCP\AppFramework\Http;
use OCP\Lock\ILockingProvider;
+/**
+ * Class DownloadTest
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest
+ */
class DownloadTest extends RequestTest {
public function testDownload() {
$user = $this->getUniqueID();
diff --git a/apps/dav/tests/unit/connector/sabre/requesttest/encryptionuploadtest.php b/apps/dav/tests/unit/connector/sabre/requesttest/encryptionuploadtest.php
index ed1d6046d75..c5c6d0da0c2 100644
--- a/apps/dav/tests/unit/connector/sabre/requesttest/encryptionuploadtest.php
+++ b/apps/dav/tests/unit/connector/sabre/requesttest/encryptionuploadtest.php
@@ -1,9 +1,23 @@
<?php
/**
- * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
@@ -11,6 +25,13 @@ namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
use OC\Files\View;
use Test\Traits\EncryptionTrait;
+/**
+ * Class EncryptionUploadTest
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest
+ */
class EncryptionUploadTest extends UploadTest {
use EncryptionTrait;
diff --git a/apps/dav/tests/unit/connector/sabre/requesttest/exceptionplugin.php b/apps/dav/tests/unit/connector/sabre/requesttest/exceptionplugin.php
index 53cd186bbc8..a6a0f9d3b86 100644
--- a/apps/dav/tests/unit/connector/sabre/requesttest/exceptionplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/requesttest/exceptionplugin.php
@@ -1,9 +1,23 @@
<?php
/**
- * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
diff --git a/apps/dav/tests/unit/connector/sabre/requesttest/requesttest.php b/apps/dav/tests/unit/connector/sabre/requesttest/requesttest.php
index a83f25c1585..e3cdca5abfa 100644
--- a/apps/dav/tests/unit/connector/sabre/requesttest/requesttest.php
+++ b/apps/dav/tests/unit/connector/sabre/requesttest/requesttest.php
@@ -1,9 +1,25 @@
<?php
/**
- * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
@@ -46,7 +62,6 @@ abstract class RequestTest extends TestCase {
\OC::$server->getUserSession(),
\OC::$server->getMountManager(),
\OC::$server->getTagManager(),
- \OC::$server->getEventDispatcher(),
$this->getMock('\OCP\IRequest')
);
}
diff --git a/apps/dav/tests/unit/connector/sabre/requesttest/sapi.php b/apps/dav/tests/unit/connector/sabre/requesttest/sapi.php
index 3af94010288..6407d9bc28b 100644
--- a/apps/dav/tests/unit/connector/sabre/requesttest/sapi.php
+++ b/apps/dav/tests/unit/connector/sabre/requesttest/sapi.php
@@ -1,9 +1,23 @@
<?php
/**
- * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
diff --git a/apps/dav/tests/unit/connector/sabre/requesttest/uploadtest.php b/apps/dav/tests/unit/connector/sabre/requesttest/uploadtest.php
index a2a8326f4ff..ae30268e366 100644
--- a/apps/dav/tests/unit/connector/sabre/requesttest/uploadtest.php
+++ b/apps/dav/tests/unit/connector/sabre/requesttest/uploadtest.php
@@ -1,9 +1,23 @@
<?php
/**
- * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
*/
namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
@@ -12,6 +26,13 @@ use OC\Connector\Sabre\Exception\FileLocked;
use OCP\AppFramework\Http;
use OCP\Lock\ILockingProvider;
+/**
+ * Class UploadTest
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest
+ */
class UploadTest extends RequestTest {
public function testBasicUpload() {
$user = $this->getUniqueID();
diff --git a/apps/dav/tests/unit/connector/sabre/tagsplugin.php b/apps/dav/tests/unit/connector/sabre/tagsplugin.php
index f1f6cc40dab..95ba002e393 100644
--- a/apps/dav/tests/unit/connector/sabre/tagsplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/tagsplugin.php
@@ -1,5 +1,24 @@
<?php
-
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
diff --git a/apps/dav/tests/unit/dav/groupprincipaltest.php b/apps/dav/tests/unit/dav/groupprincipaltest.php
new file mode 100644
index 00000000000..9d012639310
--- /dev/null
+++ b/apps/dav/tests/unit/dav/groupprincipaltest.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\Tests\Unit\DAV;
+
+use OCA\DAV\DAV\GroupPrincipalBackend;
+use OCP\IGroupManager;
+use PHPUnit_Framework_MockObject_MockObject;
+use \Sabre\DAV\PropPatch;
+
+class GroupPrincipalTest extends \Test\TestCase {
+
+ /** @var IGroupManager | PHPUnit_Framework_MockObject_MockObject */
+ private $groupManager;
+
+ /** @var GroupPrincipalBackend */
+ private $connector;
+
+ public function setUp() {
+ $this->groupManager = $this->getMockBuilder('\OCP\IGroupManager')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->connector = new GroupPrincipalBackend($this->groupManager);
+ parent::setUp();
+ }
+
+ public function testGetPrincipalsByPrefixWithoutPrefix() {
+ $response = $this->connector->getPrincipalsByPrefix('');
+ $this->assertSame([], $response);
+ }
+
+ public function testGetPrincipalsByPrefixWithUsers() {
+ $group1 = $this->mockGroup('foo');
+ $group2 = $this->mockGroup('bar');
+ $this->groupManager
+ ->expects($this->once())
+ ->method('search')
+ ->with('')
+ ->will($this->returnValue([$group1, $group2]));
+
+ $expectedResponse = [
+ 0 => [
+ 'uri' => 'principals/groups/foo',
+ '{DAV:}displayname' => 'foo'
+ ],
+ 1 => [
+ 'uri' => 'principals/groups/bar',
+ '{DAV:}displayname' => 'bar',
+ ]
+ ];
+ $response = $this->connector->getPrincipalsByPrefix('principals/groups');
+ $this->assertSame($expectedResponse, $response);
+ }
+
+ public function testGetPrincipalsByPrefixEmpty() {
+ $this->groupManager
+ ->expects($this->once())
+ ->method('search')
+ ->with('')
+ ->will($this->returnValue([]));
+
+ $response = $this->connector->getPrincipalsByPrefix('principals/groups');
+ $this->assertSame([], $response);
+ }
+
+ public function testGetPrincipalsByPathWithoutMail() {
+ $group1 = $this->mockGroup('foo');
+ $this->groupManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('foo')
+ ->will($this->returnValue($group1));
+
+ $expectedResponse = [
+ 'uri' => 'principals/groups/foo',
+ '{DAV:}displayname' => 'foo'
+ ];
+ $response = $this->connector->getPrincipalByPath('principals/groups/foo');
+ $this->assertSame($expectedResponse, $response);
+ }
+
+ public function testGetPrincipalsByPathWithMail() {
+ $fooUser = $this->mockGroup('foo');
+ $this->groupManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('foo')
+ ->will($this->returnValue($fooUser));
+
+ $expectedResponse = [
+ 'uri' => 'principals/groups/foo',
+ '{DAV:}displayname' => 'foo',
+ ];
+ $response = $this->connector->getPrincipalByPath('principals/groups/foo');
+ $this->assertSame($expectedResponse, $response);
+ }
+
+ public function testGetPrincipalsByPathEmpty() {
+ $this->groupManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('foo')
+ ->will($this->returnValue(null));
+
+ $response = $this->connector->getPrincipalByPath('principals/groups/foo');
+ $this->assertSame(null, $response);
+ }
+
+ public function testGetGroupMemberSet() {
+ $response = $this->connector->getGroupMemberSet('principals/groups/foo');
+ $this->assertSame([], $response);
+ }
+
+ public function testGetGroupMembership() {
+ $response = $this->connector->getGroupMembership('principals/groups/foo');
+ $this->assertSame([], $response);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception
+ * @expectedExceptionMessage Setting members of the group is not supported yet
+ */
+ public function testSetGroupMembership() {
+ $this->connector->setGroupMemberSet('principals/groups/foo', ['foo']);
+ }
+
+ public function testUpdatePrincipal() {
+ $this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch(array())));
+ }
+
+ public function testSearchPrincipals() {
+ $this->assertSame([], $this->connector->searchPrincipals('principals/groups', []));
+ }
+
+ /**
+ * @return PHPUnit_Framework_MockObject_MockObject
+ */
+ private function mockGroup($gid) {
+ $fooUser = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()->getMock();
+ $fooUser
+ ->expects($this->exactly(1))
+ ->method('getGID')
+ ->will($this->returnValue($gid));
+ return $fooUser;
+ }
+}
diff --git a/apps/dav/tests/unit/dav/sharing/plugintest.php b/apps/dav/tests/unit/dav/sharing/plugintest.php
new file mode 100644
index 00000000000..ce6c96f1bfc
--- /dev/null
+++ b/apps/dav/tests/unit/dav/sharing/plugintest.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\DAV;
+
+
+use OCA\DAV\DAV\Sharing\IShareable;
+use OCA\DAV\DAV\Sharing\Plugin;
+use OCA\DAV\Connector\Sabre\Auth;
+use OCP\IRequest;
+use Sabre\DAV\Server;
+use Sabre\DAV\SimpleCollection;
+use Sabre\HTTP\Request;
+use Sabre\HTTP\Response;
+use Test\TestCase;
+
+class PluginTest extends TestCase {
+
+ /** @var Plugin */
+ private $plugin;
+ /** @var Server */
+ private $server;
+ /** @var IShareable | \PHPUnit_Framework_MockObject_MockObject */
+ private $book;
+
+ public function setUp() {
+ parent::setUp();
+
+ /** @var Auth | \PHPUnit_Framework_MockObject_MockObject $authBackend */
+ $authBackend = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Auth')->disableOriginalConstructor()->getMock();
+ $authBackend->method('isDavAuthenticated')->willReturn(true);
+
+ /** @var IRequest $request */
+ $request = $this->getMockBuilder('OCP\IRequest')->disableOriginalConstructor()->getMock();
+ $this->plugin = new Plugin($authBackend, $request);
+
+ $root = new SimpleCollection('root');
+ $this->server = new \Sabre\DAV\Server($root);
+ /** @var SimpleCollection $node */
+ $this->book = $this->getMockBuilder('OCA\DAV\DAV\Sharing\IShareable')->
+ disableOriginalConstructor()->
+ getMock();
+ $this->book->method('getName')->willReturn('addressbook1.vcf');
+ $root->addChild($this->book);
+ $this->plugin->initialize($this->server);
+ }
+
+ public function testSharing() {
+
+ $this->book->expects($this->once())->method('updateShares')->with([[
+ 'href' => 'principal:principals/admin',
+ 'commonName' => null,
+ 'summary' => null,
+ 'readOnly' => false
+ ]], ['mailto:wilfredo@example.com']);
+
+ // setup request
+ $request = new Request();
+ $request->addHeader('Content-Type', 'application/xml');
+ $request->setUrl('addressbook1.vcf');
+ $request->setBody('<?xml version="1.0" encoding="utf-8" ?><CS:share xmlns:D="DAV:" xmlns:CS="http://owncloud.org/ns"><CS:set><D:href>principal:principals/admin</D:href><CS:read-write/></CS:set> <CS:remove><D:href>mailto:wilfredo@example.com</D:href></CS:remove></CS:share>');
+ $response = new Response();
+ $this->plugin->httpPost($request, $response);
+ }
+}
diff --git a/apps/dav/tests/unit/dav/systemprincipalbackendtest.php b/apps/dav/tests/unit/dav/systemprincipalbackendtest.php
new file mode 100644
index 00000000000..26717f7509b
--- /dev/null
+++ b/apps/dav/tests/unit/dav/systemprincipalbackendtest.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\DAV;
+
+use OCA\DAV\DAV\SystemPrincipalBackend;
+use Test\TestCase;
+
+class SystemPrincipalBackendTest extends TestCase {
+
+ /**
+ * @dataProvider providesPrefix
+ * @param $expected
+ * @param $prefix
+ */
+ public function testGetPrincipalsByPrefix($expected, $prefix) {
+ $backend = new SystemPrincipalBackend();
+ $result = $backend->getPrincipalsByPrefix($prefix);
+ $this->assertEquals($expected, $result);
+ }
+
+ public function providesPrefix() {
+ return [
+ [[], ''],
+ [[[
+ 'uri' => 'principals/system/system',
+ '{DAV:}displayname' => 'system',
+ ]], 'principals/system'],
+ ];
+ }
+
+ /**
+ * @dataProvider providesPath
+ * @param $expected
+ * @param $path
+ */
+ public function testGetPrincipalByPath($expected, $path) {
+ $backend = new SystemPrincipalBackend();
+ $result = $backend->getPrincipalByPath($path);
+ $this->assertEquals($expected, $result);
+ }
+
+ public function providesPath() {
+ return [
+ [null, ''],
+ [null, 'principals'],
+ [null, 'principals/system'],
+ [[
+ 'uri' => 'principals/system/system',
+ '{DAV:}displayname' => 'system',
+ ], 'principals/system/system'],
+ ];
+ }
+
+ /**
+ * @dataProvider providesPrincipalForGetGroupMemberSet
+ * @expectedException \Sabre\DAV\Exception
+ * @expectedExceptionMessage Principal not found
+ *
+ * @param string $principal
+ * @throws \Sabre\DAV\Exception
+ */
+ public function testGetGroupMemberSetExceptional($principal) {
+ $backend = new SystemPrincipalBackend();
+ $backend->getGroupMemberSet($principal);
+ }
+
+ public function providesPrincipalForGetGroupMemberSet() {
+ return [
+ [null],
+ ['principals/system'],
+ ];
+ }
+
+ /**
+ * @throws \Sabre\DAV\Exception
+ */
+ public function testGetGroupMemberSet() {
+ $backend = new SystemPrincipalBackend();
+ $result = $backend->getGroupMemberSet('principals/system/system');
+ $this->assertEquals(['principals/system/system'], $result);
+ }
+
+ /**
+ * @dataProvider providesPrincipalForGetGroupMembership
+ * @expectedException \Sabre\DAV\Exception
+ * @expectedExceptionMessage Principal not found
+ *
+ * @param string $principal
+ * @throws \Sabre\DAV\Exception
+ */
+ public function testGetGroupMembershipExceptional($principal) {
+ $backend = new SystemPrincipalBackend();
+ $backend->getGroupMembership($principal);
+ }
+
+ public function providesPrincipalForGetGroupMembership() {
+ return [
+ ['principals/system/a'],
+ ];
+ }
+
+ /**
+ * @throws \Sabre\DAV\Exception
+ */
+ public function testGetGroupMembership() {
+ $backend = new SystemPrincipalBackend();
+ $result = $backend->getGroupMembership('principals/system/system');
+ $this->assertEquals([], $result);
+ }
+
+
+}
diff --git a/apps/dav/tests/unit/migration/addressbookadaptertest.php b/apps/dav/tests/unit/migration/addressbookadaptertest.php
new file mode 100644
index 00000000000..e6e57049a93
--- /dev/null
+++ b/apps/dav/tests/unit/migration/addressbookadaptertest.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\Tests\Unit\Migration;
+
+use DomainException;
+use OCA\Dav\Migration\AddressBookAdapter;
+use OCP\IDBConnection;
+use Test\TestCase;
+
+/**
+ * Class AddressbookAdapterTest
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit\Migration
+ */
+class AddressbookAdapterTest extends TestCase {
+
+ /** @var IDBConnection */
+ private $db;
+ /** @var AddressBookAdapter */
+ private $adapter;
+ /** @var array */
+ private $books = [];
+ /** @var array */
+ private $cards = [];
+
+ public function setUp() {
+ parent::setUp();
+ $this->db = \OC::$server->getDatabaseConnection();
+
+ $manager = new \OC\DB\MDB2SchemaManager($this->db);
+ $manager->createDbFromStructure(__DIR__ . '/contacts_schema.xml');
+
+ $this->adapter = new AddressBookAdapter($this->db);
+ }
+
+ public function tearDown() {
+ $this->db->dropTable('contacts_addressbooks');
+ $this->db->dropTable('contacts_cards');
+ parent::tearDown();
+ }
+
+ /**
+ * @expectedException DomainException
+ */
+ public function testOldTablesDoNotExist() {
+ $adapter = new AddressBookAdapter(\OC::$server->getDatabaseConnection(), 'crazy_table_that_does_no_exist');
+ $adapter->setup();
+ }
+
+ public function test() {
+
+ // insert test data
+ $builder = $this->db->getQueryBuilder();
+ $builder->insert('contacts_addressbooks')
+ ->values([
+ 'userid' => $builder->createNamedParameter('test-user-666'),
+ 'displayname' => $builder->createNamedParameter('Display Name'),
+ 'uri' => $builder->createNamedParameter('contacts'),
+ 'description' => $builder->createNamedParameter('An address book for testing'),
+ 'ctag' => $builder->createNamedParameter('112233'),
+ 'active' => $builder->createNamedParameter('1')
+ ])
+ ->execute();
+ $builder = $this->db->getQueryBuilder();
+ $builder->insert('contacts_cards')
+ ->values([
+ 'addressbookid' => $builder->createNamedParameter(6666),
+ 'fullname' => $builder->createNamedParameter('Full Name'),
+ 'carddata' => $builder->createNamedParameter('datadatadata'),
+ 'uri' => $builder->createNamedParameter('some-card.vcf'),
+ 'lastmodified' => $builder->createNamedParameter('112233'),
+ ])
+ ->execute();
+ $builder = $this->db->getQueryBuilder();
+ $builder->insert('share')
+ ->values([
+ 'share_type' => $builder->createNamedParameter(1),
+ 'share_with' => $builder->createNamedParameter('user01'),
+ 'uid_owner' => $builder->createNamedParameter('user02'),
+ 'item_type' => $builder->createNamedParameter('addressbook'),
+ 'item_source' => $builder->createNamedParameter(6666),
+ 'item_target' => $builder->createNamedParameter('Contacts (user02)'),
+ ])
+ ->execute();
+
+ // test the adapter
+ $this->adapter->foreachBook('test-user-666', function($row) {
+ $this->books[] = $row;
+ });
+ $this->assertArrayHasKey('id', $this->books[0]);
+ $this->assertEquals('test-user-666', $this->books[0]['userid']);
+ $this->assertEquals('Display Name', $this->books[0]['displayname']);
+ $this->assertEquals('contacts', $this->books[0]['uri']);
+ $this->assertEquals('An address book for testing', $this->books[0]['description']);
+ $this->assertEquals('112233', $this->books[0]['ctag']);
+
+ $this->adapter->foreachCard(6666, function($row) {
+ $this->cards[]= $row;
+ });
+ $this->assertArrayHasKey('id', $this->cards[0]);
+ $this->assertEquals(6666, $this->cards[0]['addressbookid']);
+
+ // test getShares
+ $shares = $this->adapter->getShares(6666);
+ $this->assertEquals(1, count($shares));
+
+ }
+
+}
diff --git a/apps/dav/tests/unit/migration/contacts_schema.xml b/apps/dav/tests/unit/migration/contacts_schema.xml
new file mode 100644
index 00000000000..51836a1e0c6
--- /dev/null
+++ b/apps/dav/tests/unit/migration/contacts_schema.xml
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<database>
+
+ <name>*dbname*</name>
+ <create>true</create>
+ <overwrite>false</overwrite>
+ <charset>utf8</charset>
+ <table>
+
+ <name>*dbprefix*contacts_addressbooks</name>
+
+ <declaration>
+
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>userid</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>displayname</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>200</length>
+ </field>
+
+ <field>
+ <name>description</name>
+ <type>text</type>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>ctag</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>active</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <length>4</length>
+ </field>
+
+ <index>
+ <name>c_addressbook_userid_index</name>
+ <field>
+ <name>userid</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ </declaration>
+
+ </table>
+
+ <table>
+
+ <name>*dbprefix*contacts_cards</name>
+
+ <declaration>
+
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>addressbookid</name>
+ <type>integer</type>
+ <default></default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>fullname</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+
+ <field>
+ <name>carddata</name>
+ <type>clob</type>
+ <notnull>false</notnull>
+ </field>
+
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>200</length>
+ </field>
+
+ <field>
+ <name>lastmodified</name>
+ <type>integer</type>
+ <default></default>
+ <notnull>false</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+
+ <index>
+ <name>c_addressbookid_index</name>
+ <field>
+ <name>addressbookid</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ </declaration>
+
+ </table>
+
+</database>
diff --git a/apps/dav/tests/unit/migration/migrateaddressbooktest.php b/apps/dav/tests/unit/migration/migrateaddressbooktest.php
new file mode 100644
index 00000000000..1b27536ce3b
--- /dev/null
+++ b/apps/dav/tests/unit/migration/migrateaddressbooktest.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\Tests\Unit\Migration;
+
+use OCA\DAV\CardDAV\CardDavBackend;
+use OCA\Dav\Migration\AddressBookAdapter;
+use Test\TestCase;
+
+class MigrateAddressbookTest extends TestCase {
+
+ public function testMigration() {
+ /** @var AddressBookAdapter | \PHPUnit_Framework_MockObject_MockObject $adapter */
+ $adapter = $this->mockAdapter();
+
+ /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $cardDav */
+ $cardDav = $this->getMockBuilder('\OCA\Dav\CardDAV\CardDAVBackend')->disableOriginalConstructor()->getMock();
+ $cardDav->method('createAddressBook')->willReturn(666);
+ $cardDav->expects($this->once())->method('createAddressBook')->with('principals/users/test01', 'test_contacts');
+ $cardDav->expects($this->once())->method('createCard')->with(666, '63f0dd6c-39d5-44be-9d34-34e7a7441fc2.vcf', 'BEGIN:VCARD');
+
+ $m = new \OCA\Dav\Migration\MigrateAddressbooks($adapter, $cardDav);
+ $m->migrateForUser('test01');
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject
+ */
+ private function mockAdapter($shares = []) {
+ $adapter = $this->getMockBuilder('\OCA\Dav\Migration\AddressBookAdapter')->disableOriginalConstructor()->getMock();
+ $adapter->method('foreachBook')->willReturnCallback(function ($user, \Closure $callBack) {
+ $callBack([
+ 'id' => 0,
+ 'userid' => $user,
+ 'displayname' => 'Test Contacts',
+ 'uri' => 'test_contacts',
+ 'description' => 'Contacts to test with',
+ 'ctag' => 1234567890,
+ 'active' => 1
+ ]);
+ });
+ $adapter->method('foreachCard')->willReturnCallback(function ($addressBookId, \Closure $callBack) {
+ $callBack([
+ 'userid' => $addressBookId,
+ 'uri' => '63f0dd6c-39d5-44be-9d34-34e7a7441fc2.vcf',
+ 'carddata' => 'BEGIN:VCARD'
+ ]);
+ });
+ $adapter->method('getShares')->willReturn($shares);
+ return $adapter;
+ }
+
+}
diff --git a/apps/dav/tests/unit/phpunit.xml b/apps/dav/tests/unit/phpunit.xml
index 46c3cdfb345..314855d863b 100644
--- a/apps/dav/tests/unit/phpunit.xml
+++ b/apps/dav/tests/unit/phpunit.xml
@@ -6,7 +6,7 @@
timeoutForLargeTests="900"
>
<testsuite name='unit'>
- <directory suffix='test.php'>.</directory>
+ <directory suffix='.php'>.</directory>
</testsuite>
<!-- filters for code coverage -->
<filter>
diff --git a/apps/dav/tests/unit/servertest.php b/apps/dav/tests/unit/servertest.php
new file mode 100644
index 00000000000..63bab482b45
--- /dev/null
+++ b/apps/dav/tests/unit/servertest.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace OCA\DAV\Tests\Unit;
+
+use OCA\DAV\Server;
+use OCP\IRequest;
+
+/**
+ * Class ServerTest
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit
+ */
+class ServerTest extends \Test\TestCase {
+
+ public function test() {
+ /** @var IRequest $r */
+ $r = $this->getMockBuilder('\OCP\IRequest')
+ ->disableOriginalConstructor()->getMock();
+ $s = new Server($r, '/');
+ $this->assertNotNull($s->server);
+ }
+} \ No newline at end of file
diff --git a/apps/dav/tests/unit/systemtag/systemtagmappingnode.php b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php
new file mode 100644
index 00000000000..7f2ff7d6616
--- /dev/null
+++ b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\SystemTag;
+
+use Sabre\DAV\Exception\NotFound;
+use OC\SystemTag\SystemTag;
+use OCP\SystemTag\TagNotFoundException;
+
+class SystemTagMappingNode extends \Test\TestCase {
+
+ /**
+ * @var \OCP\SystemTag\ISystemTagManager
+ */
+ private $tagManager;
+
+ /**
+ * @var \OCP\SystemTag\ISystemTagObjectMapper
+ */
+ private $tagMapper;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager');
+ $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper');
+ }
+
+ public function getMappingNode($isAdmin = true, $tag = null) {
+ if ($tag === null) {
+ $tag = new SystemTag(1, 'Test', true, true);
+ }
+ return new \OCA\DAV\SystemTag\SystemTagMappingNode(
+ $tag,
+ 123,
+ 'files',
+ $isAdmin,
+ $this->tagManager,
+ $this->tagMapper
+ );
+ }
+
+ public function testGetters() {
+ $tag = new SystemTag(1, 'Test', true, false);
+ $node = $this->getMappingNode(true, $tag);
+ $this->assertEquals('1', $node->getName());
+ $this->assertEquals($tag, $node->getSystemTag());
+ $this->assertEquals(123, $node->getObjectId());
+ $this->assertEquals('files', $node->getObjectType());
+ }
+
+ public function adminFlagProvider() {
+ return [[true], [false]];
+ }
+
+ /**
+ * @dataProvider adminFlagProvider
+ */
+ public function testDeleteTag($isAdmin) {
+ $this->tagManager->expects($this->never())
+ ->method('deleteTags');
+ $this->tagMapper->expects($this->once())
+ ->method('unassignTags')
+ ->with(123, 'files', 1);
+
+ $this->getMappingNode($isAdmin)->delete();
+ }
+
+ public function tagNodeDeleteProviderPermissionException() {
+ return [
+ [
+ // cannot unassign invisible tag
+ new SystemTag(1, 'Original', false, true),
+ 'Sabre\DAV\Exception\NotFound',
+ ],
+ [
+ // cannot unassign non-assignable tag
+ new SystemTag(1, 'Original', true, false),
+ 'Sabre\DAV\Exception\Forbidden',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider tagNodeDeleteProviderPermissionException
+ */
+ public function testDeleteTagExpectedException($tag, $expectedException) {
+ $this->tagManager->expects($this->never())
+ ->method('deleteTags');
+ $this->tagMapper->expects($this->never())
+ ->method('unassignTags');
+
+ $thrown = null;
+ try {
+ $this->getMappingNode(false, $tag)->delete();
+ } catch (\Exception $e) {
+ $thrown = $e;
+ }
+
+ $this->assertInstanceOf($expectedException, $thrown);
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\NotFound
+ */
+ public function testDeleteTagNotFound() {
+ $this->tagMapper->expects($this->once())
+ ->method('unassignTags')
+ ->with(123, 'files', 1)
+ ->will($this->throwException(new TagNotFoundException()));
+
+ $this->getMappingNode()->delete();
+ }
+}
diff --git a/apps/dav/tests/unit/systemtag/systemtagnode.php b/apps/dav/tests/unit/systemtag/systemtagnode.php
new file mode 100644
index 00000000000..5184b74e5c8
--- /dev/null
+++ b/apps/dav/tests/unit/systemtag/systemtagnode.php
@@ -0,0 +1,244 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\SystemTag;
+
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Exception\MethodNotAllowed;
+use Sabre\DAV\Exception\Conflict;
+
+use OC\SystemTag\SystemTag;
+use OCP\SystemTag\TagNotFoundException;
+use OCP\SystemTag\TagAlreadyExistsException;
+
+class SystemTagNode extends \Test\TestCase {
+
+ /**
+ * @var \OCP\SystemTag\ISystemTagManager
+ */
+ private $tagManager;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager');
+ }
+
+ protected function getTagNode($isAdmin = true, $tag = null) {
+ if ($tag === null) {
+ $tag = new SystemTag(1, 'Test', true, true);
+ }
+ return new \OCA\DAV\SystemTag\SystemTagNode(
+ $tag,
+ $isAdmin,
+ $this->tagManager
+ );
+ }
+
+ public function adminFlagProvider() {
+ return [[true], [false]];
+ }
+
+ /**
+ * @dataProvider adminFlagProvider
+ */
+ public function testGetters($isAdmin) {
+ $tag = new SystemTag('1', 'Test', true, true);
+ $node = $this->getTagNode($isAdmin, $tag);
+ $this->assertEquals('1', $node->getName());
+ $this->assertEquals($tag, $node->getSystemTag());
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\MethodNotAllowed
+ */
+ public function testSetName() {
+ $this->getTagNode()->setName('2');
+ }
+
+ public function tagNodeProvider() {
+ return [
+ // admin
+ [
+ true,
+ new SystemTag(1, 'Original', true, true),
+ ['Renamed', true, true]
+ ],
+ [
+ true,
+ new SystemTag(1, 'Original', true, true),
+ ['Original', false, false]
+ ],
+ // non-admin
+ [
+ // renaming allowed
+ false,
+ new SystemTag(1, 'Original', true, true),
+ ['Rename', true, true]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider tagNodeProvider
+ */
+ public function testUpdateTag($isAdmin, $originalTag, $changedArgs) {
+ $this->tagManager->expects($this->once())
+ ->method('updateTag')
+ ->with(1, $changedArgs[0], $changedArgs[1], $changedArgs[2]);
+ $this->getTagNode($isAdmin, $originalTag)
+ ->update($changedArgs[0], $changedArgs[1], $changedArgs[2]);
+ }
+
+ public function tagNodeProviderPermissionException() {
+ return [
+ [
+ // changing permissions not allowed
+ new SystemTag(1, 'Original', true, true),
+ ['Original', false, true],
+ 'Sabre\DAV\Exception\Forbidden',
+ ],
+ [
+ // changing permissions not allowed
+ new SystemTag(1, 'Original', true, true),
+ ['Original', true, false],
+ 'Sabre\DAV\Exception\Forbidden',
+ ],
+ [
+ // changing permissions not allowed
+ new SystemTag(1, 'Original', true, true),
+ ['Original', false, false],
+ 'Sabre\DAV\Exception\Forbidden',
+ ],
+ [
+ // changing non-assignable not allowed
+ new SystemTag(1, 'Original', true, false),
+ ['Rename', true, false],
+ 'Sabre\DAV\Exception\Forbidden',
+ ],
+ [
+ // changing non-assignable not allowed
+ new SystemTag(1, 'Original', true, false),
+ ['Original', true, true],
+ 'Sabre\DAV\Exception\Forbidden',
+ ],
+ [
+ // invisible tag does not exist
+ new SystemTag(1, 'Original', false, false),
+ ['Rename', false, false],
+ 'Sabre\DAV\Exception\NotFound',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider tagNodeProviderPermissionException
+ */
+ public function testUpdateTagPermissionException($originalTag, $changedArgs, $expectedException = null) {
+ $this->tagManager->expects($this->never())
+ ->method('updateTag');
+
+ $thrown = null;
+
+ try {
+ $this->getTagNode(false, $originalTag)
+ ->update($changedArgs[0], $changedArgs[1], $changedArgs[2]);
+ } catch (\Exception $e) {
+ $thrown = $e;
+ }
+
+ $this->assertInstanceOf($expectedException, $thrown);
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Conflict
+ */
+ public function testUpdateTagAlreadyExists() {
+ $this->tagManager->expects($this->once())
+ ->method('updateTag')
+ ->with(1, 'Renamed', false, true)
+ ->will($this->throwException(new TagAlreadyExistsException()));
+ $this->getTagNode()->update('Renamed', false, true);
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\NotFound
+ */
+ public function testUpdateTagNotFound() {
+ $this->tagManager->expects($this->once())
+ ->method('updateTag')
+ ->with(1, 'Renamed', false, true)
+ ->will($this->throwException(new TagNotFoundException()));
+ $this->getTagNode()->update('Renamed', false, true);
+ }
+
+ /**
+ * @dataProvider adminFlagProvider
+ */
+ public function testDeleteTag($isAdmin) {
+ $this->tagManager->expects($this->once())
+ ->method('deleteTags')
+ ->with('1');
+ $this->getTagNode($isAdmin)->delete();
+ }
+
+ public function tagNodeDeleteProviderPermissionException() {
+ return [
+ [
+ // cannot delete invisible tag
+ new SystemTag(1, 'Original', false, true),
+ 'Sabre\DAV\Exception\NotFound',
+ ],
+ [
+ // cannot delete non-assignable tag
+ new SystemTag(1, 'Original', true, false),
+ 'Sabre\DAV\Exception\Forbidden',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider tagNodeDeleteProviderPermissionException
+ */
+ public function testDeleteTagPermissionException($tag, $expectedException) {
+ $this->tagManager->expects($this->never())
+ ->method('deleteTags');
+
+ try {
+ $this->getTagNode(false, $tag)->delete();
+ } catch (\Exception $e) {
+ $thrown = $e;
+ }
+
+ $this->assertInstanceOf($expectedException, $thrown);
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\NotFound
+ */
+ public function testDeleteTagNotFound() {
+ $this->tagManager->expects($this->once())
+ ->method('deleteTags')
+ ->with('1')
+ ->will($this->throwException(new TagNotFoundException()));
+ $this->getTagNode()->delete();
+ }
+}
diff --git a/apps/dav/tests/unit/systemtag/systemtagplugin.php b/apps/dav/tests/unit/systemtag/systemtagplugin.php
new file mode 100644
index 00000000000..b026451701f
--- /dev/null
+++ b/apps/dav/tests/unit/systemtag/systemtagplugin.php
@@ -0,0 +1,355 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\SystemTag;
+
+use OC\SystemTag\SystemTag;
+use OCP\SystemTag\TagAlreadyExistsException;
+
+class SystemTagPlugin extends \Test\TestCase {
+
+ const ID_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::ID_PROPERTYNAME;
+ const DISPLAYNAME_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::DISPLAYNAME_PROPERTYNAME;
+ const USERVISIBLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USERVISIBLE_PROPERTYNAME;
+ const USERASSIGNABLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USERASSIGNABLE_PROPERTYNAME;
+
+ /**
+ * @var \Sabre\DAV\Server
+ */
+ private $server;
+
+ /**
+ * @var \Sabre\DAV\Tree
+ */
+ private $tree;
+
+ /**
+ * @var \OCP\SystemTag\ISystemTagManager
+ */
+ private $tagManager;
+
+ /**
+ * @var \OCA\DAV\SystemTag\SystemTagPlugin
+ */
+ private $plugin;
+
+ public function setUp() {
+ parent::setUp();
+ $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->server = new \Sabre\DAV\Server($this->tree);
+
+ $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager');
+
+ $this->plugin = new \OCA\DAV\SystemTag\SystemTagPlugin($this->tagManager);
+ $this->plugin->initialize($this->server);
+ }
+
+ public function testGetProperties() {
+ $systemTag = new SystemTag(1, 'Test', true, true);
+ $requestedProperties = [
+ self::ID_PROPERTYNAME,
+ self::DISPLAYNAME_PROPERTYNAME,
+ self::USERVISIBLE_PROPERTYNAME,
+ self::USERASSIGNABLE_PROPERTYNAME
+ ];
+ $expectedProperties = [
+ 200 => [
+ self::ID_PROPERTYNAME => '1',
+ self::DISPLAYNAME_PROPERTYNAME => 'Test',
+ self::USERVISIBLE_PROPERTYNAME => 'true',
+ self::USERASSIGNABLE_PROPERTYNAME => 'true',
+ ]
+ ];
+
+ $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->any())
+ ->method('getSystemTag')
+ ->will($this->returnValue($systemTag));
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/systemtag/1')
+ ->will($this->returnValue($node));
+
+ $propFind = new \Sabre\DAV\PropFind(
+ '/systemtag/1',
+ $requestedProperties,
+ 0
+ );
+
+ $this->plugin->handleGetProperties(
+ $propFind,
+ $node
+ );
+
+ $result = $propFind->getResultForMultiStatus();
+
+ $this->assertEmpty($result[404]);
+ unset($result[404]);
+ $this->assertEquals($expectedProperties, $result);
+ }
+
+ public function testUpdateProperties() {
+ $systemTag = new SystemTag(1, 'Test', true, false);
+ $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->any())
+ ->method('getSystemTag')
+ ->will($this->returnValue($systemTag));
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/systemtag/1')
+ ->will($this->returnValue($node));
+
+ $node->expects($this->once())
+ ->method('update')
+ ->with('Test changed', false, true);
+
+ // properties to set
+ $propPatch = new \Sabre\DAV\PropPatch(array(
+ self::DISPLAYNAME_PROPERTYNAME => 'Test changed',
+ self::USERVISIBLE_PROPERTYNAME => 'false',
+ self::USERASSIGNABLE_PROPERTYNAME => 'true',
+ ));
+
+ $this->plugin->handleUpdateProperties(
+ '/systemtag/1',
+ $propPatch
+ );
+
+ $propPatch->commit();
+
+ // all requested properties removed, as they were processed already
+ $this->assertEmpty($propPatch->getRemainingMutations());
+
+ $result = $propPatch->getResult();
+ $this->assertEquals(200, $result[self::DISPLAYNAME_PROPERTYNAME]);
+ $this->assertEquals(200, $result[self::USERASSIGNABLE_PROPERTYNAME]);
+ $this->assertEquals(200, $result[self::USERVISIBLE_PROPERTYNAME]);
+ }
+
+ public function testCreateTagInByIdCollection() {
+ $systemTag = new SystemTag(1, 'Test', true, false);
+
+ $requestData = json_encode([
+ 'name' => 'Test',
+ 'userVisible' => true,
+ 'userAssignable' => false,
+ ]);
+
+ $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsByIdCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->tagManager->expects($this->once())
+ ->method('createTag')
+ ->with('Test', true, false)
+ ->will($this->returnValue($systemTag));
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/systemtags')
+ ->will($this->returnValue($node));
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/systemtags'));
+
+ $request->expects($this->once())
+ ->method('getBodyAsString')
+ ->will($this->returnValue($requestData));
+
+ $request->expects($this->once())
+ ->method('getHeader')
+ ->with('Content-Type')
+ ->will($this->returnValue('application/json'));
+
+ $request->expects($this->once())
+ ->method('getUrl')
+ ->will($this->returnValue('http://example.com/dav/systemtags'));
+
+ $response->expects($this->once())
+ ->method('setHeader')
+ ->with('Content-Location', 'http://example.com/dav/systemtags/1');
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+ public function nodeClassProvider() {
+ return [
+ ['\OCA\DAV\SystemTag\SystemTagsByIdCollection'],
+ ['\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection'],
+ ];
+ }
+
+ public function testCreateTagInMappingCollection() {
+ $systemTag = new SystemTag(1, 'Test', true, false);
+
+ $requestData = json_encode([
+ 'name' => 'Test',
+ 'userVisible' => true,
+ 'userAssignable' => false,
+ ]);
+
+ $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->tagManager->expects($this->once())
+ ->method('createTag')
+ ->with('Test', true, false)
+ ->will($this->returnValue($systemTag));
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/systemtags-relations/files/12')
+ ->will($this->returnValue($node));
+
+ $node->expects($this->once())
+ ->method('createFile')
+ ->with(1);
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/systemtags-relations/files/12'));
+
+ $request->expects($this->once())
+ ->method('getBodyAsString')
+ ->will($this->returnValue($requestData));
+
+ $request->expects($this->once())
+ ->method('getHeader')
+ ->with('Content-Type')
+ ->will($this->returnValue('application/json'));
+
+ $request->expects($this->once())
+ ->method('getBaseUrl')
+ ->will($this->returnValue('http://example.com/dav/'));
+
+ $response->expects($this->once())
+ ->method('setHeader')
+ ->with('Content-Location', 'http://example.com/dav/systemtags/1');
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotFound
+ */
+ public function testCreateTagToUnknownNode() {
+ $systemTag = new SystemTag(1, 'Test', true, false);
+
+ $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->will($this->throwException(new \Sabre\DAV\Exception\NotFound()));
+
+ $this->tagManager->expects($this->never())
+ ->method('createTag');
+
+ $node->expects($this->never())
+ ->method('createFile');
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/systemtags-relations/files/12'));
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+ /**
+ * @dataProvider nodeClassProvider
+ * @expectedException Sabre\DAV\Exception\Conflict
+ */
+ public function testCreateTagConflict($nodeClass) {
+ $requestData = json_encode([
+ 'name' => 'Test',
+ 'userVisible' => true,
+ 'userAssignable' => false,
+ ]);
+
+ $node = $this->getMockBuilder($nodeClass)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->tagManager->expects($this->once())
+ ->method('createTag')
+ ->with('Test', true, false)
+ ->will($this->throwException(new TagAlreadyExistsException('Tag already exists')));
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/systemtags')
+ ->will($this->returnValue($node));
+
+ $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $request->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/systemtags'));
+
+ $request->expects($this->once())
+ ->method('getBodyAsString')
+ ->will($this->returnValue($requestData));
+
+ $request->expects($this->once())
+ ->method('getHeader')
+ ->with('Content-Type')
+ ->will($this->returnValue('application/json'));
+
+ $this->plugin->httpPost($request, $response);
+ }
+
+}
diff --git a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php
new file mode 100644
index 00000000000..a2bf571ab68
--- /dev/null
+++ b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php
@@ -0,0 +1,244 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\SystemTag;
+
+
+use OC\SystemTag\SystemTag;
+use OCP\SystemTag\TagNotFoundException;
+
+class SystemTagsByIdCollection extends \Test\TestCase {
+
+ /**
+ * @var \OCP\SystemTag\ISystemTagManager
+ */
+ private $tagManager;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager');
+ }
+
+ public function getNode($isAdmin = true) {
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('testuser'));
+ $userSession = $this->getMock('\OCP\IUserSession');
+ $userSession->expects($this->any())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+ $groupManager = $this->getMock('\OCP\IGroupManager');
+ $groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->with('testuser')
+ ->will($this->returnValue($isAdmin));
+ return new \OCA\DAV\SystemTag\SystemTagsByIdCollection(
+ $this->tagManager,
+ $userSession,
+ $groupManager
+ );
+ }
+
+ public function adminFlagProvider() {
+ return [[true], [false]];
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Forbidden
+ */
+ public function testForbiddenCreateFile() {
+ $this->getNode()->createFile('555');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Forbidden
+ */
+ public function testForbiddenCreateDirectory() {
+ $this->getNode()->createDirectory('789');
+ }
+
+ public function getChildProvider() {
+ return [
+ [
+ true,
+ true,
+ ],
+ [
+ true,
+ false,
+ ],
+ [
+ false,
+ true,
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider getChildProvider
+ */
+ public function testGetChild($isAdmin, $userVisible) {
+ $tag = new SystemTag(123, 'Test', $userVisible, false);
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['123'])
+ ->will($this->returnValue([$tag]));
+
+ $childNode = $this->getNode($isAdmin)->getChild('123');
+
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode);
+ $this->assertEquals('123', $childNode->getName());
+ $this->assertEquals($tag, $childNode->getSystemTag());
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\BadRequest
+ */
+ public function testGetChildInvalidName() {
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['invalid'])
+ ->will($this->throwException(new \InvalidArgumentException()));
+
+ $this->getNode()->getChild('invalid');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\NotFound
+ */
+ public function testGetChildNotFound() {
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['444'])
+ ->will($this->throwException(new TagNotFoundException()));
+
+ $this->getNode()->getChild('444');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\NotFound
+ */
+ public function testGetChildUserNotVisible() {
+ $tag = new SystemTag(123, 'Test', false, false);
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['123'])
+ ->will($this->returnValue([$tag]));
+
+ $this->getNode(false)->getChild('123');
+ }
+
+ public function testGetChildrenAdmin() {
+ $tag1 = new SystemTag(123, 'One', true, false);
+ $tag2 = new SystemTag(456, 'Two', true, true);
+
+ $this->tagManager->expects($this->once())
+ ->method('getAllTags')
+ ->with(null)
+ ->will($this->returnValue([$tag1, $tag2]));
+
+ $children = $this->getNode(true)->getChildren();
+
+ $this->assertCount(2, $children);
+
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[0]);
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[1]);
+ $this->assertEquals($tag1, $children[0]->getSystemTag());
+ $this->assertEquals($tag2, $children[1]->getSystemTag());
+ }
+
+ public function testGetChildrenNonAdmin() {
+ $tag1 = new SystemTag(123, 'One', true, false);
+ $tag2 = new SystemTag(456, 'Two', true, true);
+
+ $this->tagManager->expects($this->once())
+ ->method('getAllTags')
+ ->with(true)
+ ->will($this->returnValue([$tag1, $tag2]));
+
+ $children = $this->getNode(false)->getChildren();
+
+ $this->assertCount(2, $children);
+
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[0]);
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[1]);
+ $this->assertEquals($tag1, $children[0]->getSystemTag());
+ $this->assertEquals($tag2, $children[1]->getSystemTag());
+ }
+
+ public function testGetChildrenEmpty() {
+ $this->tagManager->expects($this->once())
+ ->method('getAllTags')
+ ->with(null)
+ ->will($this->returnValue([]));
+ $this->assertCount(0, $this->getNode()->getChildren());
+ }
+
+ public function childExistsProvider() {
+ return [
+ // admins, always visible
+ [true, true, true],
+ [true, false, true],
+ // non-admins, depends on flag
+ [false, true, true],
+ [false, false, false],
+ ];
+ }
+
+ /**
+ * @dataProvider childExistsProvider
+ */
+ public function testChildExists($isAdmin, $userVisible, $expectedResult) {
+ $tag = new SystemTag(123, 'One', $userVisible, false);
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['123'])
+ ->will($this->returnValue([$tag]));
+
+ $this->assertEquals($expectedResult, $this->getNode($isAdmin)->childExists('123'));
+ }
+
+ public function testChildExistsNotFound() {
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['123'])
+ ->will($this->throwException(new TagNotFoundException()));
+
+ $this->assertFalse($this->getNode()->childExists('123'));
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\BadRequest
+ */
+ public function testChildExistsBadRequest() {
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['invalid'])
+ ->will($this->throwException(new \InvalidArgumentException()));
+
+ $this->getNode()->childExists('invalid');
+ }
+}
diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php
new file mode 100644
index 00000000000..df97acd846b
--- /dev/null
+++ b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php
@@ -0,0 +1,381 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\SystemTag;
+
+
+use OC\SystemTag\SystemTag;
+use OCP\SystemTag\TagNotFoundException;
+
+class SystemTagsObjectMappingCollection extends \Test\TestCase {
+
+ /**
+ * @var \OCP\SystemTag\ISystemTagManager
+ */
+ private $tagManager;
+
+ /**
+ * @var \OCP\SystemTag\ISystemTagMapper
+ */
+ private $tagMapper;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager');
+ $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper');
+ }
+
+ public function getNode($isAdmin = true) {
+ return new \OCA\DAV\SystemTag\SystemTagsObjectMappingCollection (
+ 111,
+ 'files',
+ $isAdmin,
+ $this->tagManager,
+ $this->tagMapper
+ );
+ }
+
+ public function testAssignTagAsAdmin() {
+ $this->tagManager->expects($this->never())
+ ->method('getTagsByIds');
+ $this->tagMapper->expects($this->once())
+ ->method('assignTags')
+ ->with(111, 'files', '555');
+
+ $this->getNode(true)->createFile('555');
+ }
+
+ public function testAssignTagAsUser() {
+ $tag = new SystemTag('1', 'Test', true, true);
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with('555')
+ ->will($this->returnValue([$tag]));
+ $this->tagMapper->expects($this->once())
+ ->method('assignTags')
+ ->with(111, 'files', '555');
+
+ $this->getNode(false)->createFile('555');
+ }
+
+ public function permissionsProvider() {
+ return [
+ // invisible, tag does not exist for user
+ [false, true, '\Sabre\DAV\Exception\PreconditionFailed'],
+ // visible but static, cannot assign tag
+ [true, false, '\Sabre\DAV\Exception\Forbidden'],
+ ];
+ }
+
+ /**
+ * @dataProvider permissionsProvider
+ */
+ public function testAssignTagAsUserNoPermission($userVisible, $userAssignable, $expectedException) {
+ $tag = new SystemTag('1', 'Test', $userVisible, $userAssignable);
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with('555')
+ ->will($this->returnValue([$tag]));
+ $this->tagMapper->expects($this->never())
+ ->method('assignTags');
+
+ $thrown = null;
+ try {
+ $this->getNode(false)->createFile('555');
+ } catch (\Exception $e) {
+ $thrown = $e;
+ }
+
+ $this->assertInstanceOf($expectedException, $thrown);
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\PreconditionFailed
+ */
+ public function testAssignTagNotFound() {
+ $this->tagMapper->expects($this->once())
+ ->method('assignTags')
+ ->with(111, 'files', '555')
+ ->will($this->throwException(new TagNotFoundException()));
+
+ $this->getNode()->createFile('555');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Forbidden
+ */
+ public function testForbiddenCreateDirectory() {
+ $this->getNode()->createDirectory('789');
+ }
+
+ public function getChildProvider() {
+ return [
+ [
+ true,
+ true,
+ ],
+ [
+ true,
+ false,
+ ],
+ [
+ false,
+ true,
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider getChildProvider
+ */
+ public function testGetChild($isAdmin, $userVisible) {
+ $tag = new SystemTag(555, 'TheTag', $userVisible, false);
+
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '555', true)
+ ->will($this->returnValue(true));
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['555'])
+ ->will($this->returnValue(['555' => $tag]));
+
+ $childNode = $this->getNode($isAdmin)->getChild('555');
+
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode);
+ $this->assertEquals('555', $childNode->getName());
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotFound
+ */
+ public function testGetChildUserNonVisible() {
+ $tag = new SystemTag(555, 'TheTag', false, false);
+
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '555', true)
+ ->will($this->returnValue(true));
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['555'])
+ ->will($this->returnValue(['555' => $tag]));
+
+ $this->getNode(false)->getChild('555');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\NotFound
+ */
+ public function testGetChildRelationNotFound() {
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '777')
+ ->will($this->returnValue(false));
+
+ $this->getNode()->getChild('777');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\BadRequest
+ */
+ public function testGetChildInvalidId() {
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', 'badid')
+ ->will($this->throwException(new \InvalidArgumentException()));
+
+ $this->getNode()->getChild('badid');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\NotFound
+ */
+ public function testGetChildTagDoesNotExist() {
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '777')
+ ->will($this->throwException(new TagNotFoundException()));
+
+ $this->getNode()->getChild('777');
+ }
+
+ public function testGetChildrenAsAdmin() {
+ $tag1 = new SystemTag(555, 'TagOne', true, false);
+ $tag2 = new SystemTag(556, 'TagTwo', true, true);
+ $tag3 = new SystemTag(557, 'InvisibleTag', false, true);
+
+ $this->tagMapper->expects($this->once())
+ ->method('getTagIdsForObjects')
+ ->with([111], 'files')
+ ->will($this->returnValue(['111' => ['555', '556', '557']]));
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['555', '556', '557'])
+ ->will($this->returnValue(['555' => $tag1, '556' => $tag2, '557' => $tag3]));
+
+ $children = $this->getNode(true)->getChildren();
+
+ $this->assertCount(3, $children);
+
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[0]);
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[1]);
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[2]);
+
+ $this->assertEquals(111, $children[0]->getObjectId());
+ $this->assertEquals('files', $children[0]->getObjectType());
+ $this->assertEquals($tag1, $children[0]->getSystemTag());
+
+ $this->assertEquals(111, $children[1]->getObjectId());
+ $this->assertEquals('files', $children[1]->getObjectType());
+ $this->assertEquals($tag2, $children[1]->getSystemTag());
+
+ $this->assertEquals(111, $children[2]->getObjectId());
+ $this->assertEquals('files', $children[2]->getObjectType());
+ $this->assertEquals($tag3, $children[2]->getSystemTag());
+ }
+
+ public function testGetChildrenAsUser() {
+ $tag1 = new SystemTag(555, 'TagOne', true, false);
+ $tag2 = new SystemTag(556, 'TagTwo', true, true);
+ $tag3 = new SystemTag(557, 'InvisibleTag', false, true);
+
+ $this->tagMapper->expects($this->once())
+ ->method('getTagIdsForObjects')
+ ->with([111], 'files')
+ ->will($this->returnValue(['111' => ['555', '556', '557']]));
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with(['555', '556', '557'])
+ ->will($this->returnValue(['555' => $tag1, '556' => $tag2, '557' => $tag3]));
+
+ $children = $this->getNode(false)->getChildren();
+
+ $this->assertCount(2, $children);
+
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[0]);
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[1]);
+
+ $this->assertEquals(111, $children[0]->getObjectId());
+ $this->assertEquals('files', $children[0]->getObjectType());
+ $this->assertEquals($tag1, $children[0]->getSystemTag());
+
+ $this->assertEquals(111, $children[1]->getObjectId());
+ $this->assertEquals('files', $children[1]->getObjectType());
+ $this->assertEquals($tag2, $children[1]->getSystemTag());
+ }
+
+ public function testChildExistsAsAdmin() {
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '555')
+ ->will($this->returnValue(true));
+
+ $this->assertTrue($this->getNode(true)->childExists('555'));
+ }
+
+ public function testChildExistsWithVisibleTagAsUser() {
+ $tag = new SystemTag(555, 'TagOne', true, false);
+
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '555')
+ ->will($this->returnValue(true));
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with('555')
+ ->will($this->returnValue([$tag]));
+
+ $this->assertTrue($this->getNode(false)->childExists('555'));
+ }
+
+ public function testChildExistsWithInvisibleTagAsUser() {
+ $tag = new SystemTag(555, 'TagOne', false, false);
+
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '555')
+ ->will($this->returnValue(true));
+
+ $this->tagManager->expects($this->once())
+ ->method('getTagsByIds')
+ ->with('555')
+ ->will($this->returnValue([$tag]));
+
+ $this->assertFalse($this->getNode(false)->childExists('555'));
+ }
+
+ public function testChildExistsNotFound() {
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '555')
+ ->will($this->returnValue(false));
+
+ $this->assertFalse($this->getNode()->childExists('555'));
+ }
+
+ public function testChildExistsTagNotFound() {
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '555')
+ ->will($this->throwException(new TagNotFoundException()));
+
+ $this->assertFalse($this->getNode()->childExists('555'));
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\BadRequest
+ */
+ public function testChildExistsInvalidId() {
+ $this->tagMapper->expects($this->once())
+ ->method('haveTag')
+ ->with([111], 'files', '555')
+ ->will($this->throwException(new \InvalidArgumentException()));
+
+ $this->getNode()->childExists('555');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Forbidden
+ */
+ public function testDelete() {
+ $this->getNode()->delete();
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Forbidden
+ */
+ public function testSetName() {
+ $this->getNode()->setName('somethingelse');
+ }
+
+ public function testGetName() {
+ $this->assertEquals('111', $this->getNode()->getName());
+ }
+}
diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php
new file mode 100644
index 00000000000..1d4264f94f9
--- /dev/null
+++ b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php
@@ -0,0 +1,160 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Tests\Unit\SystemTag;
+
+class SystemTagsObjectTypeCollection extends \Test\TestCase {
+
+ /**
+ * @var \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection
+ */
+ private $node;
+
+ /**
+ * @var \OCP\SystemTag\ISystemTagManager
+ */
+ private $tagManager;
+
+ /**
+ * @var \OCP\SystemTag\ISystemTagMapper
+ */
+ private $tagMapper;
+
+ /**
+ * @var \OCP\Files\Folder
+ */
+ private $userFolder;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager');
+ $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper');
+
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('testuser'));
+ $userSession = $this->getMock('\OCP\IUserSession');
+ $userSession->expects($this->any())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+ $groupManager = $this->getMock('\OCP\IGroupManager');
+ $groupManager->expects($this->any())
+ ->method('isAdmin')
+ ->with('testuser')
+ ->will($this->returnValue(true));
+
+ $this->userFolder = $this->getMock('\OCP\Files\Folder');
+
+ $fileRoot = $this->getMock('\OCP\Files\IRootFolder');
+ $fileRoot->expects($this->any())
+ ->method('getUserfolder')
+ ->with('testuser')
+ ->will($this->returnValue($this->userFolder));
+
+ $this->node = new \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection(
+ 'files',
+ $this->tagManager,
+ $this->tagMapper,
+ $userSession,
+ $groupManager,
+ $fileRoot
+ );
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Forbidden
+ */
+ public function testForbiddenCreateFile() {
+ $this->node->createFile('555');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Forbidden
+ */
+ public function testForbiddenCreateDirectory() {
+ $this->node->createDirectory('789');
+ }
+
+ public function testGetChild() {
+ $this->userFolder->expects($this->once())
+ ->method('getById')
+ ->with('555')
+ ->will($this->returnValue([true]));
+ $childNode = $this->node->getChild('555');
+
+ $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection', $childNode);
+ $this->assertEquals('555', $childNode->getName());
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\NotFound
+ */
+ public function testGetChildWithoutAccess() {
+ $this->userFolder->expects($this->once())
+ ->method('getById')
+ ->with('555')
+ ->will($this->returnValue([]));
+ $this->node->getChild('555');
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\MethodNotAllowed
+ */
+ public function testGetChildren() {
+ $this->node->getChildren();
+ }
+
+ public function testChildExists() {
+ $this->userFolder->expects($this->once())
+ ->method('getById')
+ ->with('123')
+ ->will($this->returnValue([true]));
+ $this->assertTrue($this->node->childExists('123'));
+ }
+
+ public function testChildExistsWithoutAccess() {
+ $this->userFolder->expects($this->once())
+ ->method('getById')
+ ->with('555')
+ ->will($this->returnValue([]));
+ $this->assertFalse($this->node->childExists('555'));
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Forbidden
+ */
+ public function testDelete() {
+ $this->node->delete();
+ }
+
+ /**
+ * @expectedException Sabre\DAV\Exception\Forbidden
+ */
+ public function testSetName() {
+ $this->node->setName('somethingelse');
+ }
+
+ public function testGetName() {
+ $this->assertEquals('files', $this->node->getName());
+ }
+}
diff --git a/apps/encryption/appinfo/app.php b/apps/encryption/appinfo/app.php
index 1f336c05a8c..7c684b563d8 100644
--- a/apps/encryption/appinfo/app.php
+++ b/apps/encryption/appinfo/app.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/appinfo/application.php b/apps/encryption/appinfo/application.php
index 6275047252e..433e9e86284 100644
--- a/apps/encryption/appinfo/application.php
+++ b/apps/encryption/appinfo/application.php
@@ -4,7 +4,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/appinfo/info.xml b/apps/encryption/appinfo/info.xml
index 2224f026e4d..970b58e3898 100644
--- a/apps/encryption/appinfo/info.xml
+++ b/apps/encryption/appinfo/info.xml
@@ -12,9 +12,8 @@
to enable server-side encryption.
</description>
<name>Default encryption module</name>
- <license>AGPL</license>
+ <licence>AGPL</licence>
<author>Bjoern Schiessle, Clark Tomlinson</author>
- <shipped>true</shipped>
<documentation>
<user>user-encryption</user>
<admin>admin-encryption</admin>
@@ -26,7 +25,7 @@
</types>
<dependencies>
<lib>openssl</lib>
- <owncloud min-version="9.0" />
+ <owncloud min-version="9.0" max-version="9.0" />
</dependencies>
</info>
diff --git a/apps/encryption/appinfo/register_command.php b/apps/encryption/appinfo/register_command.php
index 4987ef24d61..2bb49d55c2e 100644
--- a/apps/encryption/appinfo/register_command.php
+++ b/apps/encryption/appinfo/register_command.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/appinfo/routes.php b/apps/encryption/appinfo/routes.php
index 260337361e8..2ceba7898e9 100644
--- a/apps/encryption/appinfo/routes.php
+++ b/apps/encryption/appinfo/routes.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/command/enablemasterkey.php b/apps/encryption/command/enablemasterkey.php
index f49579a3b81..fd86c221176 100644
--- a/apps/encryption/command/enablemasterkey.php
+++ b/apps/encryption/command/enablemasterkey.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/command/migratekeys.php b/apps/encryption/command/migratekeys.php
index 89e2aa01610..88d8d46973f 100644
--- a/apps/encryption/command/migratekeys.php
+++ b/apps/encryption/command/migratekeys.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/controller/recoverycontroller.php b/apps/encryption/controller/recoverycontroller.php
index f1a2651443e..e4b02e004dc 100644
--- a/apps/encryption/controller/recoverycontroller.php
+++ b/apps/encryption/controller/recoverycontroller.php
@@ -4,7 +4,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/controller/settingscontroller.php b/apps/encryption/controller/settingscontroller.php
index 59e23087b3a..5c171a23aec 100644
--- a/apps/encryption/controller/settingscontroller.php
+++ b/apps/encryption/controller/settingscontroller.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/controller/statuscontroller.php b/apps/encryption/controller/statuscontroller.php
index 409fe1a258b..99fdc68c3d0 100644
--- a/apps/encryption/controller/statuscontroller.php
+++ b/apps/encryption/controller/statuscontroller.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/hooks/contracts/ihook.php b/apps/encryption/hooks/contracts/ihook.php
index d4f20700d78..4bf7ead8c15 100644
--- a/apps/encryption/hooks/contracts/ihook.php
+++ b/apps/encryption/hooks/contracts/ihook.php
@@ -2,7 +2,7 @@
/**
* @author Clark Tomlinson <fallen013@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/hooks/userhooks.php b/apps/encryption/hooks/userhooks.php
index 5bd5e39f3c5..3f84187bc1e 100644
--- a/apps/encryption/hooks/userhooks.php
+++ b/apps/encryption/hooks/userhooks.php
@@ -2,9 +2,10 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -141,7 +142,7 @@ class UserHooks implements IHook {
*
* @note This method should never be called for users using client side encryption
* @param array $params
- * @return bool
+ * @return boolean|null
*/
public function login($params) {
@@ -199,7 +200,7 @@ class UserHooks implements IHook {
* If the password can't be changed within ownCloud, than update the key password in advance.
*
* @param array $params : uid, password
- * @return bool
+ * @return boolean|null
*/
public function preSetPassphrase($params) {
if (App::isEnabled('encryption')) {
@@ -216,7 +217,7 @@ class UserHooks implements IHook {
* Change a user's encryption passphrase
*
* @param array $params keys: uid, password
- * @return bool
+ * @return boolean|null
*/
public function setPassphrase($params) {
diff --git a/apps/encryption/l10n/es.js b/apps/encryption/l10n/es.js
index 6b49b3917fd..bdaeabb68cb 100644
--- a/apps/encryption/l10n/es.js
+++ b/apps/encryption/l10n/es.js
@@ -32,6 +32,8 @@ OC.L10N.register(
"The share will expire on %s." : "El objeto dejará de ser compartido el %s.",
"Cheers!" : "¡Saludos!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Hola,\n<br><br>\nEl administrador ha habilitado el cifrado del lado servidor. Sus archivos serán cifrados usando como contraseña: <strong>%s</strong>\n<br><br>\nPor favor, identifíquese en la interfaz web, vaya a la sección 'Modulo básico de cifrado' de sus opciones personales y actualice su contraseña tecleando esta contraseña en el campo 'contraseña antigua' e introduciendo la nueva en su correspondiente campo.<br><br>",
+ "Encrypt the home storage" : "Encriptar el almacenamiento personal",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Al activar esta opción se encriptarán todos los archivos almacenados en la memoria principal, de lo contrario serán cifrados sólo los archivos de almacenamiento externo",
"Enable recovery key" : "Activa la clave de recuperación",
"Disable recovery key" : "Desactiva la clave de recuperación",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "La clave de recuperación es una clave de cifrado extra que se usa para cifrar ficheros. Permite la recuperación de los ficheros de un usuario si él o ella olvida su contraseña.",
diff --git a/apps/encryption/l10n/es.json b/apps/encryption/l10n/es.json
index 3f21b4c09a0..3eb7994eb9d 100644
--- a/apps/encryption/l10n/es.json
+++ b/apps/encryption/l10n/es.json
@@ -30,6 +30,8 @@
"The share will expire on %s." : "El objeto dejará de ser compartido el %s.",
"Cheers!" : "¡Saludos!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Hola,\n<br><br>\nEl administrador ha habilitado el cifrado del lado servidor. Sus archivos serán cifrados usando como contraseña: <strong>%s</strong>\n<br><br>\nPor favor, identifíquese en la interfaz web, vaya a la sección 'Modulo básico de cifrado' de sus opciones personales y actualice su contraseña tecleando esta contraseña en el campo 'contraseña antigua' e introduciendo la nueva en su correspondiente campo.<br><br>",
+ "Encrypt the home storage" : "Encriptar el almacenamiento personal",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Al activar esta opción se encriptarán todos los archivos almacenados en la memoria principal, de lo contrario serán cifrados sólo los archivos de almacenamiento externo",
"Enable recovery key" : "Activa la clave de recuperación",
"Disable recovery key" : "Desactiva la clave de recuperación",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "La clave de recuperación es una clave de cifrado extra que se usa para cifrar ficheros. Permite la recuperación de los ficheros de un usuario si él o ella olvida su contraseña.",
diff --git a/apps/encryption/l10n/es_AR.js b/apps/encryption/l10n/es_AR.js
index bff5b7c593e..3f2fbb5de32 100644
--- a/apps/encryption/l10n/es_AR.js
+++ b/apps/encryption/l10n/es_AR.js
@@ -1,6 +1,7 @@
OC.L10N.register(
"encryption",
{
+ "Missing recovery key password" : "Falta contraseña de recuperación",
"Recovery key successfully enabled" : "Se habilitó la recuperación de archivos",
"Could not enable recovery key. Please check your recovery key password!" : "No se pudo habilitar la clave de recuperación. Por favor, comprobá tu contraseña.",
"Recovery key successfully disabled" : "Clave de recuperación deshabilitada",
diff --git a/apps/encryption/l10n/es_AR.json b/apps/encryption/l10n/es_AR.json
index 0cdcd9cd121..225ca5139f2 100644
--- a/apps/encryption/l10n/es_AR.json
+++ b/apps/encryption/l10n/es_AR.json
@@ -1,4 +1,5 @@
{ "translations": {
+ "Missing recovery key password" : "Falta contraseña de recuperación",
"Recovery key successfully enabled" : "Se habilitó la recuperación de archivos",
"Could not enable recovery key. Please check your recovery key password!" : "No se pudo habilitar la clave de recuperación. Por favor, comprobá tu contraseña.",
"Recovery key successfully disabled" : "Clave de recuperación deshabilitada",
diff --git a/apps/encryption/l10n/et_EE.js b/apps/encryption/l10n/et_EE.js
index 501772c2808..3a29b24cc54 100644
--- a/apps/encryption/l10n/et_EE.js
+++ b/apps/encryption/l10n/et_EE.js
@@ -34,6 +34,7 @@ OC.L10N.register(
"New recovery key password" : "Uus taastevõtme parool",
"Repeat new recovery key password" : "Korda uut taastevõtme parooli",
"Change Password" : "Muuda parooli",
+ "ownCloud basic encryption module" : "ownCloud peamine küpteerimismoodul",
"Your private key password no longer matches your log-in password." : "Sinu provaatvõtme parool ei kattu enam sinu sisselogimise parooliga.",
"Set your old private key password to your current log-in password:" : "Pane oma vana privaatvõtme parooliks oma praegune sisselogimise parool.",
" If you don't remember your old password you can ask your administrator to recover your files." : "Kui sa ei mäleta oma vana parooli, siis palu oma süsteemihalduril taastada ligipääs failidele.",
diff --git a/apps/encryption/l10n/et_EE.json b/apps/encryption/l10n/et_EE.json
index 14d4c59f9fc..916bc0667ad 100644
--- a/apps/encryption/l10n/et_EE.json
+++ b/apps/encryption/l10n/et_EE.json
@@ -32,6 +32,7 @@
"New recovery key password" : "Uus taastevõtme parool",
"Repeat new recovery key password" : "Korda uut taastevõtme parooli",
"Change Password" : "Muuda parooli",
+ "ownCloud basic encryption module" : "ownCloud peamine küpteerimismoodul",
"Your private key password no longer matches your log-in password." : "Sinu provaatvõtme parool ei kattu enam sinu sisselogimise parooliga.",
"Set your old private key password to your current log-in password:" : "Pane oma vana privaatvõtme parooliks oma praegune sisselogimise parool.",
" If you don't remember your old password you can ask your administrator to recover your files." : "Kui sa ei mäleta oma vana parooli, siis palu oma süsteemihalduril taastada ligipääs failidele.",
diff --git a/apps/encryption/l10n/he.js b/apps/encryption/l10n/he.js
new file mode 100644
index 00000000000..be4d62c76c9
--- /dev/null
+++ b/apps/encryption/l10n/he.js
@@ -0,0 +1,59 @@
+OC.L10N.register(
+ "encryption",
+ {
+ "Missing recovery key password" : "חסרה סיסמת מפתח שחזור",
+ "Please repeat the recovery key password" : "יש לחזור על סיסמת מפתח השחזור",
+ "Repeated recovery key password does not match the provided recovery key password" : "סיסמת מפתח השחזור החוזרת אינה מתאימה לסיסמת מפתח השחזור הקיימת",
+ "Recovery key successfully enabled" : "מפתח השחזור אופשר בהצלחה",
+ "Could not enable recovery key. Please check your recovery key password!" : "איפשור מפתח השחזור נכשל. יש לבדוק את סיסמת מפתח השחזור שלך!",
+ "Recovery key successfully disabled" : "מפתח השחזור נוטרל בהצלחה",
+ "Could not disable recovery key. Please check your recovery key password!" : "נטרול מפתח השחזור נכשל. יש לבדוק את סיסמת מפתח השחזור שלך!",
+ "Missing parameters" : "פרמטרים חסרים",
+ "Please provide the old recovery password" : "יש לספק את סיסמת השחזור הישנה",
+ "Please provide a new recovery password" : "יש לספק את סיסמת השחזור החדשה",
+ "Please repeat the new recovery password" : "יש לספק את סיסמת השחזור החדשה",
+ "Password successfully changed." : "הסיסמא שונתה בהצלחה.",
+ "Could not change the password. Maybe the old password was not correct." : "שינוי הסיסמא נכשל. יתכן שהסיסמא הישנה לא נכונה.",
+ "Recovery Key disabled" : "מפתח שחזור מנוטרל",
+ "Recovery Key enabled" : "מפתח שחזור מאופשר",
+ "Could not enable the recovery key, please try again or contact your administrator" : "איפשור מפתח השחזור נכשל. יש לנסות שנית או לפנות למנהל שלך",
+ "Could not update the private key password." : "לא ניתן לעדכן את סיסמת המפתח האישי",
+ "The old password was not correct, please try again." : "הסיסמא הישנה לא נכונה, יש לנסות שנית.",
+ "The current log-in password was not correct, please try again." : "סיסמת ההתחברות הנוכחית אינה נכונה, יש לנסות שנית.",
+ "Private key password successfully updated." : "סיסמת מפתח אישי עודכנה בהצלחה.",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please run 'occ encryption:migrate' or contact your administrator" : "יש צורך להמיר את מפתחות ההצפנה מהצופן הישן (ownCloud <= 8.0) לצופן החדש. יש להריץ 'occ encryption:migrate' או לפנות למנהל שלך",
+ "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "המפתח האישי של יישום ההצפנה אינו תקין. יש לעדכן אתצהמפתח האישי בהגדרות האישיות לצורך שחזור הגישה לקבצים המוצפנים.",
+ "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "יישום הצפנה מאופשר אבל המפתחות שלך לא אותחלו, יש להתנתק ולהתחבר מחדש",
+ "Encryption App is enabled and ready" : "יישום ההצפנה מאופשר ומוכן",
+ "one-time password for server-side-encryption" : "סיסמא חד פעמית עבור הצפנת צד השרת",
+ "Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "לא ניתן להסיר את ההצפנה לקובץ זה, ייתכן ומדובר בקובץ משותף. יש לבקש מהבעלים של הקובץ לשתף מחדש את הקובץ אתך.",
+ "Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "לא ניתן לקרוא קובץ זה, ייתכן ומדובר בקובץ משותף. יש לבקש מהבעלים של הקובץ לשתף מחדש את הקובץ אתך.",
+ "Hey there,\n\nthe admin enabled server-side-encryption. Your files were encrypted using the password '%s'.\n\nPlease login to the web interface, go to the section 'ownCloud basic encryption module' of your personal settings and update your encryption password by entering this password into the 'old log-in password' field and your current login-password.\n\n" : "שלום,\n\nהמנהל אפשר את ההצפנה בצד השרת. הקבצים שלך הוצפנו על בסיס הסיסמא '%s'.\n\nיש להתחבר לממשק האינטרנט, ולגשת אל 'מודול הצפנה בסיסי של ownCloud' בהגדרות הבסיסיות ולעדכן את סיסמת ההצפנה שלך על ידי הכנסת הסיסמא אל שדה 'סיסמת ההתחברות הישנה' ואת סיסמת ההתחברות הנוכחית.\n\n",
+ "The share will expire on %s." : "השיתוף יפוג תוקף ב- %s.",
+ "Cheers!" : "לחיים!",
+ "Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "שלום,<br><br>המנהל אפשר את ההצפנה בצד השרת. הקבצים שלך הוצפנו על בסיס הסיסמא <strong>%s</strong>.<br><br>יש להתחבר לממשק האינטרנט, ולגשת אל \"מודול הצפנה בסיסי של ownCloud\" בהגדרות הבסיסיות ולעדכן את סיסמת ההצפנה שלך על ידי הכנסת הסיסמא אל שדה \"סיסמת ההתחברות הישנה\" ואת סיסמת ההתחברות הנוכחית.<br><br>",
+ "Encrypt the home storage" : "הצפנת אחסון הבית",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "הפעלת אפשרות זו מצפינה את כל הקבצים המאוחסנים באחסון המרכזי, אחרת רק הקבצים המאוחסנים בהתקנים חיצוניים יוצפנו",
+ "Enable recovery key" : "מאפשר מפתח שחזור",
+ "Disable recovery key" : "מנטרל מפתח שחזור",
+ "The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "מפתח השחזור הנו מפתח הצפנה נוסף לשימוש לצורך הצפנת הקבצים. הוא מאפשר את שחזור קבצי המשתמש אם המשתמש שוכח את הסיסמא שלו.",
+ "Recovery key password" : "סיסמת מפתח השחזור",
+ "Repeat recovery key password" : "יש לחזור על סיסמת מפתח השחזור",
+ "Change recovery key password:" : "החלפת סיסמת מפתח השחזור:",
+ "Old recovery key password" : "סיסמת מפתח שחזור ישנה",
+ "New recovery key password" : "סיסמת מפתח שחזור חדשה",
+ "Repeat new recovery key password" : "יש לחזור על סיסמת מפתח השחזור החדשה",
+ "Change Password" : "שינוי סיסמא",
+ "ownCloud basic encryption module" : "מודול הצפנה בסיסי של ownCloud",
+ "Your private key password no longer matches your log-in password." : "סיסמת המפתח האישי שלך כבר אינה מתאימה לסיסמת ההתחברות שלך.",
+ "Set your old private key password to your current log-in password:" : "יש להחליף את סיסמת המפתח האישי הישנה בסיסמת ההתחברות הנוכחית:",
+ " If you don't remember your old password you can ask your administrator to recover your files." : "אם הסיסמא הישנה נשכחה ניתן לפנות למנהל על מנת שישחזר את הקבצים שלך.",
+ "Old log-in password" : "סיסמת התחברות ישנה",
+ "Current log-in password" : "סיסמת התחברות נוכחית",
+ "Update Private Key Password" : "עדכון סיסמת המפתח האישי",
+ "Enable password recovery:" : "מאפשר שחזור סיסמא:",
+ "Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" : "הפעלת אפשרות זו תאפשר לך לקבל מחדש גישה לקבצים המוצפנים שלך במקרה שסיסמא נשכחת",
+ "Enabled" : "מופעל",
+ "Disabled" : "מנוטרל"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/encryption/l10n/he.json b/apps/encryption/l10n/he.json
new file mode 100644
index 00000000000..de38b4ee0c9
--- /dev/null
+++ b/apps/encryption/l10n/he.json
@@ -0,0 +1,57 @@
+{ "translations": {
+ "Missing recovery key password" : "חסרה סיסמת מפתח שחזור",
+ "Please repeat the recovery key password" : "יש לחזור על סיסמת מפתח השחזור",
+ "Repeated recovery key password does not match the provided recovery key password" : "סיסמת מפתח השחזור החוזרת אינה מתאימה לסיסמת מפתח השחזור הקיימת",
+ "Recovery key successfully enabled" : "מפתח השחזור אופשר בהצלחה",
+ "Could not enable recovery key. Please check your recovery key password!" : "איפשור מפתח השחזור נכשל. יש לבדוק את סיסמת מפתח השחזור שלך!",
+ "Recovery key successfully disabled" : "מפתח השחזור נוטרל בהצלחה",
+ "Could not disable recovery key. Please check your recovery key password!" : "נטרול מפתח השחזור נכשל. יש לבדוק את סיסמת מפתח השחזור שלך!",
+ "Missing parameters" : "פרמטרים חסרים",
+ "Please provide the old recovery password" : "יש לספק את סיסמת השחזור הישנה",
+ "Please provide a new recovery password" : "יש לספק את סיסמת השחזור החדשה",
+ "Please repeat the new recovery password" : "יש לספק את סיסמת השחזור החדשה",
+ "Password successfully changed." : "הסיסמא שונתה בהצלחה.",
+ "Could not change the password. Maybe the old password was not correct." : "שינוי הסיסמא נכשל. יתכן שהסיסמא הישנה לא נכונה.",
+ "Recovery Key disabled" : "מפתח שחזור מנוטרל",
+ "Recovery Key enabled" : "מפתח שחזור מאופשר",
+ "Could not enable the recovery key, please try again or contact your administrator" : "איפשור מפתח השחזור נכשל. יש לנסות שנית או לפנות למנהל שלך",
+ "Could not update the private key password." : "לא ניתן לעדכן את סיסמת המפתח האישי",
+ "The old password was not correct, please try again." : "הסיסמא הישנה לא נכונה, יש לנסות שנית.",
+ "The current log-in password was not correct, please try again." : "סיסמת ההתחברות הנוכחית אינה נכונה, יש לנסות שנית.",
+ "Private key password successfully updated." : "סיסמת מפתח אישי עודכנה בהצלחה.",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please run 'occ encryption:migrate' or contact your administrator" : "יש צורך להמיר את מפתחות ההצפנה מהצופן הישן (ownCloud <= 8.0) לצופן החדש. יש להריץ 'occ encryption:migrate' או לפנות למנהל שלך",
+ "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "המפתח האישי של יישום ההצפנה אינו תקין. יש לעדכן אתצהמפתח האישי בהגדרות האישיות לצורך שחזור הגישה לקבצים המוצפנים.",
+ "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "יישום הצפנה מאופשר אבל המפתחות שלך לא אותחלו, יש להתנתק ולהתחבר מחדש",
+ "Encryption App is enabled and ready" : "יישום ההצפנה מאופשר ומוכן",
+ "one-time password for server-side-encryption" : "סיסמא חד פעמית עבור הצפנת צד השרת",
+ "Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "לא ניתן להסיר את ההצפנה לקובץ זה, ייתכן ומדובר בקובץ משותף. יש לבקש מהבעלים של הקובץ לשתף מחדש את הקובץ אתך.",
+ "Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "לא ניתן לקרוא קובץ זה, ייתכן ומדובר בקובץ משותף. יש לבקש מהבעלים של הקובץ לשתף מחדש את הקובץ אתך.",
+ "Hey there,\n\nthe admin enabled server-side-encryption. Your files were encrypted using the password '%s'.\n\nPlease login to the web interface, go to the section 'ownCloud basic encryption module' of your personal settings and update your encryption password by entering this password into the 'old log-in password' field and your current login-password.\n\n" : "שלום,\n\nהמנהל אפשר את ההצפנה בצד השרת. הקבצים שלך הוצפנו על בסיס הסיסמא '%s'.\n\nיש להתחבר לממשק האינטרנט, ולגשת אל 'מודול הצפנה בסיסי של ownCloud' בהגדרות הבסיסיות ולעדכן את סיסמת ההצפנה שלך על ידי הכנסת הסיסמא אל שדה 'סיסמת ההתחברות הישנה' ואת סיסמת ההתחברות הנוכחית.\n\n",
+ "The share will expire on %s." : "השיתוף יפוג תוקף ב- %s.",
+ "Cheers!" : "לחיים!",
+ "Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "שלום,<br><br>המנהל אפשר את ההצפנה בצד השרת. הקבצים שלך הוצפנו על בסיס הסיסמא <strong>%s</strong>.<br><br>יש להתחבר לממשק האינטרנט, ולגשת אל \"מודול הצפנה בסיסי של ownCloud\" בהגדרות הבסיסיות ולעדכן את סיסמת ההצפנה שלך על ידי הכנסת הסיסמא אל שדה \"סיסמת ההתחברות הישנה\" ואת סיסמת ההתחברות הנוכחית.<br><br>",
+ "Encrypt the home storage" : "הצפנת אחסון הבית",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "הפעלת אפשרות זו מצפינה את כל הקבצים המאוחסנים באחסון המרכזי, אחרת רק הקבצים המאוחסנים בהתקנים חיצוניים יוצפנו",
+ "Enable recovery key" : "מאפשר מפתח שחזור",
+ "Disable recovery key" : "מנטרל מפתח שחזור",
+ "The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "מפתח השחזור הנו מפתח הצפנה נוסף לשימוש לצורך הצפנת הקבצים. הוא מאפשר את שחזור קבצי המשתמש אם המשתמש שוכח את הסיסמא שלו.",
+ "Recovery key password" : "סיסמת מפתח השחזור",
+ "Repeat recovery key password" : "יש לחזור על סיסמת מפתח השחזור",
+ "Change recovery key password:" : "החלפת סיסמת מפתח השחזור:",
+ "Old recovery key password" : "סיסמת מפתח שחזור ישנה",
+ "New recovery key password" : "סיסמת מפתח שחזור חדשה",
+ "Repeat new recovery key password" : "יש לחזור על סיסמת מפתח השחזור החדשה",
+ "Change Password" : "שינוי סיסמא",
+ "ownCloud basic encryption module" : "מודול הצפנה בסיסי של ownCloud",
+ "Your private key password no longer matches your log-in password." : "סיסמת המפתח האישי שלך כבר אינה מתאימה לסיסמת ההתחברות שלך.",
+ "Set your old private key password to your current log-in password:" : "יש להחליף את סיסמת המפתח האישי הישנה בסיסמת ההתחברות הנוכחית:",
+ " If you don't remember your old password you can ask your administrator to recover your files." : "אם הסיסמא הישנה נשכחה ניתן לפנות למנהל על מנת שישחזר את הקבצים שלך.",
+ "Old log-in password" : "סיסמת התחברות ישנה",
+ "Current log-in password" : "סיסמת התחברות נוכחית",
+ "Update Private Key Password" : "עדכון סיסמת המפתח האישי",
+ "Enable password recovery:" : "מאפשר שחזור סיסמא:",
+ "Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" : "הפעלת אפשרות זו תאפשר לך לקבל מחדש גישה לקבצים המוצפנים שלך במקרה שסיסמא נשכחת",
+ "Enabled" : "מופעל",
+ "Disabled" : "מנוטרל"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/encryption/l10n/nb_NO.js b/apps/encryption/l10n/nb_NO.js
index d5ce6618689..f8f29883d5e 100644
--- a/apps/encryption/l10n/nb_NO.js
+++ b/apps/encryption/l10n/nb_NO.js
@@ -32,6 +32,8 @@ OC.L10N.register(
"The share will expire on %s." : "Delingen vil opphøre %s.",
"Cheers!" : "Ha det!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Hei,<br><br>Administratoren har aktivert serverkryptering. Filene dine er blitt kryptert med passordet <strong>%s</strong>.<br><br>Vennligst logg inn på web-grensesnittet, gå til seksjonen \"ownCloud grunnleggende krypteringsmodul\" i dine personlige innstillinger og oppdater krypteringspassordet ditt ved å legge inn dette passordet i feltet \"gammelt påloggingspassord\" sammen med ditt nåværende påloggingspassord.<br><br>",
+ "Encrypt the home storage" : "Krypter hjemmelageret",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Aktivering av dette valget krypterer alle filer som er lagret på hovedlageret. Ellers vil kun filer på eksterne lagre bli kryptert.",
"Enable recovery key" : "Aktiver gjenopprettingsnøkkel",
"Disable recovery key" : "Deaktiver gjenopprettingsnøkkel",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Gjenopprettingsnøkkelen er en ekstra krypteringsnøkkel som brukes til å kryptere filer. Den tillater gjenoppretting av en brukers filer i tilfelle brukeren glemmer passordet sitt.",
diff --git a/apps/encryption/l10n/nb_NO.json b/apps/encryption/l10n/nb_NO.json
index 8b3e8c11747..26b2daab43a 100644
--- a/apps/encryption/l10n/nb_NO.json
+++ b/apps/encryption/l10n/nb_NO.json
@@ -30,6 +30,8 @@
"The share will expire on %s." : "Delingen vil opphøre %s.",
"Cheers!" : "Ha det!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Hei,<br><br>Administratoren har aktivert serverkryptering. Filene dine er blitt kryptert med passordet <strong>%s</strong>.<br><br>Vennligst logg inn på web-grensesnittet, gå til seksjonen \"ownCloud grunnleggende krypteringsmodul\" i dine personlige innstillinger og oppdater krypteringspassordet ditt ved å legge inn dette passordet i feltet \"gammelt påloggingspassord\" sammen med ditt nåværende påloggingspassord.<br><br>",
+ "Encrypt the home storage" : "Krypter hjemmelageret",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Aktivering av dette valget krypterer alle filer som er lagret på hovedlageret. Ellers vil kun filer på eksterne lagre bli kryptert.",
"Enable recovery key" : "Aktiver gjenopprettingsnøkkel",
"Disable recovery key" : "Deaktiver gjenopprettingsnøkkel",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Gjenopprettingsnøkkelen er en ekstra krypteringsnøkkel som brukes til å kryptere filer. Den tillater gjenoppretting av en brukers filer i tilfelle brukeren glemmer passordet sitt.",
diff --git a/apps/encryption/l10n/pt_BR.js b/apps/encryption/l10n/pt_BR.js
index 334bbf05282..80c35dea495 100644
--- a/apps/encryption/l10n/pt_BR.js
+++ b/apps/encryption/l10n/pt_BR.js
@@ -30,7 +30,7 @@ OC.L10N.register(
"Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Não é possível ler este arquivo, provavelmente este é um arquivo compartilhado. Por favor, pergunte o dono do arquivo para recompartilhar o arquivo com você.",
"Hey there,\n\nthe admin enabled server-side-encryption. Your files were encrypted using the password '%s'.\n\nPlease login to the web interface, go to the section 'ownCloud basic encryption module' of your personal settings and update your encryption password by entering this password into the 'old log-in password' field and your current login-password.\n\n" : "Olá,\n\nO administrador habilitou criptografia-lado-servidor. Os seus arquivos foram criptografados usando a senha '%s'.\n\nPor favor faça o login para a interface da Web, vá para a seção 'ownCloud módulo de criptografia básico' das suas definições pessoais e atualize sua senha de criptografia, inserindo esta senha no campo 'senha antiga de log-in' e sua atual senha-de-login.\n\n",
"The share will expire on %s." : "O compartilhamento irá expirar em %s.",
- "Cheers!" : "Saúde!",
+ "Cheers!" : "Saudações!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Olá,<br><br>o administrador habilitou criptografia-lado-servidor. Os seus arquivos foram criptografados usando a senha <strong>%s</strong>.<br><br>Por favor faça o login para a interface da Web, vá para a seção 'ownCloud módulo de criptografia básico' das suas definições pessoais e atualize sua senha de criptografia, inserindo esta senha no campo 'senha antiga de log-in' e sua atual senha-de-login..<br><br>",
"Encrypt the home storage" : "Criptografar a pasta de armazenamento home",
"Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Ativar essa opção de criptografia para todos os arquivos armazenados no armazenamento principal, caso contrário, apenas arquivos no armazenamento externo serão criptografados",
diff --git a/apps/encryption/l10n/pt_BR.json b/apps/encryption/l10n/pt_BR.json
index 794eb478c74..b3ce8c7238e 100644
--- a/apps/encryption/l10n/pt_BR.json
+++ b/apps/encryption/l10n/pt_BR.json
@@ -28,7 +28,7 @@
"Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Não é possível ler este arquivo, provavelmente este é um arquivo compartilhado. Por favor, pergunte o dono do arquivo para recompartilhar o arquivo com você.",
"Hey there,\n\nthe admin enabled server-side-encryption. Your files were encrypted using the password '%s'.\n\nPlease login to the web interface, go to the section 'ownCloud basic encryption module' of your personal settings and update your encryption password by entering this password into the 'old log-in password' field and your current login-password.\n\n" : "Olá,\n\nO administrador habilitou criptografia-lado-servidor. Os seus arquivos foram criptografados usando a senha '%s'.\n\nPor favor faça o login para a interface da Web, vá para a seção 'ownCloud módulo de criptografia básico' das suas definições pessoais e atualize sua senha de criptografia, inserindo esta senha no campo 'senha antiga de log-in' e sua atual senha-de-login.\n\n",
"The share will expire on %s." : "O compartilhamento irá expirar em %s.",
- "Cheers!" : "Saúde!",
+ "Cheers!" : "Saudações!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Olá,<br><br>o administrador habilitou criptografia-lado-servidor. Os seus arquivos foram criptografados usando a senha <strong>%s</strong>.<br><br>Por favor faça o login para a interface da Web, vá para a seção 'ownCloud módulo de criptografia básico' das suas definições pessoais e atualize sua senha de criptografia, inserindo esta senha no campo 'senha antiga de log-in' e sua atual senha-de-login..<br><br>",
"Encrypt the home storage" : "Criptografar a pasta de armazenamento home",
"Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Ativar essa opção de criptografia para todos os arquivos armazenados no armazenamento principal, caso contrário, apenas arquivos no armazenamento externo serão criptografados",
diff --git a/apps/encryption/l10n/pt_PT.js b/apps/encryption/l10n/pt_PT.js
index a9e3c8bbbb4..c30f81065fa 100644
--- a/apps/encryption/l10n/pt_PT.js
+++ b/apps/encryption/l10n/pt_PT.js
@@ -25,11 +25,15 @@ OC.L10N.register(
"Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "Chave privada inválida da Aplicação de Encriptação. Por favor atualize a sua senha de chave privada nas definições pessoais, para recuperar o acesso aos seus ficheiros encriptados.",
"Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "A Aplicação de Encriptação está ativada, mas as suas chaves não inicializaram. Por favor termine e inicie a sessão novamente",
"Encryption App is enabled and ready" : "A aplicação de encriptação está ativa e pronta",
+ "one-time password for server-side-encryption" : "palavra-passe de uso único para encriptação do lado do servidor",
"Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Não é possível desencriptar este ficheiro, provavelmente é um ficheiro partilhado. Por favor, peça ao proprietário do ficheiro para voltar a partilhar o ficheiro consigo.",
"Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Não é possível ler este ficheiro, provavelmente isto é um ficheiro compartilhado. Por favor, peça ao dono do ficheiro para voltar a partilhar o ficheiro consigo.",
+ "Hey there,\n\nthe admin enabled server-side-encryption. Your files were encrypted using the password '%s'.\n\nPlease login to the web interface, go to the section 'ownCloud basic encryption module' of your personal settings and update your encryption password by entering this password into the 'old log-in password' field and your current login-password.\n\n" : "Olá,\n\no administrador ativou a encriptação do lado do servidor. Os teus ficheiros foram encriptados usando a palavra-passe '%s'.\n\nPor favor, faz login via browser, vai à secção 'Módulo de encriptação básica ownCloud' nas tuas definições pessoais e atualiza a tua palavra-passe de encriptação ao introduzir esta palavra-passe no campo 'palavra-passe antiga' e também a tua palavra-passe atual.\n\n",
"The share will expire on %s." : "Esta partilha irá expirar em %s.",
"Cheers!" : "Parabéns!",
+ "Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Olá,<br><br>o administrador ativou a encriptação do lado do servidor. Os teus ficheiros foram encriptados usando a palavra-passe <strong>%s</strong>.<br><br>Por favor, faz login via browser, vai à secção 'Módulo de encriptação básica ownCloud' nas tuas definições pessoais e atualiza a tua palavra-passe de encriptação ao introduzir esta palavra-passe no campo 'palavra-passe antiga' e também a tua palavra-passe atual.<br><br>",
"Encrypt the home storage" : "Encriptar o armazenamento do início",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Ativando esta opção todos os ficheiros armazenados no armazenamento principal serão encriptados, senão serão encriptados todos os ficheiros no armazenamento externo",
"Enable recovery key" : "Ativar a chave de recuperação",
"Disable recovery key" : "Desativar a chave de recuperação",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "A chave de recuperação é uma chave de encriptação extra que é utilizada para encriptar os ficheiros. Esta permite a recuperação dos ficheiros do utilizador se este esquecer a sua senha.",
diff --git a/apps/encryption/l10n/pt_PT.json b/apps/encryption/l10n/pt_PT.json
index e744a7bac6f..34086acf56c 100644
--- a/apps/encryption/l10n/pt_PT.json
+++ b/apps/encryption/l10n/pt_PT.json
@@ -23,11 +23,15 @@
"Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "Chave privada inválida da Aplicação de Encriptação. Por favor atualize a sua senha de chave privada nas definições pessoais, para recuperar o acesso aos seus ficheiros encriptados.",
"Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "A Aplicação de Encriptação está ativada, mas as suas chaves não inicializaram. Por favor termine e inicie a sessão novamente",
"Encryption App is enabled and ready" : "A aplicação de encriptação está ativa e pronta",
+ "one-time password for server-side-encryption" : "palavra-passe de uso único para encriptação do lado do servidor",
"Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Não é possível desencriptar este ficheiro, provavelmente é um ficheiro partilhado. Por favor, peça ao proprietário do ficheiro para voltar a partilhar o ficheiro consigo.",
"Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Não é possível ler este ficheiro, provavelmente isto é um ficheiro compartilhado. Por favor, peça ao dono do ficheiro para voltar a partilhar o ficheiro consigo.",
+ "Hey there,\n\nthe admin enabled server-side-encryption. Your files were encrypted using the password '%s'.\n\nPlease login to the web interface, go to the section 'ownCloud basic encryption module' of your personal settings and update your encryption password by entering this password into the 'old log-in password' field and your current login-password.\n\n" : "Olá,\n\no administrador ativou a encriptação do lado do servidor. Os teus ficheiros foram encriptados usando a palavra-passe '%s'.\n\nPor favor, faz login via browser, vai à secção 'Módulo de encriptação básica ownCloud' nas tuas definições pessoais e atualiza a tua palavra-passe de encriptação ao introduzir esta palavra-passe no campo 'palavra-passe antiga' e também a tua palavra-passe atual.\n\n",
"The share will expire on %s." : "Esta partilha irá expirar em %s.",
"Cheers!" : "Parabéns!",
+ "Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Olá,<br><br>o administrador ativou a encriptação do lado do servidor. Os teus ficheiros foram encriptados usando a palavra-passe <strong>%s</strong>.<br><br>Por favor, faz login via browser, vai à secção 'Módulo de encriptação básica ownCloud' nas tuas definições pessoais e atualiza a tua palavra-passe de encriptação ao introduzir esta palavra-passe no campo 'palavra-passe antiga' e também a tua palavra-passe atual.<br><br>",
"Encrypt the home storage" : "Encriptar o armazenamento do início",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Ativando esta opção todos os ficheiros armazenados no armazenamento principal serão encriptados, senão serão encriptados todos os ficheiros no armazenamento externo",
"Enable recovery key" : "Ativar a chave de recuperação",
"Disable recovery key" : "Desativar a chave de recuperação",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "A chave de recuperação é uma chave de encriptação extra que é utilizada para encriptar os ficheiros. Esta permite a recuperação dos ficheiros do utilizador se este esquecer a sua senha.",
diff --git a/apps/encryption/l10n/sl.js b/apps/encryption/l10n/sl.js
index 4e4e9998b0d..b6114f14895 100644
--- a/apps/encryption/l10n/sl.js
+++ b/apps/encryption/l10n/sl.js
@@ -16,6 +16,7 @@ OC.L10N.register(
"Could not change the password. Maybe the old password was not correct." : "Gesla ni mogoče spremeniti. Morda vnos starega gesla ni pravilen.",
"Recovery Key disabled" : "Ključ za obnovitev gesla je onemogočen.",
"Recovery Key enabled" : "Ključ za obnovitev gesla je omogočen.",
+ "Could not enable the recovery key, please try again or contact your administrator" : "Ni mogoče omogočiti obnovitvenega ključa. Poskusite znova ali pa stopite v stik s skrbnikom sistema.",
"Could not update the private key password." : "Ni mogoče posodobiti gesla zasebnega ključa.",
"The old password was not correct, please try again." : "Staro geslo ni vpisano pravilno. Poskusite znova.",
"The current log-in password was not correct, please try again." : "Trenutno geslo za prijavo ni vpisano pravilno. Poskusite znova.",
diff --git a/apps/encryption/l10n/sl.json b/apps/encryption/l10n/sl.json
index 34829a2280e..1a35d191af9 100644
--- a/apps/encryption/l10n/sl.json
+++ b/apps/encryption/l10n/sl.json
@@ -14,6 +14,7 @@
"Could not change the password. Maybe the old password was not correct." : "Gesla ni mogoče spremeniti. Morda vnos starega gesla ni pravilen.",
"Recovery Key disabled" : "Ključ za obnovitev gesla je onemogočen.",
"Recovery Key enabled" : "Ključ za obnovitev gesla je omogočen.",
+ "Could not enable the recovery key, please try again or contact your administrator" : "Ni mogoče omogočiti obnovitvenega ključa. Poskusite znova ali pa stopite v stik s skrbnikom sistema.",
"Could not update the private key password." : "Ni mogoče posodobiti gesla zasebnega ključa.",
"The old password was not correct, please try again." : "Staro geslo ni vpisano pravilno. Poskusite znova.",
"The current log-in password was not correct, please try again." : "Trenutno geslo za prijavo ni vpisano pravilno. Poskusite znova.",
diff --git a/apps/encryption/l10n/tr.js b/apps/encryption/l10n/tr.js
index e1fcb526d06..4781b01b8d1 100644
--- a/apps/encryption/l10n/tr.js
+++ b/apps/encryption/l10n/tr.js
@@ -32,6 +32,8 @@ OC.L10N.register(
"The share will expire on %s." : "Bu paylaşım %s tarihinde sona erecek.",
"Cheers!" : "Hoşçakalın!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Selam,<br><br>Sistem yöneticisi sunucu tarafında şifrelemeyi etkinleştirdi. Dosyalarınız <strong>%s</strong> parolası kullanılarak şifrelendi.<br><br>Lütfen web arayüzünde oturum açın ve kişisel ayarlarınızdan 'ownCloud temel şifreleme modülü'ne giderek 'eski oturum parolası' alanına bu parolayı girdikten sonra şifreleme parolanızı ve mevcut oturum açma parolanızı güncelleyin.<br><br>",
+ "Encrypt the home storage" : "Ana depolamayı şifrele",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Bu seçeneği etkinleştirmek ana depolamadaki bütün dosyaları şifreler, aksi takdirde sadece harici depolamadaki dosyalar şifrelenir",
"Enable recovery key" : "Kurtarma anahtarını etkinleştir",
"Disable recovery key" : "Kurtarma anahtarını devre dışı bırak",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kurtarma anahtarı, dosyaların şifrelenmesi için daha fazla \nşifreleme sunar. Bu kullanıcının dosyasının şifresini unuttuğunda kurtarmasına imkan verir.",
diff --git a/apps/encryption/l10n/tr.json b/apps/encryption/l10n/tr.json
index 743d3e7d15c..c648ea5e387 100644
--- a/apps/encryption/l10n/tr.json
+++ b/apps/encryption/l10n/tr.json
@@ -30,6 +30,8 @@
"The share will expire on %s." : "Bu paylaşım %s tarihinde sona erecek.",
"Cheers!" : "Hoşçakalın!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Selam,<br><br>Sistem yöneticisi sunucu tarafında şifrelemeyi etkinleştirdi. Dosyalarınız <strong>%s</strong> parolası kullanılarak şifrelendi.<br><br>Lütfen web arayüzünde oturum açın ve kişisel ayarlarınızdan 'ownCloud temel şifreleme modülü'ne giderek 'eski oturum parolası' alanına bu parolayı girdikten sonra şifreleme parolanızı ve mevcut oturum açma parolanızı güncelleyin.<br><br>",
+ "Encrypt the home storage" : "Ana depolamayı şifrele",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Bu seçeneği etkinleştirmek ana depolamadaki bütün dosyaları şifreler, aksi takdirde sadece harici depolamadaki dosyalar şifrelenir",
"Enable recovery key" : "Kurtarma anahtarını etkinleştir",
"Disable recovery key" : "Kurtarma anahtarını devre dışı bırak",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kurtarma anahtarı, dosyaların şifrelenmesi için daha fazla \nşifreleme sunar. Bu kullanıcının dosyasının şifresini unuttuğunda kurtarmasına imkan verir.",
diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/crypto/crypt.php
index c0dcc936bdf..e387380cd95 100644
--- a/apps/encryption/lib/crypto/crypt.php
+++ b/apps/encryption/lib/crypto/crypt.php
@@ -4,9 +4,10 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,11 +31,9 @@ use OC\Encryption\Exceptions\DecryptionFailedException;
use OC\Encryption\Exceptions\EncryptionFailedException;
use OCA\Encryption\Exceptions\MultiKeyDecryptException;
use OCA\Encryption\Exceptions\MultiKeyEncryptException;
-use OCA\Encryption\Vendor\PBKDF2Fallback;
use OCP\Encryption\Exceptions\GenericEncryptionException;
use OCP\IConfig;
use OCP\ILogger;
-use OCP\IUser;
use OCP\IUserSession;
class Crypt {
@@ -146,7 +145,7 @@ class Crypt {
/**
* @param string $plainContent
* @param string $passPhrase
- * @return bool|string
+ * @return false|string
* @throws GenericEncryptionException
*/
public function symmetricEncryptFileContent($plainContent, $passPhrase) {
@@ -273,7 +272,7 @@ class Crypt {
}
/**
- * @param $data
+ * @param string $data
* @return string
*/
private function addPadding($data) {
@@ -294,28 +293,14 @@ class Crypt {
$salt = hash('sha256', $uid . $instanceId . $instanceSecret, true);
$keySize = $this->getKeySize($cipher);
- if (function_exists('hash_pbkdf2')) {
- $hash = hash_pbkdf2(
- 'sha256',
- $password,
- $salt,
- 100000,
- $keySize,
- true
- );
- } else {
- // fallback to 3rdparty lib for PHP <= 5.4.
- // FIXME: Can be removed as soon as support for PHP 5.4 was dropped
- $fallback = new PBKDF2Fallback();
- $hash = $fallback->pbkdf2(
- 'sha256',
- $password,
- $salt,
- 100000,
- $keySize,
- true
- );
- }
+ $hash = hash_pbkdf2(
+ 'sha256',
+ $password,
+ $salt,
+ 100000,
+ $keySize,
+ true
+ );
return $hash;
}
@@ -326,7 +311,7 @@ class Crypt {
* @param string $privateKey
* @param string $password
* @param string $uid for regular users, empty for system keys
- * @return bool|string
+ * @return false|string
*/
public function encryptPrivateKey($privateKey, $password, $uid = '') {
$cipher = $this->getCipher();
@@ -343,7 +328,7 @@ class Crypt {
* @param string $privateKey
* @param string $password
* @param string $uid for regular users, empty for system keys
- * @return bool|string
+ * @return false|string
*/
public function decryptPrivateKey($privateKey, $password = '', $uid = '') {
@@ -386,7 +371,7 @@ class Crypt {
/**
* check if it is a valid private key
*
- * @param $plainKey
+ * @param string $plainKey
* @return bool
*/
protected function isValidPrivateKey($plainKey) {
@@ -402,7 +387,7 @@ class Crypt {
}
/**
- * @param $keyFileContents
+ * @param string $keyFileContents
* @param string $passPhrase
* @param string $cipher
* @return string
@@ -424,7 +409,7 @@ class Crypt {
* remove padding
*
* @param $padded
- * @return bool|string
+ * @return string|false
*/
private function removePadding($padded) {
if (substr($padded, -2) === 'xx') {
@@ -436,8 +421,8 @@ class Crypt {
/**
* split iv from encrypted content
*
- * @param $catFile
- * @return array
+ * @param string|false $catFile
+ * @return string
*/
private function splitIv($catFile) {
// Fetch encryption metadata from end of file
@@ -457,8 +442,8 @@ class Crypt {
}
/**
- * @param $encryptedContent
- * @param $iv
+ * @param string $encryptedContent
+ * @param string $iv
* @param string $passPhrase
* @param string $cipher
* @return string
@@ -479,7 +464,7 @@ class Crypt {
}
/**
- * @param $data
+ * @param string $data
* @return array
*/
protected function parseHeader($data) {
@@ -551,7 +536,7 @@ class Crypt {
* @param $encKeyFile
* @param $shareKey
* @param $privateKey
- * @return mixed
+ * @return string
* @throws MultiKeyDecryptException
*/
public function multiKeyDecrypt($encKeyFile, $shareKey, $privateKey) {
diff --git a/apps/encryption/lib/crypto/decryptall.php b/apps/encryption/lib/crypto/decryptall.php
index 1daf3699d13..fa9a3e0db95 100644
--- a/apps/encryption/lib/crypto/decryptall.php
+++ b/apps/encryption/lib/crypto/decryptall.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/lib/crypto/encryptall.php b/apps/encryption/lib/crypto/encryptall.php
index 8e97fe341b4..18e93d2e120 100644
--- a/apps/encryption/lib/crypto/encryptall.php
+++ b/apps/encryption/lib/crypto/encryptall.php
@@ -1,8 +1,10 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,6 +33,7 @@ use OCP\IL10N;
use OCP\IUserManager;
use OCP\Mail\IMailer;
use OCP\Security\ISecureRandom;
+use OCP\Util;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Helper\Table;
@@ -343,7 +346,7 @@ class EncryptAll {
* @return string password
*/
protected function generateOneTimePassword($uid) {
- $password = $this->secureRandom->getMediumStrengthGenerator()->generate(8);
+ $password = $this->secureRandom->generate(8);
$this->userPasswords[$uid] = $password;
return $password;
}
@@ -358,14 +361,15 @@ class EncryptAll {
$progress = new ProgressBar($this->output, count($this->userPasswords));
$progress->start();
- foreach ($this->userPasswords as $recipient => $password) {
+ foreach ($this->userPasswords as $uid => $password) {
$progress->advance();
if (!empty($password)) {
- $recipientDisplayName = $this->userManager->get($recipient)->getDisplayName();
- $to = $this->config->getUserValue($recipient, 'settings', 'email', '');
+ $recipient = $this->userManager->get($uid);
+ $recipientDisplayName = $recipient->getDisplayName();
+ $to = $recipient->getEMailAddress();
if ($to === '') {
- $noMail[] = $recipient;
+ $noMail[] = $uid;
continue;
}
@@ -380,12 +384,12 @@ class EncryptAll {
$message->setHtmlBody($htmlBody);
$message->setPlainBody($textBody);
$message->setFrom([
- \OCP\Util::getDefaultEmailAddress('admin-noreply')
+ Util::getDefaultEmailAddress('admin-noreply')
]);
$this->mailer->send($message);
} catch (\Exception $e) {
- $noMail[] = $recipient;
+ $noMail[] = $uid;
}
}
}
diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/crypto/encryption.php
index d1140ce7cde..3b66684a7f4 100644
--- a/apps/encryption/lib/crypto/encryption.php
+++ b/apps/encryption/lib/crypto/encryption.php
@@ -5,9 +5,10 @@
* @author Jan-Christoph Borchardt <hey@jancborchardt.net>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -247,7 +248,7 @@ class Encryption implements IEncryptionModule {
* encrypt data
*
* @param string $data you want to encrypt
- * @return mixed encrypted data
+ * @return string encrypted data
*/
public function encrypt($data) {
@@ -312,7 +313,7 @@ class Encryption implements IEncryptionModule {
* decrypt data
*
* @param string $data you want to decrypt
- * @return mixed decrypted data
+ * @return string decrypted data
* @throws DecryptionFailedException
*/
public function decrypt($data) {
diff --git a/apps/encryption/lib/exceptions/multikeydecryptexception.php b/apps/encryption/lib/exceptions/multikeydecryptexception.php
index 48b916ff1b8..59bea59344d 100644
--- a/apps/encryption/lib/exceptions/multikeydecryptexception.php
+++ b/apps/encryption/lib/exceptions/multikeydecryptexception.php
@@ -2,7 +2,7 @@
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/lib/exceptions/multikeyencryptexception.php b/apps/encryption/lib/exceptions/multikeyencryptexception.php
index 197e06adbf3..bc0872ffdd2 100644
--- a/apps/encryption/lib/exceptions/multikeyencryptexception.php
+++ b/apps/encryption/lib/exceptions/multikeyencryptexception.php
@@ -2,7 +2,7 @@
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/lib/exceptions/privatekeymissingexception.php b/apps/encryption/lib/exceptions/privatekeymissingexception.php
index 29db5a16641..fe162a8f5c4 100644
--- a/apps/encryption/lib/exceptions/privatekeymissingexception.php
+++ b/apps/encryption/lib/exceptions/privatekeymissingexception.php
@@ -4,7 +4,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/lib/exceptions/publickeymissingexception.php b/apps/encryption/lib/exceptions/publickeymissingexception.php
index 078add0369a..6fad4693dcc 100644
--- a/apps/encryption/lib/exceptions/publickeymissingexception.php
+++ b/apps/encryption/lib/exceptions/publickeymissingexception.php
@@ -2,7 +2,7 @@
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/lib/hookmanager.php b/apps/encryption/lib/hookmanager.php
index ab059369333..a4269dca031 100644
--- a/apps/encryption/lib/hookmanager.php
+++ b/apps/encryption/lib/hookmanager.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php
index c4507228878..b6365cf2cce 100644
--- a/apps/encryption/lib/keymanager.php
+++ b/apps/encryption/lib/keymanager.php
@@ -2,9 +2,11 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -213,7 +215,7 @@ class KeyManager {
}
/**
- * @param $password
+ * @param string $password
* @return bool
*/
public function checkRecoveryPassword($password) {
@@ -280,7 +282,7 @@ class KeyManager {
/**
* @param $userId
- * @param $key
+ * @param string $key
* @return bool
*/
public function setPrivateKey($userId, $key) {
@@ -365,7 +367,7 @@ class KeyManager {
/**
* @param $userId
- * @return mixed
+ * @return string
* @throws PrivateKeyMissingException
*/
public function getPrivateKey($userId) {
@@ -379,23 +381,24 @@ class KeyManager {
}
/**
- * @param $path
+ * @param string $path
* @param $uid
* @return string
*/
public function getFileKey($path, $uid) {
$encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
- if ($this->util->isMasterKeyEnabled()) {
- $uid = $this->getMasterKeyId();
- }
-
if (is_null($uid)) {
$uid = $this->getPublicShareKeyId();
$shareKey = $this->getShareKey($path, $uid);
$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
$privateKey = $this->crypt->decryptPrivateKey($privateKey);
} else {
+
+ if ($this->util->isMasterKeyEnabled()) {
+ $uid = $this->getMasterKeyId();
+ }
+
$shareKey = $this->getShareKey($path, $uid);
$privateKey = $this->session->getPrivateKey();
}
@@ -412,7 +415,7 @@ class KeyManager {
/**
* get the encrypted file key
*
- * @param $path
+ * @param string $path
* @return string
*/
public function getEncryptedFileKey($path) {
@@ -508,7 +511,7 @@ class KeyManager {
}
/**
- * @param $purpose
+ * @param string $purpose
* @param bool $timestamp
* @param bool $includeUserKeys
*/
@@ -534,13 +537,16 @@ class KeyManager {
}
/**
- * @param $uid
+ * @param string $uid
* @return bool
*/
private function deletePrivateKey($uid) {
return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId, Encryption::ID);
}
+ /**
+ * @param string $path
+ */
public function deleteAllFileKeys($path) {
return $this->keyStorage->deleteAllFileKeys($path);
}
diff --git a/apps/encryption/lib/migration.php b/apps/encryption/lib/migration.php
index 1a7c2e9877d..1b79ddfe7f1 100644
--- a/apps/encryption/lib/migration.php
+++ b/apps/encryption/lib/migration.php
@@ -2,8 +2,10 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -50,7 +52,7 @@ class Migration {
*/
public function __construct(IConfig $config, View $view, IDBConnection $connection, ILogger $logger) {
$this->view = $view;
- $this->view->getUpdater()->disable();
+ $this->view->disableCacheUpdate();
$this->connection = $connection;
$this->moduleId = \OCA\Encryption\Crypto\Encryption::ID;
$this->config = $config;
@@ -237,7 +239,7 @@ class Migration {
/**
* rename system wide public key
*
- * @param $privateKey private key for which we want to rename the corresponding public key
+ * @param string $privateKey private key for which we want to rename the corresponding public key
*/
private function renameSystemPublicKey($privateKey) {
$publicKey = substr($privateKey,0 , strrpos($privateKey, '.privateKey')) . '.publicKey';
diff --git a/apps/encryption/lib/recovery.php b/apps/encryption/lib/recovery.php
index e7b20e2c4af..8833ea8f0ed 100644
--- a/apps/encryption/lib/recovery.php
+++ b/apps/encryption/lib/recovery.php
@@ -2,8 +2,10 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -68,10 +70,6 @@ class Recovery {
* @var IFile
*/
private $file;
- /**
- * @var string
- */
- private $recoveryKeyId;
/**
* @param IUserSession $user
@@ -102,8 +100,7 @@ class Recovery {
}
/**
- * @param $recoveryKeyId
- * @param $password
+ * @param string $password
* @return bool
*/
public function enableAdminRecovery($password) {
@@ -112,6 +109,9 @@ class Recovery {
if (!$keyManager->recoveryKeyExists()) {
$keyPair = $this->crypt->createKeyPair();
+ if(!is_array($keyPair)) {
+ return false;
+ }
$this->keyManager->setRecoveryKey($password, $keyPair);
}
@@ -134,6 +134,9 @@ class Recovery {
public function changeRecoveryKeyPassword($newPassword, $oldPassword) {
$recoveryKey = $this->keyManager->getSystemPrivateKey($this->keyManager->getRecoveryKeyId());
$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $oldPassword);
+ if($decryptedRecoveryKey === false) {
+ return false;
+ }
$encryptedRecoveryKey = $this->crypt->encryptPrivateKey($decryptedRecoveryKey, $newPassword);
$header = $this->crypt->generateHeader();
if ($encryptedRecoveryKey) {
@@ -144,7 +147,7 @@ class Recovery {
}
/**
- * @param $recoveryPassword
+ * @param string $recoveryPassword
* @return bool
*/
public function disableAdminRecovery($recoveryPassword) {
@@ -212,6 +215,7 @@ class Recovery {
/**
* add recovery key to all encrypted files
+ * @param string $path
*/
private function addRecoveryKeys($path) {
$dirContent = $this->view->getDirectoryContent($path);
@@ -239,6 +243,7 @@ class Recovery {
/**
* remove recovery key to all encrypted files
+ * @param string $path
*/
private function removeRecoveryKeys($path) {
$dirContent = $this->view->getDirectoryContent($path);
@@ -262,8 +267,9 @@ class Recovery {
$encryptedKey = $this->keyManager->getSystemPrivateKey($this->keyManager->getRecoveryKeyId());
$privateKey = $this->crypt->decryptPrivateKey($encryptedKey, $recoveryPassword);
-
- $this->recoverAllFiles('/' . $user . '/files/', $privateKey, $user);
+ if($privateKey !== false) {
+ $this->recoverAllFiles('/' . $user . '/files/', $privateKey, $user);
+ }
}
/**
diff --git a/apps/encryption/lib/session.php b/apps/encryption/lib/session.php
index 2c83319d71e..62cc09b018d 100644
--- a/apps/encryption/lib/session.php
+++ b/apps/encryption/lib/session.php
@@ -4,7 +4,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/lib/users/setup.php b/apps/encryption/lib/users/setup.php
index 99368cab080..0b5fb351aca 100644
--- a/apps/encryption/lib/users/setup.php
+++ b/apps/encryption/lib/users/setup.php
@@ -5,7 +5,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/lib/util.php b/apps/encryption/lib/util.php
index 62907f8a460..e87ed478a1a 100644
--- a/apps/encryption/lib/util.php
+++ b/apps/encryption/lib/util.php
@@ -2,8 +2,9 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
+ * @author Phil Davis <phil.davis@inf.org>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/settings/settings-admin.php b/apps/encryption/settings/settings-admin.php
index 8d55d587fed..c3d523f27da 100644
--- a/apps/encryption/settings/settings-admin.php
+++ b/apps/encryption/settings/settings-admin.php
@@ -2,9 +2,10 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -42,7 +43,7 @@ $util = new \OCA\Encryption\Util(
$recoveryAdminEnabled = \OC::$server->getConfig()->getAppValue('encryption', 'recoveryAdminEnabled', '0');
$session = new \OCA\Encryption\Session(\OC::$server->getSession());
-$encryptHomeStorage = $util->shouldEncryptHomeStorage($user);
+$encryptHomeStorage = $util->shouldEncryptHomeStorage();
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled);
$tmpl->assign('initStatus', $session->getStatus());
diff --git a/apps/encryption/settings/settings-personal.php b/apps/encryption/settings/settings-personal.php
index 3815626ee64..2dff5904850 100644
--- a/apps/encryption/settings/settings-personal.php
+++ b/apps/encryption/settings/settings-personal.php
@@ -4,7 +4,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/command/testenablemasterkey.php b/apps/encryption/tests/command/testenablemasterkey.php
index c905329269e..e408a7c2b14 100644
--- a/apps/encryption/tests/command/testenablemasterkey.php
+++ b/apps/encryption/tests/command/testenablemasterkey.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/controller/RecoveryControllerTest.php b/apps/encryption/tests/controller/RecoveryControllerTest.php
index 6c554c97ae9..a4349139896 100644
--- a/apps/encryption/tests/controller/RecoveryControllerTest.php
+++ b/apps/encryption/tests/controller/RecoveryControllerTest.php
@@ -2,7 +2,7 @@
/**
* @author Clark Tomlinson <fallen013@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/controller/SettingsControllerTest.php b/apps/encryption/tests/controller/SettingsControllerTest.php
index 3b30e61a45b..61391a33002 100644
--- a/apps/encryption/tests/controller/SettingsControllerTest.php
+++ b/apps/encryption/tests/controller/SettingsControllerTest.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/controller/StatusControllerTest.php b/apps/encryption/tests/controller/StatusControllerTest.php
index b57fd1cc33e..3c937623b7a 100644
--- a/apps/encryption/tests/controller/StatusControllerTest.php
+++ b/apps/encryption/tests/controller/StatusControllerTest.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/hooks/UserHooksTest.php b/apps/encryption/tests/hooks/UserHooksTest.php
index ada0081f649..08d1981266c 100644
--- a/apps/encryption/tests/hooks/UserHooksTest.php
+++ b/apps/encryption/tests/hooks/UserHooksTest.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/lib/HookManagerTest.php b/apps/encryption/tests/lib/HookManagerTest.php
index 288b27b5d8b..d69674faec0 100644
--- a/apps/encryption/tests/lib/HookManagerTest.php
+++ b/apps/encryption/tests/lib/HookManagerTest.php
@@ -3,7 +3,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/lib/KeyManagerTest.php b/apps/encryption/tests/lib/KeyManagerTest.php
index 35ae8ad6ca0..c69610fb541 100644
--- a/apps/encryption/tests/lib/KeyManagerTest.php
+++ b/apps/encryption/tests/lib/KeyManagerTest.php
@@ -5,7 +5,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -342,25 +342,77 @@ class KeyManagerTest extends TestCase {
$this->assertTrue($this->instance->getEncryptedFileKey('/'));
}
- public function testGetFileKey() {
- $this->keyStorageMock->expects($this->exactly(4))
+ /**
+ * @dataProvider dataTestGetFileKey
+ *
+ * @param $uid
+ * @param $isMasterKeyEnabled
+ * @param $privateKey
+ * @param $expected
+ */
+ public function testGetFileKey($uid, $isMasterKeyEnabled, $privateKey, $expected) {
+
+ $path = '/foo.txt';
+
+ if ($isMasterKeyEnabled) {
+ $expectedUid = 'masterKeyId';
+ } else {
+ $expectedUid = $uid;
+ }
+
+ $this->invokePrivate($this->instance, 'masterKeyId', ['masterKeyId']);
+
+ $this->keyStorageMock->expects($this->at(0))
->method('getFileKey')
+ ->with($path, 'fileKey', 'OC_DEFAULT_MODULE')
->willReturn(true);
- $this->keyStorageMock->expects($this->once())
- ->method('getSystemUserKey')
+ $this->keyStorageMock->expects($this->at(1))
+ ->method('getFileKey')
+ ->with($path, $expectedUid . '.shareKey', 'OC_DEFAULT_MODULE')
->willReturn(true);
- $this->cryptMock->expects($this->once())
- ->method('decryptPrivateKey')
- ->willReturn(true);
+ if (is_null($uid)) {
+ $this->keyStorageMock->expects($this->once())
+ ->method('getSystemUserKey')
+ ->willReturn(true);
+ $this->cryptMock->expects($this->once())
+ ->method('decryptPrivateKey')
+ ->willReturn($privateKey);
+ } else {
+ $this->keyStorageMock->expects($this->never())
+ ->method('getSystemUserKey');
+ $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
+ ->willReturn($isMasterKeyEnabled);
+ $this->sessionMock->expects($this->once())->method('getPrivateKey')->willReturn($privateKey);
+ }
- $this->cryptMock->expects($this->once())
- ->method('multiKeyDecrypt')
- ->willReturn(true);
+ if($privateKey) {
+ $this->cryptMock->expects($this->once())
+ ->method('multiKeyDecrypt')
+ ->willReturn(true);
+ } else {
+ $this->cryptMock->expects($this->never())
+ ->method('multiKeyDecrypt');
+ }
- $this->assertTrue($this->instance->getFileKey('/', null));
- $this->assertEmpty($this->instance->getFileKey('/', $this->userId));
+ $this->assertSame($expected,
+ $this->instance->getFileKey($path, $uid)
+ );
+
+ }
+
+ public function dataTestGetFileKey() {
+ return [
+ ['user1', false, 'privateKey', true],
+ ['user1', false, false, ''],
+ ['user1', true, 'privateKey', true],
+ ['user1', true, false, ''],
+ ['', false, 'privateKey', true],
+ ['', false, false, ''],
+ ['', true, 'privateKey', true],
+ ['', true, false, '']
+ ];
}
public function testDeletePrivateKey() {
diff --git a/apps/encryption/tests/lib/MigrationTest.php b/apps/encryption/tests/lib/MigrationTest.php
index 65fefa262a7..f00704e42e8 100644
--- a/apps/encryption/tests/lib/MigrationTest.php
+++ b/apps/encryption/tests/lib/MigrationTest.php
@@ -3,8 +3,10 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -43,15 +45,18 @@ class MigrationTest extends \Test\TestCase {
public static function setUpBeforeClass() {
parent::setUpBeforeClass();
- \OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER1, 'foo');
- \OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER2, 'foo');
- \OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER3, 'foo');
+ \OC::$server->getUserManager()->createUser(self::TEST_ENCRYPTION_MIGRATION_USER1, 'foo');
+ \OC::$server->getUserManager()->createUser(self::TEST_ENCRYPTION_MIGRATION_USER2, 'foo');
+ \OC::$server->getUserManager()->createUser(self::TEST_ENCRYPTION_MIGRATION_USER3, 'foo');
}
public static function tearDownAfterClass() {
- \OC_User::deleteUser(self::TEST_ENCRYPTION_MIGRATION_USER1);
- \OC_User::deleteUser(self::TEST_ENCRYPTION_MIGRATION_USER2);
- \OC_User::deleteUser(self::TEST_ENCRYPTION_MIGRATION_USER3);
+ $user = \OC::$server->getUserManager()->get(self::TEST_ENCRYPTION_MIGRATION_USER1);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get(self::TEST_ENCRYPTION_MIGRATION_USER2);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get(self::TEST_ENCRYPTION_MIGRATION_USER3);
+ if ($user !== null) { $user->delete(); }
parent::tearDownAfterClass();
}
@@ -62,6 +67,9 @@ class MigrationTest extends \Test\TestCase {
$this->moduleId = \OCA\Encryption\Crypto\Encryption::ID;
}
+ /**
+ * @param string $uid
+ */
protected function createDummyShareKeys($uid) {
$this->loginAsUser($uid);
@@ -89,6 +97,9 @@ class MigrationTest extends \Test\TestCase {
}
}
+ /**
+ * @param string $uid
+ */
protected function createDummyUserKeys($uid) {
$this->loginAsUser($uid);
@@ -98,6 +109,9 @@ class MigrationTest extends \Test\TestCase {
$this->view->file_put_contents('/files_encryption/public_keys/' . $uid . '.publicKey', 'publicKey');
}
+ /**
+ * @param string $uid
+ */
protected function createDummyFileKeys($uid) {
$this->loginAsUser($uid);
@@ -111,6 +125,9 @@ class MigrationTest extends \Test\TestCase {
$this->view->file_put_contents($uid . '/files_encryption/keys/folder2/file.2.1/fileKey' , 'data');
}
+ /**
+ * @param string $uid
+ */
protected function createDummyFiles($uid) {
$this->loginAsUser($uid);
@@ -124,6 +141,9 @@ class MigrationTest extends \Test\TestCase {
$this->view->file_put_contents($uid . '/files/folder2/file.2.1/fileKey' , 'data');
}
+ /**
+ * @param string $uid
+ */
protected function createDummyFilesInTrash($uid) {
$this->loginAsUser($uid);
@@ -239,6 +259,9 @@ class MigrationTest extends \Test\TestCase {
}
+ /**
+ * @param string $uid
+ */
protected function verifyFilesInTrash($uid) {
$this->loginAsUser($uid);
@@ -266,6 +289,9 @@ class MigrationTest extends \Test\TestCase {
);
}
+ /**
+ * @param string $uid
+ */
protected function verifyNewKeyPath($uid) {
// private key
if ($uid !== '') {
@@ -394,6 +420,11 @@ class MigrationTest extends \Test\TestCase {
}
+ /**
+ * @param string $table
+ * @param string $appid
+ * @param integer $expected
+ */
public function verifyDB($table, $appid, $expected) {
/** @var \OCP\IDBConnection $connection */
$connection = \OC::$server->getDatabaseConnection();
diff --git a/apps/encryption/tests/lib/RecoveryTest.php b/apps/encryption/tests/lib/RecoveryTest.php
index 0cdd76d6b44..68c21c80b34 100644
--- a/apps/encryption/tests/lib/RecoveryTest.php
+++ b/apps/encryption/tests/lib/RecoveryTest.php
@@ -3,8 +3,9 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -59,14 +60,44 @@ class RecoveryTest extends TestCase {
*/
private $instance;
- public function testEnableAdminRecovery() {
+ public function testEnableAdminRecoverySuccessful() {
$this->keyManagerMock->expects($this->exactly(2))
->method('recoveryKeyExists')
->willReturnOnConsecutiveCalls(false, true);
$this->cryptMock->expects($this->once())
->method('createKeyPair')
- ->willReturn(true);
+ ->willReturn([
+ 'publicKey' => 'privateKey',
+ 'privateKey' => 'publicKey',
+ ]);
+
+ $this->keyManagerMock->expects($this->once())
+ ->method('setRecoveryKey')
+ ->willReturn(false);
+
+ $this->keyManagerMock->expects($this->exactly(2))
+ ->method('checkRecoveryPassword')
+ ->willReturnOnConsecutiveCalls(true, true);
+
+ $this->assertTrue($this->instance->enableAdminRecovery('password'));
+ $this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
+ $this->assertEquals(1, self::$tempStorage['recoveryAdminEnabled']);
+
+ $this->assertTrue($this->instance->enableAdminRecovery('password'));
+ }
+
+ public function testEnableAdminRecoveryCouldNotCheckPassword() {
+ $this->keyManagerMock->expects($this->exactly(2))
+ ->method('recoveryKeyExists')
+ ->willReturnOnConsecutiveCalls(false, true);
+
+ $this->cryptMock->expects($this->once())
+ ->method('createKeyPair')
+ ->willReturn([
+ 'publicKey' => 'privateKey',
+ 'privateKey' => 'publicKey',
+ ]);
$this->keyManagerMock->expects($this->once())
->method('setRecoveryKey')
@@ -83,7 +114,19 @@ class RecoveryTest extends TestCase {
$this->assertFalse($this->instance->enableAdminRecovery('password'));
}
- public function testChangeRecoveryKeyPassword() {
+ public function testEnableAdminRecoveryCouldNotCreateKey() {
+ $this->keyManagerMock->expects($this->once())
+ ->method('recoveryKeyExists')
+ ->willReturn(false);
+
+ $this->cryptMock->expects($this->once())
+ ->method('createKeyPair')
+ ->willReturn(false);
+
+ $this->assertFalse($this->instance->enableAdminRecovery('password'));
+ }
+
+ public function testChangeRecoveryKeyPasswordSuccessful() {
$this->assertFalse($this->instance->changeRecoveryKeyPassword('password',
'passwordOld'));
@@ -101,6 +144,19 @@ class RecoveryTest extends TestCase {
'passwordOld'));
}
+ public function testChangeRecoveryKeyPasswordCouldNotDecryptPrivateRecoveryKey() {
+ $this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
+
+ $this->keyManagerMock->expects($this->once())
+ ->method('getSystemPrivateKey');
+
+ $this->cryptMock->expects($this->once())
+ ->method('decryptPrivateKey')
+ ->will($this->returnValue(false));
+
+ $this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
+ }
+
public function testDisableAdminRecovery() {
$this->keyManagerMock->expects($this->exactly(2))
@@ -145,8 +201,7 @@ class RecoveryTest extends TestCase {
$this->cryptMock->expects($this->once())
->method('decryptPrivateKey');
- $this->assertNull($this->instance->recoverUsersFiles('password',
- 'admin'));
+ $this->assertNull($this->instance->recoverUsersFiles('password', 'admin'));
}
public function testRecoverFile() {
diff --git a/apps/encryption/tests/lib/SessionTest.php b/apps/encryption/tests/lib/SessionTest.php
index 1cc0d89a93d..f7a8a0369bb 100644
--- a/apps/encryption/tests/lib/SessionTest.php
+++ b/apps/encryption/tests/lib/SessionTest.php
@@ -4,7 +4,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/lib/UtilTest.php b/apps/encryption/tests/lib/UtilTest.php
index d55b6b50b3e..fa90125d6e9 100644
--- a/apps/encryption/tests/lib/UtilTest.php
+++ b/apps/encryption/tests/lib/UtilTest.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/lib/crypto/cryptTest.php b/apps/encryption/tests/lib/crypto/cryptTest.php
index cad34761840..e599cc28963 100644
--- a/apps/encryption/tests/lib/crypto/cryptTest.php
+++ b/apps/encryption/tests/lib/crypto/cryptTest.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/lib/crypto/decryptalltest.php b/apps/encryption/tests/lib/crypto/decryptalltest.php
index d6a52fe97c0..84819aa73bd 100644
--- a/apps/encryption/tests/lib/crypto/decryptalltest.php
+++ b/apps/encryption/tests/lib/crypto/decryptalltest.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/lib/crypto/encryptalltest.php b/apps/encryption/tests/lib/crypto/encryptalltest.php
index e907d154a2d..04d931342a7 100644
--- a/apps/encryption/tests/lib/crypto/encryptalltest.php
+++ b/apps/encryption/tests/lib/crypto/encryptalltest.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/lib/crypto/encryptionTest.php b/apps/encryption/tests/lib/crypto/encryptionTest.php
index 138c1bc9446..62e77c742d8 100644
--- a/apps/encryption/tests/lib/crypto/encryptionTest.php
+++ b/apps/encryption/tests/lib/crypto/encryptionTest.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/tests/lib/users/SetupTest.php b/apps/encryption/tests/lib/users/SetupTest.php
index 022bf5dc466..0cc59384b16 100644
--- a/apps/encryption/tests/lib/users/SetupTest.php
+++ b/apps/encryption/tests/lib/users/SetupTest.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Clark Tomlinson <fallen013@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/encryption/vendor/pbkdf2fallback.php b/apps/encryption/vendor/pbkdf2fallback.php
deleted file mode 100644
index ca579f8e7dc..00000000000
--- a/apps/encryption/vendor/pbkdf2fallback.php
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-/* Note; This class can be removed as soon as we drop PHP 5.4 support.
- *
- *
- * Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
- * Copyright (c) 2013, Taylor Hornby
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-namespace OCA\Encryption\Vendor;
-
-class PBKDF2Fallback {
-
- /*
- * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
- * $algorithm - The hash algorithm to use. Recommended: SHA256
- * $password - The password.
- * $salt - A salt that is unique to the password.
- * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
- * $key_length - The length of the derived key in bytes.
- * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
- * Returns: A $key_length-byte key derived from the password and salt.
- *
- * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
- *
- * This implementation of PBKDF2 was originally created by https://defuse.ca
- * With improvements by http://www.variations-of-shadow.com
- */
- public function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) {
- $algorithm = strtolower($algorithm);
- if (!in_array($algorithm, hash_algos(), true))
- trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
- if ($count <= 0 || $key_length <= 0)
- trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);
-
- if (function_exists("hash_pbkdf2")) {
- // The output length is in NIBBLES (4-bits) if $raw_output is false!
- if (!$raw_output) {
- $key_length = $key_length * 2;
- }
- return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
- }
-
- $hash_length = strlen(hash($algorithm, "", true));
- $block_count = ceil($key_length / $hash_length);
-
- $output = "";
- for ($i = 1; $i <= $block_count; $i++) {
- // $i encoded as 4 bytes, big endian.
- $last = $salt . pack("N", $i);
- // first iteration
- $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
- // perform the other $count - 1 iterations
- for ($j = 1; $j < $count; $j++) {
- $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
- }
- $output .= $xorsum;
- }
-
- if ($raw_output)
- return substr($output, 0, $key_length);
- else
- return bin2hex(substr($output, 0, $key_length));
- }
-}
diff --git a/apps/federation/api/ocsauthapi.php b/apps/federation/api/ocsauthapi.php
new file mode 100644
index 00000000000..058a5966374
--- /dev/null
+++ b/apps/federation/api/ocsauthapi.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\API;
+
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\ILogger;
+use OCP\IRequest;
+use OCP\Security\ISecureRandom;
+use OCP\Security\StringUtils;
+
+/**
+ * Class OCSAuthAPI
+ *
+ * OCS API end-points to exchange shared secret between two connected ownClouds
+ *
+ * @package OCA\Federation\API
+ */
+class OCSAuthAPI {
+
+ /** @var IRequest */
+ private $request;
+
+ /** @var ISecureRandom */
+ private $secureRandom;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ /** @var DbHandler */
+ private $dbHandler;
+
+ /** @var ILogger */
+ private $logger;
+
+ /**
+ * OCSAuthAPI constructor.
+ *
+ * @param IRequest $request
+ * @param ISecureRandom $secureRandom
+ * @param IJobList $jobList
+ * @param TrustedServers $trustedServers
+ * @param DbHandler $dbHandler
+ * @param ILogger $logger
+ */
+ public function __construct(
+ IRequest $request,
+ ISecureRandom $secureRandom,
+ IJobList $jobList,
+ TrustedServers $trustedServers,
+ DbHandler $dbHandler,
+ ILogger $logger
+ ) {
+ $this->request = $request;
+ $this->secureRandom = $secureRandom;
+ $this->jobList = $jobList;
+ $this->trustedServers = $trustedServers;
+ $this->dbHandler = $dbHandler;
+ $this->logger = $logger;
+ }
+
+ /**
+ * request received to ask remote server for a shared secret
+ *
+ * @return \OC_OCS_Result
+ */
+ public function requestSharedSecret() {
+
+ $url = $this->request->getParam('url');
+ $token = $this->request->getParam('token');
+
+ if ($this->trustedServers->isTrustedServer($url) === false) {
+ $this->logger->log(\OCP\Util::ERROR, 'remote server not trusted (' . $url . ') while requesting shared secret', ['app' => 'federation']);
+ return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
+ }
+
+ // if both server initiated the exchange of the shared secret the greater
+ // token wins
+ $localToken = $this->dbHandler->getToken($url);
+ if (strcmp($localToken, $token) > 0) {
+ $this->logger->log(\OCP\Util::ERROR, 'remote server (' . $url . ') presented lower token', ['app' => 'federation']);
+ return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
+ }
+
+ $this->jobList->add(
+ 'OCA\Federation\BackgroundJob\GetSharedSecret',
+ [
+ 'url' => $url,
+ 'token' => $token,
+ ]
+ );
+
+ return new \OC_OCS_Result(null, Http::STATUS_OK);
+
+ }
+
+ /**
+ * create shared secret and return it
+ *
+ * @return \OC_OCS_Result
+ */
+ public function getSharedSecret() {
+
+ $url = $this->request->getParam('url');
+ $token = $this->request->getParam('token');
+
+ if ($this->trustedServers->isTrustedServer($url) === false) {
+ $this->logger->log(\OCP\Util::ERROR, 'remote server not trusted (' . $url . ') while getting shared secret', ['app' => 'federation']);
+ return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
+ }
+
+ if ($this->isValidToken($url, $token) === false) {
+ $this->logger->log(\OCP\Util::ERROR, 'remote server (' . $url . ') didn\'t send a valid token (got ' . $token . ') while getting shared secret', ['app' => 'federation']);
+ return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
+ }
+
+ $sharedSecret = $this->secureRandom->generate(32);
+
+ $this->trustedServers->addSharedSecret($url, $sharedSecret);
+ // reset token after the exchange of the shared secret was successful
+ $this->dbHandler->addToken($url, '');
+
+ return new \OC_OCS_Result(['sharedSecret' => $sharedSecret], Http::STATUS_OK);
+
+ }
+
+ protected function isValidToken($url, $token) {
+ $storedToken = $this->dbHandler->getToken($url);
+ return hash_equals($storedToken, $token);
+ }
+
+}
diff --git a/apps/federation/appinfo/app.php b/apps/federation/appinfo/app.php
new file mode 100644
index 00000000000..6686f90121c
--- /dev/null
+++ b/apps/federation/appinfo/app.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Federation\AppInfo;
+
+$app = new Application();
+$app->registerSettings();
+$app->registerHooks();
diff --git a/apps/federation/appinfo/application.php b/apps/federation/appinfo/application.php
new file mode 100644
index 00000000000..0d033f44982
--- /dev/null
+++ b/apps/federation/appinfo/application.php
@@ -0,0 +1,182 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Federation\AppInfo;
+
+use OCA\Federation\API\OCSAuthAPI;
+use OCA\Federation\Controller\SettingsController;
+use OCA\Federation\DAV\FedAuth;
+use OCA\Federation\DbHandler;
+use OCA\Federation\Hooks;
+use OCA\Federation\Middleware\AddServerMiddleware;
+use OCA\Federation\SyncFederationAddressBooks;
+use OCA\Federation\SyncJob;
+use OCA\Federation\TrustedServers;
+use OCP\API;
+use OCP\App;
+use OCP\AppFramework\IAppContainer;
+use OCP\SabrePluginEvent;
+use OCP\Util;
+use Sabre\DAV\Auth\Plugin;
+
+class Application extends \OCP\AppFramework\App {
+
+ /**
+ * @param array $urlParams
+ */
+ public function __construct($urlParams = array()) {
+ parent::__construct('federation', $urlParams);
+ $this->registerService();
+ $this->registerMiddleware();
+ }
+
+ /**
+ * register setting scripts
+ */
+ public function registerSettings() {
+ App::registerAdmin('federation', 'settings/settings-admin');
+ }
+
+ private function registerService() {
+ $container = $this->getContainer();
+
+ $container->registerService('addServerMiddleware', function(IAppContainer $c) {
+ return new AddServerMiddleware(
+ $c->getAppName(),
+ \OC::$server->getL10N($c->getAppName()),
+ \OC::$server->getLogger()
+ );
+ });
+
+ $container->registerService('DbHandler', function(IAppContainer $c) {
+ return new DbHandler(
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getL10N($c->getAppName())
+ );
+ });
+
+ $container->registerService('TrustedServers', function(IAppContainer $c) {
+ return new TrustedServers(
+ $c->query('DbHandler'),
+ \OC::$server->getHTTPClientService(),
+ \OC::$server->getLogger(),
+ \OC::$server->getJobList(),
+ \OC::$server->getSecureRandom(),
+ \OC::$server->getConfig()
+ );
+ });
+
+ $container->registerService('SettingsController', function (IAppContainer $c) {
+ $server = $c->getServer();
+ return new SettingsController(
+ $c->getAppName(),
+ $server->getRequest(),
+ $server->getL10N($c->getAppName()),
+ $c->query('TrustedServers')
+ );
+ });
+ }
+
+ private function registerMiddleware() {
+ $container = $this->getContainer();
+ $container->registerMiddleware('addServerMiddleware');
+ }
+
+ /**
+ * register OCS API Calls
+ */
+ public function registerOCSApi() {
+
+ $container = $this->getContainer();
+ $server = $container->getServer();
+
+ $auth = new OCSAuthAPI(
+ $server->getRequest(),
+ $server->getSecureRandom(),
+ $server->getJobList(),
+ $container->query('TrustedServers'),
+ $container->query('DbHandler'),
+ $server->getLogger()
+
+ );
+
+ API::register('get',
+ '/apps/federation/api/v1/shared-secret',
+ array($auth, 'getSharedSecret'),
+ 'federation',
+ API::GUEST_AUTH
+ );
+
+ API::register('post',
+ '/apps/federation/api/v1/request-shared-secret',
+ array($auth, 'requestSharedSecret'),
+ 'federation',
+ API::GUEST_AUTH
+ );
+
+ }
+
+ /**
+ * listen to federated_share_added hooks to auto-add new servers to the
+ * list of trusted servers.
+ */
+ public function registerHooks() {
+
+ $container = $this->getContainer();
+ $hooksManager = new Hooks($container->query('TrustedServers'));
+
+ Util::connectHook(
+ 'OCP\Share',
+ 'federated_share_added',
+ $hooksManager,
+ 'addServerHook'
+ );
+
+ $dispatcher = $this->getContainer()->getServer()->getEventDispatcher();
+ $dispatcher->addListener('OCA\DAV\Connector\Sabre::authInit', function($event) use($container) {
+ if ($event instanceof SabrePluginEvent) {
+ $authPlugin = $event->getServer()->getPlugin('auth');
+ if ($authPlugin instanceof Plugin) {
+ $h = new DbHandler($container->getServer()->getDatabaseConnection(),
+ $container->getServer()->getL10N('federation')
+ );
+ $authPlugin->addBackend(new FedAuth($h));
+ }
+ }
+ });
+ }
+
+ public function setupCron() {
+ $jl = $this->getContainer()->getServer()->getJobList();
+ $jl->add(new SyncJob());
+ }
+
+ /**
+ * @return SyncFederationAddressBooks
+ */
+ public function getSyncService() {
+ $syncService = \OC::$server->query('CardDAVSyncService');
+ $dbHandler = $this->getContainer()->query('DbHandler');
+ return new SyncFederationAddressBooks($dbHandler, $syncService);
+ }
+
+}
diff --git a/apps/federation/appinfo/database.xml b/apps/federation/appinfo/database.xml
new file mode 100644
index 00000000000..05b7fb12b49
--- /dev/null
+++ b/apps/federation/appinfo/database.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<database>
+ <name>*dbname*</name>
+ <create>true</create>
+ <overwrite>false</overwrite>
+ <charset>utf8</charset>
+ <table>
+ <name>*dbprefix*trusted_servers</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <length>4</length>
+ </field>
+ <field>
+ <name>url</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>512</length>
+ <comments>Url of trusted server</comments>
+ </field>
+ <field>
+ <name>url_hash</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>32</length>
+ <comments>md5 hash of the url without the protocol</comments>
+ </field>
+ <field>
+ <name>token</name>
+ <type>text</type>
+ <length>128</length>
+ <comments>token used to exchange the shared secret</comments>
+ </field>
+ <field>
+ <name>shared_secret</name>
+ <type>text</type>
+ <length>256</length>
+ <comments>shared secret used to authenticate</comments>
+ </field>
+ <field>
+ <name>status</name>
+ <type>integer</type>
+ <length>4</length>
+ <notnull>true</notnull>
+ <default>2</default>
+ <comments>current status of the connection</comments>
+ </field>
+ <field>
+ <name>sync_token</name>
+ <type>text</type>
+ <length>512</length>
+ <comments>cardDav sync token</comments>
+ </field>
+ <index>
+ <name>url_hash</name>
+ <unique>true</unique>
+ <field>
+ <name>url_hash</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ </declaration>
+ </table>
+</database>
diff --git a/apps/federation/appinfo/info.xml b/apps/federation/appinfo/info.xml
new file mode 100644
index 00000000000..7786deef38e
--- /dev/null
+++ b/apps/federation/appinfo/info.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<info>
+ <id>federation</id>
+ <name>Federation</name>
+ <description>ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing.</description>
+ <licence>AGPL</licence>
+ <author>Bjoern Schiessle</author>
+ <version>0.0.3</version>
+ <namespace>Federation</namespace>
+ <category>other</category>
+ <dependencies>
+ <owncloud min-version="9.0" max-version="9.0" />
+ </dependencies>
+ <types>
+ <authentication/>
+ </types>
+</info>
diff --git a/apps/federation/appinfo/install.php b/apps/federation/appinfo/install.php
new file mode 100644
index 00000000000..f2a98d7f555
--- /dev/null
+++ b/apps/federation/appinfo/install.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+$app = new \OCA\Federation\AppInfo\Application();
+$app->setupCron();
diff --git a/apps/federation/appinfo/register_command.php b/apps/federation/appinfo/register_command.php
new file mode 100644
index 00000000000..162e103372e
--- /dev/null
+++ b/apps/federation/appinfo/register_command.php
@@ -0,0 +1,7 @@
+<?php
+
+$app = new \OCA\Federation\AppInfo\Application();
+$syncService = $app->getSyncService();
+
+/** @var Symfony\Component\Console\Application $application */
+$application->add(new \OCA\Federation\Command\SyncFederationAddressBooks($syncService));
diff --git a/apps/federation/appinfo/routes.php b/apps/federation/appinfo/routes.php
new file mode 100644
index 00000000000..6b4124094df
--- /dev/null
+++ b/apps/federation/appinfo/routes.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+$application = new \OCA\Federation\AppInfo\Application();
+
+$application->registerRoutes(
+ $this,
+ [
+ 'routes' => [
+ [
+ 'name' => 'Settings#addServer',
+ 'url' => '/trusted-servers',
+ 'verb' => 'POST'
+ ],
+ [
+ 'name' => 'Settings#removeServer',
+ 'url' => '/trusted-servers/{id}',
+ 'verb' => 'DELETE'
+ ],
+ [
+ 'name' => 'Settings#autoAddServers',
+ 'url' => '/auto-add-servers',
+ 'verb' => 'POST'
+ ],
+ ]
+ ]
+);
+
+$application->registerOCSApi();
diff --git a/apps/federation/appinfo/update.php b/apps/federation/appinfo/update.php
new file mode 100644
index 00000000000..f2a98d7f555
--- /dev/null
+++ b/apps/federation/appinfo/update.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+$app = new \OCA\Federation\AppInfo\Application();
+$app->setupCron();
diff --git a/apps/federation/backgroundjob/getsharedsecret.php b/apps/federation/backgroundjob/getsharedsecret.php
new file mode 100644
index 00000000000..a98a17e323b
--- /dev/null
+++ b/apps/federation/backgroundjob/getsharedsecret.php
@@ -0,0 +1,191 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\BackgroundJob;
+
+use GuzzleHttp\Exception\ClientException;
+use OC\BackgroundJob\JobList;
+use OC\BackgroundJob\QueuedJob;
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClient;
+use OCP\ILogger;
+use OCP\IURLGenerator;
+
+/**
+ * Class GetSharedSecret
+ *
+ * request shared secret from remote ownCloud
+ *
+ * @package OCA\Federation\Backgroundjob
+ */
+class GetSharedSecret extends QueuedJob{
+
+ /** @var IClient */
+ private $httpClient;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ /** @var DbHandler */
+ private $dbHandler;
+
+ /** @var ILogger */
+ private $logger;
+
+ private $endPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret?format=json';
+
+ /**
+ * RequestSharedSecret constructor.
+ *
+ * @param IClient $httpClient
+ * @param IURLGenerator $urlGenerator
+ * @param IJobList $jobList
+ * @param TrustedServers $trustedServers
+ * @param ILogger $logger
+ * @param DbHandler $dbHandler
+ */
+ public function __construct(
+ IClient $httpClient = null,
+ IURLGenerator $urlGenerator = null,
+ IJobList $jobList = null,
+ TrustedServers $trustedServers = null,
+ ILogger $logger = null,
+ dbHandler $dbHandler = null
+ ) {
+ $this->logger = $logger ? $logger : \OC::$server->getLogger();
+ $this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient();
+ $this->jobList = $jobList ? $jobList : \OC::$server->getJobList();
+ $this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator();
+ $this->dbHandler = $dbHandler ? $dbHandler : new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation'));
+ if ($trustedServers) {
+ $this->trustedServers = $trustedServers;
+ } else {
+ $this->trustedServers = new TrustedServers(
+ $this->dbHandler,
+ \OC::$server->getHTTPClientService(),
+ $this->logger,
+ $this->jobList,
+ \OC::$server->getSecureRandom(),
+ \OC::$server->getConfig()
+ );
+ }
+ }
+
+ /**
+ * run the job, then remove it from the joblist
+ *
+ * @param JobList $jobList
+ * @param ILogger $logger
+ */
+ public function execute($jobList, ILogger $logger = null) {
+ $jobList->remove($this, $this->argument);
+ $target = $this->argument['url'];
+ // only execute if target is still in the list of trusted domains
+ if ($this->trustedServers->isTrustedServer($target)) {
+ $this->parentExecute($jobList, $logger);
+ }
+ }
+
+ /**
+ * call execute() method of parent
+ *
+ * @param JobList $jobList
+ * @param ILogger $logger
+ */
+ protected function parentExecute($jobList, $logger) {
+ parent::execute($jobList, $logger);
+ }
+
+ protected function run($argument) {
+ $target = $argument['url'];
+ $source = $this->urlGenerator->getAbsoluteURL('/');
+ $source = rtrim($source, '/');
+ $token = $argument['token'];
+
+ try {
+ $result = $this->httpClient->get(
+ $target . $this->endPoint,
+ [
+ 'query' =>
+ [
+ 'url' => $source,
+ 'token' => $token
+ ],
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ );
+
+ $status = $result->getStatusCode();
+
+ } catch (ClientException $e) {
+ $status = $e->getCode();
+ $this->logger->logException($e);
+ } catch (\Exception $e) {
+ $status = HTTP::STATUS_INTERNAL_SERVER_ERROR;
+ $this->logger->logException($e);
+ }
+
+ // if we received a unexpected response we try again later
+ if (
+ $status !== Http::STATUS_OK
+ && $status !== Http::STATUS_FORBIDDEN
+ ) {
+ $this->jobList->add(
+ 'OCA\Federation\BackgroundJob\GetSharedSecret',
+ $argument
+ );
+ } else {
+ // reset token if we received a valid response
+ $this->dbHandler->addToken($target, '');
+ }
+
+ if ($status === Http::STATUS_OK) {
+ $body = $result->getBody();
+ $result = json_decode($body, true);
+ if (isset($result['ocs']['data']['sharedSecret'])) {
+ $this->trustedServers->addSharedSecret(
+ $target,
+ $result['ocs']['data']['sharedSecret']
+ );
+ } else {
+ $this->logger->error(
+ 'remote server "' . $target . '"" does not return a valid shared secret',
+ ['app' => 'federation']
+ );
+ $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
+ }
+ }
+
+ }
+}
diff --git a/apps/federation/backgroundjob/requestsharedsecret.php b/apps/federation/backgroundjob/requestsharedsecret.php
new file mode 100644
index 00000000000..2db5d09545a
--- /dev/null
+++ b/apps/federation/backgroundjob/requestsharedsecret.php
@@ -0,0 +1,174 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\BackgroundJob;
+
+
+use GuzzleHttp\Exception\ClientException;
+use OC\BackgroundJob\JobList;
+use OC\BackgroundJob\QueuedJob;
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClient;
+use OCP\ILogger;
+use OCP\IURLGenerator;
+
+/**
+ * Class RequestSharedSecret
+ *
+ * Ask remote ownCloud to request a sharedSecret from this server
+ *
+ * @package OCA\Federation\Backgroundjob
+ */
+class RequestSharedSecret extends QueuedJob {
+
+ /** @var IClient */
+ private $httpClient;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var DbHandler */
+ private $dbHandler;
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ private $endPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret?format=json';
+
+ /** @var ILogger */
+ private $logger;
+
+ /**
+ * RequestSharedSecret constructor.
+ *
+ * @param IClient $httpClient
+ * @param IURLGenerator $urlGenerator
+ * @param IJobList $jobList
+ * @param TrustedServers $trustedServers
+ * @param DbHandler $dbHandler
+ */
+ public function __construct(
+ IClient $httpClient = null,
+ IURLGenerator $urlGenerator = null,
+ IJobList $jobList = null,
+ TrustedServers $trustedServers = null,
+ dbHandler $dbHandler = null
+ ) {
+ $this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient();
+ $this->jobList = $jobList ? $jobList : \OC::$server->getJobList();
+ $this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator();
+ $this->dbHandler = $dbHandler ? $dbHandler : new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation'));
+ $this->logger = \OC::$server->getLogger();
+ if ($trustedServers) {
+ $this->trustedServers = $trustedServers;
+ } else {
+ $this->trustedServers = new TrustedServers(
+ $this->dbHandler,
+ \OC::$server->getHTTPClientService(),
+ $this->logger,
+ $this->jobList,
+ \OC::$server->getSecureRandom(),
+ \OC::$server->getConfig()
+ );
+ }
+ }
+
+
+ /**
+ * run the job, then remove it from the joblist
+ *
+ * @param JobList $jobList
+ * @param ILogger $logger
+ */
+ public function execute($jobList, ILogger $logger = null) {
+ $jobList->remove($this, $this->argument);
+ $target = $this->argument['url'];
+ // only execute if target is still in the list of trusted domains
+ if ($this->trustedServers->isTrustedServer($target)) {
+ $this->parentExecute($jobList, $logger);
+ }
+ }
+
+ /**
+ * @param JobList $jobList
+ * @param ILogger $logger
+ */
+ protected function parentExecute($jobList, $logger) {
+ parent::execute($jobList, $logger);
+ }
+
+ protected function run($argument) {
+
+ $target = $argument['url'];
+ $source = $this->urlGenerator->getAbsoluteURL('/');
+ $source = rtrim($source, '/');
+ $token = $argument['token'];
+
+ try {
+ $result = $this->httpClient->post(
+ $target . $this->endPoint,
+ [
+ 'body' => [
+ 'url' => $source,
+ 'token' => $token,
+ ],
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ );
+
+ $status = $result->getStatusCode();
+
+ } catch (ClientException $e) {
+ $status = $e->getCode();
+ $this->logger->logException($e);
+ } catch (\Exception $e) {
+ $status = HTTP::STATUS_INTERNAL_SERVER_ERROR;
+ $this->logger->logException($e);
+ }
+
+ // if we received a unexpected response we try again later
+ if (
+ $status !== Http::STATUS_OK
+ && $status !== Http::STATUS_FORBIDDEN
+ ) {
+ $this->jobList->add(
+ 'OCA\Federation\BackgroundJob\RequestSharedSecret',
+ $argument
+ );
+ }
+
+ if ($status === Http::STATUS_FORBIDDEN) {
+ // clear token if remote server refuses to ask for shared secret
+ $this->dbHandler->addToken($target, '');
+ }
+
+ }
+}
diff --git a/apps/federation/command/syncfederationaddressbooks.php b/apps/federation/command/syncfederationaddressbooks.php
new file mode 100644
index 00000000000..61703d9d4e4
--- /dev/null
+++ b/apps/federation/command/syncfederationaddressbooks.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace OCA\Federation\Command;
+
+use OCA\Federation\DbHandler;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SyncFederationAddressBooks extends Command {
+
+ /** @var \OCA\Federation\SyncFederationAddressBooks */
+ private $syncService;
+
+ /**
+ * @param \OCA\Federation\SyncFederationAddressBooks $syncService
+ */
+ function __construct(\OCA\Federation\SyncFederationAddressBooks $syncService) {
+ parent::__construct();
+
+ $this->syncService = $syncService;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('federation:sync-addressbooks')
+ ->setDescription('Synchronizes addressbooks of all federated clouds');
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return int
+ */
+ protected function execute(InputInterface $input, OutputInterface $output) {
+
+ $progress = new ProgressBar($output);
+ $progress->start();
+ $this->syncService->syncThemAll(function($url, $ex) use ($progress, $output) {
+ if ($ex instanceof \Exception) {
+ $output->writeln("Error while syncing $url : " . $ex->getMessage());
+ } else {
+ $progress->advance();
+ }
+ });
+
+ $progress->finish();
+ $output->writeln('');
+
+ return 0;
+ }
+}
diff --git a/apps/federation/controller/settingscontroller.php b/apps/federation/controller/settingscontroller.php
new file mode 100644
index 00000000000..e5e46606f12
--- /dev/null
+++ b/apps/federation/controller/settingscontroller.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Federation\Controller;
+
+use OC\HintException;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\IConfig;
+use OCP\IL10N;
+use OCP\IRequest;
+
+
+class SettingsController extends Controller {
+
+ /** @var IL10N */
+ private $l;
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ /**
+ * @param string $AppName
+ * @param IRequest $request
+ * @param IL10N $l10n
+ * @param TrustedServers $trustedServers
+ */
+ public function __construct($AppName,
+ IRequest $request,
+ IL10N $l10n,
+ TrustedServers $trustedServers
+ ) {
+ parent::__construct($AppName, $request);
+ $this->l = $l10n;
+ $this->trustedServers = $trustedServers;
+ }
+
+
+ /**
+ * add server to the list of trusted ownClouds
+ *
+ * @param string $url
+ * @return DataResponse
+ * @throws HintException
+ */
+ public function addServer($url) {
+ $this->checkServer($url);
+ $id = $this->trustedServers->addServer($url);
+
+ return new DataResponse(
+ [
+ 'url' => $url,
+ 'id' => $id,
+ 'message' => (string) $this->l->t('Server added to the list of trusted ownClouds')
+ ]
+ );
+ }
+
+ /**
+ * add server to the list of trusted ownClouds
+ *
+ * @param int $id
+ * @return DataResponse
+ */
+ public function removeServer($id) {
+ $this->trustedServers->removeServer($id);
+ return new DataResponse();
+ }
+
+ /**
+ * enable/disable to automatically add servers to the list of trusted servers
+ * once a federated share was created and accepted successfully
+ *
+ * @param bool $autoAddServers
+ */
+ public function autoAddServers($autoAddServers) {
+ $this->trustedServers->setAutoAddServers($autoAddServers);
+ }
+
+ /**
+ * check if the server should be added to the list of trusted servers or not
+ *
+ * @param string $url
+ * @return bool
+ * @throws HintException
+ */
+ protected function checkServer($url) {
+ if ($this->trustedServers->isTrustedServer($url) === true) {
+ $message = 'Server is already in the list of trusted servers.';
+ $hint = $this->l->t('Server is already in the list of trusted servers.');
+ throw new HintException($message, $hint);
+ }
+
+ if ($this->trustedServers->isOwnCloudServer($url) === false) {
+ $message = 'No ownCloud server found';
+ $hint = $this->l->t('No ownCloud server found');
+ throw new HintException($message, $hint);
+ }
+
+ return true;
+ }
+
+}
diff --git a/apps/federation/css/settings-admin.css b/apps/federation/css/settings-admin.css
new file mode 100644
index 00000000000..55b1dd64d15
--- /dev/null
+++ b/apps/federation/css/settings-admin.css
@@ -0,0 +1,26 @@
+#ocFederationSettings p {
+ padding-top: 10px;
+}
+
+#listOfTrustedServers li {
+ padding-top: 10px;
+ padding-left: 20px;
+}
+
+.removeTrustedServer {
+ display: none;
+ vertical-align:middle;
+ padding-left: 10px;
+}
+
+#ocFederationAddServerButton {
+ cursor: pointer;
+}
+
+#listOfTrustedServers li:hover {
+ cursor: pointer;
+}
+
+#listOfTrustedServers .status {
+ margin-right: 10px;
+}
diff --git a/apps/federation/dav/fedauth.php b/apps/federation/dav/fedauth.php
new file mode 100644
index 00000000000..09d61a1f2c7
--- /dev/null
+++ b/apps/federation/dav/fedauth.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\Federation\DAV;
+
+use OCA\Federation\DbHandler;
+use Sabre\DAV\Auth\Backend\AbstractBasic;
+
+class FedAuth extends AbstractBasic {
+
+ /** @var DbHandler */
+ private $db;
+
+ /**
+ * FedAuth constructor.
+ *
+ * @param DbHandler $db
+ */
+ public function __construct(DbHandler $db) {
+ $this->db = $db;
+ $this->principalPrefix = 'principals/system/';
+ }
+
+ /**
+ * Validates a username and password
+ *
+ * This method should return true or false depending on if login
+ * succeeded.
+ *
+ * @param string $username
+ * @param string $password
+ * @return bool
+ */
+ protected function validateUserPass($username, $password) {
+ return $this->db->auth($username, $password);
+ }
+}
diff --git a/apps/federation/img/app.svg b/apps/federation/img/app.svg
new file mode 100644
index 00000000000..b6ae35211a3
--- /dev/null
+++ b/apps/federation/img/app.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.0" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m13.733 0.00064c-0.52991 0-0.93331 0.40337-0.93331 0.93333v2.6666c-1.182 0.3034-2.243 0.7934-3.2668 1.4001l-1.9334-1.9334c-0.3747-0.3747-0.9586-0.3747-1.3333 0l-3.1999 3.2c-0.37473 0.37474-0.37473 0.95859 0 1.3333l1.9334 1.9335c-0.6067 1.0239-1.0967 2.0849-1.4001 3.2669h-2.6666c-0.52994 0-0.9333 0.403-0.9333 0.933v4.5333c2e-8 0.52996 0.40336 0.93333 0.93331 0.93333h2.6666c0.30335 1.1817 0.79332 2.2426 1.4 3.2666l-1.9334 1.9349c-0.37473 0.37474-0.37473 0.95859 0 1.3333l3.1999 3.2c0.37473 0.37474 0.95857 0.37474 1.3333 0l1.9334-1.9349c1.024 0.608 2.0849 1.0965 3.2665 1.3995v2.6667c0 0.53 0.403 0.933 0.933 0.933h4.5332c0.52991 0 0.93331-0.4032 0.93331-0.9344v-2.6667c1.1816-0.30336 2.2425-0.79335 3.2665-1.4l1.9333 1.9333c0.37473 0.37474 0.95857 0.37474 1.3333 0l3.1999-3.2c0.37473-0.37474 0.37473-0.95859 0-1.3333l-1.9327-1.9328c0.60798-1.024 1.0965-2.0845 1.3994-3.2661h2.6666c0.532 0 0.935-0.403 0.935-0.933v-4.534c0-0.53-0.403-0.933-0.934-0.933h-2.667c-0.303-1.182-0.791-2.243-1.399-3.2666l1.932-1.9334c0.37473-0.37474 0.37473-0.95859 0-1.3333l-3.2-3.2c-0.37473-0.37474-0.95857-0.37474-1.3333 0l-1.9327 1.9334c-1.024-0.6067-2.084-1.0967-3.266-1.4001v-2.6667c0-0.52993-0.403-0.9333-0.933-0.9333zm2.2666 8.8689c3.9361 0 7.1309 3.1947 7.1309 7.1311 0 3.9362-3.1946 7.1311-7.1309 7.1311-3.9361 0-7.1309-3.1955-7.1309-7.1317s3.1948-7.1311 7.1309-7.1311z" display="block" fill="#fff"/>
+</svg>
diff --git a/apps/federation/js/settings-admin.js b/apps/federation/js/settings-admin.js
new file mode 100644
index 00000000000..7d531b39d8c
--- /dev/null
+++ b/apps/federation/js/settings-admin.js
@@ -0,0 +1,82 @@
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+$(document).ready(function () {
+
+ // show input field to add a new trusted server
+ $("#ocFederationAddServer").on('click', function() {
+ $('#ocFederationAddServerButton').addClass('hidden');
+ $("#serverUrl").removeClass('hidden');
+ $("#serverUrl").focus();
+ });
+
+ // add new trusted server
+ $("#serverUrl").keyup(function (e) {
+ if (e.keyCode === 13) { // add server on "enter"
+ var url = $('#serverUrl').val();
+ OC.msg.startSaving('#ocFederationAddServer .msg');
+ $.post(
+ OC.generateUrl('/apps/federation/trusted-servers'),
+ {
+ url: url
+ }
+ ).done(function (data) {
+ $('#serverUrl').attr('value', '');
+ $('ul#listOfTrustedServers').prepend(
+ $('<li>')
+ .attr('id', data.id)
+ .attr('class', 'icon-delete')
+ .html('<span class="status indeterminate"></span>' + data.url)
+ );
+ OC.msg.finishedSuccess('#ocFederationAddServer .msg', data.message);
+ })
+ .fail(function (jqXHR) {
+ OC.msg.finishedError('#ocFederationAddServer .msg', JSON.parse(jqXHR.responseText).message);
+ });
+ } else if (e.keyCode === 27) { // hide input filed again in ESC
+ $('#ocFederationAddServerButton').toggleClass('hidden');
+ $("#serverUrl").toggleClass('hidden');
+ }
+ });
+
+ // remove trusted server from list
+ $( "#listOfTrustedServers" ).on('click', 'li', function() {
+ var id = $(this).attr('id');
+ var $this = $(this);
+ $.ajax({
+ url: OC.generateUrl('/apps/federation/trusted-servers/' + id),
+ type: 'DELETE',
+ success: function(response) {
+ $this.remove();
+ }
+ });
+
+ });
+
+ $("#ocFederationSettings #autoAddServers").change(function() {
+ $.post(
+ OC.generateUrl('/apps/federation/auto-add-servers'),
+ {
+ autoAddServers: $(this).is(":checked")
+ }
+ );
+ });
+
+});
diff --git a/apps/federation/lib/dbhandler.php b/apps/federation/lib/dbhandler.php
new file mode 100644
index 00000000000..9e44c72cc42
--- /dev/null
+++ b/apps/federation/lib/dbhandler.php
@@ -0,0 +1,290 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation;
+
+
+use OC\Files\Filesystem;
+use OC\HintException;
+use OCP\IDBConnection;
+use OCP\IL10N;
+
+/**
+ * Class DbHandler
+ *
+ * handles all database calls for the federation app
+ *
+ * @group DB
+ * @package OCA\Federation
+ */
+class DbHandler {
+
+ /** @var IDBConnection */
+ private $connection;
+
+ /** @var IL10N */
+ private $l;
+
+ /** @var string */
+ private $dbTable = 'trusted_servers';
+
+ /**
+ * @param IDBConnection $connection
+ * @param IL10N $il10n
+ */
+ public function __construct(
+ IDBConnection $connection,
+ IL10N $il10n
+ ) {
+ $this->connection = $connection;
+ $this->IL10N = $il10n;
+ }
+
+ /**
+ * add server to the list of trusted ownCloud servers
+ *
+ * @param string $url
+ * @return int
+ * @throws HintException
+ */
+ public function addServer($url) {
+ $hash = $this->hash($url);
+ $url = rtrim($url, '/');
+ $query = $this->connection->getQueryBuilder();
+ $query->insert($this->dbTable)
+ ->values(
+ [
+ 'url' => $query->createParameter('url'),
+ 'url_hash' => $query->createParameter('url_hash'),
+ ]
+ )
+ ->setParameter('url', $url)
+ ->setParameter('url_hash', $hash);
+
+ $result = $query->execute();
+
+ if ($result) {
+ return (int)$this->connection->lastInsertId('*PREFIX*'.$this->dbTable);
+ } else {
+ $message = 'Internal failure, Could not add ownCloud as trusted server: ' . $url;
+ $message_t = $this->l->t('Could not add server');
+ throw new HintException($message, $message_t);
+ }
+ }
+
+ /**
+ * remove server from the list of trusted ownCloud servers
+ *
+ * @param int $id
+ */
+ public function removeServer($id) {
+ $query = $this->connection->getQueryBuilder();
+ $query->delete($this->dbTable)
+ ->where($query->expr()->eq('id', $query->createParameter('id')))
+ ->setParameter('id', $id);
+ $query->execute();
+ }
+
+ /**
+ * get all trusted servers
+ *
+ * @return array
+ */
+ public function getAllServer() {
+ $query = $this->connection->getQueryBuilder();
+ $query->select(['url', 'id', 'status', 'shared_secret', 'sync_token'])->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ return $result;
+ }
+
+ /**
+ * check if server already exists in the database table
+ *
+ * @param string $url
+ * @return bool
+ */
+ public function serverExists($url) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->select('url')->from($this->dbTable)
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash);
+ $result = $query->execute()->fetchAll();
+
+ return !empty($result);
+ }
+
+ /**
+ * write token to database. Token is used to exchange the secret
+ *
+ * @param string $url
+ * @param string $token
+ */
+ public function addToken($url, $token) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->update($this->dbTable)
+ ->set('token', $query->createParameter('token'))
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash)
+ ->setParameter('token', $token);
+ $query->execute();
+ }
+
+ /**
+ * get token stored in database
+ *
+ * @param string $url
+ * @return string
+ */
+ public function getToken($url) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->select('token')->from($this->dbTable)
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash);
+
+ $result = $query->execute()->fetch();
+ return $result['token'];
+ }
+
+ /**
+ * add shared Secret to database
+ *
+ * @param string $url
+ * @param string $sharedSecret
+ */
+ public function addSharedSecret($url, $sharedSecret) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->update($this->dbTable)
+ ->set('shared_secret', $query->createParameter('sharedSecret'))
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash)
+ ->setParameter('sharedSecret', $sharedSecret);
+ $query->execute();
+ }
+
+ /**
+ * get shared secret from database
+ *
+ * @param string $url
+ * @return string
+ */
+ public function getSharedSecret($url) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->select('shared_secret')->from($this->dbTable)
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash);
+
+ $result = $query->execute()->fetch();
+ return $result['shared_secret'];
+ }
+
+ /**
+ * set server status
+ *
+ * @param string $url
+ * @param int $status
+ * @param string|null $token
+ */
+ public function setServerStatus($url, $status, $token = null) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->update($this->dbTable)
+ ->set('status', $query->createNamedParameter($status))
+ ->where($query->expr()->eq('url_hash', $query->createNamedParameter($hash)));
+ if (!is_null($token)) {
+ $query->set('sync_token', $query->createNamedParameter($token));
+ }
+ $query->execute();
+ }
+
+ /**
+ * get server status
+ *
+ * @param string $url
+ * @return int
+ */
+ public function getServerStatus($url) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->select('status')->from($this->dbTable)
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash);
+
+ $result = $query->execute()->fetch();
+ return (int)$result['status'];
+ }
+
+ /**
+ * create hash from URL
+ *
+ * @param string $url
+ * @return string
+ */
+ protected function hash($url) {
+ $normalized = $this->normalizeUrl($url);
+ return md5($normalized);
+ }
+
+ /**
+ * normalize URL, used to create the md5 hash
+ *
+ * @param string $url
+ * @return string
+ */
+ protected function normalizeUrl($url) {
+ $normalized = $url;
+
+ if (strpos($url, 'https://') === 0) {
+ $normalized = substr($url, strlen('https://'));
+ } else if (strpos($url, 'http://') === 0) {
+ $normalized = substr($url, strlen('http://'));
+ }
+
+ $normalized = Filesystem::normalizePath($normalized);
+ $normalized = trim($normalized, '/');
+
+ return $normalized;
+ }
+
+ /**
+ * @param $username
+ * @param $password
+ * @return bool
+ */
+ public function auth($username, $password) {
+ if ($username !== 'system') {
+ return false;
+ }
+ $query = $this->connection->getQueryBuilder();
+ $query->select('url')->from($this->dbTable)
+ ->where($query->expr()->eq('shared_secret', $query->createNamedParameter($password)));
+
+ $result = $query->execute()->fetch();
+ return !empty($result);
+ }
+
+}
diff --git a/apps/federation/lib/hooks.php b/apps/federation/lib/hooks.php
new file mode 100644
index 00000000000..b7f63d27f55
--- /dev/null
+++ b/apps/federation/lib/hooks.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation;
+
+
+
+class Hooks {
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ public function __construct(TrustedServers $trustedServers) {
+ $this->trustedServers = $trustedServers;
+ }
+
+ /**
+ * add servers to the list of trusted servers once a federated share was established
+ *
+ * @param array $params
+ */
+ public function addServerHook($params) {
+ if (
+ $this->trustedServers->getAutoAddServers() === true &&
+ $this->trustedServers->isTrustedServer($params['server']) === false
+ ) {
+ $this->trustedServers->addServer($params['server']);
+ }
+ }
+
+}
diff --git a/apps/federation/lib/syncfederationaddressbooks.php b/apps/federation/lib/syncfederationaddressbooks.php
new file mode 100644
index 00000000000..6419fdddf8e
--- /dev/null
+++ b/apps/federation/lib/syncfederationaddressbooks.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace OCA\Federation;
+
+use OCA\DAV\CardDAV\SyncService;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SyncFederationAddressBooks {
+
+ /** @var DbHandler */
+ protected $dbHandler;
+
+ /** @var SyncService */
+ private $syncService;
+
+ /**
+ * @param DbHandler $dbHandler
+ * @param SyncService $syncService
+ */
+ function __construct(DbHandler $dbHandler, SyncService $syncService) {
+ $this->syncService = $syncService;
+ $this->dbHandler = $dbHandler;
+ }
+
+ /**
+ * @param \Closure $callback
+ */
+ public function syncThemAll(\Closure $callback) {
+
+ $trustedServers = $this->dbHandler->getAllServer();
+ foreach ($trustedServers as $trustedServer) {
+ $url = $trustedServer['url'];
+ $callback($url, null);
+ $sharedSecret = $trustedServer['shared_secret'];
+ $syncToken = $trustedServer['sync_token'];
+
+ if (is_null($sharedSecret)) {
+ continue;
+ }
+ $targetBookId = sha1($url);
+ $targetPrincipal = "principals/system/system";
+ $targetBookProperties = [
+ '{DAV:}displayname' => $url
+ ];
+ try {
+ $newToken = $this->syncService->syncRemoteAddressBook($url, 'system', $sharedSecret, $syncToken, $targetBookId, $targetPrincipal, $targetBookProperties);
+ if ($newToken !== $syncToken) {
+ $this->dbHandler->setServerStatus($url, TrustedServers::STATUS_OK, $newToken);
+ }
+ } catch (\Exception $ex) {
+ $callback($url, $ex);
+ }
+ }
+ }
+}
diff --git a/apps/federation/lib/syncjob.php b/apps/federation/lib/syncjob.php
new file mode 100644
index 00000000000..2b904813b92
--- /dev/null
+++ b/apps/federation/lib/syncjob.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Federation;
+
+use OC\BackgroundJob\TimedJob;
+use OCA\Federation\AppInfo\Application;
+
+class SyncJob extends TimedJob {
+
+ public function __construct() {
+ // Run once a day
+ $this->setInterval(24 * 60 * 60);
+ }
+
+ protected function run($argument) {
+ $app = new Application();
+ $ss = $app->getSyncService();
+ $ss->syncThemAll(function($url, $ex) {
+ if ($ex instanceof \Exception) {
+ \OC::$server->getLogger()->error("Error while syncing $url : " . $ex->getMessage(), ['app' => 'fed-sync']);
+ }
+ });
+ }
+}
diff --git a/apps/federation/lib/trustedservers.php b/apps/federation/lib/trustedservers.php
new file mode 100644
index 00000000000..e3ce8228cc3
--- /dev/null
+++ b/apps/federation/lib/trustedservers.php
@@ -0,0 +1,255 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation;
+
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClientService;
+use OCP\IConfig;
+use OCP\ILogger;
+use OCP\Security\ISecureRandom;
+
+class TrustedServers {
+
+ /** after a user list was exchanged at least once successfully */
+ const STATUS_OK = 1;
+ /** waiting for shared secret or initial user list exchange */
+ const STATUS_PENDING = 2;
+ /** something went wrong, misconfigured server, software bug,... user interaction needed */
+ const STATUS_FAILURE = 3;
+
+ /** @var dbHandler */
+ private $dbHandler;
+
+ /** @var IClientService */
+ private $httpClientService;
+
+ /** @var ILogger */
+ private $logger;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var ISecureRandom */
+ private $secureRandom;
+
+ /** @var IConfig */
+ private $config;
+
+ /**
+ * @param DbHandler $dbHandler
+ * @param IClientService $httpClientService
+ * @param ILogger $logger
+ * @param IJobList $jobList
+ * @param ISecureRandom $secureRandom
+ * @param IConfig $config
+ */
+ public function __construct(
+ DbHandler $dbHandler,
+ IClientService $httpClientService,
+ ILogger $logger,
+ IJobList $jobList,
+ ISecureRandom $secureRandom,
+ IConfig $config
+ ) {
+ $this->dbHandler = $dbHandler;
+ $this->httpClientService = $httpClientService;
+ $this->logger = $logger;
+ $this->jobList = $jobList;
+ $this->secureRandom = $secureRandom;
+ $this->config = $config;
+ }
+
+ /**
+ * add server to the list of trusted ownCloud servers
+ *
+ * @param $url
+ * @return int server id
+ */
+ public function addServer($url) {
+ $url = $this->updateProtocol($url);
+ $result = $this->dbHandler->addServer($url);
+ if ($result) {
+ $token = $this->secureRandom->generate(16);
+ $this->dbHandler->addToken($url, $token);
+ $this->jobList->add(
+ 'OCA\Federation\BackgroundJob\RequestSharedSecret',
+ [
+ 'url' => $url,
+ 'token' => $token
+ ]
+ );
+ }
+
+ return $result;
+ }
+
+ /**
+ * enable/disable to automatically add servers to the list of trusted servers
+ * once a federated share was created and accepted successfully
+ *
+ * @param bool $status
+ */
+ public function setAutoAddServers($status) {
+ $value = $status ? '1' : '0';
+ $this->config->setAppValue('federation', 'autoAddServers', $value);
+ }
+
+ /**
+ * return if we automatically add servers to the list of trusted servers
+ * once a federated share was created and accepted successfully
+ *
+ * @return bool
+ */
+ public function getAutoAddServers() {
+ $value = $this->config->getAppValue('federation', 'autoAddServers', '1');
+ return $value === '1';
+ }
+
+ /**
+ * get shared secret for the given server
+ *
+ * @param string $url
+ * @return string
+ */
+ public function getSharedSecret($url) {
+ return $this->dbHandler->getSharedSecret($url);
+ }
+
+ /**
+ * add shared secret for the given server
+ *
+ * @param string $url
+ * @param $sharedSecret
+ */
+ public function addSharedSecret($url, $sharedSecret) {
+ $this->dbHandler->addSharedSecret($url, $sharedSecret);
+ }
+
+ /**
+ * remove server from the list of trusted ownCloud servers
+ *
+ * @param int $id
+ */
+ public function removeServer($id) {
+ $this->dbHandler->removeServer($id);
+ }
+
+ /**
+ * get all trusted servers
+ *
+ * @return array
+ */
+ public function getServers() {
+ return $this->dbHandler->getAllServer();
+ }
+
+ /**
+ * check if given server is a trusted ownCloud server
+ *
+ * @param string $url
+ * @return bool
+ */
+ public function isTrustedServer($url) {
+ return $this->dbHandler->serverExists($url);
+ }
+
+ /**
+ * set server status
+ *
+ * @param string $url
+ * @param int $status
+ */
+ public function setServerStatus($url, $status) {
+ $this->dbHandler->setServerStatus($url, $status);
+ }
+
+ /**
+ * @param string $url
+ * @return int
+ */
+ public function getServerStatus($url) {
+ return $this->dbHandler->getServerStatus($url);
+ }
+
+ /**
+ * check if URL point to a ownCloud server
+ *
+ * @param string $url
+ * @return bool
+ */
+ public function isOwnCloudServer($url) {
+ $isValidOwnCloud = false;
+ $client = $this->httpClientService->newClient();
+ try {
+ $result = $client->get(
+ $url . '/status.php',
+ [
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ );
+ if ($result->getStatusCode() === Http::STATUS_OK) {
+ $isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody());
+ }
+ } catch (\Exception $e) {
+ $this->logger->error($e->getMessage(), ['app' => 'federation']);
+ return false;
+ }
+ return $isValidOwnCloud;
+ }
+
+ /**
+ * check if ownCloud version is >= 9.0
+ *
+ * @param $statusphp
+ * @return bool
+ */
+ protected function checkOwnCloudVersion($statusphp) {
+ $decoded = json_decode($statusphp, true);
+ if (!empty($decoded) && isset($decoded['version'])) {
+ return version_compare($decoded['version'], '9.0.0', '>=');
+ }
+ return false;
+ }
+
+ /**
+ * check if the URL contain a protocol, if not add https
+ *
+ * @param string $url
+ * @return string
+ */
+ protected function updateProtocol($url) {
+ if (
+ strpos($url, 'https://') === 0
+ || strpos($url, 'http://') === 0
+ ) {
+
+ return $url;
+
+ }
+
+ return 'https://' . $url;
+ }
+}
diff --git a/apps/federation/middleware/addservermiddleware.php b/apps/federation/middleware/addservermiddleware.php
new file mode 100644
index 00000000000..cd9ccff4403
--- /dev/null
+++ b/apps/federation/middleware/addservermiddleware.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Federation\Middleware ;
+
+use OC\HintException;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Middleware;
+use OCP\IL10N;
+use OCP\ILogger;
+
+class AddServerMiddleware extends Middleware {
+
+ /** @var string */
+ protected $appName;
+
+ /** @var IL10N */
+ protected $l;
+
+ /** @var ILogger */
+ protected $logger;
+
+ public function __construct($appName, IL10N $l, ILogger $logger) {
+ $this->appName = $appName;
+ $this->l = $l;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Log error message and return a response which can be displayed to the user
+ *
+ * @param \OCP\AppFramework\Controller $controller
+ * @param string $methodName
+ * @param \Exception $exception
+ * @return JSONResponse
+ */
+ public function afterException($controller, $methodName, \Exception $exception) {
+ $this->logger->error($exception->getMessage(), ['app' => $this->appName]);
+ if ($exception instanceof HintException) {
+ $message = $exception->getHint();
+ } else {
+ $message = $this->l->t('Unknown error');
+ }
+
+ return new JSONResponse(
+ ['message' => $message],
+ Http::STATUS_BAD_REQUEST
+ );
+
+ }
+
+}
diff --git a/apps/federation/settings/settings-admin.php b/apps/federation/settings/settings-admin.php
new file mode 100644
index 00000000000..8c6bfe6bbbb
--- /dev/null
+++ b/apps/federation/settings/settings-admin.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+\OC_Util::checkAdminUser();
+
+$template = new OCP\Template('federation', 'settings-admin');
+
+$dbHandler = new \OCA\Federation\DbHandler(
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getL10N('federation')
+);
+
+$trustedServers = new \OCA\Federation\TrustedServers(
+ $dbHandler,
+ \OC::$server->getHTTPClientService(),
+ \OC::$server->getLogger(),
+ \OC::$server->getJobList(),
+ \OC::$server->getSecureRandom(),
+ \OC::$server->getConfig()
+);
+
+$template->assign('trustedServers', $trustedServers->getServers());
+$template->assign('autoAddServers', $trustedServers->getAutoAddServers());
+
+return $template->fetchPage();
diff --git a/apps/federation/templates/settings-admin.php b/apps/federation/templates/settings-admin.php
new file mode 100644
index 00000000000..854bb744179
--- /dev/null
+++ b/apps/federation/templates/settings-admin.php
@@ -0,0 +1,40 @@
+<?php
+/** @var array $_ */
+use OCA\Federation\TrustedServers;
+
+/** @var OC_L10N $l */
+script('federation', 'settings-admin');
+style('federation', 'settings-admin')
+?>
+<div id="ocFederationSettings" class="section">
+ <h2><?php p($l->t('Federation')); ?></h2>
+ <em><?php p($l->t('ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing.')); ?></em>
+
+ <p>
+ <input id="autoAddServers" type="checkbox" class="checkbox" <?php if($_['autoAddServers']) p('checked'); ?> />
+ <label for="autoAddServers">Add server automatically once a federated share was created successfully</label>
+ </p>
+
+ <h3>Trusted ownCloud Servers</h3>
+ <p id="ocFederationAddServer">
+ <button id="ocFederationAddServerButton" class="">+ Add ownCloud server</button>
+ <input id="serverUrl" class="hidden" type="text" value="" placeholder="ownCloud Server" name="server_url"/>
+ <span class="msg"></span>
+ </p>
+ <ul id="listOfTrustedServers">
+ <?php foreach($_['trustedServers'] as $trustedServer) { ?>
+ <li id="<?php p($trustedServer['id']); ?>" class="icon-delete">
+ <?php if((int)$trustedServer['status'] === TrustedServers::STATUS_OK) { ?>
+ <span class="status success"></span>
+ <?php } elseif((int)$trustedServer['status'] === TrustedServers::STATUS_PENDING) { ?>
+ <span class="status indeterminate"></span>
+ <?php } else {?>
+ <span class="status error"></span>
+ <?php } ?>
+ <?php p($trustedServer['url']); ?>
+ </li>
+ <?php } ?>
+ </ul>
+
+</div>
+
diff --git a/apps/federation/tests/api/ocsauthapitest.php b/apps/federation/tests/api/ocsauthapitest.php
new file mode 100644
index 00000000000..9c751fff895
--- /dev/null
+++ b/apps/federation/tests/api/ocsauthapitest.php
@@ -0,0 +1,191 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\API;
+
+
+use OC\BackgroundJob\JobList;
+use OCA\Federation\API\OCSAuthAPI;
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\ILogger;
+use OCP\IRequest;
+use OCP\Security\ISecureRandom;
+use Test\TestCase;
+
+class OCSAuthAPITest extends TestCase {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IRequest */
+ private $request;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ISecureRandom */
+ private $secureRandom;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | JobList */
+ private $jobList;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
+ private $trustedServers;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
+ private $dbHandler;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
+ private $logger;
+
+ /** @var OCSAuthApi */
+ private $ocsAuthApi;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->request = $this->getMock('OCP\IRequest');
+ $this->secureRandom = $this->getMock('OCP\Security\ISecureRandom');
+ $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->disableOriginalConstructor()->getMock();
+ $this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
+ ->disableOriginalConstructor()->getMock();
+ $this->jobList = $this->getMockBuilder('OC\BackgroundJob\JobList')
+ ->disableOriginalConstructor()->getMock();
+ $this->logger = $this->getMockBuilder('OCP\ILogger')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->ocsAuthApi = new OCSAuthAPI(
+ $this->request,
+ $this->secureRandom,
+ $this->jobList,
+ $this->trustedServers,
+ $this->dbHandler,
+ $this->logger
+ );
+
+ }
+
+ /**
+ * @dataProvider dataTestRequestSharedSecret
+ *
+ * @param string $token
+ * @param string $localToken
+ * @param bool $isTrustedServer
+ * @param int $expected
+ */
+ public function testRequestSharedSecret($token, $localToken, $isTrustedServer, $expected) {
+
+ $url = 'url';
+
+ $this->request->expects($this->at(0))->method('getParam')->with('url')->willReturn($url);
+ $this->request->expects($this->at(1))->method('getParam')->with('token')->willReturn($token);
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isTrustedServer')->with($url)->willReturn($isTrustedServer);
+ $this->dbHandler->expects($this->any())
+ ->method('getToken')->with($url)->willReturn($localToken);
+
+ if ($expected === Http::STATUS_OK) {
+ $this->jobList->expects($this->once())->method('add')
+ ->with('OCA\Federation\BackgroundJob\GetSharedSecret', ['url' => $url, 'token' => $token]);
+ } else {
+ $this->jobList->expects($this->never())->method('add');
+ }
+
+ $result = $this->ocsAuthApi->requestSharedSecret();
+ $this->assertSame($expected, $result->getStatusCode());
+ }
+
+ public function dataTestRequestSharedSecret() {
+ return [
+ ['token2', 'token1', true, Http::STATUS_OK],
+ ['token1', 'token2', false, Http::STATUS_FORBIDDEN],
+ ['token1', 'token2', true, Http::STATUS_FORBIDDEN],
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestGetSharedSecret
+ *
+ * @param bool $isTrustedServer
+ * @param bool $isValidToken
+ * @param int $expected
+ */
+ public function testGetSharedSecret($isTrustedServer, $isValidToken, $expected) {
+
+ $url = 'url';
+ $token = 'token';
+
+ $this->request->expects($this->at(0))->method('getParam')->with('url')->willReturn($url);
+ $this->request->expects($this->at(1))->method('getParam')->with('token')->willReturn($token);
+
+ /** @var OCSAuthAPI | \PHPUnit_Framework_MockObject_MockObject $ocsAuthApi */
+ $ocsAuthApi = $this->getMockBuilder('OCA\Federation\API\OCSAuthAPI')
+ ->setConstructorArgs(
+ [
+ $this->request,
+ $this->secureRandom,
+ $this->jobList,
+ $this->trustedServers,
+ $this->dbHandler,
+ $this->logger
+ ]
+ )->setMethods(['isValidToken'])->getMock();
+
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isTrustedServer')->with($url)->willReturn($isTrustedServer);
+ $ocsAuthApi->expects($this->any())
+ ->method('isValidToken')->with($url, $token)->willReturn($isValidToken);
+
+ if($expected === Http::STATUS_OK) {
+ $this->secureRandom->expects($this->once())->method('generate')->with(32)
+ ->willReturn('secret');
+ $this->trustedServers->expects($this->once())
+ ->method('addSharedSecret')->willReturn($url, 'secret');
+ $this->dbHandler->expects($this->once())
+ ->method('addToken')->with($url, '');
+ } else {
+ $this->secureRandom->expects($this->never())->method('getMediumStrengthGenerator');
+ $this->secureRandom->expects($this->never())->method('generate');
+ $this->trustedServers->expects($this->never())->method('addSharedSecret');
+ $this->dbHandler->expects($this->never())->method('addToken');
+ }
+
+ $result = $ocsAuthApi->getSharedSecret();
+
+ $this->assertSame($expected, $result->getStatusCode());
+
+ if ($expected === Http::STATUS_OK) {
+ $data = $result->getData();
+ $this->assertSame('secret', $data['sharedSecret']);
+ }
+ }
+
+ public function dataTestGetSharedSecret() {
+ return [
+ [true, true, Http::STATUS_OK],
+ [false, true, Http::STATUS_FORBIDDEN],
+ [true, false, Http::STATUS_FORBIDDEN],
+ [false, false, Http::STATUS_FORBIDDEN],
+ ];
+ }
+
+}
diff --git a/apps/federation/tests/backgroundjob/getsharedsecrettest.php b/apps/federation/tests/backgroundjob/getsharedsecrettest.php
new file mode 100644
index 00000000000..08c8677415c
--- /dev/null
+++ b/apps/federation/tests/backgroundjob/getsharedsecrettest.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\BackgroundJob;
+
+
+use OCA\Federation\BackgroundJob\GetSharedSecret;
+use OCA\Files_Sharing\Tests\TestCase;
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClient;
+use OCP\Http\Client\IResponse;
+use OCP\ILogger;
+use OCP\IURLGenerator;
+
+/**
+ * Class GetSharedSecretTest
+ *
+ * @group DB
+ *
+ * @package OCA\Federation\Tests\BackgroundJob
+ */
+class GetSharedSecretTest extends TestCase {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IClient */
+ private $httpClient;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
+ private $jobList;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IURLGenerator */
+ private $urlGenerator;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
+ private $trustedServers;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
+ private $dbHandler;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
+ private $logger;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */
+ private $response;
+
+ /** @var GetSharedSecret */
+ private $getSharedSecret;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->httpClient = $this->getMock('OCP\Http\Client\IClient');
+ $this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
+ $this->urlGenerator = $this->getMock('OCP\IURLGenerator');
+ $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->disableOriginalConstructor()->getMock();
+ $this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
+ ->disableOriginalConstructor()->getMock();
+ $this->logger = $this->getMock('OCP\ILogger');
+ $this->response = $this->getMock('OCP\Http\Client\IResponse');
+
+ $this->getSharedSecret = new GetSharedSecret(
+ $this->httpClient,
+ $this->urlGenerator,
+ $this->jobList,
+ $this->trustedServers,
+ $this->logger,
+ $this->dbHandler
+ );
+ }
+
+ /**
+ * @dataProvider dataTestExecute
+ *
+ * @param bool $isTrustedServer
+ */
+ public function testExecute($isTrustedServer) {
+ /** @var GetSharedSecret |\PHPUnit_Framework_MockObject_MockObject $getSharedSecret */
+ $getSharedSecret = $this->getMockBuilder('OCA\Federation\BackgroundJob\GetSharedSecret')
+ ->setConstructorArgs(
+ [
+ $this->httpClient,
+ $this->urlGenerator,
+ $this->jobList,
+ $this->trustedServers,
+ $this->logger,
+ $this->dbHandler
+ ]
+ )->setMethods(['parentExecute'])->getMock();
+ $this->invokePrivate($getSharedSecret, 'argument', [['url' => 'url']]);
+
+ $this->jobList->expects($this->once())->method('remove');
+ $this->trustedServers->expects($this->once())->method('isTrustedServer')
+ ->with('url')->willReturn($isTrustedServer);
+ if ($isTrustedServer) {
+ $getSharedSecret->expects($this->once())->method('parentExecute');
+ } else {
+ $getSharedSecret->expects($this->never())->method('parentExecute');
+ }
+
+ $getSharedSecret->execute($this->jobList);
+
+ }
+
+ public function dataTestExecute() {
+ return [
+ [true],
+ [false]
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestRun
+ *
+ * @param int $statusCode
+ */
+ public function testRun($statusCode) {
+
+ $target = 'targetURL';
+ $source = 'sourceURL';
+ $token = 'token';
+
+ $argument = ['url' => $target, 'token' => $token];
+
+ $this->urlGenerator->expects($this->once())->method('getAbsoluteURL')->with('/')
+ ->willReturn($source);
+ $this->httpClient->expects($this->once())->method('get')
+ ->with(
+ $target . '/ocs/v2.php/apps/federation/api/v1/shared-secret?format=json',
+ [
+ 'query' =>
+ [
+ 'url' => $source,
+ 'token' => $token
+ ],
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ )->willReturn($this->response);
+
+ $this->response->expects($this->once())->method('getStatusCode')
+ ->willReturn($statusCode);
+
+ if (
+ $statusCode !== Http::STATUS_OK
+ && $statusCode !== Http::STATUS_FORBIDDEN
+ ) {
+ $this->jobList->expects($this->once())->method('add')
+ ->with('OCA\Federation\BackgroundJob\GetSharedSecret', $argument);
+ $this->dbHandler->expects($this->never())->method('addToken');
+ } else {
+ $this->dbHandler->expects($this->once())->method('addToken')->with($target, '');
+ $this->jobList->expects($this->never())->method('add');
+ }
+
+ if ($statusCode === Http::STATUS_OK) {
+ $this->response->expects($this->once())->method('getBody')
+ ->willReturn('{"ocs":{"data":{"sharedSecret":"secret"}}}');
+ $this->trustedServers->expects($this->once())->method('addSharedSecret')
+ ->with($target, 'secret');
+ } else {
+ $this->trustedServers->expects($this->never())->method('addSharedSecret');
+ }
+
+ $this->invokePrivate($this->getSharedSecret, 'run', [$argument]);
+ }
+
+ public function dataTestRun() {
+ return [
+ [Http::STATUS_OK],
+ [Http::STATUS_FORBIDDEN],
+ [Http::STATUS_CONFLICT],
+ ];
+ }
+
+}
diff --git a/apps/federation/tests/backgroundjob/requestsharedsecrettest.php b/apps/federation/tests/backgroundjob/requestsharedsecrettest.php
new file mode 100644
index 00000000000..45f79e05249
--- /dev/null
+++ b/apps/federation/tests/backgroundjob/requestsharedsecrettest.php
@@ -0,0 +1,169 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\BackgroundJob;
+
+
+use OCA\Federation\BackgroundJob\RequestSharedSecret;
+use OCP\AppFramework\Http;
+use Test\TestCase;
+
+class RequestSharedSecretTest extends TestCase {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IClient */
+ private $httpClient;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
+ private $jobList;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IURLGenerator */
+ private $urlGenerator;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
+ private $dbHandler;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
+ private $trustedServers;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */
+ private $response;
+
+ /** @var RequestSharedSecret */
+ private $requestSharedSecret;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->httpClient = $this->getMock('OCP\Http\Client\IClient');
+ $this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
+ $this->urlGenerator = $this->getMock('OCP\IURLGenerator');
+ $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->disableOriginalConstructor()->getMock();
+ $this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
+ ->disableOriginalConstructor()->getMock();
+ $this->response = $this->getMock('OCP\Http\Client\IResponse');
+
+ $this->requestSharedSecret = new RequestSharedSecret(
+ $this->httpClient,
+ $this->urlGenerator,
+ $this->jobList,
+ $this->trustedServers,
+ $this->dbHandler
+ );
+ }
+
+ /**
+ * @dataProvider dataTestExecute
+ *
+ * @param bool $isTrustedServer
+ */
+ public function testExecute($isTrustedServer) {
+ /** @var RequestSharedSecret |\PHPUnit_Framework_MockObject_MockObject $requestSharedSecret */
+ $requestSharedSecret = $this->getMockBuilder('OCA\Federation\BackgroundJob\RequestSharedSecret')
+ ->setConstructorArgs(
+ [
+ $this->httpClient,
+ $this->urlGenerator,
+ $this->jobList,
+ $this->trustedServers,
+ $this->dbHandler
+ ]
+ )->setMethods(['parentExecute'])->getMock();
+ $this->invokePrivate($requestSharedSecret, 'argument', [['url' => 'url']]);
+
+ $this->jobList->expects($this->once())->method('remove');
+ $this->trustedServers->expects($this->once())->method('isTrustedServer')
+ ->with('url')->willReturn($isTrustedServer);
+ if ($isTrustedServer) {
+ $requestSharedSecret->expects($this->once())->method('parentExecute');
+ } else {
+ $requestSharedSecret->expects($this->never())->method('parentExecute');
+ }
+
+ $requestSharedSecret->execute($this->jobList);
+
+ }
+
+ public function dataTestExecute() {
+ return [
+ [true],
+ [false]
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestRun
+ *
+ * @param int $statusCode
+ */
+ public function testRun($statusCode) {
+
+ $target = 'targetURL';
+ $source = 'sourceURL';
+ $token = 'token';
+
+ $argument = ['url' => $target, 'token' => $token];
+
+ $this->urlGenerator->expects($this->once())->method('getAbsoluteURL')->with('/')
+ ->willReturn($source);
+ $this->httpClient->expects($this->once())->method('post')
+ ->with(
+ $target . '/ocs/v2.php/apps/federation/api/v1/request-shared-secret?format=json',
+ [
+ 'body' =>
+ [
+ 'url' => $source,
+ 'token' => $token
+ ],
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ )->willReturn($this->response);
+
+ $this->response->expects($this->once())->method('getStatusCode')
+ ->willReturn($statusCode);
+
+ if (
+ $statusCode !== Http::STATUS_OK
+ && $statusCode !== Http::STATUS_FORBIDDEN
+ ) {
+ $this->jobList->expects($this->once())->method('add')
+ ->with('OCA\Federation\BackgroundJob\RequestSharedSecret', $argument);
+ $this->dbHandler->expects($this->never())->method('addToken');
+ }
+
+ if ($statusCode === Http::STATUS_FORBIDDEN) {
+ $this->jobList->expects($this->never())->method('add');
+ $this->dbHandler->expects($this->once())->method('addToken')->with($target, '');
+ }
+
+ $this->invokePrivate($this->requestSharedSecret, 'run', [$argument]);
+ }
+
+ public function dataTestRun() {
+ return [
+ [Http::STATUS_OK],
+ [Http::STATUS_FORBIDDEN],
+ [Http::STATUS_CONFLICT],
+ ];
+ }
+}
diff --git a/apps/federation/tests/controller/settingscontrollertest.php b/apps/federation/tests/controller/settingscontrollertest.php
new file mode 100644
index 00000000000..65f7d5f91d3
--- /dev/null
+++ b/apps/federation/tests/controller/settingscontrollertest.php
@@ -0,0 +1,166 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\Controller;
+
+
+use OCA\Federation\Controller\SettingsController;
+use OCP\AppFramework\Http\DataResponse;
+use Test\TestCase;
+
+class SettingsControllerTest extends TestCase {
+
+ /** @var SettingsController */
+ private $controller;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IRequest */
+ private $request;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IL10N */
+ private $l10n;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCA\Federation\TrustedServers */
+ private $trustedServers;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->request = $this->getMock('OCP\IRequest');
+ $this->l10n = $this->getMock('OCP\IL10N');
+ $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->controller = new SettingsController(
+ 'SettingsControllerTest',
+ $this->request,
+ $this->l10n,
+ $this->trustedServers
+ );
+ }
+
+ public function testAddServer() {
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isTrustedServer')
+ ->with('url')
+ ->willReturn(false);
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isOwnCloudServer')
+ ->with('url')
+ ->willReturn(true);
+
+ $result = $this->controller->addServer('url');
+ $this->assertTrue($result instanceof DataResponse);
+
+ $data = $result->getData();
+ $this->assertSame(200, $result->getStatus());
+ $this->assertSame('url', $data['url']);
+ $this->assertArrayHasKey('id', $data);
+ }
+
+ /**
+ * @dataProvider checkServerFails
+ * @expectedException \OC\HintException
+ *
+ * @param bool $isTrustedServer
+ * @param bool $isOwnCloud
+ */
+ public function testAddServerFail($isTrustedServer, $isOwnCloud) {
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isTrustedServer')
+ ->with('url')
+ ->willReturn($isTrustedServer);
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isOwnCloudServer')
+ ->with('url')
+ ->willReturn($isOwnCloud);
+
+ $this->controller->addServer('url');
+ }
+
+ public function testRemoveServer() {
+ $this->trustedServers->expects($this->once())->method('removeServer')
+ ->with('url');
+ $result = $this->controller->removeServer('url');
+ $this->assertTrue($result instanceof DataResponse);
+ $this->assertSame(200, $result->getStatus());
+ }
+
+ public function testCheckServer() {
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isTrustedServer')
+ ->with('url')
+ ->willReturn(false);
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isOwnCloudServer')
+ ->with('url')
+ ->willReturn(true);
+
+ $this->assertTrue(
+ $this->invokePrivate($this->controller, 'checkServer', ['url'])
+ );
+
+ }
+
+ /**
+ * @dataProvider checkServerFails
+ * @expectedException \OC\HintException
+ *
+ * @param bool $isTrustedServer
+ * @param bool $isOwnCloud
+ */
+ public function testCheckServerFail($isTrustedServer, $isOwnCloud) {
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isTrustedServer')
+ ->with('url')
+ ->willReturn($isTrustedServer);
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isOwnCloudServer')
+ ->with('url')
+ ->willReturn($isOwnCloud);
+
+ $this->assertTrue(
+ $this->invokePrivate($this->controller, 'checkServer', ['url'])
+ );
+
+ }
+
+ /**
+ * data to simulate checkServer fails
+ *
+ * @return array
+ */
+ public function checkServerFails() {
+ return [
+ [true, true],
+ [false, false]
+ ];
+ }
+
+}
diff --git a/apps/federation/tests/dav/fedauthtest.php b/apps/federation/tests/dav/fedauthtest.php
new file mode 100644
index 00000000000..845cfc622d2
--- /dev/null
+++ b/apps/federation/tests/dav/fedauthtest.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\DAV;
+
+use OCA\Federation\DAV\FedAuth;
+use OCA\Federation\DbHandler;
+use Test\TestCase;
+
+class FedAuthTest extends TestCase {
+
+ /**
+ * @dataProvider providesUser
+ *
+ * @param array $expected
+ * @param string $user
+ * @param string $password
+ */
+ public function testFedAuth($expected, $user, $password) {
+ /** @var DbHandler | \PHPUnit_Framework_MockObject_MockObject $db */
+ $db = $this->getMockBuilder('OCA\Federation\DbHandler')->disableOriginalConstructor()->getMock();
+ $db->method('auth')->willReturn(true);
+ $auth = new FedAuth($db);
+ $result = $this->invokePrivate($auth, 'validateUserPass', [$user, $password]);
+ $this->assertEquals($expected, $result);
+ }
+
+ public function providesUser() {
+ return [
+ [true, 'system', '123456']
+ ];
+ }
+}
diff --git a/apps/federation/tests/lib/dbhandlertest.php b/apps/federation/tests/lib/dbhandlertest.php
new file mode 100644
index 00000000000..6fe5d9ea8ef
--- /dev/null
+++ b/apps/federation/tests/lib/dbhandlertest.php
@@ -0,0 +1,283 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\lib;
+
+
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\IDBConnection;
+use OCP\IL10N;
+use Test\TestCase;
+
+/**
+ * @group DB
+ */
+class DbHandlerTest extends TestCase {
+
+ /** @var DbHandler */
+ private $dbHandler;
+
+ /** @var IL10N | \PHPUnit_Framework_MockObject_MockObject */
+ private $il10n;
+
+ /** @var IDBConnection */
+ private $connection;
+
+ /** @var string */
+ private $dbTable = 'trusted_servers';
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->connection = \OC::$server->getDatabaseConnection();
+ $this->il10n = $this->getMock('OCP\IL10N');
+
+ $this->dbHandler = new DbHandler(
+ $this->connection,
+ $this->il10n
+ );
+
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertEmpty($result, 'we need to start with a empty trusted_servers table');
+ }
+
+ public function tearDown() {
+ parent::tearDown();
+ $query = $this->connection->getQueryBuilder()->delete($this->dbTable);
+ $query->execute();
+ }
+
+ /**
+ * @dataProvider dataTestAddServer
+ *
+ * @param string $url passed to the method
+ * @param string $expectedUrl the url we expect to be written to the db
+ * @param string $expectedHash the hash value we expect to be written to the db
+ */
+ public function testAddServer($url, $expectedUrl, $expectedHash) {
+ $id = $this->dbHandler->addServer($url);
+
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame($expectedUrl, $result[0]['url']);
+ $this->assertSame($id, (int)$result[0]['id']);
+ $this->assertSame($expectedHash, $result[0]['url_hash']);
+ $this->assertSame(TrustedServers::STATUS_PENDING, (int)$result[0]['status']);
+ }
+
+ public function dataTestAddServer() {
+ return [
+ ['http://owncloud.org', 'http://owncloud.org', md5('owncloud.org')],
+ ['https://owncloud.org', 'https://owncloud.org', md5('owncloud.org')],
+ ['http://owncloud.org/', 'http://owncloud.org', md5('owncloud.org')],
+ ];
+ }
+
+ public function testRemove() {
+ $id1 = $this->dbHandler->addServer('server1');
+ $id2 = $this->dbHandler->addServer('server2');
+
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(2, count($result));
+ $this->assertSame('server1', $result[0]['url']);
+ $this->assertSame('server2', $result[1]['url']);
+ $this->assertSame($id1, (int)$result[0]['id']);
+ $this->assertSame($id2, (int)$result[1]['id']);
+
+ $this->dbHandler->removeServer($id2);
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame('server1', $result[0]['url']);
+ $this->assertSame($id1, (int)$result[0]['id']);
+ }
+
+ public function testGetAll() {
+ $id1 = $this->dbHandler->addServer('server1');
+ $id2 = $this->dbHandler->addServer('server2');
+
+ $result = $this->dbHandler->getAllServer();
+ $this->assertSame(2, count($result));
+ $this->assertSame('server1', $result[0]['url']);
+ $this->assertSame('server2', $result[1]['url']);
+ $this->assertSame($id1, (int)$result[0]['id']);
+ $this->assertSame($id2, (int)$result[1]['id']);
+ }
+
+ /**
+ * @dataProvider dataTestServerExists
+ *
+ * @param string $serverInTable
+ * @param string $checkForServer
+ * @param bool $expected
+ */
+ public function testServerExists($serverInTable, $checkForServer, $expected) {
+ $this->dbHandler->addServer($serverInTable);
+ $this->assertSame($expected,
+ $this->dbHandler->serverExists($checkForServer)
+ );
+ }
+
+ public function dataTestServerExists() {
+ return [
+ ['server1', 'server1', true],
+ ['server1', 'http://server1', true],
+ ['server1', 'server2', false]
+ ];
+ }
+
+ public function testAddToken() {
+ $this->dbHandler->addServer('server1');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame(null, $result[0]['token']);
+ $this->dbHandler->addToken('http://server1', 'token');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame('token', $result[0]['token']);
+ }
+
+ public function testGetToken() {
+ $this->dbHandler->addServer('server1');
+ $this->dbHandler->addToken('http://server1', 'token');
+ $this->assertSame('token',
+ $this->dbHandler->getToken('https://server1')
+ );
+ }
+
+ public function testAddSharedSecret() {
+ $this->dbHandler->addServer('server1');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame(null, $result[0]['shared_secret']);
+ $this->dbHandler->addSharedSecret('http://server1', 'secret');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame('secret', $result[0]['shared_secret']);
+ }
+
+ public function testGetSharedSecret() {
+ $this->dbHandler->addServer('server1');
+ $this->dbHandler->addSharedSecret('http://server1', 'secret');
+ $this->assertSame('secret',
+ $this->dbHandler->getSharedSecret('https://server1')
+ );
+ }
+
+ public function testSetServerStatus() {
+ $this->dbHandler->addServer('server1');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame(TrustedServers::STATUS_PENDING, (int)$result[0]['status']);
+ $this->dbHandler->setServerStatus('http://server1', TrustedServers::STATUS_OK);
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame(TrustedServers::STATUS_OK, (int)$result[0]['status']);
+ }
+
+ public function testGetServerStatus() {
+ $this->dbHandler->addServer('server1');
+ $this->dbHandler->setServerStatus('http://server1', TrustedServers::STATUS_OK);
+ $this->assertSame(TrustedServers::STATUS_OK,
+ $this->dbHandler->getServerStatus('https://server1')
+ );
+
+ // test sync token
+ $this->dbHandler->setServerStatus('http://server1', TrustedServers::STATUS_OK, 'token1234567890');
+ $servers = $this->dbHandler->getAllServer();
+ $this->assertSame('token1234567890', $servers[0]['sync_token']);
+ }
+
+ /**
+ * hash should always be computed with the normalized URL
+ *
+ * @dataProvider dataTestHash
+ *
+ * @param string $url
+ * @param string $expected
+ */
+ public function testHash($url, $expected) {
+ $this->assertSame($expected,
+ $this->invokePrivate($this->dbHandler, 'hash', [$url])
+ );
+ }
+
+ public function dataTestHash() {
+ return [
+ ['server1', md5('server1')],
+ ['http://server1', md5('server1')],
+ ['https://server1', md5('server1')],
+ ['http://server1/', md5('server1')],
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestNormalizeUrl
+ *
+ * @param string $url
+ * @param string $expected
+ */
+ public function testNormalizeUrl($url, $expected) {
+ $this->assertSame($expected,
+ $this->invokePrivate($this->dbHandler, 'normalizeUrl', [$url])
+ );
+ }
+
+ public function dataTestNormalizeUrl() {
+ return [
+ ['owncloud.org', 'owncloud.org'],
+ ['http://owncloud.org', 'owncloud.org'],
+ ['https://owncloud.org', 'owncloud.org'],
+ ['https://owncloud.org//mycloud', 'owncloud.org/mycloud'],
+ ['https://owncloud.org/mycloud/', 'owncloud.org/mycloud'],
+ ];
+ }
+
+ /**
+ * @dataProvider providesAuth
+ */
+ public function testAuth($expectedResult, $user, $password) {
+ if ($expectedResult) {
+ $this->dbHandler->addServer('url1');
+ $this->dbHandler->addSharedSecret('url1', $password);
+ }
+ $result = $this->dbHandler->auth($user, $password);
+ $this->assertEquals($expectedResult, $result);
+ }
+
+ public function providesAuth() {
+ return [
+ [false, 'foo', ''],
+ [true, 'system', '123456789'],
+ ];
+ }
+}
diff --git a/apps/federation/tests/lib/hookstest.php b/apps/federation/tests/lib/hookstest.php
new file mode 100644
index 00000000000..71569226dd2
--- /dev/null
+++ b/apps/federation/tests/lib/hookstest.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\lib;
+
+
+use OCA\Federation\Hooks;
+use OCA\Federation\TrustedServers;
+use Test\TestCase;
+
+class HooksTest extends TestCase {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
+ private $trustedServers;
+
+ /** @var Hooks */
+ private $hooks;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->hooks = new Hooks($this->trustedServers);
+ }
+
+ /**
+ * @dataProvider dataTestAddServerHook
+ *
+ * @param bool $autoAddEnabled is auto-add enabled
+ * @param bool $isTrustedServer is the server already in the list of trusted servers
+ * @param bool $addServer should the server be added
+ */
+ public function testAddServerHook($autoAddEnabled, $isTrustedServer, $addServer) {
+ $this->trustedServers->expects($this->any())->method('getAutoAddServers')
+ ->willReturn($autoAddEnabled);
+ $this->trustedServers->expects($this->any())->method('isTrustedServer')
+ ->with('url')->willReturn($isTrustedServer);
+
+ if ($addServer) {
+ $this->trustedServers->expects($this->once())->method('addServer')
+ ->with('url');
+ } else {
+ $this->trustedServers->expects($this->never())->method('addServer');
+ }
+
+ $this->hooks->addServerHook(['server' => 'url']);
+
+ }
+
+ public function dataTestAddServerHook() {
+ return [
+ [true, true, false],
+ [false, true, false],
+ [true, false, true],
+ [false, false, false],
+ ];
+ }
+}
diff --git a/apps/federation/tests/lib/syncfederationaddressbookstest.php b/apps/federation/tests/lib/syncfederationaddressbookstest.php
new file mode 100644
index 00000000000..770896535fa
--- /dev/null
+++ b/apps/federation/tests/lib/syncfederationaddressbookstest.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace OCA\Federation\Tests\lib;
+
+use OCA\Federation\DbHandler;
+use OCA\Federation\SyncFederationAddressBooks;
+
+class SyncFederationAddressbooksTest extends \Test\TestCase {
+
+ /** @var array */
+ private $callBacks = [];
+
+ function testSync() {
+ /** @var DbHandler | \PHPUnit_Framework_MockObject_MockObject $dbHandler */
+ $dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')->
+ disableOriginalConstructor()->
+ getMock();
+ $dbHandler->method('getAllServer')->
+ willReturn([
+ [
+ 'url' => 'https://cloud.drop.box',
+ 'shared_secret' => 'iloveowncloud',
+ 'sync_token' => '0'
+ ]
+ ]);
+ $dbHandler->expects($this->once())->method('setServerStatus')->
+ with('https://cloud.drop.box', 1, '1');
+ $syncService = $this->getMockBuilder('OCA\DAV\CardDAV\SyncService')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $syncService->expects($this->once())->method('syncRemoteAddressBook')
+ ->willReturn(1);
+
+ $s = new SyncFederationAddressBooks($dbHandler, $syncService);
+ $s->syncThemAll(function($url, $ex) {
+ $this->callBacks[] = [$url, $ex];
+ });
+ $this->assertEquals(1, count($this->callBacks));
+ }
+
+ function testException() {
+ /** @var DbHandler | \PHPUnit_Framework_MockObject_MockObject $dbHandler */
+ $dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')->
+ disableOriginalConstructor()->
+ getMock();
+ $dbHandler->method('getAllServer')->
+ willReturn([
+ [
+ 'url' => 'https://cloud.drop.box',
+ 'shared_secret' => 'iloveowncloud',
+ 'sync_token' => '0'
+ ]
+ ]);
+ $syncService = $this->getMockBuilder('OCA\DAV\CardDAV\SyncService')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $syncService->expects($this->once())->method('syncRemoteAddressBook')
+ ->willThrowException(new \Exception('something did not work out'));
+
+ $s = new SyncFederationAddressBooks($dbHandler, $syncService);
+ $s->syncThemAll(function($url, $ex) {
+ $this->callBacks[] = [$url, $ex];
+ });
+ $this->assertEquals(2, count($this->callBacks));
+ }
+}
diff --git a/apps/federation/tests/lib/trustedserverstest.php b/apps/federation/tests/lib/trustedserverstest.php
new file mode 100644
index 00000000000..e57391ed198
--- /dev/null
+++ b/apps/federation/tests/lib/trustedserverstest.php
@@ -0,0 +1,342 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\lib;
+
+
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClient;
+use OCP\Http\Client\IClientService;
+use OCP\Http\Client\IResponse;
+use OCP\IConfig;
+use OCP\ILogger;
+use OCP\Security\ISecureRandom;
+use Test\TestCase;
+
+class TrustedServersTest extends TestCase {
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
+ private $dbHandler;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IClientService */
+ private $httpClientService;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IClient */
+ private $httpClient;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */
+ private $response;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
+ private $logger;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
+ private $jobList;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ISecureRandom */
+ private $secureRandom;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IConfig */
+ private $config;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->dbHandler = $this->getMockBuilder('\OCA\Federation\DbHandler')
+ ->disableOriginalConstructor()->getMock();
+ $this->httpClientService = $this->getMock('OCP\Http\Client\IClientService');
+ $this->httpClient = $this->getMock('OCP\Http\Client\IClient');
+ $this->response = $this->getMock('OCP\Http\Client\IResponse');
+ $this->logger = $this->getMock('OCP\ILogger');
+ $this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
+ $this->secureRandom = $this->getMock('OCP\Security\ISecureRandom');
+ $this->config = $this->getMock('OCP\IConfig');
+
+ $this->trustedServers = new TrustedServers(
+ $this->dbHandler,
+ $this->httpClientService,
+ $this->logger,
+ $this->jobList,
+ $this->secureRandom,
+ $this->config
+ );
+
+ }
+
+ /**
+ * @dataProvider dataTrueFalse
+ *
+ * @param bool $success
+ */
+ public function testAddServer($success) {
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */
+ $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->setConstructorArgs(
+ [
+ $this->dbHandler,
+ $this->httpClientService,
+ $this->logger,
+ $this->jobList,
+ $this->secureRandom,
+ $this->config
+ ]
+ )
+ ->setMethods(['normalizeUrl', 'updateProtocol'])
+ ->getMock();
+ $trustedServers->expects($this->once())->method('updateProtocol')
+ ->with('url')->willReturn('https://url');
+ $this->dbHandler->expects($this->once())->method('addServer')->with('https://url')
+ ->willReturn($success);
+
+ if ($success) {
+ $this->secureRandom->expects($this->once())->method('generate')
+ ->willReturn('token');
+ $this->dbHandler->expects($this->once())->method('addToken')->with('https://url', 'token');
+ $this->jobList->expects($this->once())->method('add')
+ ->with('OCA\Federation\BackgroundJob\RequestSharedSecret',
+ ['url' => 'https://url', 'token' => 'token']);
+ } else {
+ $this->jobList->expects($this->never())->method('add');
+ }
+
+ $this->assertSame($success,
+ $trustedServers->addServer('url')
+ );
+ }
+
+ public function dataTrueFalse() {
+ return [
+ [true],
+ [false]
+ ];
+ }
+
+ /**
+ * @dataProvider dataTrueFalse
+ *
+ * @param bool $status
+ */
+ public function testSetAutoAddServers($status) {
+ if ($status) {
+ $this->config->expects($this->once())->method('setAppValue')
+ ->with('federation', 'autoAddServers', '1');
+ } else {
+ $this->config->expects($this->once())->method('setAppValue')
+ ->with('federation', 'autoAddServers', '0');
+ }
+
+ $this->trustedServers->setAutoAddServers($status);
+ }
+
+ /**
+ * @dataProvider dataTestGetAutoAddServers
+ *
+ * @param string $status
+ * @param bool $expected
+ */
+ public function testGetAutoAddServers($status, $expected) {
+ $this->config->expects($this->once())->method('getAppValue')
+ ->with('federation', 'autoAddServers', '1')->willReturn($status);
+
+ $this->assertSame($expected,
+ $this->trustedServers->getAutoAddServers($status)
+ );
+ }
+
+ public function dataTestGetAutoAddServers() {
+ return [
+ ['1', true],
+ ['0', false]
+ ];
+ }
+
+ public function testAddSharedSecret() {
+ $this->dbHandler->expects($this->once())->method('addSharedSecret')
+ ->with('url', 'secret');
+ $this->trustedServers->addSharedSecret('url', 'secret');
+ }
+
+ public function testGetSharedSecret() {
+ $this->dbHandler->expects($this->once())->method('getSharedSecret')
+ ->with('url')->willReturn(true);
+ $this->assertTrue(
+ $this->trustedServers->getSharedSecret('url')
+ );
+ }
+
+ public function testRemoveServer() {
+ $id = 42;
+ $this->dbHandler->expects($this->once())->method('removeServer')->with($id);
+ $this->trustedServers->removeServer($id);
+ }
+
+ public function testGetServers() {
+ $this->dbHandler->expects($this->once())->method('getAllServer')->willReturn(true);
+
+ $this->assertTrue(
+ $this->trustedServers->getServers()
+ );
+ }
+
+
+ public function testIsTrustedServer() {
+ $this->dbHandler->expects($this->once())->method('serverExists')->with('url')
+ ->willReturn(true);
+
+ $this->assertTrue(
+ $this->trustedServers->isTrustedServer('url')
+ );
+ }
+
+ public function testSetServerStatus() {
+ $this->dbHandler->expects($this->once())->method('setServerStatus')
+ ->with('url', 'status');
+ $this->trustedServers->setServerStatus('url', 'status');
+ }
+
+ public function testGetServerStatus() {
+ $this->dbHandler->expects($this->once())->method('getServerStatus')
+ ->with('url')->willReturn(true);
+ $this->assertTrue(
+ $this->trustedServers->getServerStatus('url')
+ );
+ }
+
+ /**
+ * @dataProvider dataTestIsOwnCloudServer
+ *
+ * @param int $statusCode
+ * @param bool $isValidOwnCloudVersion
+ * @param bool $expected
+ */
+ public function testIsOwnCloudServer($statusCode, $isValidOwnCloudVersion, $expected) {
+
+ $server = 'server1';
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */
+ $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->setConstructorArgs(
+ [
+ $this->dbHandler,
+ $this->httpClientService,
+ $this->logger,
+ $this->jobList,
+ $this->secureRandom,
+ $this->config
+ ]
+ )
+ ->setMethods(['checkOwnCloudVersion'])
+ ->getMock();
+
+ $this->httpClientService->expects($this->once())->method('newClient')
+ ->willReturn($this->httpClient);
+
+ $this->httpClient->expects($this->once())->method('get')->with($server . '/status.php')
+ ->willReturn($this->response);
+
+ $this->response->expects($this->once())->method('getStatusCode')
+ ->willReturn($statusCode);
+
+ if ($statusCode === 200) {
+ $trustedServers->expects($this->once())->method('checkOwnCloudVersion')
+ ->willReturn($isValidOwnCloudVersion);
+ } else {
+ $trustedServers->expects($this->never())->method('checkOwnCloudVersion');
+ }
+
+ $this->assertSame($expected,
+ $trustedServers->isOwnCloudServer($server)
+ );
+
+ }
+
+ public function dataTestIsOwnCloudServer() {
+ return [
+ [200, true, true],
+ [200, false, false],
+ [404, true, false],
+ ];
+ }
+
+ public function testIsOwnCloudServerFail() {
+ $server = 'server1';
+
+ $this->httpClientService->expects($this->once())->method('newClient')
+ ->willReturn($this->httpClient);
+
+ $this->logger->expects($this->once())->method('error')
+ ->with('simulated exception', ['app' => 'federation']);
+
+ $this->httpClient->expects($this->once())->method('get')->with($server . '/status.php')
+ ->willReturnCallback(function () {
+ throw new \Exception('simulated exception');
+ });
+
+ $this->assertFalse($this->trustedServers->isOwnCloudServer($server));
+
+ }
+
+ /**
+ * @dataProvider dataTestCheckOwnCloudVersion
+ *
+ * @param $statusphp
+ * @param $expected
+ */
+ public function testCheckOwnCloudVersion($statusphp, $expected) {
+ $this->assertSame($expected,
+ $this->invokePrivate($this->trustedServers, 'checkOwnCloudVersion', [$statusphp])
+ );
+ }
+
+ public function dataTestCheckOwnCloudVersion() {
+ return [
+ ['{"version":"8.4.0"}', false],
+ ['{"version":"9.0.0"}', true],
+ ['{"version":"9.1.0"}', true]
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestUpdateProtocol
+ * @param string $url
+ * @param string $expected
+ */
+ public function testUpdateProtocol($url, $expected) {
+ $this->assertSame($expected,
+ $this->invokePrivate($this->trustedServers, 'updateProtocol', [$url])
+ );
+ }
+
+ public function dataTestUpdateProtocol() {
+ return [
+ ['http://owncloud.org', 'http://owncloud.org'],
+ ['https://owncloud.org', 'https://owncloud.org'],
+ ['owncloud.org', 'https://owncloud.org'],
+ ['httpserver', 'https://httpserver'],
+ ];
+ }
+}
diff --git a/apps/federation/tests/middleware/addservermiddlewaretest.php b/apps/federation/tests/middleware/addservermiddlewaretest.php
new file mode 100644
index 00000000000..a94d907ae76
--- /dev/null
+++ b/apps/federation/tests/middleware/addservermiddlewaretest.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\Middleware;
+
+
+use OC\HintException;
+use OCA\Federation\Middleware\AddServerMiddleware;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use Test\TestCase;
+
+class AddServerMiddlewareTest extends TestCase {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
+ private $logger;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IL10N */
+ private $l10n;
+
+ /** @var AddServerMiddleware */
+ private $middleware;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | Controller */
+ private $controller;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->logger = $this->getMock('OCP\ILogger');
+ $this->l10n = $this->getMock('OCP\IL10N');
+ $this->controller = $this->getMockBuilder('OCP\AppFramework\Controller')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->middleware = new AddServerMiddleware(
+ 'AddServerMiddlewareTest',
+ $this->l10n,
+ $this->logger
+ );
+ }
+
+ /**
+ * @dataProvider dataTestAfterException
+ *
+ * @param \Exception $exception
+ * @param string $message
+ * @param string $hint
+ */
+ public function testAfterException($exception, $message, $hint) {
+
+ $this->logger->expects($this->once())->method('error')
+ ->with($message, ['app' => 'AddServerMiddlewareTest']);
+
+ $this->l10n->expects($this->any())->method('t')
+ ->willReturnCallback(
+ function($message) {
+ return $message;
+ }
+ );
+
+ $result = $this->middleware->afterException($this->controller, 'method', $exception);
+
+ $this->assertSame(Http::STATUS_BAD_REQUEST,
+ $result->getStatus()
+ );
+
+ $data = $result->getData();
+
+ $this->assertSame($hint,
+ $data['message']
+ );
+ }
+
+ public function dataTestAfterException() {
+ return [
+ [new HintException('message', 'hint'), 'message', 'hint'],
+ [new \Exception('message'), 'message', 'Unknown error'],
+ ];
+ }
+
+}
diff --git a/apps/files/admin.php b/apps/files/admin.php
index 786a8edf2a6..6e818a174bb 100644
--- a/apps/files/admin.php
+++ b/apps/files/admin.php
@@ -1,16 +1,16 @@
<?php
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Clark Tomlinson <fallen013@gmail.com>
* @author Frank Karlitschek <frank@owncloud.org>
* @author Jakob Sack <mail@jakobsack.de>
- * @author Lukas Reschke <lukas@owncloud.com>
* @author Michael Göhler <somebody.here@gmx.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,11 +30,10 @@
OCP\User::checkAdminUser();
$htaccessWorking=(getenv('htaccessWorking')=='true');
-
-$upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize'));
-$post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size'));
+$upload_max_filesize = OC::$server->getIniWrapper()->getBytes('upload_max_filesize');
+$post_max_size = OC::$server->getIniWrapper()->getBytes('post_max_size');
$maxUploadFilesize = OCP\Util::humanFileSize(min($upload_max_filesize, $post_max_size));
-if($_POST && OC_Util::isCallRegistered()) {
+if($_POST && \OC::$server->getRequest()->passesCSRFCheck()) {
if(isset($_POST['maxUploadSize'])) {
if(($setMaxSize = OC_Files::setUploadLimit(OCP\Util::computerFileSize($_POST['maxUploadSize']))) !== false) {
$maxUploadFilesize = OCP\Util::humanFileSize($setMaxSize);
diff --git a/apps/files/ajax/delete.php b/apps/files/ajax/delete.php
deleted file mode 100644
index 2d02869df14..00000000000
--- a/apps/files/ajax/delete.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-
-// Get data
-$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
-$allFiles = isset($_POST["allfiles"]) ? (string)$_POST["allfiles"] : false;
-
-// delete all files in dir ?
-if ($allFiles === 'true') {
- $files = array();
- $fileList = \OC\Files\Filesystem::getDirectoryContent($dir);
- foreach ($fileList as $fileInfo) {
- $files[] = $fileInfo['name'];
- }
-} else {
- $files = isset($_POST["file"]) ? (string)$_POST["file"] : (string)$_POST["files"];
- $files = json_decode($files);
-}
-$filesWithError = '';
-
-$success = true;
-
-//Now delete
-foreach ($files as $file) {
- try {
- if (\OC\Files\Filesystem::file_exists($dir . '/' . $file) &&
- !(\OC\Files\Filesystem::isDeletable($dir . '/' . $file) &&
- \OC\Files\Filesystem::unlink($dir . '/' . $file))
- ) {
- $filesWithError .= $file . "\n";
- $success = false;
- }
- } catch (\Exception $e) {
- $filesWithError .= $file . "\n";
- $success = false;
- }
-}
-
-// get array with updated storage stats (e.g. max file size) after upload
-try {
- $storageStats = \OCA\Files\Helper::buildFileStorageStatistics($dir);
-} catch(\OCP\Files\NotFoundException $e) {
- OCP\JSON::error(['data' => ['message' => 'File not found']]);
- return;
-}
-
-if ($success) {
- OCP\JSON::success(array("data" => array_merge(array("dir" => $dir, "files" => $files), $storageStats)));
-} else {
- OCP\JSON::error(array("data" => array_merge(array("message" => "Could not delete:\n" . $filesWithError), $storageStats)));
-}
diff --git a/apps/files/ajax/download.php b/apps/files/ajax/download.php
index 26bab8837b4..28ce4c6542e 100644
--- a/apps/files/ajax/download.php
+++ b/apps/files/ajax/download.php
@@ -9,7 +9,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/ajax/getstoragestats.php b/apps/files/ajax/getstoragestats.php
index 10f8704dded..83466ecc033 100644
--- a/apps/files/ajax/getstoragestats.php
+++ b/apps/files/ajax/getstoragestats.php
@@ -6,7 +6,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php
index 6cfa04b49d6..26ec126becf 100644
--- a/apps/files/ajax/list.php
+++ b/apps/files/ajax/list.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/ajax/move.php b/apps/files/ajax/move.php
deleted file mode 100644
index 0961636a116..00000000000
--- a/apps/files/ajax/move.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-// Get data
-$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
-$file = isset($_POST['file']) ? (string)$_POST['file'] : '';
-$target = isset($_POST['target']) ? rawurldecode((string)$_POST['target']) : '';
-
-$l = \OC::$server->getL10N('files');
-
-if(\OC\Files\Filesystem::file_exists($target . '/' . $file)) {
- OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s - File with this name already exists", array($file)) )));
- exit;
-}
-
-if ($target != '' || strtolower($file) != 'shared') {
- $targetFile = \OC\Files\Filesystem::normalizePath($target . '/' . $file);
- $sourceFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file);
- try {
- if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) {
- OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $file )));
- } else {
- OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) )));
- }
- } catch (\OCP\Files\NotPermittedException $e) {
- OCP\JSON::error(array("data" => array( "message" => $l->t("Permission denied") )));
- } catch (\Exception $e) {
- OCP\JSON::error(array("data" => array( "message" => $e->getMessage())));
- }
-}else{
- OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) )));
-}
diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php
deleted file mode 100644
index be09b288d4b..00000000000
--- a/apps/files/ajax/newfile.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-/**
- * @author Andreas Fischer <bantu@owncloud.com>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-// Init owncloud
-global $eventSource;
-
-\OCP\JSON::checkLoggedIn();
-\OCP\JSON::callCheck();
-
-\OC::$server->getSession()->close();
-
-// Get the params
-$dir = isset( $_REQUEST['dir'] ) ? '/'.trim((string)$_REQUEST['dir'], '/\\') : '';
-$fileName = isset( $_REQUEST['filename'] ) ? trim((string)$_REQUEST['filename'], '/\\') : '';
-
-$l10n = \OC::$server->getL10N('files');
-
-$result = array(
- 'success' => false,
- 'data' => NULL
-);
-
-try {
- \OC\Files\Filesystem::getView()->verifyPath($dir, $fileName);
-} catch (\OCP\Files\InvalidPathException $ex) {
- $result['data'] = [
- 'message' => $ex->getMessage()];
- OCP\JSON::error($result);
- return;
-}
-
-if (!\OC\Files\Filesystem::file_exists($dir . '/')) {
- $result['data'] = array('message' => (string)$l10n->t(
- 'The target folder has been moved or deleted.'),
- 'code' => 'targetnotfound'
- );
- OCP\JSON::error($result);
- exit();
-}
-
-$target = $dir.'/'.$fileName;
-
-if (\OC\Files\Filesystem::file_exists($target)) {
- $result['data'] = array('message' => (string)$l10n->t(
- 'The name %s is already used in the folder %s. Please choose a different name.',
- array($fileName, $dir))
- );
- OCP\JSON::error($result);
- exit();
-}
-
-$success = false;
-$templateManager = OC_Helper::getFileTemplateManager();
-$mimeType = OC_Helper::getMimetypeDetector()->detectPath($target);
-$content = $templateManager->getTemplate($mimeType);
-
-try {
- if($content) {
- $success = \OC\Files\Filesystem::file_put_contents($target, $content);
- } else {
- $success = \OC\Files\Filesystem::touch($target);
- }
-} catch (\Exception $e) {
- $result = [
- 'success' => false,
- 'data' => [
- 'message' => $e->getMessage()
- ]
- ];
- OCP\JSON::error($result);
- exit();
-}
-
-if($success) {
- $meta = \OC\Files\Filesystem::getFileInfo($target);
- OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta)));
- return;
-}
-
-OCP\JSON::error(array('data' => array( 'message' => $l10n->t('Error when creating the file') )));
diff --git a/apps/files/ajax/newfolder.php b/apps/files/ajax/newfolder.php
deleted file mode 100644
index a2897dd437a..00000000000
--- a/apps/files/ajax/newfolder.php
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-// Init owncloud
-
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-// Get the params
-$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
-$folderName = isset($_POST['foldername']) ?(string) $_POST['foldername'] : '';
-
-$l10n = \OC::$server->getL10N('files');
-
-$result = array(
- 'success' => false,
- 'data' => NULL
- );
-
-try {
- \OC\Files\Filesystem::getView()->verifyPath($dir, $folderName);
-} catch (\OCP\Files\InvalidPathException $ex) {
- $result['data'] = [
- 'message' => $ex->getMessage()];
- OCP\JSON::error($result);
- return;
-}
-
-if (!\OC\Files\Filesystem::file_exists($dir . '/')) {
- $result['data'] = array('message' => (string)$l10n->t(
- 'The target folder has been moved or deleted.'),
- 'code' => 'targetnotfound'
- );
- OCP\JSON::error($result);
- exit();
-}
-
-$target = $dir . '/' . $folderName;
-
-if (\OC\Files\Filesystem::file_exists($target)) {
- $result['data'] = array('message' => $l10n->t(
- 'The name %s is already used in the folder %s. Please choose a different name.',
- array($folderName, $dir))
- );
- OCP\JSON::error($result);
- exit();
-}
-
-try {
- if(\OC\Files\Filesystem::mkdir($target)) {
- if ( $dir !== '/') {
- $path = $dir.'/'.$folderName;
- } else {
- $path = '/'.$folderName;
- }
- $meta = \OC\Files\Filesystem::getFileInfo($path);
- $meta['type'] = 'dir'; // missing ?!
- OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta)));
- exit();
- }
-} catch (\Exception $e) {
- $result = [
- 'success' => false,
- 'data' => [
- 'message' => $e->getMessage()
- ]
- ];
- OCP\JSON::error($result);
- exit();
-}
-
-OCP\JSON::error(array('data' => array( 'message' => $l10n->t('Error when creating the folder') )));
diff --git a/apps/files/ajax/rename.php b/apps/files/ajax/rename.php
deleted file mode 100644
index a24a57b1046..00000000000
--- a/apps/files/ajax/rename.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-/**
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-$l10n = \OC::$server->getL10N('files');
-
-$files = new \OCA\Files\App(
- \OC\Files\Filesystem::getView(),
- \OC::$server->getL10N('files')
-);
-try {
- $result = $files->rename(
- isset($_GET['dir']) ? (string)$_GET['dir'] : '',
- isset($_GET['file']) ? (string)$_GET['file'] : '',
- isset($_GET['newname']) ? (string)$_GET['newname'] : ''
- );
-} catch (\Exception $e) {
- $result = [
- 'success' => false,
- 'data' => [
- 'message' => $e->getMessage()
- ]
- ];
-}
-
-if($result['success'] === true){
- OCP\JSON::success(['data' => $result['data']]);
-} else {
- OCP\JSON::error(['data' => $result['data']]);
-}
diff --git a/apps/files/ajax/scan.php b/apps/files/ajax/scan.php
deleted file mode 100644
index 491adaa9b88..00000000000
--- a/apps/files/ajax/scan.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-/**
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-set_time_limit(0); //scanning can take ages
-
-\OCP\JSON::checkLoggedIn();
-\OCP\JSON::callCheck();
-
-\OC::$server->getSession()->close();
-
-$force = (isset($_GET['force']) and ($_GET['force'] === 'true'));
-$dir = isset($_GET['dir']) ? (string)$_GET['dir'] : '';
-if (isset($_GET['users'])) {
- \OCP\JSON::checkAdminUser();
- if ($_GET['users'] === 'all') {
- $users = OC_User::getUsers();
- } else {
- $users = json_decode($_GET['users']);
- }
-} else {
- $users = array(OC_User::getUser());
-}
-
-$eventSource = \OC::$server->createEventSource();
-$listener = new ScanListener($eventSource);
-
-foreach ($users as $user) {
- $eventSource->send('user', $user);
- $scanner = new \OC\Files\Utils\Scanner($user, \OC::$server->getDatabaseConnection());
- $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', array($listener, 'file'));
- $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', array($listener, 'folder'));
- try {
- if ($force) {
- $scanner->scan($dir);
- } else {
- $scanner->backgroundScan($dir);
- }
- } catch (\Exception $e) {
- $eventSource->send('error', get_class($e) . ': ' . $e->getMessage());
- }
-}
-
-$eventSource->send('done', $listener->getCount());
-$eventSource->close();
-
-class ScanListener {
-
- private $fileCount = 0;
- private $lastCount = 0;
-
- /**
- * @var \OCP\IEventSource event source to pass events to
- */
- private $eventSource;
-
- /**
- * @param \OCP\IEventSource $eventSource
- */
- public function __construct($eventSource) {
- $this->eventSource = $eventSource;
- }
-
- /**
- * @param string $path
- */
- public function folder($path) {
- $this->eventSource->send('folder', $path);
- }
-
- public function file() {
- $this->fileCount++;
- if ($this->fileCount > $this->lastCount + 20) { //send a count update every 20 files
- $this->lastCount = $this->fileCount;
- $this->eventSource->send('count', $this->fileCount);
- }
- }
-
- public function getCount() {
- return $this->fileCount;
- }
-}
diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php
index a784642728f..5bf69d3e304 100644
--- a/apps/files/ajax/upload.php
+++ b/apps/files/ajax/upload.php
@@ -3,6 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
+ * @author Clark Tomlinson <fallen013@gmail.com>
* @author Florian Pritz <bluewind@xinu.at>
* @author Frank Karlitschek <frank@owncloud.org>
* @author Individual IT Services <info@individual-it.net>
@@ -16,7 +17,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -41,7 +42,6 @@ OCP\JSON::setContentTypeHeader('text/plain');
// If not, check the login.
// If no token is sent along, rely on login only
-$allowedPermissions = \OCP\Constants::PERMISSION_ALL;
$errorCode = null;
$l = \OC::$server->getL10N('files');
@@ -60,8 +60,6 @@ if (empty($_POST['dirToken'])) {
\OC_User::setIncognitoMode(true);
- // return only read permissions for public upload
- $allowedPermissions = \OCP\Constants::PERMISSION_READ;
$publicDirectory = !empty($_POST['subdir']) ? (string)$_POST['subdir'] : '/';
$linkItem = OCP\Share::getShareByToken((string)$_POST['dirToken']);
@@ -117,7 +115,7 @@ foreach ($_FILES['files']['error'] as $error) {
$errors = array(
UPLOAD_ERR_OK => $l->t('There is no error, the file uploaded with success'),
UPLOAD_ERR_INI_SIZE => $l->t('The uploaded file exceeds the upload_max_filesize directive in php.ini: ')
- . ini_get('upload_max_filesize'),
+ . OC::$server->getIniWrapper()->getNumeric('upload_max_filesize'),
UPLOAD_ERR_FORM_SIZE => $l->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'),
UPLOAD_ERR_PARTIAL => $l->t('The uploaded file was only partially uploaded'),
UPLOAD_ERR_NO_FILE => $l->t('No file was uploaded'),
@@ -207,7 +205,7 @@ if (\OC\Files\Filesystem::isValidPath($dir) === true) {
$data['originalname'] = $files['name'][$i];
$data['uploadMaxFilesize'] = $maxUploadFileSize;
$data['maxHumanFilesize'] = $maxHumanFileSize;
- $data['permissions'] = $meta['permissions'] & $allowedPermissions;
+ $data['permissions'] = $meta['permissions'];
$data['directory'] = $returnedDir;
$result[] = $data;
}
@@ -234,7 +232,7 @@ if (\OC\Files\Filesystem::isValidPath($dir) === true) {
$data['originalname'] = $files['name'][$i];
$data['uploadMaxFilesize'] = $maxUploadFileSize;
$data['maxHumanFilesize'] = $maxHumanFileSize;
- $data['permissions'] = $meta['permissions'] & $allowedPermissions;
+ $data['permissions'] = $meta['permissions'];
$data['directory'] = $returnedDir;
$result[] = $data;
}
diff --git a/apps/files/appinfo/app.php b/apps/files/appinfo/app.php
index c752b5e7d72..94360786ac3 100644
--- a/apps/files/appinfo/app.php
+++ b/apps/files/appinfo/app.php
@@ -3,11 +3,12 @@
* @author Jakob Sack <mail@jakobsack.de>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -65,6 +66,7 @@ $templateManager->registerTemplate('application/vnd.oasis.opendocument.spreadshe
new \OCA\Files\ActivityHelper(
\OC::$server->getTagManager()
),
+ \OC::$server->getDatabaseConnection(),
\OC::$server->getConfig()
);
});
diff --git a/apps/files/appinfo/application.php b/apps/files/appinfo/application.php
index 6aff517e17f..bc6dc9fb9ed 100644
--- a/apps/files/appinfo/application.php
+++ b/apps/files/appinfo/application.php
@@ -4,7 +4,7 @@
* @author Tobias Kaminsky <tobias@kaminsky.me>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/appinfo/info.xml b/apps/files/appinfo/info.xml
index ba8bb62494e..136baa2ed07 100644
--- a/apps/files/appinfo/info.xml
+++ b/apps/files/appinfo/info.xml
@@ -5,15 +5,13 @@
<description>File Management</description>
<licence>AGPL</licence>
<author>Robin Appelman, Vincent Petry</author>
- <shipped>true</shipped>
- <standalone/>
<default_enable/>
- <version>1.3.0</version>
+ <version>1.4.2</version>
<types>
<filesystem/>
</types>
<dependencies>
- <owncloud min-version="9.0" />
+ <owncloud min-version="9.0" max-version="9.0" />
</dependencies>
<documentation>
<user>user-files</user>
diff --git a/apps/files/appinfo/install.php b/apps/files/appinfo/install.php
new file mode 100644
index 00000000000..b9a893d1ee8
--- /dev/null
+++ b/apps/files/appinfo/install.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+// Cron job for scanning user storages
+\OC::$server->getJobList()->add('OCA\Files\BackgroundJob\ScanFiles');
+\OC::$server->getJobList()->add('OCA\Files\BackgroundJob\DeleteOrphanedTagsJob');
diff --git a/apps/files/appinfo/register_command.php b/apps/files/appinfo/register_command.php
index 3042c259872..4aaf49df9e2 100644
--- a/apps/files/appinfo/register_command.php
+++ b/apps/files/appinfo/register_command.php
@@ -2,8 +2,9 @@
/**
* @author Bart Visscher <bartv@thisnet.nl>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,5 +21,5 @@
*
*/
-$application->add(new OCA\Files\Command\Scan(OC_User::getManager()));
+$application->add(new OCA\Files\Command\Scan(\OC::$server->getUserManager()));
$application->add(new OCA\Files\Command\DeleteOrphanedFiles(\OC::$server->getDatabaseConnection()));
diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php
index 2bb913c30a6..731c671b60a 100644
--- a/apps/files/appinfo/routes.php
+++ b/apps/files/appinfo/routes.php
@@ -7,7 +7,7 @@
* @author Tom Needham <tom@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -75,8 +75,6 @@ $this->create('files_ajax_newfolder', 'ajax/newfolder.php')
->actionInclude('files/ajax/newfolder.php');
$this->create('files_ajax_rename', 'ajax/rename.php')
->actionInclude('files/ajax/rename.php');
-$this->create('files_ajax_scan', 'ajax/scan.php')
- ->actionInclude('files/ajax/scan.php');
$this->create('files_ajax_upload', 'ajax/upload.php')
->actionInclude('files/ajax/upload.php');
diff --git a/apps/files/appinfo/update.php b/apps/files/appinfo/update.php
index 6084435fa5a..003f6916ac5 100644
--- a/apps/files/appinfo/update.php
+++ b/apps/files/appinfo/update.php
@@ -2,9 +2,10 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -96,11 +97,6 @@ if ($installedVersion === '1.1.9' && (
}
}
-/**
- * migrate old constant DEBUG to new config value 'debug'
- *
- * TODO: remove this in ownCloud 8.3
- */
-if(defined('DEBUG') && DEBUG === true) {
- \OC::$server->getConfig()->setSystemValue('debug', true);
-}
+// Add cron job for scanning user storages
+\OC::$server->getJobList()->add('OCA\Files\BackgroundJob\ScanFiles');
+\OC::$server->getJobList()->add('OCA\Files\BackgroundJob\DeleteOrphanedTagsJob');
diff --git a/apps/files/command/deleteorphanedfiles.php b/apps/files/command/deleteorphanedfiles.php
index 0dc9c29f4f7..d276e9a0993 100644
--- a/apps/files/command/deleteorphanedfiles.php
+++ b/apps/files/command/deleteorphanedfiles.php
@@ -2,7 +2,7 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/command/scan.php b/apps/files/command/scan.php
index 99ce64e09cc..3251682445c 100644
--- a/apps/files/command/scan.php
+++ b/apps/files/command/scan.php
@@ -2,11 +2,12 @@
/**
* @author Bart Visscher <bartv@thisnet.nl>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author martin.mattel@diemattels.at <martin.mattel@diemattels.at>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,26 +26,35 @@
namespace OCA\Files\Command;
+use OC\Core\Command\Base;
use OC\ForbiddenException;
-use Symfony\Component\Console\Command\Command;
+use OCP\Files\StorageNotAvailableException;
+use OCP\IUserManager;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Helper\Table;
-class Scan extends Command {
+class Scan extends Base {
- /**
- * @var \OC\User\Manager $userManager
- */
+ /** @var IUserManager $userManager */
private $userManager;
+ /** @var float */
+ protected $execTime = 0;
+ /** @var int */
+ protected $foldersCounter = 0;
+ /** @var int */
+ protected $filesCounter = 0;
- public function __construct(\OC\User\Manager $userManager) {
+ public function __construct(IUserManager $userManager) {
$this->userManager = $userManager;
parent::__construct();
}
protected function configure() {
+ parent::configure();
+
$this
->setName('files:scan')
->setDescription('rescan filesystem')
@@ -63,7 +73,13 @@ class Scan extends Command {
'quiet',
'q',
InputOption::VALUE_NONE,
- 'suppress output'
+ 'suppress any output'
+ )
+ ->addOption(
+ 'verbose',
+ '-v|vv|vvv',
+ InputOption::VALUE_NONE,
+ 'verbose the output'
)
->addOption(
'all',
@@ -73,24 +89,56 @@ class Scan extends Command {
);
}
- protected function scanFiles($user, $path, $quiet, OutputInterface $output) {
- $scanner = new \OC\Files\Utils\Scanner($user, \OC::$server->getDatabaseConnection());
- if (!$quiet) {
+ protected function scanFiles($user, $path, $verbose, OutputInterface $output) {
+ $scanner = new \OC\Files\Utils\Scanner($user, \OC::$server->getDatabaseConnection(), \OC::$server->getLogger());
+ # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
+ # printout and count
+ if ($verbose) {
$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
- $output->writeln("Scanning file <info>$path</info>");
+ $output->writeln("\tFile <info>$path</info>");
+ $this->filesCounter += 1;
+ if ($this->hasBeenInterrupted()) {
+ throw new \Exception('ctrl-c');
+ }
});
$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
- $output->writeln("Scanning folder <info>$path</info>");
+ $output->writeln("\tFolder <info>$path</info>");
+ $this->foldersCounter += 1;
+ if ($this->hasBeenInterrupted()) {
+ throw new \Exception('ctrl-c');
+ }
+ });
+ $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
+ $output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")");
+ });
+ # count only
+ } else {
+ $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) {
+ $this->filesCounter += 1;
+ if ($this->hasBeenInterrupted()) {
+ throw new \Exception('ctrl-c');
+ }
+ });
+ $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) {
+ $this->foldersCounter += 1;
+ if ($this->hasBeenInterrupted()) {
+ throw new \Exception('ctrl-c');
+ }
});
}
+
try {
$scanner->scan($path);
} catch (ForbiddenException $e) {
$output->writeln("<error>Home storage for user $user not writable</error>");
$output->writeln("Make sure you're running the scan command only as the user the web server runs as");
+ } catch (\Exception $e) {
+ # exit the function if ctrl-c has been pressed
+ return;
}
}
+
protected function execute(InputInterface $input, OutputInterface $output) {
$inputPath = $input->getOption('path');
if ($inputPath) {
@@ -102,24 +150,144 @@ class Scan extends Command {
} else {
$users = $input->getArgument('user_id');
}
- $quiet = $input->getOption('quiet');
+ # no messaging level option means: no full printout but statistics
+ # $quiet means no print at all
+ # $verbose means full printout including statistics
+ # -q -v full stat
+ # 0 0 no yes
+ # 0 1 yes yes
+ # 1 -- no no (quiet overrules verbose)
+ $verbose = $input->getOption('verbose');
+ $quiet = $input->getOption('quiet');
+ # restrict the verbosity level to VERBOSITY_VERBOSE
+ if ($output->getVerbosity()>OutputInterface::VERBOSITY_VERBOSE) {
+ $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
+ }
+ if ($quiet) {
+ $verbose = false;
+ }
- if (count($users) === 0) {
+ # check quantity of users to be process and show it on the command line
+ $users_total = count($users);
+ if ($users_total === 0) {
$output->writeln("<error>Please specify the user id to scan, \"--all\" to scan for all users or \"--path=...\"</error>");
return;
+ } else {
+ if ($users_total > 1) {
+ $output->writeln("\nScanning files for $users_total users");
+ }
}
+ $this->initTools();
+
+ $user_count = 0;
foreach ($users as $user) {
if (is_object($user)) {
$user = $user->getUID();
}
$path = $inputPath ? $inputPath : '/' . $user;
+ $user_count += 1;
if ($this->userManager->userExists($user)) {
- $this->scanFiles($user, $path, $quiet, $output);
+ # add an extra line when verbose is set to optical separate users
+ if ($verbose) {$output->writeln(""); }
+ $output->writeln("Starting scan for user $user_count out of $users_total ($user)");
+ # full: printout data if $verbose was set
+ $this->scanFiles($user, $path, $verbose, $output);
} else {
- $output->writeln("<error>Unknown user $user</error>");
+ $output->writeln("<error>Unknown user $user_count $user</error>");
}
+ # check on each user if there was a user interrupt (ctrl-c) and exit foreach
+ if ($this->hasBeenInterrupted()) {
+ break;
+ }
+ }
+
+ # stat: printout statistics if $quiet was not set
+ if (!$quiet) {
+ $this->presentStats($output);
}
}
+
+ /**
+ * Initialises some useful tools for the Command
+ */
+ protected function initTools() {
+ // Start the timer
+ $this->execTime = -microtime(true);
+ // Convert PHP errors to exceptions
+ set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
+ }
+
+ /**
+ * Processes PHP errors as exceptions in order to be able to keep track of problems
+ *
+ * @see https://secure.php.net/manual/en/function.set-error-handler.php
+ *
+ * @param int $severity the level of the error raised
+ * @param string $message
+ * @param string $file the filename that the error was raised in
+ * @param int $line the line number the error was raised
+ *
+ * @throws \ErrorException
+ */
+ public function exceptionErrorHandler($severity, $message, $file, $line) {
+ if (!(error_reporting() & $severity)) {
+ // This error code is not included in error_reporting
+ return;
+ }
+ throw new \ErrorException($message, 0, $severity, $file, $line);
+ }
+
+ /**
+ * @param OutputInterface $output
+ */
+ protected function presentStats(OutputInterface $output) {
+ // Stop the timer
+ $this->execTime += microtime(true);
+ $output->writeln("");
+
+ $headers = [
+ 'Folders', 'Files', 'Elapsed time'
+ ];
+
+ $this->showSummary($headers, null, $output);
+ }
+
+ /**
+ * Shows a summary of operations
+ *
+ * @param string[] $headers
+ * @param string[] $rows
+ * @param OutputInterface $output
+ */
+ protected function showSummary($headers, $rows, OutputInterface $output) {
+ $niceDate = $this->formatExecTime();
+ if (!$rows) {
+ $rows = [
+ $this->foldersCounter,
+ $this->filesCounter,
+ $niceDate,
+ ];
+ }
+ $table = new Table($output);
+ $table
+ ->setHeaders($headers)
+ ->setRows([$rows]);
+ $table->render();
+ }
+
+
+ /**
+ * Formats microtime into a human readable format
+ *
+ * @return string
+ */
+ protected function formatExecTime() {
+ list($secs, $tens) = explode('.', sprintf("%.1f", ($this->execTime)));
+
+ # if you want to have microseconds add this: . '.' . $tens;
+ return date('H:i:s', $secs);
+ }
+
}
diff --git a/apps/files/controller/apicontroller.php b/apps/files/controller/apicontroller.php
index 1ecd5294c66..c96d92a046b 100644
--- a/apps/files/controller/apicontroller.php
+++ b/apps/files/controller/apicontroller.php
@@ -8,7 +8,7 @@
* @author Tobias Kaminsky <tobias@kaminsky.me>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -127,7 +127,7 @@ class ApiController extends Controller {
*
* @NoAdminRequired
*
- * @param array|string $tagName tag name to filter by
+ * @param string $tagName tag name to filter by
* @return DataResponse
*/
public function getFilesByTag($tagName) {
diff --git a/apps/files/controller/viewcontroller.php b/apps/files/controller/viewcontroller.php
index c274680e525..800cf008fa7 100644
--- a/apps/files/controller/viewcontroller.php
+++ b/apps/files/controller/viewcontroller.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +24,7 @@ namespace OCA\Files\Controller;
use OC\AppFramework\Http\Request;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IL10N;
@@ -119,6 +121,8 @@ class ViewController extends Controller {
* @throws \OCP\Files\NotFoundException
*/
public function index($dir = '', $view = '') {
+ $nav = new \OCP\Template('files', 'appnavigation', '');
+
// Load the files we need
\OCP\Util::addStyle('files', 'files');
\OCP\Util::addStyle('files', 'upload');
@@ -169,8 +173,6 @@ class ViewController extends Controller {
// FIXME: Make non static
$storageInfo = $this->getStorageInfo();
- $nav = new \OCP\Template('files', 'appnavigation', '');
-
\OCA\Files\App::getNavigationManager()->add(
[
'id' => 'favorites',
@@ -215,10 +217,15 @@ class ViewController extends Controller {
$params['appContents'] = $contentItems;
$this->navigationManager->setActiveEntry('files_index');
- return new TemplateResponse(
+ $response = new TemplateResponse(
$this->appName,
'index',
$params
);
+ $policy = new ContentSecurityPolicy();
+ $policy->addAllowedFrameDomain('\'self\'');
+ $response->setContentSecurityPolicy($policy);
+
+ return $response;
}
}
diff --git a/apps/files/css/detailsView.css b/apps/files/css/detailsView.css
index 485c20e6865..c65107937da 100644
--- a/apps/files/css/detailsView.css
+++ b/apps/files/css/detailsView.css
@@ -83,6 +83,9 @@
}
#app-sidebar .file-details {
+ color: #999;
+}
+#app-sidebar .file-details img {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
opacity: .5;
}
diff --git a/apps/files/css/files.css b/apps/files/css/files.css
index 9588faebc3b..4929039f837 100644
--- a/apps/files/css/files.css
+++ b/apps/files/css/files.css
@@ -59,7 +59,7 @@
/* fit app list view heights */
.app-files #app-content>.viewcontainer {
- min-height: 100%;
+ min-height: 0%;
}
.app-files #app-content {
@@ -682,8 +682,6 @@ table tr.summary td {
margin-left: 90px;
}
-#scanning-message{ top:40%; left:40%; position:absolute; display:none; }
-
table.dragshadow {
width:auto;
}
diff --git a/apps/files/download.php b/apps/files/download.php
index b0628e394be..f71b54c4784 100644
--- a/apps/files/download.php
+++ b/apps/files/download.php
@@ -4,12 +4,12 @@
* @author Felix Moeller <mail@felixmoeller.de>
* @author Frank Karlitschek <frank@owncloud.org>
* @author Jakob Sack <mail@jakobsack.de>
- * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -39,7 +39,7 @@ if(!\OC\Files\Filesystem::file_exists($filename)) {
exit;
}
-$ftype=\OC_Helper::getSecureMimeType(\OC\Files\Filesystem::getMimeType( $filename ));
+$ftype=\OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType( $filename ));
header('Content-Type:'.$ftype);
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
diff --git a/apps/files/js/app.js b/apps/files/js/app.js
index f31770466fe..ff505d417f1 100644
--- a/apps/files/js/app.js
+++ b/apps/files/js/app.js
@@ -71,7 +71,8 @@
folderDropOptions: folderDropOptions,
fileActions: fileActions,
allowLegacyActions: true,
- scrollTo: urlParams.scrollto
+ scrollTo: urlParams.scrollto,
+ filesClient: OC.Files.getClient()
}
);
this.files.initialize();
diff --git a/apps/files/js/favoritesplugin.js b/apps/files/js/favoritesplugin.js
index 417a32ef804..454a505c7bd 100644
--- a/apps/files/js/favoritesplugin.js
+++ b/apps/files/js/favoritesplugin.js
@@ -92,7 +92,7 @@
// folder in the files app instead of opening it directly
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
OCA.Files.App.setActiveView('files', {silent: true});
- OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true);
+ OCA.Files.App.fileList.changeDirectory(OC.joinPaths(context.$file.attr('data-path'), filename), true, true);
});
fileActions.setDefault('dir', 'Open');
return fileActions;
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 6a767d48a28..67125f1570f 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -575,7 +575,8 @@
},
actionHandler: function (filename, context) {
var dir = context.dir || context.fileList.getCurrentDirectory();
- var url = context.fileList.getDownloadUrl(filename, dir);
+ var isDir = context.$file.attr('data-type') === 'dir';
+ var url = context.fileList.getDownloadUrl(filename, dir, isDir);
var downloadFileaction = $(context.$file).find('.fileactions .action-download');
@@ -611,15 +612,21 @@
this.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
var dir = context.$file.attr('data-path') || context.fileList.getCurrentDirectory();
- if (dir !== '/') {
- dir = dir + '/';
- }
- context.fileList.changeDirectory(dir + filename);
+ context.fileList.changeDirectory(OC.joinPaths(dir, filename));
});
this.registerAction({
name: 'Delete',
- displayName: t('files', 'Delete'),
+ displayName: function(context) {
+ var mountType = context.$file.attr('data-mounttype');
+ var deleteTitle = t('files', 'Delete');
+ if (mountType === 'external-root') {
+ deleteTitle = t('files', 'Disconnect storage');
+ } else if (mountType === 'shared-root') {
+ deleteTitle = t('files', 'Unshare');
+ }
+ return deleteTitle;
+ },
mime: 'all',
order: 1000,
// permission is READ because we show a hint instead if there is no permission
@@ -670,8 +677,9 @@
* @typedef {Object} OCA.Files.FileAction
*
* @property {String} name identifier of the action
- * @property {String} displayName display name of the action, defaults
- * to the name given in name property
+ * @property {(String|OCA.Files.FileActions~displayNameFunction)} displayName
+ * display name string for the action, or function that returns the display name.
+ * Defaults to the name given in name property
* @property {String} mime mime type
* @property {int} permissions permissions
* @property {(Function|String)} icon icon path to the icon or function
@@ -705,6 +713,16 @@
*/
/**
+ * Display name function for actions.
+ * The function returns the display name of the action using
+ * the given context information..
+ *
+ * @callback OCA.Files.FileActions~displayNameFunction
+ * @param {OCA.Files.FileActionContext} context action context
+ * @return {String} display name
+ */
+
+ /**
* Action handler function for file actions
*
* @callback OCA.Files.FileActions~actionHandler
diff --git a/apps/files/js/fileactionsmenu.js b/apps/files/js/fileactionsmenu.js
index 67cbb48c965..9e51d8f1f1f 100644
--- a/apps/files/js/fileactionsmenu.js
+++ b/apps/files/js/fileactionsmenu.js
@@ -81,6 +81,7 @@
* Renders the menu with the currently set items
*/
render: function() {
+ var self = this;
var fileActions = this._context.fileActions;
var actions = fileActions.getActions(
fileActions.getCurrentMimeType(),
@@ -100,6 +101,13 @@
(!defaultAction || actionSpec.name !== defaultAction.name)
);
});
+ items = _.map(items, function(item) {
+ if (_.isFunction(item.displayName)) {
+ item = _.extend({}, item);
+ item.displayName = item.displayName(self._context);
+ }
+ return item;
+ });
items = items.sort(function(actionA, actionB) {
var orderA = actionA.order || 0;
var orderB = actionB.order || 0;
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index d1f68d98eab..35999b5d0ee 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -22,11 +22,12 @@
*
* @param $el container element with existing markup for the #controls
* and a table
- * @param [options] map of options, see other parameters
- * @param [options.scrollContainer] scrollable container, defaults to $(window)
- * @param [options.dragOptions] drag options, disabled by default
- * @param [options.folderDropOptions] folder drop options, disabled by default
- * @param [options.detailsViewEnabled=true] whether to enable details view
+ * @param {Object} [options] map of options, see other parameters
+ * @param {Object} [options.scrollContainer] scrollable container, defaults to $(window)
+ * @param {Object} [options.dragOptions] drag options, disabled by default
+ * @param {Object} [options.folderDropOptions] folder drop options, disabled by default
+ * @param {boolean} [options.detailsViewEnabled=true] whether to enable details view
+ * @param {OC.Files.Client} [options.filesClient] files client to use
*/
var FileList = function($el, options) {
this.initialize($el, options);
@@ -74,6 +75,13 @@
_detailsView: null,
/**
+ * Files client instance
+ *
+ * @type OC.Files.Client
+ */
+ filesClient: null,
+
+ /**
* Whether the file list was initialized already.
* @type boolean
*/
@@ -92,11 +100,18 @@
* Array of files in the current folder.
* The entries are of file data.
*
- * @type Array.<Object>
+ * @type Array.<OC.Files.FileInfo>
*/
files: [],
/**
+ * Current directory entry
+ *
+ * @type OC.Files.FileInfo
+ */
+ dirInfo: null,
+
+ /**
* File actions handler, defaults to OCA.Files.FileActions
* @type OCA.Files.FileActions
*/
@@ -149,7 +164,7 @@
* When false, clicking on a table header will call reload().
* When true, clicking on a table header will simply resort the list.
*/
- _clientSideSort: false,
+ _clientSideSort: true,
/**
* Current directory
@@ -170,6 +185,7 @@
* @param options.dragOptions drag options, disabled by default
* @param options.folderDropOptions folder drop options, disabled by default
* @param options.scrollTo name of file to scroll to after the first load
+ * @param {OC.Files.Client} [options.filesClient] files API client
* @private
*/
initialize: function($el, options) {
@@ -185,6 +201,12 @@
if (options.folderDropOptions) {
this._folderDropOptions = options.folderDropOptions;
}
+ if (options.filesClient) {
+ this.filesClient = options.filesClient;
+ } else {
+ // default client if not specified
+ this.filesClient = OC.Files.getClient();
+ }
this.$el = $el;
if (options.id) {
@@ -209,6 +231,8 @@
this.files = [];
this._selectedFiles = {};
this._selectionSummary = new OCA.Files.FileSummary();
+ // dummy root dir info
+ this.dirInfo = new OC.Files.FileInfo({});
this.fileSummary = this._createSummary();
@@ -359,7 +383,7 @@
var highlightState = $tr.hasClass('highlighted');
$tr = self.updateRow(
$tr,
- _.extend({isPreviewAvailable: true}, model.toJSON()),
+ model.toJSON(),
{updateSummary: true, silent: false, animate: true}
);
$tr.toggleClass('highlighted', highlightState);
@@ -618,7 +642,13 @@
};
OCA.Files.FileActions.updateFileActionSpinner(downloadFileaction, true);
- OCA.Files.Files.handleDownload(this.getDownloadUrl(files, dir), disableLoadingState);
+ if(this.getSelectedFiles().length > 1) {
+ OCA.Files.Files.handleDownload(this.getDownloadUrl(files, dir, true), disableLoadingState);
+ }
+ else {
+ first = this.getSelectedFiles()[0];
+ OCA.Files.Files.handleDownload(this.getDownloadUrl(first.name, dir, true), disableLoadingState);
+ }
return false;
},
@@ -894,16 +924,39 @@
self.$el.closest('#app-content').trigger(jQuery.Event('apprendered'));
});
},
+
+ /**
+ * Returns the icon URL matching the given file info
+ *
+ * @param {OC.Files.FileInfo} fileInfo file info
+ *
+ * @return {string} icon URL
+ */
+ _getIconUrl: function(fileInfo) {
+ var mimeType = fileInfo.mimetype || 'application/octet-stream';
+ if (mimeType === 'httpd/unix-directory') {
+ // use default folder icon
+ if (fileInfo.mountType === 'shared' || fileInfo.mountType === 'shared-root') {
+ return OC.MimeType.getIconUrl('dir-shared');
+ } else if (fileInfo.mountType === 'external-root') {
+ return OC.MimeType.getIconUrl('dir-external');
+ }
+ return OC.MimeType.getIconUrl('dir');
+ }
+ return OC.MimeType.getIconUrl(mimeType);
+ },
+
/**
* Creates a new table row element using the given file data.
- * @param {OCA.Files.FileInfo} fileData file info attributes
+ * @param {OC.Files.FileInfo} fileData file info attributes
* @param options map of attributes
* @return new tr element (not appended to the table)
*/
_createRow: function(fileData, options) {
var td, simpleSize, basename, extension, sizeColor,
- icon = OC.MimeType.getIconUrl(fileData.mimetype),
+ icon = fileData.icon || this._getIconUrl(fileData),
name = fileData.name,
+ // TODO: get rid of type, only use mime type
type = fileData.type || 'file',
mtime = parseInt(fileData.mtime, 10),
mime = fileData.mimetype,
@@ -943,6 +996,17 @@
}
if (fileData.mountType) {
+ // dirInfo (parent) only exist for the "real" file list
+ if (this.dirInfo.id) {
+ // FIXME: HACK: detect shared-root
+ if (fileData.mountType === 'shared' && this.dirInfo.mountType !== 'shared' && this.dirInfo.mountType !== 'shared-root') {
+ // if parent folder isn't share, assume the displayed folder is a share root
+ fileData.mountType = 'shared-root';
+ } else if (fileData.mountType === 'external' && this.dirInfo.mountType !== 'external' && this.dirInfo.mountType !== 'external-root') {
+ // if parent folder isn't external, assume the displayed folder is the external storage root
+ fileData.mountType = 'external-root';
+ }
+ }
tr.attr('data-mounttype', fileData.mountType);
}
@@ -953,24 +1017,16 @@
path = this.getCurrentDirectory();
}
- if (type === 'dir') {
- // use default folder icon
- icon = icon || OC.imagePath('core', 'filetypes/folder');
- }
- else {
- icon = icon || OC.imagePath('core', 'filetypes/file');
- }
-
// filename td
td = $('<td class="filename"></td>');
// linkUrl
- if (type === 'dir') {
+ if (mime === 'httpd/unix-directory') {
linkUrl = this.linkTo(path + '/' + name);
}
else {
- linkUrl = this.getDownloadUrl(name, path);
+ linkUrl = this.getDownloadUrl(name, path, type === 'dir');
}
if (this._allowSelection) {
td.append(
@@ -996,7 +1052,7 @@
basename = '';
extension = name;
// split extension from filename for non dirs
- } else if (type !== 'dir' && name.indexOf('.') !== -1) {
+ } else if (mime !== 'httpd/unix-directory' && name.indexOf('.') !== -1) {
basename = name.substr(0, name.lastIndexOf('.'));
extension = name.substr(name.lastIndexOf('.'));
} else {
@@ -1018,7 +1074,7 @@
nameSpan.tooltip({placement: 'right'});
}
// dirs can show the number of uploaded files
- if (type === 'dir') {
+ if (mime === 'httpd/unix-directory') {
linkElem.append($('<span></span>').attr({
'class': 'uploadtext',
'currentUploads': 0
@@ -1074,7 +1130,7 @@
* Adds an entry to the files array and also into the DOM
* in a sorted manner.
*
- * @param {OCA.Files.FileInfo} fileData map of file attributes
+ * @param {OC.Files.FileInfo} fileData map of file attributes
* @param {Object} [options] map of attributes
* @param {boolean} [options.updateSummary] true to update the summary
* after adding (default), false otherwise. Defaults to true.
@@ -1147,7 +1203,7 @@
* Creates a new row element based on the given attributes
* and returns it.
*
- * @param {OCA.Files.FileInfo} fileData map of file attributes
+ * @param {OC.Files.FileInfo} fileData map of file attributes
* @param {Object} [options] map of attributes
* @param {int} [options.index] index at which to insert the element
* @param {boolean} [options.updateSummary] true to update the summary
@@ -1182,7 +1238,7 @@
filenameTd.draggable(this._dragOptions);
}
// allow dropping on folders
- if (this._folderDropOptions && fileData.type === 'dir') {
+ if (this._folderDropOptions && mime === 'httpd/unix-directory') {
filenameTd.droppable(this._folderDropOptions);
}
@@ -1193,7 +1249,7 @@
// display actions
this.fileActions.display(filenameTd, !options.silent, this);
- if (fileData.isPreviewAvailable && mime !== 'httpd/unix-directory') {
+ if (mime !== 'httpd/unix-directory') {
var iconDiv = filenameTd.find('.thumbnail');
// lazy load / newly inserted td ?
// the typeof check ensures that the default value of animate is true
@@ -1330,6 +1386,13 @@
},
/**
+ * Returns list of webdav properties to request
+ */
+ _getWebdavProperties: function() {
+ return [].concat(this.filesClient.getPropfindProperties());
+ },
+
+ /**
* Reloads the file list using ajax call
*
* @return ajax call object
@@ -1343,17 +1406,12 @@
this._currentFileModel = null;
this.$el.find('.select-all').prop('checked', false);
this.showMask();
- if (this._reloadCall) {
- this._reloadCall.abort();
- }
- this._reloadCall = $.ajax({
- url: this.getAjaxUrl('list'),
- data: {
- dir : this.getCurrentDirectory(),
- sort: this._sort,
- sortdirection: this._sortDirection
+ this._reloadCall = this.filesClient.getFolderContents(
+ this.getCurrentDirectory(), {
+ includeParent: true,
+ properties: this._getWebdavProperties()
}
- });
+ );
if (this._detailsView) {
// close sidebar
this._updateDetailsView(null);
@@ -1361,24 +1419,19 @@
var callBack = this.reloadCallback.bind(this);
return this._reloadCall.then(callBack, callBack);
},
- reloadCallback: function(result) {
+ reloadCallback: function(status, result) {
delete this._reloadCall;
this.hideMask();
- if (!result || result.status === 'error') {
- // if the error is not related to folder we're trying to load, reload the page to handle logout etc
- if (result.data.error === 'authentication_error' ||
- result.data.error === 'token_expired' ||
- result.data.error === 'application_not_enabled'
- ) {
- OC.redirect(OC.generateUrl('apps/files'));
- }
- OC.Notification.showTemporary(result.data.message);
+ if (status === 401) {
+ // TODO: append current URL to be able to get back after logging in again
+ OC.redirect(OC.generateUrl('apps/files'));
+ OC.Notification.show(result);
return false;
}
// Firewall Blocked request?
- if (result.status === 403) {
+ if (status === 403) {
// Go home
this.changeDirectory('/');
OC.Notification.showTemporary(t('files', 'This operation is forbidden'));
@@ -1386,32 +1439,49 @@
}
// Did share service die or something else fail?
- if (result.status === 500) {
+ if (status === 500) {
// Go home
this.changeDirectory('/');
- OC.Notification.showTemporary(t('files', 'This directory is unavailable, please check the logs or contact the administrator'));
+ OC.Notification.showTemporary(
+ t('files', 'This directory is unavailable, please check the logs or contact the administrator')
+ );
return false;
}
- if (result.status === 404) {
+ if (status === 503) {
+ // Go home
+ if (this.getCurrentDirectory() !== '/') {
+ this.changeDirectory('/');
+ // TODO: read error message from exception
+ OC.Notification.showTemporary(
+ t('files', 'Storage not available')
+ );
+ }
+ return false;
+ }
+
+ if (status === 404) {
// go back home
this.changeDirectory('/');
return false;
}
// aborted ?
- if (result.status === 0){
+ if (status === 0){
return true;
}
- // TODO: should rather return upload file size through
- // the files list ajax call
+ // TODO: parse remaining quota from PROPFIND response
this.updateStorageStatistics(true);
- if (result.data.permissions) {
- this.setDirectoryPermissions(result.data.permissions);
+ // first entry is the root
+ this.dirInfo = result.shift();
+
+ if (this.dirInfo.permissions) {
+ this.setDirectoryPermissions(this.dirInfo.permissions);
}
- this.setFiles(result.data.files);
+ result.sort(this._sortComparator);
+ this.setFiles(result);
return true;
},
@@ -1419,12 +1489,15 @@
OCA.Files.Files.updateStorageStatistics(this.getCurrentDirectory(), force);
},
+ /**
+ * @deprecated do not use nor override
+ */
getAjaxUrl: function(action, params) {
return OCA.Files.Files.getAjaxUrl(action, params);
},
- getDownloadUrl: function(files, dir) {
- return OCA.Files.Files.getDownloadUrl(files, dir || this.getCurrentDirectory());
+ getDownloadUrl: function(files, dir, isDir) {
+ return OCA.Files.Files.getDownloadUrl(files, dir || this.getCurrentDirectory(), isDir);
},
/**
@@ -1489,8 +1562,6 @@
if (etag){
// use etag as cache buster
urlSpec.c = etag;
- } else {
- console.warn('OCA.Files.FileList.lazyLoadPreview(): missing etag argument');
}
previewURL = self.generatePreviewUrl(urlSpec);
@@ -1514,6 +1585,9 @@
img.src = previewURL;
},
+ /**
+ * @deprecated
+ */
setDirectoryPermissions: function(permissions) {
var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
this.$el.find('#permissions').val(permissions);
@@ -1610,7 +1684,7 @@
* fileData should be inserted, considering the current
* sorting
*
- * @param {OCA.Files.FileInfo} fileData file info
+ * @param {OC.Files.FileInfo} fileData file info
*/
_findInsertionIndex: function(fileData) {
var index = 0;
@@ -1628,6 +1702,9 @@
move: function(fileNames, targetPath) {
var self = this;
var dir = this.getCurrentDirectory();
+ if (dir.charAt(dir.length - 1) !== '/') {
+ dir += '/';
+ }
var target = OC.basename(targetPath);
if (!_.isArray(fileNames)) {
fileNames = [fileNames];
@@ -1635,46 +1712,42 @@
_.each(fileNames, function(fileName) {
var $tr = self.findFileEl(fileName);
self.showFileBusyState($tr, true);
- // TODO: improve performance by sending all file names in a single call
- $.post(
- OC.filePath('files', 'ajax', 'move.php'),
- {
- dir: dir,
- file: fileName,
- target: targetPath
- },
- function(result) {
- if (result) {
- if (result.status === 'success') {
- // if still viewing the same directory
- if (self.getCurrentDirectory() === dir) {
- // recalculate folder size
- var oldFile = self.findFileEl(target);
- var newFile = self.findFileEl(fileName);
- var oldSize = oldFile.data('size');
- var newSize = oldSize + newFile.data('size');
- oldFile.data('size', newSize);
- oldFile.find('td.filesize').text(OC.Util.humanFileSize(newSize));
-
- // TODO: also update entry in FileList.files
-
- self.remove(fileName);
- }
- } else {
- OC.Notification.hide();
- if (result.status === 'error' && result.data.message) {
- OC.Notification.showTemporary(result.data.message);
- }
- else {
- OC.Notification.showTemporary(t('files', 'Error moving file.'));
- }
- }
+ if (targetPath.charAt(targetPath.length - 1) !== '/') {
+ // make sure we move the files into the target dir,
+ // not overwrite it
+ targetPath = targetPath + '/';
+ }
+ self.filesClient.move(dir + fileName, targetPath + fileName)
+ .done(function() {
+ // if still viewing the same directory
+ if (OC.joinPaths(self.getCurrentDirectory(), '/') === dir) {
+ // recalculate folder size
+ var oldFile = self.findFileEl(target);
+ var newFile = self.findFileEl(fileName);
+ var oldSize = oldFile.data('size');
+ var newSize = oldSize + newFile.data('size');
+ oldFile.data('size', newSize);
+ oldFile.find('td.filesize').text(OC.Util.humanFileSize(newSize));
+
+ // TODO: also update entry in FileList.files
+ self.remove(fileName);
+ }
+ })
+ .fail(function(status) {
+ if (status === 412) {
+ // TODO: some day here we should invoke the conflict dialog
+ OC.Notification.showTemporary(
+ t('files', 'Could not move "{file}", target exists', {file: fileName})
+ );
} else {
- OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
+ OC.Notification.showTemporary(
+ t('files', 'Could not move "{file}"', {file: fileName})
+ );
}
+ })
+ .always(function() {
self.showFileBusyState($tr, false);
- }
- );
+ });
});
},
@@ -1691,7 +1764,9 @@
updateRow: function($tr, fileInfo, options) {
this.files.splice($tr.index(), 1);
$tr.remove();
- $tr = this.add(fileInfo, _.extend({updateSummary: false, silent: true}, options));
+ options = _.extend({silent: true}, options);
+ options = _.extend(options, {updateSummary: false});
+ $tr = this.add(fileInfo, options);
this.$fileList.trigger($.Event('fileActionsReady', {fileList: this, $files: $tr}));
return $tr;
},
@@ -1700,16 +1775,16 @@
* Triggers file rename input field for the given file name.
* If the user enters a new name, the file will be renamed.
*
- * @param oldname file name of the file to rename
+ * @param oldName file name of the file to rename
*/
- rename: function(oldname) {
+ rename: function(oldName) {
var self = this;
var tr, td, input, form;
- tr = this.findFileEl(oldname);
+ tr = this.findFileEl(oldName);
var oldFileInfo = this.files[tr.index()];
tr.data('renaming',true);
td = tr.children('td.filename');
- input = $('<input type="text" class="filename"/>').val(oldname);
+ input = $('<input type="text" class="filename"/>').val(oldName);
form = $('<form></form>');
form.append(input);
td.children('a.name').hide();
@@ -1724,11 +1799,11 @@
input.selectRange(0, len);
var checkInput = function () {
var filename = input.val();
- if (filename !== oldname) {
+ if (filename !== oldName) {
// Files.isFileNameValid(filename) throws an exception itself
OCA.Files.Files.isFileNameValid(filename);
if (self.inList(filename)) {
- throw t('files', '{new_name} already exists', {new_name: filename});
+ throw t('files', '{newName} already exists', {newName: filename});
}
}
return true;
@@ -1741,6 +1816,12 @@
td.children('a.name').show();
}
+ function updateInList(fileInfo) {
+ self.updateRow(tr, fileInfo);
+ self._updateDetailsView(fileInfo.name, false);
+ }
+
+ // TODO: too many nested blocks, move parts into functions
form.submit(function(event) {
event.stopPropagation();
event.preventDefault();
@@ -1753,7 +1834,7 @@
input.tooltip('hide');
form.remove();
- if (newName !== oldname) {
+ if (newName !== oldName) {
checkInput();
// mark as loading (temp element)
self.showFileBusyState(tr, true);
@@ -1765,34 +1846,45 @@
td.find('a.name span.nametext').text(basename);
td.children('a.name').show();
- $.ajax({
- url: OC.filePath('files','ajax','rename.php'),
- data: {
- dir : tr.attr('data-path') || self.getCurrentDirectory(),
- newname: newName,
- file: oldname
- },
- success: function(result) {
- var fileInfo;
- if (!result || result.status === 'error') {
- OC.dialogs.alert(result.data.message, t('files', 'Could not rename file'));
- fileInfo = oldFileInfo;
- if (result.data.code === 'sourcenotfound') {
- self.remove(result.data.newname, {updateSummary: true});
- return;
- }
- }
- else {
- fileInfo = result.data;
+ var path = tr.attr('data-path') || self.getCurrentDirectory();
+ self.filesClient.move(OC.joinPaths(path, oldName), OC.joinPaths(path, newName))
+ .done(function() {
+ oldFileInfo.name = newName;
+ updateInList(oldFileInfo);
+ })
+ .fail(function(status) {
+ // TODO: 409 means current folder does not exist, redirect ?
+ if (status === 404) {
+ // source not found, so remove it from the list
+ OC.Notification.showTemporary(
+ t(
+ 'files',
+ 'Could not rename "{fileName}", it does not exist any more',
+ {fileName: oldName}
+ )
+ );
+ self.remove(newName, {updateSummary: true});
+ return;
+ } else if (status === 412) {
+ // target exists
+ OC.Notification.showTemporary(
+ t(
+ 'files',
+ 'The name "{targetName}" is already used in the folder "{dir}". Please choose a different name.',
+ {
+ targetName: newName,
+ dir: self.getCurrentDirectory()
+ }
+ )
+ );
+ } else {
+ // restore the item to its previous state
+ OC.Notification.showTemporary(
+ t('files', 'Could not rename "{fileName}"', {fileName: oldName})
+ );
}
- // reinsert row
- self.files.splice(tr.index(), 1);
- tr.remove();
- tr = self.add(fileInfo, {updateSummary: false, silent: true});
- self.$fileList.trigger($.Event('fileActionsReady', {fileList: self, $files: $(tr)}));
- self._updateDetailsView(fileInfo.name, false);
- }
- });
+ updateInList(oldFileInfo);
+ });
} else {
// add back the old file info when cancelled
self.files.splice(tr.index(), 1);
@@ -1849,32 +1941,48 @@
var promise = deferred.promise();
OCA.Files.Files.isFileNameValid(name);
- name = this.getUniqueName(name);
if (this.lastAction) {
this.lastAction();
}
- $.post(
- OC.generateUrl('/apps/files/ajax/newfile.php'),
- {
- dir: this.getCurrentDirectory(),
- filename: name
- },
- function(result) {
- if (result.status === 'success') {
- self.add(result.data, {animate: true, scrollTo: true});
- deferred.resolve(result.status, result.data);
+ name = this.getUniqueName(name);
+ var targetPath = this.getCurrentDirectory() + '/' + name;
+
+ self.filesClient.putFileContents(
+ targetPath,
+ '',
+ {
+ contentType: 'text/plain',
+ overwrite: true
+ }
+ )
+ .done(function() {
+ // TODO: error handling / conflicts
+ self.filesClient.getFileInfo(
+ targetPath, {
+ properties: self._getWebdavProperties()
+ }
+ )
+ .then(function(status, data) {
+ self.add(data, {animate: true, scrollTo: true});
+ deferred.resolve(status, data);
+ })
+ .fail(function(status) {
+ OC.Notification.showTemporary(t('files', 'Could not create file "{file}"', {file: name}));
+ deferred.reject(status);
+ });
+ })
+ .fail(function(status) {
+ if (status === 412) {
+ OC.Notification.showTemporary(
+ t('files', 'Could not create file "{file}" because it already exists', {file: name})
+ );
} else {
- if (result.data && result.data.message) {
- OC.Notification.showTemporary(result.data.message);
- } else {
- OC.Notification.showTemporary(t('core', 'Could not create file'));
- }
- deferred.reject(result.status, result.data);
+ OC.Notification.showTemporary(t('files', 'Could not create file "{file}"', {file: name}));
}
- }
- );
+ deferred.reject(status);
+ });
return promise;
},
@@ -1895,32 +2003,58 @@
var promise = deferred.promise();
OCA.Files.Files.isFileNameValid(name);
- name = this.getUniqueName(name);
if (this.lastAction) {
this.lastAction();
}
- $.post(
- OC.generateUrl('/apps/files/ajax/newfolder.php'),
- {
- dir: this.getCurrentDirectory(),
- foldername: name
- },
- function(result) {
- if (result.status === 'success') {
- self.add(result.data, {animate: true, scrollTo: true});
- deferred.resolve(result.status, result.data);
+ name = this.getUniqueName(name);
+ var targetPath = this.getCurrentDirectory() + '/' + name;
+
+ this.filesClient.createDirectory(targetPath)
+ .done(function(createStatus) {
+ self.filesClient.getFileInfo(
+ targetPath, {
+ properties: self._getWebdavProperties()
+ }
+ )
+ .done(function(status, data) {
+ self.add(data, {animate: true, scrollTo: true});
+ deferred.resolve(status, data);
+ })
+ .fail(function() {
+ OC.Notification.showTemporary(t('files', 'Could not create folder "{dir}"', {dir: name}));
+ deferred.reject(createStatus);
+ });
+ })
+ .fail(function(createStatus) {
+ // method not allowed, folder might exist already
+ if (createStatus === 405) {
+ self.filesClient.getFileInfo(
+ targetPath, {
+ properties: self._getWebdavProperties()
+ }
+ )
+ .done(function(status, data) {
+ // add it to the list, for completeness
+ self.add(data, {animate: true, scrollTo: true});
+ OC.Notification.showTemporary(
+ t('files', 'Could not create folder "{dir}" because it already exists', {dir: name})
+ );
+ // still consider a failure
+ deferred.reject(createStatus, data);
+ })
+ .fail(function() {
+ OC.Notification.showTemporary(
+ t('files', 'Could not create folder "{dir}"', {dir: name})
+ );
+ deferred.reject(status);
+ });
} else {
- if (result.data && result.data.message) {
- OC.Notification.showTemporary(result.data.message);
- } else {
- OC.Notification.showTemporary(t('core', 'Could not create folder'));
- }
- deferred.reject(result.status);
+ OC.Notification.showTemporary(t('files', 'Could not create folder "{dir}"', {dir: name}));
+ deferred.reject(createStatus);
}
- }
- );
+ });
return promise;
},
@@ -1946,7 +2080,7 @@
*/
showFileBusyState: function(files, state) {
var self = this;
- if (!_.isArray(files)) {
+ if (!_.isArray(files) && !files.is) {
files = [files];
}
@@ -1954,10 +2088,13 @@
state = true;
}
- _.each(files, function($tr) {
+ _.each(files, function(fileName) {
// jquery element already ?
- if (!$tr.is) {
- $tr = self.findFileEl($tr);
+ var $tr;
+ if (_.isString(fileName)) {
+ $tr = self.findFileEl(fileName);
+ } else {
+ $tr = $(fileName);
}
var $thumbEl = $tr.find('.thumbnail');
@@ -1981,76 +2118,59 @@
*/
do_delete:function(files, dir) {
var self = this;
- var params;
if (files && files.substr) {
files=[files];
}
+ if (!files) {
+ // delete all files in directory
+ files = _.pluck(this.files, 'name');
+ }
if (files) {
this.showFileBusyState(files, true);
- for (var i=0; i<files.length; i++) {
- }
}
// Finish any existing actions
if (this.lastAction) {
this.lastAction();
}
- params = {
- dir: dir || this.getCurrentDirectory()
- };
- if (files) {
- params.files = JSON.stringify(files);
+ dir = dir || this.getCurrentDirectory();
+
+ function removeFromList(file) {
+ var fileEl = self.remove(file, {updateSummary: false});
+ // FIXME: not sure why we need this after the
+ // element isn't even in the DOM any more
+ fileEl.find('.selectCheckBox').prop('checked', false);
+ fileEl.removeClass('selected');
+ self.fileSummary.remove({type: fileEl.attr('data-type'), size: fileEl.attr('data-size')});
+ // TODO: this info should be returned by the ajax call!
+ self.updateEmptyContent();
+ self.fileSummary.update();
+ self.updateSelectionSummary();
+ // FIXME: don't repeat this, do it once all files are done
+ self.updateStorageStatistics();
}
- else {
- // no files passed, delete all in current dir
- params.allfiles = true;
- // show spinner for all files
- this.showFileBusyState(this.$fileList.find('tr'), true);
- }
-
- $.post(OC.filePath('files', 'ajax', 'delete.php'),
- params,
- function(result) {
- if (result.status === 'success') {
- if (params.allfiles) {
- self.setFiles([]);
- }
- else {
- $.each(files,function(index,file) {
- var fileEl = self.remove(file, {updateSummary: false});
- // FIXME: not sure why we need this after the
- // element isn't even in the DOM any more
- fileEl.find('.selectCheckBox').prop('checked', false);
- fileEl.removeClass('selected');
- self.fileSummary.remove({type: fileEl.attr('data-type'), size: fileEl.attr('data-size')});
- });
- }
- // TODO: this info should be returned by the ajax call!
- self.updateEmptyContent();
- self.fileSummary.update();
- self.updateSelectionSummary();
- self.updateStorageStatistics();
- // in case there was a "storage full" permanent notification
- OC.Notification.hide();
+
+ _.each(files, function(file) {
+ self.filesClient.remove(dir + '/' + file)
+ .done(function() {
+ removeFromList(file);
+ })
+ .fail(function(status) {
+ if (status === 404) {
+ // the file already did not exist, remove it from the list
+ removeFromList(file);
} else {
- if (result.status === 'error' && result.data.message) {
- OC.Notification.showTemporary(result.data.message);
- }
- else {
- OC.Notification.showTemporary(t('files', 'Error deleting file.'));
- }
- if (params.allfiles) {
- // reload the page as we don't know what files were deleted
- // and which ones remain
- self.reload();
- }
- else {
- $.each(files,function(index,file) {
- self.showFileBusyState(file, false);
- });
- }
+ // only reset the spinner for that one file
+ OC.Notification.showTemporary(
+ t('files', 'Error deleting file "{fileName}".', {fileName: file}),
+ {timeout: 10}
+ );
+ var deleteAction = self.findFileEl(file).find('.action.delete');
+ deleteAction.removeClass('icon-loading-small').addClass('icon-delete');
+ self.showFileBusyState(files, false);
}
});
+ });
},
/**
* Creates the file summary section
@@ -2185,7 +2305,6 @@
*/
updateSelectionSummary: function() {
var summary = this._selectionSummary.summary;
- var canDelete;
var selection;
if (summary.totalFiles === 0 && summary.totalDirs === 0) {
@@ -2196,7 +2315,6 @@
this.$el.find('.selectedActions').addClass('hidden');
}
else {
- canDelete = (this.getDirectoryPermissions() & OC.PERMISSION_DELETE) && this.isSelectedDeletable();
this.$el.find('.selectedActions').removeClass('hidden');
this.$el.find('#headerSize a>span:first').text(OC.Util.humanFileSize(summary.totalSize));
@@ -2218,7 +2336,7 @@
this.$el.find('#headerName a.name>span:first').text(selection);
this.$el.find('#modified a>span:first').text('');
this.$el.find('table').addClass('multiselect');
- this.$el.find('.delete-selected').toggleClass('hidden', !canDelete);
+ this.$el.find('.delete-selected').toggleClass('hidden', !this.isSelectedDeletable());
}
},
@@ -2359,6 +2477,7 @@
}
});
fileUploadStart.on('fileuploadadd', function(e, data) {
+ console.log('XXXXXXX');
OC.Upload.log('filelist handle fileuploadadd', e, data);
//finish delete if we are uploading a deleted file
@@ -2378,8 +2497,7 @@
var translatedText = n('files', 'Uploading %n file', 'Uploading %n files', currentUploads);
if (currentUploads === 1) {
- var img = OC.imagePath('core', 'loading.gif');
- data.context.find('.thumbnail').css('background-image', 'url(' + img + ')');
+ self.showFileBusyState(uploadText.closest('tr'), true);
uploadText.text(translatedText);
uploadText.show();
} else {
@@ -2417,8 +2535,7 @@
uploadText.attr('currentUploads', currentUploads);
var translatedText = n('files', 'Uploading %n file', 'Uploading %n files', currentUploads);
if (currentUploads === 0) {
- var img = OC.imagePath('core', 'filetypes/folder');
- data.context.find('.thumbnail').css('background-image', 'url(' + img + ')');
+ self.showFileBusyState(uploadText.closest('tr'), false);
uploadText.text(translatedText);
uploadText.hide();
} else {
@@ -2495,18 +2612,15 @@
}
}
});
- fileUploadStart.on('fileuploadstop', function(e, data) {
- OC.Upload.log('filelist handle fileuploadstop', e, data);
+ fileUploadStart.on('fileuploadstop', function() {
+ OC.Upload.log('filelist handle fileuploadstop');
+
+ //cleanup uploading to a dir
+ var uploadText = self.$fileList.find('tr .uploadtext');
+ self.showFileBusyState(uploadText.closest('tr'), false);
+ uploadText.fadeOut();
+ uploadText.attr('currentUploads', 0);
- //if user pressed cancel hide upload chrome
- if (data.errorThrown === 'abort') {
- //cleanup uploading to a dir
- var uploadText = $('tr .uploadtext');
- var img = OC.imagePath('core', 'filetypes/folder');
- uploadText.parents('td.filename').find('.thumbnail').css('background-image', 'url(' + img + ')');
- uploadText.fadeOut();
- uploadText.attr('currentUploads', 0);
- }
self.updateStorageStatistics();
});
fileUploadStart.on('fileuploadfail', function(e, data) {
@@ -2515,9 +2629,8 @@
//if user pressed cancel hide upload chrome
if (data.errorThrown === 'abort') {
//cleanup uploading to a dir
- var uploadText = $('tr .uploadtext');
- var img = OC.imagePath('core', 'filetypes/folder');
- uploadText.parents('td.filename').find('.thumbnail').css('background-image', 'url(' + img + ')');
+ var uploadText = self.$fileList.find('tr .uploadtext');
+ self.showFileBusyState(uploadText.closest('tr'), false);
uploadText.fadeOut();
uploadText.attr('currentUploads', 0);
}
@@ -2659,8 +2772,8 @@
* Compares two file infos by name, making directories appear
* first.
*
- * @param {OCA.Files.FileInfo} fileInfo1 file info
- * @param {OCA.Files.FileInfo} fileInfo2 file info
+ * @param {OC.Files.FileInfo} fileInfo1 file info
+ * @param {OC.Files.FileInfo} fileInfo2 file info
* @return {int} -1 if the first file must appear before the second one,
* 0 if they are identify, 1 otherwise.
*/
@@ -2676,8 +2789,8 @@
/**
* Compares two file infos by size.
*
- * @param {OCA.Files.FileInfo} fileInfo1 file info
- * @param {OCA.Files.FileInfo} fileInfo2 file info
+ * @param {OC.Files.FileInfo} fileInfo1 file info
+ * @param {OC.Files.FileInfo} fileInfo2 file info
* @return {int} -1 if the first file must appear before the second one,
* 0 if they are identify, 1 otherwise.
*/
@@ -2687,8 +2800,8 @@
/**
* Compares two file infos by timestamp.
*
- * @param {OCA.Files.FileInfo} fileInfo1 file info
- * @param {OCA.Files.FileInfo} fileInfo2 file info
+ * @param {OC.Files.FileInfo} fileInfo1 file info
+ * @param {OC.Files.FileInfo} fileInfo2 file info
* @return {int} -1 if the first file must appear before the second one,
* 0 if they are identify, 1 otherwise.
*/
@@ -2700,23 +2813,14 @@
/**
* File info attributes.
*
- * @todo make this a real class in the future
- * @typedef {Object} OCA.Files.FileInfo
+ * @typedef {Object} OC.Files.FileInfo
+ *
+ * @lends OC.Files.FileInfo
+ *
+ * @deprecated use OC.Files.FileInfo instead
*
- * @property {int} id file id
- * @property {String} name file name
- * @property {String} [path] file path, defaults to the list's current path
- * @property {String} mimetype mime type
- * @property {String} type "file" for files or "dir" for directories
- * @property {int} permissions file permissions
- * @property {int} mtime modification time in milliseconds
- * @property {boolean} [isShareMountPoint] whether the file is a share mount
- * point
- * @property {boolean} [isPreviewAvailable] whether a preview is available
- * for the given file type
- * @property {String} [icon] path to the mime type icon
- * @property {String} etag etag of the file
*/
+ OCA.Files.FileInfo = OC.Files.FileInfo;
OCA.Files.FileList = FileList;
})();
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index ae38511ec05..3b70e283749 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -136,13 +136,27 @@
/**
* Returns the download URL of the given file(s)
- * @param filename string or array of file names to download
- * @param dir optional directory in which the file name is, defaults to the current directory
+ * @param {string} filename string or array of file names to download
+ * @param {string} [dir] optional directory in which the file name is, defaults to the current directory
+ * @param {bool} [isDir=false] whether the given filename is a directory and might need a special URL
*/
- getDownloadUrl: function(filename, dir) {
- if ($.isArray(filename)) {
+ getDownloadUrl: function(filename, dir, isDir) {
+ if (!_.isArray(filename) && !isDir) {
+ var pathSections = dir.split('/');
+ pathSections.push(filename);
+ var encodedPath = '';
+ _.each(pathSections, function(section) {
+ if (section !== '') {
+ encodedPath += '/' + encodeURIComponent(section);
+ }
+ });
+ return OC.linkToRemoteBase('webdav') + encodedPath;
+ }
+
+ if (_.isArray(filename)) {
filename = JSON.stringify(filename);
}
+
var params = {
dir: dir,
files: filename
@@ -193,7 +207,7 @@
*/
lazyLoadPreview : function(path, mime, ready, width, height, etag) {
console.warn('DEPRECATED: please use lazyLoadPreview() from an OCA.Files.FileList instance');
- return OCA.Files.App.fileList.lazyLoadPreview({
+ return FileList.lazyLoadPreview({
path: path,
mime: mime,
callback: ready,
@@ -229,9 +243,6 @@
e.preventDefault(); // prevent browser from doing anything, if file isn't dropped in dropZone
});
- //do a background scan if needed
- scanFiles();
-
// display storage warnings
setTimeout(Files.displayStorageWarnings, 100);
@@ -260,8 +271,9 @@
}
- $('#webdavurl').on('click', function () {
- $('#webdavurl').select();
+ $('#webdavurl').on('click touchstart', function () {
+ this.focus();
+ this.setSelectionRange(0, this.value.length);
});
$('#upload').tooltip({placement:'right'});
@@ -309,55 +321,12 @@
OCA.Files.Files = Files;
})();
-function scanFiles(force, dir, users) {
- if (!OC.currentUser) {
- return;
- }
-
- if (!dir) {
- dir = '';
- }
- force = !!force; //cast to bool
- scanFiles.scanning = true;
- var scannerEventSource;
- if (users) {
- var usersString;
- if (users === 'all') {
- usersString = users;
- } else {
- usersString = JSON.stringify(users);
- }
- scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force: force,dir: dir, users: usersString});
- } else {
- scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force: force,dir: dir});
- }
- scanFiles.cancel = scannerEventSource.close.bind(scannerEventSource);
- scannerEventSource.listen('count',function(count) {
- console.log(count + ' files scanned');
- });
- scannerEventSource.listen('folder',function(path) {
- console.log('now scanning ' + path);
- });
- scannerEventSource.listen('error',function(message) {
- console.error('Scanner error: ', message);
- });
- scannerEventSource.listen('done',function(count) {
- scanFiles.scanning=false;
- console.log('done after ' + count + ' files');
- if (OCA.Files.App) {
- OCA.Files.App.fileList.updateStorageStatistics(true);
- }
- });
- scannerEventSource.listen('user',function(user) {
- console.log('scanning files for ' + user);
- });
-}
-scanFiles.scanning=false;
-
// TODO: move to FileList
var createDragShadow = function(event) {
+ // FIXME: inject file list instance somehow
+ /* global FileList, Files */
+
//select dragged file
- var FileList = OCA.Files.App.fileList;
var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked');
if (!isDragSelected) {
//select dragged file
@@ -394,7 +363,7 @@ var createDragShadow = function(event) {
.css('background-image', 'url(' + OC.imagePath('core', 'filetypes/folder.png') + ')');
} else {
var path = dir + '/' + elem.name;
- OCA.Files.App.files.lazyLoadPreview(path, elem.mime, function(previewpath) {
+ Files.lazyLoadPreview(path, elem.mimetype, function(previewpath) {
newtr.find('td.filename')
.css('background-image', 'url(' + previewpath + ')');
}, null, null, elem.etag);
@@ -441,7 +410,7 @@ var folderDropOptions = {
hoverClass: "canDrop",
drop: function( event, ui ) {
// don't allow moving a file into a selected folder
- var FileList = OCA.Files.App.fileList;
+ /* global FileList */
if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) {
return false;
}
diff --git a/apps/files/js/newfilemenu.js b/apps/files/js/newfilemenu.js
index 175eb1d1a75..be7dcc40b6e 100644
--- a/apps/files/js/newfilemenu.js
+++ b/apps/files/js/newfilemenu.js
@@ -44,6 +44,11 @@
'click .menuitem': '_onClickAction'
},
+ /**
+ * @type OCA.Files.FileList
+ */
+ fileList: null,
+
initialize: function(options) {
var self = this;
var $uploadEl = $('#file_upload_start');
@@ -55,25 +60,16 @@
console.warn('Missing upload element "file_upload_start"');
}
- this._fileList = options && options.fileList;
+ this.fileList = options && options.fileList;
this._menuItems = [{
- id: 'file',
- displayName: t('files', 'Text file'),
- templateName: t('files', 'New text file.txt'),
- iconClass: 'icon-filetype-text',
- fileType: 'file',
- actionHandler: function(name) {
- self._fileList.createFile(name);
- }
- }, {
id: 'folder',
displayName: t('files', 'Folder'),
templateName: t('files', 'New folder'),
iconClass: 'icon-folder',
fileType: 'folder',
actionHandler: function(name) {
- self._fileList.createDirectory(name);
+ self.fileList.createDirectory(name);
}
}];
@@ -149,7 +145,7 @@
try {
if (!Files.isFileNameValid(filename)) {
// Files.isFileNameValid(filename) throws an exception itself
- } else if (self._fileList.inList(filename)) {
+ } else if (self.fileList.inList(filename)) {
throw t('files', '{newname} already exists', {newname: filename});
} else {
return true;
diff --git a/apps/files/js/tagsplugin.js b/apps/files/js/tagsplugin.js
index 23945d52603..81b22e34cc2 100644
--- a/apps/files/js/tagsplugin.js
+++ b/apps/files/js/tagsplugin.js
@@ -161,6 +161,38 @@
fileInfo.tags = tags;
return fileInfo;
};
+
+ var NS_OC = 'http://owncloud.org/ns';
+
+ var oldGetWebdavProperties = fileList._getWebdavProperties;
+ fileList._getWebdavProperties = function() {
+ var props = oldGetWebdavProperties.apply(this, arguments);
+ props.push('{' + NS_OC + '}tags');
+ props.push('{' + NS_OC + '}favorite');
+ return props;
+ };
+
+ fileList.filesClient.addFileInfoParser(function(response) {
+ var data = {};
+ var props = response.propStat[0].properties;
+ var tags = props['{' + NS_OC + '}tags'];
+ var favorite = props['{' + NS_OC + '}favorite'];
+ if (tags && tags.length) {
+ tags = _.chain(tags).filter(function(xmlvalue) {
+ return (xmlvalue.namespaceURI === NS_OC && xmlvalue.nodeName.split(':')[1] === 'tag');
+ }).map(function(xmlvalue) {
+ return xmlvalue.textContent || xmlvalue.text;
+ }).value();
+ }
+ if (tags) {
+ data.tags = tags;
+ }
+ if (favorite && parseInt(favorite, 10) !== 0) {
+ data.tags = data.tags || [];
+ data.tags.push(OC.TAG_FAVORITE);
+ }
+ return data;
+ });
},
attach: function(fileList) {
diff --git a/apps/files/l10n/af_ZA.js b/apps/files/l10n/af_ZA.js
index 2061e5ec49c..7e5e98ed493 100644
--- a/apps/files/l10n/af_ZA.js
+++ b/apps/files/l10n/af_ZA.js
@@ -1,7 +1,7 @@
OC.L10N.register(
"files",
{
- "Error" : "Fout",
+ "Unshare" : "Deel terug neem",
"Folder" : "Omslag",
"Settings" : "Instellings"
},
diff --git a/apps/files/l10n/af_ZA.json b/apps/files/l10n/af_ZA.json
index 95096fd551b..1f27a43719c 100644
--- a/apps/files/l10n/af_ZA.json
+++ b/apps/files/l10n/af_ZA.json
@@ -1,5 +1,5 @@
{ "translations": {
- "Error" : "Fout",
+ "Unshare" : "Deel terug neem",
"Folder" : "Omslag",
"Settings" : "Instellings"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/files/l10n/ar.js b/apps/files/l10n/ar.js
index b4414525c68..a2329a0b57d 100644
--- a/apps/files/l10n/ar.js
+++ b/apps/files/l10n/ar.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "وحدة التخزين غير متوفرة ",
"Storage invalid" : "وحدة تخزين غير صالحه ",
"Unknown error" : "خطأ غير معروف. ",
- "Could not move %s - File with this name already exists" : "فشل في نقل الملف %s - يوجد ملف بنفس هذا الاسم",
- "Could not move %s" : "فشل في نقل %s",
- "Permission denied" : "تم رفض الاذن ",
- "The target folder has been moved or deleted." : "المجلد المطلوب قد تم نقله او حذفه ",
- "The name %s is already used in the folder %s. Please choose a different name." : "هذا الاسم %s مستخدم مسبقا في المجلد %s . فضلا اختر اسم مختلف .",
- "Error when creating the file" : "خطأ اثناء انشاء الملف ",
- "Error when creating the folder" : "خطأ اثناء انشاء المجلد ",
"Unable to set upload directory." : "غير قادر على تحميل المجلد",
"Invalid Token" : "علامة غير صالحة",
"No file was uploaded. Unknown error" : "لم يتم رفع أي ملف , خطأ غير معروف",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "المجلد المؤقت غير موجود",
"Failed to write to disk" : "خطأ في الكتابة على القرص الصلب",
"Not enough storage available" : "لا يوجد مساحة تخزينية كافية",
+ "The target folder has been moved or deleted." : "المجلد المطلوب قد تم نقله او حذفه ",
"Upload failed. Could not find uploaded file" : "*فشلت علمية الرفع. تعذر إيجاد الملف الذي تم رفعه.\n*فشلت علمية التحميل. تعذر إيجاد الملف الذي تم تحميله.",
"Upload failed. Could not get file info." : "فشلت عملية الرفع. تعذر الحصول على معلومات الملف.",
"Invalid directory." : "مسار غير صحيح.",
@@ -40,19 +34,12 @@ OC.L10N.register(
"Download" : "تحميل",
"Rename" : "إعادة التسمية",
"Delete" : "حذف ",
+ "Unshare" : "إلغاء المشاركة",
"Details" : "تفاصيل",
"Select" : "اختار",
"Pending" : "قيد الانتظار",
"Unable to determine date" : "تعذر تحديد التاريخ",
"This operation is forbidden" : "هذة العملية ممنوعة ",
- "Error moving file." : "خطأ اثناء نقل الملف ",
- "Error moving file" : "حدث خطأ أثناء نقل الملف",
- "Error" : "خطأ",
- "{new_name} already exists" : "{new_name} موجود مسبقا",
- "Could not rename file" : "لا يستطيع اعادة تسمية الملف",
- "Could not create file" : "لا يستطيع انشاء ملف ",
- "Could not create folder" : "لا يستطيع انشاء مجلد ",
- "Error deleting file." : "خطأ اثناء حذف الملف ",
"No entries in this folder match '{filter}'" : "لا يوجد مدخلات في هذا المجلد تتوافق مع '{filter}'",
"Name" : "اسم",
"Size" : "حجم",
@@ -70,8 +57,6 @@ OC.L10N.register(
"Storage of {owner} is almost full ({usedSpacePercent}%)" : "المساحة التخزينية لـ {owner} ممتلئة تقريبا ({usedSpacePercent}%)",
"Your storage is almost full ({usedSpacePercent}%)" : "مساحتك التخزينية امتلأت تقريبا ",
"Favorite" : "المفضلة",
- "Text file" : "ملف نصي",
- "New text file.txt" : "ملف نصي جديد fille.txt",
"Folder" : "مجلد",
"New folder" : "مجلد جديد",
"{newname} already exists" : "{newname} موجود مسبقاً",
@@ -90,8 +75,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s حذف %1$s",
"You restored %1$s" : "لقد قمت باستعادة %1$s",
"%2$s restored %1$s" : "%2$s مستعاد %1$s",
- "%s could not be renamed as it has been deleted" : "%s لا يمكن اعادة تسميته فقد تم حذفه ",
- "%s could not be renamed" : "%s لا يمكن إعادة تسميته. ",
"Upload (max. %s)" : "الرفع ( حد اقصى. %s ) ",
"File handling" : "التعامل مع الملف",
"Maximum upload size" : "الحد الأقصى لحجم الملفات التي يمكن رفعها",
@@ -107,9 +90,9 @@ OC.L10N.register(
"Select all" : "تحديد الكل ",
"Upload too large" : "حجم الترفيع أعلى من المسموح",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "حجم الملفات التي تريد ترفيعها أعلى من المسموح على الخادم.",
- "Files are being scanned, please wait." : "يرجى الانتظار , جاري فحص الملفات .",
- "Currently scanning" : "حالياً يقوم بالفحص",
"No favorites" : "لا يوجد مفضلات ",
- "Files and folders you mark as favorite will show up here" : "الملفات والمجلدات التي حددتها كامفضلة سوف تظهر هنا "
+ "Files and folders you mark as favorite will show up here" : "الملفات والمجلدات التي حددتها كامفضلة سوف تظهر هنا ",
+ "Text file" : "ملف نصي",
+ "New text file.txt" : "ملف نصي جديد fille.txt"
},
"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");
diff --git a/apps/files/l10n/ar.json b/apps/files/l10n/ar.json
index 0783c769ee1..fbc3f2e21d5 100644
--- a/apps/files/l10n/ar.json
+++ b/apps/files/l10n/ar.json
@@ -2,13 +2,6 @@
"Storage not available" : "وحدة التخزين غير متوفرة ",
"Storage invalid" : "وحدة تخزين غير صالحه ",
"Unknown error" : "خطأ غير معروف. ",
- "Could not move %s - File with this name already exists" : "فشل في نقل الملف %s - يوجد ملف بنفس هذا الاسم",
- "Could not move %s" : "فشل في نقل %s",
- "Permission denied" : "تم رفض الاذن ",
- "The target folder has been moved or deleted." : "المجلد المطلوب قد تم نقله او حذفه ",
- "The name %s is already used in the folder %s. Please choose a different name." : "هذا الاسم %s مستخدم مسبقا في المجلد %s . فضلا اختر اسم مختلف .",
- "Error when creating the file" : "خطأ اثناء انشاء الملف ",
- "Error when creating the folder" : "خطأ اثناء انشاء المجلد ",
"Unable to set upload directory." : "غير قادر على تحميل المجلد",
"Invalid Token" : "علامة غير صالحة",
"No file was uploaded. Unknown error" : "لم يتم رفع أي ملف , خطأ غير معروف",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "المجلد المؤقت غير موجود",
"Failed to write to disk" : "خطأ في الكتابة على القرص الصلب",
"Not enough storage available" : "لا يوجد مساحة تخزينية كافية",
+ "The target folder has been moved or deleted." : "المجلد المطلوب قد تم نقله او حذفه ",
"Upload failed. Could not find uploaded file" : "*فشلت علمية الرفع. تعذر إيجاد الملف الذي تم رفعه.\n*فشلت علمية التحميل. تعذر إيجاد الملف الذي تم تحميله.",
"Upload failed. Could not get file info." : "فشلت عملية الرفع. تعذر الحصول على معلومات الملف.",
"Invalid directory." : "مسار غير صحيح.",
@@ -38,19 +32,12 @@
"Download" : "تحميل",
"Rename" : "إعادة التسمية",
"Delete" : "حذف ",
+ "Unshare" : "إلغاء المشاركة",
"Details" : "تفاصيل",
"Select" : "اختار",
"Pending" : "قيد الانتظار",
"Unable to determine date" : "تعذر تحديد التاريخ",
"This operation is forbidden" : "هذة العملية ممنوعة ",
- "Error moving file." : "خطأ اثناء نقل الملف ",
- "Error moving file" : "حدث خطأ أثناء نقل الملف",
- "Error" : "خطأ",
- "{new_name} already exists" : "{new_name} موجود مسبقا",
- "Could not rename file" : "لا يستطيع اعادة تسمية الملف",
- "Could not create file" : "لا يستطيع انشاء ملف ",
- "Could not create folder" : "لا يستطيع انشاء مجلد ",
- "Error deleting file." : "خطأ اثناء حذف الملف ",
"No entries in this folder match '{filter}'" : "لا يوجد مدخلات في هذا المجلد تتوافق مع '{filter}'",
"Name" : "اسم",
"Size" : "حجم",
@@ -68,8 +55,6 @@
"Storage of {owner} is almost full ({usedSpacePercent}%)" : "المساحة التخزينية لـ {owner} ممتلئة تقريبا ({usedSpacePercent}%)",
"Your storage is almost full ({usedSpacePercent}%)" : "مساحتك التخزينية امتلأت تقريبا ",
"Favorite" : "المفضلة",
- "Text file" : "ملف نصي",
- "New text file.txt" : "ملف نصي جديد fille.txt",
"Folder" : "مجلد",
"New folder" : "مجلد جديد",
"{newname} already exists" : "{newname} موجود مسبقاً",
@@ -88,8 +73,6 @@
"%2$s deleted %1$s" : "%2$s حذف %1$s",
"You restored %1$s" : "لقد قمت باستعادة %1$s",
"%2$s restored %1$s" : "%2$s مستعاد %1$s",
- "%s could not be renamed as it has been deleted" : "%s لا يمكن اعادة تسميته فقد تم حذفه ",
- "%s could not be renamed" : "%s لا يمكن إعادة تسميته. ",
"Upload (max. %s)" : "الرفع ( حد اقصى. %s ) ",
"File handling" : "التعامل مع الملف",
"Maximum upload size" : "الحد الأقصى لحجم الملفات التي يمكن رفعها",
@@ -105,9 +88,9 @@
"Select all" : "تحديد الكل ",
"Upload too large" : "حجم الترفيع أعلى من المسموح",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "حجم الملفات التي تريد ترفيعها أعلى من المسموح على الخادم.",
- "Files are being scanned, please wait." : "يرجى الانتظار , جاري فحص الملفات .",
- "Currently scanning" : "حالياً يقوم بالفحص",
"No favorites" : "لا يوجد مفضلات ",
- "Files and folders you mark as favorite will show up here" : "الملفات والمجلدات التي حددتها كامفضلة سوف تظهر هنا "
+ "Files and folders you mark as favorite will show up here" : "الملفات والمجلدات التي حددتها كامفضلة سوف تظهر هنا ",
+ "Text file" : "ملف نصي",
+ "New text file.txt" : "ملف نصي جديد fille.txt"
},"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"
} \ No newline at end of file
diff --git a/apps/files/l10n/ast.js b/apps/files/l10n/ast.js
index 5dfcae172ea..2262d23345e 100644
--- a/apps/files/l10n/ast.js
+++ b/apps/files/l10n/ast.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Almacenamientu non disponible",
"Storage invalid" : "Almacenamientu inválidu",
"Unknown error" : "Fallu desconocíu",
- "Could not move %s - File with this name already exists" : "Nun pudo movese %s - Yá existe un ficheru con esi nome.",
- "Could not move %s" : "Nun pudo movese %s",
- "Permission denied" : "Permisu denegáu",
- "The target folder has been moved or deleted." : "La carpeta oxetivu movióse o desanicióse.",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nome %s yá ta n'usu na carpeta %s. Por favor, escueyi un nome diferente.",
- "Error when creating the file" : "Fallu cuando se creaba'l ficheru",
- "Error when creating the folder" : "Fallu cuando se creaba la carpeta",
"Unable to set upload directory." : "Nun pue afitase la carpeta de xubida.",
"Invalid Token" : "Token inválidu",
"No file was uploaded. Unknown error" : "Nun se xubió dengún ficheru. Fallu desconocíu",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Falta una carpeta temporal",
"Failed to write to disk" : "Fallu al escribir al discu",
"Not enough storage available" : "Nun hai abondu espaciu disponible",
+ "The target folder has been moved or deleted." : "La carpeta oxetivu movióse o desanicióse.",
"Upload failed. Could not find uploaded file" : "Xubida fallida. Nun pudo atopase'l ficheru xubíu.",
"Upload failed. Could not get file info." : "Falló la xubida. Nun se pudo obtener la información del ficheru.",
"Invalid directory." : "Direutoriu non válidu.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "Descargar",
"Rename" : "Renomar",
"Delete" : "Desaniciar",
+ "Disconnect storage" : "Desconeutar almacenamientu",
+ "Unshare" : "Dexar de compartir",
"Details" : "Detalles",
"Select" : "Esbillar",
"Pending" : "Pendiente",
"Unable to determine date" : "Imposible determinar la fecha",
"This operation is forbidden" : "La operación ta prohibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Esti direutoriu nun ta disponible, por favor verifica'l rexistru o contacta l'alministrador",
- "Error moving file." : "Fallu moviendo'l ficheru.",
- "Error moving file" : "Fallu moviendo'l ficheru",
- "Error" : "Fallu",
- "{new_name} already exists" : "{new_name} yá existe",
- "Could not rename file" : "Nun pudo renomase'l ficheru",
- "Could not create file" : "Nun pudo crease'l ficheru",
- "Could not create folder" : "Nun pudo crease la carpeta",
- "Error deleting file." : "Fallu desaniciando'l ficheru.",
"No entries in this folder match '{filter}'" : "Nun concasa nenguna entrada nesta carpeta '{filter}'",
"Name" : "Nome",
"Size" : "Tamañu",
@@ -75,8 +63,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n bytes","%n bytes"],
"Favorited" : "Favoritos",
"Favorite" : "Favoritu",
- "Text file" : "Ficheru de testu",
- "New text file.txt" : "Nuevu testu ficheru.txt",
"Folder" : "Carpeta",
"New folder" : "Nueva carpeta",
"{newname} already exists" : "{newname} yá existe",
@@ -99,8 +85,6 @@ OC.L10N.register(
"Changed by %2$s" : "Modificáu por %2$s",
"Deleted by %2$s" : "Desaniciáu por %2$s",
"Restored by %2$s" : "Recuperáu por %2$s",
- "%s could not be renamed as it has been deleted" : "%s nun pue renomase dempués de desaniciase",
- "%s could not be renamed" : "Nun se puede renomar %s ",
"Upload (max. %s)" : "Xuba (máx. %s)",
"File handling" : "Alministración de ficheros",
"Maximum upload size" : "Tamañu máximu de xubida",
@@ -116,9 +100,9 @@ OC.L10N.register(
"Select all" : "Esbillar too",
"Upload too large" : "La xuba ye abondo grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los ficheros que tas intentando xubir perpasen el tamañu máximu pa les xubíes de ficheros nesti servidor.",
- "Files are being scanned, please wait." : "Tan escaniándose los ficheros, espera por favor.",
- "Currently scanning" : "Anguaño escaneando",
"No favorites" : "Nengún favoritu",
- "Files and folders you mark as favorite will show up here" : "Los ficheros y carpetes que marque como favoritos apaecerán equí"
+ "Files and folders you mark as favorite will show up here" : "Los ficheros y carpetes que marque como favoritos apaecerán equí",
+ "Text file" : "Ficheru de testu",
+ "New text file.txt" : "Nuevu testu ficheru.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/ast.json b/apps/files/l10n/ast.json
index a0934808529..53a2c6f8d86 100644
--- a/apps/files/l10n/ast.json
+++ b/apps/files/l10n/ast.json
@@ -2,13 +2,6 @@
"Storage not available" : "Almacenamientu non disponible",
"Storage invalid" : "Almacenamientu inválidu",
"Unknown error" : "Fallu desconocíu",
- "Could not move %s - File with this name already exists" : "Nun pudo movese %s - Yá existe un ficheru con esi nome.",
- "Could not move %s" : "Nun pudo movese %s",
- "Permission denied" : "Permisu denegáu",
- "The target folder has been moved or deleted." : "La carpeta oxetivu movióse o desanicióse.",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nome %s yá ta n'usu na carpeta %s. Por favor, escueyi un nome diferente.",
- "Error when creating the file" : "Fallu cuando se creaba'l ficheru",
- "Error when creating the folder" : "Fallu cuando se creaba la carpeta",
"Unable to set upload directory." : "Nun pue afitase la carpeta de xubida.",
"Invalid Token" : "Token inválidu",
"No file was uploaded. Unknown error" : "Nun se xubió dengún ficheru. Fallu desconocíu",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Falta una carpeta temporal",
"Failed to write to disk" : "Fallu al escribir al discu",
"Not enough storage available" : "Nun hai abondu espaciu disponible",
+ "The target folder has been moved or deleted." : "La carpeta oxetivu movióse o desanicióse.",
"Upload failed. Could not find uploaded file" : "Xubida fallida. Nun pudo atopase'l ficheru xubíu.",
"Upload failed. Could not get file info." : "Falló la xubida. Nun se pudo obtener la información del ficheru.",
"Invalid directory." : "Direutoriu non válidu.",
@@ -38,20 +32,14 @@
"Download" : "Descargar",
"Rename" : "Renomar",
"Delete" : "Desaniciar",
+ "Disconnect storage" : "Desconeutar almacenamientu",
+ "Unshare" : "Dexar de compartir",
"Details" : "Detalles",
"Select" : "Esbillar",
"Pending" : "Pendiente",
"Unable to determine date" : "Imposible determinar la fecha",
"This operation is forbidden" : "La operación ta prohibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Esti direutoriu nun ta disponible, por favor verifica'l rexistru o contacta l'alministrador",
- "Error moving file." : "Fallu moviendo'l ficheru.",
- "Error moving file" : "Fallu moviendo'l ficheru",
- "Error" : "Fallu",
- "{new_name} already exists" : "{new_name} yá existe",
- "Could not rename file" : "Nun pudo renomase'l ficheru",
- "Could not create file" : "Nun pudo crease'l ficheru",
- "Could not create folder" : "Nun pudo crease la carpeta",
- "Error deleting file." : "Fallu desaniciando'l ficheru.",
"No entries in this folder match '{filter}'" : "Nun concasa nenguna entrada nesta carpeta '{filter}'",
"Name" : "Nome",
"Size" : "Tamañu",
@@ -73,8 +61,6 @@
"_%n byte_::_%n bytes_" : ["%n bytes","%n bytes"],
"Favorited" : "Favoritos",
"Favorite" : "Favoritu",
- "Text file" : "Ficheru de testu",
- "New text file.txt" : "Nuevu testu ficheru.txt",
"Folder" : "Carpeta",
"New folder" : "Nueva carpeta",
"{newname} already exists" : "{newname} yá existe",
@@ -97,8 +83,6 @@
"Changed by %2$s" : "Modificáu por %2$s",
"Deleted by %2$s" : "Desaniciáu por %2$s",
"Restored by %2$s" : "Recuperáu por %2$s",
- "%s could not be renamed as it has been deleted" : "%s nun pue renomase dempués de desaniciase",
- "%s could not be renamed" : "Nun se puede renomar %s ",
"Upload (max. %s)" : "Xuba (máx. %s)",
"File handling" : "Alministración de ficheros",
"Maximum upload size" : "Tamañu máximu de xubida",
@@ -114,9 +98,9 @@
"Select all" : "Esbillar too",
"Upload too large" : "La xuba ye abondo grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los ficheros que tas intentando xubir perpasen el tamañu máximu pa les xubíes de ficheros nesti servidor.",
- "Files are being scanned, please wait." : "Tan escaniándose los ficheros, espera por favor.",
- "Currently scanning" : "Anguaño escaneando",
"No favorites" : "Nengún favoritu",
- "Files and folders you mark as favorite will show up here" : "Los ficheros y carpetes que marque como favoritos apaecerán equí"
+ "Files and folders you mark as favorite will show up here" : "Los ficheros y carpetes que marque como favoritos apaecerán equí",
+ "Text file" : "Ficheru de testu",
+ "New text file.txt" : "Nuevu testu ficheru.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/az.js b/apps/files/l10n/az.js
index 10cbd661ebf..57db9be81be 100644
--- a/apps/files/l10n/az.js
+++ b/apps/files/l10n/az.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "İnformasiya daşıyıcısı mövcud deyil",
"Storage invalid" : "İnformasiya daşıyıcısı yalnışdır",
"Unknown error" : "Bəlli olmayan səhv baş verdi",
- "Could not move %s - File with this name already exists" : "Köçürmə mümkün deyil %s - Bu adla fayl artıq mövcuddur",
- "Could not move %s" : "Yerdəyişmə mükün olmadı %s",
- "Permission denied" : "Yetki qadağandır",
- "The target folder has been moved or deleted." : "Mənsəbdə olan qovluqun ünvanı dəyişib yada silinib.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Bu ad %s artıq %s qovluğunda istifadə edilir. Xahiş olunur fərqli ad istifadə edəsiniz.",
- "Error when creating the file" : "Fayl yaratdıqda səhv baş vermişdir",
- "Error when creating the folder" : "Qovluğu yaratdıqda səhv baş vermişdir",
"Unable to set upload directory." : "Əlavələr qovluğunu təyin etmək mümkün olmadı.",
"Invalid Token" : "Yalnış token",
"No file was uploaded. Unknown error" : "Heç bir fayl uüklənilmədi. Naməlum səhv",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Müvəqqəti qovluq çatışmır",
"Failed to write to disk" : "Sərt diskə yazmaq mümkün olmadı",
"Not enough storage available" : "Tələb edilən qədər yer yoxdur.",
+ "The target folder has been moved or deleted." : "Mənsəbdə olan qovluqun ünvanı dəyişib yada silinib.",
"Upload failed. Could not find uploaded file" : "Yüklənmədə səhv oldu. Yüklənmiş faylı tapmaq olmur.",
"Upload failed. Could not get file info." : "Yüklənmədə səhv oldu. Faylın informasiyasını almaq mümkün olmadı.",
"Invalid directory." : "Yalnış qovluq.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "Yüklə",
"Rename" : "Adı dəyiş",
"Delete" : "Sil",
+ "Disconnect storage" : "Daşıyıcını ayır",
+ "Unshare" : "Paylaşımı durdur",
"Details" : "Detallar",
"Select" : "Seç",
"Pending" : "Gözləmə",
"Unable to determine date" : "Tarixi təyin etmək mümkün olmadı",
"This operation is forbidden" : "Bu əməliyyat qadağandır",
"This directory is unavailable, please check the logs or contact the administrator" : "Bu qovluq tapılmir. Xahiş olunur jurnalları yoxlayın ya da inzibatçı ilə əlaqə saxlayın",
- "Error moving file." : "Faylın köçürülməsində səhv baş verdi.",
- "Error moving file" : "Faylın köçürülməsində səhv baş verdi",
- "Error" : "Səhv",
- "{new_name} already exists" : "{new_name} artıq mövcuddur",
- "Could not rename file" : "Faylın adını dəyişmək mümkün olmadı",
- "Could not create file" : "Faylı yaratmaq olmur",
- "Could not create folder" : "Qovluğu yaratmaq olmur",
- "Error deleting file." : "Faylın silinməsində səhv baş verdi.",
"No entries in this folder match '{filter}'" : "Bu qovluqda '{filter}' uyğunluğunda heç bir verilən tapılmadı",
"Name" : "Ad",
"Size" : "Həcm",
@@ -75,8 +63,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n baytlar","%n bytes"],
"Favorited" : "İstəkləndi",
"Favorite" : "İstəkli",
- "Text file" : "Tekst faylı",
- "New text file.txt" : "Yeni mətn file.txt",
"Folder" : "Qovluq",
"New folder" : "Yeni qovluq",
"{newname} already exists" : "{newname} artıq mövcuddur",
@@ -96,8 +82,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s silindi %1$s",
"You restored %1$s" : "Siz qayıtdınız %1$s",
"%2$s restored %1$s" : "%2$s bərpa edildi %1$s",
- "%s could not be renamed as it has been deleted" : "%s adını dəyişə bilmərik ona görə ki, o silinib artıq",
- "%s could not be renamed" : "%s adını dəyişə bilməz",
"Upload (max. %s)" : "Yüklə (max. %s)",
"File handling" : "Fayl emalı",
"Maximum upload size" : "Maksimal yükləmə həcmi",
@@ -113,9 +97,9 @@ OC.L10N.register(
"Select all" : "Hamısıı seç",
"Upload too large" : "Yüklənmə şox böyükdür",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Yükləmək istədiyiniz faylların həcmi, bu serverdə izin verilmiş maksimal yüklənmə həcmindən böyükdür.",
- "Files are being scanned, please wait." : "Faylların skanı başlanıb, xahiş olunur gözləyəsiniz.",
- "Currently scanning" : "Hal-hazırda skan edilir",
"No favorites" : "Seçilmiş yoxdur",
- "Files and folders you mark as favorite will show up here" : "İstəkli qeyd etdiyiniz fayllar və qovluqlar burda göstəriləcək"
+ "Files and folders you mark as favorite will show up here" : "İstəkli qeyd etdiyiniz fayllar və qovluqlar burda göstəriləcək",
+ "Text file" : "Tekst faylı",
+ "New text file.txt" : "Yeni mətn file.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/az.json b/apps/files/l10n/az.json
index 0587f91d97b..e1539015a83 100644
--- a/apps/files/l10n/az.json
+++ b/apps/files/l10n/az.json
@@ -2,13 +2,6 @@
"Storage not available" : "İnformasiya daşıyıcısı mövcud deyil",
"Storage invalid" : "İnformasiya daşıyıcısı yalnışdır",
"Unknown error" : "Bəlli olmayan səhv baş verdi",
- "Could not move %s - File with this name already exists" : "Köçürmə mümkün deyil %s - Bu adla fayl artıq mövcuddur",
- "Could not move %s" : "Yerdəyişmə mükün olmadı %s",
- "Permission denied" : "Yetki qadağandır",
- "The target folder has been moved or deleted." : "Mənsəbdə olan qovluqun ünvanı dəyişib yada silinib.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Bu ad %s artıq %s qovluğunda istifadə edilir. Xahiş olunur fərqli ad istifadə edəsiniz.",
- "Error when creating the file" : "Fayl yaratdıqda səhv baş vermişdir",
- "Error when creating the folder" : "Qovluğu yaratdıqda səhv baş vermişdir",
"Unable to set upload directory." : "Əlavələr qovluğunu təyin etmək mümkün olmadı.",
"Invalid Token" : "Yalnış token",
"No file was uploaded. Unknown error" : "Heç bir fayl uüklənilmədi. Naməlum səhv",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Müvəqqəti qovluq çatışmır",
"Failed to write to disk" : "Sərt diskə yazmaq mümkün olmadı",
"Not enough storage available" : "Tələb edilən qədər yer yoxdur.",
+ "The target folder has been moved or deleted." : "Mənsəbdə olan qovluqun ünvanı dəyişib yada silinib.",
"Upload failed. Could not find uploaded file" : "Yüklənmədə səhv oldu. Yüklənmiş faylı tapmaq olmur.",
"Upload failed. Could not get file info." : "Yüklənmədə səhv oldu. Faylın informasiyasını almaq mümkün olmadı.",
"Invalid directory." : "Yalnış qovluq.",
@@ -38,20 +32,14 @@
"Download" : "Yüklə",
"Rename" : "Adı dəyiş",
"Delete" : "Sil",
+ "Disconnect storage" : "Daşıyıcını ayır",
+ "Unshare" : "Paylaşımı durdur",
"Details" : "Detallar",
"Select" : "Seç",
"Pending" : "Gözləmə",
"Unable to determine date" : "Tarixi təyin etmək mümkün olmadı",
"This operation is forbidden" : "Bu əməliyyat qadağandır",
"This directory is unavailable, please check the logs or contact the administrator" : "Bu qovluq tapılmir. Xahiş olunur jurnalları yoxlayın ya da inzibatçı ilə əlaqə saxlayın",
- "Error moving file." : "Faylın köçürülməsində səhv baş verdi.",
- "Error moving file" : "Faylın köçürülməsində səhv baş verdi",
- "Error" : "Səhv",
- "{new_name} already exists" : "{new_name} artıq mövcuddur",
- "Could not rename file" : "Faylın adını dəyişmək mümkün olmadı",
- "Could not create file" : "Faylı yaratmaq olmur",
- "Could not create folder" : "Qovluğu yaratmaq olmur",
- "Error deleting file." : "Faylın silinməsində səhv baş verdi.",
"No entries in this folder match '{filter}'" : "Bu qovluqda '{filter}' uyğunluğunda heç bir verilən tapılmadı",
"Name" : "Ad",
"Size" : "Həcm",
@@ -73,8 +61,6 @@
"_%n byte_::_%n bytes_" : ["%n baytlar","%n bytes"],
"Favorited" : "İstəkləndi",
"Favorite" : "İstəkli",
- "Text file" : "Tekst faylı",
- "New text file.txt" : "Yeni mətn file.txt",
"Folder" : "Qovluq",
"New folder" : "Yeni qovluq",
"{newname} already exists" : "{newname} artıq mövcuddur",
@@ -94,8 +80,6 @@
"%2$s deleted %1$s" : "%2$s silindi %1$s",
"You restored %1$s" : "Siz qayıtdınız %1$s",
"%2$s restored %1$s" : "%2$s bərpa edildi %1$s",
- "%s could not be renamed as it has been deleted" : "%s adını dəyişə bilmərik ona görə ki, o silinib artıq",
- "%s could not be renamed" : "%s adını dəyişə bilməz",
"Upload (max. %s)" : "Yüklə (max. %s)",
"File handling" : "Fayl emalı",
"Maximum upload size" : "Maksimal yükləmə həcmi",
@@ -111,9 +95,9 @@
"Select all" : "Hamısıı seç",
"Upload too large" : "Yüklənmə şox böyükdür",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Yükləmək istədiyiniz faylların həcmi, bu serverdə izin verilmiş maksimal yüklənmə həcmindən böyükdür.",
- "Files are being scanned, please wait." : "Faylların skanı başlanıb, xahiş olunur gözləyəsiniz.",
- "Currently scanning" : "Hal-hazırda skan edilir",
"No favorites" : "Seçilmiş yoxdur",
- "Files and folders you mark as favorite will show up here" : "İstəkli qeyd etdiyiniz fayllar və qovluqlar burda göstəriləcək"
+ "Files and folders you mark as favorite will show up here" : "İstəkli qeyd etdiyiniz fayllar və qovluqlar burda göstəriləcək",
+ "Text file" : "Tekst faylı",
+ "New text file.txt" : "Yeni mətn file.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/be.js b/apps/files/l10n/be.js
index 77e9a4d6071..55e94ac2477 100644
--- a/apps/files/l10n/be.js
+++ b/apps/files/l10n/be.js
@@ -1,7 +1,6 @@
OC.L10N.register(
"files",
{
- "Error" : "Памылка",
"Settings" : "Налады"
},
"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/apps/files/l10n/be.json b/apps/files/l10n/be.json
index 27c2988b703..3f70a0783fe 100644
--- a/apps/files/l10n/be.json
+++ b/apps/files/l10n/be.json
@@ -1,5 +1,4 @@
{ "translations": {
- "Error" : "Памылка",
"Settings" : "Налады"
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files/l10n/bg_BG.js b/apps/files/l10n/bg_BG.js
index 7f83daa45f6..dcc4508e2e2 100644
--- a/apps/files/l10n/bg_BG.js
+++ b/apps/files/l10n/bg_BG.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Липсва дисковото устройство.",
"Storage invalid" : "Невалидно дисково устройство.",
"Unknown error" : "Непозната грешка.",
- "Could not move %s - File with this name already exists" : "Неуспешно преместване на %s - Файл със същото име вече съществува.",
- "Could not move %s" : "Неуспешно преместване на %s.",
- "Permission denied" : "Достъпът отказан",
- "The target folder has been moved or deleted." : "Крайната папка е изтрита или преместена.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Името %s е вече в папка %s. Моля, избери друго име.",
- "Error when creating the file" : "Грешка при създаването на файлът.",
- "Error when creating the folder" : "Грешка при създаването на папката.",
"Unable to set upload directory." : "Неуспешно задаване на директория за качване.",
"Invalid Token" : "Невалиеден токен.",
"No file was uploaded. Unknown error" : "Неуспешно качвачване на файл. Непозната грешка.",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Липсва временна папка.",
"Failed to write to disk" : "Възникна проблем при запис на диска.",
"Not enough storage available" : "Недостатъчно място.",
+ "The target folder has been moved or deleted." : "Крайната папка е изтрита или преместена.",
"Upload failed. Could not find uploaded file" : "Неуспешно качване. Не бе открит качения файл.",
"Upload failed. Could not get file info." : "Неуспешно качване. Не се получи информация за файла.",
"Invalid directory." : "Невалидна директория.",
@@ -40,18 +34,12 @@ OC.L10N.register(
"Download" : "Изтегли",
"Rename" : "Преименуване",
"Delete" : "Изтрий",
+ "Disconnect storage" : "Извади дисковото устройство.",
+ "Unshare" : "Премахване на споделяне",
"Details" : "Подробности",
"Select" : "Избери",
"Pending" : "Чакащо",
"Unable to determine date" : "Неуспешно установяване на дата",
- "Error moving file." : "Грешка при местенето на файла.",
- "Error moving file" : "Грешка при преместването на файла.",
- "Error" : "Грешка",
- "{new_name} already exists" : "{new_name} вече съществува.",
- "Could not rename file" : "Неуспешно преименуване на файла.",
- "Could not create file" : "Несупешно създаване на файла.",
- "Could not create folder" : "Неуспешно създаване на папка.",
- "Error deleting file." : "Грешка при изтриването на файла.",
"No entries in this folder match '{filter}'" : "Нищо в тази папка не отговаря на '{filter}'",
"Name" : "Име",
"Size" : "Размер",
@@ -69,7 +57,6 @@ OC.L10N.register(
"_matches '{filter}'_::_match '{filter}'_" : ["пасва на '{filter}'","пасват на '{filter}'\n "],
"Favorited" : "Отбелязано в любими",
"Favorite" : "Любими",
- "Text file" : "Текстов файл",
"Folder" : "Папка",
"New folder" : "Нова папка",
"Upload" : "Качване",
@@ -87,8 +74,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s изтри %1$s.",
"You restored %1$s" : "Вие възстановихте %1$s",
"%2$s restored %1$s" : "%2$s възстанови %1$s",
- "%s could not be renamed as it has been deleted" : "%s не може да бъде преименуван, защото е вече изтрит",
- "%s could not be renamed" : "%s не може да бъде преименуван.",
"Upload (max. %s)" : "Качи (макс. %s)",
"File handling" : "Операция с файла",
"Maximum upload size" : "Максимален размер",
@@ -104,9 +89,8 @@ OC.L10N.register(
"Select all" : "Избери всички",
"Upload too large" : "Прекалено голям файл за качване.",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Файловете, които се опитваш да качиш са по-големи от позволеното на този сървър.",
- "Files are being scanned, please wait." : "Файловете се сканирват, изчакайте.",
- "Currently scanning" : "В момента се търси",
"No favorites" : "Няма любими",
- "Files and folders you mark as favorite will show up here" : "Файловете и папките които отбелязваш като любими ще се показват тук"
+ "Files and folders you mark as favorite will show up here" : "Файловете и папките които отбелязваш като любими ще се показват тук",
+ "Text file" : "Текстов файл"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/bg_BG.json b/apps/files/l10n/bg_BG.json
index 639b39c258d..88370db84f7 100644
--- a/apps/files/l10n/bg_BG.json
+++ b/apps/files/l10n/bg_BG.json
@@ -2,13 +2,6 @@
"Storage not available" : "Липсва дисковото устройство.",
"Storage invalid" : "Невалидно дисково устройство.",
"Unknown error" : "Непозната грешка.",
- "Could not move %s - File with this name already exists" : "Неуспешно преместване на %s - Файл със същото име вече съществува.",
- "Could not move %s" : "Неуспешно преместване на %s.",
- "Permission denied" : "Достъпът отказан",
- "The target folder has been moved or deleted." : "Крайната папка е изтрита или преместена.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Името %s е вече в папка %s. Моля, избери друго име.",
- "Error when creating the file" : "Грешка при създаването на файлът.",
- "Error when creating the folder" : "Грешка при създаването на папката.",
"Unable to set upload directory." : "Неуспешно задаване на директория за качване.",
"Invalid Token" : "Невалиеден токен.",
"No file was uploaded. Unknown error" : "Неуспешно качвачване на файл. Непозната грешка.",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Липсва временна папка.",
"Failed to write to disk" : "Възникна проблем при запис на диска.",
"Not enough storage available" : "Недостатъчно място.",
+ "The target folder has been moved or deleted." : "Крайната папка е изтрита или преместена.",
"Upload failed. Could not find uploaded file" : "Неуспешно качване. Не бе открит качения файл.",
"Upload failed. Could not get file info." : "Неуспешно качване. Не се получи информация за файла.",
"Invalid directory." : "Невалидна директория.",
@@ -38,18 +32,12 @@
"Download" : "Изтегли",
"Rename" : "Преименуване",
"Delete" : "Изтрий",
+ "Disconnect storage" : "Извади дисковото устройство.",
+ "Unshare" : "Премахване на споделяне",
"Details" : "Подробности",
"Select" : "Избери",
"Pending" : "Чакащо",
"Unable to determine date" : "Неуспешно установяване на дата",
- "Error moving file." : "Грешка при местенето на файла.",
- "Error moving file" : "Грешка при преместването на файла.",
- "Error" : "Грешка",
- "{new_name} already exists" : "{new_name} вече съществува.",
- "Could not rename file" : "Неуспешно преименуване на файла.",
- "Could not create file" : "Несупешно създаване на файла.",
- "Could not create folder" : "Неуспешно създаване на папка.",
- "Error deleting file." : "Грешка при изтриването на файла.",
"No entries in this folder match '{filter}'" : "Нищо в тази папка не отговаря на '{filter}'",
"Name" : "Име",
"Size" : "Размер",
@@ -67,7 +55,6 @@
"_matches '{filter}'_::_match '{filter}'_" : ["пасва на '{filter}'","пасват на '{filter}'\n "],
"Favorited" : "Отбелязано в любими",
"Favorite" : "Любими",
- "Text file" : "Текстов файл",
"Folder" : "Папка",
"New folder" : "Нова папка",
"Upload" : "Качване",
@@ -85,8 +72,6 @@
"%2$s deleted %1$s" : "%2$s изтри %1$s.",
"You restored %1$s" : "Вие възстановихте %1$s",
"%2$s restored %1$s" : "%2$s възстанови %1$s",
- "%s could not be renamed as it has been deleted" : "%s не може да бъде преименуван, защото е вече изтрит",
- "%s could not be renamed" : "%s не може да бъде преименуван.",
"Upload (max. %s)" : "Качи (макс. %s)",
"File handling" : "Операция с файла",
"Maximum upload size" : "Максимален размер",
@@ -102,9 +87,8 @@
"Select all" : "Избери всички",
"Upload too large" : "Прекалено голям файл за качване.",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Файловете, които се опитваш да качиш са по-големи от позволеното на този сървър.",
- "Files are being scanned, please wait." : "Файловете се сканирват, изчакайте.",
- "Currently scanning" : "В момента се търси",
"No favorites" : "Няма любими",
- "Files and folders you mark as favorite will show up here" : "Файловете и папките които отбелязваш като любими ще се показват тук"
+ "Files and folders you mark as favorite will show up here" : "Файловете и папките които отбелязваш като любими ще се показват тук",
+ "Text file" : "Текстов файл"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/bn_BD.js b/apps/files/l10n/bn_BD.js
index 412f4aa0399..e9020ade843 100644
--- a/apps/files/l10n/bn_BD.js
+++ b/apps/files/l10n/bn_BD.js
@@ -4,11 +4,6 @@ OC.L10N.register(
"Storage not available" : "সংরক্ষণের স্থান নেই",
"Storage invalid" : "সংরক্ষণাগার বৈধ নয়",
"Unknown error" : "অজানা জটিলতা",
- "Could not move %s - File with this name already exists" : "%s কে স্থানান্তর করা সম্ভব হলো না - এই নামের ফাইল বিদ্যমান",
- "Could not move %s" : "%s কে স্থানান্তর করা সম্ভব হলো না",
- "Permission denied" : "অনুমতি দেয়া হয়নি",
- "Error when creating the file" : "ফাইলটি তৈরী করতে যেয়ে সমস্যা হলো",
- "Error when creating the folder" : "ফোল্ডার তৈরী করতে যেয়ে সমস্যা হলো",
"Unable to set upload directory." : "েআপলোড ডিরেক্টরি নির্ধারণ করা গেলনা।",
"No file was uploaded. Unknown error" : "কোন ফাইল আপলোড করা হয় নি। সমস্যার কারণটি অজ্ঞাত।",
"There is no error, the file uploaded with success" : "কোন সমস্যা হয় নি, ফাইল আপলোড সুসম্পন্ন হয়েছে।",
@@ -31,13 +26,9 @@ OC.L10N.register(
"Download" : "ডাউনলোড",
"Rename" : "পূনঃনামকরণ",
"Delete" : "মুছে",
+ "Unshare" : "ভাগাভাগি বাতিল ",
"Details" : "বিস্তারিত",
"Pending" : "মুলতুবি",
- "Error moving file." : "ফাইল সরাতে সমস্যা হলো।",
- "Error moving file" : "ফাইল সরাতে সমস্যা হলো",
- "Error" : "সমস্যা",
- "{new_name} already exists" : "{new_name} টি বিদ্যমান",
- "Could not rename file" : "ফাইলের পূণঃনামকরণ করা গেলনা",
"Name" : "রাম",
"Size" : "আকার",
"Modified" : "পরিবর্তিত",
@@ -47,7 +38,6 @@ OC.L10N.register(
"File name cannot be empty." : "ফাইলের নামটি ফাঁকা রাখা যাবে না।",
"Your storage is almost full ({usedSpacePercent}%)" : "আপনার সংরক্ষণাধার প্রায় পরিপূর্ণ ({usedSpacePercent}%) ",
"Favorite" : "প্রিয়জন",
- "Text file" : "টেক্সট ফাইল",
"Folder" : "ফোল্ডার",
"New folder" : "নব ফােলডার",
"Upload" : "আপলোড",
@@ -70,6 +60,6 @@ OC.L10N.register(
"Cancel upload" : "আপলোড বাতিল কর",
"Upload too large" : "আপলোডের আকারটি অনেক বড়",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "আপনি এই সার্ভারে আপলোড করার জন্য অনুমোদিত ফাইলের সর্বোচ্চ আকারের চেয়ে বৃহদাকার ফাইল আপলোড করার চেষ্টা করছেন ",
- "Files are being scanned, please wait." : "ফাইলগুলো স্ক্যান করা হচ্ছে, দয়া করে অপেক্ষা করুন।"
+ "Text file" : "টেক্সট ফাইল"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/bn_BD.json b/apps/files/l10n/bn_BD.json
index b8078f43071..1cd65349314 100644
--- a/apps/files/l10n/bn_BD.json
+++ b/apps/files/l10n/bn_BD.json
@@ -2,11 +2,6 @@
"Storage not available" : "সংরক্ষণের স্থান নেই",
"Storage invalid" : "সংরক্ষণাগার বৈধ নয়",
"Unknown error" : "অজানা জটিলতা",
- "Could not move %s - File with this name already exists" : "%s কে স্থানান্তর করা সম্ভব হলো না - এই নামের ফাইল বিদ্যমান",
- "Could not move %s" : "%s কে স্থানান্তর করা সম্ভব হলো না",
- "Permission denied" : "অনুমতি দেয়া হয়নি",
- "Error when creating the file" : "ফাইলটি তৈরী করতে যেয়ে সমস্যা হলো",
- "Error when creating the folder" : "ফোল্ডার তৈরী করতে যেয়ে সমস্যা হলো",
"Unable to set upload directory." : "েআপলোড ডিরেক্টরি নির্ধারণ করা গেলনা।",
"No file was uploaded. Unknown error" : "কোন ফাইল আপলোড করা হয় নি। সমস্যার কারণটি অজ্ঞাত।",
"There is no error, the file uploaded with success" : "কোন সমস্যা হয় নি, ফাইল আপলোড সুসম্পন্ন হয়েছে।",
@@ -29,13 +24,9 @@
"Download" : "ডাউনলোড",
"Rename" : "পূনঃনামকরণ",
"Delete" : "মুছে",
+ "Unshare" : "ভাগাভাগি বাতিল ",
"Details" : "বিস্তারিত",
"Pending" : "মুলতুবি",
- "Error moving file." : "ফাইল সরাতে সমস্যা হলো।",
- "Error moving file" : "ফাইল সরাতে সমস্যা হলো",
- "Error" : "সমস্যা",
- "{new_name} already exists" : "{new_name} টি বিদ্যমান",
- "Could not rename file" : "ফাইলের পূণঃনামকরণ করা গেলনা",
"Name" : "রাম",
"Size" : "আকার",
"Modified" : "পরিবর্তিত",
@@ -45,7 +36,6 @@
"File name cannot be empty." : "ফাইলের নামটি ফাঁকা রাখা যাবে না।",
"Your storage is almost full ({usedSpacePercent}%)" : "আপনার সংরক্ষণাধার প্রায় পরিপূর্ণ ({usedSpacePercent}%) ",
"Favorite" : "প্রিয়জন",
- "Text file" : "টেক্সট ফাইল",
"Folder" : "ফোল্ডার",
"New folder" : "নব ফােলডার",
"Upload" : "আপলোড",
@@ -68,6 +58,6 @@
"Cancel upload" : "আপলোড বাতিল কর",
"Upload too large" : "আপলোডের আকারটি অনেক বড়",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "আপনি এই সার্ভারে আপলোড করার জন্য অনুমোদিত ফাইলের সর্বোচ্চ আকারের চেয়ে বৃহদাকার ফাইল আপলোড করার চেষ্টা করছেন ",
- "Files are being scanned, please wait." : "ফাইলগুলো স্ক্যান করা হচ্ছে, দয়া করে অপেক্ষা করুন।"
+ "Text file" : "টেক্সট ফাইল"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/bn_IN.js b/apps/files/l10n/bn_IN.js
index d7f61133133..e69597d35ca 100644
--- a/apps/files/l10n/bn_IN.js
+++ b/apps/files/l10n/bn_IN.js
@@ -1,8 +1,6 @@
OC.L10N.register(
"files",
{
- "Could not move %s - File with this name already exists" : "%s সরানো যায়নি-এই নামে আগে থেকেই ফাইল আছে",
- "Could not move %s" : "%s সরানো যায়নি",
"No file was uploaded. Unknown error" : "কোন ফাইল আপলোড করা হয় নি।অজানা ত্রুটি",
"There is no error, the file uploaded with success" : "কোন ত্রুটি নেই,ফাইল সাফল্যের সঙ্গে আপলোড করা হয়েছে",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "আপলোড করা ফাইল-php.ini মধ্যে upload_max_filesize নির্দেশ অতিক্রম করে:",
@@ -19,7 +17,6 @@ OC.L10N.register(
"Rename" : "পুনঃনামকরণ",
"Delete" : "মুছে ফেলা",
"Pending" : "মুলতুবি",
- "Error" : "ভুল",
"Name" : "নাম",
"Size" : "আকার",
"Folder" : "ফোল্ডার",
diff --git a/apps/files/l10n/bn_IN.json b/apps/files/l10n/bn_IN.json
index f2d5d9fbf74..20c8c2e795e 100644
--- a/apps/files/l10n/bn_IN.json
+++ b/apps/files/l10n/bn_IN.json
@@ -1,6 +1,4 @@
{ "translations": {
- "Could not move %s - File with this name already exists" : "%s সরানো যায়নি-এই নামে আগে থেকেই ফাইল আছে",
- "Could not move %s" : "%s সরানো যায়নি",
"No file was uploaded. Unknown error" : "কোন ফাইল আপলোড করা হয় নি।অজানা ত্রুটি",
"There is no error, the file uploaded with success" : "কোন ত্রুটি নেই,ফাইল সাফল্যের সঙ্গে আপলোড করা হয়েছে",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "আপলোড করা ফাইল-php.ini মধ্যে upload_max_filesize নির্দেশ অতিক্রম করে:",
@@ -17,7 +15,6 @@
"Rename" : "পুনঃনামকরণ",
"Delete" : "মুছে ফেলা",
"Pending" : "মুলতুবি",
- "Error" : "ভুল",
"Name" : "নাম",
"Size" : "আকার",
"Folder" : "ফোল্ডার",
diff --git a/apps/files/l10n/bs.js b/apps/files/l10n/bs.js
index b084f2eb3be..a164132aeff 100644
--- a/apps/files/l10n/bs.js
+++ b/apps/files/l10n/bs.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Pohrana je nedostupna",
"Storage invalid" : "Pohrana je neispravna",
"Unknown error" : "Nepoznata greška",
- "Could not move %s - File with this name already exists" : "Nemoguće premjestiti %s - Datoteka takvog naziva već postoji",
- "Could not move %s" : "Nemoguće premjestiti %s",
- "Permission denied" : "Nemate ovlaštenje",
- "The target folder has been moved or deleted." : "Ciljni direktorij je premješten ili izbrisan.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Naziv %s je već iskorišten u direktoriju %s. Molim odaberite drugi naziv.",
- "Error when creating the file" : "Greška pri kreiranju datoteke",
- "Error when creating the folder" : "Greška pri kreiranju direktorija",
"Unable to set upload directory." : "Odredba direktorija učitavanja nije moguća.",
"Invalid Token" : "Neispravan Znak",
"No file was uploaded. Unknown error" : "Nijedna datoteka nije učitana. Nepoznata greška.",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Nedostaje privremeni direktorij.",
"Failed to write to disk" : "Zapisivanje na disk nije uspjelo.",
"Not enough storage available" : "Prostor za pohranu je nedovoljan",
+ "The target folder has been moved or deleted." : "Ciljni direktorij je premješten ili izbrisan.",
"Upload failed. Could not find uploaded file" : "Neuspješno učitavanje. Nije pronađena učitana dataoteka",
"Upload failed. Could not get file info." : "Neuspješno učitavanje. Nedostupne informacije o datoteci.",
"Invalid directory." : "Neispravan direktorij.",
@@ -40,17 +34,11 @@ OC.L10N.register(
"Download" : "Preuzmi",
"Rename" : "Preimenuj",
"Delete" : "Izbriši",
+ "Disconnect storage" : "Diskonektuj pohranu",
+ "Unshare" : "Prestani dijeliti",
"Select" : "Izaberi",
"Pending" : "Na čekanju",
"Unable to determine date" : "Nemoguće odrediti datum",
- "Error moving file." : "Greška pri premještanju datoteke",
- "Error moving file" : "Greška pri premještanju datoteke",
- "Error" : "Greška",
- "{new_name} already exists" : "{new_name} već postoji",
- "Could not rename file" : "Nemoguće preimenovati datoteku",
- "Could not create file" : "Datoteku nije moguće kreirati",
- "Could not create folder" : "Direktorij nije moguće kreirati",
- "Error deleting file." : "Greška pri brisanju datoteke",
"Name" : "Ime",
"Size" : "Veličina",
"Modified" : "Izmijenjeno",
@@ -66,12 +54,9 @@ OC.L10N.register(
"Your storage is almost full ({usedSpacePercent}%)" : "Vaš prostor za pohranu je skoro pun ({usedSpacePercent}%)",
"Favorited" : "Favorizovano",
"Favorite" : "Favorit",
- "Text file" : "Tekstualna datoteka",
"Folder" : "Direktorij",
"New folder" : "Novi direktorij",
"Upload" : "Učitaj",
- "%s could not be renamed as it has been deleted" : "%s nije moguće preimenovati jer je izbrisan",
- "%s could not be renamed" : "%s nije moguće preimenovati",
"Upload (max. %s)" : "Učitaj (max. %s)",
"File handling" : "Obrada datoteke",
"Maximum upload size" : "Maksimalna veličina učitavanja",
@@ -85,9 +70,8 @@ OC.L10N.register(
"Select all" : "Označi sve",
"Upload too large" : "Učitavanje je preveliko",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Datoteke koje pokušavate učitati prelaze maksimalnu veličinu za učitavanje datoteka na ovom serveru.",
- "Files are being scanned, please wait." : "Datoteke se provjeravaju, molim pričekajte.",
- "Currently scanning" : "Provjera u toku",
"No favorites" : "Nema favorita",
- "Files and folders you mark as favorite will show up here" : "Datoteke i direktorij koje ste označili kao favorite će biti prikazane ovdje"
+ "Files and folders you mark as favorite will show up here" : "Datoteke i direktorij koje ste označili kao favorite će biti prikazane ovdje",
+ "Text file" : "Tekstualna datoteka"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files/l10n/bs.json b/apps/files/l10n/bs.json
index e02689ff9fe..3e7bb70cee8 100644
--- a/apps/files/l10n/bs.json
+++ b/apps/files/l10n/bs.json
@@ -2,13 +2,6 @@
"Storage not available" : "Pohrana je nedostupna",
"Storage invalid" : "Pohrana je neispravna",
"Unknown error" : "Nepoznata greška",
- "Could not move %s - File with this name already exists" : "Nemoguće premjestiti %s - Datoteka takvog naziva već postoji",
- "Could not move %s" : "Nemoguće premjestiti %s",
- "Permission denied" : "Nemate ovlaštenje",
- "The target folder has been moved or deleted." : "Ciljni direktorij je premješten ili izbrisan.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Naziv %s je već iskorišten u direktoriju %s. Molim odaberite drugi naziv.",
- "Error when creating the file" : "Greška pri kreiranju datoteke",
- "Error when creating the folder" : "Greška pri kreiranju direktorija",
"Unable to set upload directory." : "Odredba direktorija učitavanja nije moguća.",
"Invalid Token" : "Neispravan Znak",
"No file was uploaded. Unknown error" : "Nijedna datoteka nije učitana. Nepoznata greška.",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Nedostaje privremeni direktorij.",
"Failed to write to disk" : "Zapisivanje na disk nije uspjelo.",
"Not enough storage available" : "Prostor za pohranu je nedovoljan",
+ "The target folder has been moved or deleted." : "Ciljni direktorij je premješten ili izbrisan.",
"Upload failed. Could not find uploaded file" : "Neuspješno učitavanje. Nije pronađena učitana dataoteka",
"Upload failed. Could not get file info." : "Neuspješno učitavanje. Nedostupne informacije o datoteci.",
"Invalid directory." : "Neispravan direktorij.",
@@ -38,17 +32,11 @@
"Download" : "Preuzmi",
"Rename" : "Preimenuj",
"Delete" : "Izbriši",
+ "Disconnect storage" : "Diskonektuj pohranu",
+ "Unshare" : "Prestani dijeliti",
"Select" : "Izaberi",
"Pending" : "Na čekanju",
"Unable to determine date" : "Nemoguće odrediti datum",
- "Error moving file." : "Greška pri premještanju datoteke",
- "Error moving file" : "Greška pri premještanju datoteke",
- "Error" : "Greška",
- "{new_name} already exists" : "{new_name} već postoji",
- "Could not rename file" : "Nemoguće preimenovati datoteku",
- "Could not create file" : "Datoteku nije moguće kreirati",
- "Could not create folder" : "Direktorij nije moguće kreirati",
- "Error deleting file." : "Greška pri brisanju datoteke",
"Name" : "Ime",
"Size" : "Veličina",
"Modified" : "Izmijenjeno",
@@ -64,12 +52,9 @@
"Your storage is almost full ({usedSpacePercent}%)" : "Vaš prostor za pohranu je skoro pun ({usedSpacePercent}%)",
"Favorited" : "Favorizovano",
"Favorite" : "Favorit",
- "Text file" : "Tekstualna datoteka",
"Folder" : "Direktorij",
"New folder" : "Novi direktorij",
"Upload" : "Učitaj",
- "%s could not be renamed as it has been deleted" : "%s nije moguće preimenovati jer je izbrisan",
- "%s could not be renamed" : "%s nije moguće preimenovati",
"Upload (max. %s)" : "Učitaj (max. %s)",
"File handling" : "Obrada datoteke",
"Maximum upload size" : "Maksimalna veličina učitavanja",
@@ -83,9 +68,8 @@
"Select all" : "Označi sve",
"Upload too large" : "Učitavanje je preveliko",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Datoteke koje pokušavate učitati prelaze maksimalnu veličinu za učitavanje datoteka na ovom serveru.",
- "Files are being scanned, please wait." : "Datoteke se provjeravaju, molim pričekajte.",
- "Currently scanning" : "Provjera u toku",
"No favorites" : "Nema favorita",
- "Files and folders you mark as favorite will show up here" : "Datoteke i direktorij koje ste označili kao favorite će biti prikazane ovdje"
+ "Files and folders you mark as favorite will show up here" : "Datoteke i direktorij koje ste označili kao favorite će biti prikazane ovdje",
+ "Text file" : "Tekstualna datoteka"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files/l10n/ca.js b/apps/files/l10n/ca.js
index 601781a1182..70626bb1ffa 100644
--- a/apps/files/l10n/ca.js
+++ b/apps/files/l10n/ca.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Emmagatzemament no disponible",
"Storage invalid" : "Emmagatzemament no vàlid",
"Unknown error" : "Error desconegut",
- "Could not move %s - File with this name already exists" : "No s'ha pogut moure %s - Ja hi ha un fitxer amb aquest nom",
- "Could not move %s" : " No s'ha pogut moure %s",
- "Permission denied" : "Permís denegat",
- "The target folder has been moved or deleted." : "La carpeta de destí s'ha mogut o eliminat.",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nom %s ja s'usa en la carpeta %s. Indiqueu un nom diferent.",
- "Error when creating the file" : "S'ha produït un error en crear el fitxer",
- "Error when creating the folder" : "S'ha produït un error en crear la carpeta",
"Unable to set upload directory." : "No es pot establir la carpeta de pujada.",
"Invalid Token" : "Testimoni no vàlid",
"No file was uploaded. Unknown error" : "No s'ha carregat cap fitxer. Error desconegut",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Falta un fitxer temporal",
"Failed to write to disk" : "Ha fallat en escriure al disc",
"Not enough storage available" : "No hi ha prou espai disponible",
+ "The target folder has been moved or deleted." : "La carpeta de destí s'ha mogut o eliminat.",
"Upload failed. Could not find uploaded file" : "La pujada ha fallat. El fitxer pujat no s'ha trobat.",
"Upload failed. Could not get file info." : "La pujada ha fallat. No s'ha pogut obtenir informació del fitxer.",
"Invalid directory." : "Directori no vàlid.",
@@ -40,18 +34,12 @@ OC.L10N.register(
"Download" : "Baixa",
"Rename" : "Reanomena",
"Delete" : "Esborra",
+ "Disconnect storage" : "Desonnecta l'emmagatzematge",
+ "Unshare" : "Deixa de compartir",
"Details" : "Detalls",
"Select" : "Selecciona",
"Pending" : "Pendent",
"Unable to determine date" : "No s'ha pogut determinar la data",
- "Error moving file." : "Error en moure el fitxer.",
- "Error moving file" : "Error en moure el fitxer",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} ja existeix",
- "Could not rename file" : "No es pot canviar el nom de fitxer",
- "Could not create file" : "No s'ha pogut crear el fitxer",
- "Could not create folder" : "No s'ha pogut crear la carpeta",
- "Error deleting file." : "Error en esborrar el fitxer.",
"No entries in this folder match '{filter}'" : "No hi ha resultats que coincideixin amb '{filter}'",
"Name" : "Nom",
"Size" : "Mida",
@@ -71,7 +59,6 @@ OC.L10N.register(
"_matches '{filter}'_::_match '{filter}'_" : ["coincidències '{filter}'","coincidència '{filter}'"],
"Favorited" : "Agregat a favorits",
"Favorite" : "Preferits",
- "Text file" : "Fitxer de text",
"Folder" : "Carpeta",
"New folder" : "Carpeta nova",
"Upload" : "Puja",
@@ -90,8 +77,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s ha esborrat %1$s",
"You restored %1$s" : "Has restaurat %1$s",
"%2$s restored %1$s" : "%2$s ha restaurat %1$s",
- "%s could not be renamed as it has been deleted" : "No s'ha pogut renombrar %s ja que ha estat borrat",
- "%s could not be renamed" : "%s no es pot canviar el nom",
"Upload (max. %s)" : "Pujada (màx. %s)",
"File handling" : "Gestió de fitxers",
"Maximum upload size" : "Mida màxima de pujada",
@@ -107,9 +92,8 @@ OC.L10N.register(
"Select all" : "Seleccionar tot",
"Upload too large" : "La pujada és massa gran",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Els fitxers que esteu intentant pujar excedeixen la mida màxima de pujada del servidor",
- "Files are being scanned, please wait." : "S'estan escanejant els fitxers, espereu",
- "Currently scanning" : "Actualment escanejant",
"No favorites" : "No hi ha favorits",
- "Files and folders you mark as favorite will show up here" : "Aquí apareixeran els arxius i carpetes que vostè marqui com favorits"
+ "Files and folders you mark as favorite will show up here" : "Aquí apareixeran els arxius i carpetes que vostè marqui com favorits",
+ "Text file" : "Fitxer de text"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/ca.json b/apps/files/l10n/ca.json
index 748a55d3c8e..3a9dae4e75e 100644
--- a/apps/files/l10n/ca.json
+++ b/apps/files/l10n/ca.json
@@ -2,13 +2,6 @@
"Storage not available" : "Emmagatzemament no disponible",
"Storage invalid" : "Emmagatzemament no vàlid",
"Unknown error" : "Error desconegut",
- "Could not move %s - File with this name already exists" : "No s'ha pogut moure %s - Ja hi ha un fitxer amb aquest nom",
- "Could not move %s" : " No s'ha pogut moure %s",
- "Permission denied" : "Permís denegat",
- "The target folder has been moved or deleted." : "La carpeta de destí s'ha mogut o eliminat.",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nom %s ja s'usa en la carpeta %s. Indiqueu un nom diferent.",
- "Error when creating the file" : "S'ha produït un error en crear el fitxer",
- "Error when creating the folder" : "S'ha produït un error en crear la carpeta",
"Unable to set upload directory." : "No es pot establir la carpeta de pujada.",
"Invalid Token" : "Testimoni no vàlid",
"No file was uploaded. Unknown error" : "No s'ha carregat cap fitxer. Error desconegut",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Falta un fitxer temporal",
"Failed to write to disk" : "Ha fallat en escriure al disc",
"Not enough storage available" : "No hi ha prou espai disponible",
+ "The target folder has been moved or deleted." : "La carpeta de destí s'ha mogut o eliminat.",
"Upload failed. Could not find uploaded file" : "La pujada ha fallat. El fitxer pujat no s'ha trobat.",
"Upload failed. Could not get file info." : "La pujada ha fallat. No s'ha pogut obtenir informació del fitxer.",
"Invalid directory." : "Directori no vàlid.",
@@ -38,18 +32,12 @@
"Download" : "Baixa",
"Rename" : "Reanomena",
"Delete" : "Esborra",
+ "Disconnect storage" : "Desonnecta l'emmagatzematge",
+ "Unshare" : "Deixa de compartir",
"Details" : "Detalls",
"Select" : "Selecciona",
"Pending" : "Pendent",
"Unable to determine date" : "No s'ha pogut determinar la data",
- "Error moving file." : "Error en moure el fitxer.",
- "Error moving file" : "Error en moure el fitxer",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} ja existeix",
- "Could not rename file" : "No es pot canviar el nom de fitxer",
- "Could not create file" : "No s'ha pogut crear el fitxer",
- "Could not create folder" : "No s'ha pogut crear la carpeta",
- "Error deleting file." : "Error en esborrar el fitxer.",
"No entries in this folder match '{filter}'" : "No hi ha resultats que coincideixin amb '{filter}'",
"Name" : "Nom",
"Size" : "Mida",
@@ -69,7 +57,6 @@
"_matches '{filter}'_::_match '{filter}'_" : ["coincidències '{filter}'","coincidència '{filter}'"],
"Favorited" : "Agregat a favorits",
"Favorite" : "Preferits",
- "Text file" : "Fitxer de text",
"Folder" : "Carpeta",
"New folder" : "Carpeta nova",
"Upload" : "Puja",
@@ -88,8 +75,6 @@
"%2$s deleted %1$s" : "%2$s ha esborrat %1$s",
"You restored %1$s" : "Has restaurat %1$s",
"%2$s restored %1$s" : "%2$s ha restaurat %1$s",
- "%s could not be renamed as it has been deleted" : "No s'ha pogut renombrar %s ja que ha estat borrat",
- "%s could not be renamed" : "%s no es pot canviar el nom",
"Upload (max. %s)" : "Pujada (màx. %s)",
"File handling" : "Gestió de fitxers",
"Maximum upload size" : "Mida màxima de pujada",
@@ -105,9 +90,8 @@
"Select all" : "Seleccionar tot",
"Upload too large" : "La pujada és massa gran",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Els fitxers que esteu intentant pujar excedeixen la mida màxima de pujada del servidor",
- "Files are being scanned, please wait." : "S'estan escanejant els fitxers, espereu",
- "Currently scanning" : "Actualment escanejant",
"No favorites" : "No hi ha favorits",
- "Files and folders you mark as favorite will show up here" : "Aquí apareixeran els arxius i carpetes que vostè marqui com favorits"
+ "Files and folders you mark as favorite will show up here" : "Aquí apareixeran els arxius i carpetes que vostè marqui com favorits",
+ "Text file" : "Fitxer de text"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/cs_CZ.js b/apps/files/l10n/cs_CZ.js
index 3c6bdc05a1b..bf7eb4c895a 100644
--- a/apps/files/l10n/cs_CZ.js
+++ b/apps/files/l10n/cs_CZ.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Úložiště není dostupné",
"Storage invalid" : "Neplatné úložiště",
"Unknown error" : "Neznámá chyba",
- "Could not move %s - File with this name already exists" : "Nelze přesunout %s - již existuje soubor se stejným názvem",
- "Could not move %s" : "Nelze přesunout %s",
- "Permission denied" : "Přístup odepřen",
- "The target folder has been moved or deleted." : "Cílová složka byla přesunuta nebo smazána.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Název %s ve složce %s již existuje. Vyberte prosím jiné jméno.",
- "Error when creating the file" : "Chyba při vytváření souboru",
- "Error when creating the folder" : "Chyba při vytváření složky",
"Unable to set upload directory." : "Nelze nastavit adresář pro nahrané soubory.",
"Invalid Token" : "Neplatný token",
"No file was uploaded. Unknown error" : "Žádný soubor nebyl odeslán. Neznámá chyba",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Chybí adresář pro dočasné soubory",
"Failed to write to disk" : "Zápis na disk selhal",
"Not enough storage available" : "Nedostatek dostupného úložného prostoru",
+ "The target folder has been moved or deleted." : "Cílová složka byla přesunuta nebo smazána.",
"Upload failed. Could not find uploaded file" : "Nahrávání selhalo. Nepodařilo se nalézt nahraný soubor.",
"Upload failed. Could not get file info." : "Nahrávání selhalo. Nepodařilo se získat informace o souboru.",
"Invalid directory." : "Neplatný adresář",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Stáhnout",
"Rename" : "Přejmenovat",
"Delete" : "Smazat",
+ "Disconnect storage" : "Odpojit úložiště",
+ "Unshare" : "Zrušit sdílení",
"Details" : "Podrobnosti",
"Select" : "Vybrat",
"Pending" : "Nevyřízené",
"Unable to determine date" : "Nelze určit datum",
"This operation is forbidden" : "Tato operace je zakázána",
"This directory is unavailable, please check the logs or contact the administrator" : "Tento adresář není dostupný, zkontrolujte prosím logy nebo kontaktujte svého správce systému",
- "Error moving file." : "Chyba při přesunu souboru.",
- "Error moving file" : "Chyba při přesunu souboru",
- "Error" : "Chyba",
- "{new_name} already exists" : "{new_name} již existuje",
- "Could not rename file" : "Nepodařilo se přejmenovat soubor",
- "Could not create file" : "Nepodařilo se vytvořit soubor",
- "Could not create folder" : "Nepodařilo se vytvořit složku",
- "Error deleting file." : "Chyba při mazání souboru.",
+ "Could not move \"{file}\", target exists" : "Nelze přesunout \"{file}\", cíl existuje",
+ "Could not move \"{file}\"" : "Nelze přesunout \"{file}\"",
+ "{newName} already exists" : "{newName} již existuje",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Nelze přejmenovat \"{fileName}\", již neexistuje",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Jméno \"{targetName}\" je již použito v adresáři \"{dir}\". Vyberte prosím jiné jméno.",
+ "Could not rename \"{fileName}\"" : "Nelze přejmenovat \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Nelze vytvořit soubor \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Nelze vytvořit soubor \"{file}\", protože již existuje",
+ "Could not create folder \"{dir}\"" : "Nelze vytvořit adresář \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Nelze vytvořit adresář \"{dir}\", protože již existuje",
+ "Error deleting file \"{fileName}\"." : "Chyba mazání souboru \"{fileName}\".",
"No entries in this folder match '{filter}'" : "V tomto adresáři nic nesouhlasí s '{filter}'",
"Name" : "Název",
"Size" : "Velikost",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n bajt","%n bajty","%n bajtů"],
"Favorited" : "Přidáno k oblíbeným",
"Favorite" : "Oblíbené",
- "Text file" : "Textový soubor",
- "New text file.txt" : "Nový textový soubor.txt",
"Folder" : "Složka",
"New folder" : "Nová složka",
"{newname} already exists" : "{newname} již existuje",
@@ -99,8 +96,6 @@ OC.L10N.register(
"Changed by %2$s" : "Změněno uživatelem %2$s",
"Deleted by %2$s" : "Smazáno uživatelem %2$s",
"Restored by %2$s" : "Obnoveno uživatelem %2$s",
- "%s could not be renamed as it has been deleted" : "%s nelze přejmenovat, protože byl smazán",
- "%s could not be renamed" : "%s nemůže být přejmenován",
"Upload (max. %s)" : "Nahrát (max. %s)",
"File handling" : "Zacházení se soubory",
"Maximum upload size" : "Maximální velikost pro odesílání",
@@ -118,9 +113,9 @@ OC.L10N.register(
"Select all" : "Vybrat vše",
"Upload too large" : "Odesílaný soubor je příliš velký",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Soubory, které se snažíte odeslat, překračují limit velikosti odesílání na tomto serveru.",
- "Files are being scanned, please wait." : "Soubory se prohledávají, prosím čekejte.",
- "Currently scanning" : "Prohledává se",
"No favorites" : "Žádné oblíbené",
- "Files and folders you mark as favorite will show up here" : "Soubory a adresáře označené jako oblíbené budou zobrazeny zde"
+ "Files and folders you mark as favorite will show up here" : "Soubory a adresáře označené jako oblíbené budou zobrazeny zde",
+ "Text file" : "Textový soubor",
+ "New text file.txt" : "Nový textový soubor.txt"
},
"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;");
diff --git a/apps/files/l10n/cs_CZ.json b/apps/files/l10n/cs_CZ.json
index bf9170f2ee3..97444abc876 100644
--- a/apps/files/l10n/cs_CZ.json
+++ b/apps/files/l10n/cs_CZ.json
@@ -2,13 +2,6 @@
"Storage not available" : "Úložiště není dostupné",
"Storage invalid" : "Neplatné úložiště",
"Unknown error" : "Neznámá chyba",
- "Could not move %s - File with this name already exists" : "Nelze přesunout %s - již existuje soubor se stejným názvem",
- "Could not move %s" : "Nelze přesunout %s",
- "Permission denied" : "Přístup odepřen",
- "The target folder has been moved or deleted." : "Cílová složka byla přesunuta nebo smazána.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Název %s ve složce %s již existuje. Vyberte prosím jiné jméno.",
- "Error when creating the file" : "Chyba při vytváření souboru",
- "Error when creating the folder" : "Chyba při vytváření složky",
"Unable to set upload directory." : "Nelze nastavit adresář pro nahrané soubory.",
"Invalid Token" : "Neplatný token",
"No file was uploaded. Unknown error" : "Žádný soubor nebyl odeslán. Neznámá chyba",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Chybí adresář pro dočasné soubory",
"Failed to write to disk" : "Zápis na disk selhal",
"Not enough storage available" : "Nedostatek dostupného úložného prostoru",
+ "The target folder has been moved or deleted." : "Cílová složka byla přesunuta nebo smazána.",
"Upload failed. Could not find uploaded file" : "Nahrávání selhalo. Nepodařilo se nalézt nahraný soubor.",
"Upload failed. Could not get file info." : "Nahrávání selhalo. Nepodařilo se získat informace o souboru.",
"Invalid directory." : "Neplatný adresář",
@@ -38,20 +32,25 @@
"Download" : "Stáhnout",
"Rename" : "Přejmenovat",
"Delete" : "Smazat",
+ "Disconnect storage" : "Odpojit úložiště",
+ "Unshare" : "Zrušit sdílení",
"Details" : "Podrobnosti",
"Select" : "Vybrat",
"Pending" : "Nevyřízené",
"Unable to determine date" : "Nelze určit datum",
"This operation is forbidden" : "Tato operace je zakázána",
"This directory is unavailable, please check the logs or contact the administrator" : "Tento adresář není dostupný, zkontrolujte prosím logy nebo kontaktujte svého správce systému",
- "Error moving file." : "Chyba při přesunu souboru.",
- "Error moving file" : "Chyba při přesunu souboru",
- "Error" : "Chyba",
- "{new_name} already exists" : "{new_name} již existuje",
- "Could not rename file" : "Nepodařilo se přejmenovat soubor",
- "Could not create file" : "Nepodařilo se vytvořit soubor",
- "Could not create folder" : "Nepodařilo se vytvořit složku",
- "Error deleting file." : "Chyba při mazání souboru.",
+ "Could not move \"{file}\", target exists" : "Nelze přesunout \"{file}\", cíl existuje",
+ "Could not move \"{file}\"" : "Nelze přesunout \"{file}\"",
+ "{newName} already exists" : "{newName} již existuje",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Nelze přejmenovat \"{fileName}\", již neexistuje",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Jméno \"{targetName}\" je již použito v adresáři \"{dir}\". Vyberte prosím jiné jméno.",
+ "Could not rename \"{fileName}\"" : "Nelze přejmenovat \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Nelze vytvořit soubor \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Nelze vytvořit soubor \"{file}\", protože již existuje",
+ "Could not create folder \"{dir}\"" : "Nelze vytvořit adresář \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Nelze vytvořit adresář \"{dir}\", protože již existuje",
+ "Error deleting file \"{fileName}\"." : "Chyba mazání souboru \"{fileName}\".",
"No entries in this folder match '{filter}'" : "V tomto adresáři nic nesouhlasí s '{filter}'",
"Name" : "Název",
"Size" : "Velikost",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n bajt","%n bajty","%n bajtů"],
"Favorited" : "Přidáno k oblíbeným",
"Favorite" : "Oblíbené",
- "Text file" : "Textový soubor",
- "New text file.txt" : "Nový textový soubor.txt",
"Folder" : "Složka",
"New folder" : "Nová složka",
"{newname} already exists" : "{newname} již existuje",
@@ -97,8 +94,6 @@
"Changed by %2$s" : "Změněno uživatelem %2$s",
"Deleted by %2$s" : "Smazáno uživatelem %2$s",
"Restored by %2$s" : "Obnoveno uživatelem %2$s",
- "%s could not be renamed as it has been deleted" : "%s nelze přejmenovat, protože byl smazán",
- "%s could not be renamed" : "%s nemůže být přejmenován",
"Upload (max. %s)" : "Nahrát (max. %s)",
"File handling" : "Zacházení se soubory",
"Maximum upload size" : "Maximální velikost pro odesílání",
@@ -116,9 +111,9 @@
"Select all" : "Vybrat vše",
"Upload too large" : "Odesílaný soubor je příliš velký",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Soubory, které se snažíte odeslat, překračují limit velikosti odesílání na tomto serveru.",
- "Files are being scanned, please wait." : "Soubory se prohledávají, prosím čekejte.",
- "Currently scanning" : "Prohledává se",
"No favorites" : "Žádné oblíbené",
- "Files and folders you mark as favorite will show up here" : "Soubory a adresáře označené jako oblíbené budou zobrazeny zde"
+ "Files and folders you mark as favorite will show up here" : "Soubory a adresáře označené jako oblíbené budou zobrazeny zde",
+ "Text file" : "Textový soubor",
+ "New text file.txt" : "Nový textový soubor.txt"
},"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
} \ No newline at end of file
diff --git a/apps/files/l10n/cy_GB.js b/apps/files/l10n/cy_GB.js
index 570fc14fa3a..e3879890b86 100644
--- a/apps/files/l10n/cy_GB.js
+++ b/apps/files/l10n/cy_GB.js
@@ -1,8 +1,6 @@
OC.L10N.register(
"files",
{
- "Could not move %s - File with this name already exists" : "Methwyd symud %s - Mae ffeil gyda'r enw hwn eisoes yn bodoli",
- "Could not move %s" : "Methwyd symud %s",
"No file was uploaded. Unknown error" : "Ni lwythwyd ffeil i fyny. Gwall anhysbys.",
"There is no error, the file uploaded with success" : "Does dim gwall, llwythodd y ffeil i fyny'n llwyddiannus",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "Mae'r ffeil lwythwyd i fyny'n fwy na chyfarwyddeb upload_max_filesize yn php.ini:",
@@ -22,10 +20,9 @@ OC.L10N.register(
"Download" : "Llwytho i lawr",
"Rename" : "Ailenwi",
"Delete" : "Dileu",
+ "Unshare" : "Dad-rannu",
"Details" : "Manylion",
"Pending" : "I ddod",
- "Error" : "Gwall",
- "{new_name} already exists" : "{new_name} yn bodoli'n barod",
"Name" : "Enw",
"Size" : "Maint",
"Modified" : "Addaswyd",
@@ -33,7 +30,6 @@ OC.L10N.register(
"File name cannot be empty." : "Does dim hawl cael enw ffeil gwag.",
"Your storage is full, files can not be updated or synced anymore!" : "Mae eich storfa'n llawn, ni ellir diweddaru a chydweddu ffeiliau mwyach!",
"Your storage is almost full ({usedSpacePercent}%)" : "Mae eich storfa bron a bod yn llawn ({usedSpacePercent}%)",
- "Text file" : "Ffeil destun",
"Folder" : "Plygell",
"Upload" : "Llwytho i fyny",
"File handling" : "Trafod ffeiliau",
@@ -44,6 +40,6 @@ OC.L10N.register(
"Cancel upload" : "Diddymu llwytho i fyny",
"Upload too large" : "Maint llwytho i fyny'n rhy fawr",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Mae'r ffeiliau rydych yn ceisio llwytho i fyny'n fwy na maint mwyaf llwytho ffeiliau i fyny ar y gweinydd hwn.",
- "Files are being scanned, please wait." : "Arhoswch, mae ffeiliau'n cael eu sganio."
+ "Text file" : "Ffeil destun"
},
"nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;");
diff --git a/apps/files/l10n/cy_GB.json b/apps/files/l10n/cy_GB.json
index e0b42d77a7a..7d217d631ae 100644
--- a/apps/files/l10n/cy_GB.json
+++ b/apps/files/l10n/cy_GB.json
@@ -1,6 +1,4 @@
{ "translations": {
- "Could not move %s - File with this name already exists" : "Methwyd symud %s - Mae ffeil gyda'r enw hwn eisoes yn bodoli",
- "Could not move %s" : "Methwyd symud %s",
"No file was uploaded. Unknown error" : "Ni lwythwyd ffeil i fyny. Gwall anhysbys.",
"There is no error, the file uploaded with success" : "Does dim gwall, llwythodd y ffeil i fyny'n llwyddiannus",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "Mae'r ffeil lwythwyd i fyny'n fwy na chyfarwyddeb upload_max_filesize yn php.ini:",
@@ -20,10 +18,9 @@
"Download" : "Llwytho i lawr",
"Rename" : "Ailenwi",
"Delete" : "Dileu",
+ "Unshare" : "Dad-rannu",
"Details" : "Manylion",
"Pending" : "I ddod",
- "Error" : "Gwall",
- "{new_name} already exists" : "{new_name} yn bodoli'n barod",
"Name" : "Enw",
"Size" : "Maint",
"Modified" : "Addaswyd",
@@ -31,7 +28,6 @@
"File name cannot be empty." : "Does dim hawl cael enw ffeil gwag.",
"Your storage is full, files can not be updated or synced anymore!" : "Mae eich storfa'n llawn, ni ellir diweddaru a chydweddu ffeiliau mwyach!",
"Your storage is almost full ({usedSpacePercent}%)" : "Mae eich storfa bron a bod yn llawn ({usedSpacePercent}%)",
- "Text file" : "Ffeil destun",
"Folder" : "Plygell",
"Upload" : "Llwytho i fyny",
"File handling" : "Trafod ffeiliau",
@@ -42,6 +38,6 @@
"Cancel upload" : "Diddymu llwytho i fyny",
"Upload too large" : "Maint llwytho i fyny'n rhy fawr",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Mae'r ffeiliau rydych yn ceisio llwytho i fyny'n fwy na maint mwyaf llwytho ffeiliau i fyny ar y gweinydd hwn.",
- "Files are being scanned, please wait." : "Arhoswch, mae ffeiliau'n cael eu sganio."
+ "Text file" : "Ffeil destun"
},"pluralForm" :"nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;"
} \ No newline at end of file
diff --git a/apps/files/l10n/da.js b/apps/files/l10n/da.js
index 307a58e74f0..6b406fed534 100644
--- a/apps/files/l10n/da.js
+++ b/apps/files/l10n/da.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Lagerplads er ikke tilgængeligt",
"Storage invalid" : "Lagerplads er ugyldig",
"Unknown error" : "Ukendt fejl",
- "Could not move %s - File with this name already exists" : "Kunne ikke flytte %s - der findes allerede en fil med dette navn",
- "Could not move %s" : "Kunne ikke flytte %s",
- "Permission denied" : "Adgang nægtet",
- "The target folder has been moved or deleted." : "Mappen er blevet slettet eller fjernet.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Navnet %s er allerede i brug i mappen %s. Vælg venligst et andet navn.",
- "Error when creating the file" : "Fejl ved oprettelse af fil",
- "Error when creating the folder" : "Fejl ved oprettelse af mappen",
"Unable to set upload directory." : "Ude af stand til at vælge upload mappe.",
"Invalid Token" : "Ugyldig Token ",
"No file was uploaded. Unknown error" : "Ingen fil blev uploadet. Ukendt fejl.",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Manglende midlertidig mappe.",
"Failed to write to disk" : "Fejl ved skrivning til disk.",
"Not enough storage available" : "Der er ikke nok plads til rådlighed",
+ "The target folder has been moved or deleted." : "Mappen er blevet slettet eller fjernet.",
"Upload failed. Could not find uploaded file" : "Upload fejlede. Kunne ikke finde den uploadede fil.",
"Upload failed. Could not get file info." : "Upload fejlede. Kunne ikke hente filinformation.",
"Invalid directory." : "Ugyldig mappe.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "Download",
"Rename" : "Omdøb",
"Delete" : "Slet",
+ "Disconnect storage" : "Frakobl lager",
+ "Unshare" : "Fjern deling",
"Details" : "Detaljer",
"Select" : "Vælg",
"Pending" : "Afventer",
"Unable to determine date" : "Kan ikke fastslå datoen",
"This operation is forbidden" : "Denne operation er forbudt",
"This directory is unavailable, please check the logs or contact the administrator" : "Denne mappe er utilgængelig, tjek venligst loggene eller kontakt administratoren",
- "Error moving file." : "Fejl ved flytning af fil",
- "Error moving file" : "Fejl ved flytning af fil",
- "Error" : "Fejl",
- "{new_name} already exists" : "{new_name} eksisterer allerede",
- "Could not rename file" : "Kunne ikke omdøbe filen",
- "Could not create file" : "Kunne ikke oprette fil",
- "Could not create folder" : "Kunne ikke oprette mappe",
- "Error deleting file." : "Fejl ved sletnign af fil.",
"No entries in this folder match '{filter}'" : "Der er ingen poster i denne mappe, der matcher '{filter}'",
"Name" : "Navn",
"Size" : "Størrelse",
@@ -75,8 +63,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Gjort til foretrukken",
"Favorite" : "Foretrukken",
- "Text file" : "Tekstfil",
- "New text file.txt" : "Ny tekst file.txt",
"Folder" : "Mappe",
"New folder" : "Ny Mappe",
"{newname} already exists" : "{newname} eksistere allerede",
@@ -99,8 +85,6 @@ OC.L10N.register(
"Changed by %2$s" : "Ændret af %2$s",
"Deleted by %2$s" : "Slettet af %2$s",
"Restored by %2$s" : "Gendannet af %2$s",
- "%s could not be renamed as it has been deleted" : "%s kunne ikke omdøbes, da den er blevet slettet",
- "%s could not be renamed" : "%s kunne ikke omdøbes",
"Upload (max. %s)" : "Upload (max. %s)",
"File handling" : "Filhåndtering",
"Maximum upload size" : "Maksimal upload-størrelse",
@@ -116,9 +100,9 @@ OC.L10N.register(
"Select all" : "Vælg alle",
"Upload too large" : "Upload er for stor",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Filerne, du prøver at uploade, er større end den maksimale størrelse for fil-upload på denne server.",
- "Files are being scanned, please wait." : "Filerne bliver indlæst, vent venligst.",
- "Currently scanning" : "Skanning er i gang",
"No favorites" : "Ingen foretrukne",
- "Files and folders you mark as favorite will show up here" : "Filer og mapper som du har markeret som foretrukne, vil blive vist her"
+ "Files and folders you mark as favorite will show up here" : "Filer og mapper som du har markeret som foretrukne, vil blive vist her",
+ "Text file" : "Tekstfil",
+ "New text file.txt" : "Ny tekst file.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/da.json b/apps/files/l10n/da.json
index ae5d9655536..e186674656c 100644
--- a/apps/files/l10n/da.json
+++ b/apps/files/l10n/da.json
@@ -2,13 +2,6 @@
"Storage not available" : "Lagerplads er ikke tilgængeligt",
"Storage invalid" : "Lagerplads er ugyldig",
"Unknown error" : "Ukendt fejl",
- "Could not move %s - File with this name already exists" : "Kunne ikke flytte %s - der findes allerede en fil med dette navn",
- "Could not move %s" : "Kunne ikke flytte %s",
- "Permission denied" : "Adgang nægtet",
- "The target folder has been moved or deleted." : "Mappen er blevet slettet eller fjernet.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Navnet %s er allerede i brug i mappen %s. Vælg venligst et andet navn.",
- "Error when creating the file" : "Fejl ved oprettelse af fil",
- "Error when creating the folder" : "Fejl ved oprettelse af mappen",
"Unable to set upload directory." : "Ude af stand til at vælge upload mappe.",
"Invalid Token" : "Ugyldig Token ",
"No file was uploaded. Unknown error" : "Ingen fil blev uploadet. Ukendt fejl.",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Manglende midlertidig mappe.",
"Failed to write to disk" : "Fejl ved skrivning til disk.",
"Not enough storage available" : "Der er ikke nok plads til rådlighed",
+ "The target folder has been moved or deleted." : "Mappen er blevet slettet eller fjernet.",
"Upload failed. Could not find uploaded file" : "Upload fejlede. Kunne ikke finde den uploadede fil.",
"Upload failed. Could not get file info." : "Upload fejlede. Kunne ikke hente filinformation.",
"Invalid directory." : "Ugyldig mappe.",
@@ -38,20 +32,14 @@
"Download" : "Download",
"Rename" : "Omdøb",
"Delete" : "Slet",
+ "Disconnect storage" : "Frakobl lager",
+ "Unshare" : "Fjern deling",
"Details" : "Detaljer",
"Select" : "Vælg",
"Pending" : "Afventer",
"Unable to determine date" : "Kan ikke fastslå datoen",
"This operation is forbidden" : "Denne operation er forbudt",
"This directory is unavailable, please check the logs or contact the administrator" : "Denne mappe er utilgængelig, tjek venligst loggene eller kontakt administratoren",
- "Error moving file." : "Fejl ved flytning af fil",
- "Error moving file" : "Fejl ved flytning af fil",
- "Error" : "Fejl",
- "{new_name} already exists" : "{new_name} eksisterer allerede",
- "Could not rename file" : "Kunne ikke omdøbe filen",
- "Could not create file" : "Kunne ikke oprette fil",
- "Could not create folder" : "Kunne ikke oprette mappe",
- "Error deleting file." : "Fejl ved sletnign af fil.",
"No entries in this folder match '{filter}'" : "Der er ingen poster i denne mappe, der matcher '{filter}'",
"Name" : "Navn",
"Size" : "Størrelse",
@@ -73,8 +61,6 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Gjort til foretrukken",
"Favorite" : "Foretrukken",
- "Text file" : "Tekstfil",
- "New text file.txt" : "Ny tekst file.txt",
"Folder" : "Mappe",
"New folder" : "Ny Mappe",
"{newname} already exists" : "{newname} eksistere allerede",
@@ -97,8 +83,6 @@
"Changed by %2$s" : "Ændret af %2$s",
"Deleted by %2$s" : "Slettet af %2$s",
"Restored by %2$s" : "Gendannet af %2$s",
- "%s could not be renamed as it has been deleted" : "%s kunne ikke omdøbes, da den er blevet slettet",
- "%s could not be renamed" : "%s kunne ikke omdøbes",
"Upload (max. %s)" : "Upload (max. %s)",
"File handling" : "Filhåndtering",
"Maximum upload size" : "Maksimal upload-størrelse",
@@ -114,9 +98,9 @@
"Select all" : "Vælg alle",
"Upload too large" : "Upload er for stor",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Filerne, du prøver at uploade, er større end den maksimale størrelse for fil-upload på denne server.",
- "Files are being scanned, please wait." : "Filerne bliver indlæst, vent venligst.",
- "Currently scanning" : "Skanning er i gang",
"No favorites" : "Ingen foretrukne",
- "Files and folders you mark as favorite will show up here" : "Filer og mapper som du har markeret som foretrukne, vil blive vist her"
+ "Files and folders you mark as favorite will show up here" : "Filer og mapper som du har markeret som foretrukne, vil blive vist her",
+ "Text file" : "Tekstfil",
+ "New text file.txt" : "Ny tekst file.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/de.js b/apps/files/l10n/de.js
index 5a35a5f21ee..960edf5b718 100644
--- a/apps/files/l10n/de.js
+++ b/apps/files/l10n/de.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Speicher nicht verfügbar",
"Storage invalid" : "Speicher ungültig",
"Unknown error" : "Unbekannter Fehler",
- "Could not move %s - File with this name already exists" : "Konnte %s nicht verschieben. Eine Datei mit diesem Namen existiert bereits",
- "Could not move %s" : "Konnte %s nicht verschieben",
- "Permission denied" : "Zugriff verweigert",
- "The target folder has been moved or deleted." : "Der Zielordner wurde verschoben oder gelöscht.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Der Name %s wird bereits im Ordner %s benutzt. Bitte wähle einen anderen Namen.",
- "Error when creating the file" : "Fehler beim Erstellen der Datei",
- "Error when creating the folder" : "Fehler beim Erstellen des Ordners",
"Unable to set upload directory." : "Das Upload-Verzeichnis konnte nicht gesetzt werden.",
"Invalid Token" : "Ungültiger Token",
"No file was uploaded. Unknown error" : "Keine Datei hochgeladen. Unbekannter Fehler",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Kein temporärer Ordner vorhanden",
"Failed to write to disk" : "Fehler beim Schreiben auf die Festplatte",
"Not enough storage available" : "Nicht genug Speicher vorhanden.",
+ "The target folder has been moved or deleted." : "Der Zielordner wurde verschoben oder gelöscht.",
"Upload failed. Could not find uploaded file" : "Hochladen fehlgeschlagen. Hochgeladene Datei konnte nicht gefunden werden.",
"Upload failed. Could not get file info." : "Hochladen fehlgeschlagen. Dateiinformationen konnten nicht abgerufen werden.",
"Invalid directory." : "Ungültiges Verzeichnis.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Herunterladen",
"Rename" : "Umbenennen",
"Delete" : "Löschen",
+ "Disconnect storage" : "Speicher trennen",
+ "Unshare" : "Freigabe aufheben",
"Details" : "Details",
"Select" : "Auswählen",
"Pending" : "Ausstehend",
"Unable to determine date" : "Datum konnte nicht ermittelt werden",
"This operation is forbidden" : "Diese Operation ist nicht erlaubt",
"This directory is unavailable, please check the logs or contact the administrator" : "Dieses Verzeichnis ist nicht verfügbar, bitte überprüfe die Logdateien oder kontaktiere den Administrator",
- "Error moving file." : "Fehler beim Verschieben der Datei.",
- "Error moving file" : "Fehler beim Verschieben der Datei",
- "Error" : "Fehler",
- "{new_name} already exists" : "{new_name} existiert bereits",
- "Could not rename file" : "Die Datei konnte nicht umbenannt werden",
- "Could not create file" : "Die Datei konnte nicht erstellt werden",
- "Could not create folder" : "Der Ordner konnte nicht erstellt werden",
- "Error deleting file." : "Fehler beim Löschen der Datei.",
+ "Could not move \"{file}\", target exists" : "Konnte nicht verschieben \"{file}\", Ziel existiert bereits",
+ "Could not move \"{file}\"" : "Konnte nicht verschieben \"{file}\"",
+ "{newName} already exists" : "{newName} existiert bereits",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Konnte nicht umbennen \"{fileName}\", da es nicht mehr existiert",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Der Name \"{targetName}\" wird bereits bereits in diesem Ordner benutzt \"{dir}\". Bitte nimm einen anderen Namen.",
+ "Could not rename \"{fileName}\"" : "Die Datei konnte nicht umbenannt werden \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Die Datei konnte nicht erstellt werden \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Die Datei konnte nicht erstellt werden \"{file}\", da sie bereits existiert.",
+ "Could not create folder \"{dir}\"" : "Der Ordner konnte nicht erstellt werden \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Der Ordner konnte nicht erstellt werden \"{dir}\", da dieser bereits existiert",
+ "Error deleting file \"{fileName}\"." : "Fehler beim löschen der Datei \"{fileName}\"",
"No entries in this folder match '{filter}'" : "Keine Einträge in diesem Ordner stimmen mit '{filter}' überein",
"Name" : "Name",
"Size" : "Größe",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n Byte","%n Bytes"],
"Favorited" : "Favorisiert",
"Favorite" : "Favorit",
- "Text file" : "Textdatei",
- "New text file.txt" : "Neue Textdatei.txt",
"Folder" : "Ordner",
"New folder" : "Neuer Ordner",
"{newname} already exists" : "{newname} existiert bereits",
@@ -99,8 +96,6 @@ OC.L10N.register(
"Changed by %2$s" : "Geändert von %2$s",
"Deleted by %2$s" : "Gelöscht von %2$s",
"Restored by %2$s" : "Wiederhergestellt von %2$s",
- "%s could not be renamed as it has been deleted" : "%s konnte nicht umbenannt werden, da es gelöscht wurde",
- "%s could not be renamed" : "%s konnte nicht umbenannt werden",
"Upload (max. %s)" : "Hochladen (max. %s)",
"File handling" : "Dateibehandlung",
"Maximum upload size" : "Maximale Upload-Größe",
@@ -116,9 +111,9 @@ OC.L10N.register(
"Select all" : "Alle auswählen",
"Upload too large" : "Der Upload ist zu groß",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Die Datei überschreitet die Maximalgröße für Uploads auf diesem Server.",
- "Files are being scanned, please wait." : "Dateien werden gescannt, bitte warten.",
- "Currently scanning" : "Durchsuchen läuft",
"No favorites" : "Keine Favoriten",
- "Files and folders you mark as favorite will show up here" : "Dateien und Ordner, die Du als Favoriten markierst, werden hier erscheinen"
+ "Files and folders you mark as favorite will show up here" : "Dateien und Ordner, die Du als Favoriten markierst, werden hier erscheinen",
+ "Text file" : "Textdatei",
+ "New text file.txt" : "Neue Textdatei.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/de.json b/apps/files/l10n/de.json
index 860a97916be..3d1e061781e 100644
--- a/apps/files/l10n/de.json
+++ b/apps/files/l10n/de.json
@@ -2,13 +2,6 @@
"Storage not available" : "Speicher nicht verfügbar",
"Storage invalid" : "Speicher ungültig",
"Unknown error" : "Unbekannter Fehler",
- "Could not move %s - File with this name already exists" : "Konnte %s nicht verschieben. Eine Datei mit diesem Namen existiert bereits",
- "Could not move %s" : "Konnte %s nicht verschieben",
- "Permission denied" : "Zugriff verweigert",
- "The target folder has been moved or deleted." : "Der Zielordner wurde verschoben oder gelöscht.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Der Name %s wird bereits im Ordner %s benutzt. Bitte wähle einen anderen Namen.",
- "Error when creating the file" : "Fehler beim Erstellen der Datei",
- "Error when creating the folder" : "Fehler beim Erstellen des Ordners",
"Unable to set upload directory." : "Das Upload-Verzeichnis konnte nicht gesetzt werden.",
"Invalid Token" : "Ungültiger Token",
"No file was uploaded. Unknown error" : "Keine Datei hochgeladen. Unbekannter Fehler",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Kein temporärer Ordner vorhanden",
"Failed to write to disk" : "Fehler beim Schreiben auf die Festplatte",
"Not enough storage available" : "Nicht genug Speicher vorhanden.",
+ "The target folder has been moved or deleted." : "Der Zielordner wurde verschoben oder gelöscht.",
"Upload failed. Could not find uploaded file" : "Hochladen fehlgeschlagen. Hochgeladene Datei konnte nicht gefunden werden.",
"Upload failed. Could not get file info." : "Hochladen fehlgeschlagen. Dateiinformationen konnten nicht abgerufen werden.",
"Invalid directory." : "Ungültiges Verzeichnis.",
@@ -38,20 +32,25 @@
"Download" : "Herunterladen",
"Rename" : "Umbenennen",
"Delete" : "Löschen",
+ "Disconnect storage" : "Speicher trennen",
+ "Unshare" : "Freigabe aufheben",
"Details" : "Details",
"Select" : "Auswählen",
"Pending" : "Ausstehend",
"Unable to determine date" : "Datum konnte nicht ermittelt werden",
"This operation is forbidden" : "Diese Operation ist nicht erlaubt",
"This directory is unavailable, please check the logs or contact the administrator" : "Dieses Verzeichnis ist nicht verfügbar, bitte überprüfe die Logdateien oder kontaktiere den Administrator",
- "Error moving file." : "Fehler beim Verschieben der Datei.",
- "Error moving file" : "Fehler beim Verschieben der Datei",
- "Error" : "Fehler",
- "{new_name} already exists" : "{new_name} existiert bereits",
- "Could not rename file" : "Die Datei konnte nicht umbenannt werden",
- "Could not create file" : "Die Datei konnte nicht erstellt werden",
- "Could not create folder" : "Der Ordner konnte nicht erstellt werden",
- "Error deleting file." : "Fehler beim Löschen der Datei.",
+ "Could not move \"{file}\", target exists" : "Konnte nicht verschieben \"{file}\", Ziel existiert bereits",
+ "Could not move \"{file}\"" : "Konnte nicht verschieben \"{file}\"",
+ "{newName} already exists" : "{newName} existiert bereits",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Konnte nicht umbennen \"{fileName}\", da es nicht mehr existiert",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Der Name \"{targetName}\" wird bereits bereits in diesem Ordner benutzt \"{dir}\". Bitte nimm einen anderen Namen.",
+ "Could not rename \"{fileName}\"" : "Die Datei konnte nicht umbenannt werden \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Die Datei konnte nicht erstellt werden \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Die Datei konnte nicht erstellt werden \"{file}\", da sie bereits existiert.",
+ "Could not create folder \"{dir}\"" : "Der Ordner konnte nicht erstellt werden \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Der Ordner konnte nicht erstellt werden \"{dir}\", da dieser bereits existiert",
+ "Error deleting file \"{fileName}\"." : "Fehler beim löschen der Datei \"{fileName}\"",
"No entries in this folder match '{filter}'" : "Keine Einträge in diesem Ordner stimmen mit '{filter}' überein",
"Name" : "Name",
"Size" : "Größe",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n Byte","%n Bytes"],
"Favorited" : "Favorisiert",
"Favorite" : "Favorit",
- "Text file" : "Textdatei",
- "New text file.txt" : "Neue Textdatei.txt",
"Folder" : "Ordner",
"New folder" : "Neuer Ordner",
"{newname} already exists" : "{newname} existiert bereits",
@@ -97,8 +94,6 @@
"Changed by %2$s" : "Geändert von %2$s",
"Deleted by %2$s" : "Gelöscht von %2$s",
"Restored by %2$s" : "Wiederhergestellt von %2$s",
- "%s could not be renamed as it has been deleted" : "%s konnte nicht umbenannt werden, da es gelöscht wurde",
- "%s could not be renamed" : "%s konnte nicht umbenannt werden",
"Upload (max. %s)" : "Hochladen (max. %s)",
"File handling" : "Dateibehandlung",
"Maximum upload size" : "Maximale Upload-Größe",
@@ -114,9 +109,9 @@
"Select all" : "Alle auswählen",
"Upload too large" : "Der Upload ist zu groß",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Die Datei überschreitet die Maximalgröße für Uploads auf diesem Server.",
- "Files are being scanned, please wait." : "Dateien werden gescannt, bitte warten.",
- "Currently scanning" : "Durchsuchen läuft",
"No favorites" : "Keine Favoriten",
- "Files and folders you mark as favorite will show up here" : "Dateien und Ordner, die Du als Favoriten markierst, werden hier erscheinen"
+ "Files and folders you mark as favorite will show up here" : "Dateien und Ordner, die Du als Favoriten markierst, werden hier erscheinen",
+ "Text file" : "Textdatei",
+ "New text file.txt" : "Neue Textdatei.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/de_AT.js b/apps/files/l10n/de_AT.js
index 7bebb1e6eaf..783ff4aaa6b 100644
--- a/apps/files/l10n/de_AT.js
+++ b/apps/files/l10n/de_AT.js
@@ -5,8 +5,8 @@ OC.L10N.register(
"Files" : "Dateien",
"Download" : "Herunterladen",
"Delete" : "Löschen",
+ "Unshare" : "Teilung zurücknehmen",
"Details" : "Details",
- "Error" : "Fehler",
"New folder" : "Neuer Ordner",
"Upload" : "Hochladen",
"A new file or folder has been <strong>created</strong>" : "Eine neue Datei oder ein neuer Ordner wurde <strong>erstellt</strong>",
diff --git a/apps/files/l10n/de_AT.json b/apps/files/l10n/de_AT.json
index fffb3863e85..2d54751bdf6 100644
--- a/apps/files/l10n/de_AT.json
+++ b/apps/files/l10n/de_AT.json
@@ -3,8 +3,8 @@
"Files" : "Dateien",
"Download" : "Herunterladen",
"Delete" : "Löschen",
+ "Unshare" : "Teilung zurücknehmen",
"Details" : "Details",
- "Error" : "Fehler",
"New folder" : "Neuer Ordner",
"Upload" : "Hochladen",
"A new file or folder has been <strong>created</strong>" : "Eine neue Datei oder ein neuer Ordner wurde <strong>erstellt</strong>",
diff --git a/apps/files/l10n/de_DE.js b/apps/files/l10n/de_DE.js
index ddb84ffedfb..ce8a9132a0c 100644
--- a/apps/files/l10n/de_DE.js
+++ b/apps/files/l10n/de_DE.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Speicher nicht verfügbar",
"Storage invalid" : "Speicher ungültig",
"Unknown error" : "Unbekannter Fehler",
- "Could not move %s - File with this name already exists" : "%s konnte nicht verschoben werden. Eine Datei mit diesem Namen existiert bereits.",
- "Could not move %s" : "Konnte %s nicht verschieben",
- "Permission denied" : "Zugriff verweigert",
- "The target folder has been moved or deleted." : "Der Zielordner wurde verschoben oder gelöscht.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Der Name %s wird bereits im Ordner %s benutzt. Bitte wählen Sie einen anderen Namen.",
- "Error when creating the file" : "Fehler beim Erstellen der Datei",
- "Error when creating the folder" : "Fehler beim Erstellen des Ordners",
"Unable to set upload directory." : "Das Upload-Verzeichnis konnte nicht gesetzt werden.",
"Invalid Token" : "Ungültiger Token",
"No file was uploaded. Unknown error" : "Keine Datei hochgeladen. Unbekannter Fehler",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Kein temporärer Ordner vorhanden",
"Failed to write to disk" : "Fehler beim Schreiben auf die Festplatte",
"Not enough storage available" : "Nicht genug Speicher vorhanden.",
+ "The target folder has been moved or deleted." : "Der Zielordner wurde verschoben oder gelöscht.",
"Upload failed. Could not find uploaded file" : "Hochladen fehlgeschlagen. Die hochgeladene Datei konnte nicht gefunden werden.",
"Upload failed. Could not get file info." : "Hochladen fehlgeschlagen. Die Dateiinformationen konnten nicht abgerufen werden.",
"Invalid directory." : "Ungültiges Verzeichnis.",
@@ -40,20 +34,24 @@ OC.L10N.register(
"Download" : "Herunterladen",
"Rename" : "Umbenennen",
"Delete" : "Löschen",
+ "Disconnect storage" : "Speicher trennen",
+ "Unshare" : "Freigabe aufheben",
"Details" : "Details",
"Select" : "Auswählen",
"Pending" : "Ausstehend",
"Unable to determine date" : "Datum konnte nicht ermittelt werden",
"This operation is forbidden" : "Diese Operation ist nicht erlaubt",
"This directory is unavailable, please check the logs or contact the administrator" : "Dieses Verzeichnis ist nicht verfügbar, bitte überprüfen Sie die Logdateien oder kontaktieren Sie den Administrator",
- "Error moving file." : "Fehler beim Verschieben der Datei.",
- "Error moving file" : "Fehler beim Verschieben der Datei",
- "Error" : "Fehler",
- "{new_name} already exists" : "{new_name} existiert bereits",
- "Could not rename file" : "Die Datei konnte nicht umbenannt werden",
- "Could not create file" : "Die Datei konnte nicht erstellt werden",
- "Could not create folder" : "Der Ordner konnte nicht erstellt werden",
- "Error deleting file." : "Fehler beim Löschen der Datei.",
+ "Could not move \"{file}\", target exists" : "Die Datei konnte nicht verschoben werden \"{file}\", da die Datei im Zielordner bereits existiert",
+ "Could not move \"{file}\"" : "Die Datei konnte nicht verschoben werden \"{file}\"",
+ "{newName} already exists" : "{newName} existiert bereits",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Die Datei konnte nicht umbennant werden \"{fileName}\", da die Datei nicht mehr existiert",
+ "Could not rename \"{fileName}\"" : "Die Datei konnte nicht umbenannt werden \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Die Datei konnte nicht erstellt werden \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Die Datei konnte nicht erstellt werden \"{file}\", da diese bereits existiert",
+ "Could not create folder \"{dir}\"" : "Der Ordner konnte nicht erstellt werden \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Der Ordner konnte nicht erstellt werden \"{dir}\", da dieser bereits existiert",
+ "Error deleting file \"{fileName}\"." : "Fehler beim löschen der Datei \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Keine Einträge in diesem Ordner stimmen mit '{filter}' überein",
"Name" : "Name",
"Size" : "Größe",
@@ -71,11 +69,13 @@ OC.L10N.register(
"Storage of {owner} is almost full ({usedSpacePercent}%)" : "Der Speicher von {owner} ist beinahe voll ({usedSpacePercent}%)",
"Your storage is almost full ({usedSpacePercent}%)" : "Ihr Speicher ist fast voll ({usedSpacePercent}%)",
"_matches '{filter}'_::_match '{filter}'_" : ["stimmt mit '{filter}' überein","stimmen mit '{filter}' überein"],
+ "Path" : "Pfad",
+ "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Favorisiert",
"Favorite" : "Favorit",
- "Text file" : "Textdatei",
"Folder" : "Ordner",
"New folder" : "Neuer Ordner",
+ "{newname} already exists" : "{newname} existiert bereits",
"Upload" : "Hochladen",
"An error occurred while trying to update the tags" : "Es ist ein Fehler beim Aktualisieren der Tags aufgetreten",
"A new file or folder has been <strong>created</strong>" : "Eine neue Datei oder ein neuer Ordner wurde <strong>erstellt</strong>",
@@ -92,13 +92,15 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s hat %1$s gelöscht",
"You restored %1$s" : "Sie haben %1$s wiederhergestellt",
"%2$s restored %1$s" : "%2$s wiederhergestellt %1$s",
- "%s could not be renamed as it has been deleted" : "%s konnte nicht umbenannt werden, da es gelöscht wurde",
- "%s could not be renamed" : "%s konnte nicht umbenannt werden",
+ "Changed by %2$s" : "Geändert von %2$s",
+ "Deleted by %2$s" : "Gelöscht durch %2$s",
+ "Restored by %2$s" : "Wiederhergestellt durch %2$s",
"Upload (max. %s)" : "Hochladen (max. %s)",
"File handling" : "Dateibehandlung",
"Maximum upload size" : "Maximale Upload-Größe",
"max. possible: " : "maximal möglich:",
"Save" : "Speichern",
+ "Missing permissions to edit from here." : "Fehlende Berechtigungen um von hier aus zu bearbeiten.",
"Settings" : "Einstellungen",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Benutzen Sie diese Adresse, um <a href=\"%s\" target=\"_blank\">über WebDAV auf Ihre Dateien zuzugreifen</a>",
@@ -109,9 +111,9 @@ OC.L10N.register(
"Select all" : "Alle auswählen",
"Upload too large" : "Der Upload ist zu groß",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Die Datei überschreitet die Maximalgröße für Uploads auf diesem Server.",
- "Files are being scanned, please wait." : "Dateien werden gescannt, bitte warten.",
- "Currently scanning" : "Durchsuchen läuft",
"No favorites" : "Keine Favoriten",
- "Files and folders you mark as favorite will show up here" : "Dateien und Ordner, die Sie als Favoriten kennzeichnen, werden hier erscheinen"
+ "Files and folders you mark as favorite will show up here" : "Dateien und Ordner, die Sie als Favoriten kennzeichnen, werden hier erscheinen",
+ "Text file" : "Textdatei",
+ "New text file.txt" : "Neue Textdatei file.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/de_DE.json b/apps/files/l10n/de_DE.json
index 5f7cd053e8e..f6a3abc9891 100644
--- a/apps/files/l10n/de_DE.json
+++ b/apps/files/l10n/de_DE.json
@@ -2,13 +2,6 @@
"Storage not available" : "Speicher nicht verfügbar",
"Storage invalid" : "Speicher ungültig",
"Unknown error" : "Unbekannter Fehler",
- "Could not move %s - File with this name already exists" : "%s konnte nicht verschoben werden. Eine Datei mit diesem Namen existiert bereits.",
- "Could not move %s" : "Konnte %s nicht verschieben",
- "Permission denied" : "Zugriff verweigert",
- "The target folder has been moved or deleted." : "Der Zielordner wurde verschoben oder gelöscht.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Der Name %s wird bereits im Ordner %s benutzt. Bitte wählen Sie einen anderen Namen.",
- "Error when creating the file" : "Fehler beim Erstellen der Datei",
- "Error when creating the folder" : "Fehler beim Erstellen des Ordners",
"Unable to set upload directory." : "Das Upload-Verzeichnis konnte nicht gesetzt werden.",
"Invalid Token" : "Ungültiger Token",
"No file was uploaded. Unknown error" : "Keine Datei hochgeladen. Unbekannter Fehler",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Kein temporärer Ordner vorhanden",
"Failed to write to disk" : "Fehler beim Schreiben auf die Festplatte",
"Not enough storage available" : "Nicht genug Speicher vorhanden.",
+ "The target folder has been moved or deleted." : "Der Zielordner wurde verschoben oder gelöscht.",
"Upload failed. Could not find uploaded file" : "Hochladen fehlgeschlagen. Die hochgeladene Datei konnte nicht gefunden werden.",
"Upload failed. Could not get file info." : "Hochladen fehlgeschlagen. Die Dateiinformationen konnten nicht abgerufen werden.",
"Invalid directory." : "Ungültiges Verzeichnis.",
@@ -38,20 +32,24 @@
"Download" : "Herunterladen",
"Rename" : "Umbenennen",
"Delete" : "Löschen",
+ "Disconnect storage" : "Speicher trennen",
+ "Unshare" : "Freigabe aufheben",
"Details" : "Details",
"Select" : "Auswählen",
"Pending" : "Ausstehend",
"Unable to determine date" : "Datum konnte nicht ermittelt werden",
"This operation is forbidden" : "Diese Operation ist nicht erlaubt",
"This directory is unavailable, please check the logs or contact the administrator" : "Dieses Verzeichnis ist nicht verfügbar, bitte überprüfen Sie die Logdateien oder kontaktieren Sie den Administrator",
- "Error moving file." : "Fehler beim Verschieben der Datei.",
- "Error moving file" : "Fehler beim Verschieben der Datei",
- "Error" : "Fehler",
- "{new_name} already exists" : "{new_name} existiert bereits",
- "Could not rename file" : "Die Datei konnte nicht umbenannt werden",
- "Could not create file" : "Die Datei konnte nicht erstellt werden",
- "Could not create folder" : "Der Ordner konnte nicht erstellt werden",
- "Error deleting file." : "Fehler beim Löschen der Datei.",
+ "Could not move \"{file}\", target exists" : "Die Datei konnte nicht verschoben werden \"{file}\", da die Datei im Zielordner bereits existiert",
+ "Could not move \"{file}\"" : "Die Datei konnte nicht verschoben werden \"{file}\"",
+ "{newName} already exists" : "{newName} existiert bereits",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Die Datei konnte nicht umbennant werden \"{fileName}\", da die Datei nicht mehr existiert",
+ "Could not rename \"{fileName}\"" : "Die Datei konnte nicht umbenannt werden \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Die Datei konnte nicht erstellt werden \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Die Datei konnte nicht erstellt werden \"{file}\", da diese bereits existiert",
+ "Could not create folder \"{dir}\"" : "Der Ordner konnte nicht erstellt werden \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Der Ordner konnte nicht erstellt werden \"{dir}\", da dieser bereits existiert",
+ "Error deleting file \"{fileName}\"." : "Fehler beim löschen der Datei \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Keine Einträge in diesem Ordner stimmen mit '{filter}' überein",
"Name" : "Name",
"Size" : "Größe",
@@ -69,11 +67,13 @@
"Storage of {owner} is almost full ({usedSpacePercent}%)" : "Der Speicher von {owner} ist beinahe voll ({usedSpacePercent}%)",
"Your storage is almost full ({usedSpacePercent}%)" : "Ihr Speicher ist fast voll ({usedSpacePercent}%)",
"_matches '{filter}'_::_match '{filter}'_" : ["stimmt mit '{filter}' überein","stimmen mit '{filter}' überein"],
+ "Path" : "Pfad",
+ "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Favorisiert",
"Favorite" : "Favorit",
- "Text file" : "Textdatei",
"Folder" : "Ordner",
"New folder" : "Neuer Ordner",
+ "{newname} already exists" : "{newname} existiert bereits",
"Upload" : "Hochladen",
"An error occurred while trying to update the tags" : "Es ist ein Fehler beim Aktualisieren der Tags aufgetreten",
"A new file or folder has been <strong>created</strong>" : "Eine neue Datei oder ein neuer Ordner wurde <strong>erstellt</strong>",
@@ -90,13 +90,15 @@
"%2$s deleted %1$s" : "%2$s hat %1$s gelöscht",
"You restored %1$s" : "Sie haben %1$s wiederhergestellt",
"%2$s restored %1$s" : "%2$s wiederhergestellt %1$s",
- "%s could not be renamed as it has been deleted" : "%s konnte nicht umbenannt werden, da es gelöscht wurde",
- "%s could not be renamed" : "%s konnte nicht umbenannt werden",
+ "Changed by %2$s" : "Geändert von %2$s",
+ "Deleted by %2$s" : "Gelöscht durch %2$s",
+ "Restored by %2$s" : "Wiederhergestellt durch %2$s",
"Upload (max. %s)" : "Hochladen (max. %s)",
"File handling" : "Dateibehandlung",
"Maximum upload size" : "Maximale Upload-Größe",
"max. possible: " : "maximal möglich:",
"Save" : "Speichern",
+ "Missing permissions to edit from here." : "Fehlende Berechtigungen um von hier aus zu bearbeiten.",
"Settings" : "Einstellungen",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Benutzen Sie diese Adresse, um <a href=\"%s\" target=\"_blank\">über WebDAV auf Ihre Dateien zuzugreifen</a>",
@@ -107,9 +109,9 @@
"Select all" : "Alle auswählen",
"Upload too large" : "Der Upload ist zu groß",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Die Datei überschreitet die Maximalgröße für Uploads auf diesem Server.",
- "Files are being scanned, please wait." : "Dateien werden gescannt, bitte warten.",
- "Currently scanning" : "Durchsuchen läuft",
"No favorites" : "Keine Favoriten",
- "Files and folders you mark as favorite will show up here" : "Dateien und Ordner, die Sie als Favoriten kennzeichnen, werden hier erscheinen"
+ "Files and folders you mark as favorite will show up here" : "Dateien und Ordner, die Sie als Favoriten kennzeichnen, werden hier erscheinen",
+ "Text file" : "Textdatei",
+ "New text file.txt" : "Neue Textdatei file.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/el.js b/apps/files/l10n/el.js
index 6c8e2cbff33..20b57e415b0 100644
--- a/apps/files/l10n/el.js
+++ b/apps/files/l10n/el.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Μη διαθέσιμος αποθηκευτικός χώρος",
"Storage invalid" : "Μη έγκυρος αποθηκευτικός χώρος",
"Unknown error" : "Άγνωστο σφάλμα",
- "Could not move %s - File with this name already exists" : "Αδυναμία μετακίνησης του %s - υπάρχει ήδη αρχείο με αυτό το όνομα",
- "Could not move %s" : "Αδυναμία μετακίνησης του %s",
- "Permission denied" : "Η πρόσβαση απορρίφθηκε",
- "The target folder has been moved or deleted." : "Ο φάκελος προορισμού έχει μετακινηθεί ή διαγραφεί.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Το όνομα %s χρησιμοποιείτε ήδη στον φάκελο %s. Παρακαλώ επιλέξτε ένα άλλο όνομα.",
- "Error when creating the file" : "Σφάλμα κατά τη δημιουργία του αρχείου",
- "Error when creating the folder" : "Σφάλμα κατά τη δημιουργία του φακέλου",
"Unable to set upload directory." : "Αδυναμία ορισμού καταλόγου αποστολής.",
"Invalid Token" : "Μη έγκυρο Token",
"No file was uploaded. Unknown error" : "Δεν ανέβηκε κάποιο αρχείο. Άγνωστο σφάλμα",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Λείπει ο προσωρινός φάκελος",
"Failed to write to disk" : "Αποτυχία εγγραφής στο δίσκο",
"Not enough storage available" : "Ο διαθέσιμος αποθηκευτικός χώρος δεν επαρκεί",
+ "The target folder has been moved or deleted." : "Ο φάκελος προορισμού έχει μετακινηθεί ή διαγραφεί.",
"Upload failed. Could not find uploaded file" : "Η φόρτωση απέτυχε. Αδυναμία εύρεσης αρχείου προς φόρτωση.",
"Upload failed. Could not get file info." : "Η φόρτωση απέτυχε. Αδυναμία λήψης πληροφοριών αρχείων.",
"Invalid directory." : "Μη έγκυρος φάκελος.",
@@ -40,20 +34,21 @@ OC.L10N.register(
"Download" : "Λήψη",
"Rename" : "Μετονομασία",
"Delete" : "Διαγραφή",
+ "Disconnect storage" : "Αποσυνδεδεμένος αποθηκευτικός χώρος",
+ "Unshare" : "Διακοπή διαμοιρασμού",
"Details" : "Λεπτομέρειες",
"Select" : "Επιλογή",
"Pending" : "Εκκρεμεί",
"Unable to determine date" : "Αδυναμία προσδιορισμού ημερομηνίας ",
"This operation is forbidden" : "Αυτή η ενέργεια δεν επιτρέπεται",
"This directory is unavailable, please check the logs or contact the administrator" : "Ο κατάλογος δεν είναι διαθέσιμος, παρακαλώ ελέγξτε τα αρχεία καταγραφής ή επικοινωνήστε με το διαχειριστή",
- "Error moving file." : "Σφάλμα κατά τη μετακίνηση του αρχείου.",
- "Error moving file" : "Σφάλμα κατά τη μετακίνηση του αρχείου",
- "Error" : "Σφάλμα",
- "{new_name} already exists" : "το {new_name} υπάρχει ήδη",
- "Could not rename file" : "Αδυναμία μετονομασίας αρχείου",
- "Could not create file" : "Αδυναμία δημιουργίας αρχείου",
- "Could not create folder" : "Αδυναμία δημιουργίας φακέλου",
- "Error deleting file." : "Σφάλμα κατά τη διαγραφή του αρχείου.",
+ "Could not move \"{file}\", target exists" : "Αδυναμία μετακίνησης του \"{file}\", υπάρχει ήδη αρχείο με αυτό το όνομα",
+ "Could not move \"{file}\"" : "Αδυναμία μετακίνησης του \"{file}\"",
+ "{newName} already exists" : "Το {newname} υπάρχει ήδη",
+ "Could not rename \"{fileName}\"" : "Αδυναμία μετονομασίας του \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Αδυναμία δημιουργίας του \"{file}\"",
+ "Could not create folder \"{dir}\"" : "Αδυναμία δημιουργίας του φακέλου \"{dir}\"",
+ "Error deleting file \"{fileName}\"." : "Αδυναμία διαγραφής του \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Δεν ταιριάζουν καταχωρήσεις σε αυτόν το φάκελο '{filter}'",
"Name" : "Όνομα",
"Size" : "Μέγεθος",
@@ -75,8 +70,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Προτιμώμενα",
"Favorite" : "Αγαπημένο",
- "Text file" : "Αρχείο κειμένου",
- "New text file.txt" : "Νέο αρχείο κειμένου.txt",
"Folder" : "Φάκελος",
"New folder" : "Νέος φάκελος",
"{newname} already exists" : "το {newname} υπάρχει ήδη",
@@ -99,8 +92,6 @@ OC.L10N.register(
"Changed by %2$s" : "Άλλαξε από το χρήστη %2$s",
"Deleted by %2$s" : "Διαγράφηκε από το χρήστη %2$s",
"Restored by %2$s" : "Επαναφορά από το χρήστη %2$s",
- "%s could not be renamed as it has been deleted" : "Το %s δεν μπορούσε να μετονομαστεί εφόσον είχε διαγραφεί",
- "%s could not be renamed" : "Αδυναμία μετονομασίας του %s",
"Upload (max. %s)" : "Διαμοιρασμός (max. %s)",
"File handling" : "Διαχείριση αρχείων",
"Maximum upload size" : "Μέγιστο μέγεθος αποστολής",
@@ -118,9 +109,9 @@ OC.L10N.register(
"Select all" : "Επιλογή όλων",
"Upload too large" : "Πολύ μεγάλο αρχείο προς αποστολή",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Τα αρχεία που προσπαθείτε να ανεβάσετε υπερβαίνουν το μέγιστο μέγεθος αποστολής αρχείων σε αυτόν τον διακομιστή.",
- "Files are being scanned, please wait." : "Τα αρχεία σαρώνονται, παρακαλώ περιμένετε.",
- "Currently scanning" : "Σάρωση σε εξέλιξη",
"No favorites" : "Δεν υπάρχουν αγαπημένα",
- "Files and folders you mark as favorite will show up here" : "Τα αρχεία και οι φάκελοι που σημειώνονται ως αγαπημένα θα εμφανιστούν εδώ "
+ "Files and folders you mark as favorite will show up here" : "Τα αρχεία και οι φάκελοι που σημειώνονται ως αγαπημένα θα εμφανιστούν εδώ ",
+ "Text file" : "Αρχείο κειμένου",
+ "New text file.txt" : "Νέο αρχείο κειμένου.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/el.json b/apps/files/l10n/el.json
index ee9e4ebde54..849b0ee8a09 100644
--- a/apps/files/l10n/el.json
+++ b/apps/files/l10n/el.json
@@ -2,13 +2,6 @@
"Storage not available" : "Μη διαθέσιμος αποθηκευτικός χώρος",
"Storage invalid" : "Μη έγκυρος αποθηκευτικός χώρος",
"Unknown error" : "Άγνωστο σφάλμα",
- "Could not move %s - File with this name already exists" : "Αδυναμία μετακίνησης του %s - υπάρχει ήδη αρχείο με αυτό το όνομα",
- "Could not move %s" : "Αδυναμία μετακίνησης του %s",
- "Permission denied" : "Η πρόσβαση απορρίφθηκε",
- "The target folder has been moved or deleted." : "Ο φάκελος προορισμού έχει μετακινηθεί ή διαγραφεί.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Το όνομα %s χρησιμοποιείτε ήδη στον φάκελο %s. Παρακαλώ επιλέξτε ένα άλλο όνομα.",
- "Error when creating the file" : "Σφάλμα κατά τη δημιουργία του αρχείου",
- "Error when creating the folder" : "Σφάλμα κατά τη δημιουργία του φακέλου",
"Unable to set upload directory." : "Αδυναμία ορισμού καταλόγου αποστολής.",
"Invalid Token" : "Μη έγκυρο Token",
"No file was uploaded. Unknown error" : "Δεν ανέβηκε κάποιο αρχείο. Άγνωστο σφάλμα",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Λείπει ο προσωρινός φάκελος",
"Failed to write to disk" : "Αποτυχία εγγραφής στο δίσκο",
"Not enough storage available" : "Ο διαθέσιμος αποθηκευτικός χώρος δεν επαρκεί",
+ "The target folder has been moved or deleted." : "Ο φάκελος προορισμού έχει μετακινηθεί ή διαγραφεί.",
"Upload failed. Could not find uploaded file" : "Η φόρτωση απέτυχε. Αδυναμία εύρεσης αρχείου προς φόρτωση.",
"Upload failed. Could not get file info." : "Η φόρτωση απέτυχε. Αδυναμία λήψης πληροφοριών αρχείων.",
"Invalid directory." : "Μη έγκυρος φάκελος.",
@@ -38,20 +32,21 @@
"Download" : "Λήψη",
"Rename" : "Μετονομασία",
"Delete" : "Διαγραφή",
+ "Disconnect storage" : "Αποσυνδεδεμένος αποθηκευτικός χώρος",
+ "Unshare" : "Διακοπή διαμοιρασμού",
"Details" : "Λεπτομέρειες",
"Select" : "Επιλογή",
"Pending" : "Εκκρεμεί",
"Unable to determine date" : "Αδυναμία προσδιορισμού ημερομηνίας ",
"This operation is forbidden" : "Αυτή η ενέργεια δεν επιτρέπεται",
"This directory is unavailable, please check the logs or contact the administrator" : "Ο κατάλογος δεν είναι διαθέσιμος, παρακαλώ ελέγξτε τα αρχεία καταγραφής ή επικοινωνήστε με το διαχειριστή",
- "Error moving file." : "Σφάλμα κατά τη μετακίνηση του αρχείου.",
- "Error moving file" : "Σφάλμα κατά τη μετακίνηση του αρχείου",
- "Error" : "Σφάλμα",
- "{new_name} already exists" : "το {new_name} υπάρχει ήδη",
- "Could not rename file" : "Αδυναμία μετονομασίας αρχείου",
- "Could not create file" : "Αδυναμία δημιουργίας αρχείου",
- "Could not create folder" : "Αδυναμία δημιουργίας φακέλου",
- "Error deleting file." : "Σφάλμα κατά τη διαγραφή του αρχείου.",
+ "Could not move \"{file}\", target exists" : "Αδυναμία μετακίνησης του \"{file}\", υπάρχει ήδη αρχείο με αυτό το όνομα",
+ "Could not move \"{file}\"" : "Αδυναμία μετακίνησης του \"{file}\"",
+ "{newName} already exists" : "Το {newname} υπάρχει ήδη",
+ "Could not rename \"{fileName}\"" : "Αδυναμία μετονομασίας του \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Αδυναμία δημιουργίας του \"{file}\"",
+ "Could not create folder \"{dir}\"" : "Αδυναμία δημιουργίας του φακέλου \"{dir}\"",
+ "Error deleting file \"{fileName}\"." : "Αδυναμία διαγραφής του \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Δεν ταιριάζουν καταχωρήσεις σε αυτόν το φάκελο '{filter}'",
"Name" : "Όνομα",
"Size" : "Μέγεθος",
@@ -73,8 +68,6 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Προτιμώμενα",
"Favorite" : "Αγαπημένο",
- "Text file" : "Αρχείο κειμένου",
- "New text file.txt" : "Νέο αρχείο κειμένου.txt",
"Folder" : "Φάκελος",
"New folder" : "Νέος φάκελος",
"{newname} already exists" : "το {newname} υπάρχει ήδη",
@@ -97,8 +90,6 @@
"Changed by %2$s" : "Άλλαξε από το χρήστη %2$s",
"Deleted by %2$s" : "Διαγράφηκε από το χρήστη %2$s",
"Restored by %2$s" : "Επαναφορά από το χρήστη %2$s",
- "%s could not be renamed as it has been deleted" : "Το %s δεν μπορούσε να μετονομαστεί εφόσον είχε διαγραφεί",
- "%s could not be renamed" : "Αδυναμία μετονομασίας του %s",
"Upload (max. %s)" : "Διαμοιρασμός (max. %s)",
"File handling" : "Διαχείριση αρχείων",
"Maximum upload size" : "Μέγιστο μέγεθος αποστολής",
@@ -116,9 +107,9 @@
"Select all" : "Επιλογή όλων",
"Upload too large" : "Πολύ μεγάλο αρχείο προς αποστολή",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Τα αρχεία που προσπαθείτε να ανεβάσετε υπερβαίνουν το μέγιστο μέγεθος αποστολής αρχείων σε αυτόν τον διακομιστή.",
- "Files are being scanned, please wait." : "Τα αρχεία σαρώνονται, παρακαλώ περιμένετε.",
- "Currently scanning" : "Σάρωση σε εξέλιξη",
"No favorites" : "Δεν υπάρχουν αγαπημένα",
- "Files and folders you mark as favorite will show up here" : "Τα αρχεία και οι φάκελοι που σημειώνονται ως αγαπημένα θα εμφανιστούν εδώ "
+ "Files and folders you mark as favorite will show up here" : "Τα αρχεία και οι φάκελοι που σημειώνονται ως αγαπημένα θα εμφανιστούν εδώ ",
+ "Text file" : "Αρχείο κειμένου",
+ "New text file.txt" : "Νέο αρχείο κειμένου.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/en_GB.js b/apps/files/l10n/en_GB.js
index cf37ac56dc0..03358df97a7 100644
--- a/apps/files/l10n/en_GB.js
+++ b/apps/files/l10n/en_GB.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Storage not available",
"Storage invalid" : "Storage invalid",
"Unknown error" : "Unknown error",
- "Could not move %s - File with this name already exists" : "Could not move %s - File with this name already exists",
- "Could not move %s" : "Could not move %s",
- "Permission denied" : "Permission denied",
- "The target folder has been moved or deleted." : "The target folder has been moved or deleted.",
- "The name %s is already used in the folder %s. Please choose a different name." : "The name %s is already used in the folder %s. Please choose a different name.",
- "Error when creating the file" : "Error when creating the file",
- "Error when creating the folder" : "Error when creating the folder",
"Unable to set upload directory." : "Unable to set upload directory.",
"Invalid Token" : "Invalid Token",
"No file was uploaded. Unknown error" : "No file was uploaded. Unknown error",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Missing a temporary folder",
"Failed to write to disk" : "Failed to write to disk",
"Not enough storage available" : "Not enough storage available",
+ "The target folder has been moved or deleted." : "The target folder has been moved or deleted.",
"Upload failed. Could not find uploaded file" : "Upload failed. Could not find uploaded file",
"Upload failed. Could not get file info." : "Upload failed. Could not get file info.",
"Invalid directory." : "Invalid directory.",
@@ -40,18 +34,12 @@ OC.L10N.register(
"Download" : "Download",
"Rename" : "Rename",
"Delete" : "Delete",
+ "Disconnect storage" : "Disconnect storage",
+ "Unshare" : "Unshare",
"Details" : "Details",
"Select" : "Select",
"Pending" : "Pending",
"Unable to determine date" : "Unable to determine date",
- "Error moving file." : "Error moving file.",
- "Error moving file" : "Error moving file",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} already exists",
- "Could not rename file" : "Could not rename file",
- "Could not create file" : "Could not create file",
- "Could not create folder" : "Could not create folder",
- "Error deleting file." : "Error deleting file.",
"No entries in this folder match '{filter}'" : "No entries in this folder match '{filter}'",
"Name" : "Name",
"Size" : "Size",
@@ -69,7 +57,6 @@ OC.L10N.register(
"_matches '{filter}'_::_match '{filter}'_" : ["matches '{filter}'","match '{filter}'"],
"Favorited" : "Favourited",
"Favorite" : "Favourite",
- "Text file" : "Text file",
"Folder" : "Folder",
"New folder" : "New folder",
"Upload" : "Upload",
@@ -88,8 +75,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s deleted %1$s",
"You restored %1$s" : "You restored %1$s",
"%2$s restored %1$s" : "%2$s restored %1$s",
- "%s could not be renamed as it has been deleted" : "%s could not be renamed as it has been deleted",
- "%s could not be renamed" : "%s could not be renamed",
"Upload (max. %s)" : "Upload (max. %s)",
"File handling" : "File handling",
"Maximum upload size" : "Maximum upload size",
@@ -105,9 +90,8 @@ OC.L10N.register(
"Select all" : "Select all",
"Upload too large" : "Upload too large",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "The files you are trying to upload exceed the maximum size for file uploads on this server.",
- "Files are being scanned, please wait." : "Files are being scanned, please wait.",
- "Currently scanning" : "Currently scanning",
"No favorites" : "No favourites",
- "Files and folders you mark as favorite will show up here" : "Files and folders you mark as favourite will show up here"
+ "Files and folders you mark as favorite will show up here" : "Files and folders you mark as favourite will show up here",
+ "Text file" : "Text file"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/en_GB.json b/apps/files/l10n/en_GB.json
index 764198384a6..f7b5e5e76f8 100644
--- a/apps/files/l10n/en_GB.json
+++ b/apps/files/l10n/en_GB.json
@@ -2,13 +2,6 @@
"Storage not available" : "Storage not available",
"Storage invalid" : "Storage invalid",
"Unknown error" : "Unknown error",
- "Could not move %s - File with this name already exists" : "Could not move %s - File with this name already exists",
- "Could not move %s" : "Could not move %s",
- "Permission denied" : "Permission denied",
- "The target folder has been moved or deleted." : "The target folder has been moved or deleted.",
- "The name %s is already used in the folder %s. Please choose a different name." : "The name %s is already used in the folder %s. Please choose a different name.",
- "Error when creating the file" : "Error when creating the file",
- "Error when creating the folder" : "Error when creating the folder",
"Unable to set upload directory." : "Unable to set upload directory.",
"Invalid Token" : "Invalid Token",
"No file was uploaded. Unknown error" : "No file was uploaded. Unknown error",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Missing a temporary folder",
"Failed to write to disk" : "Failed to write to disk",
"Not enough storage available" : "Not enough storage available",
+ "The target folder has been moved or deleted." : "The target folder has been moved or deleted.",
"Upload failed. Could not find uploaded file" : "Upload failed. Could not find uploaded file",
"Upload failed. Could not get file info." : "Upload failed. Could not get file info.",
"Invalid directory." : "Invalid directory.",
@@ -38,18 +32,12 @@
"Download" : "Download",
"Rename" : "Rename",
"Delete" : "Delete",
+ "Disconnect storage" : "Disconnect storage",
+ "Unshare" : "Unshare",
"Details" : "Details",
"Select" : "Select",
"Pending" : "Pending",
"Unable to determine date" : "Unable to determine date",
- "Error moving file." : "Error moving file.",
- "Error moving file" : "Error moving file",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} already exists",
- "Could not rename file" : "Could not rename file",
- "Could not create file" : "Could not create file",
- "Could not create folder" : "Could not create folder",
- "Error deleting file." : "Error deleting file.",
"No entries in this folder match '{filter}'" : "No entries in this folder match '{filter}'",
"Name" : "Name",
"Size" : "Size",
@@ -67,7 +55,6 @@
"_matches '{filter}'_::_match '{filter}'_" : ["matches '{filter}'","match '{filter}'"],
"Favorited" : "Favourited",
"Favorite" : "Favourite",
- "Text file" : "Text file",
"Folder" : "Folder",
"New folder" : "New folder",
"Upload" : "Upload",
@@ -86,8 +73,6 @@
"%2$s deleted %1$s" : "%2$s deleted %1$s",
"You restored %1$s" : "You restored %1$s",
"%2$s restored %1$s" : "%2$s restored %1$s",
- "%s could not be renamed as it has been deleted" : "%s could not be renamed as it has been deleted",
- "%s could not be renamed" : "%s could not be renamed",
"Upload (max. %s)" : "Upload (max. %s)",
"File handling" : "File handling",
"Maximum upload size" : "Maximum upload size",
@@ -103,9 +88,8 @@
"Select all" : "Select all",
"Upload too large" : "Upload too large",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "The files you are trying to upload exceed the maximum size for file uploads on this server.",
- "Files are being scanned, please wait." : "Files are being scanned, please wait.",
- "Currently scanning" : "Currently scanning",
"No favorites" : "No favourites",
- "Files and folders you mark as favorite will show up here" : "Files and folders you mark as favourite will show up here"
+ "Files and folders you mark as favorite will show up here" : "Files and folders you mark as favourite will show up here",
+ "Text file" : "Text file"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/eo.js b/apps/files/l10n/eo.js
index eb8ffd7728b..4d52e391112 100644
--- a/apps/files/l10n/eo.js
+++ b/apps/files/l10n/eo.js
@@ -2,11 +2,6 @@ OC.L10N.register(
"files",
{
"Unknown error" : "Nekonata eraro",
- "Could not move %s - File with this name already exists" : "Ne eblis movi %s: dosiero kun ĉi tiu nomo jam ekzistas",
- "Could not move %s" : "Ne eblis movi %s",
- "The name %s is already used in the folder %s. Please choose a different name." : "La nomo %s jam uziĝas en la dosierujo %s. Bonvolu elekti malsaman nomon.",
- "Error when creating the file" : "Eraris la kreo de la dosiero",
- "Error when creating the folder" : "Eraris la kreo de la dosierujo",
"Unable to set upload directory." : "Ne povis agordiĝi la alŝuta dosierujo.",
"No file was uploaded. Unknown error" : "Neniu dosiero alŝutiĝis. Nekonata eraro.",
"There is no error, the file uploaded with success" : "Ne estas eraro, la dosiero alŝutiĝis sukcese.",
@@ -33,15 +28,10 @@ OC.L10N.register(
"Download" : "Elŝuti",
"Rename" : "Alinomigi",
"Delete" : "Forigi",
+ "Unshare" : "Malkunhavigi",
"Details" : "Detaloj",
"Select" : "Elekti",
"Pending" : "Traktotaj",
- "Error moving file" : "Eraris movo de dosiero",
- "Error" : "Eraro",
- "{new_name} already exists" : "{new_name} jam ekzistas",
- "Could not rename file" : "Ne povis alinomiĝi dosiero",
- "Could not create file" : "Ne povis kreiĝi dosiero",
- "Could not create folder" : "Ne povis kreiĝi dosierujo",
"Name" : "Nomo",
"Size" : "Grando",
"Modified" : "Modifita",
@@ -55,7 +45,6 @@ OC.L10N.register(
"Your storage is full, files can not be updated or synced anymore!" : "Via memoro plenas, ne plu eblas ĝisdatigi aŭ sinkronigi dosierojn!",
"Your storage is almost full ({usedSpacePercent}%)" : "Via memoro preskaŭ plenas ({usedSpacePercent}%)",
"Favorite" : "Favorato",
- "Text file" : "Tekstodosiero",
"Folder" : "Dosierujo",
"New folder" : "Nova dosierujo",
"Upload" : "Alŝuti",
@@ -66,8 +55,6 @@ OC.L10N.register(
"%2$s changed %1$s" : "%2$s ŝanĝis %1$s",
"You deleted %1$s" : "Vi forigis %1$s",
"%2$s deleted %1$s" : "%2$s forigis %1$s",
- "%s could not be renamed as it has been deleted" : "%s ne povis alinomiĝi ĉar ĝi forigitis",
- "%s could not be renamed" : "%s ne povis alinomiĝi",
"Upload (max. %s)" : "Alŝuti (maks. %s)",
"File handling" : "Dosieradministro",
"Maximum upload size" : "Maksimuma alŝutogrando",
@@ -81,6 +68,6 @@ OC.L10N.register(
"Select all" : "Elekti ĉion",
"Upload too large" : "Alŝuto tro larĝa",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "La dosieroj, kiujn vi provas alŝuti, transpasas la maksimuman grandon por dosieralŝutoj en ĉi tiu servilo.",
- "Files are being scanned, please wait." : "Dosieroj estas skanataj, bonvolu atendi."
+ "Text file" : "Tekstodosiero"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/eo.json b/apps/files/l10n/eo.json
index 5f899df1e0c..844da285e2b 100644
--- a/apps/files/l10n/eo.json
+++ b/apps/files/l10n/eo.json
@@ -1,10 +1,5 @@
{ "translations": {
"Unknown error" : "Nekonata eraro",
- "Could not move %s - File with this name already exists" : "Ne eblis movi %s: dosiero kun ĉi tiu nomo jam ekzistas",
- "Could not move %s" : "Ne eblis movi %s",
- "The name %s is already used in the folder %s. Please choose a different name." : "La nomo %s jam uziĝas en la dosierujo %s. Bonvolu elekti malsaman nomon.",
- "Error when creating the file" : "Eraris la kreo de la dosiero",
- "Error when creating the folder" : "Eraris la kreo de la dosierujo",
"Unable to set upload directory." : "Ne povis agordiĝi la alŝuta dosierujo.",
"No file was uploaded. Unknown error" : "Neniu dosiero alŝutiĝis. Nekonata eraro.",
"There is no error, the file uploaded with success" : "Ne estas eraro, la dosiero alŝutiĝis sukcese.",
@@ -31,15 +26,10 @@
"Download" : "Elŝuti",
"Rename" : "Alinomigi",
"Delete" : "Forigi",
+ "Unshare" : "Malkunhavigi",
"Details" : "Detaloj",
"Select" : "Elekti",
"Pending" : "Traktotaj",
- "Error moving file" : "Eraris movo de dosiero",
- "Error" : "Eraro",
- "{new_name} already exists" : "{new_name} jam ekzistas",
- "Could not rename file" : "Ne povis alinomiĝi dosiero",
- "Could not create file" : "Ne povis kreiĝi dosiero",
- "Could not create folder" : "Ne povis kreiĝi dosierujo",
"Name" : "Nomo",
"Size" : "Grando",
"Modified" : "Modifita",
@@ -53,7 +43,6 @@
"Your storage is full, files can not be updated or synced anymore!" : "Via memoro plenas, ne plu eblas ĝisdatigi aŭ sinkronigi dosierojn!",
"Your storage is almost full ({usedSpacePercent}%)" : "Via memoro preskaŭ plenas ({usedSpacePercent}%)",
"Favorite" : "Favorato",
- "Text file" : "Tekstodosiero",
"Folder" : "Dosierujo",
"New folder" : "Nova dosierujo",
"Upload" : "Alŝuti",
@@ -64,8 +53,6 @@
"%2$s changed %1$s" : "%2$s ŝanĝis %1$s",
"You deleted %1$s" : "Vi forigis %1$s",
"%2$s deleted %1$s" : "%2$s forigis %1$s",
- "%s could not be renamed as it has been deleted" : "%s ne povis alinomiĝi ĉar ĝi forigitis",
- "%s could not be renamed" : "%s ne povis alinomiĝi",
"Upload (max. %s)" : "Alŝuti (maks. %s)",
"File handling" : "Dosieradministro",
"Maximum upload size" : "Maksimuma alŝutogrando",
@@ -79,6 +66,6 @@
"Select all" : "Elekti ĉion",
"Upload too large" : "Alŝuto tro larĝa",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "La dosieroj, kiujn vi provas alŝuti, transpasas la maksimuman grandon por dosieralŝutoj en ĉi tiu servilo.",
- "Files are being scanned, please wait." : "Dosieroj estas skanataj, bonvolu atendi."
+ "Text file" : "Tekstodosiero"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/es.js b/apps/files/l10n/es.js
index 5226fb4774e..9b8b43ad5a1 100644
--- a/apps/files/l10n/es.js
+++ b/apps/files/l10n/es.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Almacenamiento no disponible",
"Storage invalid" : "Almacenamiento inválido",
"Unknown error" : "Error desconocido",
- "Could not move %s - File with this name already exists" : "No se pudo mover %s - Ya existe un archivo con ese nombre.",
- "Could not move %s" : "No se pudo mover %s",
- "Permission denied" : "Permiso denegado",
- "The target folder has been moved or deleted." : "La carpeta de destino fue movida o eliminada.",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nombre %s ya está en uso por la carpeta %s. Por favor elija uno diferente.",
- "Error when creating the file" : "Error al crear el archivo",
- "Error when creating the folder" : "Error al crear la carpeta.",
"Unable to set upload directory." : "Incapaz de crear directorio de subida.",
"Invalid Token" : "Token Inválido",
"No file was uploaded. Unknown error" : "No se subió ningún archivo. Error desconocido",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Falta la carpeta temporal",
"Failed to write to disk" : "Falló al escribir al disco",
"Not enough storage available" : "No hay suficiente espacio disponible",
+ "The target folder has been moved or deleted." : "La carpeta de destino fue movida o eliminada.",
"Upload failed. Could not find uploaded file" : "Actualización fallida. No se pudo encontrar el archivo subido",
"Upload failed. Could not get file info." : "Actualización fallida. No se pudo obtener información del archivo.",
"Invalid directory." : "Directorio inválido.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Descargar",
"Rename" : "Renombrar",
"Delete" : "Eliminar",
+ "Disconnect storage" : "Desconectar almacenamiento",
+ "Unshare" : "Dejar de compartir",
"Details" : "Detalles",
"Select" : "Seleccionar",
"Pending" : "Pendiente",
"Unable to determine date" : "No se pudo determinar la fecha",
"This operation is forbidden" : "Esta operación está prohibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Esta carpeta no está disponible, por favor verifique los registros o contáctese con el administrador",
- "Error moving file." : "Error al mover el archivo.",
- "Error moving file" : "Error moviendo archivo",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} ya existe",
- "Could not rename file" : "No se pudo renombrar el archivo",
- "Could not create file" : "No se pudo crear el archivo",
- "Could not create folder" : "No se pudo crear la carpeta",
- "Error deleting file." : "Error al borrar el archivo",
+ "Could not move \"{file}\", target exists" : "No se pudo mover \"{file}\", destino ya existe",
+ "Could not move \"{file}\"" : "No se pudo mover \"{file}\"",
+ "{newName} already exists" : "{newName} ya existe",
+ "Could not rename \"{fileName}\", it does not exist any more" : "No se pudo renombrar \"{fileName}\", ya no existe",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "El nombre \"{targetName}\" ya se utiliza en la carpeta \"{dir}\". Por favor elija un nombre diferente.",
+ "Could not rename \"{fileName}\"" : "No se pudo renombrar \"{fileName}\"",
+ "Could not create file \"{file}\"" : "No se pudo crear archivo \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "No se pudo crear archivo \"{file}\" porque ya existe",
+ "Could not create folder \"{dir}\"" : "No se pudo crear la carpeta \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "No se pudo crear la carpeta \"{dir}\" porque ya existe",
+ "Error deleting file \"{fileName}\"." : "Error al borrar el archivo \"{fileName}\".",
"No entries in this folder match '{filter}'" : "No hay resultados que coincidan con '{filter}'",
"Name" : "Nombre",
"Size" : "Tamaño",
@@ -75,11 +74,9 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Agregado a Favoritos",
"Favorite" : "Favorito",
- "Text file" : "Archivo de texto",
- "New text file.txt" : "Nuevo archivo de texto.txt",
"Folder" : "Carpeta",
"New folder" : "Nueva carpeta",
- "{newname} already exists" : "{new_name} ya existe",
+ "{newname} already exists" : "{newname} ya existe",
"Upload" : "Subir",
"An error occurred while trying to update the tags" : "Se produjo un error al tratar de actualizar las etiquetas",
"A new file or folder has been <strong>created</strong>" : "Se ha <strong>creado</strong> un nuevo archivo o carpeta",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "Cambiado por %2$s",
"Deleted by %2$s" : "Eliminado por %2$s",
"Restored by %2$s" : "Restaurado por %2$s",
- "%s could not be renamed as it has been deleted" : "%s no se pudo renombrar pues ha sido eliminado",
- "%s could not be renamed" : "%s no pudo ser renombrado",
"Upload (max. %s)" : "Subida (máx. %s)",
"File handling" : "Administración de archivos",
"Maximum upload size" : "Tamaño máximo de subida",
"max. possible: " : "máx. posible:",
"Save" : "Guardar",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Con PHP-FPM podría tomar 5 minutos para que los cambios se apliquen.",
+ "Missing permissions to edit from here." : "Faltan permisos para poder editar desde aquí.",
"Settings" : "Ajustes",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Use esta URL <a href=\"%s\" target=\"_blank\">para acceder via WebDAV</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "Seleccionar todo",
"Upload too large" : "Subida demasido grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los archivos que está intentando subir sobrepasan el tamaño máximo permitido en este servidor.",
- "Files are being scanned, please wait." : "Los archivos se están escaneando, por favor espere.",
- "Currently scanning" : "Escaneando en este momento",
"No favorites" : "No hay favoritos",
- "Files and folders you mark as favorite will show up here" : "Aquí aparecerán los archivos y carpetas que usted marque como favoritos"
+ "Files and folders you mark as favorite will show up here" : "Aquí aparecerán los archivos y carpetas que usted marque como favoritos",
+ "Text file" : "Archivo de texto",
+ "New text file.txt" : "Nuevo archivo de texto.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/es.json b/apps/files/l10n/es.json
index cb255204571..f0649db14b2 100644
--- a/apps/files/l10n/es.json
+++ b/apps/files/l10n/es.json
@@ -2,13 +2,6 @@
"Storage not available" : "Almacenamiento no disponible",
"Storage invalid" : "Almacenamiento inválido",
"Unknown error" : "Error desconocido",
- "Could not move %s - File with this name already exists" : "No se pudo mover %s - Ya existe un archivo con ese nombre.",
- "Could not move %s" : "No se pudo mover %s",
- "Permission denied" : "Permiso denegado",
- "The target folder has been moved or deleted." : "La carpeta de destino fue movida o eliminada.",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nombre %s ya está en uso por la carpeta %s. Por favor elija uno diferente.",
- "Error when creating the file" : "Error al crear el archivo",
- "Error when creating the folder" : "Error al crear la carpeta.",
"Unable to set upload directory." : "Incapaz de crear directorio de subida.",
"Invalid Token" : "Token Inválido",
"No file was uploaded. Unknown error" : "No se subió ningún archivo. Error desconocido",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Falta la carpeta temporal",
"Failed to write to disk" : "Falló al escribir al disco",
"Not enough storage available" : "No hay suficiente espacio disponible",
+ "The target folder has been moved or deleted." : "La carpeta de destino fue movida o eliminada.",
"Upload failed. Could not find uploaded file" : "Actualización fallida. No se pudo encontrar el archivo subido",
"Upload failed. Could not get file info." : "Actualización fallida. No se pudo obtener información del archivo.",
"Invalid directory." : "Directorio inválido.",
@@ -38,20 +32,25 @@
"Download" : "Descargar",
"Rename" : "Renombrar",
"Delete" : "Eliminar",
+ "Disconnect storage" : "Desconectar almacenamiento",
+ "Unshare" : "Dejar de compartir",
"Details" : "Detalles",
"Select" : "Seleccionar",
"Pending" : "Pendiente",
"Unable to determine date" : "No se pudo determinar la fecha",
"This operation is forbidden" : "Esta operación está prohibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Esta carpeta no está disponible, por favor verifique los registros o contáctese con el administrador",
- "Error moving file." : "Error al mover el archivo.",
- "Error moving file" : "Error moviendo archivo",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} ya existe",
- "Could not rename file" : "No se pudo renombrar el archivo",
- "Could not create file" : "No se pudo crear el archivo",
- "Could not create folder" : "No se pudo crear la carpeta",
- "Error deleting file." : "Error al borrar el archivo",
+ "Could not move \"{file}\", target exists" : "No se pudo mover \"{file}\", destino ya existe",
+ "Could not move \"{file}\"" : "No se pudo mover \"{file}\"",
+ "{newName} already exists" : "{newName} ya existe",
+ "Could not rename \"{fileName}\", it does not exist any more" : "No se pudo renombrar \"{fileName}\", ya no existe",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "El nombre \"{targetName}\" ya se utiliza en la carpeta \"{dir}\". Por favor elija un nombre diferente.",
+ "Could not rename \"{fileName}\"" : "No se pudo renombrar \"{fileName}\"",
+ "Could not create file \"{file}\"" : "No se pudo crear archivo \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "No se pudo crear archivo \"{file}\" porque ya existe",
+ "Could not create folder \"{dir}\"" : "No se pudo crear la carpeta \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "No se pudo crear la carpeta \"{dir}\" porque ya existe",
+ "Error deleting file \"{fileName}\"." : "Error al borrar el archivo \"{fileName}\".",
"No entries in this folder match '{filter}'" : "No hay resultados que coincidan con '{filter}'",
"Name" : "Nombre",
"Size" : "Tamaño",
@@ -73,11 +72,9 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Agregado a Favoritos",
"Favorite" : "Favorito",
- "Text file" : "Archivo de texto",
- "New text file.txt" : "Nuevo archivo de texto.txt",
"Folder" : "Carpeta",
"New folder" : "Nueva carpeta",
- "{newname} already exists" : "{new_name} ya existe",
+ "{newname} already exists" : "{newname} ya existe",
"Upload" : "Subir",
"An error occurred while trying to update the tags" : "Se produjo un error al tratar de actualizar las etiquetas",
"A new file or folder has been <strong>created</strong>" : "Se ha <strong>creado</strong> un nuevo archivo o carpeta",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "Cambiado por %2$s",
"Deleted by %2$s" : "Eliminado por %2$s",
"Restored by %2$s" : "Restaurado por %2$s",
- "%s could not be renamed as it has been deleted" : "%s no se pudo renombrar pues ha sido eliminado",
- "%s could not be renamed" : "%s no pudo ser renombrado",
"Upload (max. %s)" : "Subida (máx. %s)",
"File handling" : "Administración de archivos",
"Maximum upload size" : "Tamaño máximo de subida",
"max. possible: " : "máx. posible:",
"Save" : "Guardar",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Con PHP-FPM podría tomar 5 minutos para que los cambios se apliquen.",
+ "Missing permissions to edit from here." : "Faltan permisos para poder editar desde aquí.",
"Settings" : "Ajustes",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Use esta URL <a href=\"%s\" target=\"_blank\">para acceder via WebDAV</a>",
@@ -114,9 +111,9 @@
"Select all" : "Seleccionar todo",
"Upload too large" : "Subida demasido grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los archivos que está intentando subir sobrepasan el tamaño máximo permitido en este servidor.",
- "Files are being scanned, please wait." : "Los archivos se están escaneando, por favor espere.",
- "Currently scanning" : "Escaneando en este momento",
"No favorites" : "No hay favoritos",
- "Files and folders you mark as favorite will show up here" : "Aquí aparecerán los archivos y carpetas que usted marque como favoritos"
+ "Files and folders you mark as favorite will show up here" : "Aquí aparecerán los archivos y carpetas que usted marque como favoritos",
+ "Text file" : "Archivo de texto",
+ "New text file.txt" : "Nuevo archivo de texto.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/es_AR.js b/apps/files/l10n/es_AR.js
index 4f74717175d..bd4504592f1 100644
--- a/apps/files/l10n/es_AR.js
+++ b/apps/files/l10n/es_AR.js
@@ -1,12 +1,9 @@
OC.L10N.register(
"files",
{
+ "Storage not available" : "Almacenamiento no disponible",
+ "Storage invalid" : "Almacenamiento invalido",
"Unknown error" : "Error desconocido",
- "Could not move %s - File with this name already exists" : "No se pudo mover %s - Un archivo con este nombre ya existe",
- "Could not move %s" : "No se pudo mover %s ",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nombre %s está en uso en el directorio %s. Por favor elija un otro nombre.",
- "Error when creating the file" : "Error al crear el archivo",
- "Error when creating the folder" : "Error al crear el directorio",
"Unable to set upload directory." : "No fue posible crear el directorio de subida.",
"Invalid Token" : "Token Inválido",
"No file was uploaded. Unknown error" : "El archivo no fue subido. Error desconocido",
@@ -18,31 +15,30 @@ OC.L10N.register(
"Missing a temporary folder" : "Falta un directorio temporal",
"Failed to write to disk" : "Error al escribir en el disco",
"Not enough storage available" : "No hay suficiente almacenamiento",
+ "The target folder has been moved or deleted." : "La carpeta destino fue movida o borrada.",
"Upload failed. Could not find uploaded file" : "Falló la carga. No se pudo encontrar el archivo subido.",
"Upload failed. Could not get file info." : "Falló la carga. No se pudo obtener la información del archivo.",
"Invalid directory." : "Directorio inválido.",
"Files" : "Archivos",
+ "All files" : "Todos los archivos",
"Favorites" : "Favoritos",
"Home" : "Particular",
"Close" : "Cerrar",
"Upload cancelled." : "La subida fue cancelada",
"Unable to upload {filename} as it is a directory or has 0 bytes" : "Imposible cargar {filename} puesto que es un directoro o tiene 0 bytes.",
+ "Total file size {size1} exceeds upload limit {size2}" : "El tamaño total del archivo {size1} excede el límite {size2}",
+ "Not enough free space, you are uploading {size1} but only {size2} is left" : "No hay suficiente espacio libre. Quiere subir {size1} pero solo quedan {size2}",
"Could not get result from server." : "No se pudo obtener resultados del servidor.",
"File upload is in progress. Leaving the page now will cancel the upload." : "La subida del archivo está en proceso. Si salís de la página ahora, la subida se cancelará.",
"Actions" : "Acciones",
"Download" : "Descargar",
"Rename" : "Cambiar nombre",
"Delete" : "Borrar",
+ "Unshare" : "Dejar de compartir",
"Details" : "Detalles",
"Select" : "Seleccionar",
"Pending" : "Pendientes",
- "Error moving file" : "Error moviendo el archivo",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} ya existe",
- "Could not rename file" : "No se pudo renombrar el archivo",
- "Could not create file" : "No se pudo crear el archivo",
- "Could not create folder" : "No se pudo crear el directorio",
- "Error deleting file." : "Error al borrar el archivo.",
+ "Unable to determine date" : "No fue posible determinar la fecha",
"Name" : "Nombre",
"Size" : "Tamaño",
"Modified" : "Modificado",
@@ -56,7 +52,6 @@ OC.L10N.register(
"Your storage is full, files can not be updated or synced anymore!" : "El almacenamiento está lleno, los archivos no se pueden seguir actualizando ni sincronizando",
"Your storage is almost full ({usedSpacePercent}%)" : "El almacenamiento está casi lleno ({usedSpacePercent}%)",
"Favorite" : "Favorito",
- "Text file" : "Archivo de texto",
"Folder" : "Carpeta",
"New folder" : "Nueva Carpeta",
"Upload" : "Subir",
@@ -69,7 +64,6 @@ OC.L10N.register(
"%2$s changed %1$s" : "%2$s modificó %1$s",
"You deleted %1$s" : "Eliminaste %1$s",
"%2$s deleted %1$s" : "%2$s eliminó %1$s",
- "%s could not be renamed" : "No se pudo renombrar %s",
"File handling" : "Tratamiento de archivos",
"Maximum upload size" : "Tamaño máximo de subida",
"max. possible: " : "máx. posible:",
@@ -80,6 +74,6 @@ OC.L10N.register(
"Cancel upload" : "Cancelar subida",
"Upload too large" : "El tamaño del archivo que querés subir es demasiado grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los archivos que intentás subir sobrepasan el tamaño máximo ",
- "Files are being scanned, please wait." : "Se están escaneando los archivos, por favor esperá."
+ "Text file" : "Archivo de texto"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/es_AR.json b/apps/files/l10n/es_AR.json
index 363fedc787e..81898bf489d 100644
--- a/apps/files/l10n/es_AR.json
+++ b/apps/files/l10n/es_AR.json
@@ -1,10 +1,7 @@
{ "translations": {
+ "Storage not available" : "Almacenamiento no disponible",
+ "Storage invalid" : "Almacenamiento invalido",
"Unknown error" : "Error desconocido",
- "Could not move %s - File with this name already exists" : "No se pudo mover %s - Un archivo con este nombre ya existe",
- "Could not move %s" : "No se pudo mover %s ",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nombre %s está en uso en el directorio %s. Por favor elija un otro nombre.",
- "Error when creating the file" : "Error al crear el archivo",
- "Error when creating the folder" : "Error al crear el directorio",
"Unable to set upload directory." : "No fue posible crear el directorio de subida.",
"Invalid Token" : "Token Inválido",
"No file was uploaded. Unknown error" : "El archivo no fue subido. Error desconocido",
@@ -16,31 +13,30 @@
"Missing a temporary folder" : "Falta un directorio temporal",
"Failed to write to disk" : "Error al escribir en el disco",
"Not enough storage available" : "No hay suficiente almacenamiento",
+ "The target folder has been moved or deleted." : "La carpeta destino fue movida o borrada.",
"Upload failed. Could not find uploaded file" : "Falló la carga. No se pudo encontrar el archivo subido.",
"Upload failed. Could not get file info." : "Falló la carga. No se pudo obtener la información del archivo.",
"Invalid directory." : "Directorio inválido.",
"Files" : "Archivos",
+ "All files" : "Todos los archivos",
"Favorites" : "Favoritos",
"Home" : "Particular",
"Close" : "Cerrar",
"Upload cancelled." : "La subida fue cancelada",
"Unable to upload {filename} as it is a directory or has 0 bytes" : "Imposible cargar {filename} puesto que es un directoro o tiene 0 bytes.",
+ "Total file size {size1} exceeds upload limit {size2}" : "El tamaño total del archivo {size1} excede el límite {size2}",
+ "Not enough free space, you are uploading {size1} but only {size2} is left" : "No hay suficiente espacio libre. Quiere subir {size1} pero solo quedan {size2}",
"Could not get result from server." : "No se pudo obtener resultados del servidor.",
"File upload is in progress. Leaving the page now will cancel the upload." : "La subida del archivo está en proceso. Si salís de la página ahora, la subida se cancelará.",
"Actions" : "Acciones",
"Download" : "Descargar",
"Rename" : "Cambiar nombre",
"Delete" : "Borrar",
+ "Unshare" : "Dejar de compartir",
"Details" : "Detalles",
"Select" : "Seleccionar",
"Pending" : "Pendientes",
- "Error moving file" : "Error moviendo el archivo",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} ya existe",
- "Could not rename file" : "No se pudo renombrar el archivo",
- "Could not create file" : "No se pudo crear el archivo",
- "Could not create folder" : "No se pudo crear el directorio",
- "Error deleting file." : "Error al borrar el archivo.",
+ "Unable to determine date" : "No fue posible determinar la fecha",
"Name" : "Nombre",
"Size" : "Tamaño",
"Modified" : "Modificado",
@@ -54,7 +50,6 @@
"Your storage is full, files can not be updated or synced anymore!" : "El almacenamiento está lleno, los archivos no se pueden seguir actualizando ni sincronizando",
"Your storage is almost full ({usedSpacePercent}%)" : "El almacenamiento está casi lleno ({usedSpacePercent}%)",
"Favorite" : "Favorito",
- "Text file" : "Archivo de texto",
"Folder" : "Carpeta",
"New folder" : "Nueva Carpeta",
"Upload" : "Subir",
@@ -67,7 +62,6 @@
"%2$s changed %1$s" : "%2$s modificó %1$s",
"You deleted %1$s" : "Eliminaste %1$s",
"%2$s deleted %1$s" : "%2$s eliminó %1$s",
- "%s could not be renamed" : "No se pudo renombrar %s",
"File handling" : "Tratamiento de archivos",
"Maximum upload size" : "Tamaño máximo de subida",
"max. possible: " : "máx. posible:",
@@ -78,6 +72,6 @@
"Cancel upload" : "Cancelar subida",
"Upload too large" : "El tamaño del archivo que querés subir es demasiado grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los archivos que intentás subir sobrepasan el tamaño máximo ",
- "Files are being scanned, please wait." : "Se están escaneando los archivos, por favor esperá."
+ "Text file" : "Archivo de texto"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/es_CL.js b/apps/files/l10n/es_CL.js
index f7443bc4944..7b67ca39ac5 100644
--- a/apps/files/l10n/es_CL.js
+++ b/apps/files/l10n/es_CL.js
@@ -6,7 +6,6 @@ OC.L10N.register(
"Download" : "Descargar",
"Rename" : "Renombrar",
"Details" : "detalles",
- "Error" : "Error",
"New folder" : "Nuevo directorio",
"Upload" : "Subir",
"A new file or folder has been <strong>created</strong>" : "Un nuevo archivo o carpeta ha sido <strong>creado</strong>",
diff --git a/apps/files/l10n/es_CL.json b/apps/files/l10n/es_CL.json
index 29c0ef45fcf..7c42b2a4097 100644
--- a/apps/files/l10n/es_CL.json
+++ b/apps/files/l10n/es_CL.json
@@ -4,7 +4,6 @@
"Download" : "Descargar",
"Rename" : "Renombrar",
"Details" : "detalles",
- "Error" : "Error",
"New folder" : "Nuevo directorio",
"Upload" : "Subir",
"A new file or folder has been <strong>created</strong>" : "Un nuevo archivo o carpeta ha sido <strong>creado</strong>",
diff --git a/apps/files/l10n/es_MX.js b/apps/files/l10n/es_MX.js
index dadcf54d15c..780c206c622 100644
--- a/apps/files/l10n/es_MX.js
+++ b/apps/files/l10n/es_MX.js
@@ -2,11 +2,6 @@ OC.L10N.register(
"files",
{
"Unknown error" : "Error desconocido",
- "Could not move %s - File with this name already exists" : "No se pudo mover %s - Ya existe un archivo con ese nombre.",
- "Could not move %s" : "No se pudo mover %s",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nombre %s ya está en uso por la carpeta %s. Por favor elija uno diferente.",
- "Error when creating the file" : "Error al crear el archivo",
- "Error when creating the folder" : "Error al crear la carpeta.",
"Unable to set upload directory." : "Incapaz de crear directorio de subida.",
"Invalid Token" : "Token Inválido",
"No file was uploaded. Unknown error" : "No se subió ningún archivo. Error desconocido",
@@ -33,15 +28,9 @@ OC.L10N.register(
"Download" : "Descargar",
"Rename" : "Renombrar",
"Delete" : "Eliminar",
+ "Unshare" : "Dejar de compartir",
"Details" : "Detalles",
"Pending" : "Pendiente",
- "Error moving file" : "Error moviendo archivo",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} ya existe",
- "Could not rename file" : "No se pudo renombrar el archivo",
- "Could not create file" : "No se pudo crear el archivo",
- "Could not create folder" : "No se pudo crear la carpeta",
- "Error deleting file." : "Error borrando el archivo.",
"Name" : "Nombre",
"Size" : "Tamaño",
"Modified" : "Modificado",
@@ -55,14 +44,12 @@ OC.L10N.register(
"Your storage is full, files can not be updated or synced anymore!" : "Su almacenamiento está lleno, ¡los archivos no se actualizarán ni sincronizarán más!",
"Your storage is almost full ({usedSpacePercent}%)" : "Su almacenamiento está casi lleno ({usedSpacePercent}%)",
"Favorite" : "Favorito",
- "Text file" : "Archivo de texto",
"Folder" : "Carpeta",
"New folder" : "Nueva carpeta",
"Upload" : "Subir archivo",
"You created %1$s" : "Has creado %1$s",
"You changed %1$s" : "Has cambiado %1$s",
"You deleted %1$s" : "Has eliminado %1$s",
- "%s could not be renamed" : "%s no pudo ser renombrado",
"File handling" : "Administración de archivos",
"Maximum upload size" : "Tamaño máximo de subida",
"max. possible: " : "máx. posible:",
@@ -73,6 +60,6 @@ OC.L10N.register(
"Cancel upload" : "Cancelar subida",
"Upload too large" : "Subida demasido grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los archivos que estás intentando subir sobrepasan el tamaño máximo permitido en este servidor.",
- "Files are being scanned, please wait." : "Los archivos están siendo escaneados, por favor espere."
+ "Text file" : "Archivo de texto"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/es_MX.json b/apps/files/l10n/es_MX.json
index 61156506368..17d5cb74e87 100644
--- a/apps/files/l10n/es_MX.json
+++ b/apps/files/l10n/es_MX.json
@@ -1,10 +1,5 @@
{ "translations": {
"Unknown error" : "Error desconocido",
- "Could not move %s - File with this name already exists" : "No se pudo mover %s - Ya existe un archivo con ese nombre.",
- "Could not move %s" : "No se pudo mover %s",
- "The name %s is already used in the folder %s. Please choose a different name." : "El nombre %s ya está en uso por la carpeta %s. Por favor elija uno diferente.",
- "Error when creating the file" : "Error al crear el archivo",
- "Error when creating the folder" : "Error al crear la carpeta.",
"Unable to set upload directory." : "Incapaz de crear directorio de subida.",
"Invalid Token" : "Token Inválido",
"No file was uploaded. Unknown error" : "No se subió ningún archivo. Error desconocido",
@@ -31,15 +26,9 @@
"Download" : "Descargar",
"Rename" : "Renombrar",
"Delete" : "Eliminar",
+ "Unshare" : "Dejar de compartir",
"Details" : "Detalles",
"Pending" : "Pendiente",
- "Error moving file" : "Error moviendo archivo",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} ya existe",
- "Could not rename file" : "No se pudo renombrar el archivo",
- "Could not create file" : "No se pudo crear el archivo",
- "Could not create folder" : "No se pudo crear la carpeta",
- "Error deleting file." : "Error borrando el archivo.",
"Name" : "Nombre",
"Size" : "Tamaño",
"Modified" : "Modificado",
@@ -53,14 +42,12 @@
"Your storage is full, files can not be updated or synced anymore!" : "Su almacenamiento está lleno, ¡los archivos no se actualizarán ni sincronizarán más!",
"Your storage is almost full ({usedSpacePercent}%)" : "Su almacenamiento está casi lleno ({usedSpacePercent}%)",
"Favorite" : "Favorito",
- "Text file" : "Archivo de texto",
"Folder" : "Carpeta",
"New folder" : "Nueva carpeta",
"Upload" : "Subir archivo",
"You created %1$s" : "Has creado %1$s",
"You changed %1$s" : "Has cambiado %1$s",
"You deleted %1$s" : "Has eliminado %1$s",
- "%s could not be renamed" : "%s no pudo ser renombrado",
"File handling" : "Administración de archivos",
"Maximum upload size" : "Tamaño máximo de subida",
"max. possible: " : "máx. posible:",
@@ -71,6 +58,6 @@
"Cancel upload" : "Cancelar subida",
"Upload too large" : "Subida demasido grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los archivos que estás intentando subir sobrepasan el tamaño máximo permitido en este servidor.",
- "Files are being scanned, please wait." : "Los archivos están siendo escaneados, por favor espere."
+ "Text file" : "Archivo de texto"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/et_EE.js b/apps/files/l10n/et_EE.js
index e57e6e39c81..5c59cf614b7 100644
--- a/apps/files/l10n/et_EE.js
+++ b/apps/files/l10n/et_EE.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Andmehoidla pole saadaval",
"Storage invalid" : "Vigane andmehoidla",
"Unknown error" : "Tundmatu viga",
- "Could not move %s - File with this name already exists" : "Ei saa liigutada faili %s - samanimeline fail on juba olemas",
- "Could not move %s" : "%s liigutamine ebaõnnestus",
- "Permission denied" : "Ligipääs keelatud",
- "The target folder has been moved or deleted." : "Sihtkataloog on ümber tõstetud või kustutatud.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nimi %s on juba kasutusel kataloogis %s. Palun vali mõni teine nimi.",
- "Error when creating the file" : "Viga faili loomisel",
- "Error when creating the folder" : "Viga kataloogi loomisel",
"Unable to set upload directory." : "Üleslaadimiste kausta määramine ebaõnnestus.",
"Invalid Token" : "Vigane kontrollkood",
"No file was uploaded. Unknown error" : "Ühtegi faili ei laetud üles. Tundmatu viga",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Ajutiste failide kaust puudub",
"Failed to write to disk" : "Kettale kirjutamine ebaõnnestus",
"Not enough storage available" : "Saadaval pole piisavalt ruumi",
+ "The target folder has been moved or deleted." : "Sihtkataloog on ümber tõstetud või kustutatud.",
"Upload failed. Could not find uploaded file" : "Üleslaadimine ebaõnnestus. Üleslaetud faili ei leitud",
"Upload failed. Could not get file info." : "Üleslaadimine ebaõnnestus. Faili info hankimine ebaõnnestus.",
"Invalid directory." : "Vigane kaust.",
@@ -40,20 +34,19 @@ OC.L10N.register(
"Download" : "Lae alla",
"Rename" : "Nimeta ümber",
"Delete" : "Kustuta",
+ "Disconnect storage" : "Ühenda andmehoidla lahti.",
+ "Unshare" : "Lõpeta jagamine",
"Details" : "Üksikasjad",
"Select" : "Vali",
"Pending" : "Ootel",
"Unable to determine date" : "Kuupäeva tuvastamine ei õnnestunud",
"This operation is forbidden" : "See toiming on keelatud",
"This directory is unavailable, please check the logs or contact the administrator" : "See kaust pole saadaval. Palun kontrolli logifaile või võta ühendust administraatoriga",
- "Error moving file." : "Viga faili liigutamisel.",
- "Error moving file" : "Viga faili eemaldamisel",
- "Error" : "Viga",
- "{new_name} already exists" : "{new_name} on juba olemas",
- "Could not rename file" : "Ei suuda faili ümber nimetada",
- "Could not create file" : "Ei suuda luua faili",
- "Could not create folder" : "Ei suuda luua kataloogi",
- "Error deleting file." : "Viga faili kustutamisel.",
+ "Could not move \"{file}\"" : "\"{file}\" liigutamine ebaõnnestus",
+ "{newName} already exists" : "{newName} on juba olemas",
+ "Could not rename \"{fileName}\"" : "\"{fileName}\" ümbernimetamine ebaõnnestus",
+ "Could not create file \"{file}\"" : "Faili \"{file}\" loomine ebaõnnestus",
+ "Error deleting file \"{fileName}\"." : "Tõrge faili \"{fileName}\" kustutamisel.",
"No entries in this folder match '{filter}'" : "Ükski sissekanne ei kattu filtriga '{filter}'",
"Name" : "Nimi",
"Size" : "Suurus",
@@ -74,9 +67,9 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n bait","%n baiti"],
"Favorited" : "Lemmikud",
"Favorite" : "Lemmik",
- "Text file" : "Tekstifail",
"Folder" : "Kaust",
"New folder" : "Uus kaust",
+ "{newname} already exists" : "{newname} on juba olemas",
"Upload" : "Lae üles",
"An error occurred while trying to update the tags" : "Siltide uuendamisel tekkis tõrge",
"A new file or folder has been <strong>created</strong>" : "Uus fail või kataloog on <strong>loodud</strong>",
@@ -92,8 +85,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s kustutas %1$s",
"You restored %1$s" : "Sa taastasid %1$s",
"%2$s restored %1$s" : "%2$s taastas %1$s",
- "%s could not be renamed as it has been deleted" : "%s ei saa ümber nimetada, kuna see on kustutatud",
- "%s could not be renamed" : "%s ümbernimetamine ebaõnnestus",
"Upload (max. %s)" : "Üleslaadimine (max. %s)",
"File handling" : "Failide käsitlemine",
"Maximum upload size" : "Maksimaalne üleslaadimise suurus",
@@ -109,9 +100,9 @@ OC.L10N.register(
"Select all" : "Vali kõik",
"Upload too large" : "Üleslaadimine on liiga suur",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Failid, mida sa proovid üles laadida, ületab serveri poolt üleslaetavatele failidele määratud maksimaalse suuruse.",
- "Files are being scanned, please wait." : "Faile skannitakse, palun oota.",
- "Currently scanning" : "Praegu skännimisel",
"No favorites" : "Lemmikuid pole",
- "Files and folders you mark as favorite will show up here" : "Siin kuvatakse faile ja kaustasid, mille oled märkinud lemmikuteks"
+ "Files and folders you mark as favorite will show up here" : "Siin kuvatakse faile ja kaustasid, mille oled märkinud lemmikuteks",
+ "Text file" : "Tekstifail",
+ "New text file.txt" : "Uus tekstifail.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/et_EE.json b/apps/files/l10n/et_EE.json
index 02dc68f96d9..f438d07cdc8 100644
--- a/apps/files/l10n/et_EE.json
+++ b/apps/files/l10n/et_EE.json
@@ -2,13 +2,6 @@
"Storage not available" : "Andmehoidla pole saadaval",
"Storage invalid" : "Vigane andmehoidla",
"Unknown error" : "Tundmatu viga",
- "Could not move %s - File with this name already exists" : "Ei saa liigutada faili %s - samanimeline fail on juba olemas",
- "Could not move %s" : "%s liigutamine ebaõnnestus",
- "Permission denied" : "Ligipääs keelatud",
- "The target folder has been moved or deleted." : "Sihtkataloog on ümber tõstetud või kustutatud.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nimi %s on juba kasutusel kataloogis %s. Palun vali mõni teine nimi.",
- "Error when creating the file" : "Viga faili loomisel",
- "Error when creating the folder" : "Viga kataloogi loomisel",
"Unable to set upload directory." : "Üleslaadimiste kausta määramine ebaõnnestus.",
"Invalid Token" : "Vigane kontrollkood",
"No file was uploaded. Unknown error" : "Ühtegi faili ei laetud üles. Tundmatu viga",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Ajutiste failide kaust puudub",
"Failed to write to disk" : "Kettale kirjutamine ebaõnnestus",
"Not enough storage available" : "Saadaval pole piisavalt ruumi",
+ "The target folder has been moved or deleted." : "Sihtkataloog on ümber tõstetud või kustutatud.",
"Upload failed. Could not find uploaded file" : "Üleslaadimine ebaõnnestus. Üleslaetud faili ei leitud",
"Upload failed. Could not get file info." : "Üleslaadimine ebaõnnestus. Faili info hankimine ebaõnnestus.",
"Invalid directory." : "Vigane kaust.",
@@ -38,20 +32,19 @@
"Download" : "Lae alla",
"Rename" : "Nimeta ümber",
"Delete" : "Kustuta",
+ "Disconnect storage" : "Ühenda andmehoidla lahti.",
+ "Unshare" : "Lõpeta jagamine",
"Details" : "Üksikasjad",
"Select" : "Vali",
"Pending" : "Ootel",
"Unable to determine date" : "Kuupäeva tuvastamine ei õnnestunud",
"This operation is forbidden" : "See toiming on keelatud",
"This directory is unavailable, please check the logs or contact the administrator" : "See kaust pole saadaval. Palun kontrolli logifaile või võta ühendust administraatoriga",
- "Error moving file." : "Viga faili liigutamisel.",
- "Error moving file" : "Viga faili eemaldamisel",
- "Error" : "Viga",
- "{new_name} already exists" : "{new_name} on juba olemas",
- "Could not rename file" : "Ei suuda faili ümber nimetada",
- "Could not create file" : "Ei suuda luua faili",
- "Could not create folder" : "Ei suuda luua kataloogi",
- "Error deleting file." : "Viga faili kustutamisel.",
+ "Could not move \"{file}\"" : "\"{file}\" liigutamine ebaõnnestus",
+ "{newName} already exists" : "{newName} on juba olemas",
+ "Could not rename \"{fileName}\"" : "\"{fileName}\" ümbernimetamine ebaõnnestus",
+ "Could not create file \"{file}\"" : "Faili \"{file}\" loomine ebaõnnestus",
+ "Error deleting file \"{fileName}\"." : "Tõrge faili \"{fileName}\" kustutamisel.",
"No entries in this folder match '{filter}'" : "Ükski sissekanne ei kattu filtriga '{filter}'",
"Name" : "Nimi",
"Size" : "Suurus",
@@ -72,9 +65,9 @@
"_%n byte_::_%n bytes_" : ["%n bait","%n baiti"],
"Favorited" : "Lemmikud",
"Favorite" : "Lemmik",
- "Text file" : "Tekstifail",
"Folder" : "Kaust",
"New folder" : "Uus kaust",
+ "{newname} already exists" : "{newname} on juba olemas",
"Upload" : "Lae üles",
"An error occurred while trying to update the tags" : "Siltide uuendamisel tekkis tõrge",
"A new file or folder has been <strong>created</strong>" : "Uus fail või kataloog on <strong>loodud</strong>",
@@ -90,8 +83,6 @@
"%2$s deleted %1$s" : "%2$s kustutas %1$s",
"You restored %1$s" : "Sa taastasid %1$s",
"%2$s restored %1$s" : "%2$s taastas %1$s",
- "%s could not be renamed as it has been deleted" : "%s ei saa ümber nimetada, kuna see on kustutatud",
- "%s could not be renamed" : "%s ümbernimetamine ebaõnnestus",
"Upload (max. %s)" : "Üleslaadimine (max. %s)",
"File handling" : "Failide käsitlemine",
"Maximum upload size" : "Maksimaalne üleslaadimise suurus",
@@ -107,9 +98,9 @@
"Select all" : "Vali kõik",
"Upload too large" : "Üleslaadimine on liiga suur",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Failid, mida sa proovid üles laadida, ületab serveri poolt üleslaetavatele failidele määratud maksimaalse suuruse.",
- "Files are being scanned, please wait." : "Faile skannitakse, palun oota.",
- "Currently scanning" : "Praegu skännimisel",
"No favorites" : "Lemmikuid pole",
- "Files and folders you mark as favorite will show up here" : "Siin kuvatakse faile ja kaustasid, mille oled märkinud lemmikuteks"
+ "Files and folders you mark as favorite will show up here" : "Siin kuvatakse faile ja kaustasid, mille oled märkinud lemmikuteks",
+ "Text file" : "Tekstifail",
+ "New text file.txt" : "Uus tekstifail.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/eu.js b/apps/files/l10n/eu.js
index 0758119cad4..16d681ebeab 100644
--- a/apps/files/l10n/eu.js
+++ b/apps/files/l10n/eu.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Biltegia ez dago eskuragarri",
"Storage invalid" : "Biltegi bliogabea",
"Unknown error" : "Errore ezezaguna",
- "Could not move %s - File with this name already exists" : "Ezin da %s mugitu - Izen hau duen fitxategia dagoeneko existitzen da",
- "Could not move %s" : "Ezin dira fitxategiak mugitu %s",
- "Permission denied" : "Baimena Ukatua",
- "The target folder has been moved or deleted." : "Jatorrizko karpeta mugitu edo ezabatu da.",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s izena dagoeneko erabilita dago %s karpetan. Mesdez hautatu izen ezberdina.",
- "Error when creating the file" : "Errorea fitxategia sortzerakoan",
- "Error when creating the folder" : "Errorea karpeta sortzerakoan",
"Unable to set upload directory." : "Ezin da igoera direktorioa ezarri.",
"Invalid Token" : "Lekuko baliogabea",
"No file was uploaded. Unknown error" : "Ez da fitxategirik igo. Errore ezezaguna",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Aldi bateko karpeta falta da",
"Failed to write to disk" : "Errore bat izan da diskoan idazterakoan",
"Not enough storage available" : "Ez dago behar aina leku erabilgarri,",
+ "The target folder has been moved or deleted." : "Jatorrizko karpeta mugitu edo ezabatu da.",
"Upload failed. Could not find uploaded file" : "Igoerak huts egin du. Ezin izan da igotako fitxategia aurkitu",
"Upload failed. Could not get file info." : "Igoerak huts egin du. Ezin izan da fitxategiaren informazioa eskuratu.",
"Invalid directory." : "Baliogabeko karpeta.",
@@ -40,18 +34,12 @@ OC.L10N.register(
"Download" : "Deskargatu",
"Rename" : "Berrizendatu",
"Delete" : "Ezabatu",
+ "Disconnect storage" : "Deskonektatu biltegia",
+ "Unshare" : "Ez elkarbanatu",
"Details" : "Xehetasunak",
"Select" : "hautatu",
"Pending" : "Zain",
"Unable to determine date" : "Ezin izan da data zehaztu",
- "Error moving file." : "Errorea fitxategia mugitzean.",
- "Error moving file" : "Errorea fitxategia mugitzean",
- "Error" : "Errorea",
- "{new_name} already exists" : "{new_name} dagoeneko existitzen da",
- "Could not rename file" : "Ezin izan da fitxategia berrizendatu",
- "Could not create file" : "Ezin izan da fitxategia sortu",
- "Could not create folder" : "Ezin izan da karpeta sortu",
- "Error deleting file." : "Errorea fitxategia ezabatzerakoan.",
"No entries in this folder match '{filter}'" : "Karpeta honetan ez dago sarrerarik '{filter}' iragazkiarekin bat egiten dutenak",
"Name" : "Izena",
"Size" : "Tamaina",
@@ -68,7 +56,6 @@ OC.L10N.register(
"Your storage is almost full ({usedSpacePercent}%)" : "Zure biltegiratzea nahiko beterik dago (%{usedSpacePercent})",
"Favorited" : "Gogokoa",
"Favorite" : "Gogokoa",
- "Text file" : "Testu fitxategia",
"Folder" : "Karpeta",
"New folder" : "Karpeta berria",
"Upload" : "Igo",
@@ -85,8 +72,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$sk ezabatuta %1$s",
"You restored %1$s" : "Zuk %1$s berrezarri duzu",
"%2$s restored %1$s" : "%2$sk %1$s berrezarri du",
- "%s could not be renamed as it has been deleted" : "%s ezin izan da berrizendatu ezabatua zegoen eta",
- "%s could not be renamed" : "%s ezin da berrizendatu",
"Upload (max. %s)" : "Igo (max. %s)",
"File handling" : "Fitxategien kudeaketa",
"Maximum upload size" : "Igo daitekeen gehienezko tamaina",
@@ -101,9 +86,8 @@ OC.L10N.register(
"Select all" : "Hautatu dena",
"Upload too large" : "Igoera handiegia da",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Igotzen saiatzen ari zaren fitxategiak zerbitzari honek igotzeko onartzen duena baino handiagoak dira.",
- "Files are being scanned, please wait." : "Fitxategiak eskaneatzen ari da, itxoin mezedez.",
- "Currently scanning" : "Eskaneatzen une honetan",
"No favorites" : "Gogokorik ez",
- "Files and folders you mark as favorite will show up here" : "Gogokotzat markatutako fitxategi eta karpeta hemen agertuko dira"
+ "Files and folders you mark as favorite will show up here" : "Gogokotzat markatutako fitxategi eta karpeta hemen agertuko dira",
+ "Text file" : "Testu fitxategia"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/eu.json b/apps/files/l10n/eu.json
index 9e225f2290a..f23d06bb5db 100644
--- a/apps/files/l10n/eu.json
+++ b/apps/files/l10n/eu.json
@@ -2,13 +2,6 @@
"Storage not available" : "Biltegia ez dago eskuragarri",
"Storage invalid" : "Biltegi bliogabea",
"Unknown error" : "Errore ezezaguna",
- "Could not move %s - File with this name already exists" : "Ezin da %s mugitu - Izen hau duen fitxategia dagoeneko existitzen da",
- "Could not move %s" : "Ezin dira fitxategiak mugitu %s",
- "Permission denied" : "Baimena Ukatua",
- "The target folder has been moved or deleted." : "Jatorrizko karpeta mugitu edo ezabatu da.",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s izena dagoeneko erabilita dago %s karpetan. Mesdez hautatu izen ezberdina.",
- "Error when creating the file" : "Errorea fitxategia sortzerakoan",
- "Error when creating the folder" : "Errorea karpeta sortzerakoan",
"Unable to set upload directory." : "Ezin da igoera direktorioa ezarri.",
"Invalid Token" : "Lekuko baliogabea",
"No file was uploaded. Unknown error" : "Ez da fitxategirik igo. Errore ezezaguna",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Aldi bateko karpeta falta da",
"Failed to write to disk" : "Errore bat izan da diskoan idazterakoan",
"Not enough storage available" : "Ez dago behar aina leku erabilgarri,",
+ "The target folder has been moved or deleted." : "Jatorrizko karpeta mugitu edo ezabatu da.",
"Upload failed. Could not find uploaded file" : "Igoerak huts egin du. Ezin izan da igotako fitxategia aurkitu",
"Upload failed. Could not get file info." : "Igoerak huts egin du. Ezin izan da fitxategiaren informazioa eskuratu.",
"Invalid directory." : "Baliogabeko karpeta.",
@@ -38,18 +32,12 @@
"Download" : "Deskargatu",
"Rename" : "Berrizendatu",
"Delete" : "Ezabatu",
+ "Disconnect storage" : "Deskonektatu biltegia",
+ "Unshare" : "Ez elkarbanatu",
"Details" : "Xehetasunak",
"Select" : "hautatu",
"Pending" : "Zain",
"Unable to determine date" : "Ezin izan da data zehaztu",
- "Error moving file." : "Errorea fitxategia mugitzean.",
- "Error moving file" : "Errorea fitxategia mugitzean",
- "Error" : "Errorea",
- "{new_name} already exists" : "{new_name} dagoeneko existitzen da",
- "Could not rename file" : "Ezin izan da fitxategia berrizendatu",
- "Could not create file" : "Ezin izan da fitxategia sortu",
- "Could not create folder" : "Ezin izan da karpeta sortu",
- "Error deleting file." : "Errorea fitxategia ezabatzerakoan.",
"No entries in this folder match '{filter}'" : "Karpeta honetan ez dago sarrerarik '{filter}' iragazkiarekin bat egiten dutenak",
"Name" : "Izena",
"Size" : "Tamaina",
@@ -66,7 +54,6 @@
"Your storage is almost full ({usedSpacePercent}%)" : "Zure biltegiratzea nahiko beterik dago (%{usedSpacePercent})",
"Favorited" : "Gogokoa",
"Favorite" : "Gogokoa",
- "Text file" : "Testu fitxategia",
"Folder" : "Karpeta",
"New folder" : "Karpeta berria",
"Upload" : "Igo",
@@ -83,8 +70,6 @@
"%2$s deleted %1$s" : "%2$sk ezabatuta %1$s",
"You restored %1$s" : "Zuk %1$s berrezarri duzu",
"%2$s restored %1$s" : "%2$sk %1$s berrezarri du",
- "%s could not be renamed as it has been deleted" : "%s ezin izan da berrizendatu ezabatua zegoen eta",
- "%s could not be renamed" : "%s ezin da berrizendatu",
"Upload (max. %s)" : "Igo (max. %s)",
"File handling" : "Fitxategien kudeaketa",
"Maximum upload size" : "Igo daitekeen gehienezko tamaina",
@@ -99,9 +84,8 @@
"Select all" : "Hautatu dena",
"Upload too large" : "Igoera handiegia da",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Igotzen saiatzen ari zaren fitxategiak zerbitzari honek igotzeko onartzen duena baino handiagoak dira.",
- "Files are being scanned, please wait." : "Fitxategiak eskaneatzen ari da, itxoin mezedez.",
- "Currently scanning" : "Eskaneatzen une honetan",
"No favorites" : "Gogokorik ez",
- "Files and folders you mark as favorite will show up here" : "Gogokotzat markatutako fitxategi eta karpeta hemen agertuko dira"
+ "Files and folders you mark as favorite will show up here" : "Gogokotzat markatutako fitxategi eta karpeta hemen agertuko dira",
+ "Text file" : "Testu fitxategia"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/fa.js b/apps/files/l10n/fa.js
index 306992d15af..0d6086e0900 100644
--- a/apps/files/l10n/fa.js
+++ b/apps/files/l10n/fa.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "فضای ذخیره سازی موجود نیست",
"Storage invalid" : "فضای ذخیره‌سازی نامعتبر",
"Unknown error" : "خطای نامشخص",
- "Could not move %s - File with this name already exists" : "%s نمی توان جابجا کرد - در حال حاضر پرونده با این نام وجود دارد. ",
- "Could not move %s" : "%s نمی تواند حرکت کند ",
- "Permission denied" : "رد دسترسی",
- "The target folder has been moved or deleted." : "پوشه مقصد انتقال یافته یا حذف شده است.",
- "The name %s is already used in the folder %s. Please choose a different name." : "نام %s هم‌اکنون در پوشه %s مورد استفاده قرار گرفته شده است. لطفا نام دیگری انتخاب کنید.",
- "Error when creating the file" : "خطا در حین ایجاد فایل",
- "Error when creating the folder" : "خطا در حین ایجاد پوشه",
"Unable to set upload directory." : "قادر به تنظیم پوشه آپلود نمی باشد.",
"Invalid Token" : "رمز نامعتبر",
"No file was uploaded. Unknown error" : "هیچ فایلی آپلود نشد.خطای ناشناس",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "یک پوشه موقت گم شده",
"Failed to write to disk" : "نوشتن بر روی دیسک سخت ناموفق بود",
"Not enough storage available" : "فضای کافی در دسترس نیست",
+ "The target folder has been moved or deleted." : "پوشه مقصد انتقال یافته یا حذف شده است.",
"Upload failed. Could not find uploaded file" : "خطا در آپلود. امکان یافتن فایل‌های آپلود شده وجود ندارد",
"Upload failed. Could not get file info." : "خطای آپلود. امکان دریافت جزئیات فایل وجود ندارد.",
"Invalid directory." : "فهرست راهنما نامعتبر می باشد.",
@@ -40,20 +34,13 @@ OC.L10N.register(
"Download" : "دانلود",
"Rename" : "تغییرنام",
"Delete" : "حذف",
+ "Unshare" : "لغو اشتراک",
"Details" : "جزئیات",
"Select" : "انتخاب",
"Pending" : "در انتظار",
"Unable to determine date" : "امکان تعیین تاریخ وجود ندارد",
"This operation is forbidden" : "این عملیات غیرمجاز است",
"This directory is unavailable, please check the logs or contact the administrator" : "پوشه‌ در دسترس نیست، لطفا لاگ‌ها را بررسی کنید یا به مدیر سیستم اطلاع دهید",
- "Error moving file." : "خطا در انتقال فایل.",
- "Error moving file" : "خطا در انتقال فایل",
- "Error" : "خطا",
- "{new_name} already exists" : "{نام _جدید} در حال حاضر وجود دارد.",
- "Could not rename file" : "امکان تغییر نام وجود ندارد",
- "Could not create file" : "امکان ایجاد فایل وجود ندارد",
- "Could not create folder" : "امکان ایجاد پوشه وجود ندارد",
- "Error deleting file." : "خطا در حذف فایل.",
"No entries in this folder match '{filter}'" : "هیچ ورودی‌ای با '{filter}' تطبیق ندارد",
"Name" : "نام",
"Size" : "اندازه",
@@ -75,7 +62,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n بایت"],
"Favorited" : "برگزیده شده",
"Favorite" : "برگزیده",
- "Text file" : "فایل متنی",
"Folder" : "پوشه",
"New folder" : "پوشه جدید",
"{newname} already exists" : "{newname} هم‌اکنون وجود دارد",
@@ -97,8 +83,6 @@ OC.L10N.register(
"Changed by %2$s" : "تغییریافته توسط %2$s",
"Deleted by %2$s" : "حذف شده توسط %2$s",
"Restored by %2$s" : "بازگردانی شده توسط %2$s",
- "%s could not be renamed as it has been deleted" : "امکان تغییر نام %s با توجه به حذف شدن آن وجود ندارد",
- "%s could not be renamed" : "%s نمیتواند تغییر نام دهد.",
"Upload (max. %s)" : "آپلود (بیشترین سایز %s)",
"File handling" : "اداره پرونده ها",
"Maximum upload size" : "حداکثر اندازه بارگزاری",
@@ -114,9 +98,8 @@ OC.L10N.register(
"Select all" : "انتخاب همه",
"Upload too large" : "سایز فایل برای آپلود زیاد است(م.تنظیمات در php.ini)",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "فایلها بیش از حد تعیین شده در این سرور هستند\nمترجم:با تغییر فایل php,ini میتوان این محدودیت را برطرف کرد",
- "Files are being scanned, please wait." : "پرونده ها در حال بازرسی هستند لطفا صبر کنید",
- "Currently scanning" : "در حال اسکن",
"No favorites" : "هیچ برگزیده",
- "Files and folders you mark as favorite will show up here" : "فایل‌ها و پوشه‌های انتخاب شده به عنوان برگزیده توسط شما، در اینجا نمایش داده می‌شود"
+ "Files and folders you mark as favorite will show up here" : "فایل‌ها و پوشه‌های انتخاب شده به عنوان برگزیده توسط شما، در اینجا نمایش داده می‌شود",
+ "Text file" : "فایل متنی"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/fa.json b/apps/files/l10n/fa.json
index ddf67b42593..109dfbdb585 100644
--- a/apps/files/l10n/fa.json
+++ b/apps/files/l10n/fa.json
@@ -2,13 +2,6 @@
"Storage not available" : "فضای ذخیره سازی موجود نیست",
"Storage invalid" : "فضای ذخیره‌سازی نامعتبر",
"Unknown error" : "خطای نامشخص",
- "Could not move %s - File with this name already exists" : "%s نمی توان جابجا کرد - در حال حاضر پرونده با این نام وجود دارد. ",
- "Could not move %s" : "%s نمی تواند حرکت کند ",
- "Permission denied" : "رد دسترسی",
- "The target folder has been moved or deleted." : "پوشه مقصد انتقال یافته یا حذف شده است.",
- "The name %s is already used in the folder %s. Please choose a different name." : "نام %s هم‌اکنون در پوشه %s مورد استفاده قرار گرفته شده است. لطفا نام دیگری انتخاب کنید.",
- "Error when creating the file" : "خطا در حین ایجاد فایل",
- "Error when creating the folder" : "خطا در حین ایجاد پوشه",
"Unable to set upload directory." : "قادر به تنظیم پوشه آپلود نمی باشد.",
"Invalid Token" : "رمز نامعتبر",
"No file was uploaded. Unknown error" : "هیچ فایلی آپلود نشد.خطای ناشناس",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "یک پوشه موقت گم شده",
"Failed to write to disk" : "نوشتن بر روی دیسک سخت ناموفق بود",
"Not enough storage available" : "فضای کافی در دسترس نیست",
+ "The target folder has been moved or deleted." : "پوشه مقصد انتقال یافته یا حذف شده است.",
"Upload failed. Could not find uploaded file" : "خطا در آپلود. امکان یافتن فایل‌های آپلود شده وجود ندارد",
"Upload failed. Could not get file info." : "خطای آپلود. امکان دریافت جزئیات فایل وجود ندارد.",
"Invalid directory." : "فهرست راهنما نامعتبر می باشد.",
@@ -38,20 +32,13 @@
"Download" : "دانلود",
"Rename" : "تغییرنام",
"Delete" : "حذف",
+ "Unshare" : "لغو اشتراک",
"Details" : "جزئیات",
"Select" : "انتخاب",
"Pending" : "در انتظار",
"Unable to determine date" : "امکان تعیین تاریخ وجود ندارد",
"This operation is forbidden" : "این عملیات غیرمجاز است",
"This directory is unavailable, please check the logs or contact the administrator" : "پوشه‌ در دسترس نیست، لطفا لاگ‌ها را بررسی کنید یا به مدیر سیستم اطلاع دهید",
- "Error moving file." : "خطا در انتقال فایل.",
- "Error moving file" : "خطا در انتقال فایل",
- "Error" : "خطا",
- "{new_name} already exists" : "{نام _جدید} در حال حاضر وجود دارد.",
- "Could not rename file" : "امکان تغییر نام وجود ندارد",
- "Could not create file" : "امکان ایجاد فایل وجود ندارد",
- "Could not create folder" : "امکان ایجاد پوشه وجود ندارد",
- "Error deleting file." : "خطا در حذف فایل.",
"No entries in this folder match '{filter}'" : "هیچ ورودی‌ای با '{filter}' تطبیق ندارد",
"Name" : "نام",
"Size" : "اندازه",
@@ -73,7 +60,6 @@
"_%n byte_::_%n bytes_" : ["%n بایت"],
"Favorited" : "برگزیده شده",
"Favorite" : "برگزیده",
- "Text file" : "فایل متنی",
"Folder" : "پوشه",
"New folder" : "پوشه جدید",
"{newname} already exists" : "{newname} هم‌اکنون وجود دارد",
@@ -95,8 +81,6 @@
"Changed by %2$s" : "تغییریافته توسط %2$s",
"Deleted by %2$s" : "حذف شده توسط %2$s",
"Restored by %2$s" : "بازگردانی شده توسط %2$s",
- "%s could not be renamed as it has been deleted" : "امکان تغییر نام %s با توجه به حذف شدن آن وجود ندارد",
- "%s could not be renamed" : "%s نمیتواند تغییر نام دهد.",
"Upload (max. %s)" : "آپلود (بیشترین سایز %s)",
"File handling" : "اداره پرونده ها",
"Maximum upload size" : "حداکثر اندازه بارگزاری",
@@ -112,9 +96,8 @@
"Select all" : "انتخاب همه",
"Upload too large" : "سایز فایل برای آپلود زیاد است(م.تنظیمات در php.ini)",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "فایلها بیش از حد تعیین شده در این سرور هستند\nمترجم:با تغییر فایل php,ini میتوان این محدودیت را برطرف کرد",
- "Files are being scanned, please wait." : "پرونده ها در حال بازرسی هستند لطفا صبر کنید",
- "Currently scanning" : "در حال اسکن",
"No favorites" : "هیچ برگزیده",
- "Files and folders you mark as favorite will show up here" : "فایل‌ها و پوشه‌های انتخاب شده به عنوان برگزیده توسط شما، در اینجا نمایش داده می‌شود"
+ "Files and folders you mark as favorite will show up here" : "فایل‌ها و پوشه‌های انتخاب شده به عنوان برگزیده توسط شما، در اینجا نمایش داده می‌شود",
+ "Text file" : "فایل متنی"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/fi_FI.js b/apps/files/l10n/fi_FI.js
index 79f3321577f..62386eb781d 100644
--- a/apps/files/l10n/fi_FI.js
+++ b/apps/files/l10n/fi_FI.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Tallennustila ei ole käytettävissä",
"Storage invalid" : "Virheellinen tallennustila",
"Unknown error" : "Tuntematon virhe",
- "Could not move %s - File with this name already exists" : "Kohteen %s siirto ei onnistunut - Tiedosto samalla nimellä on jo olemassa",
- "Could not move %s" : "Kohteen %s siirto ei onnistunut",
- "Permission denied" : "Ei käyttöoikeutta",
- "The target folder has been moved or deleted." : "Kohdekansio on siirretty tai poistettu.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nimi %s on jo käytössä kansiossa %s. Valitse toinen nimi.",
- "Error when creating the file" : "Virhe tiedostoa luotaessa",
- "Error when creating the folder" : "Virhe kansiota luotaessa",
"Unable to set upload directory." : "Lähetyskansion asettaminen epäonnistui.",
"Invalid Token" : "Virheellinen token",
"No file was uploaded. Unknown error" : "Tiedostoa ei lähetetty. Tuntematon virhe",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Tilapäiskansio puuttuu",
"Failed to write to disk" : "Levylle kirjoitus epäonnistui",
"Not enough storage available" : "Tallennustilaa ei ole riittävästi käytettävissä",
+ "The target folder has been moved or deleted." : "Kohdekansio on siirretty tai poistettu.",
"Upload failed. Could not find uploaded file" : "Lähetys epäonnistui. Lähettävää tiedostoa ei löydetty.",
"Upload failed. Could not get file info." : "Lähetys epäonnistui. Lähettävää tiedostoa ei löydetty.",
"Invalid directory." : "Virheellinen kansio.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Lataa",
"Rename" : "Nimeä uudelleen",
"Delete" : "Poista",
+ "Disconnect storage" : "Katkaise yhteys tallennustilaan",
+ "Unshare" : "Peru jakaminen",
"Details" : "Tiedot",
"Select" : "Valitse",
"Pending" : "Odottaa",
"Unable to determine date" : "Päivämäärän määrittäminen epäonnistui",
"This operation is forbidden" : "Tämä toiminto on kielletty",
"This directory is unavailable, please check the logs or contact the administrator" : "Hakemisto ei ole käytettävissä. Tarkista lokit tai ole yhteydessä ylläpitoon.",
- "Error moving file." : "Virhe tiedostoa siirrettäessä.",
- "Error moving file" : "Virhe tiedostoa siirrettäessä",
- "Error" : "Virhe",
- "{new_name} already exists" : "{new_name} on jo olemassa",
- "Could not rename file" : "Tiedoston nimeäminen uudelleen epäonnistui",
- "Could not create file" : "Tiedoston luominen epäonnistui",
- "Could not create folder" : "Kansion luominen epäonnistui",
- "Error deleting file." : "Virhe tiedostoa poistaessa.",
+ "Could not move \"{file}\", target exists" : "Tiedoston \"{file}\" siirtäminen ei onnistunut, kohde on olemassa",
+ "Could not move \"{file}\"" : "Tiedoston \"{file}\" siirtäminen ei onnistunut",
+ "{newName} already exists" : "{newName} on jo olemassa",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Tiedoston \"{fileName}\" nimeäminen uudelleen ei onnistunut, koska sitä ei ole enää olemassa",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Nimi \"{targetName}\" on jo käytössä kansiossa \"{dir}\". Valitse toinen nimi.",
+ "Could not rename \"{fileName}\"" : "Tiedoston \"{fileName}\" nimeäminen uudelleen ei onnistunut",
+ "Could not create file \"{file}\"" : "Tiedostoa \"{file}\" ei voitu luoda",
+ "Could not create file \"{file}\" because it already exists" : "Tiedostoa \"{file}\" ei voitu luoda, koska se on jo olemassa",
+ "Could not create folder \"{dir}\"" : "Kansiota \"{dir}\" ei voitu luoda",
+ "Could not create folder \"{dir}\" because it already exists" : "Kansiota \"{dir}\" ei voitu luoda, koska se on jo olemassa",
+ "Error deleting file \"{fileName}\"." : "Virhe poistaessa tiedostoa \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Mikään tässä kansiossa ei vastaa suodatusta '{filter}'",
"Name" : "Nimi",
"Size" : "Koko",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n tavu","%n tavua"],
"Favorited" : "Lisätty suosikkeihin",
"Favorite" : "Suosikki",
- "Text file" : "Tekstitiedosto",
- "New text file.txt" : "Uusi tekstitiedosto.txt",
"Folder" : "Kansio",
"New folder" : "Uusi kansio",
"{newname} already exists" : "{newname} on jo olemassa",
@@ -99,14 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "Muuttanut %2$s",
"Deleted by %2$s" : "Poistanut %2$s",
"Restored by %2$s" : "Palauttanut %2$s",
- "%s could not be renamed as it has been deleted" : "Kohdetta %s ei voitu nimetä uudelleen, koska se on poistettu",
- "%s could not be renamed" : "kohteen %s nimeäminen uudelleen epäonnistui",
"Upload (max. %s)" : "Lähetys (enintään %s)",
"File handling" : "Tiedostonhallinta",
"Maximum upload size" : "Lähetettävän tiedoston suurin sallittu koko",
"max. possible: " : "suurin mahdollinen:",
"Save" : "Tallenna",
"With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM:tä käyttäen muutoksien voimaantulossa saattaa kestää 5 minuuttia.",
+ "Missing permissions to edit from here." : "Käyttöoikeudet eivät riitä tätä kautta muokkaamiseen.",
"Settings" : "Asetukset",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Käytä tätä osoitetta <a href=\"%s\" target=\"_blank\">käyttääksesi tiedostojasi WebDAVin kautta</a>",
@@ -117,9 +113,9 @@ OC.L10N.register(
"Select all" : "Valitse kaikki",
"Upload too large" : "Lähetettävä tiedosto on liian suuri",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Lähetettäväksi valitsemasi tiedostot ylittävät palvelimen salliman tiedostokoon rajan.",
- "Files are being scanned, please wait." : "Tiedostoja tarkistetaan, odota hetki.",
- "Currently scanning" : "Tutkitaan parhaillaan",
"No favorites" : "Ei suosikkeja",
- "Files and folders you mark as favorite will show up here" : "Suosikeiksi merkitsemäsi tiedostot ja kansiot näkyvät täällä"
+ "Files and folders you mark as favorite will show up here" : "Suosikeiksi merkitsemäsi tiedostot ja kansiot näkyvät täällä",
+ "Text file" : "Tekstitiedosto",
+ "New text file.txt" : "Uusi tekstitiedosto.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/fi_FI.json b/apps/files/l10n/fi_FI.json
index e46327c83fa..0484e85edd2 100644
--- a/apps/files/l10n/fi_FI.json
+++ b/apps/files/l10n/fi_FI.json
@@ -2,13 +2,6 @@
"Storage not available" : "Tallennustila ei ole käytettävissä",
"Storage invalid" : "Virheellinen tallennustila",
"Unknown error" : "Tuntematon virhe",
- "Could not move %s - File with this name already exists" : "Kohteen %s siirto ei onnistunut - Tiedosto samalla nimellä on jo olemassa",
- "Could not move %s" : "Kohteen %s siirto ei onnistunut",
- "Permission denied" : "Ei käyttöoikeutta",
- "The target folder has been moved or deleted." : "Kohdekansio on siirretty tai poistettu.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nimi %s on jo käytössä kansiossa %s. Valitse toinen nimi.",
- "Error when creating the file" : "Virhe tiedostoa luotaessa",
- "Error when creating the folder" : "Virhe kansiota luotaessa",
"Unable to set upload directory." : "Lähetyskansion asettaminen epäonnistui.",
"Invalid Token" : "Virheellinen token",
"No file was uploaded. Unknown error" : "Tiedostoa ei lähetetty. Tuntematon virhe",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Tilapäiskansio puuttuu",
"Failed to write to disk" : "Levylle kirjoitus epäonnistui",
"Not enough storage available" : "Tallennustilaa ei ole riittävästi käytettävissä",
+ "The target folder has been moved or deleted." : "Kohdekansio on siirretty tai poistettu.",
"Upload failed. Could not find uploaded file" : "Lähetys epäonnistui. Lähettävää tiedostoa ei löydetty.",
"Upload failed. Could not get file info." : "Lähetys epäonnistui. Lähettävää tiedostoa ei löydetty.",
"Invalid directory." : "Virheellinen kansio.",
@@ -38,20 +32,25 @@
"Download" : "Lataa",
"Rename" : "Nimeä uudelleen",
"Delete" : "Poista",
+ "Disconnect storage" : "Katkaise yhteys tallennustilaan",
+ "Unshare" : "Peru jakaminen",
"Details" : "Tiedot",
"Select" : "Valitse",
"Pending" : "Odottaa",
"Unable to determine date" : "Päivämäärän määrittäminen epäonnistui",
"This operation is forbidden" : "Tämä toiminto on kielletty",
"This directory is unavailable, please check the logs or contact the administrator" : "Hakemisto ei ole käytettävissä. Tarkista lokit tai ole yhteydessä ylläpitoon.",
- "Error moving file." : "Virhe tiedostoa siirrettäessä.",
- "Error moving file" : "Virhe tiedostoa siirrettäessä",
- "Error" : "Virhe",
- "{new_name} already exists" : "{new_name} on jo olemassa",
- "Could not rename file" : "Tiedoston nimeäminen uudelleen epäonnistui",
- "Could not create file" : "Tiedoston luominen epäonnistui",
- "Could not create folder" : "Kansion luominen epäonnistui",
- "Error deleting file." : "Virhe tiedostoa poistaessa.",
+ "Could not move \"{file}\", target exists" : "Tiedoston \"{file}\" siirtäminen ei onnistunut, kohde on olemassa",
+ "Could not move \"{file}\"" : "Tiedoston \"{file}\" siirtäminen ei onnistunut",
+ "{newName} already exists" : "{newName} on jo olemassa",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Tiedoston \"{fileName}\" nimeäminen uudelleen ei onnistunut, koska sitä ei ole enää olemassa",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Nimi \"{targetName}\" on jo käytössä kansiossa \"{dir}\". Valitse toinen nimi.",
+ "Could not rename \"{fileName}\"" : "Tiedoston \"{fileName}\" nimeäminen uudelleen ei onnistunut",
+ "Could not create file \"{file}\"" : "Tiedostoa \"{file}\" ei voitu luoda",
+ "Could not create file \"{file}\" because it already exists" : "Tiedostoa \"{file}\" ei voitu luoda, koska se on jo olemassa",
+ "Could not create folder \"{dir}\"" : "Kansiota \"{dir}\" ei voitu luoda",
+ "Could not create folder \"{dir}\" because it already exists" : "Kansiota \"{dir}\" ei voitu luoda, koska se on jo olemassa",
+ "Error deleting file \"{fileName}\"." : "Virhe poistaessa tiedostoa \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Mikään tässä kansiossa ei vastaa suodatusta '{filter}'",
"Name" : "Nimi",
"Size" : "Koko",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n tavu","%n tavua"],
"Favorited" : "Lisätty suosikkeihin",
"Favorite" : "Suosikki",
- "Text file" : "Tekstitiedosto",
- "New text file.txt" : "Uusi tekstitiedosto.txt",
"Folder" : "Kansio",
"New folder" : "Uusi kansio",
"{newname} already exists" : "{newname} on jo olemassa",
@@ -97,14 +94,13 @@
"Changed by %2$s" : "Muuttanut %2$s",
"Deleted by %2$s" : "Poistanut %2$s",
"Restored by %2$s" : "Palauttanut %2$s",
- "%s could not be renamed as it has been deleted" : "Kohdetta %s ei voitu nimetä uudelleen, koska se on poistettu",
- "%s could not be renamed" : "kohteen %s nimeäminen uudelleen epäonnistui",
"Upload (max. %s)" : "Lähetys (enintään %s)",
"File handling" : "Tiedostonhallinta",
"Maximum upload size" : "Lähetettävän tiedoston suurin sallittu koko",
"max. possible: " : "suurin mahdollinen:",
"Save" : "Tallenna",
"With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM:tä käyttäen muutoksien voimaantulossa saattaa kestää 5 minuuttia.",
+ "Missing permissions to edit from here." : "Käyttöoikeudet eivät riitä tätä kautta muokkaamiseen.",
"Settings" : "Asetukset",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Käytä tätä osoitetta <a href=\"%s\" target=\"_blank\">käyttääksesi tiedostojasi WebDAVin kautta</a>",
@@ -115,9 +111,9 @@
"Select all" : "Valitse kaikki",
"Upload too large" : "Lähetettävä tiedosto on liian suuri",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Lähetettäväksi valitsemasi tiedostot ylittävät palvelimen salliman tiedostokoon rajan.",
- "Files are being scanned, please wait." : "Tiedostoja tarkistetaan, odota hetki.",
- "Currently scanning" : "Tutkitaan parhaillaan",
"No favorites" : "Ei suosikkeja",
- "Files and folders you mark as favorite will show up here" : "Suosikeiksi merkitsemäsi tiedostot ja kansiot näkyvät täällä"
+ "Files and folders you mark as favorite will show up here" : "Suosikeiksi merkitsemäsi tiedostot ja kansiot näkyvät täällä",
+ "Text file" : "Tekstitiedosto",
+ "New text file.txt" : "Uusi tekstitiedosto.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/fr.js b/apps/files/l10n/fr.js
index e068b3c45ba..461157d6749 100644
--- a/apps/files/l10n/fr.js
+++ b/apps/files/l10n/fr.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Support de stockage non disponible",
"Storage invalid" : "Support de stockage non valable",
"Unknown error" : "Erreur Inconnue ",
- "Could not move %s - File with this name already exists" : "Impossible de déplacer %s - Un fichier portant ce nom existe déjà",
- "Could not move %s" : "Impossible de déplacer %s",
- "Permission denied" : "Permission refusée",
- "The target folder has been moved or deleted." : "Le dossier cible a été déplacé ou supprimé.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Le nom %s est déjà utilisé dans le dossier %s. Merci de choisir un nom différent.",
- "Error when creating the file" : "Erreur pendant la création du fichier",
- "Error when creating the folder" : "Erreur pendant la création du dossier",
"Unable to set upload directory." : "Impossible de définir le dossier de destination.",
"Invalid Token" : "Jeton non valide",
"No file was uploaded. Unknown error" : "Aucun fichier n'a été envoyé. Erreur inconnue",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Absence de dossier temporaire",
"Failed to write to disk" : "Erreur d'écriture sur le disque",
"Not enough storage available" : "Trop peu d'espace de stockage disponible",
+ "The target folder has been moved or deleted." : "Le dossier cible a été déplacé ou supprimé.",
"Upload failed. Could not find uploaded file" : "L'envoi a échoué. Impossible de trouver le fichier envoyé.",
"Upload failed. Could not get file info." : "L'envoi a échoué. Impossible d'obtenir les informations du fichier.",
"Invalid directory." : "Dossier non valide.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Télécharger",
"Rename" : "Renommer",
"Delete" : "Supprimer",
+ "Disconnect storage" : "Déconnecter ce support de stockage",
+ "Unshare" : "Ne plus partager",
"Details" : "Détails",
"Select" : "Sélectionner",
"Pending" : "En attente",
"Unable to determine date" : "Impossible de déterminer la date",
"This operation is forbidden" : "Cette opération est interdite",
"This directory is unavailable, please check the logs or contact the administrator" : "Ce répertoire n'est pas disponible. Consultez les logs ou contactez votre administrateur",
- "Error moving file." : "Erreur lors du déplacement du fichier.",
- "Error moving file" : "Erreur lors du déplacement du fichier",
- "Error" : "Erreur",
- "{new_name} already exists" : "{new_name} existe déjà",
- "Could not rename file" : "Impossible de renommer le fichier",
- "Could not create file" : "Impossible de créer le fichier",
- "Could not create folder" : "Impossible de créer le dossier",
- "Error deleting file." : "Erreur pendant la suppression du fichier.",
+ "Could not move \"{file}\", target exists" : "Impossible de déplacer \"{file}\", la cible existe",
+ "Could not move \"{file}\"" : "Impossible de déplacer \"{file}\"",
+ "{newName} already exists" : "{newName} existe déjà",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Impossible de renommer \"{file}\", il n'existe plus",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Le nom \"{targetName}\" est déjà utilisé dans le dossier \"{dir}\". Merci de choisir un nom différent.",
+ "Could not rename \"{fileName}\"" : "Impossible de renommer \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Impossible de créer le fichier \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Impossible de créer le fichier \"{file}\" car il existe déjà",
+ "Could not create folder \"{dir}\"" : "Impossible de créer le dossier \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Impossible de créer le dossier \"{dir}\" car il existe déjà",
+ "Error deleting file \"{fileName}\"." : "Erreur à la suppression du fichier \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Aucune entrée de ce dossier ne correspond à '{filter}'",
"Name" : "Nom",
"Size" : "Taille",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n octet","%n octets"],
"Favorited" : "Marqué comme favori",
"Favorite" : "Favoris",
- "Text file" : "Fichier texte",
- "New text file.txt" : "Nouveau fichier texte.txt",
"Folder" : "Dossier",
"New folder" : "Nouveau dossier",
"{newname} already exists" : "{newname} existe déjà",
@@ -99,14 +96,12 @@ OC.L10N.register(
"Changed by %2$s" : "Modifié par %2$s",
"Deleted by %2$s" : "Supprimé par %2$s",
"Restored by %2$s" : "Restauré par %2$s",
- "%s could not be renamed as it has been deleted" : "%s ne peut être renommé car il a été supprimé ",
- "%s could not be renamed" : "%s ne peut être renommé",
"Upload (max. %s)" : "Envoi (max. %s)",
"File handling" : "Gestion de fichiers",
"Maximum upload size" : "Taille max. d'envoi",
"max. possible: " : "Max. possible :",
"Save" : "Sauvegarder",
- "With PHP-FPM it might take 5 minutes for changes to be applied." : "Avec PHP-FPM il peut se passer 5 minutes pour que les changements soient appliqués.",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Avec PHP-FPM il peut se passer jusqu'à 5 minutes pour que les changements soient appliqués.",
"Missing permissions to edit from here." : "Manque de permissions pour éditer à partir d'ici.",
"Settings" : "Paramètres",
"WebDAV" : "WebDAV",
@@ -118,9 +113,9 @@ OC.L10N.register(
"Select all" : "Tout sélectionner",
"Upload too large" : "Téléversement trop volumineux",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Les fichiers que vous essayez d'envoyer dépassent la taille maximale d'envoi permise par ce serveur.",
- "Files are being scanned, please wait." : "Les fichiers sont en cours d'analyse, veuillez patienter.",
- "Currently scanning" : "Analyse en cours",
"No favorites" : "Aucun favori",
- "Files and folders you mark as favorite will show up here" : "Les fichiers et dossiers ajoutés à vos favoris apparaîtront ici"
+ "Files and folders you mark as favorite will show up here" : "Les fichiers et dossiers ajoutés à vos favoris apparaîtront ici",
+ "Text file" : "Fichier texte",
+ "New text file.txt" : "Nouveau fichier texte.txt"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files/l10n/fr.json b/apps/files/l10n/fr.json
index a297b3525d1..ed9fbc860d3 100644
--- a/apps/files/l10n/fr.json
+++ b/apps/files/l10n/fr.json
@@ -2,13 +2,6 @@
"Storage not available" : "Support de stockage non disponible",
"Storage invalid" : "Support de stockage non valable",
"Unknown error" : "Erreur Inconnue ",
- "Could not move %s - File with this name already exists" : "Impossible de déplacer %s - Un fichier portant ce nom existe déjà",
- "Could not move %s" : "Impossible de déplacer %s",
- "Permission denied" : "Permission refusée",
- "The target folder has been moved or deleted." : "Le dossier cible a été déplacé ou supprimé.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Le nom %s est déjà utilisé dans le dossier %s. Merci de choisir un nom différent.",
- "Error when creating the file" : "Erreur pendant la création du fichier",
- "Error when creating the folder" : "Erreur pendant la création du dossier",
"Unable to set upload directory." : "Impossible de définir le dossier de destination.",
"Invalid Token" : "Jeton non valide",
"No file was uploaded. Unknown error" : "Aucun fichier n'a été envoyé. Erreur inconnue",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Absence de dossier temporaire",
"Failed to write to disk" : "Erreur d'écriture sur le disque",
"Not enough storage available" : "Trop peu d'espace de stockage disponible",
+ "The target folder has been moved or deleted." : "Le dossier cible a été déplacé ou supprimé.",
"Upload failed. Could not find uploaded file" : "L'envoi a échoué. Impossible de trouver le fichier envoyé.",
"Upload failed. Could not get file info." : "L'envoi a échoué. Impossible d'obtenir les informations du fichier.",
"Invalid directory." : "Dossier non valide.",
@@ -38,20 +32,25 @@
"Download" : "Télécharger",
"Rename" : "Renommer",
"Delete" : "Supprimer",
+ "Disconnect storage" : "Déconnecter ce support de stockage",
+ "Unshare" : "Ne plus partager",
"Details" : "Détails",
"Select" : "Sélectionner",
"Pending" : "En attente",
"Unable to determine date" : "Impossible de déterminer la date",
"This operation is forbidden" : "Cette opération est interdite",
"This directory is unavailable, please check the logs or contact the administrator" : "Ce répertoire n'est pas disponible. Consultez les logs ou contactez votre administrateur",
- "Error moving file." : "Erreur lors du déplacement du fichier.",
- "Error moving file" : "Erreur lors du déplacement du fichier",
- "Error" : "Erreur",
- "{new_name} already exists" : "{new_name} existe déjà",
- "Could not rename file" : "Impossible de renommer le fichier",
- "Could not create file" : "Impossible de créer le fichier",
- "Could not create folder" : "Impossible de créer le dossier",
- "Error deleting file." : "Erreur pendant la suppression du fichier.",
+ "Could not move \"{file}\", target exists" : "Impossible de déplacer \"{file}\", la cible existe",
+ "Could not move \"{file}\"" : "Impossible de déplacer \"{file}\"",
+ "{newName} already exists" : "{newName} existe déjà",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Impossible de renommer \"{file}\", il n'existe plus",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Le nom \"{targetName}\" est déjà utilisé dans le dossier \"{dir}\". Merci de choisir un nom différent.",
+ "Could not rename \"{fileName}\"" : "Impossible de renommer \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Impossible de créer le fichier \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Impossible de créer le fichier \"{file}\" car il existe déjà",
+ "Could not create folder \"{dir}\"" : "Impossible de créer le dossier \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Impossible de créer le dossier \"{dir}\" car il existe déjà",
+ "Error deleting file \"{fileName}\"." : "Erreur à la suppression du fichier \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Aucune entrée de ce dossier ne correspond à '{filter}'",
"Name" : "Nom",
"Size" : "Taille",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n octet","%n octets"],
"Favorited" : "Marqué comme favori",
"Favorite" : "Favoris",
- "Text file" : "Fichier texte",
- "New text file.txt" : "Nouveau fichier texte.txt",
"Folder" : "Dossier",
"New folder" : "Nouveau dossier",
"{newname} already exists" : "{newname} existe déjà",
@@ -97,14 +94,12 @@
"Changed by %2$s" : "Modifié par %2$s",
"Deleted by %2$s" : "Supprimé par %2$s",
"Restored by %2$s" : "Restauré par %2$s",
- "%s could not be renamed as it has been deleted" : "%s ne peut être renommé car il a été supprimé ",
- "%s could not be renamed" : "%s ne peut être renommé",
"Upload (max. %s)" : "Envoi (max. %s)",
"File handling" : "Gestion de fichiers",
"Maximum upload size" : "Taille max. d'envoi",
"max. possible: " : "Max. possible :",
"Save" : "Sauvegarder",
- "With PHP-FPM it might take 5 minutes for changes to be applied." : "Avec PHP-FPM il peut se passer 5 minutes pour que les changements soient appliqués.",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Avec PHP-FPM il peut se passer jusqu'à 5 minutes pour que les changements soient appliqués.",
"Missing permissions to edit from here." : "Manque de permissions pour éditer à partir d'ici.",
"Settings" : "Paramètres",
"WebDAV" : "WebDAV",
@@ -116,9 +111,9 @@
"Select all" : "Tout sélectionner",
"Upload too large" : "Téléversement trop volumineux",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Les fichiers que vous essayez d'envoyer dépassent la taille maximale d'envoi permise par ce serveur.",
- "Files are being scanned, please wait." : "Les fichiers sont en cours d'analyse, veuillez patienter.",
- "Currently scanning" : "Analyse en cours",
"No favorites" : "Aucun favori",
- "Files and folders you mark as favorite will show up here" : "Les fichiers et dossiers ajoutés à vos favoris apparaîtront ici"
+ "Files and folders you mark as favorite will show up here" : "Les fichiers et dossiers ajoutés à vos favoris apparaîtront ici",
+ "Text file" : "Fichier texte",
+ "New text file.txt" : "Nouveau fichier texte.txt"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/gl.js b/apps/files/l10n/gl.js
index 2713148bbb9..e463ef16b3d 100644
--- a/apps/files/l10n/gl.js
+++ b/apps/files/l10n/gl.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Almacenamento non dispoñíbel",
"Storage invalid" : "Almacenamento incorrecto",
"Unknown error" : "Produciuse un erro descoñecido",
- "Could not move %s - File with this name already exists" : "Non foi posíbel mover %s; Xa existe un ficheiro con ese nome.",
- "Could not move %s" : "Non foi posíbel mover %s",
- "Permission denied" : "Permiso denegado",
- "The target folder has been moved or deleted." : "O cartafol de destino foi movido ou eliminado.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Xa existe o nome %s no cartafol %s. Escolla outro nome.",
- "Error when creating the file" : "Produciuse un erro ao crear o ficheiro",
- "Error when creating the folder" : "Produciuse un erro ao crear o cartafol",
"Unable to set upload directory." : "Non é posíbel configurar o directorio de envíos.",
"Invalid Token" : "Marca incorrecta",
"No file was uploaded. Unknown error" : "Non se enviou ningún ficheiro. Produciuse un erro descoñecido.",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Falta o cartafol temporal",
"Failed to write to disk" : "Produciuse un erro ao escribir no disco",
"Not enough storage available" : "Non hai espazo de almacenamento abondo",
+ "The target folder has been moved or deleted." : "O cartafol de destino foi movido ou eliminado.",
"Upload failed. Could not find uploaded file" : "O envío fracasou. Non foi posíbel atopar o ficheiro enviado",
"Upload failed. Could not get file info." : "O envío fracasou. Non foi posíbel obter información do ficheiro.",
"Invalid directory." : "O directorio é incorrecto.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "Descargar",
"Rename" : "Renomear",
"Delete" : "Eliminar",
+ "Disconnect storage" : "Desconectar o almacenamento",
+ "Unshare" : "Deixar de compartir",
"Details" : "Detalles",
"Select" : "Seleccionar",
"Pending" : "Pendentes",
"Unable to determine date" : "Non é posíbel determinar a data",
"This operation is forbidden" : "Esta operación está prohibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Este directorio non está dispoñíbel, comprobe os rexistros ou póñase en contacto co administrador",
- "Error moving file." : "Produciuse un erro ao mover o ficheiro.",
- "Error moving file" : "Produciuse un erro ao mover o ficheiro",
- "Error" : "Erro",
- "{new_name} already exists" : "Xa existe un {new_name}",
- "Could not rename file" : "Non foi posíbel renomear o ficheiro",
- "Could not create file" : "Non foi posíbel crear o ficheiro",
- "Could not create folder" : "Non foi posíbel crear o cartafol",
- "Error deleting file." : "Produciuse un erro ao eliminar o ficheiro.",
"No entries in this folder match '{filter}'" : "Non hai entradas neste cartafol coincidentes con «{filter}»",
"Name" : "Nome",
"Size" : "Tamaño",
@@ -75,7 +63,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Marcado como favorito",
"Favorite" : "Favorito",
- "Text file" : "Ficheiro de texto",
"Folder" : "Cartafol",
"New folder" : "Novo cartafol",
"Upload" : "Enviar",
@@ -94,8 +81,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s eliminado %1$s",
"You restored %1$s" : "Vostede restaurou %1$s",
"%2$s restored %1$s" : "%2$s restaurou %1$s",
- "%s could not be renamed as it has been deleted" : "Non é posíbel renomear %s xa que foi eliminado",
- "%s could not be renamed" : "%s non pode cambiar de nome",
"Upload (max. %s)" : "Envío (máx. %s)",
"File handling" : "Manexo de ficheiro",
"Maximum upload size" : "Tamaño máximo do envío",
@@ -111,9 +96,8 @@ OC.L10N.register(
"Select all" : "Seleccionar todo",
"Upload too large" : "Envío grande de máis",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Os ficheiros que tenta enviar exceden do tamaño máximo permitido neste servidor",
- "Files are being scanned, please wait." : "Estanse analizando os ficheiros. Agarde.",
- "Currently scanning" : "Análise actual",
"No favorites" : "Non hai favoritos",
- "Files and folders you mark as favorite will show up here" : "Os ficheiros e cartafoles que marque como favoritos amosaranse aquí"
+ "Files and folders you mark as favorite will show up here" : "Os ficheiros e cartafoles que marque como favoritos amosaranse aquí",
+ "Text file" : "Ficheiro de texto"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/gl.json b/apps/files/l10n/gl.json
index f04420d11a7..418767c5167 100644
--- a/apps/files/l10n/gl.json
+++ b/apps/files/l10n/gl.json
@@ -2,13 +2,6 @@
"Storage not available" : "Almacenamento non dispoñíbel",
"Storage invalid" : "Almacenamento incorrecto",
"Unknown error" : "Produciuse un erro descoñecido",
- "Could not move %s - File with this name already exists" : "Non foi posíbel mover %s; Xa existe un ficheiro con ese nome.",
- "Could not move %s" : "Non foi posíbel mover %s",
- "Permission denied" : "Permiso denegado",
- "The target folder has been moved or deleted." : "O cartafol de destino foi movido ou eliminado.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Xa existe o nome %s no cartafol %s. Escolla outro nome.",
- "Error when creating the file" : "Produciuse un erro ao crear o ficheiro",
- "Error when creating the folder" : "Produciuse un erro ao crear o cartafol",
"Unable to set upload directory." : "Non é posíbel configurar o directorio de envíos.",
"Invalid Token" : "Marca incorrecta",
"No file was uploaded. Unknown error" : "Non se enviou ningún ficheiro. Produciuse un erro descoñecido.",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Falta o cartafol temporal",
"Failed to write to disk" : "Produciuse un erro ao escribir no disco",
"Not enough storage available" : "Non hai espazo de almacenamento abondo",
+ "The target folder has been moved or deleted." : "O cartafol de destino foi movido ou eliminado.",
"Upload failed. Could not find uploaded file" : "O envío fracasou. Non foi posíbel atopar o ficheiro enviado",
"Upload failed. Could not get file info." : "O envío fracasou. Non foi posíbel obter información do ficheiro.",
"Invalid directory." : "O directorio é incorrecto.",
@@ -38,20 +32,14 @@
"Download" : "Descargar",
"Rename" : "Renomear",
"Delete" : "Eliminar",
+ "Disconnect storage" : "Desconectar o almacenamento",
+ "Unshare" : "Deixar de compartir",
"Details" : "Detalles",
"Select" : "Seleccionar",
"Pending" : "Pendentes",
"Unable to determine date" : "Non é posíbel determinar a data",
"This operation is forbidden" : "Esta operación está prohibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Este directorio non está dispoñíbel, comprobe os rexistros ou póñase en contacto co administrador",
- "Error moving file." : "Produciuse un erro ao mover o ficheiro.",
- "Error moving file" : "Produciuse un erro ao mover o ficheiro",
- "Error" : "Erro",
- "{new_name} already exists" : "Xa existe un {new_name}",
- "Could not rename file" : "Non foi posíbel renomear o ficheiro",
- "Could not create file" : "Non foi posíbel crear o ficheiro",
- "Could not create folder" : "Non foi posíbel crear o cartafol",
- "Error deleting file." : "Produciuse un erro ao eliminar o ficheiro.",
"No entries in this folder match '{filter}'" : "Non hai entradas neste cartafol coincidentes con «{filter}»",
"Name" : "Nome",
"Size" : "Tamaño",
@@ -73,7 +61,6 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Marcado como favorito",
"Favorite" : "Favorito",
- "Text file" : "Ficheiro de texto",
"Folder" : "Cartafol",
"New folder" : "Novo cartafol",
"Upload" : "Enviar",
@@ -92,8 +79,6 @@
"%2$s deleted %1$s" : "%2$s eliminado %1$s",
"You restored %1$s" : "Vostede restaurou %1$s",
"%2$s restored %1$s" : "%2$s restaurou %1$s",
- "%s could not be renamed as it has been deleted" : "Non é posíbel renomear %s xa que foi eliminado",
- "%s could not be renamed" : "%s non pode cambiar de nome",
"Upload (max. %s)" : "Envío (máx. %s)",
"File handling" : "Manexo de ficheiro",
"Maximum upload size" : "Tamaño máximo do envío",
@@ -109,9 +94,8 @@
"Select all" : "Seleccionar todo",
"Upload too large" : "Envío grande de máis",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Os ficheiros que tenta enviar exceden do tamaño máximo permitido neste servidor",
- "Files are being scanned, please wait." : "Estanse analizando os ficheiros. Agarde.",
- "Currently scanning" : "Análise actual",
"No favorites" : "Non hai favoritos",
- "Files and folders you mark as favorite will show up here" : "Os ficheiros e cartafoles que marque como favoritos amosaranse aquí"
+ "Files and folders you mark as favorite will show up here" : "Os ficheiros e cartafoles que marque como favoritos amosaranse aquí",
+ "Text file" : "Ficheiro de texto"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/he.js b/apps/files/l10n/he.js
index 36fba4bd7f0..2ff7090ad59 100644
--- a/apps/files/l10n/he.js
+++ b/apps/files/l10n/he.js
@@ -1,9 +1,11 @@
OC.L10N.register(
"files",
{
+ "Storage not available" : "אחסון לא זמין",
+ "Storage invalid" : "אחסון לא חוקי",
"Unknown error" : "שגיאה בלתי ידועה",
- "Could not move %s - File with this name already exists" : "לא ניתן להעביר את %s - קובץ בשם הזה כבר קיים",
- "Could not move %s" : "לא ניתן להעביר את %s",
+ "Unable to set upload directory." : "לא היה ניתן לקבוע תיקיית העלאות.",
+ "Invalid Token" : "קוד לא חוקי",
"No file was uploaded. Unknown error" : "לא הועלה קובץ. טעות בלתי מזוהה.",
"There is no error, the file uploaded with success" : "לא התרחשה שגיאה, הקובץ הועלה בהצלחה",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "הקבצים שנשלחו חורגים מהגודל שצוין בהגדרה upload_max_filesize שבקובץ php.ini:",
@@ -13,38 +15,75 @@ OC.L10N.register(
"Missing a temporary folder" : "תקיה זמנית חסרה",
"Failed to write to disk" : "הכתיבה לכונן נכשלה",
"Not enough storage available" : "אין די שטח פנוי באחסון",
+ "The target folder has been moved or deleted." : "תיקיית המטרה הועברה או נמחקה.",
+ "Upload failed. Could not find uploaded file" : "העלאה נכשלה. לא נמצא הקובץ להעלאה",
"Upload failed. Could not get file info." : "העלאה נכשלה. לא ניתן להשיג את פרטי הקובץ.",
"Invalid directory." : "תיקייה שגויה.",
"Files" : "קבצים",
+ "All files" : "כל הקבצים",
"Favorites" : "מועדפים",
"Home" : "בית",
"Close" : "סגירה",
"Upload cancelled." : "ההעלאה בוטלה.",
+ "Unable to upload {filename} as it is a directory or has 0 bytes" : "לא ניתן להעלות {filename} כיוון שמדובר בתיקייה או שגודלו 0 בייט",
+ "Total file size {size1} exceeds upload limit {size2}" : "גודל הקובת {size1} עובר את מגבלת הגודל להעלאה {size2}",
+ "Not enough free space, you are uploading {size1} but only {size2} is left" : "לא קיים מספיק מקום פנוי, הקובץ המיועד להעלאה {size1} אבל נשאר {size2} בלבד",
"Could not get result from server." : "לא ניתן לגשת לתוצאות מהשרת.",
"File upload is in progress. Leaving the page now will cancel the upload." : "מתבצעת כעת העלאת קבצים. עזיבה של העמוד תבטל את ההעלאה.",
"Actions" : "פעולות",
"Download" : "הורדה",
"Rename" : "שינוי שם",
"Delete" : "מחיקה",
+ "Disconnect storage" : "ניתוק אחסון",
+ "Unshare" : "הסר שיתוף",
"Details" : "פרטים",
"Select" : "בחר",
"Pending" : "ממתין",
- "Error" : "שגיאה",
- "{new_name} already exists" : "{new_name} כבר קיים",
+ "Unable to determine date" : "לא ניתן לקבוע תאריך",
+ "This operation is forbidden" : "פעולה זו אסורה",
+ "This directory is unavailable, please check the logs or contact the administrator" : "תיקייה זו לא קיימת, יש לבדוק את הלוגים או ליצור קשר עם המנהל",
+ "Could not move \"{file}\", target exists" : "לא ניתן להעביר \"{file}\", קובץ מטרה קיים",
+ "Could not move \"{file}\"" : "לא ניתן להעביר \"{file}\"",
+ "{newName} already exists" : "{newName} כבר קיים",
+ "Could not rename \"{fileName}\", it does not exist any more" : "לא ניתן לשנות שם \"{fileName}\", הוא כבר לא קיים יותר",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "השם \"{targetName}\" כבר קיים בתיקייה \"{dir}\". יש לבחור שם אחר.",
+ "Could not rename \"{fileName}\"" : "לא ניתן לשנות את השם \"{fileName}\"",
+ "Could not create file \"{file}\"" : "לא ניתן ליצור את הקובץ \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "לא ניתן ליצור את הקובץ \"{file}\" כיוון שהוא כבר קיים",
+ "Could not create folder \"{dir}\"" : "לא ניתן ליצור את התיקייה \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "לא ניתן ליצור את התיקייה \"{dir}\" כיוון שהיא כבר קיימת",
+ "Error deleting file \"{fileName}\"." : "שגיאה בזמן מחיקת קובץ \"{fileName}\".",
+ "No entries in this folder match '{filter}'" : "לא נמצאו התאמות בתיקייה זו ל- '{filter}'",
"Name" : "שם",
"Size" : "גודל",
"Modified" : "זמן שינוי",
+ "_%n folder_::_%n folders_" : ["%n תיקייה","%n תיקיות"],
+ "_%n file_::_%n files_" : ["%n קובץ","%n קבצים"],
+ "{dirs} and {files}" : "{dirs} וכן {files}",
+ "You don’t have permission to upload or create files here" : "אין לך הרשאות להעלות או ליצור קבצים כאן",
+ "_Uploading %n file_::_Uploading %n files_" : ["מעלה %n קובץ","מעלה %n קבצים"],
"New" : "חדש",
+ "\"{name}\" is an invalid file name." : "\"{name}\" הנו שם קובץ לא חוקי.",
"File name cannot be empty." : "שם קובץ אינו יכול להיות ריק",
+ "Storage of {owner} is full, files can not be updated or synced anymore!" : "האחסון של {owner} מלא, כבר לא ניתן לעדכן ולסנכרן קבצים!",
+ "Your storage is full, files can not be updated or synced anymore!" : "האחסון שלך מלא, כבר לא ניתן לעדכן ולסנכרן קבצים!",
+ "Storage of {owner} is almost full ({usedSpacePercent}%)" : "האחסון של {owner} כמעט מלא ({usedSpacePercent}%)",
"Your storage is almost full ({usedSpacePercent}%)" : "שטח האחסון שלך כמעט מלא ({usedSpacePercent}%)",
+ "_matches '{filter}'_::_match '{filter}'_" : ["מתאים ל- '{filter}'","מתאים ל- '{filter}'"],
+ "Path" : "נתיב",
+ "_%n byte_::_%n bytes_" : ["%n בייט","%n בייטים"],
+ "Favorited" : "מועדף",
"Favorite" : "מועדף",
- "Text file" : "קובץ טקסט",
"Folder" : "תיקייה",
"New folder" : "תיקייה חדשה",
+ "{newname} already exists" : "{newname} כבר קיים",
"Upload" : "העלאה",
+ "An error occurred while trying to update the tags" : "שגיאה אירעה בזמן עדכון התגיות",
"A new file or folder has been <strong>created</strong>" : "קובץ או תיקייה חדשים <strong>נוצרו<strong/>",
"A file or folder has been <strong>changed</strong>" : "קובץ או תיקייה <strong>שונו<strong/>",
+ "Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "הגבלת הודעות על יצירת או שינוי <strong>הקבצים המועדפים</strong> שלך <em>(Stream only)</em>",
"A file or folder has been <strong>deleted</strong>" : "קובץ או תיקייה <strong>נמחקו<strong/>",
+ "A file or folder has been <strong>restored</strong>" : "קובץ או תיקייה <strong>שוחזר</strong>",
"You created %1$s" : "יצרת %1$s",
"%2$s created %1$s" : "%2$s נוצרו %1$s",
"%1$s was created in a public folder" : "%1$s נוצר בתיקייה ציבורית",
@@ -52,16 +91,31 @@ OC.L10N.register(
"%2$s changed %1$s" : "%2$s שונו %1$s",
"You deleted %1$s" : "מחקת %1$s",
"%2$s deleted %1$s" : "%2$s נמחקו %1$s",
+ "You restored %1$s" : "שחזרת %1$s",
+ "%2$s restored %1$s" : "%2$s שוחזרו %1$s",
+ "Changed by %2$s" : "שונו על ידי %2$s",
+ "Deleted by %2$s" : "נמחקו על ידי %2$s",
+ "Restored by %2$s" : "שוחזרו על ידי %2$s",
"Upload (max. %s)" : "העלאה (מקסימום %s)",
"File handling" : "טיפול בקבצים",
"Maximum upload size" : "גודל העלאה מקסימלי",
"max. possible: " : "המרבי האפשרי: ",
"Save" : "שמירה",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "בשימוש ב- PHP-FPM זה יכול להמשך 5 דקות לשינויים לחול.",
+ "Missing permissions to edit from here." : "חסרות הרשאות לעריכה מכאן.",
"Settings" : "הגדרות",
"WebDAV" : "WebDAV",
+ "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "השתמש בכתובת זו לצורך <a href=\"%s\" target=\"_blank\">כניסה אל הקבצים שלך בעזרת WebDAV</a>",
"Cancel upload" : "ביטול ההעלאה",
+ "No files in here" : "אין כאן קבצים",
+ "Upload some content or sync with your devices!" : "יש להעלות קצת תוכן או לסנכרן עם ההתקנים שלך!",
+ "No entries found in this folder" : "לא נמצאו כניסות לתיקייה זו",
+ "Select all" : "לבחור הכול",
"Upload too large" : "העלאה גדולה מידי",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "הקבצים שניסית להעלות חרגו מהגודל המקסימלי להעלאת קבצים על שרת זה.",
- "Files are being scanned, please wait." : "הקבצים נסרקים, נא להמתין."
+ "No favorites" : "אין מועדפים",
+ "Files and folders you mark as favorite will show up here" : "קבצים ותיקיות שסומנו על ידך כמועדפים יוצגו כאן",
+ "Text file" : "קובץ טקסט",
+ "New text file.txt" : "קובץ טקסט חדש.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/he.json b/apps/files/l10n/he.json
index 61fe8ca29b7..001dc96db8d 100644
--- a/apps/files/l10n/he.json
+++ b/apps/files/l10n/he.json
@@ -1,7 +1,9 @@
{ "translations": {
+ "Storage not available" : "אחסון לא זמין",
+ "Storage invalid" : "אחסון לא חוקי",
"Unknown error" : "שגיאה בלתי ידועה",
- "Could not move %s - File with this name already exists" : "לא ניתן להעביר את %s - קובץ בשם הזה כבר קיים",
- "Could not move %s" : "לא ניתן להעביר את %s",
+ "Unable to set upload directory." : "לא היה ניתן לקבוע תיקיית העלאות.",
+ "Invalid Token" : "קוד לא חוקי",
"No file was uploaded. Unknown error" : "לא הועלה קובץ. טעות בלתי מזוהה.",
"There is no error, the file uploaded with success" : "לא התרחשה שגיאה, הקובץ הועלה בהצלחה",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "הקבצים שנשלחו חורגים מהגודל שצוין בהגדרה upload_max_filesize שבקובץ php.ini:",
@@ -11,38 +13,75 @@
"Missing a temporary folder" : "תקיה זמנית חסרה",
"Failed to write to disk" : "הכתיבה לכונן נכשלה",
"Not enough storage available" : "אין די שטח פנוי באחסון",
+ "The target folder has been moved or deleted." : "תיקיית המטרה הועברה או נמחקה.",
+ "Upload failed. Could not find uploaded file" : "העלאה נכשלה. לא נמצא הקובץ להעלאה",
"Upload failed. Could not get file info." : "העלאה נכשלה. לא ניתן להשיג את פרטי הקובץ.",
"Invalid directory." : "תיקייה שגויה.",
"Files" : "קבצים",
+ "All files" : "כל הקבצים",
"Favorites" : "מועדפים",
"Home" : "בית",
"Close" : "סגירה",
"Upload cancelled." : "ההעלאה בוטלה.",
+ "Unable to upload {filename} as it is a directory or has 0 bytes" : "לא ניתן להעלות {filename} כיוון שמדובר בתיקייה או שגודלו 0 בייט",
+ "Total file size {size1} exceeds upload limit {size2}" : "גודל הקובת {size1} עובר את מגבלת הגודל להעלאה {size2}",
+ "Not enough free space, you are uploading {size1} but only {size2} is left" : "לא קיים מספיק מקום פנוי, הקובץ המיועד להעלאה {size1} אבל נשאר {size2} בלבד",
"Could not get result from server." : "לא ניתן לגשת לתוצאות מהשרת.",
"File upload is in progress. Leaving the page now will cancel the upload." : "מתבצעת כעת העלאת קבצים. עזיבה של העמוד תבטל את ההעלאה.",
"Actions" : "פעולות",
"Download" : "הורדה",
"Rename" : "שינוי שם",
"Delete" : "מחיקה",
+ "Disconnect storage" : "ניתוק אחסון",
+ "Unshare" : "הסר שיתוף",
"Details" : "פרטים",
"Select" : "בחר",
"Pending" : "ממתין",
- "Error" : "שגיאה",
- "{new_name} already exists" : "{new_name} כבר קיים",
+ "Unable to determine date" : "לא ניתן לקבוע תאריך",
+ "This operation is forbidden" : "פעולה זו אסורה",
+ "This directory is unavailable, please check the logs or contact the administrator" : "תיקייה זו לא קיימת, יש לבדוק את הלוגים או ליצור קשר עם המנהל",
+ "Could not move \"{file}\", target exists" : "לא ניתן להעביר \"{file}\", קובץ מטרה קיים",
+ "Could not move \"{file}\"" : "לא ניתן להעביר \"{file}\"",
+ "{newName} already exists" : "{newName} כבר קיים",
+ "Could not rename \"{fileName}\", it does not exist any more" : "לא ניתן לשנות שם \"{fileName}\", הוא כבר לא קיים יותר",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "השם \"{targetName}\" כבר קיים בתיקייה \"{dir}\". יש לבחור שם אחר.",
+ "Could not rename \"{fileName}\"" : "לא ניתן לשנות את השם \"{fileName}\"",
+ "Could not create file \"{file}\"" : "לא ניתן ליצור את הקובץ \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "לא ניתן ליצור את הקובץ \"{file}\" כיוון שהוא כבר קיים",
+ "Could not create folder \"{dir}\"" : "לא ניתן ליצור את התיקייה \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "לא ניתן ליצור את התיקייה \"{dir}\" כיוון שהיא כבר קיימת",
+ "Error deleting file \"{fileName}\"." : "שגיאה בזמן מחיקת קובץ \"{fileName}\".",
+ "No entries in this folder match '{filter}'" : "לא נמצאו התאמות בתיקייה זו ל- '{filter}'",
"Name" : "שם",
"Size" : "גודל",
"Modified" : "זמן שינוי",
+ "_%n folder_::_%n folders_" : ["%n תיקייה","%n תיקיות"],
+ "_%n file_::_%n files_" : ["%n קובץ","%n קבצים"],
+ "{dirs} and {files}" : "{dirs} וכן {files}",
+ "You don’t have permission to upload or create files here" : "אין לך הרשאות להעלות או ליצור קבצים כאן",
+ "_Uploading %n file_::_Uploading %n files_" : ["מעלה %n קובץ","מעלה %n קבצים"],
"New" : "חדש",
+ "\"{name}\" is an invalid file name." : "\"{name}\" הנו שם קובץ לא חוקי.",
"File name cannot be empty." : "שם קובץ אינו יכול להיות ריק",
+ "Storage of {owner} is full, files can not be updated or synced anymore!" : "האחסון של {owner} מלא, כבר לא ניתן לעדכן ולסנכרן קבצים!",
+ "Your storage is full, files can not be updated or synced anymore!" : "האחסון שלך מלא, כבר לא ניתן לעדכן ולסנכרן קבצים!",
+ "Storage of {owner} is almost full ({usedSpacePercent}%)" : "האחסון של {owner} כמעט מלא ({usedSpacePercent}%)",
"Your storage is almost full ({usedSpacePercent}%)" : "שטח האחסון שלך כמעט מלא ({usedSpacePercent}%)",
+ "_matches '{filter}'_::_match '{filter}'_" : ["מתאים ל- '{filter}'","מתאים ל- '{filter}'"],
+ "Path" : "נתיב",
+ "_%n byte_::_%n bytes_" : ["%n בייט","%n בייטים"],
+ "Favorited" : "מועדף",
"Favorite" : "מועדף",
- "Text file" : "קובץ טקסט",
"Folder" : "תיקייה",
"New folder" : "תיקייה חדשה",
+ "{newname} already exists" : "{newname} כבר קיים",
"Upload" : "העלאה",
+ "An error occurred while trying to update the tags" : "שגיאה אירעה בזמן עדכון התגיות",
"A new file or folder has been <strong>created</strong>" : "קובץ או תיקייה חדשים <strong>נוצרו<strong/>",
"A file or folder has been <strong>changed</strong>" : "קובץ או תיקייה <strong>שונו<strong/>",
+ "Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "הגבלת הודעות על יצירת או שינוי <strong>הקבצים המועדפים</strong> שלך <em>(Stream only)</em>",
"A file or folder has been <strong>deleted</strong>" : "קובץ או תיקייה <strong>נמחקו<strong/>",
+ "A file or folder has been <strong>restored</strong>" : "קובץ או תיקייה <strong>שוחזר</strong>",
"You created %1$s" : "יצרת %1$s",
"%2$s created %1$s" : "%2$s נוצרו %1$s",
"%1$s was created in a public folder" : "%1$s נוצר בתיקייה ציבורית",
@@ -50,16 +89,31 @@
"%2$s changed %1$s" : "%2$s שונו %1$s",
"You deleted %1$s" : "מחקת %1$s",
"%2$s deleted %1$s" : "%2$s נמחקו %1$s",
+ "You restored %1$s" : "שחזרת %1$s",
+ "%2$s restored %1$s" : "%2$s שוחזרו %1$s",
+ "Changed by %2$s" : "שונו על ידי %2$s",
+ "Deleted by %2$s" : "נמחקו על ידי %2$s",
+ "Restored by %2$s" : "שוחזרו על ידי %2$s",
"Upload (max. %s)" : "העלאה (מקסימום %s)",
"File handling" : "טיפול בקבצים",
"Maximum upload size" : "גודל העלאה מקסימלי",
"max. possible: " : "המרבי האפשרי: ",
"Save" : "שמירה",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "בשימוש ב- PHP-FPM זה יכול להמשך 5 דקות לשינויים לחול.",
+ "Missing permissions to edit from here." : "חסרות הרשאות לעריכה מכאן.",
"Settings" : "הגדרות",
"WebDAV" : "WebDAV",
+ "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "השתמש בכתובת זו לצורך <a href=\"%s\" target=\"_blank\">כניסה אל הקבצים שלך בעזרת WebDAV</a>",
"Cancel upload" : "ביטול ההעלאה",
+ "No files in here" : "אין כאן קבצים",
+ "Upload some content or sync with your devices!" : "יש להעלות קצת תוכן או לסנכרן עם ההתקנים שלך!",
+ "No entries found in this folder" : "לא נמצאו כניסות לתיקייה זו",
+ "Select all" : "לבחור הכול",
"Upload too large" : "העלאה גדולה מידי",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "הקבצים שניסית להעלות חרגו מהגודל המקסימלי להעלאת קבצים על שרת זה.",
- "Files are being scanned, please wait." : "הקבצים נסרקים, נא להמתין."
+ "No favorites" : "אין מועדפים",
+ "Files and folders you mark as favorite will show up here" : "קבצים ותיקיות שסומנו על ידך כמועדפים יוצגו כאן",
+ "Text file" : "קובץ טקסט",
+ "New text file.txt" : "קובץ טקסט חדש.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/hi.js b/apps/files/l10n/hi.js
index 3b6da840e0d..2de5b85e169 100644
--- a/apps/files/l10n/hi.js
+++ b/apps/files/l10n/hi.js
@@ -4,7 +4,6 @@ OC.L10N.register(
"Files" : "फाइलें ",
"Close" : "बंद करें ",
"Details" : "विवरण ",
- "Error" : "त्रुटि",
"New folder" : "नया फ़ोल्डर",
"Upload" : "अपलोड ",
"Save" : "सहेजें",
diff --git a/apps/files/l10n/hi.json b/apps/files/l10n/hi.json
index a5a2ba34b01..3bccaa2d9f0 100644
--- a/apps/files/l10n/hi.json
+++ b/apps/files/l10n/hi.json
@@ -2,7 +2,6 @@
"Files" : "फाइलें ",
"Close" : "बंद करें ",
"Details" : "विवरण ",
- "Error" : "त्रुटि",
"New folder" : "नया फ़ोल्डर",
"Upload" : "अपलोड ",
"Save" : "सहेजें",
diff --git a/apps/files/l10n/hr.js b/apps/files/l10n/hr.js
index a15e52dcd49..746ee8ded91 100644
--- a/apps/files/l10n/hr.js
+++ b/apps/files/l10n/hr.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Pohrana nedostupna",
"Storage invalid" : "Pohrana neispravna",
"Unknown error" : "Nepoznata pogreška",
- "Could not move %s - File with this name already exists" : "Nemoguće premjestiti %s - Datoteka takvog naziva već postoji",
- "Could not move %s" : "Nemoguće premjestiti %s",
- "Permission denied" : "Nemate dozvolu",
- "The target folder has been moved or deleted." : "Ciljna mapa je premještena ili izbrisana.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Naziv %s je već iskorišten u mapi %s. Molimo odaberite drukčiji naziv.",
- "Error when creating the file" : "Pogreška pri kreiranju datoteke",
- "Error when creating the folder" : "Pogreška pri kreiranju mape",
"Unable to set upload directory." : "Postavka učitavanja direktorija nije moguća",
"Invalid Token" : "Neispravan token",
"No file was uploaded. Unknown error" : "Nijedna datoteka nije učitana. Pogreška nepoznata.",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Nedostaje privremena mapa",
"Failed to write to disk" : "Zapisivanje na disk nije uspjelo",
"Not enough storage available" : "Prostor za pohranu nedostatan",
+ "The target folder has been moved or deleted." : "Ciljna mapa je premještena ili izbrisana.",
"Upload failed. Could not find uploaded file" : "Učitavanje neuspješno. Nije emoguće pronaći učitanu dataoteku",
"Upload failed. Could not get file info." : "Učitavanje neuspješno. Nije moguće dohvatiti informacije o datoteci",
"Invalid directory." : "Neispravan direktorij",
@@ -40,18 +34,12 @@ OC.L10N.register(
"Download" : "Preuzimanje",
"Rename" : "Preimenujte",
"Delete" : "Izbrišite",
+ "Disconnect storage" : "Isključite pohranu",
+ "Unshare" : "Prestanite dijeliti",
"Details" : "Detalji",
"Select" : "Selektiraj",
"Pending" : "Na čekanju",
"Unable to determine date" : "Nemogucnost odredjivanja datuma",
- "Error moving file." : "Pogrešno premještanje datoteke",
- "Error moving file" : "Pogrešno premještanje datoteke",
- "Error" : "Pogreška",
- "{new_name} already exists" : "{new_name} već postoji",
- "Could not rename file" : "Datoteku nije moguće preimenovati",
- "Could not create file" : "Datoteku nije moguće kreirati",
- "Could not create folder" : "Mapu nije moguće kreirati",
- "Error deleting file." : "Pogrešno brisanje datoteke",
"No entries in this folder match '{filter}'" : "Nema zapisa u ovom folderu match '{filter}'",
"Name" : "Naziv",
"Size" : "Veličina",
@@ -68,7 +56,6 @@ OC.L10N.register(
"Your storage is almost full ({usedSpacePercent}%)" : "Vaš prostor za pohranu je skoro pun ({usedSpacePercent}%)",
"Favorited" : "Favoritovan",
"Favorite" : "Favorit",
- "Text file" : "Tekstualna datoteka",
"Folder" : "Mapa",
"New folder" : "Nova mapa",
"Upload" : "Učitavanje",
@@ -85,8 +72,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s je izbrisao %1$s",
"You restored %1$s" : "Vraćeno %1$s",
"%2$s restored %1$s" : "%2$s vraćeno %1$s",
- "%s could not be renamed as it has been deleted" : "%s nije moguće preimenovati jer je izbrisan",
- "%s could not be renamed" : "%s nije moguće preimenovati",
"Upload (max. %s)" : "Prijenos (max. %s)",
"File handling" : "Obrada datoteke",
"Maximum upload size" : "Maksimalna veličina učitanog sadržaja",
@@ -101,9 +86,8 @@ OC.L10N.register(
"Select all" : "Selektiraj sve",
"Upload too large" : "Unos je prevelik",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Datoteke koje pokušavate učitati premašuju maksimalnu veličinu za unos datoteka na ovom poslužitelju.",
- "Files are being scanned, please wait." : "Datoteke se provjeravaju, molimo pričekajte.",
- "Currently scanning" : "Provjera u tijeku",
"No favorites" : "Nema favorita",
- "Files and folders you mark as favorite will show up here" : "Fajlovi i folderi koje oznacite kao favorite ce se prikazati ovdje"
+ "Files and folders you mark as favorite will show up here" : "Fajlovi i folderi koje oznacite kao favorite ce se prikazati ovdje",
+ "Text file" : "Tekstualna datoteka"
},
"nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;");
diff --git a/apps/files/l10n/hr.json b/apps/files/l10n/hr.json
index e0463579f4a..35bc43df7e0 100644
--- a/apps/files/l10n/hr.json
+++ b/apps/files/l10n/hr.json
@@ -2,13 +2,6 @@
"Storage not available" : "Pohrana nedostupna",
"Storage invalid" : "Pohrana neispravna",
"Unknown error" : "Nepoznata pogreška",
- "Could not move %s - File with this name already exists" : "Nemoguće premjestiti %s - Datoteka takvog naziva već postoji",
- "Could not move %s" : "Nemoguće premjestiti %s",
- "Permission denied" : "Nemate dozvolu",
- "The target folder has been moved or deleted." : "Ciljna mapa je premještena ili izbrisana.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Naziv %s je već iskorišten u mapi %s. Molimo odaberite drukčiji naziv.",
- "Error when creating the file" : "Pogreška pri kreiranju datoteke",
- "Error when creating the folder" : "Pogreška pri kreiranju mape",
"Unable to set upload directory." : "Postavka učitavanja direktorija nije moguća",
"Invalid Token" : "Neispravan token",
"No file was uploaded. Unknown error" : "Nijedna datoteka nije učitana. Pogreška nepoznata.",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Nedostaje privremena mapa",
"Failed to write to disk" : "Zapisivanje na disk nije uspjelo",
"Not enough storage available" : "Prostor za pohranu nedostatan",
+ "The target folder has been moved or deleted." : "Ciljna mapa je premještena ili izbrisana.",
"Upload failed. Could not find uploaded file" : "Učitavanje neuspješno. Nije emoguće pronaći učitanu dataoteku",
"Upload failed. Could not get file info." : "Učitavanje neuspješno. Nije moguće dohvatiti informacije o datoteci",
"Invalid directory." : "Neispravan direktorij",
@@ -38,18 +32,12 @@
"Download" : "Preuzimanje",
"Rename" : "Preimenujte",
"Delete" : "Izbrišite",
+ "Disconnect storage" : "Isključite pohranu",
+ "Unshare" : "Prestanite dijeliti",
"Details" : "Detalji",
"Select" : "Selektiraj",
"Pending" : "Na čekanju",
"Unable to determine date" : "Nemogucnost odredjivanja datuma",
- "Error moving file." : "Pogrešno premještanje datoteke",
- "Error moving file" : "Pogrešno premještanje datoteke",
- "Error" : "Pogreška",
- "{new_name} already exists" : "{new_name} već postoji",
- "Could not rename file" : "Datoteku nije moguće preimenovati",
- "Could not create file" : "Datoteku nije moguće kreirati",
- "Could not create folder" : "Mapu nije moguće kreirati",
- "Error deleting file." : "Pogrešno brisanje datoteke",
"No entries in this folder match '{filter}'" : "Nema zapisa u ovom folderu match '{filter}'",
"Name" : "Naziv",
"Size" : "Veličina",
@@ -66,7 +54,6 @@
"Your storage is almost full ({usedSpacePercent}%)" : "Vaš prostor za pohranu je skoro pun ({usedSpacePercent}%)",
"Favorited" : "Favoritovan",
"Favorite" : "Favorit",
- "Text file" : "Tekstualna datoteka",
"Folder" : "Mapa",
"New folder" : "Nova mapa",
"Upload" : "Učitavanje",
@@ -83,8 +70,6 @@
"%2$s deleted %1$s" : "%2$s je izbrisao %1$s",
"You restored %1$s" : "Vraćeno %1$s",
"%2$s restored %1$s" : "%2$s vraćeno %1$s",
- "%s could not be renamed as it has been deleted" : "%s nije moguće preimenovati jer je izbrisan",
- "%s could not be renamed" : "%s nije moguće preimenovati",
"Upload (max. %s)" : "Prijenos (max. %s)",
"File handling" : "Obrada datoteke",
"Maximum upload size" : "Maksimalna veličina učitanog sadržaja",
@@ -99,9 +84,8 @@
"Select all" : "Selektiraj sve",
"Upload too large" : "Unos je prevelik",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Datoteke koje pokušavate učitati premašuju maksimalnu veličinu za unos datoteka na ovom poslužitelju.",
- "Files are being scanned, please wait." : "Datoteke se provjeravaju, molimo pričekajte.",
- "Currently scanning" : "Provjera u tijeku",
"No favorites" : "Nema favorita",
- "Files and folders you mark as favorite will show up here" : "Fajlovi i folderi koje oznacite kao favorite ce se prikazati ovdje"
+ "Files and folders you mark as favorite will show up here" : "Fajlovi i folderi koje oznacite kao favorite ce se prikazati ovdje",
+ "Text file" : "Tekstualna datoteka"
},"pluralForm" :"nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"
} \ No newline at end of file
diff --git a/apps/files/l10n/hu_HU.js b/apps/files/l10n/hu_HU.js
index 48e9bfb168b..399c70932b7 100644
--- a/apps/files/l10n/hu_HU.js
+++ b/apps/files/l10n/hu_HU.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "A tároló elérhetetlen.",
"Storage invalid" : "A tároló érvénytelen",
"Unknown error" : "Ismeretlen hiba",
- "Could not move %s - File with this name already exists" : "%s áthelyezése nem sikerült - már létezik másik fájl ezzel a névvel",
- "Could not move %s" : "Nem sikerült %s áthelyezése",
- "Permission denied" : "Engedély megtagadva ",
- "The target folder has been moved or deleted." : "A célmappa törlődött, vagy áthelyezésre került.",
- "The name %s is already used in the folder %s. Please choose a different name." : "A %s név már létezik a %s mappában. Kérem válasszon másik nevet!",
- "Error when creating the file" : "Hiba történt az állomány létrehozásakor",
- "Error when creating the folder" : "Hiba történt a mappa létrehozásakor",
"Unable to set upload directory." : "Nem található a mappa, ahova feltölteni szeretne.",
"Invalid Token" : "Hibás token",
"No file was uploaded. Unknown error" : "Nem történt feltöltés. Ismeretlen hiba",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Hiányzik egy ideiglenes mappa",
"Failed to write to disk" : "Nem sikerült a lemezre történő írás",
"Not enough storage available" : "Nincs elég szabad hely.",
+ "The target folder has been moved or deleted." : "A célmappa törlődött, vagy áthelyezésre került.",
"Upload failed. Could not find uploaded file" : "A feltöltés nem sikerült. Nem található a feltöltendő állomány.",
"Upload failed. Could not get file info." : "A feltöltés nem sikerült. Az állományt leíró információk nem érhetők el.",
"Invalid directory." : "Érvénytelen mappa.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Letöltés",
"Rename" : "Átnevezés",
"Delete" : "Törlés",
+ "Disconnect storage" : "Tároló leválasztása",
+ "Unshare" : "A megosztás visszavonása",
"Details" : "Részletek",
"Select" : "Kiválaszt",
"Pending" : "Folyamatban",
"Unable to determine date" : "Nem lehet meghatározni a dátumot",
"This operation is forbidden" : "Tiltott művelet",
"This directory is unavailable, please check the logs or contact the administrator" : "Ez a könyvtár nem elérhető, kérem nézze meg a naplófájlokat vagy keresse az adminisztrátort",
- "Error moving file." : "Hiba történt a fájl áthelyezése közben.",
- "Error moving file" : "Az állomány áthelyezése nem sikerült.",
- "Error" : "Hiba",
- "{new_name} already exists" : "{new_name} már létezik",
- "Could not rename file" : "Az állomány nem nevezhető át",
- "Could not create file" : "Az állomány nem hozható létre",
- "Could not create folder" : "A mappa nem hozható létre",
- "Error deleting file." : "Hiba a file törlése közben.",
+ "Could not move \"{file}\", target exists" : "{file} fájl nem áthelyezhető, mert a cél már létezik",
+ "Could not move \"{file}\"" : "{file} fájl nem áthelyezhető",
+ "{newName} already exists" : "{newName} már létezik",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Nem átnevezhető erre: {fileName}, mert már nem létezik",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "{targetName} már használatban van a(z) {dir} könyvtárban. Kérjük, válassz másik nevet.",
+ "Could not rename \"{fileName}\"" : "{fileName} fájl nem átnevezhető",
+ "Could not create file \"{file}\"" : "{file} fájl nem létrehozható",
+ "Could not create file \"{file}\" because it already exists" : "{file} fájl nem létrehozható, mert már létezik",
+ "Could not create folder \"{dir}\"" : "{dir} könyvtár nem létrehozható",
+ "Could not create folder \"{dir}\" because it already exists" : "{dir} könyvtár nem létrehozható, mert már létezik",
+ "Error deleting file \"{fileName}\"." : "Hiba történt {fileName} fájl törlése közben.",
"No entries in this folder match '{filter}'" : "Nincsenek egyező bejegyzések ebben a könyvtárban '{filter}'",
"Name" : "Név",
"Size" : "Méret",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n bájt","%n bájt"],
"Favorited" : "Kedvenc",
"Favorite" : "Kedvenc",
- "Text file" : "Szövegfájl",
- "New text file.txt" : "Új szöveges fájl.txt",
"Folder" : "Mappa",
"New folder" : "Új mappa",
"{newname} already exists" : "{newname} már létezik",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "Megváltoztatta: %2$s",
"Deleted by %2$s" : "Törölte: %2$s",
"Restored by %2$s" : "Visszaállította: %2$s",
- "%s could not be renamed as it has been deleted" : "%s nem lehet átnevezni, mivel törölve lett",
- "%s could not be renamed" : "%s átnevezése nem sikerült",
"Upload (max. %s)" : "Feltöltés (max.: %s)",
"File handling" : "Fájlkezelés",
"Maximum upload size" : "Maximális feltölthető fájlméret",
"max. possible: " : "max. lehetséges: ",
"Save" : "Mentés",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM-mel akár 5 percbe is telhet, míg ez a beállítás érvénybe lép.",
+ "Missing permissions to edit from here." : "Innen nem lehet szerkeszteni hiányzó jogosultság miatt.",
"Settings" : "Beállítások",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Ezt a címet használja, ha <a href=\"%s\" target=\"_blank\">WebDAV-on keresztül szeretné elérni a fájljait</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "Összes kijelölése",
"Upload too large" : "A feltöltés túl nagy",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "A feltöltendő állományok mérete meghaladja a kiszolgálón megengedett maximális méretet.",
- "Files are being scanned, please wait." : "A fájllista ellenőrzése zajlik, kis türelmet!",
- "Currently scanning" : "Mappaellenőrzés: ",
"No favorites" : "Nincsenek kedvencek",
- "Files and folders you mark as favorite will show up here" : "A kedvencnek jelölt fájlokat és mappákat itt találod meg"
+ "Files and folders you mark as favorite will show up here" : "A kedvencnek jelölt fájlokat és mappákat itt találod meg",
+ "Text file" : "Szövegfájl",
+ "New text file.txt" : "Új szöveges fájl.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/hu_HU.json b/apps/files/l10n/hu_HU.json
index c72dfa0d48b..fdad8332499 100644
--- a/apps/files/l10n/hu_HU.json
+++ b/apps/files/l10n/hu_HU.json
@@ -2,13 +2,6 @@
"Storage not available" : "A tároló elérhetetlen.",
"Storage invalid" : "A tároló érvénytelen",
"Unknown error" : "Ismeretlen hiba",
- "Could not move %s - File with this name already exists" : "%s áthelyezése nem sikerült - már létezik másik fájl ezzel a névvel",
- "Could not move %s" : "Nem sikerült %s áthelyezése",
- "Permission denied" : "Engedély megtagadva ",
- "The target folder has been moved or deleted." : "A célmappa törlődött, vagy áthelyezésre került.",
- "The name %s is already used in the folder %s. Please choose a different name." : "A %s név már létezik a %s mappában. Kérem válasszon másik nevet!",
- "Error when creating the file" : "Hiba történt az állomány létrehozásakor",
- "Error when creating the folder" : "Hiba történt a mappa létrehozásakor",
"Unable to set upload directory." : "Nem található a mappa, ahova feltölteni szeretne.",
"Invalid Token" : "Hibás token",
"No file was uploaded. Unknown error" : "Nem történt feltöltés. Ismeretlen hiba",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Hiányzik egy ideiglenes mappa",
"Failed to write to disk" : "Nem sikerült a lemezre történő írás",
"Not enough storage available" : "Nincs elég szabad hely.",
+ "The target folder has been moved or deleted." : "A célmappa törlődött, vagy áthelyezésre került.",
"Upload failed. Could not find uploaded file" : "A feltöltés nem sikerült. Nem található a feltöltendő állomány.",
"Upload failed. Could not get file info." : "A feltöltés nem sikerült. Az állományt leíró információk nem érhetők el.",
"Invalid directory." : "Érvénytelen mappa.",
@@ -38,20 +32,25 @@
"Download" : "Letöltés",
"Rename" : "Átnevezés",
"Delete" : "Törlés",
+ "Disconnect storage" : "Tároló leválasztása",
+ "Unshare" : "A megosztás visszavonása",
"Details" : "Részletek",
"Select" : "Kiválaszt",
"Pending" : "Folyamatban",
"Unable to determine date" : "Nem lehet meghatározni a dátumot",
"This operation is forbidden" : "Tiltott művelet",
"This directory is unavailable, please check the logs or contact the administrator" : "Ez a könyvtár nem elérhető, kérem nézze meg a naplófájlokat vagy keresse az adminisztrátort",
- "Error moving file." : "Hiba történt a fájl áthelyezése közben.",
- "Error moving file" : "Az állomány áthelyezése nem sikerült.",
- "Error" : "Hiba",
- "{new_name} already exists" : "{new_name} már létezik",
- "Could not rename file" : "Az állomány nem nevezhető át",
- "Could not create file" : "Az állomány nem hozható létre",
- "Could not create folder" : "A mappa nem hozható létre",
- "Error deleting file." : "Hiba a file törlése közben.",
+ "Could not move \"{file}\", target exists" : "{file} fájl nem áthelyezhető, mert a cél már létezik",
+ "Could not move \"{file}\"" : "{file} fájl nem áthelyezhető",
+ "{newName} already exists" : "{newName} már létezik",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Nem átnevezhető erre: {fileName}, mert már nem létezik",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "{targetName} már használatban van a(z) {dir} könyvtárban. Kérjük, válassz másik nevet.",
+ "Could not rename \"{fileName}\"" : "{fileName} fájl nem átnevezhető",
+ "Could not create file \"{file}\"" : "{file} fájl nem létrehozható",
+ "Could not create file \"{file}\" because it already exists" : "{file} fájl nem létrehozható, mert már létezik",
+ "Could not create folder \"{dir}\"" : "{dir} könyvtár nem létrehozható",
+ "Could not create folder \"{dir}\" because it already exists" : "{dir} könyvtár nem létrehozható, mert már létezik",
+ "Error deleting file \"{fileName}\"." : "Hiba történt {fileName} fájl törlése közben.",
"No entries in this folder match '{filter}'" : "Nincsenek egyező bejegyzések ebben a könyvtárban '{filter}'",
"Name" : "Név",
"Size" : "Méret",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n bájt","%n bájt"],
"Favorited" : "Kedvenc",
"Favorite" : "Kedvenc",
- "Text file" : "Szövegfájl",
- "New text file.txt" : "Új szöveges fájl.txt",
"Folder" : "Mappa",
"New folder" : "Új mappa",
"{newname} already exists" : "{newname} már létezik",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "Megváltoztatta: %2$s",
"Deleted by %2$s" : "Törölte: %2$s",
"Restored by %2$s" : "Visszaállította: %2$s",
- "%s could not be renamed as it has been deleted" : "%s nem lehet átnevezni, mivel törölve lett",
- "%s could not be renamed" : "%s átnevezése nem sikerült",
"Upload (max. %s)" : "Feltöltés (max.: %s)",
"File handling" : "Fájlkezelés",
"Maximum upload size" : "Maximális feltölthető fájlméret",
"max. possible: " : "max. lehetséges: ",
"Save" : "Mentés",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM-mel akár 5 percbe is telhet, míg ez a beállítás érvénybe lép.",
+ "Missing permissions to edit from here." : "Innen nem lehet szerkeszteni hiányzó jogosultság miatt.",
"Settings" : "Beállítások",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Ezt a címet használja, ha <a href=\"%s\" target=\"_blank\">WebDAV-on keresztül szeretné elérni a fájljait</a>",
@@ -114,9 +111,9 @@
"Select all" : "Összes kijelölése",
"Upload too large" : "A feltöltés túl nagy",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "A feltöltendő állományok mérete meghaladja a kiszolgálón megengedett maximális méretet.",
- "Files are being scanned, please wait." : "A fájllista ellenőrzése zajlik, kis türelmet!",
- "Currently scanning" : "Mappaellenőrzés: ",
"No favorites" : "Nincsenek kedvencek",
- "Files and folders you mark as favorite will show up here" : "A kedvencnek jelölt fájlokat és mappákat itt találod meg"
+ "Files and folders you mark as favorite will show up here" : "A kedvencnek jelölt fájlokat és mappákat itt találod meg",
+ "Text file" : "Szövegfájl",
+ "New text file.txt" : "Új szöveges fájl.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/hy.js b/apps/files/l10n/hy.js
index 62bc84d6c7b..ecf99c1077f 100644
--- a/apps/files/l10n/hy.js
+++ b/apps/files/l10n/hy.js
@@ -2,6 +2,7 @@ OC.L10N.register(
"files",
{
"Files" : "Ֆայլեր",
+ "All files" : "Բոլոր ֆայլերը",
"Close" : "Փակել",
"Download" : "Բեռնել",
"Rename" : "Վերանվանել",
@@ -9,10 +10,17 @@ OC.L10N.register(
"Select" : "Նշել",
"Name" : "Անուն",
"Size" : "Չափս",
+ "Modified" : "Փոփոխված",
+ "_%n folder_::_%n folders_" : ["%n պանակ","%n պանակ"],
+ "_%n file_::_%n files_" : ["%n ֆայլ","%n ֆայլ"],
+ "{dirs} and {files}" : "{dirs} և {files}",
"New" : "Նոր",
+ "_%n byte_::_%n bytes_" : ["%n բայտ","%n բայտ"],
"Folder" : "Պանակ",
"New folder" : "Նոր պանակ",
"Save" : "Պահպանել",
- "Select all" : "Նշել բոլորը"
+ "Select all" : "Նշել բոլորը",
+ "Text file" : "Տեքստ ֆայլ",
+ "New text file.txt" : "Նոր տեքստ ֆայլ.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/hy.json b/apps/files/l10n/hy.json
index c5afd306272..8b23697b4a2 100644
--- a/apps/files/l10n/hy.json
+++ b/apps/files/l10n/hy.json
@@ -1,5 +1,6 @@
{ "translations": {
"Files" : "Ֆայլեր",
+ "All files" : "Բոլոր ֆայլերը",
"Close" : "Փակել",
"Download" : "Բեռնել",
"Rename" : "Վերանվանել",
@@ -7,10 +8,17 @@
"Select" : "Նշել",
"Name" : "Անուն",
"Size" : "Չափս",
+ "Modified" : "Փոփոխված",
+ "_%n folder_::_%n folders_" : ["%n պանակ","%n պանակ"],
+ "_%n file_::_%n files_" : ["%n ֆայլ","%n ֆայլ"],
+ "{dirs} and {files}" : "{dirs} և {files}",
"New" : "Նոր",
+ "_%n byte_::_%n bytes_" : ["%n բայտ","%n բայտ"],
"Folder" : "Պանակ",
"New folder" : "Նոր պանակ",
"Save" : "Պահպանել",
- "Select all" : "Նշել բոլորը"
+ "Select all" : "Նշել բոլորը",
+ "Text file" : "Տեքստ ֆայլ",
+ "New text file.txt" : "Նոր տեքստ ֆայլ.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/ia.js b/apps/files/l10n/ia.js
index f1db4466ea1..8310334287f 100644
--- a/apps/files/l10n/ia.js
+++ b/apps/files/l10n/ia.js
@@ -10,13 +10,12 @@ OC.L10N.register(
"Close" : "Clauder",
"Download" : "Discargar",
"Delete" : "Deler",
- "Error" : "Error",
+ "Unshare" : "Leva compartir",
"Name" : "Nomine",
"Size" : "Dimension",
"Modified" : "Modificate",
"New" : "Nove",
"File name cannot be empty." : "Le nomine de file non pote esser vacue.",
- "Text file" : "File de texto",
"Folder" : "Dossier",
"New folder" : "Nove dossier",
"Upload" : "Incargar",
@@ -37,6 +36,7 @@ OC.L10N.register(
"Maximum upload size" : "Dimension maxime de incargamento",
"Save" : "Salveguardar",
"Settings" : "Configurationes",
- "Upload too large" : "Incargamento troppo longe"
+ "Upload too large" : "Incargamento troppo longe",
+ "Text file" : "File de texto"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/ia.json b/apps/files/l10n/ia.json
index e7990404b98..eee4980e34a 100644
--- a/apps/files/l10n/ia.json
+++ b/apps/files/l10n/ia.json
@@ -8,13 +8,12 @@
"Close" : "Clauder",
"Download" : "Discargar",
"Delete" : "Deler",
- "Error" : "Error",
+ "Unshare" : "Leva compartir",
"Name" : "Nomine",
"Size" : "Dimension",
"Modified" : "Modificate",
"New" : "Nove",
"File name cannot be empty." : "Le nomine de file non pote esser vacue.",
- "Text file" : "File de texto",
"Folder" : "Dossier",
"New folder" : "Nove dossier",
"Upload" : "Incargar",
@@ -35,6 +34,7 @@
"Maximum upload size" : "Dimension maxime de incargamento",
"Save" : "Salveguardar",
"Settings" : "Configurationes",
- "Upload too large" : "Incargamento troppo longe"
+ "Upload too large" : "Incargamento troppo longe",
+ "Text file" : "File de texto"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/id.js b/apps/files/l10n/id.js
index f1ad4fd1f69..c67a74e43da 100644
--- a/apps/files/l10n/id.js
+++ b/apps/files/l10n/id.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Penyimpanan tidak tersedia",
"Storage invalid" : "Penyimpanan tidak sah",
"Unknown error" : "Kesalahan tidak diketahui",
- "Could not move %s - File with this name already exists" : "Tidak dapat memindahkan %s - Berkas dengan nama ini sudah ada",
- "Could not move %s" : "Tidak dapat memindahkan %s",
- "Permission denied" : "Perizinan ditolak",
- "The target folder has been moved or deleted." : "Folder tujuan telah dipindahkan atau dihapus.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nama %s sudah digunakan dalam folder %s. Silakan pilih nama yang berbeda.",
- "Error when creating the file" : "Kesalahan saat membuat berkas",
- "Error when creating the folder" : "Kesalahan saat membuat folder",
"Unable to set upload directory." : "Tidak dapat mengatur folder unggah",
"Invalid Token" : "Token tidak sah",
"No file was uploaded. Unknown error" : "Tidak ada berkas yang diunggah. Kesalahan tidak dikenal.",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Folder sementara tidak ada",
"Failed to write to disk" : "Gagal menulis ke disk",
"Not enough storage available" : "Ruang penyimpanan tidak mencukupi",
+ "The target folder has been moved or deleted." : "Folder tujuan telah dipindahkan atau dihapus.",
"Upload failed. Could not find uploaded file" : "Unggah gagal. Tidak menemukan berkas yang akan diunggah",
"Upload failed. Could not get file info." : "Unggah gagal. Tidak mendapatkan informasi berkas.",
"Invalid directory." : "Direktori tidak valid.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "Unduh",
"Rename" : "Ubah nama",
"Delete" : "Hapus",
+ "Disconnect storage" : "Memutuskan penyimpaan",
+ "Unshare" : "Batalkan berbagi",
"Details" : "Rincian",
"Select" : "Pilih",
"Pending" : "Tertunda",
"Unable to determine date" : "Tidak dapat menentukan tanggal",
"This operation is forbidden" : "Operasi ini dilarang",
"This directory is unavailable, please check the logs or contact the administrator" : "Direktori ini tidak tersedia, silakan periksa log atau hubungi kontak",
- "Error moving file." : "Kesalahan saat memindahkan berkas.",
- "Error moving file" : "Kesalahan saat memindahkan berkas",
- "Error" : "Kesalahan ",
- "{new_name} already exists" : "{new_name} sudah ada",
- "Could not rename file" : "Tidak dapat mengubah nama berkas",
- "Could not create file" : "Tidak dapat membuat berkas",
- "Could not create folder" : "Tidak dapat membuat folder",
- "Error deleting file." : "Kesalahan saat menghapus berkas.",
"No entries in this folder match '{filter}'" : "Tidak ada entri di folder ini yang cocok dengan '{filter}'",
"Name" : "Nama",
"Size" : "Ukuran",
@@ -75,8 +63,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte"],
"Favorited" : "Difavoritkan",
"Favorite" : "Favorit",
- "Text file" : "Berkas teks",
- "New text file.txt" : "Teks baru file.txt",
"Folder" : "Folder",
"New folder" : "Map baru",
"{newname} already exists" : "{newname} sudah ada",
@@ -99,8 +85,6 @@ OC.L10N.register(
"Changed by %2$s" : "Diubah oleh %2$s",
"Deleted by %2$s" : "Dihapus oleh %2$s",
"Restored by %2$s" : "Dipulihkan oleh %2$s",
- "%s could not be renamed as it has been deleted" : "%s tidak dapat diubah namanya kerena telah dihapus",
- "%s could not be renamed" : "%s tidak dapat diubah nama",
"Upload (max. %s)" : "Unggah (maks. %s)",
"File handling" : "Penanganan berkas",
"Maximum upload size" : "Ukuran pengunggahan maksimum",
@@ -116,9 +100,9 @@ OC.L10N.register(
"Select all" : "Pilih Semua",
"Upload too large" : "Yang diunggah terlalu besar",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Berkas yang dicoba untuk diunggah melebihi ukuran maksimum pengunggahan berkas di server ini.",
- "Files are being scanned, please wait." : "Berkas sedang dipindai, silakan tunggu.",
- "Currently scanning" : "Pemindaian terbaru",
"No favorites" : "Tidak ada favorit",
- "Files and folders you mark as favorite will show up here" : "Berkas dan folder yang Anda tandai sebagai favorit akan ditampilkan disini."
+ "Files and folders you mark as favorite will show up here" : "Berkas dan folder yang Anda tandai sebagai favorit akan ditampilkan disini.",
+ "Text file" : "Berkas teks",
+ "New text file.txt" : "Teks baru file.txt"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/id.json b/apps/files/l10n/id.json
index 0d357165370..68f01e0393a 100644
--- a/apps/files/l10n/id.json
+++ b/apps/files/l10n/id.json
@@ -2,13 +2,6 @@
"Storage not available" : "Penyimpanan tidak tersedia",
"Storage invalid" : "Penyimpanan tidak sah",
"Unknown error" : "Kesalahan tidak diketahui",
- "Could not move %s - File with this name already exists" : "Tidak dapat memindahkan %s - Berkas dengan nama ini sudah ada",
- "Could not move %s" : "Tidak dapat memindahkan %s",
- "Permission denied" : "Perizinan ditolak",
- "The target folder has been moved or deleted." : "Folder tujuan telah dipindahkan atau dihapus.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nama %s sudah digunakan dalam folder %s. Silakan pilih nama yang berbeda.",
- "Error when creating the file" : "Kesalahan saat membuat berkas",
- "Error when creating the folder" : "Kesalahan saat membuat folder",
"Unable to set upload directory." : "Tidak dapat mengatur folder unggah",
"Invalid Token" : "Token tidak sah",
"No file was uploaded. Unknown error" : "Tidak ada berkas yang diunggah. Kesalahan tidak dikenal.",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Folder sementara tidak ada",
"Failed to write to disk" : "Gagal menulis ke disk",
"Not enough storage available" : "Ruang penyimpanan tidak mencukupi",
+ "The target folder has been moved or deleted." : "Folder tujuan telah dipindahkan atau dihapus.",
"Upload failed. Could not find uploaded file" : "Unggah gagal. Tidak menemukan berkas yang akan diunggah",
"Upload failed. Could not get file info." : "Unggah gagal. Tidak mendapatkan informasi berkas.",
"Invalid directory." : "Direktori tidak valid.",
@@ -38,20 +32,14 @@
"Download" : "Unduh",
"Rename" : "Ubah nama",
"Delete" : "Hapus",
+ "Disconnect storage" : "Memutuskan penyimpaan",
+ "Unshare" : "Batalkan berbagi",
"Details" : "Rincian",
"Select" : "Pilih",
"Pending" : "Tertunda",
"Unable to determine date" : "Tidak dapat menentukan tanggal",
"This operation is forbidden" : "Operasi ini dilarang",
"This directory is unavailable, please check the logs or contact the administrator" : "Direktori ini tidak tersedia, silakan periksa log atau hubungi kontak",
- "Error moving file." : "Kesalahan saat memindahkan berkas.",
- "Error moving file" : "Kesalahan saat memindahkan berkas",
- "Error" : "Kesalahan ",
- "{new_name} already exists" : "{new_name} sudah ada",
- "Could not rename file" : "Tidak dapat mengubah nama berkas",
- "Could not create file" : "Tidak dapat membuat berkas",
- "Could not create folder" : "Tidak dapat membuat folder",
- "Error deleting file." : "Kesalahan saat menghapus berkas.",
"No entries in this folder match '{filter}'" : "Tidak ada entri di folder ini yang cocok dengan '{filter}'",
"Name" : "Nama",
"Size" : "Ukuran",
@@ -73,8 +61,6 @@
"_%n byte_::_%n bytes_" : ["%n byte"],
"Favorited" : "Difavoritkan",
"Favorite" : "Favorit",
- "Text file" : "Berkas teks",
- "New text file.txt" : "Teks baru file.txt",
"Folder" : "Folder",
"New folder" : "Map baru",
"{newname} already exists" : "{newname} sudah ada",
@@ -97,8 +83,6 @@
"Changed by %2$s" : "Diubah oleh %2$s",
"Deleted by %2$s" : "Dihapus oleh %2$s",
"Restored by %2$s" : "Dipulihkan oleh %2$s",
- "%s could not be renamed as it has been deleted" : "%s tidak dapat diubah namanya kerena telah dihapus",
- "%s could not be renamed" : "%s tidak dapat diubah nama",
"Upload (max. %s)" : "Unggah (maks. %s)",
"File handling" : "Penanganan berkas",
"Maximum upload size" : "Ukuran pengunggahan maksimum",
@@ -114,9 +98,9 @@
"Select all" : "Pilih Semua",
"Upload too large" : "Yang diunggah terlalu besar",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Berkas yang dicoba untuk diunggah melebihi ukuran maksimum pengunggahan berkas di server ini.",
- "Files are being scanned, please wait." : "Berkas sedang dipindai, silakan tunggu.",
- "Currently scanning" : "Pemindaian terbaru",
"No favorites" : "Tidak ada favorit",
- "Files and folders you mark as favorite will show up here" : "Berkas dan folder yang Anda tandai sebagai favorit akan ditampilkan disini."
+ "Files and folders you mark as favorite will show up here" : "Berkas dan folder yang Anda tandai sebagai favorit akan ditampilkan disini.",
+ "Text file" : "Berkas teks",
+ "New text file.txt" : "Teks baru file.txt"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/is.js b/apps/files/l10n/is.js
index f56579fa9c0..ed1fce950b7 100644
--- a/apps/files/l10n/is.js
+++ b/apps/files/l10n/is.js
@@ -1,8 +1,6 @@
OC.L10N.register(
"files",
{
- "Could not move %s - File with this name already exists" : "Gat ekki fært %s - Skrá með þessu nafni er þegar til",
- "Could not move %s" : "Gat ekki fært %s",
"No file was uploaded. Unknown error" : "Engin skrá var send inn. Óþekkt villa.",
"There is no error, the file uploaded with success" : "Engin villa, innsending heppnaðist",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "Innsend skrá er stærri en upload_max stillingin í php.ini:",
@@ -13,23 +11,24 @@ OC.L10N.register(
"Failed to write to disk" : "Tókst ekki að skrifa á disk",
"Invalid directory." : "Ógild mappa.",
"Files" : "Skrár",
+ "All files" : "Allar skrár",
"Close" : "Loka",
"Upload cancelled." : "Hætt við innsendingu.",
"File upload is in progress. Leaving the page now will cancel the upload." : "Innsending í gangi. Ef þú ferð af þessari síðu mun innsending misheppnast.",
"Download" : "Niðurhal",
"Rename" : "Endurskýra",
"Delete" : "Eyða",
+ "Unshare" : "Hætta deilingu",
"Select" : "Velja",
"Pending" : "Bíður",
- "Error" : "Villa",
- "{new_name} already exists" : "{new_name} er þegar til",
"Name" : "Nafn",
"Size" : "Stærð",
"Modified" : "Breytt",
"New" : "Nýtt",
"File name cannot be empty." : "Nafn skráar má ekki vera tómt",
- "Text file" : "Texta skrá",
+ "Favorite" : "Uppáhalds",
"Folder" : "Mappa",
+ "New folder" : "Ný mappa",
"Upload" : "Senda inn",
"File handling" : "Meðhöndlun skrár",
"Maximum upload size" : "Hámarks stærð innsendingar",
@@ -42,6 +41,6 @@ OC.L10N.register(
"Select all" : "Velja allt",
"Upload too large" : "Innsend skrá er of stór",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Skrárnar sem þú ert að senda inn eru stærri en hámarks innsendingarstærð á þessum netþjóni.",
- "Files are being scanned, please wait." : "Verið er að skima skrár, vinsamlegast hinkraðu."
+ "Text file" : "Texta skrá"
},
"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);");
diff --git a/apps/files/l10n/is.json b/apps/files/l10n/is.json
index 8a6da48f408..266a4f054bc 100644
--- a/apps/files/l10n/is.json
+++ b/apps/files/l10n/is.json
@@ -1,6 +1,4 @@
{ "translations": {
- "Could not move %s - File with this name already exists" : "Gat ekki fært %s - Skrá með þessu nafni er þegar til",
- "Could not move %s" : "Gat ekki fært %s",
"No file was uploaded. Unknown error" : "Engin skrá var send inn. Óþekkt villa.",
"There is no error, the file uploaded with success" : "Engin villa, innsending heppnaðist",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "Innsend skrá er stærri en upload_max stillingin í php.ini:",
@@ -11,23 +9,24 @@
"Failed to write to disk" : "Tókst ekki að skrifa á disk",
"Invalid directory." : "Ógild mappa.",
"Files" : "Skrár",
+ "All files" : "Allar skrár",
"Close" : "Loka",
"Upload cancelled." : "Hætt við innsendingu.",
"File upload is in progress. Leaving the page now will cancel the upload." : "Innsending í gangi. Ef þú ferð af þessari síðu mun innsending misheppnast.",
"Download" : "Niðurhal",
"Rename" : "Endurskýra",
"Delete" : "Eyða",
+ "Unshare" : "Hætta deilingu",
"Select" : "Velja",
"Pending" : "Bíður",
- "Error" : "Villa",
- "{new_name} already exists" : "{new_name} er þegar til",
"Name" : "Nafn",
"Size" : "Stærð",
"Modified" : "Breytt",
"New" : "Nýtt",
"File name cannot be empty." : "Nafn skráar má ekki vera tómt",
- "Text file" : "Texta skrá",
+ "Favorite" : "Uppáhalds",
"Folder" : "Mappa",
+ "New folder" : "Ný mappa",
"Upload" : "Senda inn",
"File handling" : "Meðhöndlun skrár",
"Maximum upload size" : "Hámarks stærð innsendingar",
@@ -40,6 +39,6 @@
"Select all" : "Velja allt",
"Upload too large" : "Innsend skrá er of stór",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Skrárnar sem þú ert að senda inn eru stærri en hámarks innsendingarstærð á þessum netþjóni.",
- "Files are being scanned, please wait." : "Verið er að skima skrár, vinsamlegast hinkraðu."
+ "Text file" : "Texta skrá"
},"pluralForm" :"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);"
} \ No newline at end of file
diff --git a/apps/files/l10n/it.js b/apps/files/l10n/it.js
index 4c6033e6caf..57e78597c54 100644
--- a/apps/files/l10n/it.js
+++ b/apps/files/l10n/it.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Archiviazione non disponibile",
"Storage invalid" : "Archiviazione non valida",
"Unknown error" : "Errore sconosciuto",
- "Could not move %s - File with this name already exists" : "Impossibile spostare %s - un file con questo nome esiste già",
- "Could not move %s" : "Impossibile spostare %s",
- "Permission denied" : "Permesso negato",
- "The target folder has been moved or deleted." : "La cartella di destinazione è stata spostata o eliminata.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Il nome %s è attualmente in uso nella cartella %s. Scegli un nome diverso.",
- "Error when creating the file" : "Errore durante la creazione del file",
- "Error when creating the folder" : "Errore durante la creazione della cartella",
"Unable to set upload directory." : "Impossibile impostare una cartella di caricamento.",
"Invalid Token" : "Token non valido",
"No file was uploaded. Unknown error" : "Nessun file è stato caricato. Errore sconosciuto",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Manca una cartella temporanea",
"Failed to write to disk" : "Scrittura su disco non riuscita",
"Not enough storage available" : "Spazio di archiviazione insufficiente",
+ "The target folder has been moved or deleted." : "La cartella di destinazione è stata spostata o eliminata.",
"Upload failed. Could not find uploaded file" : "Caricamento non riuscito. Impossibile trovare il file caricato.",
"Upload failed. Could not get file info." : "Caricamento non riuscito. Impossibile ottenere informazioni sul file.",
"Invalid directory." : "Cartella non valida.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Scarica",
"Rename" : "Rinomina",
"Delete" : "Elimina",
+ "Disconnect storage" : "Disconnetti archiviazione",
+ "Unshare" : "Rimuovi condivisione",
"Details" : "Dettagli",
"Select" : "Seleziona",
"Pending" : "In corso",
"Unable to determine date" : "Impossibile determinare la data",
"This operation is forbidden" : "Questa operazione è vietata",
"This directory is unavailable, please check the logs or contact the administrator" : "Questa cartella non è disponibile, controlla i log o contatta l'amministratore",
- "Error moving file." : "Errore durante lo spostamento del file.",
- "Error moving file" : "Errore durante lo spostamento del file",
- "Error" : "Errore",
- "{new_name} already exists" : "{new_name} esiste già",
- "Could not rename file" : "Impossibile rinominare il file",
- "Could not create file" : "Impossibile creare il file",
- "Could not create folder" : "Impossibile creare la cartella",
- "Error deleting file." : "Errore durante l'eliminazione del file.",
+ "Could not move \"{file}\", target exists" : "Impossibile spostare \"{file}\", la destinazione esiste già",
+ "Could not move \"{file}\"" : "Impossibile spostare \"{file}\"",
+ "{newName} already exists" : "{newName} esiste già",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Impossibile rinominare \"{fileName}\", non esiste più",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Il nome \"{targetName}\" è attualmente in uso nella cartella \"{dir}\". Scegli un nome diverso.",
+ "Could not rename \"{fileName}\"" : "Impossibile rinominare \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Impossibile creare il file \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Impossibile creare il file \"{file}\" poiché esiste già",
+ "Could not create folder \"{dir}\"" : "Impossibile creare la cartella \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Impossibile creare la cartella \"{dir}\" poiché esiste già",
+ "Error deleting file \"{fileName}\"." : "Errore durante l'eliminazione del file \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Nessuna voce in questa cartella corrisponde a '{filter}'",
"Name" : "Nome",
"Size" : "Dimensione",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n byte"],
"Favorited" : "Preferiti",
"Favorite" : "Preferito",
- "Text file" : "File di testo",
- "New text file.txt" : "Nuovo file di testo.txt",
"Folder" : "Cartella",
"New folder" : "Nuova cartella",
"{newname} already exists" : "{newname} esiste già",
@@ -99,8 +96,6 @@ OC.L10N.register(
"Changed by %2$s" : "Modificata da %2$s",
"Deleted by %2$s" : "Eliminata da %2$s",
"Restored by %2$s" : "Ripristinata da %2$s",
- "%s could not be renamed as it has been deleted" : "%s non può essere rinominato poiché è stato eliminato",
- "%s could not be renamed" : "%s non può essere rinominato",
"Upload (max. %s)" : "Carica (massimo %s)",
"File handling" : "Gestione file",
"Maximum upload size" : "Dimensione massima caricamento",
@@ -118,9 +113,9 @@ OC.L10N.register(
"Select all" : "Seleziona tutto",
"Upload too large" : "Caricamento troppo grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "I file che stai provando a caricare superano la dimensione massima consentita su questo server.",
- "Files are being scanned, please wait." : "Scansione dei file in corso, attendi",
- "Currently scanning" : "Scansione in corso",
"No favorites" : "Nessun preferito",
- "Files and folders you mark as favorite will show up here" : "I file e le cartelle che marchi come preferiti saranno mostrati qui"
+ "Files and folders you mark as favorite will show up here" : "I file e le cartelle che marchi come preferiti saranno mostrati qui",
+ "Text file" : "File di testo",
+ "New text file.txt" : "Nuovo file di testo.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/it.json b/apps/files/l10n/it.json
index 239b8dc399c..cdd7366fcc5 100644
--- a/apps/files/l10n/it.json
+++ b/apps/files/l10n/it.json
@@ -2,13 +2,6 @@
"Storage not available" : "Archiviazione non disponibile",
"Storage invalid" : "Archiviazione non valida",
"Unknown error" : "Errore sconosciuto",
- "Could not move %s - File with this name already exists" : "Impossibile spostare %s - un file con questo nome esiste già",
- "Could not move %s" : "Impossibile spostare %s",
- "Permission denied" : "Permesso negato",
- "The target folder has been moved or deleted." : "La cartella di destinazione è stata spostata o eliminata.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Il nome %s è attualmente in uso nella cartella %s. Scegli un nome diverso.",
- "Error when creating the file" : "Errore durante la creazione del file",
- "Error when creating the folder" : "Errore durante la creazione della cartella",
"Unable to set upload directory." : "Impossibile impostare una cartella di caricamento.",
"Invalid Token" : "Token non valido",
"No file was uploaded. Unknown error" : "Nessun file è stato caricato. Errore sconosciuto",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Manca una cartella temporanea",
"Failed to write to disk" : "Scrittura su disco non riuscita",
"Not enough storage available" : "Spazio di archiviazione insufficiente",
+ "The target folder has been moved or deleted." : "La cartella di destinazione è stata spostata o eliminata.",
"Upload failed. Could not find uploaded file" : "Caricamento non riuscito. Impossibile trovare il file caricato.",
"Upload failed. Could not get file info." : "Caricamento non riuscito. Impossibile ottenere informazioni sul file.",
"Invalid directory." : "Cartella non valida.",
@@ -38,20 +32,25 @@
"Download" : "Scarica",
"Rename" : "Rinomina",
"Delete" : "Elimina",
+ "Disconnect storage" : "Disconnetti archiviazione",
+ "Unshare" : "Rimuovi condivisione",
"Details" : "Dettagli",
"Select" : "Seleziona",
"Pending" : "In corso",
"Unable to determine date" : "Impossibile determinare la data",
"This operation is forbidden" : "Questa operazione è vietata",
"This directory is unavailable, please check the logs or contact the administrator" : "Questa cartella non è disponibile, controlla i log o contatta l'amministratore",
- "Error moving file." : "Errore durante lo spostamento del file.",
- "Error moving file" : "Errore durante lo spostamento del file",
- "Error" : "Errore",
- "{new_name} already exists" : "{new_name} esiste già",
- "Could not rename file" : "Impossibile rinominare il file",
- "Could not create file" : "Impossibile creare il file",
- "Could not create folder" : "Impossibile creare la cartella",
- "Error deleting file." : "Errore durante l'eliminazione del file.",
+ "Could not move \"{file}\", target exists" : "Impossibile spostare \"{file}\", la destinazione esiste già",
+ "Could not move \"{file}\"" : "Impossibile spostare \"{file}\"",
+ "{newName} already exists" : "{newName} esiste già",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Impossibile rinominare \"{fileName}\", non esiste più",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Il nome \"{targetName}\" è attualmente in uso nella cartella \"{dir}\". Scegli un nome diverso.",
+ "Could not rename \"{fileName}\"" : "Impossibile rinominare \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Impossibile creare il file \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Impossibile creare il file \"{file}\" poiché esiste già",
+ "Could not create folder \"{dir}\"" : "Impossibile creare la cartella \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Impossibile creare la cartella \"{dir}\" poiché esiste già",
+ "Error deleting file \"{fileName}\"." : "Errore durante l'eliminazione del file \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Nessuna voce in questa cartella corrisponde a '{filter}'",
"Name" : "Nome",
"Size" : "Dimensione",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n byte"],
"Favorited" : "Preferiti",
"Favorite" : "Preferito",
- "Text file" : "File di testo",
- "New text file.txt" : "Nuovo file di testo.txt",
"Folder" : "Cartella",
"New folder" : "Nuova cartella",
"{newname} already exists" : "{newname} esiste già",
@@ -97,8 +94,6 @@
"Changed by %2$s" : "Modificata da %2$s",
"Deleted by %2$s" : "Eliminata da %2$s",
"Restored by %2$s" : "Ripristinata da %2$s",
- "%s could not be renamed as it has been deleted" : "%s non può essere rinominato poiché è stato eliminato",
- "%s could not be renamed" : "%s non può essere rinominato",
"Upload (max. %s)" : "Carica (massimo %s)",
"File handling" : "Gestione file",
"Maximum upload size" : "Dimensione massima caricamento",
@@ -116,9 +111,9 @@
"Select all" : "Seleziona tutto",
"Upload too large" : "Caricamento troppo grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "I file che stai provando a caricare superano la dimensione massima consentita su questo server.",
- "Files are being scanned, please wait." : "Scansione dei file in corso, attendi",
- "Currently scanning" : "Scansione in corso",
"No favorites" : "Nessun preferito",
- "Files and folders you mark as favorite will show up here" : "I file e le cartelle che marchi come preferiti saranno mostrati qui"
+ "Files and folders you mark as favorite will show up here" : "I file e le cartelle che marchi come preferiti saranno mostrati qui",
+ "Text file" : "File di testo",
+ "New text file.txt" : "Nuovo file di testo.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/ja.js b/apps/files/l10n/ja.js
index be441c15ca1..deb3a35b635 100644
--- a/apps/files/l10n/ja.js
+++ b/apps/files/l10n/ja.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "ストレージが利用できません",
"Storage invalid" : "ストレージが無効です",
"Unknown error" : "不明なエラー",
- "Could not move %s - File with this name already exists" : "%s を移動できませんでした ― この名前のファイルはすでに存在します",
- "Could not move %s" : "%s を移動できませんでした",
- "Permission denied" : "アクセス拒否",
- "The target folder has been moved or deleted." : "対象のフォルダーは移動されたか、削除されました。",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s はフォルダー %s ですでに使われています。別の名前を選択してください。",
- "Error when creating the file" : "ファイルの生成エラー",
- "Error when creating the folder" : "フォルダーの生成エラー",
"Unable to set upload directory." : "アップロードディレクトリを設定できません。",
"Invalid Token" : "無効なトークン",
"No file was uploaded. Unknown error" : "ファイルは何もアップロードされていません。不明なエラー",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "一時保存フォルダーが見つかりません",
"Failed to write to disk" : "ディスクへの書き込みに失敗しました",
"Not enough storage available" : "ストレージに十分な空き容量がありません",
+ "The target folder has been moved or deleted." : "対象のフォルダーは移動されたか、削除されました。",
"Upload failed. Could not find uploaded file" : "アップロードに失敗しました。アップロード済みのファイルを見つけることができませんでした。",
"Upload failed. Could not get file info." : "アップロードに失敗しました。ファイル情報を取得できませんでした。",
"Invalid directory." : "無効なディレクトリです。",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "ダウンロード",
"Rename" : "名前の変更",
"Delete" : "削除",
+ "Disconnect storage" : "ストレージを切断する",
+ "Unshare" : "共有解除",
"Details" : "詳細",
"Select" : "選択",
"Pending" : "中断",
"Unable to determine date" : "更新日不明",
"This operation is forbidden" : "この操作は禁止されています",
"This directory is unavailable, please check the logs or contact the administrator" : "このディレクトリは利用できません。ログを確認するか管理者に問い合わせてください。",
- "Error moving file." : "ファイル移動でエラー",
- "Error moving file" : "ファイルの移動エラー",
- "Error" : "エラー",
- "{new_name} already exists" : "{new_name} はすでに存在します",
- "Could not rename file" : "ファイルの名前変更ができませんでした",
- "Could not create file" : "ファイルを作成できませんでした",
- "Could not create folder" : "フォルダーを作成できませんでした",
- "Error deleting file." : "ファイルの削除エラー。",
+ "Could not move \"{file}\", target exists" : "ターゲットが存在するため,ファイル \"{file}\"を移動できませんでした",
+ "Could not move \"{file}\"" : "\"{file}\" を移動できませんでした",
+ "{newName} already exists" : "{newName} はすでに存在します",
+ "Could not rename \"{fileName}\", it does not exist any more" : "ファイルが存在しないため,\"{fileName}\"の名前変更ができませんでした",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "\"{targetName}\" はフォルダー \"{dir}\" ですでに使われています。別の名前を選択してください。",
+ "Could not rename \"{fileName}\"" : "\"{fileName}\"の名前変更ができませんでした",
+ "Could not create file \"{file}\"" : "ファイル \"{file}\" を作成できませんでした",
+ "Could not create file \"{file}\" because it already exists" : "ファイル \"{file}\"は既に存在するため作成できませんでした",
+ "Could not create folder \"{dir}\"" : "フォルダー \"{dir}\" を作成できませんでした",
+ "Could not create folder \"{dir}\" because it already exists" : "フォルダー \"{dir}\" は既に存在するため作成できませんでした",
+ "Error deleting file \"{fileName}\"." : "\"{fileName}\" でエラーを検出しました。",
"No entries in this folder match '{filter}'" : "このフォルダー内で '{filter}' にマッチするものはありません",
"Name" : "名前",
"Size" : "サイズ",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n バイト"],
"Favorited" : "お気に入り済",
"Favorite" : "お気に入り",
- "Text file" : "テキストファイル",
- "New text file.txt" : "新規のテキストファイル作成",
"Folder" : "フォルダー",
"New folder" : "新しいフォルダー",
"{newname} already exists" : "{newname} はすでに存在します",
@@ -99,8 +96,6 @@ OC.L10N.register(
"Changed by %2$s" : "%2$s により更新",
"Deleted by %2$s" : "%2$s により削除",
"Restored by %2$s" : "%2$s により復元",
- "%s could not be renamed as it has been deleted" : "%s は削除されたため、ファイル名を変更できません",
- "%s could not be renamed" : "%sの名前を変更できませんでした",
"Upload (max. %s)" : "アップロード ( 最大 %s )",
"File handling" : "ファイル操作",
"Maximum upload size" : "最大アップロードサイズ",
@@ -118,9 +113,9 @@ OC.L10N.register(
"Select all" : "すべて選択",
"Upload too large" : "アップロードには大きすぎます。",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "アップロードしようとしているファイルは、サーバーで規定された最大サイズを超えています。",
- "Files are being scanned, please wait." : "ファイルをスキャンしています、しばらくお待ちください。",
- "Currently scanning" : "現在スキャン中",
"No favorites" : "お気に入りなし",
- "Files and folders you mark as favorite will show up here" : "お気に入りに登録されたファイルやフォルダーは、ここに表示されます。"
+ "Files and folders you mark as favorite will show up here" : "お気に入りに登録されたファイルやフォルダーは、ここに表示されます。",
+ "Text file" : "テキストファイル",
+ "New text file.txt" : "新規のテキストファイル作成"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/ja.json b/apps/files/l10n/ja.json
index 58b4870369c..aa3c45dcaa3 100644
--- a/apps/files/l10n/ja.json
+++ b/apps/files/l10n/ja.json
@@ -2,13 +2,6 @@
"Storage not available" : "ストレージが利用できません",
"Storage invalid" : "ストレージが無効です",
"Unknown error" : "不明なエラー",
- "Could not move %s - File with this name already exists" : "%s を移動できませんでした ― この名前のファイルはすでに存在します",
- "Could not move %s" : "%s を移動できませんでした",
- "Permission denied" : "アクセス拒否",
- "The target folder has been moved or deleted." : "対象のフォルダーは移動されたか、削除されました。",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s はフォルダー %s ですでに使われています。別の名前を選択してください。",
- "Error when creating the file" : "ファイルの生成エラー",
- "Error when creating the folder" : "フォルダーの生成エラー",
"Unable to set upload directory." : "アップロードディレクトリを設定できません。",
"Invalid Token" : "無効なトークン",
"No file was uploaded. Unknown error" : "ファイルは何もアップロードされていません。不明なエラー",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "一時保存フォルダーが見つかりません",
"Failed to write to disk" : "ディスクへの書き込みに失敗しました",
"Not enough storage available" : "ストレージに十分な空き容量がありません",
+ "The target folder has been moved or deleted." : "対象のフォルダーは移動されたか、削除されました。",
"Upload failed. Could not find uploaded file" : "アップロードに失敗しました。アップロード済みのファイルを見つけることができませんでした。",
"Upload failed. Could not get file info." : "アップロードに失敗しました。ファイル情報を取得できませんでした。",
"Invalid directory." : "無効なディレクトリです。",
@@ -38,20 +32,25 @@
"Download" : "ダウンロード",
"Rename" : "名前の変更",
"Delete" : "削除",
+ "Disconnect storage" : "ストレージを切断する",
+ "Unshare" : "共有解除",
"Details" : "詳細",
"Select" : "選択",
"Pending" : "中断",
"Unable to determine date" : "更新日不明",
"This operation is forbidden" : "この操作は禁止されています",
"This directory is unavailable, please check the logs or contact the administrator" : "このディレクトリは利用できません。ログを確認するか管理者に問い合わせてください。",
- "Error moving file." : "ファイル移動でエラー",
- "Error moving file" : "ファイルの移動エラー",
- "Error" : "エラー",
- "{new_name} already exists" : "{new_name} はすでに存在します",
- "Could not rename file" : "ファイルの名前変更ができませんでした",
- "Could not create file" : "ファイルを作成できませんでした",
- "Could not create folder" : "フォルダーを作成できませんでした",
- "Error deleting file." : "ファイルの削除エラー。",
+ "Could not move \"{file}\", target exists" : "ターゲットが存在するため,ファイル \"{file}\"を移動できませんでした",
+ "Could not move \"{file}\"" : "\"{file}\" を移動できませんでした",
+ "{newName} already exists" : "{newName} はすでに存在します",
+ "Could not rename \"{fileName}\", it does not exist any more" : "ファイルが存在しないため,\"{fileName}\"の名前変更ができませんでした",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "\"{targetName}\" はフォルダー \"{dir}\" ですでに使われています。別の名前を選択してください。",
+ "Could not rename \"{fileName}\"" : "\"{fileName}\"の名前変更ができませんでした",
+ "Could not create file \"{file}\"" : "ファイル \"{file}\" を作成できませんでした",
+ "Could not create file \"{file}\" because it already exists" : "ファイル \"{file}\"は既に存在するため作成できませんでした",
+ "Could not create folder \"{dir}\"" : "フォルダー \"{dir}\" を作成できませんでした",
+ "Could not create folder \"{dir}\" because it already exists" : "フォルダー \"{dir}\" は既に存在するため作成できませんでした",
+ "Error deleting file \"{fileName}\"." : "\"{fileName}\" でエラーを検出しました。",
"No entries in this folder match '{filter}'" : "このフォルダー内で '{filter}' にマッチするものはありません",
"Name" : "名前",
"Size" : "サイズ",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n バイト"],
"Favorited" : "お気に入り済",
"Favorite" : "お気に入り",
- "Text file" : "テキストファイル",
- "New text file.txt" : "新規のテキストファイル作成",
"Folder" : "フォルダー",
"New folder" : "新しいフォルダー",
"{newname} already exists" : "{newname} はすでに存在します",
@@ -97,8 +94,6 @@
"Changed by %2$s" : "%2$s により更新",
"Deleted by %2$s" : "%2$s により削除",
"Restored by %2$s" : "%2$s により復元",
- "%s could not be renamed as it has been deleted" : "%s は削除されたため、ファイル名を変更できません",
- "%s could not be renamed" : "%sの名前を変更できませんでした",
"Upload (max. %s)" : "アップロード ( 最大 %s )",
"File handling" : "ファイル操作",
"Maximum upload size" : "最大アップロードサイズ",
@@ -116,9 +111,9 @@
"Select all" : "すべて選択",
"Upload too large" : "アップロードには大きすぎます。",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "アップロードしようとしているファイルは、サーバーで規定された最大サイズを超えています。",
- "Files are being scanned, please wait." : "ファイルをスキャンしています、しばらくお待ちください。",
- "Currently scanning" : "現在スキャン中",
"No favorites" : "お気に入りなし",
- "Files and folders you mark as favorite will show up here" : "お気に入りに登録されたファイルやフォルダーは、ここに表示されます。"
+ "Files and folders you mark as favorite will show up here" : "お気に入りに登録されたファイルやフォルダーは、ここに表示されます。",
+ "Text file" : "テキストファイル",
+ "New text file.txt" : "新規のテキストファイル作成"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/ka_GE.js b/apps/files/l10n/ka_GE.js
index fe22f22ceb3..c54da5a206d 100644
--- a/apps/files/l10n/ka_GE.js
+++ b/apps/files/l10n/ka_GE.js
@@ -2,8 +2,6 @@ OC.L10N.register(
"files",
{
"Unknown error" : "უცნობი შეცდომა",
- "Could not move %s - File with this name already exists" : "%s –ის გადატანა ვერ მოხერხდა – ფაილი ამ სახელით უკვე არსებობს",
- "Could not move %s" : "%s –ის გადატანა ვერ მოხერხდა",
"No file was uploaded. Unknown error" : "ფაილი არ აიტვირთა. უცნობი შეცდომა",
"There is no error, the file uploaded with success" : "ჭოცდომა არ დაფიქსირდა, ფაილი წარმატებით აიტვირთა",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "ატვირთული ფაილი აჭარბებს upload_max_filesize დირექტივას php.ini ფაილში",
@@ -24,10 +22,9 @@ OC.L10N.register(
"Download" : "ჩამოტვირთვა",
"Rename" : "გადარქმევა",
"Delete" : "წაშლა",
+ "Unshare" : "გაუზიარებადი",
"Details" : "დეტალური ინფორმაცია",
"Pending" : "მოცდის რეჟიმში",
- "Error" : "შეცდომა",
- "{new_name} already exists" : "{new_name} უკვე არსებობს",
"Name" : "სახელი",
"Size" : "ზომა",
"Modified" : "შეცვლილია",
@@ -36,7 +33,6 @@ OC.L10N.register(
"Your storage is full, files can not be updated or synced anymore!" : "თქვენი საცავი გადაივსო. ფაილების განახლება და სინქრონიზირება ვერ მოხერხდება!",
"Your storage is almost full ({usedSpacePercent}%)" : "თქვენი საცავი თითქმის გადაივსო ({usedSpacePercent}%)",
"Favorite" : "ფავორიტი",
- "Text file" : "ტექსტური ფაილი",
"Folder" : "საქაღალდე",
"New folder" : "ახალი ფოლდერი",
"Upload" : "ატვირთვა",
@@ -49,6 +45,6 @@ OC.L10N.register(
"Cancel upload" : "ატვირთვის გაუქმება",
"Upload too large" : "ასატვირთი ფაილი ძალიან დიდია",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "ფაილის ზომა რომლის ატვირთვასაც თქვენ აპირებთ, აჭარბებს სერვერზე დაშვებულ მაქსიმუმს.",
- "Files are being scanned, please wait." : "მიმდინარეობს ფაილების სკანირება, გთხოვთ დაელოდოთ."
+ "Text file" : "ტექსტური ფაილი"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/ka_GE.json b/apps/files/l10n/ka_GE.json
index 8f23f671b7e..cdc9cd03126 100644
--- a/apps/files/l10n/ka_GE.json
+++ b/apps/files/l10n/ka_GE.json
@@ -1,7 +1,5 @@
{ "translations": {
"Unknown error" : "უცნობი შეცდომა",
- "Could not move %s - File with this name already exists" : "%s –ის გადატანა ვერ მოხერხდა – ფაილი ამ სახელით უკვე არსებობს",
- "Could not move %s" : "%s –ის გადატანა ვერ მოხერხდა",
"No file was uploaded. Unknown error" : "ფაილი არ აიტვირთა. უცნობი შეცდომა",
"There is no error, the file uploaded with success" : "ჭოცდომა არ დაფიქსირდა, ფაილი წარმატებით აიტვირთა",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " : "ატვირთული ფაილი აჭარბებს upload_max_filesize დირექტივას php.ini ფაილში",
@@ -22,10 +20,9 @@
"Download" : "ჩამოტვირთვა",
"Rename" : "გადარქმევა",
"Delete" : "წაშლა",
+ "Unshare" : "გაუზიარებადი",
"Details" : "დეტალური ინფორმაცია",
"Pending" : "მოცდის რეჟიმში",
- "Error" : "შეცდომა",
- "{new_name} already exists" : "{new_name} უკვე არსებობს",
"Name" : "სახელი",
"Size" : "ზომა",
"Modified" : "შეცვლილია",
@@ -34,7 +31,6 @@
"Your storage is full, files can not be updated or synced anymore!" : "თქვენი საცავი გადაივსო. ფაილების განახლება და სინქრონიზირება ვერ მოხერხდება!",
"Your storage is almost full ({usedSpacePercent}%)" : "თქვენი საცავი თითქმის გადაივსო ({usedSpacePercent}%)",
"Favorite" : "ფავორიტი",
- "Text file" : "ტექსტური ფაილი",
"Folder" : "საქაღალდე",
"New folder" : "ახალი ფოლდერი",
"Upload" : "ატვირთვა",
@@ -47,6 +43,6 @@
"Cancel upload" : "ატვირთვის გაუქმება",
"Upload too large" : "ასატვირთი ფაილი ძალიან დიდია",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "ფაილის ზომა რომლის ატვირთვასაც თქვენ აპირებთ, აჭარბებს სერვერზე დაშვებულ მაქსიმუმს.",
- "Files are being scanned, please wait." : "მიმდინარეობს ფაილების სკანირება, გთხოვთ დაელოდოთ."
+ "Text file" : "ტექსტური ფაილი"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/km.js b/apps/files/l10n/km.js
index b63a3a90ef0..55080926fc3 100644
--- a/apps/files/l10n/km.js
+++ b/apps/files/l10n/km.js
@@ -2,8 +2,6 @@ OC.L10N.register(
"files",
{
"Unknown error" : "មិន​ស្គាល់​កំហុស",
- "Could not move %s - File with this name already exists" : "មិន​អាច​ផ្លាស់​ទី %s - មាន​ឈ្មោះ​ឯកសារ​ដូច​នេះ​ហើយ",
- "Could not move %s" : "មិន​អាច​ផ្លាស់ទី %s",
"No file was uploaded. Unknown error" : "មិន​មាន​ឯកសារ​ដែល​បាន​ផ្ទុក​ឡើង។ មិន​ស្គាល់​កំហុស",
"There is no error, the file uploaded with success" : "មិន​មាន​កំហុស​អ្វី​ទេ ហើយ​ឯកសារ​ត្រូវ​បាន​ផ្ទុកឡើង​ដោយ​ជោគជ័យ",
"Files" : "ឯកសារ",
@@ -12,16 +10,14 @@ OC.L10N.register(
"Download" : "ទាញយក",
"Rename" : "ប្ដូរ​ឈ្មោះ",
"Delete" : "លុប",
+ "Unshare" : "លែង​ចែក​រំលែក",
"Details" : "ព័ត៌មាន​លម្អិត",
"Pending" : "កំពុង​រង់ចាំ",
- "Error" : "កំហុស",
- "{new_name} already exists" : "មាន​ឈ្មោះ {new_name} រួច​ហើយ",
"Name" : "ឈ្មោះ",
"Size" : "ទំហំ",
"Modified" : "បាន​កែ​ប្រែ",
"New" : "ថ្មី",
"File name cannot be empty." : "ឈ្មោះ​ឯកសារ​មិន​អាច​នៅ​ទទេ​បាន​ឡើយ។",
- "Text file" : "ឯកសារ​អក្សរ",
"Folder" : "ថត",
"New folder" : "ថត​ថ្មី",
"Upload" : "ផ្ទុក​ឡើង",
@@ -36,6 +32,7 @@ OC.L10N.register(
"Settings" : "ការកំណត់",
"WebDAV" : "WebDAV",
"Cancel upload" : "បោះបង់​ការ​ផ្ទុកឡើង",
- "Upload too large" : "ផ្ទុក​ឡើង​ធំ​ពេក"
+ "Upload too large" : "ផ្ទុក​ឡើង​ធំ​ពេក",
+ "Text file" : "ឯកសារ​អក្សរ"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/km.json b/apps/files/l10n/km.json
index 8dda2ab2cb1..c1e9159ee88 100644
--- a/apps/files/l10n/km.json
+++ b/apps/files/l10n/km.json
@@ -1,7 +1,5 @@
{ "translations": {
"Unknown error" : "មិន​ស្គាល់​កំហុស",
- "Could not move %s - File with this name already exists" : "មិន​អាច​ផ្លាស់​ទី %s - មាន​ឈ្មោះ​ឯកសារ​ដូច​នេះ​ហើយ",
- "Could not move %s" : "មិន​អាច​ផ្លាស់ទី %s",
"No file was uploaded. Unknown error" : "មិន​មាន​ឯកសារ​ដែល​បាន​ផ្ទុក​ឡើង។ មិន​ស្គាល់​កំហុស",
"There is no error, the file uploaded with success" : "មិន​មាន​កំហុស​អ្វី​ទេ ហើយ​ឯកសារ​ត្រូវ​បាន​ផ្ទុកឡើង​ដោយ​ជោគជ័យ",
"Files" : "ឯកសារ",
@@ -10,16 +8,14 @@
"Download" : "ទាញយក",
"Rename" : "ប្ដូរ​ឈ្មោះ",
"Delete" : "លុប",
+ "Unshare" : "លែង​ចែក​រំលែក",
"Details" : "ព័ត៌មាន​លម្អិត",
"Pending" : "កំពុង​រង់ចាំ",
- "Error" : "កំហុស",
- "{new_name} already exists" : "មាន​ឈ្មោះ {new_name} រួច​ហើយ",
"Name" : "ឈ្មោះ",
"Size" : "ទំហំ",
"Modified" : "បាន​កែ​ប្រែ",
"New" : "ថ្មី",
"File name cannot be empty." : "ឈ្មោះ​ឯកសារ​មិន​អាច​នៅ​ទទេ​បាន​ឡើយ។",
- "Text file" : "ឯកសារ​អក្សរ",
"Folder" : "ថត",
"New folder" : "ថត​ថ្មី",
"Upload" : "ផ្ទុក​ឡើង",
@@ -34,6 +30,7 @@
"Settings" : "ការកំណត់",
"WebDAV" : "WebDAV",
"Cancel upload" : "បោះបង់​ការ​ផ្ទុកឡើង",
- "Upload too large" : "ផ្ទុក​ឡើង​ធំ​ពេក"
+ "Upload too large" : "ផ្ទុក​ឡើង​ធំ​ពេក",
+ "Text file" : "ឯកសារ​អក្សរ"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/kn.js b/apps/files/l10n/kn.js
index b1c793b1ef3..1e97d7ffa79 100644
--- a/apps/files/l10n/kn.js
+++ b/apps/files/l10n/kn.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "ಲಭ್ಯವಿಲ್ಲ ಸಂಗ್ರಹ",
"Storage invalid" : "ಸಂಗ್ರಹ ಅಮಾನ್ಯವಾಗಿದೆ",
"Unknown error" : "ಗೊತ್ತಿಲ್ಲದ ದೋಷ",
- "Could not move %s - File with this name already exists" : "%s ಹೆಸರು ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ - ಸ್ಥಳ ಬದಲಾವಣೆ ಸಾಧ್ಯವಿಲ್ಲ",
- "Could not move %s" : "%s ಸ್ಥಳ ಬದಲಾವಣೆ ಸಾಧ್ಯವಿಲ್ಲ",
- "Permission denied" : "ಅನುಮತಿ ನಿರಾಕರಿಸಲಾಗಿದೆ",
- "The target folder has been moved or deleted." : "ಕೋಶದ ಉದ್ದೇಶಿತ ಸ್ಥಳ ಬದಲಾವಣೆ ಮಾಡಲಾಗಿದೆ ಅಥವಾ ಅಳಿಸಲಾಗಿದೆ.",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s ಹೆಸರಿನ ಕೋಶವನ್ನು %s ಈಗಾಗಲೇ ಬಳಸಲಾಗುತ್ತದೆ. ಬೇರೆ ಹೆಸರನ್ನು ಆಯ್ಕೆಮಾಡಿ.",
- "Error when creating the file" : "ಕಡತವನ್ನು ರಚಿಸುವಾಗ ದೋಷವಾಗಿದೆ",
- "Error when creating the folder" : "ಕೊಶವನ್ನು ರಚಿಸುವಾಗ ದೋಷವಾಗಿದೆ",
"Unable to set upload directory." : "ಪೇರಿಸವ ಕೋಶವನ್ನು ಹೊಂದಿಸಲಾಗಲಿಲ್ಲ.",
"Invalid Token" : "ಅಮಾನ್ಯ ಸಾಂಕೇತಿಕ",
"No file was uploaded. Unknown error" : "ಕಡತ ವರ್ಗಾವಣೆ ಅಜ್ಞಾತ ದೋಷದಿಂದ ವಿಪುಲವಾಗಿದೆ",
@@ -20,6 +13,7 @@ OC.L10N.register(
"Missing a temporary folder" : "ತಾತ್ಕಾಲಿಕ ಕಡತಕೋಶ ದೊರೆಕುತ್ತಿಲ್ಲ",
"Failed to write to disk" : "ಸ್ಮರಣೆ ಸಾಧನಕ್ಕೇಬರೆಯಲು ವಿಫಲವಾಗಿದೆ",
"Not enough storage available" : "ಲಭ್ಯವಿರುವ ಸಂಗ್ರಹ ಸಾಕಾಗುವುದಿಲ್ಲ",
+ "The target folder has been moved or deleted." : "ಕೋಶದ ಉದ್ದೇಶಿತ ಸ್ಥಳ ಬದಲಾವಣೆ ಮಾಡಲಾಗಿದೆ ಅಥವಾ ಅಳಿಸಲಾಗಿದೆ.",
"Invalid directory." : "ಅಮಾನ್ಯ ಕಡತಕೋಶ.",
"Files" : "ಕಡತಗಳು",
"All files" : "ಎಲ್ಲಾ ಕಡತಗಳು",
@@ -31,17 +25,11 @@ OC.L10N.register(
"Download" : "ಪ್ರತಿಯನ್ನು ಸ್ಥಳೀಯವಾಗಿ ಉಳಿಸಿಕೊಳ್ಳಿ",
"Rename" : "ಮರುಹೆಸರಿಸು",
"Delete" : "ಅಳಿಸಿ",
+ "Disconnect storage" : "ಸಂಗ್ರಹ ಸಾಧನವನ್ನು ತೆಗೆದುಹಾಕಿ",
+ "Unshare" : "ಹಂಚಿಕೆಯನ್ನು ಹಿಂತೆಗೆ",
"Select" : "ಆಯ್ಕೆ ಮಾಡಿ",
"Pending" : "ಬಾಕಿ ಇದೆ",
"Unable to determine date" : "ಮುಕ್ತಾಯ ದಿನಾಂಕ ನಿರ್ಧರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
- "Error moving file." : "ಕಡತದ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸುವಾಗ ದೋಷವಾಗಿದೆ.",
- "Error moving file" : "ಕಡತದ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸುವಾಗ ದೋಷವಾಗಿದೆ",
- "Error" : "ತಪ್ಪಾಗಿದೆ",
- "{new_name} already exists" : "ಈಗಾಗಲೇ {new_name} ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ",
- "Could not rename file" : "ಕಡತ ಮರುಹೆಸರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ",
- "Could not create file" : "ಕಡತ ರಚಿಸಲಾಗಲಿಲ್ಲ",
- "Could not create folder" : "ಕೋಶವನ್ನು ರಚಿಸಲಾಗಿಲ್ಲ",
- "Error deleting file." : "ಕಡತವನ್ನು ಅಳಿಸುವಲ್ಲಿ ಲೋಪವಾದೆ",
"Name" : "ಹೆಸರು",
"Size" : " ಪ್ರಮಾಣ",
"Modified" : "ಬದಲಾಯಿಸಿದ",
@@ -53,7 +41,6 @@ OC.L10N.register(
"File name cannot be empty." : "ಕಡತ ಹೆಸರು ಖಾಲಿ ಇರುವಂತಿಲ್ಲ.",
"Favorited" : "ಅಚ್ಚುಮೆಚ್ಚಿನವು",
"Favorite" : "ಅಚ್ಚುಮೆಚ್ಚಿನ",
- "Text file" : "ಸರಳಾಕ್ಷರದ ಕಡತ",
"Folder" : "ಕಡತಕೋಶ",
"New folder" : "ಹೊಸ ಕಡತಕೋಶ",
"Upload" : "ವರ್ಗಾಯಿಸಿ",
@@ -68,9 +55,8 @@ OC.L10N.register(
"Select all" : "ಎಲ್ಲಾ ಆಯ್ಕೆ ಮಾಡಿ",
"Upload too large" : "ದೊಡ್ಡ ಪ್ರಮಾಣದ ಪ್ರತಿಗಳನ್ನು ವರ್ಗಾವಣೆ ಮಾಡಲು ಸಾದ್ಯವಿಲ್ಲ",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "ನೀವು ವರ್ಗಾಯಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರುವ ಕಡತಗಳ ಗಾತ್ರ, ಈ ಗಣಕ ಕೋಶದ ಗರಿಷ್ಠ ಕಡತ ಮೀತಿಯಾನ್ನು ಮೀರುವಂತಿಲ್ಲ.",
- "Files are being scanned, please wait." : "ಕಡತಗಳನ್ನು ಪರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ, ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ.",
- "Currently scanning" : "ಪ್ರಸ್ತುತ ಪರೀಕ್ಷೆ",
"No favorites" : "ಯಾವ ಅಚ್ಚುಮೆಚ್ಚಿನವುಗಳು ಇಲ್ಲ",
- "Files and folders you mark as favorite will show up here" : "ನೀವು ಗುರುತು ಮಾಡಿರುವ ನೆಚ್ಚಿನ ಕಡತ ಮತ್ತು ಕಡತಕೋಶಗಳನ್ನು ಇಲ್ಲಿ ತೋರಿಸಲಾಗುತ್ತಿದೆ"
+ "Files and folders you mark as favorite will show up here" : "ನೀವು ಗುರುತು ಮಾಡಿರುವ ನೆಚ್ಚಿನ ಕಡತ ಮತ್ತು ಕಡತಕೋಶಗಳನ್ನು ಇಲ್ಲಿ ತೋರಿಸಲಾಗುತ್ತಿದೆ",
+ "Text file" : "ಸರಳಾಕ್ಷರದ ಕಡತ"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/kn.json b/apps/files/l10n/kn.json
index 6667f3ae01f..9ebd3cb619b 100644
--- a/apps/files/l10n/kn.json
+++ b/apps/files/l10n/kn.json
@@ -2,13 +2,6 @@
"Storage not available" : "ಲಭ್ಯವಿಲ್ಲ ಸಂಗ್ರಹ",
"Storage invalid" : "ಸಂಗ್ರಹ ಅಮಾನ್ಯವಾಗಿದೆ",
"Unknown error" : "ಗೊತ್ತಿಲ್ಲದ ದೋಷ",
- "Could not move %s - File with this name already exists" : "%s ಹೆಸರು ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ - ಸ್ಥಳ ಬದಲಾವಣೆ ಸಾಧ್ಯವಿಲ್ಲ",
- "Could not move %s" : "%s ಸ್ಥಳ ಬದಲಾವಣೆ ಸಾಧ್ಯವಿಲ್ಲ",
- "Permission denied" : "ಅನುಮತಿ ನಿರಾಕರಿಸಲಾಗಿದೆ",
- "The target folder has been moved or deleted." : "ಕೋಶದ ಉದ್ದೇಶಿತ ಸ್ಥಳ ಬದಲಾವಣೆ ಮಾಡಲಾಗಿದೆ ಅಥವಾ ಅಳಿಸಲಾಗಿದೆ.",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s ಹೆಸರಿನ ಕೋಶವನ್ನು %s ಈಗಾಗಲೇ ಬಳಸಲಾಗುತ್ತದೆ. ಬೇರೆ ಹೆಸರನ್ನು ಆಯ್ಕೆಮಾಡಿ.",
- "Error when creating the file" : "ಕಡತವನ್ನು ರಚಿಸುವಾಗ ದೋಷವಾಗಿದೆ",
- "Error when creating the folder" : "ಕೊಶವನ್ನು ರಚಿಸುವಾಗ ದೋಷವಾಗಿದೆ",
"Unable to set upload directory." : "ಪೇರಿಸವ ಕೋಶವನ್ನು ಹೊಂದಿಸಲಾಗಲಿಲ್ಲ.",
"Invalid Token" : "ಅಮಾನ್ಯ ಸಾಂಕೇತಿಕ",
"No file was uploaded. Unknown error" : "ಕಡತ ವರ್ಗಾವಣೆ ಅಜ್ಞಾತ ದೋಷದಿಂದ ವಿಪುಲವಾಗಿದೆ",
@@ -18,6 +11,7 @@
"Missing a temporary folder" : "ತಾತ್ಕಾಲಿಕ ಕಡತಕೋಶ ದೊರೆಕುತ್ತಿಲ್ಲ",
"Failed to write to disk" : "ಸ್ಮರಣೆ ಸಾಧನಕ್ಕೇಬರೆಯಲು ವಿಫಲವಾಗಿದೆ",
"Not enough storage available" : "ಲಭ್ಯವಿರುವ ಸಂಗ್ರಹ ಸಾಕಾಗುವುದಿಲ್ಲ",
+ "The target folder has been moved or deleted." : "ಕೋಶದ ಉದ್ದೇಶಿತ ಸ್ಥಳ ಬದಲಾವಣೆ ಮಾಡಲಾಗಿದೆ ಅಥವಾ ಅಳಿಸಲಾಗಿದೆ.",
"Invalid directory." : "ಅಮಾನ್ಯ ಕಡತಕೋಶ.",
"Files" : "ಕಡತಗಳು",
"All files" : "ಎಲ್ಲಾ ಕಡತಗಳು",
@@ -29,17 +23,11 @@
"Download" : "ಪ್ರತಿಯನ್ನು ಸ್ಥಳೀಯವಾಗಿ ಉಳಿಸಿಕೊಳ್ಳಿ",
"Rename" : "ಮರುಹೆಸರಿಸು",
"Delete" : "ಅಳಿಸಿ",
+ "Disconnect storage" : "ಸಂಗ್ರಹ ಸಾಧನವನ್ನು ತೆಗೆದುಹಾಕಿ",
+ "Unshare" : "ಹಂಚಿಕೆಯನ್ನು ಹಿಂತೆಗೆ",
"Select" : "ಆಯ್ಕೆ ಮಾಡಿ",
"Pending" : "ಬಾಕಿ ಇದೆ",
"Unable to determine date" : "ಮುಕ್ತಾಯ ದಿನಾಂಕ ನಿರ್ಧರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
- "Error moving file." : "ಕಡತದ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸುವಾಗ ದೋಷವಾಗಿದೆ.",
- "Error moving file" : "ಕಡತದ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸುವಾಗ ದೋಷವಾಗಿದೆ",
- "Error" : "ತಪ್ಪಾಗಿದೆ",
- "{new_name} already exists" : "ಈಗಾಗಲೇ {new_name} ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ",
- "Could not rename file" : "ಕಡತ ಮರುಹೆಸರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ",
- "Could not create file" : "ಕಡತ ರಚಿಸಲಾಗಲಿಲ್ಲ",
- "Could not create folder" : "ಕೋಶವನ್ನು ರಚಿಸಲಾಗಿಲ್ಲ",
- "Error deleting file." : "ಕಡತವನ್ನು ಅಳಿಸುವಲ್ಲಿ ಲೋಪವಾದೆ",
"Name" : "ಹೆಸರು",
"Size" : " ಪ್ರಮಾಣ",
"Modified" : "ಬದಲಾಯಿಸಿದ",
@@ -51,7 +39,6 @@
"File name cannot be empty." : "ಕಡತ ಹೆಸರು ಖಾಲಿ ಇರುವಂತಿಲ್ಲ.",
"Favorited" : "ಅಚ್ಚುಮೆಚ್ಚಿನವು",
"Favorite" : "ಅಚ್ಚುಮೆಚ್ಚಿನ",
- "Text file" : "ಸರಳಾಕ್ಷರದ ಕಡತ",
"Folder" : "ಕಡತಕೋಶ",
"New folder" : "ಹೊಸ ಕಡತಕೋಶ",
"Upload" : "ವರ್ಗಾಯಿಸಿ",
@@ -66,9 +53,8 @@
"Select all" : "ಎಲ್ಲಾ ಆಯ್ಕೆ ಮಾಡಿ",
"Upload too large" : "ದೊಡ್ಡ ಪ್ರಮಾಣದ ಪ್ರತಿಗಳನ್ನು ವರ್ಗಾವಣೆ ಮಾಡಲು ಸಾದ್ಯವಿಲ್ಲ",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "ನೀವು ವರ್ಗಾಯಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರುವ ಕಡತಗಳ ಗಾತ್ರ, ಈ ಗಣಕ ಕೋಶದ ಗರಿಷ್ಠ ಕಡತ ಮೀತಿಯಾನ್ನು ಮೀರುವಂತಿಲ್ಲ.",
- "Files are being scanned, please wait." : "ಕಡತಗಳನ್ನು ಪರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ, ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ.",
- "Currently scanning" : "ಪ್ರಸ್ತುತ ಪರೀಕ್ಷೆ",
"No favorites" : "ಯಾವ ಅಚ್ಚುಮೆಚ್ಚಿನವುಗಳು ಇಲ್ಲ",
- "Files and folders you mark as favorite will show up here" : "ನೀವು ಗುರುತು ಮಾಡಿರುವ ನೆಚ್ಚಿನ ಕಡತ ಮತ್ತು ಕಡತಕೋಶಗಳನ್ನು ಇಲ್ಲಿ ತೋರಿಸಲಾಗುತ್ತಿದೆ"
+ "Files and folders you mark as favorite will show up here" : "ನೀವು ಗುರುತು ಮಾಡಿರುವ ನೆಚ್ಚಿನ ಕಡತ ಮತ್ತು ಕಡತಕೋಶಗಳನ್ನು ಇಲ್ಲಿ ತೋರಿಸಲಾಗುತ್ತಿದೆ",
+ "Text file" : "ಸರಳಾಕ್ಷರದ ಕಡತ"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/ko.js b/apps/files/l10n/ko.js
index 70ee488454a..3bac96b5eb8 100644
--- a/apps/files/l10n/ko.js
+++ b/apps/files/l10n/ko.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "저장소를 사용할 수 없음",
"Storage invalid" : "저장소가 잘못됨",
"Unknown error" : "알 수 없는 오류",
- "Could not move %s - File with this name already exists" : "항목 %s을(를) 이동시킬 수 없음 - 같은 이름의 파일이 이미 존재함",
- "Could not move %s" : "항목 %s을(를) 이동시킬 수 없음",
- "Permission denied" : "권한 거부됨",
- "The target folder has been moved or deleted." : "대상 폴더가 이동되거나 삭제되었습니다.",
- "The name %s is already used in the folder %s. Please choose a different name." : "이름 %s이(가) 폴더 %s에서 이미 사용 중입니다. 다른 이름을 사용하십시오.",
- "Error when creating the file" : "파일 생성 중 오류 발생",
- "Error when creating the folder" : "폴더 생성 중 오류 발생",
"Unable to set upload directory." : "업로드 디렉터리를 설정할 수 없습니다.",
"Invalid Token" : "잘못된 토큰",
"No file was uploaded. Unknown error" : "파일이 업로드 되지 않았습니다. 알 수 없는 오류입니다",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "임시 폴더가 없음",
"Failed to write to disk" : "디스크에 쓰지 못했습니다",
"Not enough storage available" : "저장소가 용량이 충분하지 않습니다.",
+ "The target folder has been moved or deleted." : "대상 폴더가 이동되거나 삭제되었습니다.",
"Upload failed. Could not find uploaded file" : "업로드에 실패했습니다. 업로드할 파일을 찾을 수 없습니다",
"Upload failed. Could not get file info." : "업로드에 실패했습니다. 파일 정보를 가져올 수 없습니다.",
"Invalid directory." : "올바르지 않은 디렉터리입니다.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "다운로드",
"Rename" : "이름 바꾸기",
"Delete" : "삭제",
+ "Disconnect storage" : "저장소 연결 해제",
+ "Unshare" : "공유 해제",
"Details" : "자세한 정보",
"Select" : "선택",
"Pending" : "대기 중",
"Unable to determine date" : "날짜를 결정할 수 없음",
"This operation is forbidden" : "이 작업이 금지됨",
"This directory is unavailable, please check the logs or contact the administrator" : "디렉터리를 사용할 수 없습니다. 로그를 확인하거나 관리자에게 연락하십시오",
- "Error moving file." : "파일 이동 오류.",
- "Error moving file" : "파일 이동 오류",
- "Error" : "오류",
- "{new_name} already exists" : "{new_name}이(가) 이미 존재함",
- "Could not rename file" : "이름을 변경할 수 없음",
- "Could not create file" : "파일을 만들 수 없음",
- "Could not create folder" : "폴더를 만들 수 없음",
- "Error deleting file." : "파일 삭제 오류.",
"No entries in this folder match '{filter}'" : "이 폴더에 '{filter}'와(과) 일치하는 항목 없음",
"Name" : "이름",
"Size" : "크기",
@@ -75,8 +63,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n바이트"],
"Favorited" : "책갈피에 추가됨",
"Favorite" : "즐겨찾기",
- "Text file" : "텍스트 파일",
- "New text file.txt" : "새 텍스트 파일.txt",
"Folder" : "폴더",
"New folder" : "새 폴더",
"{newname} already exists" : "{newname} 항목이 이미 존재함",
@@ -99,8 +85,6 @@ OC.L10N.register(
"Changed by %2$s" : "%2$s 님이 변경함",
"Deleted by %2$s" : "%2$s 님이 삭제함",
"Restored by %2$s" : "%2$s 님이 복원함",
- "%s could not be renamed as it has been deleted" : "%s이(가) 삭제되었기 때문에 이름을 변경할 수 없습니다",
- "%s could not be renamed" : "%s의 이름을 변경할 수 없습니다",
"Upload (max. %s)" : "업로드(최대 %s)",
"File handling" : "파일 처리",
"Maximum upload size" : "최대 업로드 크기",
@@ -116,9 +100,9 @@ OC.L10N.register(
"Select all" : "모두 선택",
"Upload too large" : "업로드한 파일이 너무 큼",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "이 파일이 서버에서 허용하는 최대 업로드 가능 용량보다 큽니다.",
- "Files are being scanned, please wait." : "파일을 검색하고 있습니다. 기다려 주십시오.",
- "Currently scanning" : "현재 검사 중",
"No favorites" : "책갈피 없음",
- "Files and folders you mark as favorite will show up here" : "책갈피에 추가한 파일과 폴더가 여기에 나타납니다"
+ "Files and folders you mark as favorite will show up here" : "책갈피에 추가한 파일과 폴더가 여기에 나타납니다",
+ "Text file" : "텍스트 파일",
+ "New text file.txt" : "새 텍스트 파일.txt"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/ko.json b/apps/files/l10n/ko.json
index 65e61d8ec49..e42745fc8b4 100644
--- a/apps/files/l10n/ko.json
+++ b/apps/files/l10n/ko.json
@@ -2,13 +2,6 @@
"Storage not available" : "저장소를 사용할 수 없음",
"Storage invalid" : "저장소가 잘못됨",
"Unknown error" : "알 수 없는 오류",
- "Could not move %s - File with this name already exists" : "항목 %s을(를) 이동시킬 수 없음 - 같은 이름의 파일이 이미 존재함",
- "Could not move %s" : "항목 %s을(를) 이동시킬 수 없음",
- "Permission denied" : "권한 거부됨",
- "The target folder has been moved or deleted." : "대상 폴더가 이동되거나 삭제되었습니다.",
- "The name %s is already used in the folder %s. Please choose a different name." : "이름 %s이(가) 폴더 %s에서 이미 사용 중입니다. 다른 이름을 사용하십시오.",
- "Error when creating the file" : "파일 생성 중 오류 발생",
- "Error when creating the folder" : "폴더 생성 중 오류 발생",
"Unable to set upload directory." : "업로드 디렉터리를 설정할 수 없습니다.",
"Invalid Token" : "잘못된 토큰",
"No file was uploaded. Unknown error" : "파일이 업로드 되지 않았습니다. 알 수 없는 오류입니다",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "임시 폴더가 없음",
"Failed to write to disk" : "디스크에 쓰지 못했습니다",
"Not enough storage available" : "저장소가 용량이 충분하지 않습니다.",
+ "The target folder has been moved or deleted." : "대상 폴더가 이동되거나 삭제되었습니다.",
"Upload failed. Could not find uploaded file" : "업로드에 실패했습니다. 업로드할 파일을 찾을 수 없습니다",
"Upload failed. Could not get file info." : "업로드에 실패했습니다. 파일 정보를 가져올 수 없습니다.",
"Invalid directory." : "올바르지 않은 디렉터리입니다.",
@@ -38,20 +32,14 @@
"Download" : "다운로드",
"Rename" : "이름 바꾸기",
"Delete" : "삭제",
+ "Disconnect storage" : "저장소 연결 해제",
+ "Unshare" : "공유 해제",
"Details" : "자세한 정보",
"Select" : "선택",
"Pending" : "대기 중",
"Unable to determine date" : "날짜를 결정할 수 없음",
"This operation is forbidden" : "이 작업이 금지됨",
"This directory is unavailable, please check the logs or contact the administrator" : "디렉터리를 사용할 수 없습니다. 로그를 확인하거나 관리자에게 연락하십시오",
- "Error moving file." : "파일 이동 오류.",
- "Error moving file" : "파일 이동 오류",
- "Error" : "오류",
- "{new_name} already exists" : "{new_name}이(가) 이미 존재함",
- "Could not rename file" : "이름을 변경할 수 없음",
- "Could not create file" : "파일을 만들 수 없음",
- "Could not create folder" : "폴더를 만들 수 없음",
- "Error deleting file." : "파일 삭제 오류.",
"No entries in this folder match '{filter}'" : "이 폴더에 '{filter}'와(과) 일치하는 항목 없음",
"Name" : "이름",
"Size" : "크기",
@@ -73,8 +61,6 @@
"_%n byte_::_%n bytes_" : ["%n바이트"],
"Favorited" : "책갈피에 추가됨",
"Favorite" : "즐겨찾기",
- "Text file" : "텍스트 파일",
- "New text file.txt" : "새 텍스트 파일.txt",
"Folder" : "폴더",
"New folder" : "새 폴더",
"{newname} already exists" : "{newname} 항목이 이미 존재함",
@@ -97,8 +83,6 @@
"Changed by %2$s" : "%2$s 님이 변경함",
"Deleted by %2$s" : "%2$s 님이 삭제함",
"Restored by %2$s" : "%2$s 님이 복원함",
- "%s could not be renamed as it has been deleted" : "%s이(가) 삭제되었기 때문에 이름을 변경할 수 없습니다",
- "%s could not be renamed" : "%s의 이름을 변경할 수 없습니다",
"Upload (max. %s)" : "업로드(최대 %s)",
"File handling" : "파일 처리",
"Maximum upload size" : "최대 업로드 크기",
@@ -114,9 +98,9 @@
"Select all" : "모두 선택",
"Upload too large" : "업로드한 파일이 너무 큼",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "이 파일이 서버에서 허용하는 최대 업로드 가능 용량보다 큽니다.",
- "Files are being scanned, please wait." : "파일을 검색하고 있습니다. 기다려 주십시오.",
- "Currently scanning" : "현재 검사 중",
"No favorites" : "책갈피 없음",
- "Files and folders you mark as favorite will show up here" : "책갈피에 추가한 파일과 폴더가 여기에 나타납니다"
+ "Files and folders you mark as favorite will show up here" : "책갈피에 추가한 파일과 폴더가 여기에 나타납니다",
+ "Text file" : "텍스트 파일",
+ "New text file.txt" : "새 텍스트 파일.txt"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/ku_IQ.js b/apps/files/l10n/ku_IQ.js
index 7a995636ec9..1ceca50b705 100644
--- a/apps/files/l10n/ku_IQ.js
+++ b/apps/files/l10n/ku_IQ.js
@@ -6,7 +6,6 @@ OC.L10N.register(
"Close" : "دابخه",
"Download" : "داگرتن",
"Select" : "دیاریکردنی",
- "Error" : "هه‌ڵه",
"Name" : "ناو",
"Folder" : "بوخچه",
"Upload" : "بارکردن",
diff --git a/apps/files/l10n/ku_IQ.json b/apps/files/l10n/ku_IQ.json
index f39269efd39..e934b5eb29b 100644
--- a/apps/files/l10n/ku_IQ.json
+++ b/apps/files/l10n/ku_IQ.json
@@ -4,7 +4,6 @@
"Close" : "دابخه",
"Download" : "داگرتن",
"Select" : "دیاریکردنی",
- "Error" : "هه‌ڵه",
"Name" : "ناو",
"Folder" : "بوخچه",
"Upload" : "بارکردن",
diff --git a/apps/files/l10n/lb.js b/apps/files/l10n/lb.js
index 97cb28477f1..c6ee76819ec 100644
--- a/apps/files/l10n/lb.js
+++ b/apps/files/l10n/lb.js
@@ -17,14 +17,13 @@ OC.L10N.register(
"Download" : "Download",
"Rename" : "Ëmbenennen",
"Delete" : "Läschen",
+ "Unshare" : "Net méi deelen",
"Details" : "Detailer",
"Select" : "Auswielen",
- "Error" : "Fehler",
"Name" : "Numm",
"Size" : "Gréisst",
"Modified" : "Geännert",
"New" : "Nei",
- "Text file" : "Text Fichier",
"Folder" : "Dossier",
"New folder" : "Neien Dossier",
"Upload" : "Eroplueden",
@@ -38,6 +37,6 @@ OC.L10N.register(
"Select all" : "All auswielen",
"Upload too large" : "Upload ze grouss",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Déi Dateien déi Dir probéiert erop ze lueden sinn méi grouss wei déi Maximal Gréisst déi op dësem Server erlaabt ass.",
- "Files are being scanned, please wait." : "Fichieren gi gescannt, war weg."
+ "Text file" : "Text Fichier"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/lb.json b/apps/files/l10n/lb.json
index c3dae7b0b88..59289599719 100644
--- a/apps/files/l10n/lb.json
+++ b/apps/files/l10n/lb.json
@@ -15,14 +15,13 @@
"Download" : "Download",
"Rename" : "Ëmbenennen",
"Delete" : "Läschen",
+ "Unshare" : "Net méi deelen",
"Details" : "Detailer",
"Select" : "Auswielen",
- "Error" : "Fehler",
"Name" : "Numm",
"Size" : "Gréisst",
"Modified" : "Geännert",
"New" : "Nei",
- "Text file" : "Text Fichier",
"Folder" : "Dossier",
"New folder" : "Neien Dossier",
"Upload" : "Eroplueden",
@@ -36,6 +35,6 @@
"Select all" : "All auswielen",
"Upload too large" : "Upload ze grouss",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Déi Dateien déi Dir probéiert erop ze lueden sinn méi grouss wei déi Maximal Gréisst déi op dësem Server erlaabt ass.",
- "Files are being scanned, please wait." : "Fichieren gi gescannt, war weg."
+ "Text file" : "Text Fichier"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/lo.js b/apps/files/l10n/lo.js
index 2f3b6e43d61..2d01379b83d 100644
--- a/apps/files/l10n/lo.js
+++ b/apps/files/l10n/lo.js
@@ -4,9 +4,6 @@ OC.L10N.register(
"Storage not available" : "ບໍ່ມີພື້ນທີ່ເກັບຂໍ້ມູນ",
"Storage invalid" : "ພື້ນທີ່ເກັບຂໍ້ມູນບໍ່ຖືກຕ້ອງ",
"Unknown error" : "ຂໍ້ຜິດພາດທີ່ບໍ່ຮູ້ສາເຫດ",
- "Could not move %s - File with this name already exists" : "ບໍ່ສາມາດຍ້າຍໄຟລ໌ %s ນີ້ໄດ້ - ຊື່ໄຟລ໌ນີ້ຖືກນຳໃຊ້ແລ້ວ",
- "Could not move %s" : "ບໍ່ສາມາດຍ້າຍ %s ໄດ້",
- "Permission denied" : "ບໍ່ທີສິດໃນການເຂົ້າເຖິງ",
"The target folder has been moved or deleted." : "ໂຟນເດີທີ່ທ່ານເລືອກໄດ້ຖືກຍ້າຍ ຫຼື ລຶບອອກແລ້ວ"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/lo.json b/apps/files/l10n/lo.json
index c7bfdc31dbb..12eea86a936 100644
--- a/apps/files/l10n/lo.json
+++ b/apps/files/l10n/lo.json
@@ -2,9 +2,6 @@
"Storage not available" : "ບໍ່ມີພື້ນທີ່ເກັບຂໍ້ມູນ",
"Storage invalid" : "ພື້ນທີ່ເກັບຂໍ້ມູນບໍ່ຖືກຕ້ອງ",
"Unknown error" : "ຂໍ້ຜິດພາດທີ່ບໍ່ຮູ້ສາເຫດ",
- "Could not move %s - File with this name already exists" : "ບໍ່ສາມາດຍ້າຍໄຟລ໌ %s ນີ້ໄດ້ - ຊື່ໄຟລ໌ນີ້ຖືກນຳໃຊ້ແລ້ວ",
- "Could not move %s" : "ບໍ່ສາມາດຍ້າຍ %s ໄດ້",
- "Permission denied" : "ບໍ່ທີສິດໃນການເຂົ້າເຖິງ",
"The target folder has been moved or deleted." : "ໂຟນເດີທີ່ທ່ານເລືອກໄດ້ຖືກຍ້າຍ ຫຼື ລຶບອອກແລ້ວ"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/lt_LT.js b/apps/files/l10n/lt_LT.js
index ac7084cfc2d..6e33b1ac7cc 100644
--- a/apps/files/l10n/lt_LT.js
+++ b/apps/files/l10n/lt_LT.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Saugykla nepasiekiama",
"Storage invalid" : "Saugykla neteisinga",
"Unknown error" : "Neatpažinta klaida",
- "Could not move %s - File with this name already exists" : "Nepavyko perkelti %s - failas su tokiu pavadinimu jau egzistuoja",
- "Could not move %s" : "Nepavyko perkelti %s",
- "Permission denied" : "Neturite teisių",
- "The target folder has been moved or deleted." : "Tikslo aplankas buvo perkeltas ar ištrintas.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Pavadinimas %s jau naudojamas aplanke %s. Prašome pasirinkti kitokį pavadinimą.",
- "Error when creating the file" : "Klaida kuriant failą",
- "Error when creating the folder" : "Klaida kuriant aplanką",
"Unable to set upload directory." : "Nepavyksta nustatyti įkėlimų katalogo.",
"Invalid Token" : "Netinkamas ženklas",
"No file was uploaded. Unknown error" : "Failai nebuvo įkelti dėl nežinomos priežasties",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Nėra laikinojo katalogo",
"Failed to write to disk" : "Nepavyko įrašyti į diską",
"Not enough storage available" : "Nepakanka vietos serveryje",
+ "The target folder has been moved or deleted." : "Tikslo aplankas buvo perkeltas ar ištrintas.",
"Upload failed. Could not find uploaded file" : "Įkėlimas nepavyko. Nepavyko rasti įkelto failo",
"Upload failed. Could not get file info." : "Įkėlimas nepavyko. Nepavyko gauti failo informacijos.",
"Invalid directory." : "Neteisingas aplankas",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Atsisiųsti",
"Rename" : "Pervadinti",
"Delete" : "Ištrinti",
+ "Disconnect storage" : "Atjungti saugyklą",
+ "Unshare" : "Nebesidalinti",
"Details" : "Informacija",
"Select" : "Pasirinkiti",
"Pending" : "Laukiantis",
"Unable to determine date" : "Nepavyksta nustatyti datos",
"This operation is forbidden" : "Ši operacija yra uždrausta",
"This directory is unavailable, please check the logs or contact the administrator" : "Katalogas nepasiekiamas, prašome peržiūrėti žurnalo įrašus arba susisiekti su administratoriumi",
- "Error moving file." : "Klaida perkeliant failą.",
- "Error moving file" : "Klaida perkeliant failą",
- "Error" : "Klaida",
- "{new_name} already exists" : "{new_name} jau egzistuoja",
- "Could not rename file" : "Neįmanoma pervadinti failo",
- "Could not create file" : "Neįmanoma sukurti failo",
- "Could not create folder" : "Neįmanoma sukurti aplanko",
- "Error deleting file." : "Klaida trinant failą.",
+ "Could not move \"{file}\", target exists" : "Nepavyko perkelti \"{file}\", toks jau egzistuoja",
+ "Could not move \"{file}\"" : "Nepavyko perkelti \"{file}\"",
+ "{newName} already exists" : "{newName} jau egzistuoja",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Nepavyko pervadinti failo \"{fileName}\", nes jis jau nebeegzistuoja",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Pavadinimas \"{targetName}\" jau naudojamas aplanke \"{dir}\". Prašome pasirinkti kitokį pavadinimą.",
+ "Could not rename \"{fileName}\"" : "Nepavyko pervadinti failo \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Nepavyko sukurti failo \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Nepavyko sukurti failo \"{file}\" - failas su tokiu pavadinimu jau egzistuoja",
+ "Could not create folder \"{dir}\"" : "Nepavyko sukurti aplanko \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Nepavyko sukurti aplanko \"{dir}\"- aplankas su tokiu pavadinimu jau egzistuoja",
+ "Error deleting file \"{fileName}\"." : "Klaida trinant failą \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Nėra įrašų šiame aplanko atitikmeniui „{filter}“",
"Name" : "Pavadinimas",
"Size" : "Dydis",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n baitas","%n baitai","%n baitų"],
"Favorited" : "Pažymėta mėgstamu",
"Favorite" : "Mėgiamas",
- "Text file" : "Teksto failas",
- "New text file.txt" : "Naujas tekstas file.txt",
"Folder" : "Katalogas",
"New folder" : "Naujas aplankas",
"{newname} already exists" : "{newname} jau egzistuoja",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "Pakeitė %2$s",
"Deleted by %2$s" : "Ištrynė %2$s",
"Restored by %2$s" : "Atkūrė %2$s",
- "%s could not be renamed as it has been deleted" : "%s negalėjo būti pervadintas, nes buvo ištrintas",
- "%s could not be renamed" : "%s negali būti pervadintas",
"Upload (max. %s)" : "Įkelti (maks. %s)",
"File handling" : "Failų tvarkymas",
"Maximum upload size" : "Maksimalus įkeliamo failo dydis",
"max. possible: " : "maks. galima:",
"Save" : "Išsaugoti",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Su PHP-FPM atnaujinimai gali užtrukti apie 5min.",
+ "Missing permissions to edit from here." : "Draudžiama iš čia redaguoti",
"Settings" : "Nustatymai",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Naudokite šį adresą, kad <a href=\"%s\" target=\"_blank\">pasiektumėte savo failus per WebDAV</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "Pažymėti viską",
"Upload too large" : "Įkėlimui failas per didelis",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Bandomų įkelti failų dydis viršija maksimalų, kuris leidžiamas šiame serveryje",
- "Files are being scanned, please wait." : "Skenuojami failai, prašome palaukti.",
- "Currently scanning" : "Šiuo metu skenuojama",
"No favorites" : "Nėra mėgstamiausių",
- "Files and folders you mark as favorite will show up here" : "Failai ir aplankai, kuriuos pažymite mėgstamais, atsiras čia"
+ "Files and folders you mark as favorite will show up here" : "Failai ir aplankai, kuriuos pažymite mėgstamais, atsiras čia",
+ "Text file" : "Teksto failas",
+ "New text file.txt" : "Naujas tekstas file.txt"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files/l10n/lt_LT.json b/apps/files/l10n/lt_LT.json
index aef54469542..0d32d1dbb2a 100644
--- a/apps/files/l10n/lt_LT.json
+++ b/apps/files/l10n/lt_LT.json
@@ -2,13 +2,6 @@
"Storage not available" : "Saugykla nepasiekiama",
"Storage invalid" : "Saugykla neteisinga",
"Unknown error" : "Neatpažinta klaida",
- "Could not move %s - File with this name already exists" : "Nepavyko perkelti %s - failas su tokiu pavadinimu jau egzistuoja",
- "Could not move %s" : "Nepavyko perkelti %s",
- "Permission denied" : "Neturite teisių",
- "The target folder has been moved or deleted." : "Tikslo aplankas buvo perkeltas ar ištrintas.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Pavadinimas %s jau naudojamas aplanke %s. Prašome pasirinkti kitokį pavadinimą.",
- "Error when creating the file" : "Klaida kuriant failą",
- "Error when creating the folder" : "Klaida kuriant aplanką",
"Unable to set upload directory." : "Nepavyksta nustatyti įkėlimų katalogo.",
"Invalid Token" : "Netinkamas ženklas",
"No file was uploaded. Unknown error" : "Failai nebuvo įkelti dėl nežinomos priežasties",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Nėra laikinojo katalogo",
"Failed to write to disk" : "Nepavyko įrašyti į diską",
"Not enough storage available" : "Nepakanka vietos serveryje",
+ "The target folder has been moved or deleted." : "Tikslo aplankas buvo perkeltas ar ištrintas.",
"Upload failed. Could not find uploaded file" : "Įkėlimas nepavyko. Nepavyko rasti įkelto failo",
"Upload failed. Could not get file info." : "Įkėlimas nepavyko. Nepavyko gauti failo informacijos.",
"Invalid directory." : "Neteisingas aplankas",
@@ -38,20 +32,25 @@
"Download" : "Atsisiųsti",
"Rename" : "Pervadinti",
"Delete" : "Ištrinti",
+ "Disconnect storage" : "Atjungti saugyklą",
+ "Unshare" : "Nebesidalinti",
"Details" : "Informacija",
"Select" : "Pasirinkiti",
"Pending" : "Laukiantis",
"Unable to determine date" : "Nepavyksta nustatyti datos",
"This operation is forbidden" : "Ši operacija yra uždrausta",
"This directory is unavailable, please check the logs or contact the administrator" : "Katalogas nepasiekiamas, prašome peržiūrėti žurnalo įrašus arba susisiekti su administratoriumi",
- "Error moving file." : "Klaida perkeliant failą.",
- "Error moving file" : "Klaida perkeliant failą",
- "Error" : "Klaida",
- "{new_name} already exists" : "{new_name} jau egzistuoja",
- "Could not rename file" : "Neįmanoma pervadinti failo",
- "Could not create file" : "Neįmanoma sukurti failo",
- "Could not create folder" : "Neįmanoma sukurti aplanko",
- "Error deleting file." : "Klaida trinant failą.",
+ "Could not move \"{file}\", target exists" : "Nepavyko perkelti \"{file}\", toks jau egzistuoja",
+ "Could not move \"{file}\"" : "Nepavyko perkelti \"{file}\"",
+ "{newName} already exists" : "{newName} jau egzistuoja",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Nepavyko pervadinti failo \"{fileName}\", nes jis jau nebeegzistuoja",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Pavadinimas \"{targetName}\" jau naudojamas aplanke \"{dir}\". Prašome pasirinkti kitokį pavadinimą.",
+ "Could not rename \"{fileName}\"" : "Nepavyko pervadinti failo \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Nepavyko sukurti failo \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Nepavyko sukurti failo \"{file}\" - failas su tokiu pavadinimu jau egzistuoja",
+ "Could not create folder \"{dir}\"" : "Nepavyko sukurti aplanko \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Nepavyko sukurti aplanko \"{dir}\"- aplankas su tokiu pavadinimu jau egzistuoja",
+ "Error deleting file \"{fileName}\"." : "Klaida trinant failą \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Nėra įrašų šiame aplanko atitikmeniui „{filter}“",
"Name" : "Pavadinimas",
"Size" : "Dydis",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n baitas","%n baitai","%n baitų"],
"Favorited" : "Pažymėta mėgstamu",
"Favorite" : "Mėgiamas",
- "Text file" : "Teksto failas",
- "New text file.txt" : "Naujas tekstas file.txt",
"Folder" : "Katalogas",
"New folder" : "Naujas aplankas",
"{newname} already exists" : "{newname} jau egzistuoja",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "Pakeitė %2$s",
"Deleted by %2$s" : "Ištrynė %2$s",
"Restored by %2$s" : "Atkūrė %2$s",
- "%s could not be renamed as it has been deleted" : "%s negalėjo būti pervadintas, nes buvo ištrintas",
- "%s could not be renamed" : "%s negali būti pervadintas",
"Upload (max. %s)" : "Įkelti (maks. %s)",
"File handling" : "Failų tvarkymas",
"Maximum upload size" : "Maksimalus įkeliamo failo dydis",
"max. possible: " : "maks. galima:",
"Save" : "Išsaugoti",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Su PHP-FPM atnaujinimai gali užtrukti apie 5min.",
+ "Missing permissions to edit from here." : "Draudžiama iš čia redaguoti",
"Settings" : "Nustatymai",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Naudokite šį adresą, kad <a href=\"%s\" target=\"_blank\">pasiektumėte savo failus per WebDAV</a>",
@@ -114,9 +111,9 @@
"Select all" : "Pažymėti viską",
"Upload too large" : "Įkėlimui failas per didelis",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Bandomų įkelti failų dydis viršija maksimalų, kuris leidžiamas šiame serveryje",
- "Files are being scanned, please wait." : "Skenuojami failai, prašome palaukti.",
- "Currently scanning" : "Šiuo metu skenuojama",
"No favorites" : "Nėra mėgstamiausių",
- "Files and folders you mark as favorite will show up here" : "Failai ir aplankai, kuriuos pažymite mėgstamais, atsiras čia"
+ "Files and folders you mark as favorite will show up here" : "Failai ir aplankai, kuriuos pažymite mėgstamais, atsiras čia",
+ "Text file" : "Teksto failas",
+ "New text file.txt" : "Naujas tekstas file.txt"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files/l10n/lv.js b/apps/files/l10n/lv.js
index ad18fe93244..f5533fd8995 100644
--- a/apps/files/l10n/lv.js
+++ b/apps/files/l10n/lv.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Glabātuve nav pieejama",
"Storage invalid" : "Nepareiza krātuve",
"Unknown error" : "Nezināma kļūda",
- "Could not move %s - File with this name already exists" : "Nevarēja pārvietot %s — jau eksistē datne ar tādu nosaukumu",
- "Could not move %s" : "Nevarēja pārvietot %s",
- "Permission denied" : "Pieeja liegta",
- "The target folder has been moved or deleted." : "Mērķa mape ir pārvietota vai dzēsta",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nosaukums '%s' jau tiek izmantots mapē '%s'. Lūdzu izvēlieties citu nosaukumu.",
- "Error when creating the file" : "Kļūda veidojot datni",
- "Error when creating the folder" : "Kļūda, veidojot mapi",
"Unable to set upload directory." : "Nevar uzstādīt augšupielādes mapi.",
"Invalid Token" : "Nepareiza pilnvara",
"No file was uploaded. Unknown error" : "Netika augšupielādēta neviena datne. Nezināma kļūda",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Trūkst pagaidu mapes",
"Failed to write to disk" : "Neizdevās saglabāt diskā",
"Not enough storage available" : "Nav pietiekami daudz vietas",
+ "The target folder has been moved or deleted." : "Mērķa mape ir pārvietota vai dzēsta",
"Upload failed. Could not find uploaded file" : "Augšupielāde nesekmīga. Neizdevās atrast augšupielādēto failu.",
"Upload failed. Could not get file info." : "Augšupielāde nesekmīga. Neizdevās iegūt informāciju par failu.",
"Invalid directory." : "Nederīga direktorija.",
@@ -40,18 +34,12 @@ OC.L10N.register(
"Download" : "Lejupielādēt",
"Rename" : "Pārsaukt",
"Delete" : "Dzēst",
+ "Disconnect storage" : "Atvienot krātuvi",
+ "Unshare" : "Pārtraukt dalīšanos",
"Details" : "Detaļas",
"Select" : "Norādīt",
"Pending" : "Gaida savu kārtu",
"Unable to determine date" : "Neizdevās noteikt datumu",
- "Error moving file." : "Kļūda, pārvietojot datni.",
- "Error moving file" : "Kļūda, pārvietojot datni",
- "Error" : "Kļūda",
- "{new_name} already exists" : "{new_name} jau eksistē",
- "Could not rename file" : "Neizdevās pārsaukt datni",
- "Could not create file" : "Neizdevās izveidot datni",
- "Could not create folder" : "Neizdevās izveidot mapi",
- "Error deleting file." : "Kļūda, dzēšot datni.",
"No entries in this folder match '{filter}'" : "Šajā mapē nekas nav atrasts, meklējot pēc '{filter}'",
"Name" : "Nosaukums",
"Size" : "Izmērs",
@@ -69,7 +57,6 @@ OC.L10N.register(
"_matches '{filter}'_::_match '{filter}'_" : ["atrasts pēc '{filter}'","atrasts pēc '{filter}'","atrasti pēc '{filter}'"],
"Favorited" : "Favorīti",
"Favorite" : "Iecienītais",
- "Text file" : "Teksta datne",
"Folder" : "Mape",
"New folder" : "Jauna mape",
"Upload" : "Augšupielādēt",
@@ -87,8 +74,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s izdzēsa %1$s",
"You restored %1$s" : "Tu atjaunoji %1$s",
"%2$s restored %1$s" : "%2$s atjaunoja %1$s",
- "%s could not be renamed as it has been deleted" : "Nevarēja pārsaukt %s, jo tas ir dzēsts",
- "%s could not be renamed" : "%s nevar tikt pārsaukts",
"Upload (max. %s)" : "Augšupielādēt (maks. %s)",
"File handling" : "Datņu pārvaldība",
"Maximum upload size" : "Maksimālais datņu augšupielādes apjoms",
@@ -103,9 +88,8 @@ OC.L10N.register(
"Select all" : "Atzīmēt visu",
"Upload too large" : "Datne ir par lielu, lai to augšupielādētu",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Augšupielādējamās datnes pārsniedz servera pieļaujamo datņu augšupielādes apjomu",
- "Files are being scanned, please wait." : "Datnes šobrīd tiek caurskatītas, lūdzu, uzgaidiet.",
- "Currently scanning" : "Pašlaik skenē",
"No favorites" : "Nav favorītu",
- "Files and folders you mark as favorite will show up here" : "Faili un mapes, ko atzīmēsit kā favorītus, tiks rādīti šeit"
+ "Files and folders you mark as favorite will show up here" : "Faili un mapes, ko atzīmēsit kā favorītus, tiks rādīti šeit",
+ "Text file" : "Teksta datne"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);");
diff --git a/apps/files/l10n/lv.json b/apps/files/l10n/lv.json
index 16ac9adf08d..18189049ed8 100644
--- a/apps/files/l10n/lv.json
+++ b/apps/files/l10n/lv.json
@@ -2,13 +2,6 @@
"Storage not available" : "Glabātuve nav pieejama",
"Storage invalid" : "Nepareiza krātuve",
"Unknown error" : "Nezināma kļūda",
- "Could not move %s - File with this name already exists" : "Nevarēja pārvietot %s — jau eksistē datne ar tādu nosaukumu",
- "Could not move %s" : "Nevarēja pārvietot %s",
- "Permission denied" : "Pieeja liegta",
- "The target folder has been moved or deleted." : "Mērķa mape ir pārvietota vai dzēsta",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nosaukums '%s' jau tiek izmantots mapē '%s'. Lūdzu izvēlieties citu nosaukumu.",
- "Error when creating the file" : "Kļūda veidojot datni",
- "Error when creating the folder" : "Kļūda, veidojot mapi",
"Unable to set upload directory." : "Nevar uzstādīt augšupielādes mapi.",
"Invalid Token" : "Nepareiza pilnvara",
"No file was uploaded. Unknown error" : "Netika augšupielādēta neviena datne. Nezināma kļūda",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Trūkst pagaidu mapes",
"Failed to write to disk" : "Neizdevās saglabāt diskā",
"Not enough storage available" : "Nav pietiekami daudz vietas",
+ "The target folder has been moved or deleted." : "Mērķa mape ir pārvietota vai dzēsta",
"Upload failed. Could not find uploaded file" : "Augšupielāde nesekmīga. Neizdevās atrast augšupielādēto failu.",
"Upload failed. Could not get file info." : "Augšupielāde nesekmīga. Neizdevās iegūt informāciju par failu.",
"Invalid directory." : "Nederīga direktorija.",
@@ -38,18 +32,12 @@
"Download" : "Lejupielādēt",
"Rename" : "Pārsaukt",
"Delete" : "Dzēst",
+ "Disconnect storage" : "Atvienot krātuvi",
+ "Unshare" : "Pārtraukt dalīšanos",
"Details" : "Detaļas",
"Select" : "Norādīt",
"Pending" : "Gaida savu kārtu",
"Unable to determine date" : "Neizdevās noteikt datumu",
- "Error moving file." : "Kļūda, pārvietojot datni.",
- "Error moving file" : "Kļūda, pārvietojot datni",
- "Error" : "Kļūda",
- "{new_name} already exists" : "{new_name} jau eksistē",
- "Could not rename file" : "Neizdevās pārsaukt datni",
- "Could not create file" : "Neizdevās izveidot datni",
- "Could not create folder" : "Neizdevās izveidot mapi",
- "Error deleting file." : "Kļūda, dzēšot datni.",
"No entries in this folder match '{filter}'" : "Šajā mapē nekas nav atrasts, meklējot pēc '{filter}'",
"Name" : "Nosaukums",
"Size" : "Izmērs",
@@ -67,7 +55,6 @@
"_matches '{filter}'_::_match '{filter}'_" : ["atrasts pēc '{filter}'","atrasts pēc '{filter}'","atrasti pēc '{filter}'"],
"Favorited" : "Favorīti",
"Favorite" : "Iecienītais",
- "Text file" : "Teksta datne",
"Folder" : "Mape",
"New folder" : "Jauna mape",
"Upload" : "Augšupielādēt",
@@ -85,8 +72,6 @@
"%2$s deleted %1$s" : "%2$s izdzēsa %1$s",
"You restored %1$s" : "Tu atjaunoji %1$s",
"%2$s restored %1$s" : "%2$s atjaunoja %1$s",
- "%s could not be renamed as it has been deleted" : "Nevarēja pārsaukt %s, jo tas ir dzēsts",
- "%s could not be renamed" : "%s nevar tikt pārsaukts",
"Upload (max. %s)" : "Augšupielādēt (maks. %s)",
"File handling" : "Datņu pārvaldība",
"Maximum upload size" : "Maksimālais datņu augšupielādes apjoms",
@@ -101,9 +86,8 @@
"Select all" : "Atzīmēt visu",
"Upload too large" : "Datne ir par lielu, lai to augšupielādētu",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Augšupielādējamās datnes pārsniedz servera pieļaujamo datņu augšupielādes apjomu",
- "Files are being scanned, please wait." : "Datnes šobrīd tiek caurskatītas, lūdzu, uzgaidiet.",
- "Currently scanning" : "Pašlaik skenē",
"No favorites" : "Nav favorītu",
- "Files and folders you mark as favorite will show up here" : "Faili un mapes, ko atzīmēsit kā favorītus, tiks rādīti šeit"
+ "Files and folders you mark as favorite will show up here" : "Faili un mapes, ko atzīmēsit kā favorītus, tiks rādīti šeit",
+ "Text file" : "Teksta datne"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files/l10n/mk.js b/apps/files/l10n/mk.js
index a87cdcdc371..ec8387af0f6 100644
--- a/apps/files/l10n/mk.js
+++ b/apps/files/l10n/mk.js
@@ -1,11 +1,9 @@
OC.L10N.register(
"files",
{
+ "Storage not available" : "Сториџот не е достапен",
+ "Storage invalid" : "Сториџот не е валиден",
"Unknown error" : "Непозната грешка",
- "Could not move %s - File with this name already exists" : "Не можам да го преместам %s - Датотека со такво име веќе постои",
- "Could not move %s" : "Не можам да ги префрлам %s",
- "Error when creating the file" : "Грешка при креирање на датотека",
- "Error when creating the folder" : "Грешка при креирање на папка",
"Unable to set upload directory." : "Не може да се постави папката за префрлање на податоци.",
"Invalid Token" : "Грешен токен",
"No file was uploaded. Unknown error" : "Ниту еден фајл не се вчита. Непозната грешка",
@@ -20,6 +18,7 @@ OC.L10N.register(
"Upload failed. Could not find uploaded file" : "Префрлањето е неуспешно. Не можам да го најдам префрлената датотека.",
"Invalid directory." : "Погрешна папка.",
"Files" : "Датотеки",
+ "All files" : "Сите датотеки",
"Favorites" : "Омилени",
"Home" : "Дома",
"Close" : "Затвори",
@@ -30,15 +29,11 @@ OC.L10N.register(
"Download" : "Преземи",
"Rename" : "Преименувај",
"Delete" : "Избриши",
+ "Unshare" : "Не споделувај",
"Details" : "Детали:",
"Select" : "Избери",
"Pending" : "Чека",
- "Error moving file" : "Грешка при префрлање на датотека",
- "Error" : "Грешка",
- "{new_name} already exists" : "{new_name} веќе постои",
- "Could not rename file" : "Не можам да ја преименувам датотеката",
- "Could not create file" : "Не множам да креирам датотека",
- "Could not create folder" : "Не можам да креирам папка",
+ "This operation is forbidden" : "Операцијата не е дозволена",
"Name" : "Име",
"Size" : "Големина",
"Modified" : "Променето",
@@ -47,27 +42,39 @@ OC.L10N.register(
"File name cannot be empty." : "Името на датотеката не може да биде празно.",
"Your storage is full, files can not be updated or synced anymore!" : "Вашиот сториџ е полн, датотеките веќе не можат да се освежуваат или синхронизираат!",
"Your storage is almost full ({usedSpacePercent}%)" : "Вашиот сториџ е скоро полн ({usedSpacePercent}%)",
- "Text file" : "Текстуална датотека",
+ "Path" : "Патека",
+ "Favorited" : "Омилени",
+ "Favorite" : "Омилен",
"Folder" : "Папка",
"New folder" : "Нова папка",
+ "{newname} already exists" : "{newname} веќе постои",
"Upload" : "Подигни",
+ "An error occurred while trying to update the tags" : "Се случи грешка додека се обидувавте да ги освежите таговите",
"You created %1$s" : "Вие креиравте %1$s",
"%2$s created %1$s" : "%2$s креирано %1$s",
"You changed %1$s" : "Вие изменивте %1$s",
"%2$s changed %1$s" : "%2$s променето %1$s",
"You deleted %1$s" : "Вие избришавте %1$s",
"%2$s deleted %1$s" : "%2$s избришани %1$s",
- "%s could not be renamed" : "%s не може да биде преименуван",
+ "Changed by %2$s" : "Променето од %2$s",
+ "Deleted by %2$s" : "Избришано од %2$s",
+ "Restored by %2$s" : "Повратено од %2$s",
"Upload (max. %s)" : "Префрлање (макс. %s)",
"File handling" : "Ракување со датотеки",
"Maximum upload size" : "Максимална големина за подигање",
"max. possible: " : "макс. можно:",
"Save" : "Сними",
+ "Missing permissions to edit from here." : "Недостасуваат пермисии за да уредувате од тука",
"Settings" : "Подесувања",
"WebDAV" : "WebDAV",
"Cancel upload" : "Откажи прикачување",
+ "No files in here" : "Тука нема датотеки",
+ "No entries found in this folder" : "Нема ништо во оваа папка",
+ "Select all" : "Избери се",
"Upload too large" : "Фајлот кој се вчитува е преголем",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Датотеките кои се обидувате да ги подигнете ја надминуваат максималната големина за подигнување датотеки на овој сервер.",
- "Files are being scanned, please wait." : "Се скенираат датотеки, ве молам почекајте."
+ "Files and folders you mark as favorite will show up here" : "Датотеките и папките кои ќе ги означите како чести, ќе се појават тука",
+ "Text file" : "Текстуална датотека",
+ "New text file.txt" : "Нова текстуална датотека file.txt"
},
"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;");
diff --git a/apps/files/l10n/mk.json b/apps/files/l10n/mk.json
index 49e2fce36d7..e587f4883ef 100644
--- a/apps/files/l10n/mk.json
+++ b/apps/files/l10n/mk.json
@@ -1,9 +1,7 @@
{ "translations": {
+ "Storage not available" : "Сториџот не е достапен",
+ "Storage invalid" : "Сториџот не е валиден",
"Unknown error" : "Непозната грешка",
- "Could not move %s - File with this name already exists" : "Не можам да го преместам %s - Датотека со такво име веќе постои",
- "Could not move %s" : "Не можам да ги префрлам %s",
- "Error when creating the file" : "Грешка при креирање на датотека",
- "Error when creating the folder" : "Грешка при креирање на папка",
"Unable to set upload directory." : "Не може да се постави папката за префрлање на податоци.",
"Invalid Token" : "Грешен токен",
"No file was uploaded. Unknown error" : "Ниту еден фајл не се вчита. Непозната грешка",
@@ -18,6 +16,7 @@
"Upload failed. Could not find uploaded file" : "Префрлањето е неуспешно. Не можам да го најдам префрлената датотека.",
"Invalid directory." : "Погрешна папка.",
"Files" : "Датотеки",
+ "All files" : "Сите датотеки",
"Favorites" : "Омилени",
"Home" : "Дома",
"Close" : "Затвори",
@@ -28,15 +27,11 @@
"Download" : "Преземи",
"Rename" : "Преименувај",
"Delete" : "Избриши",
+ "Unshare" : "Не споделувај",
"Details" : "Детали:",
"Select" : "Избери",
"Pending" : "Чека",
- "Error moving file" : "Грешка при префрлање на датотека",
- "Error" : "Грешка",
- "{new_name} already exists" : "{new_name} веќе постои",
- "Could not rename file" : "Не можам да ја преименувам датотеката",
- "Could not create file" : "Не множам да креирам датотека",
- "Could not create folder" : "Не можам да креирам папка",
+ "This operation is forbidden" : "Операцијата не е дозволена",
"Name" : "Име",
"Size" : "Големина",
"Modified" : "Променето",
@@ -45,27 +40,39 @@
"File name cannot be empty." : "Името на датотеката не може да биде празно.",
"Your storage is full, files can not be updated or synced anymore!" : "Вашиот сториџ е полн, датотеките веќе не можат да се освежуваат или синхронизираат!",
"Your storage is almost full ({usedSpacePercent}%)" : "Вашиот сториџ е скоро полн ({usedSpacePercent}%)",
- "Text file" : "Текстуална датотека",
+ "Path" : "Патека",
+ "Favorited" : "Омилени",
+ "Favorite" : "Омилен",
"Folder" : "Папка",
"New folder" : "Нова папка",
+ "{newname} already exists" : "{newname} веќе постои",
"Upload" : "Подигни",
+ "An error occurred while trying to update the tags" : "Се случи грешка додека се обидувавте да ги освежите таговите",
"You created %1$s" : "Вие креиравте %1$s",
"%2$s created %1$s" : "%2$s креирано %1$s",
"You changed %1$s" : "Вие изменивте %1$s",
"%2$s changed %1$s" : "%2$s променето %1$s",
"You deleted %1$s" : "Вие избришавте %1$s",
"%2$s deleted %1$s" : "%2$s избришани %1$s",
- "%s could not be renamed" : "%s не може да биде преименуван",
+ "Changed by %2$s" : "Променето од %2$s",
+ "Deleted by %2$s" : "Избришано од %2$s",
+ "Restored by %2$s" : "Повратено од %2$s",
"Upload (max. %s)" : "Префрлање (макс. %s)",
"File handling" : "Ракување со датотеки",
"Maximum upload size" : "Максимална големина за подигање",
"max. possible: " : "макс. можно:",
"Save" : "Сними",
+ "Missing permissions to edit from here." : "Недостасуваат пермисии за да уредувате од тука",
"Settings" : "Подесувања",
"WebDAV" : "WebDAV",
"Cancel upload" : "Откажи прикачување",
+ "No files in here" : "Тука нема датотеки",
+ "No entries found in this folder" : "Нема ништо во оваа папка",
+ "Select all" : "Избери се",
"Upload too large" : "Фајлот кој се вчитува е преголем",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Датотеките кои се обидувате да ги подигнете ја надминуваат максималната големина за подигнување датотеки на овој сервер.",
- "Files are being scanned, please wait." : "Се скенираат датотеки, ве молам почекајте."
+ "Files and folders you mark as favorite will show up here" : "Датотеките и папките кои ќе ги означите како чести, ќе се појават тука",
+ "Text file" : "Текстуална датотека",
+ "New text file.txt" : "Нова текстуална датотека file.txt"
},"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"
} \ No newline at end of file
diff --git a/apps/files/l10n/ms_MY.js b/apps/files/l10n/ms_MY.js
index b57c1e61ca9..dcd0c8e15e8 100644
--- a/apps/files/l10n/ms_MY.js
+++ b/apps/files/l10n/ms_MY.js
@@ -16,12 +16,10 @@ OC.L10N.register(
"Rename" : "Namakan",
"Delete" : "Padam",
"Pending" : "Dalam proses",
- "Error" : "Ralat",
"Name" : "Nama",
"Size" : "Saiz",
"Modified" : "Dimodifikasi",
"New" : "Baru",
- "Text file" : "Fail teks",
"Folder" : "Folder",
"Upload" : "Muat naik",
"You created %1$s" : "Anda telah membina %1$s",
@@ -35,6 +33,6 @@ OC.L10N.register(
"Cancel upload" : "Batal muat naik",
"Upload too large" : "Muatnaik terlalu besar",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Fail yang cuba dimuat naik melebihi saiz maksimum fail upload server",
- "Files are being scanned, please wait." : "Fail sedang diimbas, harap bersabar."
+ "Text file" : "Fail teks"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/ms_MY.json b/apps/files/l10n/ms_MY.json
index e9db1fcad9d..6f7b93d6ef1 100644
--- a/apps/files/l10n/ms_MY.json
+++ b/apps/files/l10n/ms_MY.json
@@ -14,12 +14,10 @@
"Rename" : "Namakan",
"Delete" : "Padam",
"Pending" : "Dalam proses",
- "Error" : "Ralat",
"Name" : "Nama",
"Size" : "Saiz",
"Modified" : "Dimodifikasi",
"New" : "Baru",
- "Text file" : "Fail teks",
"Folder" : "Folder",
"Upload" : "Muat naik",
"You created %1$s" : "Anda telah membina %1$s",
@@ -33,6 +31,6 @@
"Cancel upload" : "Batal muat naik",
"Upload too large" : "Muatnaik terlalu besar",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Fail yang cuba dimuat naik melebihi saiz maksimum fail upload server",
- "Files are being scanned, please wait." : "Fail sedang diimbas, harap bersabar."
+ "Text file" : "Fail teks"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/nb_NO.js b/apps/files/l10n/nb_NO.js
index a1f8def347e..a49c7b1a3d8 100644
--- a/apps/files/l10n/nb_NO.js
+++ b/apps/files/l10n/nb_NO.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Lagringsplass ikke tilgjengelig",
"Storage invalid" : "Lagringsplass ugyldig",
"Unknown error" : "Ukjent feil",
- "Could not move %s - File with this name already exists" : "Kan ikke flytte %s - En fil med samme navn finnes allerede",
- "Could not move %s" : "Kunne ikke flytte %s",
- "Permission denied" : "Tilgang nektet",
- "The target folder has been moved or deleted." : "Målmappen er blitt flyttet eller slettet.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Navnet %s brukes allerede i mappen %s. Velg et annet navn.",
- "Error when creating the file" : "Feil ved oppretting av filen",
- "Error when creating the folder" : "Feil ved oppretting av mappen",
"Unable to set upload directory." : "Kunne ikke sette opplastingskatalog.",
"Invalid Token" : "Ugyldig nøkkel",
"No file was uploaded. Unknown error" : "Ingen filer ble lastet opp. Ukjent feil.",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Mangler midlertidig mappe",
"Failed to write to disk" : "Klarte ikke å skrive til disk",
"Not enough storage available" : "Ikke nok lagringsplass",
+ "The target folder has been moved or deleted." : "Målmappen er blitt flyttet eller slettet.",
"Upload failed. Could not find uploaded file" : "Opplasting feilet. Fant ikke opplastet fil.",
"Upload failed. Could not get file info." : "Opplasting feilet. Klarte ikke å finne informasjon om fil.",
"Invalid directory." : "Ugyldig katalog.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Last ned",
"Rename" : "Gi nytt navn",
"Delete" : "Slett",
+ "Disconnect storage" : "Koble fra lagring",
+ "Unshare" : "Avslutt deling",
"Details" : "Detaljer",
"Select" : "Velg",
"Pending" : "Ventende",
"Unable to determine date" : "Kan ikke fastslå datoen",
"This operation is forbidden" : "Operasjonen er forbudt",
"This directory is unavailable, please check the logs or contact the administrator" : "Denne mappen er utilgjengelig. Sjekk loggene eller kontakt administrator",
- "Error moving file." : "Feil ved flytting av fil.",
- "Error moving file" : "Feil ved flytting av fil",
- "Error" : "Feil",
- "{new_name} already exists" : "{new_name} finnes allerede",
- "Could not rename file" : "Klarte ikke å gi nytt navn til fil",
- "Could not create file" : "Klarte ikke å opprette fil",
- "Could not create folder" : "Klarte ikke å opprette mappe",
- "Error deleting file." : "Feil ved sletting av fil.",
+ "Could not move \"{file}\", target exists" : "Klarte ikke å flytte \"{file}\", målfilen finnes",
+ "Could not move \"{file}\"" : "Klarte ikke å flytte \"{file}\"",
+ "{newName} already exists" : "{newName} finnes allerede",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Klarte ikke å omdøpe \"{fileName}\", den finnes ikke lenger",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Navnet \"{targetName}\" brukes allerede i mappen \"{dir}\". Velg et annet navn.",
+ "Could not rename \"{fileName}\"" : "Klarte ikke å omdøpe \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Klarte ikke å opprette fil \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Klarte ikke å opprette fil \"{file}\" fordi den finnes allerede",
+ "Could not create folder \"{dir}\"" : "Klarete ikke å opprette mappe \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Klarete ikke å opprette mappe \"{dir}\" fordi den finnes allerede",
+ "Error deleting file \"{fileName}\"." : "Feil ved sletting av fil \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Ingen oppføringer i denne mappen stemmer med '{filter}'",
"Name" : "Navn",
"Size" : "Størrelse",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Er favoritt",
"Favorite" : "Gjør til favoritt",
- "Text file" : "Tekstfil",
- "New text file.txt" : "Ny tekstfil.txt",
"Folder" : "Mappe",
"New folder" : "Ny mappe",
"{newname} already exists" : "{newname} finnes allerede",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "Endret av %2$s",
"Deleted by %2$s" : "Slettet av %2$s",
"Restored by %2$s" : "Gjenopprettet av %2$s",
- "%s could not be renamed as it has been deleted" : "%s kunne ikke gis nytt navn da den er blitt slettet",
- "%s could not be renamed" : "Kunne ikke gi nytt navn til %s",
"Upload (max. %s)" : "Opplasting (maks. %s)",
"File handling" : "Filhåndtering",
"Maximum upload size" : "Største opplastingsstørrelse",
"max. possible: " : "max. mulige:",
"Save" : "Lagre",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Med PHP-FPM kan det ta 5 minutter før endringene trer i kraft.",
+ "Missing permissions to edit from here." : "Manglende rettigheter til å redigere herfra.",
"Settings" : "Innstillinger",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Bruk denne adressen for å <a href=\"%s\" target=\"_blank\">få tilgang til filene dine via WebDAV</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "Velg alle",
"Upload too large" : "Filen er for stor",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Filene du prøver å laste opp er for store til å laste opp til denne serveren.",
- "Files are being scanned, please wait." : "Skanner filer, vennligst vent.",
- "Currently scanning" : "Skanner nå",
"No favorites" : "Ingen favoritter",
- "Files and folders you mark as favorite will show up here" : "Filer og mapper som du gjør til favoritter vises her"
+ "Files and folders you mark as favorite will show up here" : "Filer og mapper som du gjør til favoritter vises her",
+ "Text file" : "Tekstfil",
+ "New text file.txt" : "Ny tekstfil.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/nb_NO.json b/apps/files/l10n/nb_NO.json
index 6d7ee493008..860ac1633ab 100644
--- a/apps/files/l10n/nb_NO.json
+++ b/apps/files/l10n/nb_NO.json
@@ -2,13 +2,6 @@
"Storage not available" : "Lagringsplass ikke tilgjengelig",
"Storage invalid" : "Lagringsplass ugyldig",
"Unknown error" : "Ukjent feil",
- "Could not move %s - File with this name already exists" : "Kan ikke flytte %s - En fil med samme navn finnes allerede",
- "Could not move %s" : "Kunne ikke flytte %s",
- "Permission denied" : "Tilgang nektet",
- "The target folder has been moved or deleted." : "Målmappen er blitt flyttet eller slettet.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Navnet %s brukes allerede i mappen %s. Velg et annet navn.",
- "Error when creating the file" : "Feil ved oppretting av filen",
- "Error when creating the folder" : "Feil ved oppretting av mappen",
"Unable to set upload directory." : "Kunne ikke sette opplastingskatalog.",
"Invalid Token" : "Ugyldig nøkkel",
"No file was uploaded. Unknown error" : "Ingen filer ble lastet opp. Ukjent feil.",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Mangler midlertidig mappe",
"Failed to write to disk" : "Klarte ikke å skrive til disk",
"Not enough storage available" : "Ikke nok lagringsplass",
+ "The target folder has been moved or deleted." : "Målmappen er blitt flyttet eller slettet.",
"Upload failed. Could not find uploaded file" : "Opplasting feilet. Fant ikke opplastet fil.",
"Upload failed. Could not get file info." : "Opplasting feilet. Klarte ikke å finne informasjon om fil.",
"Invalid directory." : "Ugyldig katalog.",
@@ -38,20 +32,25 @@
"Download" : "Last ned",
"Rename" : "Gi nytt navn",
"Delete" : "Slett",
+ "Disconnect storage" : "Koble fra lagring",
+ "Unshare" : "Avslutt deling",
"Details" : "Detaljer",
"Select" : "Velg",
"Pending" : "Ventende",
"Unable to determine date" : "Kan ikke fastslå datoen",
"This operation is forbidden" : "Operasjonen er forbudt",
"This directory is unavailable, please check the logs or contact the administrator" : "Denne mappen er utilgjengelig. Sjekk loggene eller kontakt administrator",
- "Error moving file." : "Feil ved flytting av fil.",
- "Error moving file" : "Feil ved flytting av fil",
- "Error" : "Feil",
- "{new_name} already exists" : "{new_name} finnes allerede",
- "Could not rename file" : "Klarte ikke å gi nytt navn til fil",
- "Could not create file" : "Klarte ikke å opprette fil",
- "Could not create folder" : "Klarte ikke å opprette mappe",
- "Error deleting file." : "Feil ved sletting av fil.",
+ "Could not move \"{file}\", target exists" : "Klarte ikke å flytte \"{file}\", målfilen finnes",
+ "Could not move \"{file}\"" : "Klarte ikke å flytte \"{file}\"",
+ "{newName} already exists" : "{newName} finnes allerede",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Klarte ikke å omdøpe \"{fileName}\", den finnes ikke lenger",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Navnet \"{targetName}\" brukes allerede i mappen \"{dir}\". Velg et annet navn.",
+ "Could not rename \"{fileName}\"" : "Klarte ikke å omdøpe \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Klarte ikke å opprette fil \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Klarte ikke å opprette fil \"{file}\" fordi den finnes allerede",
+ "Could not create folder \"{dir}\"" : "Klarete ikke å opprette mappe \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Klarete ikke å opprette mappe \"{dir}\" fordi den finnes allerede",
+ "Error deleting file \"{fileName}\"." : "Feil ved sletting av fil \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Ingen oppføringer i denne mappen stemmer med '{filter}'",
"Name" : "Navn",
"Size" : "Størrelse",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Er favoritt",
"Favorite" : "Gjør til favoritt",
- "Text file" : "Tekstfil",
- "New text file.txt" : "Ny tekstfil.txt",
"Folder" : "Mappe",
"New folder" : "Ny mappe",
"{newname} already exists" : "{newname} finnes allerede",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "Endret av %2$s",
"Deleted by %2$s" : "Slettet av %2$s",
"Restored by %2$s" : "Gjenopprettet av %2$s",
- "%s could not be renamed as it has been deleted" : "%s kunne ikke gis nytt navn da den er blitt slettet",
- "%s could not be renamed" : "Kunne ikke gi nytt navn til %s",
"Upload (max. %s)" : "Opplasting (maks. %s)",
"File handling" : "Filhåndtering",
"Maximum upload size" : "Største opplastingsstørrelse",
"max. possible: " : "max. mulige:",
"Save" : "Lagre",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Med PHP-FPM kan det ta 5 minutter før endringene trer i kraft.",
+ "Missing permissions to edit from here." : "Manglende rettigheter til å redigere herfra.",
"Settings" : "Innstillinger",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Bruk denne adressen for å <a href=\"%s\" target=\"_blank\">få tilgang til filene dine via WebDAV</a>",
@@ -114,9 +111,9 @@
"Select all" : "Velg alle",
"Upload too large" : "Filen er for stor",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Filene du prøver å laste opp er for store til å laste opp til denne serveren.",
- "Files are being scanned, please wait." : "Skanner filer, vennligst vent.",
- "Currently scanning" : "Skanner nå",
"No favorites" : "Ingen favoritter",
- "Files and folders you mark as favorite will show up here" : "Filer og mapper som du gjør til favoritter vises her"
+ "Files and folders you mark as favorite will show up here" : "Filer og mapper som du gjør til favoritter vises her",
+ "Text file" : "Tekstfil",
+ "New text file.txt" : "Ny tekstfil.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/nds.js b/apps/files/l10n/nds.js
index 9b28220ae43..bb3dc429711 100644
--- a/apps/files/l10n/nds.js
+++ b/apps/files/l10n/nds.js
@@ -3,7 +3,10 @@ OC.L10N.register(
{
"Files" : "Dateien",
"Delete" : "Löschen",
+ "Details" : "Details",
"Name" : "Name",
+ "New folder" : "Neuer Ordner",
+ "Upload" : "Hochladen",
"Settings" : "Einstellungen",
"WebDAV" : "WebDAV"
},
diff --git a/apps/files/l10n/nds.json b/apps/files/l10n/nds.json
index 4ab8de68b35..c8e93f2fa2b 100644
--- a/apps/files/l10n/nds.json
+++ b/apps/files/l10n/nds.json
@@ -1,7 +1,10 @@
{ "translations": {
"Files" : "Dateien",
"Delete" : "Löschen",
+ "Details" : "Details",
"Name" : "Name",
+ "New folder" : "Neuer Ordner",
+ "Upload" : "Hochladen",
"Settings" : "Einstellungen",
"WebDAV" : "WebDAV"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/files/l10n/nl.js b/apps/files/l10n/nl.js
index d60598ca147..41e1343f47e 100644
--- a/apps/files/l10n/nl.js
+++ b/apps/files/l10n/nl.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Opslag niet beschikbaar",
"Storage invalid" : "Opslag ongeldig",
"Unknown error" : "Onbekende fout",
- "Could not move %s - File with this name already exists" : "Kon %s niet verplaatsen - Er bestaat al een bestand met deze naam",
- "Could not move %s" : "Kon %s niet verplaatsen",
- "Permission denied" : "Toegang geweigerd",
- "The target folder has been moved or deleted." : "De doelmap is verplaatst of verwijderd.",
- "The name %s is already used in the folder %s. Please choose a different name." : "De naam %s bestaat al in map %s. Kies een andere naam.",
- "Error when creating the file" : "Fout bij creëren bestand",
- "Error when creating the folder" : "Fout bij aanmaken map",
"Unable to set upload directory." : "Kan uploadmap niet instellen.",
"Invalid Token" : "Ongeldig Token",
"No file was uploaded. Unknown error" : "Er was geen bestand geladen. Onbekende fout",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Er ontbreekt een tijdelijke map",
"Failed to write to disk" : "Schrijven naar schijf mislukt",
"Not enough storage available" : "Niet genoeg opslagruimte beschikbaar",
+ "The target folder has been moved or deleted." : "De doelmap is verplaatst of verwijderd.",
"Upload failed. Could not find uploaded file" : "Upload mislukt. Kon geüploade bestand niet vinden",
"Upload failed. Could not get file info." : "Upload mislukt. Kon geen bestandsinfo krijgen.",
"Invalid directory." : "Ongeldige directory.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Downloaden",
"Rename" : "Naam wijzigen",
"Delete" : "Verwijderen",
+ "Disconnect storage" : "Verbinding met opslag verbreken",
+ "Unshare" : "Stop met delen",
"Details" : "Details",
"Select" : "Selecteer",
"Pending" : "In behandeling",
"Unable to determine date" : "Kon datum niet vaststellen",
"This operation is forbidden" : "Deze taak is verboden",
"This directory is unavailable, please check the logs or contact the administrator" : "Deze map is niet beschikbaar. Verifieer de logs of neem contact op met de beheerder",
- "Error moving file." : "Fout bij verplaatsen bestand.",
- "Error moving file" : "Fout bij verplaatsen bestand",
- "Error" : "Fout",
- "{new_name} already exists" : "{new_name} bestaat al",
- "Could not rename file" : "Kon de naam van het bestand niet wijzigen",
- "Could not create file" : "Kon bestand niet creëren",
- "Could not create folder" : "Kon niet creëren map",
- "Error deleting file." : "Fout bij verwijderen bestand.",
+ "Could not move \"{file}\", target exists" : "Kon \"{file}\" niet verplaatsen, doel bestaat al",
+ "Could not move \"{file}\"" : "Kon \"{file}\" niet verplaatsen",
+ "{newName} already exists" : "{newName} bestaat al",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Kon \"{fileName}\" niet hernoemen, het bestaat niet meer",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "De naam \"{targetName}\" bestaat al in map \"{dir}\". Kies een andere naam.",
+ "Could not rename \"{fileName}\"" : "Kon \"{fileName}\" niet hernoemen",
+ "Could not create file \"{file}\"" : "Kon \"{file}\" niet aanmaken",
+ "Could not create file \"{file}\" because it already exists" : "Kon \"{file}\" niet aanmaken omdat het al bestaat",
+ "Could not create folder \"{dir}\"" : "Kon map \"{dir}\" niet aanmaken",
+ "Could not create folder \"{dir}\" because it already exists" : "Kon map \"{dir}\" niet aanmaken omdat die al bestaat",
+ "Error deleting file \"{fileName}\"." : "Fout bij verwijderen bestand \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Niets in deze map komt overeen met '{filter}'",
"Name" : "Naam",
"Size" : "Grootte",
@@ -74,8 +73,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Favoriet",
"Favorite" : "Favoriet",
- "Text file" : "Tekstbestand",
- "New text file.txt" : "Nieuw tekstbestand.txt",
"Folder" : "Map",
"New folder" : "Nieuwe map",
"{newname} already exists" : "{newname} bestaat al",
@@ -86,25 +83,25 @@ OC.L10N.register(
"Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Beperk meldingen over aanmaken en wijzigen aan uw <strong>favoriete bestanden</strong> <em>(Alleen stream)</em>",
"A file or folder has been <strong>deleted</strong>" : "Een bestand of map is <strong>verwijderd</strong>",
"A file or folder has been <strong>restored</strong>" : "Een bestand of een mmaps is <strong>hersteld</strong>",
- "You created %1$s" : "U creëerde %1$s",
+ "You created %1$s" : "Gecreëerd: %1$s",
"%2$s created %1$s" : "%2$s creëerde %1$s",
"%1$s was created in a public folder" : "%1$s werd gecreëerd in een openbare map",
- "You changed %1$s" : "U wijzigde %1$s",
+ "You changed %1$s" : "Gewijzigd: %1$s",
"%2$s changed %1$s" : "%2$s wijzigde %1$s",
- "You deleted %1$s" : "U verwijderde %1$s",
+ "You deleted %1$s" : "Verwijderd: %1$s",
"%2$s deleted %1$s" : "%2$s verwijderde %1$s",
- "You restored %1$s" : "U herstelde %1$s",
+ "You restored %1$s" : "Hersteld: %1$s",
"%2$s restored %1$s" : "%2$s herstelde %1$s",
"Changed by %2$s" : "Gewijzigd door %2$s",
"Deleted by %2$s" : "Verwijderd door %2$s",
"Restored by %2$s" : "Hersteld door %2$s",
- "%s could not be renamed as it has been deleted" : "%s kon niet worden hernoemd, omdat het verwijderd is",
- "%s could not be renamed" : "%s kon niet worden hernoemd",
"Upload (max. %s)" : "Upload (max. %s)",
"File handling" : "Bestand",
"Maximum upload size" : "Maximale bestandsgrootte voor uploads",
"max. possible: " : "max. mogelijk: ",
"Save" : "Bewaren",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Met PHP-FPM kan het 5 minuten duren voordat wijzigingen zijn doorgevoerd.",
+ "Missing permissions to edit from here." : "Ontbrekende rechten om vanaf hier te bewerken.",
"Settings" : "Instellingen",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Gebruik deze link <a href=\"%s\" target=\"_blank\">om uw bestanden via WebDAV te benaderen</a>",
@@ -115,9 +112,9 @@ OC.L10N.register(
"Select all" : "Alles selecteren",
"Upload too large" : "Upload is te groot",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "De bestanden die u probeert te uploaden zijn groter dan de maximaal toegestane bestandsgrootte voor deze server.",
- "Files are being scanned, please wait." : "Bestanden worden gescand, even wachten.",
- "Currently scanning" : "Nu aan het scannen",
"No favorites" : "Geen favorieten",
- "Files and folders you mark as favorite will show up here" : "Bestanden en mappen die u favoriet vindt worden hier getoont"
+ "Files and folders you mark as favorite will show up here" : "Bestanden en mappen die u favoriet vindt worden hier getoont",
+ "Text file" : "Tekstbestand",
+ "New text file.txt" : "Nieuw tekstbestand.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/nl.json b/apps/files/l10n/nl.json
index 28f80c09af7..5c6891d2d92 100644
--- a/apps/files/l10n/nl.json
+++ b/apps/files/l10n/nl.json
@@ -2,13 +2,6 @@
"Storage not available" : "Opslag niet beschikbaar",
"Storage invalid" : "Opslag ongeldig",
"Unknown error" : "Onbekende fout",
- "Could not move %s - File with this name already exists" : "Kon %s niet verplaatsen - Er bestaat al een bestand met deze naam",
- "Could not move %s" : "Kon %s niet verplaatsen",
- "Permission denied" : "Toegang geweigerd",
- "The target folder has been moved or deleted." : "De doelmap is verplaatst of verwijderd.",
- "The name %s is already used in the folder %s. Please choose a different name." : "De naam %s bestaat al in map %s. Kies een andere naam.",
- "Error when creating the file" : "Fout bij creëren bestand",
- "Error when creating the folder" : "Fout bij aanmaken map",
"Unable to set upload directory." : "Kan uploadmap niet instellen.",
"Invalid Token" : "Ongeldig Token",
"No file was uploaded. Unknown error" : "Er was geen bestand geladen. Onbekende fout",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Er ontbreekt een tijdelijke map",
"Failed to write to disk" : "Schrijven naar schijf mislukt",
"Not enough storage available" : "Niet genoeg opslagruimte beschikbaar",
+ "The target folder has been moved or deleted." : "De doelmap is verplaatst of verwijderd.",
"Upload failed. Could not find uploaded file" : "Upload mislukt. Kon geüploade bestand niet vinden",
"Upload failed. Could not get file info." : "Upload mislukt. Kon geen bestandsinfo krijgen.",
"Invalid directory." : "Ongeldige directory.",
@@ -38,20 +32,25 @@
"Download" : "Downloaden",
"Rename" : "Naam wijzigen",
"Delete" : "Verwijderen",
+ "Disconnect storage" : "Verbinding met opslag verbreken",
+ "Unshare" : "Stop met delen",
"Details" : "Details",
"Select" : "Selecteer",
"Pending" : "In behandeling",
"Unable to determine date" : "Kon datum niet vaststellen",
"This operation is forbidden" : "Deze taak is verboden",
"This directory is unavailable, please check the logs or contact the administrator" : "Deze map is niet beschikbaar. Verifieer de logs of neem contact op met de beheerder",
- "Error moving file." : "Fout bij verplaatsen bestand.",
- "Error moving file" : "Fout bij verplaatsen bestand",
- "Error" : "Fout",
- "{new_name} already exists" : "{new_name} bestaat al",
- "Could not rename file" : "Kon de naam van het bestand niet wijzigen",
- "Could not create file" : "Kon bestand niet creëren",
- "Could not create folder" : "Kon niet creëren map",
- "Error deleting file." : "Fout bij verwijderen bestand.",
+ "Could not move \"{file}\", target exists" : "Kon \"{file}\" niet verplaatsen, doel bestaat al",
+ "Could not move \"{file}\"" : "Kon \"{file}\" niet verplaatsen",
+ "{newName} already exists" : "{newName} bestaat al",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Kon \"{fileName}\" niet hernoemen, het bestaat niet meer",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "De naam \"{targetName}\" bestaat al in map \"{dir}\". Kies een andere naam.",
+ "Could not rename \"{fileName}\"" : "Kon \"{fileName}\" niet hernoemen",
+ "Could not create file \"{file}\"" : "Kon \"{file}\" niet aanmaken",
+ "Could not create file \"{file}\" because it already exists" : "Kon \"{file}\" niet aanmaken omdat het al bestaat",
+ "Could not create folder \"{dir}\"" : "Kon map \"{dir}\" niet aanmaken",
+ "Could not create folder \"{dir}\" because it already exists" : "Kon map \"{dir}\" niet aanmaken omdat die al bestaat",
+ "Error deleting file \"{fileName}\"." : "Fout bij verwijderen bestand \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Niets in deze map komt overeen met '{filter}'",
"Name" : "Naam",
"Size" : "Grootte",
@@ -72,8 +71,6 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Favoriet",
"Favorite" : "Favoriet",
- "Text file" : "Tekstbestand",
- "New text file.txt" : "Nieuw tekstbestand.txt",
"Folder" : "Map",
"New folder" : "Nieuwe map",
"{newname} already exists" : "{newname} bestaat al",
@@ -84,25 +81,25 @@
"Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Beperk meldingen over aanmaken en wijzigen aan uw <strong>favoriete bestanden</strong> <em>(Alleen stream)</em>",
"A file or folder has been <strong>deleted</strong>" : "Een bestand of map is <strong>verwijderd</strong>",
"A file or folder has been <strong>restored</strong>" : "Een bestand of een mmaps is <strong>hersteld</strong>",
- "You created %1$s" : "U creëerde %1$s",
+ "You created %1$s" : "Gecreëerd: %1$s",
"%2$s created %1$s" : "%2$s creëerde %1$s",
"%1$s was created in a public folder" : "%1$s werd gecreëerd in een openbare map",
- "You changed %1$s" : "U wijzigde %1$s",
+ "You changed %1$s" : "Gewijzigd: %1$s",
"%2$s changed %1$s" : "%2$s wijzigde %1$s",
- "You deleted %1$s" : "U verwijderde %1$s",
+ "You deleted %1$s" : "Verwijderd: %1$s",
"%2$s deleted %1$s" : "%2$s verwijderde %1$s",
- "You restored %1$s" : "U herstelde %1$s",
+ "You restored %1$s" : "Hersteld: %1$s",
"%2$s restored %1$s" : "%2$s herstelde %1$s",
"Changed by %2$s" : "Gewijzigd door %2$s",
"Deleted by %2$s" : "Verwijderd door %2$s",
"Restored by %2$s" : "Hersteld door %2$s",
- "%s could not be renamed as it has been deleted" : "%s kon niet worden hernoemd, omdat het verwijderd is",
- "%s could not be renamed" : "%s kon niet worden hernoemd",
"Upload (max. %s)" : "Upload (max. %s)",
"File handling" : "Bestand",
"Maximum upload size" : "Maximale bestandsgrootte voor uploads",
"max. possible: " : "max. mogelijk: ",
"Save" : "Bewaren",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Met PHP-FPM kan het 5 minuten duren voordat wijzigingen zijn doorgevoerd.",
+ "Missing permissions to edit from here." : "Ontbrekende rechten om vanaf hier te bewerken.",
"Settings" : "Instellingen",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Gebruik deze link <a href=\"%s\" target=\"_blank\">om uw bestanden via WebDAV te benaderen</a>",
@@ -113,9 +110,9 @@
"Select all" : "Alles selecteren",
"Upload too large" : "Upload is te groot",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "De bestanden die u probeert te uploaden zijn groter dan de maximaal toegestane bestandsgrootte voor deze server.",
- "Files are being scanned, please wait." : "Bestanden worden gescand, even wachten.",
- "Currently scanning" : "Nu aan het scannen",
"No favorites" : "Geen favorieten",
- "Files and folders you mark as favorite will show up here" : "Bestanden en mappen die u favoriet vindt worden hier getoont"
+ "Files and folders you mark as favorite will show up here" : "Bestanden en mappen die u favoriet vindt worden hier getoont",
+ "Text file" : "Tekstbestand",
+ "New text file.txt" : "Nieuw tekstbestand.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/nn_NO.js b/apps/files/l10n/nn_NO.js
index 6d9e9f4acdd..1e138d91b85 100644
--- a/apps/files/l10n/nn_NO.js
+++ b/apps/files/l10n/nn_NO.js
@@ -2,8 +2,6 @@ OC.L10N.register(
"files",
{
"Unknown error" : "Ukjend feil",
- "Could not move %s - File with this name already exists" : "Klarte ikkje flytta %s – det finst allereie ei fil med dette namnet",
- "Could not move %s" : "Klarte ikkje flytta %s",
"Unable to set upload directory." : "Klarte ikkje å endra opplastingsmappa.",
"Invalid Token" : "Ugyldig token",
"No file was uploaded. Unknown error" : "Ingen filer lasta opp. Ukjend feil",
@@ -30,11 +28,9 @@ OC.L10N.register(
"Download" : "Last ned",
"Rename" : "Endra namn",
"Delete" : "Slett",
+ "Unshare" : "Udel",
"Details" : "Detaljar",
"Pending" : "Under vegs",
- "Error moving file" : "Feil ved flytting av fil",
- "Error" : "Feil",
- "{new_name} already exists" : "{new_name} finst allereie",
"Name" : "Namn",
"Size" : "Storleik",
"Modified" : "Endra",
@@ -47,7 +43,6 @@ OC.L10N.register(
"Your storage is full, files can not be updated or synced anymore!" : "Lagringa di er full, kan ikkje lenger oppdatera eller synkronisera!",
"Your storage is almost full ({usedSpacePercent}%)" : "Lagringa di er nesten full ({usedSpacePercent} %)",
"Favorite" : "Favoritt",
- "Text file" : "Tekst fil",
"Folder" : "Mappe",
"New folder" : "Ny mappe",
"Upload" : "Last opp",
@@ -61,7 +56,6 @@ OC.L10N.register(
"%2$s changed %1$s" : "%2$s endra %1$s",
"You deleted %1$s" : "Du sletta %1$s",
"%2$s deleted %1$s" : "%2$s sletta %1$s",
- "%s could not be renamed" : "Klarte ikkje å omdøypa på %s",
"File handling" : "Filhandtering",
"Maximum upload size" : "Maksimal opplastingsstorleik",
"max. possible: " : "maks. moglege:",
@@ -71,6 +65,6 @@ OC.L10N.register(
"Cancel upload" : "Avbryt opplasting",
"Upload too large" : "For stor opplasting",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Filene du prøver å lasta opp er større enn maksgrensa til denne tenaren.",
- "Files are being scanned, please wait." : "Skannar filer, ver venleg og vent."
+ "Text file" : "Tekst fil"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/nn_NO.json b/apps/files/l10n/nn_NO.json
index 277c50de6da..5645a61b6bc 100644
--- a/apps/files/l10n/nn_NO.json
+++ b/apps/files/l10n/nn_NO.json
@@ -1,7 +1,5 @@
{ "translations": {
"Unknown error" : "Ukjend feil",
- "Could not move %s - File with this name already exists" : "Klarte ikkje flytta %s – det finst allereie ei fil med dette namnet",
- "Could not move %s" : "Klarte ikkje flytta %s",
"Unable to set upload directory." : "Klarte ikkje å endra opplastingsmappa.",
"Invalid Token" : "Ugyldig token",
"No file was uploaded. Unknown error" : "Ingen filer lasta opp. Ukjend feil",
@@ -28,11 +26,9 @@
"Download" : "Last ned",
"Rename" : "Endra namn",
"Delete" : "Slett",
+ "Unshare" : "Udel",
"Details" : "Detaljar",
"Pending" : "Under vegs",
- "Error moving file" : "Feil ved flytting av fil",
- "Error" : "Feil",
- "{new_name} already exists" : "{new_name} finst allereie",
"Name" : "Namn",
"Size" : "Storleik",
"Modified" : "Endra",
@@ -45,7 +41,6 @@
"Your storage is full, files can not be updated or synced anymore!" : "Lagringa di er full, kan ikkje lenger oppdatera eller synkronisera!",
"Your storage is almost full ({usedSpacePercent}%)" : "Lagringa di er nesten full ({usedSpacePercent} %)",
"Favorite" : "Favoritt",
- "Text file" : "Tekst fil",
"Folder" : "Mappe",
"New folder" : "Ny mappe",
"Upload" : "Last opp",
@@ -59,7 +54,6 @@
"%2$s changed %1$s" : "%2$s endra %1$s",
"You deleted %1$s" : "Du sletta %1$s",
"%2$s deleted %1$s" : "%2$s sletta %1$s",
- "%s could not be renamed" : "Klarte ikkje å omdøypa på %s",
"File handling" : "Filhandtering",
"Maximum upload size" : "Maksimal opplastingsstorleik",
"max. possible: " : "maks. moglege:",
@@ -69,6 +63,6 @@
"Cancel upload" : "Avbryt opplasting",
"Upload too large" : "For stor opplasting",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Filene du prøver å lasta opp er større enn maksgrensa til denne tenaren.",
- "Files are being scanned, please wait." : "Skannar filer, ver venleg og vent."
+ "Text file" : "Tekst fil"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/oc.js b/apps/files/l10n/oc.js
index d702fcace3d..6fde5981b12 100644
--- a/apps/files/l10n/oc.js
+++ b/apps/files/l10n/oc.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Supòrt d'emmagazinatge pas disponible",
"Storage invalid" : "Supòrt d'emmagazinatge pas valable",
"Unknown error" : "Error Desconeguda ",
- "Could not move %s - File with this name already exists" : "Impossible de desplaçar %s - Un fichièr que pòrta aqueste nom existís ja",
- "Could not move %s" : "Impossible de desplaçar %s",
- "Permission denied" : "Permission refusada",
- "The target folder has been moved or deleted." : "Lo dorsièr cibla es estat desplaçat o suprimit.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Lo nom %s es ja utilizat dins lo dorsièr %s. Mercé de causir un nom diferent.",
- "Error when creating the file" : "Error pendent la creacion del fichièr",
- "Error when creating the folder" : "Error pendent la creacion del dorsièr",
"Unable to set upload directory." : "Impossible de definir lo dorsièr de destinacion.",
"Invalid Token" : "Geton invalid",
"No file was uploaded. Unknown error" : "Cap de fichièr es pas estat mandat. Error desconeguda",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Abséncia de dorsièr temporari",
"Failed to write to disk" : "Error d'escritura sul disc",
"Not enough storage available" : "Pas pro d'espaci d'emmagazinatge de disponible",
+ "The target folder has been moved or deleted." : "Lo dorsièr cibla es estat desplaçat o suprimit.",
"Upload failed. Could not find uploaded file" : "Lo mandadís a fracassat. Impossible de trobar lo fichièr mandat.",
"Upload failed. Could not get file info." : "Lo mandadís a fracassat. Impossible d'obténer las informacions del fichièr.",
"Invalid directory." : "Dorsièr invalid.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Telecargar",
"Rename" : "Renomenar",
"Delete" : "Suprimir",
+ "Disconnect storage" : "Desconnectar aqueste supòrt d'emmagazinatge",
+ "Unshare" : "Partejar pas",
"Details" : "Detalhs",
"Select" : "Seleccionar",
"Pending" : "En espèra",
"Unable to determine date" : "Impossible de determinar la data",
"This operation is forbidden" : "L'operacion es interdicha",
"This directory is unavailable, please check the logs or contact the administrator" : "Aqueste repertòri es pas disponible. Consultatz los logs o contactatz vòstre administrator",
- "Error moving file." : "Error al moment del desplaçament del fichièr.",
- "Error moving file" : "Error al moment del desplaçament del fichièr",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} existís ja",
- "Could not rename file" : "Impossible de renomenar lo fichièr",
- "Could not create file" : "Impossible de crear lo fichièr",
- "Could not create folder" : "Impossible de crear lo dorsièr",
- "Error deleting file." : "Error pendent la supression del fichièr.",
+ "Could not move \"{file}\", target exists" : "Impossible de desplaçar \"{file}\", la cibla existís",
+ "Could not move \"{file}\"" : "Impossible de desplaçar \"{file}\"",
+ "{newName} already exists" : "{newName} existís ja",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Impossible de renomenar \"{file}\", existís pas mai",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Lo nom \"{targetName}\" es ja utilizat dins lo dorsièr \"{dir}\". Mercé de causir un nom diferent.",
+ "Could not rename \"{fileName}\"" : "Impossible de renomenar \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Impossible de crear lo fichièr \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Impossible de crear lo fichièr \"{file}\" perque existís ja",
+ "Could not create folder \"{dir}\"" : "Impossible de crear lo dorsièr \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Impossible de crear lo dorsièr \"{dir}\" perque existís ja",
+ "Error deleting file \"{fileName}\"." : "Error pendent la supression del fichièr \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Cap d'entrada d'aqueste dorsièr correspond pas a '{filter}'",
"Name" : "Nom",
"Size" : "Talha",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n octet","%n octets"],
"Favorited" : "Marcat coma favorit",
"Favorite" : "Favorit",
- "Text file" : "Fichièr tèxte",
- "New text file.txt" : "Novèl fichièr tèxte .txt",
"Folder" : "Dorsièr",
"New folder" : "Novèl dorsièr",
"{newname} already exists" : "{new_name} existís ja",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "Modificat per %2$s",
"Deleted by %2$s" : "Suprimit per %2$s",
"Restored by %2$s" : "Restablit per %2$s",
- "%s could not be renamed as it has been deleted" : "%s pòt pas èsser renomenat perque es estat suprimit ",
- "%s could not be renamed" : "%s pòt pas èsser renomenat",
"Upload (max. %s)" : "Mandadís (max. %s)",
"File handling" : "Gestion de fichièrs",
"Maximum upload size" : "Talha max. de mandadís",
"max. possible: " : "Max. possible :",
"Save" : "Salvar",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Amb PHP-FPM se pòdon passar 5 minutas per que los cambiaments s'apliquen.",
+ "Missing permissions to edit from here." : "Manca de permissions per editar a partir d'aicí.",
"Settings" : "Paramètres",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Utilizatz aquesta adreça per <a href=\"%s\" target=\"_blank\">accedir a vòstres fichièrs per WebDAV</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "Seleccionar tot",
"Upload too large" : "Mandadís tròp voluminós",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los fichièrs qu'ensajatz de mandar depassan la talha maximala de mandadís permesa per aqueste servidor.",
- "Files are being scanned, please wait." : "Los fichièrs son en cors d'analisi, pacientatz.",
- "Currently scanning" : "Analisi en cors",
"No favorites" : "Pas cap de favorit",
- "Files and folders you mark as favorite will show up here" : "Los fichièrs e dorsièrs aponduts a vòstres favorits apareisseràn aicí"
+ "Files and folders you mark as favorite will show up here" : "Los fichièrs e dorsièrs aponduts a vòstres favorits apareisseràn aicí",
+ "Text file" : "Fichièr tèxte",
+ "New text file.txt" : "Novèl fichièr tèxte .txt"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files/l10n/oc.json b/apps/files/l10n/oc.json
index ec91aa3ccba..37b2fc5f452 100644
--- a/apps/files/l10n/oc.json
+++ b/apps/files/l10n/oc.json
@@ -2,13 +2,6 @@
"Storage not available" : "Supòrt d'emmagazinatge pas disponible",
"Storage invalid" : "Supòrt d'emmagazinatge pas valable",
"Unknown error" : "Error Desconeguda ",
- "Could not move %s - File with this name already exists" : "Impossible de desplaçar %s - Un fichièr que pòrta aqueste nom existís ja",
- "Could not move %s" : "Impossible de desplaçar %s",
- "Permission denied" : "Permission refusada",
- "The target folder has been moved or deleted." : "Lo dorsièr cibla es estat desplaçat o suprimit.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Lo nom %s es ja utilizat dins lo dorsièr %s. Mercé de causir un nom diferent.",
- "Error when creating the file" : "Error pendent la creacion del fichièr",
- "Error when creating the folder" : "Error pendent la creacion del dorsièr",
"Unable to set upload directory." : "Impossible de definir lo dorsièr de destinacion.",
"Invalid Token" : "Geton invalid",
"No file was uploaded. Unknown error" : "Cap de fichièr es pas estat mandat. Error desconeguda",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Abséncia de dorsièr temporari",
"Failed to write to disk" : "Error d'escritura sul disc",
"Not enough storage available" : "Pas pro d'espaci d'emmagazinatge de disponible",
+ "The target folder has been moved or deleted." : "Lo dorsièr cibla es estat desplaçat o suprimit.",
"Upload failed. Could not find uploaded file" : "Lo mandadís a fracassat. Impossible de trobar lo fichièr mandat.",
"Upload failed. Could not get file info." : "Lo mandadís a fracassat. Impossible d'obténer las informacions del fichièr.",
"Invalid directory." : "Dorsièr invalid.",
@@ -38,20 +32,25 @@
"Download" : "Telecargar",
"Rename" : "Renomenar",
"Delete" : "Suprimir",
+ "Disconnect storage" : "Desconnectar aqueste supòrt d'emmagazinatge",
+ "Unshare" : "Partejar pas",
"Details" : "Detalhs",
"Select" : "Seleccionar",
"Pending" : "En espèra",
"Unable to determine date" : "Impossible de determinar la data",
"This operation is forbidden" : "L'operacion es interdicha",
"This directory is unavailable, please check the logs or contact the administrator" : "Aqueste repertòri es pas disponible. Consultatz los logs o contactatz vòstre administrator",
- "Error moving file." : "Error al moment del desplaçament del fichièr.",
- "Error moving file" : "Error al moment del desplaçament del fichièr",
- "Error" : "Error",
- "{new_name} already exists" : "{new_name} existís ja",
- "Could not rename file" : "Impossible de renomenar lo fichièr",
- "Could not create file" : "Impossible de crear lo fichièr",
- "Could not create folder" : "Impossible de crear lo dorsièr",
- "Error deleting file." : "Error pendent la supression del fichièr.",
+ "Could not move \"{file}\", target exists" : "Impossible de desplaçar \"{file}\", la cibla existís",
+ "Could not move \"{file}\"" : "Impossible de desplaçar \"{file}\"",
+ "{newName} already exists" : "{newName} existís ja",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Impossible de renomenar \"{file}\", existís pas mai",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Lo nom \"{targetName}\" es ja utilizat dins lo dorsièr \"{dir}\". Mercé de causir un nom diferent.",
+ "Could not rename \"{fileName}\"" : "Impossible de renomenar \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Impossible de crear lo fichièr \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Impossible de crear lo fichièr \"{file}\" perque existís ja",
+ "Could not create folder \"{dir}\"" : "Impossible de crear lo dorsièr \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Impossible de crear lo dorsièr \"{dir}\" perque existís ja",
+ "Error deleting file \"{fileName}\"." : "Error pendent la supression del fichièr \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Cap d'entrada d'aqueste dorsièr correspond pas a '{filter}'",
"Name" : "Nom",
"Size" : "Talha",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n octet","%n octets"],
"Favorited" : "Marcat coma favorit",
"Favorite" : "Favorit",
- "Text file" : "Fichièr tèxte",
- "New text file.txt" : "Novèl fichièr tèxte .txt",
"Folder" : "Dorsièr",
"New folder" : "Novèl dorsièr",
"{newname} already exists" : "{new_name} existís ja",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "Modificat per %2$s",
"Deleted by %2$s" : "Suprimit per %2$s",
"Restored by %2$s" : "Restablit per %2$s",
- "%s could not be renamed as it has been deleted" : "%s pòt pas èsser renomenat perque es estat suprimit ",
- "%s could not be renamed" : "%s pòt pas èsser renomenat",
"Upload (max. %s)" : "Mandadís (max. %s)",
"File handling" : "Gestion de fichièrs",
"Maximum upload size" : "Talha max. de mandadís",
"max. possible: " : "Max. possible :",
"Save" : "Salvar",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Amb PHP-FPM se pòdon passar 5 minutas per que los cambiaments s'apliquen.",
+ "Missing permissions to edit from here." : "Manca de permissions per editar a partir d'aicí.",
"Settings" : "Paramètres",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Utilizatz aquesta adreça per <a href=\"%s\" target=\"_blank\">accedir a vòstres fichièrs per WebDAV</a>",
@@ -114,9 +111,9 @@
"Select all" : "Seleccionar tot",
"Upload too large" : "Mandadís tròp voluminós",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Los fichièrs qu'ensajatz de mandar depassan la talha maximala de mandadís permesa per aqueste servidor.",
- "Files are being scanned, please wait." : "Los fichièrs son en cors d'analisi, pacientatz.",
- "Currently scanning" : "Analisi en cors",
"No favorites" : "Pas cap de favorit",
- "Files and folders you mark as favorite will show up here" : "Los fichièrs e dorsièrs aponduts a vòstres favorits apareisseràn aicí"
+ "Files and folders you mark as favorite will show up here" : "Los fichièrs e dorsièrs aponduts a vòstres favorits apareisseràn aicí",
+ "Text file" : "Fichièr tèxte",
+ "New text file.txt" : "Novèl fichièr tèxte .txt"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/pa.js b/apps/files/l10n/pa.js
index dfb7c392837..847adbc5ac1 100644
--- a/apps/files/l10n/pa.js
+++ b/apps/files/l10n/pa.js
@@ -7,7 +7,6 @@ OC.L10N.register(
"Rename" : "ਨਾਂ ਬਦਲੋ",
"Delete" : "ਹਟਾਓ",
"Details" : "ਵੇਰਵ",
- "Error" : "ਗਲਤੀ",
"Upload" : "ਅੱਪਲੋਡ",
"Settings" : "ਸੈਟਿੰਗ",
"Cancel upload" : "ਅੱਪਲੋਡ ਰੱਦ ਕਰੋ"
diff --git a/apps/files/l10n/pa.json b/apps/files/l10n/pa.json
index c1f4dae97fa..6d7025feec1 100644
--- a/apps/files/l10n/pa.json
+++ b/apps/files/l10n/pa.json
@@ -5,7 +5,6 @@
"Rename" : "ਨਾਂ ਬਦਲੋ",
"Delete" : "ਹਟਾਓ",
"Details" : "ਵੇਰਵ",
- "Error" : "ਗਲਤੀ",
"Upload" : "ਅੱਪਲੋਡ",
"Settings" : "ਸੈਟਿੰਗ",
"Cancel upload" : "ਅੱਪਲੋਡ ਰੱਦ ਕਰੋ"
diff --git a/apps/files/l10n/pl.js b/apps/files/l10n/pl.js
index e7a208bc639..e28b7bc2581 100644
--- a/apps/files/l10n/pl.js
+++ b/apps/files/l10n/pl.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Pamięć nie dostępna",
"Storage invalid" : "Pamięć nieprawidłowa",
"Unknown error" : "Nieznany błąd",
- "Could not move %s - File with this name already exists" : "Nie można było przenieść %s - Plik o takiej nazwie już istnieje",
- "Could not move %s" : "Nie można było przenieść %s",
- "Permission denied" : "Dostęp zabroniony",
- "The target folder has been moved or deleted." : "Folder docelowy został przeniesiony lub usunięty",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nazwa %s jest już używana w folderze %s. Proszę wybrać inną nazwę.",
- "Error when creating the file" : "Błąd przy tworzeniu pliku",
- "Error when creating the folder" : "Błąd przy tworzeniu folderu",
"Unable to set upload directory." : "Nie można ustawić katalog wczytywania.",
"Invalid Token" : "Nieprawidłowy Token",
"No file was uploaded. Unknown error" : "Żaden plik nie został załadowany. Nieznany błąd",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Brak folderu tymczasowego",
"Failed to write to disk" : "Błąd zapisu na dysk",
"Not enough storage available" : "Za mało dostępnego miejsca",
+ "The target folder has been moved or deleted." : "Folder docelowy został przeniesiony lub usunięty",
"Upload failed. Could not find uploaded file" : "Nieudane przesłanie. Nie można znaleźć przesyłanego pliku",
"Upload failed. Could not get file info." : "Nieudane przesłanie. Nie można pobrać informacji o pliku.",
"Invalid directory." : "Zła ścieżka.",
@@ -40,18 +34,12 @@ OC.L10N.register(
"Download" : "Pobierz",
"Rename" : "Zmień nazwę",
"Delete" : "Usuń",
+ "Disconnect storage" : "Odłącz magazyn",
+ "Unshare" : "Zatrzymaj współdzielenie",
"Details" : "Szczegóły",
"Select" : "Wybierz",
"Pending" : "Oczekujące",
"Unable to determine date" : "Nie można ustalić daty",
- "Error moving file." : "Błąd podczas przenoszenia pliku.",
- "Error moving file" : "Błąd prz przenoszeniu pliku",
- "Error" : "Błąd",
- "{new_name} already exists" : "{new_name} już istnieje",
- "Could not rename file" : "Nie można zmienić nazwy pliku",
- "Could not create file" : "Nie można utworzyć pliku",
- "Could not create folder" : "Nie można utworzyć folderu",
- "Error deleting file." : "Błąd podczas usuwania pliku",
"No entries in this folder match '{filter}'" : "Brak wyników pasujących do '{filter}'",
"Name" : "Nazwa",
"Size" : "Rozmiar",
@@ -70,7 +58,6 @@ OC.L10N.register(
"Your storage is almost full ({usedSpacePercent}%)" : "Twój magazyn jest prawie pełny ({usedSpacePercent}%)",
"Favorited" : "Ulubione",
"Favorite" : "Ulubione",
- "Text file" : "Plik tekstowy",
"Folder" : "Folder",
"New folder" : "Nowy folder",
"Upload" : "Wyślij",
@@ -87,8 +74,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s usunął %1$s",
"You restored %1$s" : "Przywróciłeś %1$s",
"%2$s restored %1$s" : "%2$s przywrócił %1$s",
- "%s could not be renamed as it has been deleted" : "%s nie może mieć zmienionej nazwy, ponieważ został usunięty",
- "%s could not be renamed" : "%s nie można zmienić nazwy",
"Upload (max. %s)" : "Wysyłka (max. %s)",
"File handling" : "Zarządzanie plikami",
"Maximum upload size" : "Maksymalny rozmiar wysyłanego pliku",
@@ -102,7 +87,6 @@ OC.L10N.register(
"Select all" : "Wybierz wszystko",
"Upload too large" : "Ładowany plik jest za duży",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Pliki, które próbujesz przesłać, przekraczają maksymalną dopuszczalną wielkość.",
- "Files are being scanned, please wait." : "Skanowanie plików, proszę czekać.",
- "Currently scanning" : "Aktualnie skanowane"
+ "Text file" : "Plik tekstowy"
},
"nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files/l10n/pl.json b/apps/files/l10n/pl.json
index 4af3ab766e4..314caeb807a 100644
--- a/apps/files/l10n/pl.json
+++ b/apps/files/l10n/pl.json
@@ -2,13 +2,6 @@
"Storage not available" : "Pamięć nie dostępna",
"Storage invalid" : "Pamięć nieprawidłowa",
"Unknown error" : "Nieznany błąd",
- "Could not move %s - File with this name already exists" : "Nie można było przenieść %s - Plik o takiej nazwie już istnieje",
- "Could not move %s" : "Nie można było przenieść %s",
- "Permission denied" : "Dostęp zabroniony",
- "The target folder has been moved or deleted." : "Folder docelowy został przeniesiony lub usunięty",
- "The name %s is already used in the folder %s. Please choose a different name." : "Nazwa %s jest już używana w folderze %s. Proszę wybrać inną nazwę.",
- "Error when creating the file" : "Błąd przy tworzeniu pliku",
- "Error when creating the folder" : "Błąd przy tworzeniu folderu",
"Unable to set upload directory." : "Nie można ustawić katalog wczytywania.",
"Invalid Token" : "Nieprawidłowy Token",
"No file was uploaded. Unknown error" : "Żaden plik nie został załadowany. Nieznany błąd",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Brak folderu tymczasowego",
"Failed to write to disk" : "Błąd zapisu na dysk",
"Not enough storage available" : "Za mało dostępnego miejsca",
+ "The target folder has been moved or deleted." : "Folder docelowy został przeniesiony lub usunięty",
"Upload failed. Could not find uploaded file" : "Nieudane przesłanie. Nie można znaleźć przesyłanego pliku",
"Upload failed. Could not get file info." : "Nieudane przesłanie. Nie można pobrać informacji o pliku.",
"Invalid directory." : "Zła ścieżka.",
@@ -38,18 +32,12 @@
"Download" : "Pobierz",
"Rename" : "Zmień nazwę",
"Delete" : "Usuń",
+ "Disconnect storage" : "Odłącz magazyn",
+ "Unshare" : "Zatrzymaj współdzielenie",
"Details" : "Szczegóły",
"Select" : "Wybierz",
"Pending" : "Oczekujące",
"Unable to determine date" : "Nie można ustalić daty",
- "Error moving file." : "Błąd podczas przenoszenia pliku.",
- "Error moving file" : "Błąd prz przenoszeniu pliku",
- "Error" : "Błąd",
- "{new_name} already exists" : "{new_name} już istnieje",
- "Could not rename file" : "Nie można zmienić nazwy pliku",
- "Could not create file" : "Nie można utworzyć pliku",
- "Could not create folder" : "Nie można utworzyć folderu",
- "Error deleting file." : "Błąd podczas usuwania pliku",
"No entries in this folder match '{filter}'" : "Brak wyników pasujących do '{filter}'",
"Name" : "Nazwa",
"Size" : "Rozmiar",
@@ -68,7 +56,6 @@
"Your storage is almost full ({usedSpacePercent}%)" : "Twój magazyn jest prawie pełny ({usedSpacePercent}%)",
"Favorited" : "Ulubione",
"Favorite" : "Ulubione",
- "Text file" : "Plik tekstowy",
"Folder" : "Folder",
"New folder" : "Nowy folder",
"Upload" : "Wyślij",
@@ -85,8 +72,6 @@
"%2$s deleted %1$s" : "%2$s usunął %1$s",
"You restored %1$s" : "Przywróciłeś %1$s",
"%2$s restored %1$s" : "%2$s przywrócił %1$s",
- "%s could not be renamed as it has been deleted" : "%s nie może mieć zmienionej nazwy, ponieważ został usunięty",
- "%s could not be renamed" : "%s nie można zmienić nazwy",
"Upload (max. %s)" : "Wysyłka (max. %s)",
"File handling" : "Zarządzanie plikami",
"Maximum upload size" : "Maksymalny rozmiar wysyłanego pliku",
@@ -100,7 +85,6 @@
"Select all" : "Wybierz wszystko",
"Upload too large" : "Ładowany plik jest za duży",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Pliki, które próbujesz przesłać, przekraczają maksymalną dopuszczalną wielkość.",
- "Files are being scanned, please wait." : "Skanowanie plików, proszę czekać.",
- "Currently scanning" : "Aktualnie skanowane"
+ "Text file" : "Plik tekstowy"
},"pluralForm" :"nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files/l10n/pt_BR.js b/apps/files/l10n/pt_BR.js
index b7a2196db63..aaa655baf5f 100644
--- a/apps/files/l10n/pt_BR.js
+++ b/apps/files/l10n/pt_BR.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Armazanamento não disponível",
"Storage invalid" : "Armazenamento invávilido",
"Unknown error" : "Erro desconhecido",
- "Could not move %s - File with this name already exists" : "Impossível mover %s - Já existe um arquivo com esse nome",
- "Could not move %s" : "Impossível mover %s",
- "Permission denied" : "Permissão Negada",
- "The target folder has been moved or deleted." : "A pasta de destino foi movida ou excluída.",
- "The name %s is already used in the folder %s. Please choose a different name." : "O nome %s já é usado na pasta %s. Por favor, escolha um nome diferente.",
- "Error when creating the file" : "Erro ao criar o arquivo",
- "Error when creating the folder" : "Erro ao criar a pasta",
"Unable to set upload directory." : "Impossível configurar o diretório de envio",
"Invalid Token" : "Token inválido",
"No file was uploaded. Unknown error" : "Nenhum arquivo foi enviado. Erro desconhecido",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Pasta temporária não encontrada",
"Failed to write to disk" : "Falha ao escrever no disco",
"Not enough storage available" : "Espaço de armazenamento insuficiente",
+ "The target folder has been moved or deleted." : "A pasta de destino foi movida ou excluída.",
"Upload failed. Could not find uploaded file" : "Falha no envio. Não foi possível encontrar o arquivo enviado",
"Upload failed. Could not get file info." : "Falha no envio. Não foi possível obter informações do arquivo.",
"Invalid directory." : "Diretório inválido.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Baixar",
"Rename" : "Renomear",
"Delete" : "Excluir",
+ "Disconnect storage" : "Desconectar armazenamento",
+ "Unshare" : "Descompartilhar",
"Details" : "Detalhes",
"Select" : "Selecionar",
"Pending" : "Pendente",
"Unable to determine date" : "Impossível determinar a data",
"This operation is forbidden" : "Esta operação é proibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Este diretório não está disponível, por favor, verifique os logs ou entre em contato com o administrador",
- "Error moving file." : "Erro movendo o arquivo.",
- "Error moving file" : "Erro movendo o arquivo",
- "Error" : "Erro",
- "{new_name} already exists" : "{new_name} já existe",
- "Could not rename file" : "Não foi possível renomear o arquivo",
- "Could not create file" : "Não foi possível criar o arquivo",
- "Could not create folder" : "Não foi possível criar a pasta",
- "Error deleting file." : "Erro eliminando o arquivo.",
+ "Could not move \"{file}\", target exists" : "Não foi possível mover o \"{file}\", o alvo já existe",
+ "Could not move \"{file}\"" : "Não foi possível mover \"{file}\"",
+ "{newName} already exists" : "{newName} já existe",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Não foi possível renomear \"{fileName}\", ele já não existe",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "O nome \"{targetName}\" já está sendo usado na pasta \"{dir}\". Por favor escolha um outro nome.",
+ "Could not rename \"{fileName}\"" : "Não foi possível renomear \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Não foi possível criar o arquivo \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Não foi possível criar o arquivo \"{file}\" porque ele já existe",
+ "Could not create folder \"{dir}\"" : "Não foi possível criar a pasta \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Não foi possível criar a pasta \"{dir}\" porque ela já existe",
+ "Error deleting file \"{fileName}\"." : "Ocorreu um erro ao apagar o arquivo \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Nenhuma entrada nesta pasta coincide com '{filter}'",
"Name" : "Nome",
"Size" : "Tamanho",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Favorito",
"Favorite" : "Favorito",
- "Text file" : "Arquivo texto",
- "New text file.txt" : "Novo texto file.txt",
"Folder" : "Pasta",
"New folder" : "Nova pasta",
"{newname} already exists" : "{newname} já existe",
@@ -84,7 +81,7 @@ OC.L10N.register(
"An error occurred while trying to update the tags" : "Ocorreu um erro enquanto tentava atualizar as etiquetas",
"A new file or folder has been <strong>created</strong>" : "Um novo arquivo ou pasta foi <strong>criado</strong>",
"A file or folder has been <strong>changed</strong>" : "Um arquivo ou pasta foi <strong>modificado</strong>",
- "Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Limite de notificações sobre a criação e alterações em seus <strong>arquivos favoritos</strong> <em>(Stream apenas)</em>",
+ "Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Limite de notificações sobre a criação e alterações em seus <strong>arquivos favoritos</strong> <em>(apenas Stream)</em>",
"A file or folder has been <strong>deleted</strong>" : "Um arquivo ou pasta foi <strong>excluído</strong>",
"A file or folder has been <strong>restored</strong>" : "Um arquivo ou pasta foi <strong>restautado</strong>",
"You created %1$s" : "Você criou %1$s",
@@ -99,8 +96,6 @@ OC.L10N.register(
"Changed by %2$s" : "Modificado por %2$s",
"Deleted by %2$s" : "Deletado por %2$s",
"Restored by %2$s" : "Restaurado por %2$s",
- "%s could not be renamed as it has been deleted" : "%s não pode ser renomeado pois foi apagado",
- "%s could not be renamed" : "%s não pode ser renomeado",
"Upload (max. %s)" : "Envio (max. %s)",
"File handling" : "Tratamento de Arquivo",
"Maximum upload size" : "Tamanho máximo para envio",
@@ -118,9 +113,9 @@ OC.L10N.register(
"Select all" : "Selecionar tudo",
"Upload too large" : "Arquivo muito grande para envio",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Os arquivos que você está tentando enviar excedeu o tamanho máximo para arquivos no servidor.",
- "Files are being scanned, please wait." : "Arquivos sendo escaneados, por favor aguarde.",
- "Currently scanning" : "Atualmente escaneando",
"No favorites" : "Sem favoritos",
- "Files and folders you mark as favorite will show up here" : "Arquivos e pastas que você marcou como favorito são mostrados aqui"
+ "Files and folders you mark as favorite will show up here" : "Arquivos e pastas que você marcou como favoritos são mostrados aqui",
+ "Text file" : "Arquivo texto",
+ "New text file.txt" : "Novo texto file.txt"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files/l10n/pt_BR.json b/apps/files/l10n/pt_BR.json
index 335b50a2d7d..111695612ce 100644
--- a/apps/files/l10n/pt_BR.json
+++ b/apps/files/l10n/pt_BR.json
@@ -2,13 +2,6 @@
"Storage not available" : "Armazanamento não disponível",
"Storage invalid" : "Armazenamento invávilido",
"Unknown error" : "Erro desconhecido",
- "Could not move %s - File with this name already exists" : "Impossível mover %s - Já existe um arquivo com esse nome",
- "Could not move %s" : "Impossível mover %s",
- "Permission denied" : "Permissão Negada",
- "The target folder has been moved or deleted." : "A pasta de destino foi movida ou excluída.",
- "The name %s is already used in the folder %s. Please choose a different name." : "O nome %s já é usado na pasta %s. Por favor, escolha um nome diferente.",
- "Error when creating the file" : "Erro ao criar o arquivo",
- "Error when creating the folder" : "Erro ao criar a pasta",
"Unable to set upload directory." : "Impossível configurar o diretório de envio",
"Invalid Token" : "Token inválido",
"No file was uploaded. Unknown error" : "Nenhum arquivo foi enviado. Erro desconhecido",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Pasta temporária não encontrada",
"Failed to write to disk" : "Falha ao escrever no disco",
"Not enough storage available" : "Espaço de armazenamento insuficiente",
+ "The target folder has been moved or deleted." : "A pasta de destino foi movida ou excluída.",
"Upload failed. Could not find uploaded file" : "Falha no envio. Não foi possível encontrar o arquivo enviado",
"Upload failed. Could not get file info." : "Falha no envio. Não foi possível obter informações do arquivo.",
"Invalid directory." : "Diretório inválido.",
@@ -38,20 +32,25 @@
"Download" : "Baixar",
"Rename" : "Renomear",
"Delete" : "Excluir",
+ "Disconnect storage" : "Desconectar armazenamento",
+ "Unshare" : "Descompartilhar",
"Details" : "Detalhes",
"Select" : "Selecionar",
"Pending" : "Pendente",
"Unable to determine date" : "Impossível determinar a data",
"This operation is forbidden" : "Esta operação é proibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Este diretório não está disponível, por favor, verifique os logs ou entre em contato com o administrador",
- "Error moving file." : "Erro movendo o arquivo.",
- "Error moving file" : "Erro movendo o arquivo",
- "Error" : "Erro",
- "{new_name} already exists" : "{new_name} já existe",
- "Could not rename file" : "Não foi possível renomear o arquivo",
- "Could not create file" : "Não foi possível criar o arquivo",
- "Could not create folder" : "Não foi possível criar a pasta",
- "Error deleting file." : "Erro eliminando o arquivo.",
+ "Could not move \"{file}\", target exists" : "Não foi possível mover o \"{file}\", o alvo já existe",
+ "Could not move \"{file}\"" : "Não foi possível mover \"{file}\"",
+ "{newName} already exists" : "{newName} já existe",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Não foi possível renomear \"{fileName}\", ele já não existe",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "O nome \"{targetName}\" já está sendo usado na pasta \"{dir}\". Por favor escolha um outro nome.",
+ "Could not rename \"{fileName}\"" : "Não foi possível renomear \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Não foi possível criar o arquivo \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Não foi possível criar o arquivo \"{file}\" porque ele já existe",
+ "Could not create folder \"{dir}\"" : "Não foi possível criar a pasta \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Não foi possível criar a pasta \"{dir}\" porque ela já existe",
+ "Error deleting file \"{fileName}\"." : "Ocorreu um erro ao apagar o arquivo \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Nenhuma entrada nesta pasta coincide com '{filter}'",
"Name" : "Nome",
"Size" : "Tamanho",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Favorito",
"Favorite" : "Favorito",
- "Text file" : "Arquivo texto",
- "New text file.txt" : "Novo texto file.txt",
"Folder" : "Pasta",
"New folder" : "Nova pasta",
"{newname} already exists" : "{newname} já existe",
@@ -82,7 +79,7 @@
"An error occurred while trying to update the tags" : "Ocorreu um erro enquanto tentava atualizar as etiquetas",
"A new file or folder has been <strong>created</strong>" : "Um novo arquivo ou pasta foi <strong>criado</strong>",
"A file or folder has been <strong>changed</strong>" : "Um arquivo ou pasta foi <strong>modificado</strong>",
- "Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Limite de notificações sobre a criação e alterações em seus <strong>arquivos favoritos</strong> <em>(Stream apenas)</em>",
+ "Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Limite de notificações sobre a criação e alterações em seus <strong>arquivos favoritos</strong> <em>(apenas Stream)</em>",
"A file or folder has been <strong>deleted</strong>" : "Um arquivo ou pasta foi <strong>excluído</strong>",
"A file or folder has been <strong>restored</strong>" : "Um arquivo ou pasta foi <strong>restautado</strong>",
"You created %1$s" : "Você criou %1$s",
@@ -97,8 +94,6 @@
"Changed by %2$s" : "Modificado por %2$s",
"Deleted by %2$s" : "Deletado por %2$s",
"Restored by %2$s" : "Restaurado por %2$s",
- "%s could not be renamed as it has been deleted" : "%s não pode ser renomeado pois foi apagado",
- "%s could not be renamed" : "%s não pode ser renomeado",
"Upload (max. %s)" : "Envio (max. %s)",
"File handling" : "Tratamento de Arquivo",
"Maximum upload size" : "Tamanho máximo para envio",
@@ -116,9 +111,9 @@
"Select all" : "Selecionar tudo",
"Upload too large" : "Arquivo muito grande para envio",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Os arquivos que você está tentando enviar excedeu o tamanho máximo para arquivos no servidor.",
- "Files are being scanned, please wait." : "Arquivos sendo escaneados, por favor aguarde.",
- "Currently scanning" : "Atualmente escaneando",
"No favorites" : "Sem favoritos",
- "Files and folders you mark as favorite will show up here" : "Arquivos e pastas que você marcou como favorito são mostrados aqui"
+ "Files and folders you mark as favorite will show up here" : "Arquivos e pastas que você marcou como favoritos são mostrados aqui",
+ "Text file" : "Arquivo texto",
+ "New text file.txt" : "Novo texto file.txt"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/pt_PT.js b/apps/files/l10n/pt_PT.js
index 537abb936b1..0e6c7d2b355 100644
--- a/apps/files/l10n/pt_PT.js
+++ b/apps/files/l10n/pt_PT.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Armazenamento indisposinvel",
"Storage invalid" : "Armazenamento inválido",
"Unknown error" : "Erro Desconhecido",
- "Could not move %s - File with this name already exists" : "Não foi possível mover %s - Já existe um ficheiro com este nome",
- "Could not move %s" : "Não foi possível mover %s",
- "Permission denied" : "Permissão negada",
- "The target folder has been moved or deleted." : "A pasta de destino foi movida ou eliminada.",
- "The name %s is already used in the folder %s. Please choose a different name." : "O nome %s já está em uso na pasta %s. Por favor escolha um nome diferente.",
- "Error when creating the file" : "Erro ao criar o ficheiro",
- "Error when creating the folder" : "Erro ao criar a pasta",
"Unable to set upload directory." : "Não foi possível criar o diretório de upload",
"Invalid Token" : "Token inválido",
"No file was uploaded. Unknown error" : "Não foi enviado nenhum ficheiro. Erro desconhecido",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "A pasta temporária está em falta",
"Failed to write to disk" : "Não foi possível gravar no disco",
"Not enough storage available" : "Não há espaço suficiente em disco",
+ "The target folder has been moved or deleted." : "A pasta de destino foi movida ou eliminada.",
"Upload failed. Could not find uploaded file" : "Falhou o envio. Não conseguiu encontrar o ficheiro enviado",
"Upload failed. Could not get file info." : "O carregamento falhou. Não foi possível obter a informação do ficheiro.",
"Invalid directory." : "Diretoria inválida.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Descarregar",
"Rename" : "Renomear",
"Delete" : "Apagar",
+ "Disconnect storage" : "Desconete o armazenamento",
+ "Unshare" : "Cancelar partilha",
"Details" : "Detalhes",
"Select" : "Selecionar",
"Pending" : "Pendente",
"Unable to determine date" : "Impossível determinar a data",
"This operation is forbidden" : "Esta operação é proibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Esta diretoria está indisponível, por favor, verifique os registos ou contacte o administrador",
- "Error moving file." : "Erro a mover o ficheiro.",
- "Error moving file" : "Erro ao mover o ficheiro",
- "Error" : "Erro",
- "{new_name} already exists" : "O nome {new_name} já existe",
- "Could not rename file" : "Não pôde renomear o ficheiro",
- "Could not create file" : "Não pôde criar ficheiro",
- "Could not create folder" : "Não pôde criar pasta",
- "Error deleting file." : "Erro ao apagar o ficheiro.",
+ "Could not move \"{file}\", target exists" : "Não foi possível mover \"{file}\", alvo já existe",
+ "Could not move \"{file}\"" : "Não foi possivel mover o ficheiro \"{file}\"",
+ "{newName} already exists" : "{newName} já existe",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Não foi possível renomear \"{fileName}\", pois já não existe",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "O nome \"{targetName}\" já está em uso na pasta \"{dir}\". Por favor escolha um nome diferente.",
+ "Could not rename \"{fileName}\"" : "Não foi possível renomear \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Não foi possível criar o ficheiro \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Não foi possível criar o ficheiro \"{file}\", porque este já existe",
+ "Could not create folder \"{dir}\"" : "Não foi possível criar a pasta \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Não foi possível criar a pasta \"{dir}\", porque esta já existe",
+ "Error deleting file \"{fileName}\"." : "Erro ao apagar o ficheiro \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Nenhumas entradas nesta pasta correspondem a '{filter}'",
"Name" : "Nome",
"Size" : "Tamanho",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Assinalado como Favorito",
"Favorite" : "Favorito",
- "Text file" : "Ficheiro de Texto",
- "New text file.txt" : "Novo texto ficheiro.txt",
"Folder" : "Pasta",
"New folder" : "Nova Pasta",
"{newname} already exists" : "{newname} já existe",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "Alterado por %2$s",
"Deleted by %2$s" : "Eliminado por %2$s",
"Restored by %2$s" : "Restaurado por %2$s",
- "%s could not be renamed as it has been deleted" : "Não foi possível renomear %s devido a ter sido eliminado",
- "%s could not be renamed" : "%s não pode ser renomeada",
"Upload (max. %s)" : "Enviar (max. %s)",
"File handling" : "Manuseamento do ficheiro",
"Maximum upload size" : "Tamanho máximo de envio",
"max. possible: " : "Máx. possível: ",
"Save" : "Guardar",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Com o PHP-FPM pode demorar 5 minutos até que as alterações sejam aplicadas.",
+ "Missing permissions to edit from here." : "Faltam permissões para editar a partir daqui.",
"Settings" : "Definições",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Utilize esta ligação para <a href=\"%s\" target=\"_blank\">aceder aos seus ficheiros via WebDAV</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "Seleccionar todos",
"Upload too large" : "Upload muito grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Os ficheiro que está a tentar enviar excedem o tamanho máximo de envio neste servidor.",
- "Files are being scanned, please wait." : "Os ficheiros estão a ser analisados, por favor aguarde.",
- "Currently scanning" : "A analisar",
"No favorites" : "Sem favoritos",
- "Files and folders you mark as favorite will show up here" : "Os ficheiros e pastas que marcou como favoritos serão mostrados aqui"
+ "Files and folders you mark as favorite will show up here" : "Os ficheiros e pastas que marcou como favoritos serão mostrados aqui",
+ "Text file" : "Ficheiro de Texto",
+ "New text file.txt" : "Novo texto ficheiro.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/pt_PT.json b/apps/files/l10n/pt_PT.json
index 20e8dd808cc..1879f7b1ecf 100644
--- a/apps/files/l10n/pt_PT.json
+++ b/apps/files/l10n/pt_PT.json
@@ -2,13 +2,6 @@
"Storage not available" : "Armazenamento indisposinvel",
"Storage invalid" : "Armazenamento inválido",
"Unknown error" : "Erro Desconhecido",
- "Could not move %s - File with this name already exists" : "Não foi possível mover %s - Já existe um ficheiro com este nome",
- "Could not move %s" : "Não foi possível mover %s",
- "Permission denied" : "Permissão negada",
- "The target folder has been moved or deleted." : "A pasta de destino foi movida ou eliminada.",
- "The name %s is already used in the folder %s. Please choose a different name." : "O nome %s já está em uso na pasta %s. Por favor escolha um nome diferente.",
- "Error when creating the file" : "Erro ao criar o ficheiro",
- "Error when creating the folder" : "Erro ao criar a pasta",
"Unable to set upload directory." : "Não foi possível criar o diretório de upload",
"Invalid Token" : "Token inválido",
"No file was uploaded. Unknown error" : "Não foi enviado nenhum ficheiro. Erro desconhecido",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "A pasta temporária está em falta",
"Failed to write to disk" : "Não foi possível gravar no disco",
"Not enough storage available" : "Não há espaço suficiente em disco",
+ "The target folder has been moved or deleted." : "A pasta de destino foi movida ou eliminada.",
"Upload failed. Could not find uploaded file" : "Falhou o envio. Não conseguiu encontrar o ficheiro enviado",
"Upload failed. Could not get file info." : "O carregamento falhou. Não foi possível obter a informação do ficheiro.",
"Invalid directory." : "Diretoria inválida.",
@@ -38,20 +32,25 @@
"Download" : "Descarregar",
"Rename" : "Renomear",
"Delete" : "Apagar",
+ "Disconnect storage" : "Desconete o armazenamento",
+ "Unshare" : "Cancelar partilha",
"Details" : "Detalhes",
"Select" : "Selecionar",
"Pending" : "Pendente",
"Unable to determine date" : "Impossível determinar a data",
"This operation is forbidden" : "Esta operação é proibida",
"This directory is unavailable, please check the logs or contact the administrator" : "Esta diretoria está indisponível, por favor, verifique os registos ou contacte o administrador",
- "Error moving file." : "Erro a mover o ficheiro.",
- "Error moving file" : "Erro ao mover o ficheiro",
- "Error" : "Erro",
- "{new_name} already exists" : "O nome {new_name} já existe",
- "Could not rename file" : "Não pôde renomear o ficheiro",
- "Could not create file" : "Não pôde criar ficheiro",
- "Could not create folder" : "Não pôde criar pasta",
- "Error deleting file." : "Erro ao apagar o ficheiro.",
+ "Could not move \"{file}\", target exists" : "Não foi possível mover \"{file}\", alvo já existe",
+ "Could not move \"{file}\"" : "Não foi possivel mover o ficheiro \"{file}\"",
+ "{newName} already exists" : "{newName} já existe",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Não foi possível renomear \"{fileName}\", pois já não existe",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "O nome \"{targetName}\" já está em uso na pasta \"{dir}\". Por favor escolha um nome diferente.",
+ "Could not rename \"{fileName}\"" : "Não foi possível renomear \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Não foi possível criar o ficheiro \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Não foi possível criar o ficheiro \"{file}\", porque este já existe",
+ "Could not create folder \"{dir}\"" : "Não foi possível criar a pasta \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Não foi possível criar a pasta \"{dir}\", porque esta já existe",
+ "Error deleting file \"{fileName}\"." : "Erro ao apagar o ficheiro \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Nenhumas entradas nesta pasta correspondem a '{filter}'",
"Name" : "Nome",
"Size" : "Tamanho",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Assinalado como Favorito",
"Favorite" : "Favorito",
- "Text file" : "Ficheiro de Texto",
- "New text file.txt" : "Novo texto ficheiro.txt",
"Folder" : "Pasta",
"New folder" : "Nova Pasta",
"{newname} already exists" : "{newname} já existe",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "Alterado por %2$s",
"Deleted by %2$s" : "Eliminado por %2$s",
"Restored by %2$s" : "Restaurado por %2$s",
- "%s could not be renamed as it has been deleted" : "Não foi possível renomear %s devido a ter sido eliminado",
- "%s could not be renamed" : "%s não pode ser renomeada",
"Upload (max. %s)" : "Enviar (max. %s)",
"File handling" : "Manuseamento do ficheiro",
"Maximum upload size" : "Tamanho máximo de envio",
"max. possible: " : "Máx. possível: ",
"Save" : "Guardar",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Com o PHP-FPM pode demorar 5 minutos até que as alterações sejam aplicadas.",
+ "Missing permissions to edit from here." : "Faltam permissões para editar a partir daqui.",
"Settings" : "Definições",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Utilize esta ligação para <a href=\"%s\" target=\"_blank\">aceder aos seus ficheiros via WebDAV</a>",
@@ -114,9 +111,9 @@
"Select all" : "Seleccionar todos",
"Upload too large" : "Upload muito grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Os ficheiro que está a tentar enviar excedem o tamanho máximo de envio neste servidor.",
- "Files are being scanned, please wait." : "Os ficheiros estão a ser analisados, por favor aguarde.",
- "Currently scanning" : "A analisar",
"No favorites" : "Sem favoritos",
- "Files and folders you mark as favorite will show up here" : "Os ficheiros e pastas que marcou como favoritos serão mostrados aqui"
+ "Files and folders you mark as favorite will show up here" : "Os ficheiros e pastas que marcou como favoritos serão mostrados aqui",
+ "Text file" : "Ficheiro de Texto",
+ "New text file.txt" : "Novo texto ficheiro.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/ro.js b/apps/files/l10n/ro.js
index c3dca30abed..bd869ce56d6 100644
--- a/apps/files/l10n/ro.js
+++ b/apps/files/l10n/ro.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Spațiu de stocare indisponibil",
"Storage invalid" : "Spațiu de stocare invalid",
"Unknown error" : "Eroare necunoscută",
- "Could not move %s - File with this name already exists" : "%s nu se poate muta - Fișierul cu acest nume există deja ",
- "Could not move %s" : "Nu se poate muta %s",
- "Permission denied" : "Accesul interzis",
- "The target folder has been moved or deleted." : "Dosarul țintă a fost mutat sau șters.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Numele %s este deja este folosit în dosarul %s. Te rog alege alt nume.",
- "Error when creating the file" : "Eroare la crearea fișierului",
- "Error when creating the folder" : "Eroare la crearea dosarului",
"Unable to set upload directory." : "Imposibil de a seta directorul pentru încărcare.",
"Invalid Token" : "Jeton Invalid",
"No file was uploaded. Unknown error" : "Niciun fișier nu a fost încărcat. Eroare necunoscută",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Lipsește un dosar temporar",
"Failed to write to disk" : "Eroare la scrierea pe disc",
"Not enough storage available" : "Nu este disponibil suficient spațiu",
+ "The target folder has been moved or deleted." : "Dosarul țintă a fost mutat sau șters.",
"Upload failed. Could not find uploaded file" : "Încărcare eșuată. Nu se poate găsi fișierul încărcat",
"Upload failed. Could not get file info." : "Încărcare eșuată. Nu se pot obține informații despre fișier.",
"Invalid directory." : "Dosar nevalid.",
@@ -40,17 +34,11 @@ OC.L10N.register(
"Download" : "Descarcă",
"Rename" : "Redenumește",
"Delete" : "Șterge",
+ "Disconnect storage" : "Deconectează stocarea",
+ "Unshare" : "Nu mai partaja",
"Details" : "Detalii",
"Select" : "Alege",
"Pending" : "În așteptare",
- "Error moving file." : "Eroare la mutarea fișierului.",
- "Error moving file" : "Eroare la mutarea fișierului",
- "Error" : "Eroare",
- "{new_name} already exists" : "{new_name} există deja",
- "Could not rename file" : "Nu s-a putut redenumi fișierul",
- "Could not create file" : "Nu s-a putut crea fisierul",
- "Could not create folder" : "Nu s-a putut crea folderul",
- "Error deleting file." : "Eroare la ștergerea fișierului.",
"Name" : "Nume",
"Size" : "Mărime",
"Modified" : "Modificat",
@@ -65,7 +53,6 @@ OC.L10N.register(
"Your storage is full, files can not be updated or synced anymore!" : "Spațiul de stocare este plin, fișierele nu mai pot fi actualizate sau sincronizate!",
"Your storage is almost full ({usedSpacePercent}%)" : "Spațiul de stocare este aproape plin ({usedSpacePercent}%)",
"Favorite" : "Favorit",
- "Text file" : "Fișier text",
"Folder" : "Dosar",
"New folder" : "Un nou dosar",
"Upload" : "Încărcă",
@@ -82,8 +69,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s a șters %1$s",
"You restored %1$s" : "Ai restaurat %1$s",
"%2$s restored %1$s" : "%2$s a restaurat %1$s",
- "%s could not be renamed as it has been deleted" : "%s nu a putut fi redenumit deoarece a fost sters",
- "%s could not be renamed" : "%s nu a putut fi redenumit",
"Upload (max. %s)" : "Încarcă (max. %s)",
"File handling" : "Manipulare fișiere",
"Maximum upload size" : "Dimensiune maximă admisă la încărcare",
@@ -96,7 +81,6 @@ OC.L10N.register(
"Select all" : "Selectează tot",
"Upload too large" : "Fișierul încărcat este prea mare",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Fișierele pe care încerci să le încarci depășesc limita de încărcare maximă admisă pe acest server.",
- "Files are being scanned, please wait." : "Fișierele sunt scanate, te rog așteaptă.",
- "Currently scanning" : "Acum scanează"
+ "Text file" : "Fișier text"
},
"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));");
diff --git a/apps/files/l10n/ro.json b/apps/files/l10n/ro.json
index 0d2f4497ff4..b842342a09a 100644
--- a/apps/files/l10n/ro.json
+++ b/apps/files/l10n/ro.json
@@ -2,13 +2,6 @@
"Storage not available" : "Spațiu de stocare indisponibil",
"Storage invalid" : "Spațiu de stocare invalid",
"Unknown error" : "Eroare necunoscută",
- "Could not move %s - File with this name already exists" : "%s nu se poate muta - Fișierul cu acest nume există deja ",
- "Could not move %s" : "Nu se poate muta %s",
- "Permission denied" : "Accesul interzis",
- "The target folder has been moved or deleted." : "Dosarul țintă a fost mutat sau șters.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Numele %s este deja este folosit în dosarul %s. Te rog alege alt nume.",
- "Error when creating the file" : "Eroare la crearea fișierului",
- "Error when creating the folder" : "Eroare la crearea dosarului",
"Unable to set upload directory." : "Imposibil de a seta directorul pentru încărcare.",
"Invalid Token" : "Jeton Invalid",
"No file was uploaded. Unknown error" : "Niciun fișier nu a fost încărcat. Eroare necunoscută",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Lipsește un dosar temporar",
"Failed to write to disk" : "Eroare la scrierea pe disc",
"Not enough storage available" : "Nu este disponibil suficient spațiu",
+ "The target folder has been moved or deleted." : "Dosarul țintă a fost mutat sau șters.",
"Upload failed. Could not find uploaded file" : "Încărcare eșuată. Nu se poate găsi fișierul încărcat",
"Upload failed. Could not get file info." : "Încărcare eșuată. Nu se pot obține informații despre fișier.",
"Invalid directory." : "Dosar nevalid.",
@@ -38,17 +32,11 @@
"Download" : "Descarcă",
"Rename" : "Redenumește",
"Delete" : "Șterge",
+ "Disconnect storage" : "Deconectează stocarea",
+ "Unshare" : "Nu mai partaja",
"Details" : "Detalii",
"Select" : "Alege",
"Pending" : "În așteptare",
- "Error moving file." : "Eroare la mutarea fișierului.",
- "Error moving file" : "Eroare la mutarea fișierului",
- "Error" : "Eroare",
- "{new_name} already exists" : "{new_name} există deja",
- "Could not rename file" : "Nu s-a putut redenumi fișierul",
- "Could not create file" : "Nu s-a putut crea fisierul",
- "Could not create folder" : "Nu s-a putut crea folderul",
- "Error deleting file." : "Eroare la ștergerea fișierului.",
"Name" : "Nume",
"Size" : "Mărime",
"Modified" : "Modificat",
@@ -63,7 +51,6 @@
"Your storage is full, files can not be updated or synced anymore!" : "Spațiul de stocare este plin, fișierele nu mai pot fi actualizate sau sincronizate!",
"Your storage is almost full ({usedSpacePercent}%)" : "Spațiul de stocare este aproape plin ({usedSpacePercent}%)",
"Favorite" : "Favorit",
- "Text file" : "Fișier text",
"Folder" : "Dosar",
"New folder" : "Un nou dosar",
"Upload" : "Încărcă",
@@ -80,8 +67,6 @@
"%2$s deleted %1$s" : "%2$s a șters %1$s",
"You restored %1$s" : "Ai restaurat %1$s",
"%2$s restored %1$s" : "%2$s a restaurat %1$s",
- "%s could not be renamed as it has been deleted" : "%s nu a putut fi redenumit deoarece a fost sters",
- "%s could not be renamed" : "%s nu a putut fi redenumit",
"Upload (max. %s)" : "Încarcă (max. %s)",
"File handling" : "Manipulare fișiere",
"Maximum upload size" : "Dimensiune maximă admisă la încărcare",
@@ -94,7 +79,6 @@
"Select all" : "Selectează tot",
"Upload too large" : "Fișierul încărcat este prea mare",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Fișierele pe care încerci să le încarci depășesc limita de încărcare maximă admisă pe acest server.",
- "Files are being scanned, please wait." : "Fișierele sunt scanate, te rog așteaptă.",
- "Currently scanning" : "Acum scanează"
+ "Text file" : "Fișier text"
},"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"
} \ No newline at end of file
diff --git a/apps/files/l10n/ru.js b/apps/files/l10n/ru.js
index 254e701a17c..510e8d8f08b 100644
--- a/apps/files/l10n/ru.js
+++ b/apps/files/l10n/ru.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Хранилище недоступно",
"Storage invalid" : "Хранилище неисправно",
"Unknown error" : "Неизвестная ошибка",
- "Could not move %s - File with this name already exists" : "Невозможно переместить %s - файл с таким именем уже существует",
- "Could not move %s" : "Невозможно переместить %s",
- "Permission denied" : "В доступе отказано",
- "The target folder has been moved or deleted." : "Целевой каталог был перемещен или удален.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Имя %s уже используется для каталога %s. Укажите другое имя.",
- "Error when creating the file" : "Ошибка при создании файла",
- "Error when creating the folder" : "Ошибка создания каталога",
"Unable to set upload directory." : "Невозможно установить каталог загрузки.",
"Invalid Token" : "Недопустимый маркер",
"No file was uploaded. Unknown error" : "Файл не был загружен. Неизвестная ошибка",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Отсутствует временный каталог",
"Failed to write to disk" : "Ошибка записи на диск",
"Not enough storage available" : "Недостаточно доступного места в хранилище",
+ "The target folder has been moved or deleted." : "Целевой каталог был перемещен или удален.",
"Upload failed. Could not find uploaded file" : "Загрузка не удалась. Невозможно найти загружаемый файл",
"Upload failed. Could not get file info." : "Загрузка не удалась. Невозможно получить информацию о файле",
"Invalid directory." : "Неверный каталог.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Скачать",
"Rename" : "Переименовать",
"Delete" : "Удалить",
+ "Disconnect storage" : "Отсоединить хранилище",
+ "Unshare" : "Закрыть доступ",
"Details" : "Подробно",
"Select" : "Выбрать",
"Pending" : "Ожидание",
"Unable to determine date" : "Невозможно определить дату",
"This operation is forbidden" : "Операция запрещена",
"This directory is unavailable, please check the logs or contact the administrator" : "Директория недоступна, пожалуйста проверьте журнал сообщений или свяжитесь с администратором",
- "Error moving file." : "Ошибка при перемещении файла.",
- "Error moving file" : "Ошибка при перемещении файла",
- "Error" : "Ошибка",
- "{new_name} already exists" : "{new_name} уже существует",
- "Could not rename file" : "Не удалось переименовать файл",
- "Could not create file" : "Не удалось создать файл",
- "Could not create folder" : "Не удалось создать каталог",
- "Error deleting file." : "Ошибка при удалении файла.",
+ "Could not move \"{file}\", target exists" : "Невозможно переместить \"{file}\", цель отсутствует",
+ "Could not move \"{file}\"" : "Невозможно переместить \"{file}\"",
+ "{newName} already exists" : "{newName} уже имеется",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Невозможно переименовать \"{fileName}\", файл больше не существует",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Имя \"{targetName}\" уже используется в каталоге \"{dir}\". Пожалуйста, выберите другое имя.",
+ "Could not rename \"{fileName}\"" : "Невозможно переименовать \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Невозможно создать файл \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Невозможно создать файл \"{file}\" потому что уже имеется",
+ "Could not create folder \"{dir}\"" : "Невозможно создать папку \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Невозможно создать папку \"{dir}\" потому что уже имеется",
+ "Error deleting file \"{fileName}\"." : "Ошибка удаления файла \"{fileName}\".",
"No entries in this folder match '{filter}'" : "В данном каталоге нет элементов соответствующих '{filter}'",
"Name" : "Имя",
"Size" : "Размер",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n байт","%n байта","%n байтов","%n байта(ов)"],
"Favorited" : "Избранное",
"Favorite" : "Избранное",
- "Text file" : "Текстовый файл",
- "New text file.txt" : "Новый текстовый документ.txt",
"Folder" : "Каталог",
"New folder" : "Новый каталог",
"{newname} already exists" : "{newname} уже существует",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "Изменено %2$s",
"Deleted by %2$s" : "Удалено %2$s",
"Restored by %2$s" : "Восстановлено %2$s",
- "%s could not be renamed as it has been deleted" : "Невозможно переименовать %s, поскольку объект удалён.",
- "%s could not be renamed" : "%s не может быть переименован",
"Upload (max. %s)" : "Загрузка (максимум %s)",
"File handling" : "Управление файлами",
"Maximum upload size" : "Максимальный размер загружаемого файла",
"max. possible: " : "макс. возможно: ",
"Save" : "Сохранить",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "В режиме PHP-FPM применение изменений может занять до 5 минут.",
+ "Missing permissions to edit from here." : "Отсутствуют права на удаление.",
"Settings" : "Настройки",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Используйте этот адрес для <a href=\"%s\" target=\"_blank\">доступа файлам через WebDAV</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "Выбрать все",
"Upload too large" : "Файл слишком велик",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Файлы, которые вы пытаетесь загрузить, превышают лимит максимального размера на этом сервере.",
- "Files are being scanned, please wait." : "Идет сканирование файлов. Пожалуйста подождите.",
- "Currently scanning" : "В настоящее время сканируется",
"No favorites" : "Нет избранного",
- "Files and folders you mark as favorite will show up here" : "Здесь появятся файлы и каталоги, отмеченные как избранные"
+ "Files and folders you mark as favorite will show up here" : "Здесь появятся файлы и каталоги, отмеченные как избранные",
+ "Text file" : "Текстовый файл",
+ "New text file.txt" : "Новый текстовый документ.txt"
},
"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/apps/files/l10n/ru.json b/apps/files/l10n/ru.json
index 7666ebb75d4..f62125fa614 100644
--- a/apps/files/l10n/ru.json
+++ b/apps/files/l10n/ru.json
@@ -2,13 +2,6 @@
"Storage not available" : "Хранилище недоступно",
"Storage invalid" : "Хранилище неисправно",
"Unknown error" : "Неизвестная ошибка",
- "Could not move %s - File with this name already exists" : "Невозможно переместить %s - файл с таким именем уже существует",
- "Could not move %s" : "Невозможно переместить %s",
- "Permission denied" : "В доступе отказано",
- "The target folder has been moved or deleted." : "Целевой каталог был перемещен или удален.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Имя %s уже используется для каталога %s. Укажите другое имя.",
- "Error when creating the file" : "Ошибка при создании файла",
- "Error when creating the folder" : "Ошибка создания каталога",
"Unable to set upload directory." : "Невозможно установить каталог загрузки.",
"Invalid Token" : "Недопустимый маркер",
"No file was uploaded. Unknown error" : "Файл не был загружен. Неизвестная ошибка",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Отсутствует временный каталог",
"Failed to write to disk" : "Ошибка записи на диск",
"Not enough storage available" : "Недостаточно доступного места в хранилище",
+ "The target folder has been moved or deleted." : "Целевой каталог был перемещен или удален.",
"Upload failed. Could not find uploaded file" : "Загрузка не удалась. Невозможно найти загружаемый файл",
"Upload failed. Could not get file info." : "Загрузка не удалась. Невозможно получить информацию о файле",
"Invalid directory." : "Неверный каталог.",
@@ -38,20 +32,25 @@
"Download" : "Скачать",
"Rename" : "Переименовать",
"Delete" : "Удалить",
+ "Disconnect storage" : "Отсоединить хранилище",
+ "Unshare" : "Закрыть доступ",
"Details" : "Подробно",
"Select" : "Выбрать",
"Pending" : "Ожидание",
"Unable to determine date" : "Невозможно определить дату",
"This operation is forbidden" : "Операция запрещена",
"This directory is unavailable, please check the logs or contact the administrator" : "Директория недоступна, пожалуйста проверьте журнал сообщений или свяжитесь с администратором",
- "Error moving file." : "Ошибка при перемещении файла.",
- "Error moving file" : "Ошибка при перемещении файла",
- "Error" : "Ошибка",
- "{new_name} already exists" : "{new_name} уже существует",
- "Could not rename file" : "Не удалось переименовать файл",
- "Could not create file" : "Не удалось создать файл",
- "Could not create folder" : "Не удалось создать каталог",
- "Error deleting file." : "Ошибка при удалении файла.",
+ "Could not move \"{file}\", target exists" : "Невозможно переместить \"{file}\", цель отсутствует",
+ "Could not move \"{file}\"" : "Невозможно переместить \"{file}\"",
+ "{newName} already exists" : "{newName} уже имеется",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Невозможно переименовать \"{fileName}\", файл больше не существует",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Имя \"{targetName}\" уже используется в каталоге \"{dir}\". Пожалуйста, выберите другое имя.",
+ "Could not rename \"{fileName}\"" : "Невозможно переименовать \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Невозможно создать файл \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Невозможно создать файл \"{file}\" потому что уже имеется",
+ "Could not create folder \"{dir}\"" : "Невозможно создать папку \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Невозможно создать папку \"{dir}\" потому что уже имеется",
+ "Error deleting file \"{fileName}\"." : "Ошибка удаления файла \"{fileName}\".",
"No entries in this folder match '{filter}'" : "В данном каталоге нет элементов соответствующих '{filter}'",
"Name" : "Имя",
"Size" : "Размер",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n байт","%n байта","%n байтов","%n байта(ов)"],
"Favorited" : "Избранное",
"Favorite" : "Избранное",
- "Text file" : "Текстовый файл",
- "New text file.txt" : "Новый текстовый документ.txt",
"Folder" : "Каталог",
"New folder" : "Новый каталог",
"{newname} already exists" : "{newname} уже существует",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "Изменено %2$s",
"Deleted by %2$s" : "Удалено %2$s",
"Restored by %2$s" : "Восстановлено %2$s",
- "%s could not be renamed as it has been deleted" : "Невозможно переименовать %s, поскольку объект удалён.",
- "%s could not be renamed" : "%s не может быть переименован",
"Upload (max. %s)" : "Загрузка (максимум %s)",
"File handling" : "Управление файлами",
"Maximum upload size" : "Максимальный размер загружаемого файла",
"max. possible: " : "макс. возможно: ",
"Save" : "Сохранить",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "В режиме PHP-FPM применение изменений может занять до 5 минут.",
+ "Missing permissions to edit from here." : "Отсутствуют права на удаление.",
"Settings" : "Настройки",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Используйте этот адрес для <a href=\"%s\" target=\"_blank\">доступа файлам через WebDAV</a>",
@@ -114,9 +111,9 @@
"Select all" : "Выбрать все",
"Upload too large" : "Файл слишком велик",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Файлы, которые вы пытаетесь загрузить, превышают лимит максимального размера на этом сервере.",
- "Files are being scanned, please wait." : "Идет сканирование файлов. Пожалуйста подождите.",
- "Currently scanning" : "В настоящее время сканируется",
"No favorites" : "Нет избранного",
- "Files and folders you mark as favorite will show up here" : "Здесь появятся файлы и каталоги, отмеченные как избранные"
+ "Files and folders you mark as favorite will show up here" : "Здесь появятся файлы и каталоги, отмеченные как избранные",
+ "Text file" : "Текстовый файл",
+ "New text file.txt" : "Новый текстовый документ.txt"
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files/l10n/si_LK.js b/apps/files/l10n/si_LK.js
index 9b2696d4530..4c26c421076 100644
--- a/apps/files/l10n/si_LK.js
+++ b/apps/files/l10n/si_LK.js
@@ -16,13 +16,12 @@ OC.L10N.register(
"Download" : "බාන්න",
"Rename" : "නැවත නම් කරන්න",
"Delete" : "මකා දමන්න",
+ "Unshare" : "නොබෙදු",
"Select" : "තෝරන්න",
- "Error" : "දෝෂයක්",
"Name" : "නම",
"Size" : "ප්‍රමාණය",
"Modified" : "වෙනස් කළ",
"New" : "නව",
- "Text file" : "පෙළ ගොනුව",
"Folder" : "ෆෝල්ඩරය",
"Upload" : "උඩුගත කරන්න",
"A new file or folder has been <strong>created</strong>" : "නව ගොනුවක් හෝ බහාලුමක් <strong> නිර්මාණය කර ඇත</ strong> ",
@@ -37,6 +36,6 @@ OC.L10N.register(
"Cancel upload" : "උඩුගත කිරීම අත් හරින්න",
"Upload too large" : "උඩුගත කිරීම විශාල වැඩිය",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "ඔබ උඩුගත කිරීමට තැත් කරන ගොනු මෙම සේවාදායකයා උඩුගත කිරීමට ඉඩදී ඇති උපරිම ගොනු විශාලත්වයට වඩා වැඩිය",
- "Files are being scanned, please wait." : "ගොනු පරික්ෂා කෙරේ. මඳක් රැඳී සිටින්න"
+ "Text file" : "පෙළ ගොනුව"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/si_LK.json b/apps/files/l10n/si_LK.json
index b46144f4881..2db6c10b75c 100644
--- a/apps/files/l10n/si_LK.json
+++ b/apps/files/l10n/si_LK.json
@@ -14,13 +14,12 @@
"Download" : "බාන්න",
"Rename" : "නැවත නම් කරන්න",
"Delete" : "මකා දමන්න",
+ "Unshare" : "නොබෙදු",
"Select" : "තෝරන්න",
- "Error" : "දෝෂයක්",
"Name" : "නම",
"Size" : "ප්‍රමාණය",
"Modified" : "වෙනස් කළ",
"New" : "නව",
- "Text file" : "පෙළ ගොනුව",
"Folder" : "ෆෝල්ඩරය",
"Upload" : "උඩුගත කරන්න",
"A new file or folder has been <strong>created</strong>" : "නව ගොනුවක් හෝ බහාලුමක් <strong> නිර්මාණය කර ඇත</ strong> ",
@@ -35,6 +34,6 @@
"Cancel upload" : "උඩුගත කිරීම අත් හරින්න",
"Upload too large" : "උඩුගත කිරීම විශාල වැඩිය",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "ඔබ උඩුගත කිරීමට තැත් කරන ගොනු මෙම සේවාදායකයා උඩුගත කිරීමට ඉඩදී ඇති උපරිම ගොනු විශාලත්වයට වඩා වැඩිය",
- "Files are being scanned, please wait." : "ගොනු පරික්ෂා කෙරේ. මඳක් රැඳී සිටින්න"
+ "Text file" : "පෙළ ගොනුව"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/sk_SK.js b/apps/files/l10n/sk_SK.js
index 1736a1f94c1..52711dd9c7b 100644
--- a/apps/files/l10n/sk_SK.js
+++ b/apps/files/l10n/sk_SK.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Úložisko nie je dostupné",
"Storage invalid" : "Úložisko nie je platné",
"Unknown error" : "Neznáma chyba",
- "Could not move %s - File with this name already exists" : "Nie je možné presunúť %s - súbor s týmto menom už existuje",
- "Could not move %s" : "Nie je možné presunúť %s",
- "Permission denied" : "Prístup bol odmietnutý",
- "The target folder has been moved or deleted." : "Cieľový priečinok bol premiestnený alebo odstránený.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Názov %s už používa priečinok s%. Prosím zvoľte iný názov.",
- "Error when creating the file" : "Chyba pri vytváraní súboru",
- "Error when creating the folder" : "Chyba pri vytváraní priečinka",
"Unable to set upload directory." : "Nemožno nastaviť priečinok pre nahrané súbory.",
"Invalid Token" : "Neplatný token",
"No file was uploaded. Unknown error" : "Žiaden súbor nebol nahraný. Neznáma chyba",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Chýba dočasný priečinok",
"Failed to write to disk" : "Zápis na disk sa nepodaril",
"Not enough storage available" : "Nedostatok dostupného úložného priestoru",
+ "The target folder has been moved or deleted." : "Cieľový priečinok bol premiestnený alebo odstránený.",
"Upload failed. Could not find uploaded file" : "Nahrávanie zlyhalo. Nepodarilo sa nájsť nahrávaný súbor",
"Upload failed. Could not get file info." : "Nahrávanie zlyhalo. Nepodarilo sa získať informácie o súbore.",
"Invalid directory." : "Neplatný priečinok.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "Sťahovanie",
"Rename" : "Premenovať",
"Delete" : "Zmazať",
+ "Disconnect storage" : "Odpojiť úložisko",
+ "Unshare" : "Zrušiť zdieľanie",
"Details" : "Podrobnosti",
"Select" : "Vybrať",
"Pending" : "Čaká",
"Unable to determine date" : "Nemožno určiť dátum",
"This operation is forbidden" : "Táto operácia je zakázaná",
"This directory is unavailable, please check the logs or contact the administrator" : "Priečinok je nedostupný, skontrolujte prosím logy, alebo kontaktujte správcu",
- "Error moving file." : "Chyba pri presune súboru.",
- "Error moving file" : "Chyba pri presúvaní súboru",
- "Error" : "Chyba",
- "{new_name} already exists" : "{new_name} už existuje",
- "Could not rename file" : "Nemožno premenovať súbor",
- "Could not create file" : "Nemožno vytvoriť súbor",
- "Could not create folder" : "Nemožno vytvoriť priečinok",
- "Error deleting file." : "Chyba pri mazaní súboru.",
"No entries in this folder match '{filter}'" : "V tomto priečinku nič nezodpovedá '{filter}'",
"Name" : "Názov",
"Size" : "Veľkosť",
@@ -75,8 +63,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n bajt","%n bajty","%n bajtov"],
"Favorited" : "Pridané k obľúbeným",
"Favorite" : "Obľúbené",
- "Text file" : "Textový súbor",
- "New text file.txt" : "Nový text file.txt",
"Folder" : "Priečinok",
"New folder" : "Nový priečinok",
"{newname} already exists" : "{newname} už existuje",
@@ -96,8 +82,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s zmazal %1$s",
"You restored %1$s" : "Bol obnovený %1$s",
"%2$s restored %1$s" : "%2$s obnovil %1$s",
- "%s could not be renamed as it has been deleted" : "%s nebolo možné premenovať, pretože bol zmazaný",
- "%s could not be renamed" : "%s nemohol byť premenovaný",
"Upload (max. %s)" : "Nahrať (max. %s)",
"File handling" : "Nastavenie správania sa k súborom",
"Maximum upload size" : "Maximálna veľkosť odosielaného súboru",
@@ -113,9 +97,9 @@ OC.L10N.register(
"Select all" : "Vybrať všetko",
"Upload too large" : "Nahrávanie je príliš veľké",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Súbory, ktoré sa snažíte nahrať, presahujú maximálnu veľkosť pre nahratie súborov na tento server.",
- "Files are being scanned, please wait." : "Čakajte, súbory sú prehľadávané.",
- "Currently scanning" : "Prehľadáva sa",
"No favorites" : "Žiadne obľúbené",
- "Files and folders you mark as favorite will show up here" : "Súbory a priečinky označené ako obľúbené budú zobrazené tu"
+ "Files and folders you mark as favorite will show up here" : "Súbory a priečinky označené ako obľúbené budú zobrazené tu",
+ "Text file" : "Textový súbor",
+ "New text file.txt" : "Nový text file.txt"
},
"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;");
diff --git a/apps/files/l10n/sk_SK.json b/apps/files/l10n/sk_SK.json
index 8936375cade..ca371eb189c 100644
--- a/apps/files/l10n/sk_SK.json
+++ b/apps/files/l10n/sk_SK.json
@@ -2,13 +2,6 @@
"Storage not available" : "Úložisko nie je dostupné",
"Storage invalid" : "Úložisko nie je platné",
"Unknown error" : "Neznáma chyba",
- "Could not move %s - File with this name already exists" : "Nie je možné presunúť %s - súbor s týmto menom už existuje",
- "Could not move %s" : "Nie je možné presunúť %s",
- "Permission denied" : "Prístup bol odmietnutý",
- "The target folder has been moved or deleted." : "Cieľový priečinok bol premiestnený alebo odstránený.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Názov %s už používa priečinok s%. Prosím zvoľte iný názov.",
- "Error when creating the file" : "Chyba pri vytváraní súboru",
- "Error when creating the folder" : "Chyba pri vytváraní priečinka",
"Unable to set upload directory." : "Nemožno nastaviť priečinok pre nahrané súbory.",
"Invalid Token" : "Neplatný token",
"No file was uploaded. Unknown error" : "Žiaden súbor nebol nahraný. Neznáma chyba",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Chýba dočasný priečinok",
"Failed to write to disk" : "Zápis na disk sa nepodaril",
"Not enough storage available" : "Nedostatok dostupného úložného priestoru",
+ "The target folder has been moved or deleted." : "Cieľový priečinok bol premiestnený alebo odstránený.",
"Upload failed. Could not find uploaded file" : "Nahrávanie zlyhalo. Nepodarilo sa nájsť nahrávaný súbor",
"Upload failed. Could not get file info." : "Nahrávanie zlyhalo. Nepodarilo sa získať informácie o súbore.",
"Invalid directory." : "Neplatný priečinok.",
@@ -38,20 +32,14 @@
"Download" : "Sťahovanie",
"Rename" : "Premenovať",
"Delete" : "Zmazať",
+ "Disconnect storage" : "Odpojiť úložisko",
+ "Unshare" : "Zrušiť zdieľanie",
"Details" : "Podrobnosti",
"Select" : "Vybrať",
"Pending" : "Čaká",
"Unable to determine date" : "Nemožno určiť dátum",
"This operation is forbidden" : "Táto operácia je zakázaná",
"This directory is unavailable, please check the logs or contact the administrator" : "Priečinok je nedostupný, skontrolujte prosím logy, alebo kontaktujte správcu",
- "Error moving file." : "Chyba pri presune súboru.",
- "Error moving file" : "Chyba pri presúvaní súboru",
- "Error" : "Chyba",
- "{new_name} already exists" : "{new_name} už existuje",
- "Could not rename file" : "Nemožno premenovať súbor",
- "Could not create file" : "Nemožno vytvoriť súbor",
- "Could not create folder" : "Nemožno vytvoriť priečinok",
- "Error deleting file." : "Chyba pri mazaní súboru.",
"No entries in this folder match '{filter}'" : "V tomto priečinku nič nezodpovedá '{filter}'",
"Name" : "Názov",
"Size" : "Veľkosť",
@@ -73,8 +61,6 @@
"_%n byte_::_%n bytes_" : ["%n bajt","%n bajty","%n bajtov"],
"Favorited" : "Pridané k obľúbeným",
"Favorite" : "Obľúbené",
- "Text file" : "Textový súbor",
- "New text file.txt" : "Nový text file.txt",
"Folder" : "Priečinok",
"New folder" : "Nový priečinok",
"{newname} already exists" : "{newname} už existuje",
@@ -94,8 +80,6 @@
"%2$s deleted %1$s" : "%2$s zmazal %1$s",
"You restored %1$s" : "Bol obnovený %1$s",
"%2$s restored %1$s" : "%2$s obnovil %1$s",
- "%s could not be renamed as it has been deleted" : "%s nebolo možné premenovať, pretože bol zmazaný",
- "%s could not be renamed" : "%s nemohol byť premenovaný",
"Upload (max. %s)" : "Nahrať (max. %s)",
"File handling" : "Nastavenie správania sa k súborom",
"Maximum upload size" : "Maximálna veľkosť odosielaného súboru",
@@ -111,9 +95,9 @@
"Select all" : "Vybrať všetko",
"Upload too large" : "Nahrávanie je príliš veľké",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Súbory, ktoré sa snažíte nahrať, presahujú maximálnu veľkosť pre nahratie súborov na tento server.",
- "Files are being scanned, please wait." : "Čakajte, súbory sú prehľadávané.",
- "Currently scanning" : "Prehľadáva sa",
"No favorites" : "Žiadne obľúbené",
- "Files and folders you mark as favorite will show up here" : "Súbory a priečinky označené ako obľúbené budú zobrazené tu"
+ "Files and folders you mark as favorite will show up here" : "Súbory a priečinky označené ako obľúbené budú zobrazené tu",
+ "Text file" : "Textový súbor",
+ "New text file.txt" : "Nový text file.txt"
},"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
} \ No newline at end of file
diff --git a/apps/files/l10n/sl.js b/apps/files/l10n/sl.js
index d89d31f6aea..dcdcae65dbf 100644
--- a/apps/files/l10n/sl.js
+++ b/apps/files/l10n/sl.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Na voljo ni dovolj prostora",
"Storage invalid" : "Določen prostor ni veljaven",
"Unknown error" : "Neznana napaka",
- "Could not move %s - File with this name already exists" : "Datoteke %s ni mogoče premakniti - datoteka s tem imenom že obstaja.",
- "Could not move %s" : "Datoteke %s ni mogoče premakniti",
- "Permission denied" : "Za to opravilo ni ustreznih dovoljenj.",
- "The target folder has been moved or deleted." : "Ciljna mapa je premaknjena ali izbrisana.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Ime %s je že v mapi %s že v uporabi. Izbrati je treba drugo ime.",
- "Error when creating the file" : "Napaka med ustvarjanjem datoteke",
- "Error when creating the folder" : "Napaka med ustvarjanjem mape",
"Unable to set upload directory." : "Mapo, v katero boste prenašali dokumente, ni mogoče določiti",
"Invalid Token" : "Neveljaven žeton",
"No file was uploaded. Unknown error" : "Ni poslane datoteke. Neznana napaka.",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Manjka začasna mapa",
"Failed to write to disk" : "Pisanje na disk je spodletelo",
"Not enough storage available" : "Na voljo ni dovolj prostora",
+ "The target folder has been moved or deleted." : "Ciljna mapa je premaknjena ali izbrisana.",
"Upload failed. Could not find uploaded file" : "Pošiljanje je spodletelo. Ni mogoče najti poslane datoteke.",
"Upload failed. Could not get file info." : "Pošiljanje je spodletelo. Ni mogoče pridobiti podrobnosti datoteke.",
"Invalid directory." : "Neveljavna mapa.",
@@ -40,18 +34,25 @@ OC.L10N.register(
"Download" : "Prejmi",
"Rename" : "Preimenuj",
"Delete" : "Izbriši",
+ "Disconnect storage" : "Odklopi shrambo",
+ "Unshare" : "Prekini souporabo",
"Details" : "Podrobnosti",
"Select" : "Izberi",
"Pending" : "V čakanju ...",
"Unable to determine date" : "Ni mogoče določiti datuma",
- "Error moving file." : "Napaka premikanja datoteke.",
- "Error moving file" : "Napaka premikanja datoteke",
- "Error" : "Napaka",
- "{new_name} already exists" : "{new_name} že obstaja",
- "Could not rename file" : "Ni mogoče preimenovati datoteke",
- "Could not create file" : "Ni mogoče ustvariti datoteke",
- "Could not create folder" : "Ni mogoče ustvariti mape",
- "Error deleting file." : "Napaka brisanja datoteke.",
+ "This operation is forbidden" : "To dejanje ni dovoljeno!",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Mapa ni na voljo. Preverite dnevnik in stopite v stik s skrbnikom sistema.",
+ "Could not move \"{file}\", target exists" : "Datoteke \"{file}\" ni mogoče premakniti, ker cilj že obstaja",
+ "Could not move \"{file}\"" : "Ni mogoče premakniti \"{file}\"",
+ "{newName} already exists" : "{newName} že obstaja",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Ni mogoče preimenovati \"{fileName}\", ker datoteka ne obstaja več",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Ime \"{targetName}\" je že v uporabi v mapi \"{dir}\". Izberite drugo ime ali drugo mapo.",
+ "Could not rename \"{fileName}\"" : "Ni mogoče preimenovati \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Ni mogoče ustvariti datoteke \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Ni mogoče ustvariti datoteke \"{file}\", ker že obstaja",
+ "Could not create folder \"{dir}\"" : "Ni mogoče ustvariti mape \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Ni mogoče ustvariti mape \"{dir}\", ker že obstaja",
+ "Error deleting file \"{fileName}\"." : "Napaka brisanja datoteke \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Ni zadetkov, ki bi bili skladni z nizom '{filter}'",
"Name" : "Ime",
"Size" : "Velikost",
@@ -69,11 +70,13 @@ OC.L10N.register(
"Storage of {owner} is almost full ({usedSpacePercent}%)" : "Shramba uporabnika {owner} je polna ({usedSpacePercent}%).",
"Your storage is almost full ({usedSpacePercent}%)" : "Prostor za shranjevanje je skoraj do konca zaseden ({usedSpacePercent}%)",
"_matches '{filter}'_::_match '{filter}'_" : ["se sklada s filtrom '{filter}'","se skladata s filtrom '{filter}'","se skladajo s filtrom '{filter}'","se skladajo s filtrom '{filter}'"],
+ "Path" : "Pot",
+ "_%n byte_::_%n bytes_" : ["%n bajt","%n bajta","%n bajti","%n bajtov"],
"Favorited" : "Označeno kot priljubljeno",
"Favorite" : "Priljubljene",
- "Text file" : "Besedilna datoteka",
"Folder" : "Mapa",
"New folder" : "Nova mapa",
+ "{newname} already exists" : "{newname} že obstaja",
"Upload" : "Pošlji",
"An error occurred while trying to update the tags" : "Prišlo je do napake med posodabljanjem oznak",
"A new file or folder has been <strong>created</strong>" : "Nova datoteka ali mapa je <strong>ustvarjena</strong>",
@@ -90,13 +93,16 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s je izbrisal %1$s",
"You restored %1$s" : "Obnovljen je predmet %1$s",
"%2$s restored %1$s" : "Uporabnik %2$s je obnovil predmet %1$s.",
- "%s could not be renamed as it has been deleted" : "Datoteke %s ni mogoče preimenovati, ker je bila že prej izbrisana.",
- "%s could not be renamed" : "%s ni mogoče preimenovati",
+ "Changed by %2$s" : "Zadnja sprememba: %2$s",
+ "Deleted by %2$s" : "Izbrisano: %2$s",
+ "Restored by %2$s" : "Obnovljeno: %2$s",
"Upload (max. %s)" : "Pošiljanje (omejitev %s)",
"File handling" : "Upravljanje z datotekami",
"Maximum upload size" : "Največja velikost za pošiljanja",
"max. possible: " : "največ mogoče:",
"Save" : "Shrani",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Uveljavljanje sprememb prek PHP-FPM lahko traja tudi 5 minut.",
+ "Missing permissions to edit from here." : "Ni ustreznih dovoljenj za urejanje na tej ravni.",
"Settings" : "Nastavitve",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Uporabite naslov <a href=\"%s\" target=\"_blank\"> za dostop do datotek peko sistema WebDAV</a>.",
@@ -107,9 +113,9 @@ OC.L10N.register(
"Select all" : "izberi vse",
"Upload too large" : "Prekoračenje omejitve velikosti",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Datoteke, ki jih želite poslati, presegajo največjo dovoljeno velikost na strežniku.",
- "Files are being scanned, please wait." : "Poteka preučevanje datotek, počakajte ...",
- "Currently scanning" : "Poteka preverjanje",
"No favorites" : "Ni priljubljenih",
- "Files and folders you mark as favorite will show up here" : "Datoteke ali mape, ki so označene kot priljubljene, bodo izpisane tukaj."
+ "Files and folders you mark as favorite will show up here" : "Datoteke ali mape, ki so označene kot priljubljene, bodo izpisane tukaj.",
+ "Text file" : "Besedilna datoteka",
+ "New text file.txt" : "Nova datoteka.txt"
},
"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);");
diff --git a/apps/files/l10n/sl.json b/apps/files/l10n/sl.json
index 6dbbd99371a..80b2338d383 100644
--- a/apps/files/l10n/sl.json
+++ b/apps/files/l10n/sl.json
@@ -2,13 +2,6 @@
"Storage not available" : "Na voljo ni dovolj prostora",
"Storage invalid" : "Določen prostor ni veljaven",
"Unknown error" : "Neznana napaka",
- "Could not move %s - File with this name already exists" : "Datoteke %s ni mogoče premakniti - datoteka s tem imenom že obstaja.",
- "Could not move %s" : "Datoteke %s ni mogoče premakniti",
- "Permission denied" : "Za to opravilo ni ustreznih dovoljenj.",
- "The target folder has been moved or deleted." : "Ciljna mapa je premaknjena ali izbrisana.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Ime %s je že v mapi %s že v uporabi. Izbrati je treba drugo ime.",
- "Error when creating the file" : "Napaka med ustvarjanjem datoteke",
- "Error when creating the folder" : "Napaka med ustvarjanjem mape",
"Unable to set upload directory." : "Mapo, v katero boste prenašali dokumente, ni mogoče določiti",
"Invalid Token" : "Neveljaven žeton",
"No file was uploaded. Unknown error" : "Ni poslane datoteke. Neznana napaka.",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Manjka začasna mapa",
"Failed to write to disk" : "Pisanje na disk je spodletelo",
"Not enough storage available" : "Na voljo ni dovolj prostora",
+ "The target folder has been moved or deleted." : "Ciljna mapa je premaknjena ali izbrisana.",
"Upload failed. Could not find uploaded file" : "Pošiljanje je spodletelo. Ni mogoče najti poslane datoteke.",
"Upload failed. Could not get file info." : "Pošiljanje je spodletelo. Ni mogoče pridobiti podrobnosti datoteke.",
"Invalid directory." : "Neveljavna mapa.",
@@ -38,18 +32,25 @@
"Download" : "Prejmi",
"Rename" : "Preimenuj",
"Delete" : "Izbriši",
+ "Disconnect storage" : "Odklopi shrambo",
+ "Unshare" : "Prekini souporabo",
"Details" : "Podrobnosti",
"Select" : "Izberi",
"Pending" : "V čakanju ...",
"Unable to determine date" : "Ni mogoče določiti datuma",
- "Error moving file." : "Napaka premikanja datoteke.",
- "Error moving file" : "Napaka premikanja datoteke",
- "Error" : "Napaka",
- "{new_name} already exists" : "{new_name} že obstaja",
- "Could not rename file" : "Ni mogoče preimenovati datoteke",
- "Could not create file" : "Ni mogoče ustvariti datoteke",
- "Could not create folder" : "Ni mogoče ustvariti mape",
- "Error deleting file." : "Napaka brisanja datoteke.",
+ "This operation is forbidden" : "To dejanje ni dovoljeno!",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Mapa ni na voljo. Preverite dnevnik in stopite v stik s skrbnikom sistema.",
+ "Could not move \"{file}\", target exists" : "Datoteke \"{file}\" ni mogoče premakniti, ker cilj že obstaja",
+ "Could not move \"{file}\"" : "Ni mogoče premakniti \"{file}\"",
+ "{newName} already exists" : "{newName} že obstaja",
+ "Could not rename \"{fileName}\", it does not exist any more" : "Ni mogoče preimenovati \"{fileName}\", ker datoteka ne obstaja več",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Ime \"{targetName}\" je že v uporabi v mapi \"{dir}\". Izberite drugo ime ali drugo mapo.",
+ "Could not rename \"{fileName}\"" : "Ni mogoče preimenovati \"{fileName}\"",
+ "Could not create file \"{file}\"" : "Ni mogoče ustvariti datoteke \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "Ni mogoče ustvariti datoteke \"{file}\", ker že obstaja",
+ "Could not create folder \"{dir}\"" : "Ni mogoče ustvariti mape \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "Ni mogoče ustvariti mape \"{dir}\", ker že obstaja",
+ "Error deleting file \"{fileName}\"." : "Napaka brisanja datoteke \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Ni zadetkov, ki bi bili skladni z nizom '{filter}'",
"Name" : "Ime",
"Size" : "Velikost",
@@ -67,11 +68,13 @@
"Storage of {owner} is almost full ({usedSpacePercent}%)" : "Shramba uporabnika {owner} je polna ({usedSpacePercent}%).",
"Your storage is almost full ({usedSpacePercent}%)" : "Prostor za shranjevanje je skoraj do konca zaseden ({usedSpacePercent}%)",
"_matches '{filter}'_::_match '{filter}'_" : ["se sklada s filtrom '{filter}'","se skladata s filtrom '{filter}'","se skladajo s filtrom '{filter}'","se skladajo s filtrom '{filter}'"],
+ "Path" : "Pot",
+ "_%n byte_::_%n bytes_" : ["%n bajt","%n bajta","%n bajti","%n bajtov"],
"Favorited" : "Označeno kot priljubljeno",
"Favorite" : "Priljubljene",
- "Text file" : "Besedilna datoteka",
"Folder" : "Mapa",
"New folder" : "Nova mapa",
+ "{newname} already exists" : "{newname} že obstaja",
"Upload" : "Pošlji",
"An error occurred while trying to update the tags" : "Prišlo je do napake med posodabljanjem oznak",
"A new file or folder has been <strong>created</strong>" : "Nova datoteka ali mapa je <strong>ustvarjena</strong>",
@@ -88,13 +91,16 @@
"%2$s deleted %1$s" : "%2$s je izbrisal %1$s",
"You restored %1$s" : "Obnovljen je predmet %1$s",
"%2$s restored %1$s" : "Uporabnik %2$s je obnovil predmet %1$s.",
- "%s could not be renamed as it has been deleted" : "Datoteke %s ni mogoče preimenovati, ker je bila že prej izbrisana.",
- "%s could not be renamed" : "%s ni mogoče preimenovati",
+ "Changed by %2$s" : "Zadnja sprememba: %2$s",
+ "Deleted by %2$s" : "Izbrisano: %2$s",
+ "Restored by %2$s" : "Obnovljeno: %2$s",
"Upload (max. %s)" : "Pošiljanje (omejitev %s)",
"File handling" : "Upravljanje z datotekami",
"Maximum upload size" : "Največja velikost za pošiljanja",
"max. possible: " : "največ mogoče:",
"Save" : "Shrani",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Uveljavljanje sprememb prek PHP-FPM lahko traja tudi 5 minut.",
+ "Missing permissions to edit from here." : "Ni ustreznih dovoljenj za urejanje na tej ravni.",
"Settings" : "Nastavitve",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Uporabite naslov <a href=\"%s\" target=\"_blank\"> za dostop do datotek peko sistema WebDAV</a>.",
@@ -105,9 +111,9 @@
"Select all" : "izberi vse",
"Upload too large" : "Prekoračenje omejitve velikosti",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Datoteke, ki jih želite poslati, presegajo največjo dovoljeno velikost na strežniku.",
- "Files are being scanned, please wait." : "Poteka preučevanje datotek, počakajte ...",
- "Currently scanning" : "Poteka preverjanje",
"No favorites" : "Ni priljubljenih",
- "Files and folders you mark as favorite will show up here" : "Datoteke ali mape, ki so označene kot priljubljene, bodo izpisane tukaj."
+ "Files and folders you mark as favorite will show up here" : "Datoteke ali mape, ki so označene kot priljubljene, bodo izpisane tukaj.",
+ "Text file" : "Besedilna datoteka",
+ "New text file.txt" : "Nova datoteka.txt"
},"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files/l10n/sq.js b/apps/files/l10n/sq.js
index 5f0b3a8c936..f86f0af4937 100644
--- a/apps/files/l10n/sq.js
+++ b/apps/files/l10n/sq.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Pa depozitë gati",
"Storage invalid" : "Depozitë e pavlefshme",
"Unknown error" : "Gabim i panjohur",
- "Could not move %s - File with this name already exists" : "S’u zhvendos dot %s - Ka tashmë kartelë me këtë",
- "Could not move %s" : "S’u zhvendos dot %s",
- "Permission denied" : "Leje e mohuar",
- "The target folder has been moved or deleted." : "Dosja vendmbërritje është zhvendosur ose fshirë.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Emri %s tashmë është i përdorur në dosjen %s. Ju lutemi, zgjidhni një emër tjetër.",
- "Error when creating the file" : "Gabim gjatë krijimit të kartelës",
- "Error when creating the folder" : "Gabim gjatë krijimit të dosjes",
"Unable to set upload directory." : "S’arrihet të caktohet drejtori ngarkimesh",
"Invalid Token" : "Token i pavlefshëm",
"No file was uploaded. Unknown error" : "S’u ngarkua ndonjë kartelë. Gabim i panjohur",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Mungon një dosje e përkohshme",
"Failed to write to disk" : "Dështoi shkrimi në disk",
"Not enough storage available" : "S’ka depozitë të mjaftueshme",
+ "The target folder has been moved or deleted." : "Dosja vendmbërritje është zhvendosur ose fshirë.",
"Upload failed. Could not find uploaded file" : "Ngarkimi dështoi. S’u gjet dot kartela e ngarkuar",
"Upload failed. Could not get file info." : "Ngarkoi dështoi. S’u morën dot të dhëna kartele.",
"Invalid directory." : "Drejtori e pavlefshme.",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "Shkarkoje",
"Rename" : "Riemërtojeni",
"Delete" : "Fshije",
+ "Disconnect storage" : "Shkëpute depozitën",
+ "Unshare" : "Hiqe ndarjen",
"Details" : "Hollësi",
"Select" : "Përzgjidhe",
"Pending" : "Në pritje",
"Unable to determine date" : "S’arrihet të përcaktohet data",
"This operation is forbidden" : "Ky veprim është i ndaluar",
"This directory is unavailable, please check the logs or contact the administrator" : "Kjo drejtori nuk kapet, ju lutemi, kontrolloni regjistrat ose lidhuni me përgjegjësin",
- "Error moving file." : "Gabim në lëvizjen e kartelës.",
- "Error moving file" : "Gabim në lëvizjen e kartelës",
- "Error" : "Gabim",
- "{new_name} already exists" : "{new_name} ekziston tashmtë",
- "Could not rename file" : "Kartela s’u riemërtua dot",
- "Could not create file" : "Kartela s’u krijua dot",
- "Could not create folder" : "Dosja s’u krijua dot",
- "Error deleting file." : "Gabim gjatë fshirjes së kartelës.",
+ "Could not move \"{file}\", target exists" : "S’u lëviz dot \"{file}\", objektivi ekziston",
+ "Could not move \"{file}\"" : "S’u lëviz dot \"{file}\"",
+ "{newName} already exists" : "{newName} ekziston tashmë",
+ "Could not rename \"{fileName}\", it does not exist any more" : "S’u riemërtua dot \"{fileName}\", s’ekziston më",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Emri \"{targetName}\" është tashmë i përdorur te dosja \"{dir}\". Ju lutemi, zgjidhni një emër tjetër.",
+ "Could not rename \"{fileName}\"" : "S’u riemërtua dot \"{fileName}\"",
+ "Could not create file \"{file}\"" : "S’u krijua dot kartela \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "S’u krijua dot kartela \"{file}\" ngaqë ka një të tillë",
+ "Could not create folder \"{dir}\"" : "S’u krijua dot dosja \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "S’u krijua dot dosja \"{dir}\" ngaqë ka një të tillë",
+ "Error deleting file \"{fileName}\"." : "Gabim në fshirjen e kartelës \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Në këtë dosje s’ka zëra me përputhje me '{filter}'",
"Name" : "Emër",
"Size" : "Madhësi",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n bajt","%n bajte"],
"Favorited" : "U kalua e parapëlqyer",
"Favorite" : "E parapëlqyer",
- "Text file" : "Kartelë tekst",
- "New text file.txt" : "Kartelë e re file.txt",
"Folder" : "Dosje",
"New folder" : "Dosje e re",
"{newname} already exists" : "Ka tashmë një {newname}",
@@ -99,15 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "Ndryshuar nga %2$s",
"Deleted by %2$s" : "Fshirë nga %2$s",
"Restored by %2$s" : "Rikthyer nga %2$s",
- "%s could not be renamed as it has been deleted" : "%s s’riemërtohet dot, sepse është fshirë",
- "%s could not be renamed" : "%s s’riemërtohet dot",
"Upload (max. %s)" : "Ngarkim (max. %s)",
"File handling" : "Trajtim kartele",
"Maximum upload size" : "Madhësi maksimale ngarkimi",
"max. possible: " : "maks. i mundshëm: ",
"Save" : "Ruaje",
"With PHP-FPM it might take 5 minutes for changes to be applied." : "Me PHP-FPM mund të duhen 5 minuta që ndryshimet të hyjnë në fuqi.",
- "Missing permissions to edit from here." : "Mungojnë lejet për të përpunuar që këtu.",
+ "Missing permissions to edit from here." : "Mungojnë lejet për përpunim që nga këtu.",
"Settings" : "Rregullime",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Përdorni këtë adresë për <a href=\"%s\" target=\"_blank\">të hyrë te Kartelat tuaja përmes WebDAV-it</a>",
@@ -118,9 +113,9 @@ OC.L10N.register(
"Select all" : "Përzgjidhe krejt",
"Upload too large" : "Ngarkim shumë i madh",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Kartelat që po rrekeni të ngarkoni e tejkalojnë madhësinë maksimale për ngarkime kartelash në këtë shërbyes.",
- "Files are being scanned, please wait." : "Kartelat po kontrollohen, ju lutemi, pritni.",
- "Currently scanning" : "Po kontrollohet",
"No favorites" : "Pa të parapëlqyera",
- "Files and folders you mark as favorite will show up here" : "Këtu do të duken kartelat dhe dosjet që i shënoni si të parapëlqyera"
+ "Files and folders you mark as favorite will show up here" : "Këtu do të duken kartelat dhe dosjet që i shënoni si të parapëlqyera",
+ "Text file" : "Kartelë tekst",
+ "New text file.txt" : "Kartelë e re file.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/sq.json b/apps/files/l10n/sq.json
index fceac2c5376..90f1af5b67f 100644
--- a/apps/files/l10n/sq.json
+++ b/apps/files/l10n/sq.json
@@ -2,13 +2,6 @@
"Storage not available" : "Pa depozitë gati",
"Storage invalid" : "Depozitë e pavlefshme",
"Unknown error" : "Gabim i panjohur",
- "Could not move %s - File with this name already exists" : "S’u zhvendos dot %s - Ka tashmë kartelë me këtë",
- "Could not move %s" : "S’u zhvendos dot %s",
- "Permission denied" : "Leje e mohuar",
- "The target folder has been moved or deleted." : "Dosja vendmbërritje është zhvendosur ose fshirë.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Emri %s tashmë është i përdorur në dosjen %s. Ju lutemi, zgjidhni një emër tjetër.",
- "Error when creating the file" : "Gabim gjatë krijimit të kartelës",
- "Error when creating the folder" : "Gabim gjatë krijimit të dosjes",
"Unable to set upload directory." : "S’arrihet të caktohet drejtori ngarkimesh",
"Invalid Token" : "Token i pavlefshëm",
"No file was uploaded. Unknown error" : "S’u ngarkua ndonjë kartelë. Gabim i panjohur",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Mungon një dosje e përkohshme",
"Failed to write to disk" : "Dështoi shkrimi në disk",
"Not enough storage available" : "S’ka depozitë të mjaftueshme",
+ "The target folder has been moved or deleted." : "Dosja vendmbërritje është zhvendosur ose fshirë.",
"Upload failed. Could not find uploaded file" : "Ngarkimi dështoi. S’u gjet dot kartela e ngarkuar",
"Upload failed. Could not get file info." : "Ngarkoi dështoi. S’u morën dot të dhëna kartele.",
"Invalid directory." : "Drejtori e pavlefshme.",
@@ -38,20 +32,25 @@
"Download" : "Shkarkoje",
"Rename" : "Riemërtojeni",
"Delete" : "Fshije",
+ "Disconnect storage" : "Shkëpute depozitën",
+ "Unshare" : "Hiqe ndarjen",
"Details" : "Hollësi",
"Select" : "Përzgjidhe",
"Pending" : "Në pritje",
"Unable to determine date" : "S’arrihet të përcaktohet data",
"This operation is forbidden" : "Ky veprim është i ndaluar",
"This directory is unavailable, please check the logs or contact the administrator" : "Kjo drejtori nuk kapet, ju lutemi, kontrolloni regjistrat ose lidhuni me përgjegjësin",
- "Error moving file." : "Gabim në lëvizjen e kartelës.",
- "Error moving file" : "Gabim në lëvizjen e kartelës",
- "Error" : "Gabim",
- "{new_name} already exists" : "{new_name} ekziston tashmtë",
- "Could not rename file" : "Kartela s’u riemërtua dot",
- "Could not create file" : "Kartela s’u krijua dot",
- "Could not create folder" : "Dosja s’u krijua dot",
- "Error deleting file." : "Gabim gjatë fshirjes së kartelës.",
+ "Could not move \"{file}\", target exists" : "S’u lëviz dot \"{file}\", objektivi ekziston",
+ "Could not move \"{file}\"" : "S’u lëviz dot \"{file}\"",
+ "{newName} already exists" : "{newName} ekziston tashmë",
+ "Could not rename \"{fileName}\", it does not exist any more" : "S’u riemërtua dot \"{fileName}\", s’ekziston më",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Emri \"{targetName}\" është tashmë i përdorur te dosja \"{dir}\". Ju lutemi, zgjidhni një emër tjetër.",
+ "Could not rename \"{fileName}\"" : "S’u riemërtua dot \"{fileName}\"",
+ "Could not create file \"{file}\"" : "S’u krijua dot kartela \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "S’u krijua dot kartela \"{file}\" ngaqë ka një të tillë",
+ "Could not create folder \"{dir}\"" : "S’u krijua dot dosja \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "S’u krijua dot dosja \"{dir}\" ngaqë ka një të tillë",
+ "Error deleting file \"{fileName}\"." : "Gabim në fshirjen e kartelës \"{fileName}\".",
"No entries in this folder match '{filter}'" : "Në këtë dosje s’ka zëra me përputhje me '{filter}'",
"Name" : "Emër",
"Size" : "Madhësi",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n bajt","%n bajte"],
"Favorited" : "U kalua e parapëlqyer",
"Favorite" : "E parapëlqyer",
- "Text file" : "Kartelë tekst",
- "New text file.txt" : "Kartelë e re file.txt",
"Folder" : "Dosje",
"New folder" : "Dosje e re",
"{newname} already exists" : "Ka tashmë një {newname}",
@@ -97,15 +94,13 @@
"Changed by %2$s" : "Ndryshuar nga %2$s",
"Deleted by %2$s" : "Fshirë nga %2$s",
"Restored by %2$s" : "Rikthyer nga %2$s",
- "%s could not be renamed as it has been deleted" : "%s s’riemërtohet dot, sepse është fshirë",
- "%s could not be renamed" : "%s s’riemërtohet dot",
"Upload (max. %s)" : "Ngarkim (max. %s)",
"File handling" : "Trajtim kartele",
"Maximum upload size" : "Madhësi maksimale ngarkimi",
"max. possible: " : "maks. i mundshëm: ",
"Save" : "Ruaje",
"With PHP-FPM it might take 5 minutes for changes to be applied." : "Me PHP-FPM mund të duhen 5 minuta që ndryshimet të hyjnë në fuqi.",
- "Missing permissions to edit from here." : "Mungojnë lejet për të përpunuar që këtu.",
+ "Missing permissions to edit from here." : "Mungojnë lejet për përpunim që nga këtu.",
"Settings" : "Rregullime",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Përdorni këtë adresë për <a href=\"%s\" target=\"_blank\">të hyrë te Kartelat tuaja përmes WebDAV-it</a>",
@@ -116,9 +111,9 @@
"Select all" : "Përzgjidhe krejt",
"Upload too large" : "Ngarkim shumë i madh",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Kartelat që po rrekeni të ngarkoni e tejkalojnë madhësinë maksimale për ngarkime kartelash në këtë shërbyes.",
- "Files are being scanned, please wait." : "Kartelat po kontrollohen, ju lutemi, pritni.",
- "Currently scanning" : "Po kontrollohet",
"No favorites" : "Pa të parapëlqyera",
- "Files and folders you mark as favorite will show up here" : "Këtu do të duken kartelat dhe dosjet që i shënoni si të parapëlqyera"
+ "Files and folders you mark as favorite will show up here" : "Këtu do të duken kartelat dhe dosjet që i shënoni si të parapëlqyera",
+ "Text file" : "Kartelë tekst",
+ "New text file.txt" : "Kartelë e re file.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/sr.js b/apps/files/l10n/sr.js
index 289b7dd432c..fbfa08ecf86 100644
--- a/apps/files/l10n/sr.js
+++ b/apps/files/l10n/sr.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Складиште није доступно",
"Storage invalid" : "Неисправно складиште",
"Unknown error" : "Непозната грешка",
- "Could not move %s - File with this name already exists" : "Не могу да преместим %s – фајл са овим називом већ постоји",
- "Could not move %s" : "Не могу да преместим %s",
- "Permission denied" : "Приступ одбијен",
- "The target folder has been moved or deleted." : "Одредишна фасцикла је премештена или обрисана.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Назив %s се већ користи у фасцикли %s. Одредите други назив.",
- "Error when creating the file" : "Грешка при стварању фајла",
- "Error when creating the folder" : "Грешка при стварању фајла",
"Unable to set upload directory." : "Не могу да поставим директоријум за отпремање.",
"Invalid Token" : "Неисправан токен",
"No file was uploaded. Unknown error" : "Ниједан фајл није отпремљен. Непозната грешка",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Недостаје привремена фасцикла",
"Failed to write to disk" : "Не могу да пишем на диск",
"Not enough storage available" : "Нема довољно простора",
+ "The target folder has been moved or deleted." : "Одредишна фасцикла је премештена или обрисана.",
"Upload failed. Could not find uploaded file" : "Неуспешно отпремање. Не могу да нађем отпремљени фајл",
"Upload failed. Could not get file info." : "Неуспешно отпремање. Не могу да добијем податке о фајлу.",
"Invalid directory." : "Неисправна фасцикла.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "Преузми",
"Rename" : "Преименуј",
"Delete" : "Обриши",
+ "Disconnect storage" : "Искључи складиште",
+ "Unshare" : "Не дели",
"Details" : "Подаци",
"Select" : "Изабери",
"Pending" : "На чекању",
"Unable to determine date" : "Не могу да одредим датум",
"This operation is forbidden" : "Ова радња је забрањена",
"This directory is unavailable, please check the logs or contact the administrator" : "Овај директоријум није доступан, проверите записе или контактирајте администратора",
- "Error moving file." : "Грешка при премештању фајла.",
- "Error moving file" : "Грешка при премештању фајла",
- "Error" : "Грешка",
- "{new_name} already exists" : "{new_name} већ постоји",
- "Could not rename file" : "Не могу да преименујем фајл",
- "Could not create file" : "Не могу да створим фајл",
- "Could not create folder" : "Не могу да створим фасциклу",
- "Error deleting file." : "Грешка при брисању фајла.",
"No entries in this folder match '{filter}'" : "У овој фасцикли ништа се не поклапа са '{filter}'",
"Name" : "Назив",
"Size" : "Величина",
@@ -75,8 +63,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n бајт","%n бајта","%n бајта"],
"Favorited" : "Омиљено",
"Favorite" : "Омиљени",
- "Text file" : "текстуални фајл",
- "New text file.txt" : "Нов текстуални фајл.txt",
"Folder" : "фасцикла",
"New folder" : "Нова фасцикла",
"{newname} already exists" : "{newname} већ постоји",
@@ -99,8 +85,6 @@ OC.L10N.register(
"Changed by %2$s" : "Изменио %2$s",
"Deleted by %2$s" : "Обрисао %2$s",
"Restored by %2$s" : "Повратио %2$s",
- "%s could not be renamed as it has been deleted" : "%s се не може преименовати јер је обрисан",
- "%s could not be renamed" : "%s се не може преименовати",
"Upload (max. %s)" : "Отпремање (макс. %s)",
"File handling" : "Руковање фајловима",
"Maximum upload size" : "Највећа величина отпремања",
@@ -116,9 +100,9 @@ OC.L10N.register(
"Select all" : "Означи све",
"Upload too large" : "Отпремање је превелико",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Фајлови које желите да отпремите превазилазе ограничење отпремања на овом серверу.",
- "Files are being scanned, please wait." : "Скенирам фајлове, сачекајте.",
- "Currently scanning" : "Тренутно скенирам",
"No favorites" : "Нема омиљених",
- "Files and folders you mark as favorite will show up here" : "Фајлови и фасцикле које обележите као омиљене појавиће се овде"
+ "Files and folders you mark as favorite will show up here" : "Фајлови и фасцикле које обележите као омиљене појавиће се овде",
+ "Text file" : "текстуални фајл",
+ "New text file.txt" : "Нов текстуални фајл.txt"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files/l10n/sr.json b/apps/files/l10n/sr.json
index 60457925962..d231c5416c8 100644
--- a/apps/files/l10n/sr.json
+++ b/apps/files/l10n/sr.json
@@ -2,13 +2,6 @@
"Storage not available" : "Складиште није доступно",
"Storage invalid" : "Неисправно складиште",
"Unknown error" : "Непозната грешка",
- "Could not move %s - File with this name already exists" : "Не могу да преместим %s – фајл са овим називом већ постоји",
- "Could not move %s" : "Не могу да преместим %s",
- "Permission denied" : "Приступ одбијен",
- "The target folder has been moved or deleted." : "Одредишна фасцикла је премештена или обрисана.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Назив %s се већ користи у фасцикли %s. Одредите други назив.",
- "Error when creating the file" : "Грешка при стварању фајла",
- "Error when creating the folder" : "Грешка при стварању фајла",
"Unable to set upload directory." : "Не могу да поставим директоријум за отпремање.",
"Invalid Token" : "Неисправан токен",
"No file was uploaded. Unknown error" : "Ниједан фајл није отпремљен. Непозната грешка",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Недостаје привремена фасцикла",
"Failed to write to disk" : "Не могу да пишем на диск",
"Not enough storage available" : "Нема довољно простора",
+ "The target folder has been moved or deleted." : "Одредишна фасцикла је премештена или обрисана.",
"Upload failed. Could not find uploaded file" : "Неуспешно отпремање. Не могу да нађем отпремљени фајл",
"Upload failed. Could not get file info." : "Неуспешно отпремање. Не могу да добијем податке о фајлу.",
"Invalid directory." : "Неисправна фасцикла.",
@@ -38,20 +32,14 @@
"Download" : "Преузми",
"Rename" : "Преименуј",
"Delete" : "Обриши",
+ "Disconnect storage" : "Искључи складиште",
+ "Unshare" : "Не дели",
"Details" : "Подаци",
"Select" : "Изабери",
"Pending" : "На чекању",
"Unable to determine date" : "Не могу да одредим датум",
"This operation is forbidden" : "Ова радња је забрањена",
"This directory is unavailable, please check the logs or contact the administrator" : "Овај директоријум није доступан, проверите записе или контактирајте администратора",
- "Error moving file." : "Грешка при премештању фајла.",
- "Error moving file" : "Грешка при премештању фајла",
- "Error" : "Грешка",
- "{new_name} already exists" : "{new_name} већ постоји",
- "Could not rename file" : "Не могу да преименујем фајл",
- "Could not create file" : "Не могу да створим фајл",
- "Could not create folder" : "Не могу да створим фасциклу",
- "Error deleting file." : "Грешка при брисању фајла.",
"No entries in this folder match '{filter}'" : "У овој фасцикли ништа се не поклапа са '{filter}'",
"Name" : "Назив",
"Size" : "Величина",
@@ -73,8 +61,6 @@
"_%n byte_::_%n bytes_" : ["%n бајт","%n бајта","%n бајта"],
"Favorited" : "Омиљено",
"Favorite" : "Омиљени",
- "Text file" : "текстуални фајл",
- "New text file.txt" : "Нов текстуални фајл.txt",
"Folder" : "фасцикла",
"New folder" : "Нова фасцикла",
"{newname} already exists" : "{newname} већ постоји",
@@ -97,8 +83,6 @@
"Changed by %2$s" : "Изменио %2$s",
"Deleted by %2$s" : "Обрисао %2$s",
"Restored by %2$s" : "Повратио %2$s",
- "%s could not be renamed as it has been deleted" : "%s се не може преименовати јер је обрисан",
- "%s could not be renamed" : "%s се не може преименовати",
"Upload (max. %s)" : "Отпремање (макс. %s)",
"File handling" : "Руковање фајловима",
"Maximum upload size" : "Највећа величина отпремања",
@@ -114,9 +98,9 @@
"Select all" : "Означи све",
"Upload too large" : "Отпремање је превелико",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Фајлови које желите да отпремите превазилазе ограничење отпремања на овом серверу.",
- "Files are being scanned, please wait." : "Скенирам фајлове, сачекајте.",
- "Currently scanning" : "Тренутно скенирам",
"No favorites" : "Нема омиљених",
- "Files and folders you mark as favorite will show up here" : "Фајлови и фасцикле које обележите као омиљене појавиће се овде"
+ "Files and folders you mark as favorite will show up here" : "Фајлови и фасцикле које обележите као омиљене појавиће се овде",
+ "Text file" : "текстуални фајл",
+ "New text file.txt" : "Нов текстуални фајл.txt"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files/l10n/sr@latin.js b/apps/files/l10n/sr@latin.js
index 2907018adfb..7c62a464494 100644
--- a/apps/files/l10n/sr@latin.js
+++ b/apps/files/l10n/sr@latin.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Skladište nije dostupno",
"Storage invalid" : "Neispravno skladište",
"Unknown error" : "Nepoznata greška",
- "Could not move %s - File with this name already exists" : "Ne mogu da premestim %s – fajl sa ovim nazivom već postoji",
- "Could not move %s" : "Ne mogu da premestim %s",
- "Permission denied" : "Pristup odbijen",
- "The target folder has been moved or deleted." : "Odredišna fascikla je premeštena ili obrisana.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Naziv %s se već koristi u fascikli %s. Odredite drugi naziv.",
- "Error when creating the file" : "Greška pri stvaranju fajla",
- "Error when creating the folder" : "Greška pri stvaranju fajla",
"Unable to set upload directory." : "Ne mogu da postavim direktorijum za otpremanje.",
"Invalid Token" : "Neispravan token",
"No file was uploaded. Unknown error" : "Nijedan fajl nije otpremljen. Nepoznata greška",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Nedostaje privremena fascikla",
"Failed to write to disk" : "Ne mogu da pišem na disk",
"Not enough storage available" : "Nema dovoljno prostora",
+ "The target folder has been moved or deleted." : "Odredišna fascikla je premeštena ili obrisana.",
"Upload failed. Could not find uploaded file" : "Neuspešno otpremanje. Ne mogu da nađem otpremljeni fajl",
"Upload failed. Could not get file info." : "Neuspešno otpremanje. Ne mogu da dobijem podatke o fajlu.",
"Invalid directory." : "Neispravna fascikla.",
@@ -39,18 +33,12 @@ OC.L10N.register(
"Download" : "Preuzmi",
"Rename" : "Preimenuj",
"Delete" : "Obriši",
+ "Disconnect storage" : "Isključi skladište",
+ "Unshare" : "Ne deli",
"Details" : "Detaljnije",
"Select" : "Izaberi",
"Pending" : "Na čekanju",
"Unable to determine date" : "Ne mogu da odredim datum",
- "Error moving file." : "Greška pri premeštanju fajla.",
- "Error moving file" : "Greška pri premeštanju fajla",
- "Error" : "Greška",
- "{new_name} already exists" : "{new_name} već postoji",
- "Could not rename file" : "Ne mogu da preimenujem fajl",
- "Could not create file" : "Ne mogu da stvorim fajl",
- "Could not create folder" : "Ne mogu da stvorim fasciklu",
- "Error deleting file." : "Greška pri brisanju fajla.",
"No entries in this folder match '{filter}'" : "U ovoj fascikli ništa se ne poklapa sa '{filter}'",
"Name" : "Naziv",
"Size" : "Veličina",
@@ -68,7 +56,6 @@ OC.L10N.register(
"_matches '{filter}'_::_match '{filter}'_" : ["se poklapa sa '{filter}'","se poklapaju sa '{filter}'","se poklapa sa '{filter}'"],
"Favorited" : "Omiljeno",
"Favorite" : "Omiljeni",
- "Text file" : "tekstualni fajl",
"Folder" : "fascikla",
"New folder" : "Nova fascikla",
"Upload" : "Otpremi",
@@ -87,8 +74,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s obrisa %1$s",
"You restored %1$s" : "Vratili ste %1$s",
"%2$s restored %1$s" : "%2$s povrati %1$s",
- "%s could not be renamed as it has been deleted" : "%s se ne može preimenovati jer je obrisan",
- "%s could not be renamed" : "%s se ne može preimenovati",
"Upload (max. %s)" : "Otpremanje (maks. %s)",
"File handling" : "Rukovanje fajlovima",
"Maximum upload size" : "Najveća veličina otpremanja",
@@ -104,9 +89,8 @@ OC.L10N.register(
"Select all" : "Označi sve",
"Upload too large" : "Otpremanje je preveliko",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Fajlovi koje želite da otpremite prevazilaze ograničenje otpremanja na ovom serveru.",
- "Files are being scanned, please wait." : "Skeniram fajlove, sačekajte.",
- "Currently scanning" : "Trenutno skeniram",
"No favorites" : "Nema omiljenih",
- "Files and folders you mark as favorite will show up here" : "Fajlovi i fascikle koje obeležite kao omiljene pojaviće se ovde"
+ "Files and folders you mark as favorite will show up here" : "Fajlovi i fascikle koje obeležite kao omiljene pojaviće se ovde",
+ "Text file" : "tekstualni fajl"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files/l10n/sr@latin.json b/apps/files/l10n/sr@latin.json
index 7026569e117..506ae677ca4 100644
--- a/apps/files/l10n/sr@latin.json
+++ b/apps/files/l10n/sr@latin.json
@@ -2,13 +2,6 @@
"Storage not available" : "Skladište nije dostupno",
"Storage invalid" : "Neispravno skladište",
"Unknown error" : "Nepoznata greška",
- "Could not move %s - File with this name already exists" : "Ne mogu da premestim %s – fajl sa ovim nazivom već postoji",
- "Could not move %s" : "Ne mogu da premestim %s",
- "Permission denied" : "Pristup odbijen",
- "The target folder has been moved or deleted." : "Odredišna fascikla je premeštena ili obrisana.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Naziv %s se već koristi u fascikli %s. Odredite drugi naziv.",
- "Error when creating the file" : "Greška pri stvaranju fajla",
- "Error when creating the folder" : "Greška pri stvaranju fajla",
"Unable to set upload directory." : "Ne mogu da postavim direktorijum za otpremanje.",
"Invalid Token" : "Neispravan token",
"No file was uploaded. Unknown error" : "Nijedan fajl nije otpremljen. Nepoznata greška",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Nedostaje privremena fascikla",
"Failed to write to disk" : "Ne mogu da pišem na disk",
"Not enough storage available" : "Nema dovoljno prostora",
+ "The target folder has been moved or deleted." : "Odredišna fascikla je premeštena ili obrisana.",
"Upload failed. Could not find uploaded file" : "Neuspešno otpremanje. Ne mogu da nađem otpremljeni fajl",
"Upload failed. Could not get file info." : "Neuspešno otpremanje. Ne mogu da dobijem podatke o fajlu.",
"Invalid directory." : "Neispravna fascikla.",
@@ -37,18 +31,12 @@
"Download" : "Preuzmi",
"Rename" : "Preimenuj",
"Delete" : "Obriši",
+ "Disconnect storage" : "Isključi skladište",
+ "Unshare" : "Ne deli",
"Details" : "Detaljnije",
"Select" : "Izaberi",
"Pending" : "Na čekanju",
"Unable to determine date" : "Ne mogu da odredim datum",
- "Error moving file." : "Greška pri premeštanju fajla.",
- "Error moving file" : "Greška pri premeštanju fajla",
- "Error" : "Greška",
- "{new_name} already exists" : "{new_name} već postoji",
- "Could not rename file" : "Ne mogu da preimenujem fajl",
- "Could not create file" : "Ne mogu da stvorim fajl",
- "Could not create folder" : "Ne mogu da stvorim fasciklu",
- "Error deleting file." : "Greška pri brisanju fajla.",
"No entries in this folder match '{filter}'" : "U ovoj fascikli ništa se ne poklapa sa '{filter}'",
"Name" : "Naziv",
"Size" : "Veličina",
@@ -66,7 +54,6 @@
"_matches '{filter}'_::_match '{filter}'_" : ["se poklapa sa '{filter}'","se poklapaju sa '{filter}'","se poklapa sa '{filter}'"],
"Favorited" : "Omiljeno",
"Favorite" : "Omiljeni",
- "Text file" : "tekstualni fajl",
"Folder" : "fascikla",
"New folder" : "Nova fascikla",
"Upload" : "Otpremi",
@@ -85,8 +72,6 @@
"%2$s deleted %1$s" : "%2$s obrisa %1$s",
"You restored %1$s" : "Vratili ste %1$s",
"%2$s restored %1$s" : "%2$s povrati %1$s",
- "%s could not be renamed as it has been deleted" : "%s se ne može preimenovati jer je obrisan",
- "%s could not be renamed" : "%s se ne može preimenovati",
"Upload (max. %s)" : "Otpremanje (maks. %s)",
"File handling" : "Rukovanje fajlovima",
"Maximum upload size" : "Najveća veličina otpremanja",
@@ -102,9 +87,8 @@
"Select all" : "Označi sve",
"Upload too large" : "Otpremanje je preveliko",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Fajlovi koje želite da otpremite prevazilaze ograničenje otpremanja na ovom serveru.",
- "Files are being scanned, please wait." : "Skeniram fajlove, sačekajte.",
- "Currently scanning" : "Trenutno skeniram",
"No favorites" : "Nema omiljenih",
- "Files and folders you mark as favorite will show up here" : "Fajlovi i fascikle koje obeležite kao omiljene pojaviće se ovde"
+ "Files and folders you mark as favorite will show up here" : "Fajlovi i fascikle koje obeležite kao omiljene pojaviće se ovde",
+ "Text file" : "tekstualni fajl"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files/l10n/sv.js b/apps/files/l10n/sv.js
index 58f6d76c29e..a541fa8b9d5 100644
--- a/apps/files/l10n/sv.js
+++ b/apps/files/l10n/sv.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Lagring inte tillgänglig",
"Storage invalid" : "Lagring ogiltig",
"Unknown error" : "Okänt fel",
- "Could not move %s - File with this name already exists" : "Kunde inte flytta %s - Det finns redan en fil med detta namn",
- "Could not move %s" : "Kan inte flytta %s",
- "Permission denied" : "Behörighet nekad.",
- "The target folder has been moved or deleted." : "Målmappen har flyttats eller tagits bort.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Namnet %s används redan i katalogen %s. Välj ett annat namn.",
- "Error when creating the file" : "Fel under skapande utav filen",
- "Error when creating the folder" : "Fel under skapande utav en katalog",
"Unable to set upload directory." : "Kan inte sätta mapp för uppladdning.",
"Invalid Token" : "Ogiltig token",
"No file was uploaded. Unknown error" : "Ingen fil uppladdad. Okänt fel",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "En temporär mapp saknas",
"Failed to write to disk" : "Misslyckades spara till disk",
"Not enough storage available" : "Inte tillräckligt med lagringsutrymme tillgängligt",
+ "The target folder has been moved or deleted." : "Målmappen har flyttats eller tagits bort.",
"Upload failed. Could not find uploaded file" : "Uppladdning misslyckades. Kunde inte hitta den uppladdade filen",
"Upload failed. Could not get file info." : "Uppladdning misslyckades. Gick inte att hämta filinformation.",
"Invalid directory." : "Felaktig mapp.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "Ladda ner",
"Rename" : "Byt namn",
"Delete" : "Radera",
+ "Disconnect storage" : "Koppla bort lagring",
+ "Unshare" : "Sluta dela",
"Details" : "Detaljer",
"Select" : "Välj",
"Pending" : "Väntar",
"Unable to determine date" : "Misslyckades avgöra datum",
"This operation is forbidden" : "Denna operation är förbjuden",
"This directory is unavailable, please check the logs or contact the administrator" : "Denna katalog är inte tillgänglig, kontrollera loggarna eller kontakta administratören",
- "Error moving file." : "Fel vid flytt av fil.",
- "Error moving file" : "Fel uppstod vid flyttning av fil",
- "Error" : "Fel",
- "{new_name} already exists" : "{new_name} finns redan",
- "Could not rename file" : "Kan ej byta filnamn",
- "Could not create file" : "Kunde ej skapa fil",
- "Could not create folder" : "Kunde ej skapa katalog",
- "Error deleting file." : "Kunde inte ta bort filen.",
"No entries in this folder match '{filter}'" : "Inga poster i denna mapp match \"{filter}\"",
"Name" : "Namn",
"Size" : "Storlek",
@@ -73,8 +61,6 @@ OC.L10N.register(
"Path" : "sökväg",
"Favorited" : "Favoritiserad",
"Favorite" : "Favorit",
- "Text file" : "Textfil",
- "New text file.txt" : "nytextfil.txt",
"Folder" : "Mapp",
"New folder" : "Ny mapp",
"{newname} already exists" : "{newname} existerar redan",
@@ -96,8 +82,6 @@ OC.L10N.register(
"Changed by %2$s" : "Ändrad av %2$s",
"Deleted by %2$s" : "Bortagen av %2$s",
"Restored by %2$s" : "Återställd av %2$s",
- "%s could not be renamed as it has been deleted" : "%s kan inte döpas om eftersom den har raderats",
- "%s could not be renamed" : "%s kunde inte namnändras",
"Upload (max. %s)" : "Ladda upp (max. %s)",
"File handling" : "Filhantering",
"Maximum upload size" : "Maximal storlek att ladda upp",
@@ -113,9 +97,9 @@ OC.L10N.register(
"Select all" : "Välj allt",
"Upload too large" : "För stor uppladdning",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Filerna du försöker ladda upp överstiger den maximala storleken för filöverföringar på servern.",
- "Files are being scanned, please wait." : "Filer skannas, var god vänta",
- "Currently scanning" : "sökning pågår",
"No favorites" : "Inga favoriter",
- "Files and folders you mark as favorite will show up here" : "Filer och mappar du markerat som favoriter kommer visas här"
+ "Files and folders you mark as favorite will show up here" : "Filer och mappar du markerat som favoriter kommer visas här",
+ "Text file" : "Textfil",
+ "New text file.txt" : "nytextfil.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/sv.json b/apps/files/l10n/sv.json
index 35faa25d1a0..09da48516a2 100644
--- a/apps/files/l10n/sv.json
+++ b/apps/files/l10n/sv.json
@@ -2,13 +2,6 @@
"Storage not available" : "Lagring inte tillgänglig",
"Storage invalid" : "Lagring ogiltig",
"Unknown error" : "Okänt fel",
- "Could not move %s - File with this name already exists" : "Kunde inte flytta %s - Det finns redan en fil med detta namn",
- "Could not move %s" : "Kan inte flytta %s",
- "Permission denied" : "Behörighet nekad.",
- "The target folder has been moved or deleted." : "Målmappen har flyttats eller tagits bort.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Namnet %s används redan i katalogen %s. Välj ett annat namn.",
- "Error when creating the file" : "Fel under skapande utav filen",
- "Error when creating the folder" : "Fel under skapande utav en katalog",
"Unable to set upload directory." : "Kan inte sätta mapp för uppladdning.",
"Invalid Token" : "Ogiltig token",
"No file was uploaded. Unknown error" : "Ingen fil uppladdad. Okänt fel",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "En temporär mapp saknas",
"Failed to write to disk" : "Misslyckades spara till disk",
"Not enough storage available" : "Inte tillräckligt med lagringsutrymme tillgängligt",
+ "The target folder has been moved or deleted." : "Målmappen har flyttats eller tagits bort.",
"Upload failed. Could not find uploaded file" : "Uppladdning misslyckades. Kunde inte hitta den uppladdade filen",
"Upload failed. Could not get file info." : "Uppladdning misslyckades. Gick inte att hämta filinformation.",
"Invalid directory." : "Felaktig mapp.",
@@ -38,20 +32,14 @@
"Download" : "Ladda ner",
"Rename" : "Byt namn",
"Delete" : "Radera",
+ "Disconnect storage" : "Koppla bort lagring",
+ "Unshare" : "Sluta dela",
"Details" : "Detaljer",
"Select" : "Välj",
"Pending" : "Väntar",
"Unable to determine date" : "Misslyckades avgöra datum",
"This operation is forbidden" : "Denna operation är förbjuden",
"This directory is unavailable, please check the logs or contact the administrator" : "Denna katalog är inte tillgänglig, kontrollera loggarna eller kontakta administratören",
- "Error moving file." : "Fel vid flytt av fil.",
- "Error moving file" : "Fel uppstod vid flyttning av fil",
- "Error" : "Fel",
- "{new_name} already exists" : "{new_name} finns redan",
- "Could not rename file" : "Kan ej byta filnamn",
- "Could not create file" : "Kunde ej skapa fil",
- "Could not create folder" : "Kunde ej skapa katalog",
- "Error deleting file." : "Kunde inte ta bort filen.",
"No entries in this folder match '{filter}'" : "Inga poster i denna mapp match \"{filter}\"",
"Name" : "Namn",
"Size" : "Storlek",
@@ -71,8 +59,6 @@
"Path" : "sökväg",
"Favorited" : "Favoritiserad",
"Favorite" : "Favorit",
- "Text file" : "Textfil",
- "New text file.txt" : "nytextfil.txt",
"Folder" : "Mapp",
"New folder" : "Ny mapp",
"{newname} already exists" : "{newname} existerar redan",
@@ -94,8 +80,6 @@
"Changed by %2$s" : "Ändrad av %2$s",
"Deleted by %2$s" : "Bortagen av %2$s",
"Restored by %2$s" : "Återställd av %2$s",
- "%s could not be renamed as it has been deleted" : "%s kan inte döpas om eftersom den har raderats",
- "%s could not be renamed" : "%s kunde inte namnändras",
"Upload (max. %s)" : "Ladda upp (max. %s)",
"File handling" : "Filhantering",
"Maximum upload size" : "Maximal storlek att ladda upp",
@@ -111,9 +95,9 @@
"Select all" : "Välj allt",
"Upload too large" : "För stor uppladdning",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Filerna du försöker ladda upp överstiger den maximala storleken för filöverföringar på servern.",
- "Files are being scanned, please wait." : "Filer skannas, var god vänta",
- "Currently scanning" : "sökning pågår",
"No favorites" : "Inga favoriter",
- "Files and folders you mark as favorite will show up here" : "Filer och mappar du markerat som favoriter kommer visas här"
+ "Files and folders you mark as favorite will show up here" : "Filer och mappar du markerat som favoriter kommer visas här",
+ "Text file" : "Textfil",
+ "New text file.txt" : "nytextfil.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/ta_LK.js b/apps/files/l10n/ta_LK.js
index 3b287a94725..8b731d1f64b 100644
--- a/apps/files/l10n/ta_LK.js
+++ b/apps/files/l10n/ta_LK.js
@@ -18,17 +18,15 @@ OC.L10N.register(
"Download" : "பதிவிறக்குக",
"Rename" : "பெயர்மாற்றம்",
"Delete" : "நீக்குக",
+ "Unshare" : "பகிரப்படாதது",
"Details" : "விவரங்கள்",
"Select" : "தெரிக",
"Pending" : "நிலுவையிலுள்ள",
- "Error" : "வழு",
- "{new_name} already exists" : "{new_name} ஏற்கனவே உள்ளது",
"Name" : "பெயர்",
"Size" : "அளவு",
"Modified" : "மாற்றப்பட்டது",
"New" : "புதிய",
"Favorite" : "விருப்பமான",
- "Text file" : "கோப்பு உரை",
"Folder" : "கோப்புறை",
"Upload" : "பதிவேற்றுக",
"File handling" : "கோப்பு கையாளுதல்",
@@ -39,6 +37,6 @@ OC.L10N.register(
"Cancel upload" : "பதிவேற்றலை இரத்து செய்க",
"Upload too large" : "பதிவேற்றல் மிகப்பெரியது",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "நீங்கள் பதிவேற்ற முயற்சிக்கும் கோப்புகளானது இந்த சேவையகத்தில் கோப்பு பதிவேற்றக்கூடிய ஆகக்கூடிய அளவிலும் கூடியது.",
- "Files are being scanned, please wait." : "கோப்புகள் வருடப்படுகின்றன, தயவுசெய்து காத்திருங்கள்."
+ "Text file" : "கோப்பு உரை"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/ta_LK.json b/apps/files/l10n/ta_LK.json
index 8da783d48d3..67cc6f18d88 100644
--- a/apps/files/l10n/ta_LK.json
+++ b/apps/files/l10n/ta_LK.json
@@ -16,17 +16,15 @@
"Download" : "பதிவிறக்குக",
"Rename" : "பெயர்மாற்றம்",
"Delete" : "நீக்குக",
+ "Unshare" : "பகிரப்படாதது",
"Details" : "விவரங்கள்",
"Select" : "தெரிக",
"Pending" : "நிலுவையிலுள்ள",
- "Error" : "வழு",
- "{new_name} already exists" : "{new_name} ஏற்கனவே உள்ளது",
"Name" : "பெயர்",
"Size" : "அளவு",
"Modified" : "மாற்றப்பட்டது",
"New" : "புதிய",
"Favorite" : "விருப்பமான",
- "Text file" : "கோப்பு உரை",
"Folder" : "கோப்புறை",
"Upload" : "பதிவேற்றுக",
"File handling" : "கோப்பு கையாளுதல்",
@@ -37,6 +35,6 @@
"Cancel upload" : "பதிவேற்றலை இரத்து செய்க",
"Upload too large" : "பதிவேற்றல் மிகப்பெரியது",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "நீங்கள் பதிவேற்ற முயற்சிக்கும் கோப்புகளானது இந்த சேவையகத்தில் கோப்பு பதிவேற்றக்கூடிய ஆகக்கூடிய அளவிலும் கூடியது.",
- "Files are being scanned, please wait." : "கோப்புகள் வருடப்படுகின்றன, தயவுசெய்து காத்திருங்கள்."
+ "Text file" : "கோப்பு உரை"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/te.js b/apps/files/l10n/te.js
index 9badfac3532..a41177c95f0 100644
--- a/apps/files/l10n/te.js
+++ b/apps/files/l10n/te.js
@@ -3,7 +3,6 @@ OC.L10N.register(
{
"Close" : "మూసివేయి",
"Delete" : "తొలగించు",
- "Error" : "పొరపాటు",
"Name" : "పేరు",
"Size" : "పరిమాణం",
"Folder" : "సంచయం",
diff --git a/apps/files/l10n/te.json b/apps/files/l10n/te.json
index 21d09484cd8..6fa2afe050b 100644
--- a/apps/files/l10n/te.json
+++ b/apps/files/l10n/te.json
@@ -1,7 +1,6 @@
{ "translations": {
"Close" : "మూసివేయి",
"Delete" : "తొలగించు",
- "Error" : "పొరపాటు",
"Name" : "పేరు",
"Size" : "పరిమాణం",
"Folder" : "సంచయం",
diff --git a/apps/files/l10n/th_TH.js b/apps/files/l10n/th_TH.js
index 1194c11ced1..d4bd37cb1e7 100644
--- a/apps/files/l10n/th_TH.js
+++ b/apps/files/l10n/th_TH.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "ไม่สามารถใช้พื้นที่จัดเก็บข้อมูลได้",
"Storage invalid" : "การจัดเก็บข้อมูลไม่ถูกต้อง",
"Unknown error" : "ข้อผิดพลาดที่ไม่ทราบสาเหตุ",
- "Could not move %s - File with this name already exists" : "ไม่สามารถย้าย %s ได้ - ไฟล์ที่ใช้ชื่อนี้มีอยู่แล้ว",
- "Could not move %s" : "ไม่สามารถย้าย %s ได้",
- "Permission denied" : "ไม่อนุญาต",
- "The target folder has been moved or deleted." : "โฟลเดอร์ปลายทางถูกย้ายหรือลบ",
- "The name %s is already used in the folder %s. Please choose a different name." : "ชื่อ %s ถูกใช้ไปแล้วในโฟลเดอร์ %s โปรดเลือกชื่ออื่นที่แตกต่างกัน",
- "Error when creating the file" : "เกิดข้อผิดพลาดเมื่อมีการสร้างไฟล์",
- "Error when creating the folder" : "เกิดข้อผิดพลาดเมื่อมีการสร้างโฟลเดอร์",
"Unable to set upload directory." : "ไม่สามารถตั้งค่าอัพโหลดไดเรกทอรี",
"Invalid Token" : "โทเค็นไม่ถูกต้อง",
"No file was uploaded. Unknown error" : "ยังไม่มีไฟล์ใดที่ถูกอัพโหลด เกิดข้อผิดพลาดที่ไม่ทราบสาเหตุ",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "โฟลเดอร์ชั่วคราวเกิดการสูญหาย",
"Failed to write to disk" : "เขียนข้อมูลลงแผ่นดิสก์ล้มเหลว",
"Not enough storage available" : "เหลือพื้นที่ไม่เพียงสำหรับใช้งาน",
+ "The target folder has been moved or deleted." : "โฟลเดอร์ปลายทางถูกย้ายหรือลบ",
"Upload failed. Could not find uploaded file" : "อัพโหลดล้มเหลว ไม่สามารถหาไฟล์ที่จะอัพโหลด",
"Upload failed. Could not get file info." : "อัพโหลดล้มเหลว ไม่สามารถรับข้อมูลไฟล์",
"Invalid directory." : "ไดเร็กทอรี่ไม่ถูกต้อง",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "ดาวน์โหลด",
"Rename" : "เปลี่ยนชื่อ",
"Delete" : "ลบ",
+ "Disconnect storage" : "ยกเลิกการเชื่อมต่อการจัดเก็บข้อมูล",
+ "Unshare" : "ยกเลิกการแชร์",
"Details" : "รายละเอียด",
"Select" : "เลือก",
"Pending" : "อยู่ระหว่างดำเนินการ",
"Unable to determine date" : "ไม่สามารถกำหนดวัน",
"This operation is forbidden" : "การดำเนินการนี้ถูกห้าม",
"This directory is unavailable, please check the logs or contact the administrator" : "ไม่สามารถใช้งานไดเรกทอรีนี้โปรดตรวจสอบบันทึกหรือติดต่อผู้ดูแลระบบ",
- "Error moving file." : "ข้อผิดพลาดในการเคลื่อนย้ายไฟล์",
- "Error moving file" : "ข้อผิดพลาดในการเคลื่อนย้ายไฟล์",
- "Error" : "ข้อผิดพลาด",
- "{new_name} already exists" : "{new_name} มีอยู่แล้วในระบบ",
- "Could not rename file" : "ไม่สามารถเปลี่ยนชื่อไฟล์",
- "Could not create file" : "ไม่สามารถสร้างไฟล์",
- "Could not create folder" : "ไม่สามารถสร้างโฟลเดอร์",
- "Error deleting file." : "เกิดข้อผิดพลาดในการลบไฟล์",
+ "Could not move \"{file}\", target exists" : "ไม่สามารถย้ายไฟล์ \"{file}\" ไม่มีไฟล์นั้นอยู่",
+ "Could not move \"{file}\"" : "ไม่สามารถย้ายไฟล์ \"{file}\"",
+ "{newName} already exists" : "{newName} มีอยู่แล้ว",
+ "Could not rename \"{fileName}\", it does not exist any more" : "ไม่สามารถเปลี่ยนชื่อไฟล์ \"{fileName}\" ไฟล์นั้นไม่มีอยู่",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "ชื่อโฟลเดอร์ \"{targetName}\" มีอยู่แล้วใน \"{dir}\" กรุณาใช้ชื่อที่แตกต่างกัน",
+ "Could not rename \"{fileName}\"" : "ไม่สามารถเปลี่ยนชื่อไฟล์ \"{fileName}\"",
+ "Could not create file \"{file}\"" : "ไม่สามารถสร้างไฟล์ \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "ไม่สามารถสร้างไฟล์ \"{file}\" เพราะมันมีอยู่แล้ว",
+ "Could not create folder \"{dir}\"" : "ไม่สามารถสร้างโฟลเดอร์ \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "ไม่สามารถสร้างโฟลเดอร์ \"{dir}\" เพราะมันมีอยู่แล้ว",
+ "Error deleting file \"{fileName}\"." : "เกิดข้อผิดพลาดขณะลบไฟล์ \"{fileName}\"",
"No entries in this folder match '{filter}'" : "ไม่มีรายการในโฟลเดอร์นี้ที่ตรงกับ '{filter}'",
"Name" : "ชื่อ",
"Size" : "ขนาด",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n ไบต์"],
"Favorited" : "รายการโปรด",
"Favorite" : "รายการโปรด",
- "Text file" : "ไฟล์ข้อความ",
- "New text file.txt" : "ไฟล์ข้อความใหม่ .txt",
"Folder" : "แฟ้มเอกสาร",
"New folder" : "โฟลเดอร์ใหม่",
"{newname} already exists" : "{newname} ถูกใช้ไปแล้ว",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "เปลี่ยนแปลงโดย %2$s",
"Deleted by %2$s" : "ลบโดย %2$s",
"Restored by %2$s" : "กู้คืนโดย %2$s",
- "%s could not be renamed as it has been deleted" : "%s ไม่สามารถเปลี่ยนชื่อเนื่องจากถูกลบไปแล้ว",
- "%s could not be renamed" : "%s ไม่สามารถเปลี่ยนชื่อ",
"Upload (max. %s)" : "อัพโหลด (สูงสุด %s)",
"File handling" : "การจัดการไฟล์",
"Maximum upload size" : "ขนาดไฟล์สูงสุดที่อัพโหลดได้",
"max. possible: " : "จำนวนสูงสุดที่สามารถทำได้: ",
"Save" : "บันทึก",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "กับ PHP-FPM อาจใช้เวลา 5 นาทีสำหรับการเปลี่ยนแปลงที่ถูกนำมาใช้",
+ "Missing permissions to edit from here." : "สิทธิ์ในการแก้ไขส่วนนี้หายไป",
"Settings" : "ตั้งค่า",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "ใช้ที่อยู่นี้เพื่อ <a href=\"%s\" target=\"_blank\">เข้าถึงไฟล์ของคุณผ่าน WebDAV</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "เลือกทั้งหมด",
"Upload too large" : "ไฟล์ที่อัพโหลดมีขนาดใหญ่เกินไป",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "ไฟล์ที่คุณพยายามที่จะอัพโหลดมีขนาดเกินกว่าขนาดสูงสุดที่กำหนดไว้ให้อัพโหลดได้สำหรับเซิร์ฟเวอร์นี้",
- "Files are being scanned, please wait." : "ไฟล์กำลังอยู่ระหว่างการสแกน, กรุณารอสักครู่.",
- "Currently scanning" : "ปัจจุบันกำลังสแกน",
"No favorites" : "ไม่มีรายการโปรด",
- "Files and folders you mark as favorite will show up here" : "ไฟล์และโฟลเดอร์ที่คุณทำเครื่องหมายเป็นรายการโปรดจะปรากฏขึ้นที่นี่"
+ "Files and folders you mark as favorite will show up here" : "ไฟล์และโฟลเดอร์ที่คุณทำเครื่องหมายเป็นรายการโปรดจะปรากฏขึ้นที่นี่",
+ "Text file" : "ไฟล์ข้อความ",
+ "New text file.txt" : "ไฟล์ข้อความใหม่ .txt"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/th_TH.json b/apps/files/l10n/th_TH.json
index 80f80e54ddf..03d6c6adb76 100644
--- a/apps/files/l10n/th_TH.json
+++ b/apps/files/l10n/th_TH.json
@@ -2,13 +2,6 @@
"Storage not available" : "ไม่สามารถใช้พื้นที่จัดเก็บข้อมูลได้",
"Storage invalid" : "การจัดเก็บข้อมูลไม่ถูกต้อง",
"Unknown error" : "ข้อผิดพลาดที่ไม่ทราบสาเหตุ",
- "Could not move %s - File with this name already exists" : "ไม่สามารถย้าย %s ได้ - ไฟล์ที่ใช้ชื่อนี้มีอยู่แล้ว",
- "Could not move %s" : "ไม่สามารถย้าย %s ได้",
- "Permission denied" : "ไม่อนุญาต",
- "The target folder has been moved or deleted." : "โฟลเดอร์ปลายทางถูกย้ายหรือลบ",
- "The name %s is already used in the folder %s. Please choose a different name." : "ชื่อ %s ถูกใช้ไปแล้วในโฟลเดอร์ %s โปรดเลือกชื่ออื่นที่แตกต่างกัน",
- "Error when creating the file" : "เกิดข้อผิดพลาดเมื่อมีการสร้างไฟล์",
- "Error when creating the folder" : "เกิดข้อผิดพลาดเมื่อมีการสร้างโฟลเดอร์",
"Unable to set upload directory." : "ไม่สามารถตั้งค่าอัพโหลดไดเรกทอรี",
"Invalid Token" : "โทเค็นไม่ถูกต้อง",
"No file was uploaded. Unknown error" : "ยังไม่มีไฟล์ใดที่ถูกอัพโหลด เกิดข้อผิดพลาดที่ไม่ทราบสาเหตุ",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "โฟลเดอร์ชั่วคราวเกิดการสูญหาย",
"Failed to write to disk" : "เขียนข้อมูลลงแผ่นดิสก์ล้มเหลว",
"Not enough storage available" : "เหลือพื้นที่ไม่เพียงสำหรับใช้งาน",
+ "The target folder has been moved or deleted." : "โฟลเดอร์ปลายทางถูกย้ายหรือลบ",
"Upload failed. Could not find uploaded file" : "อัพโหลดล้มเหลว ไม่สามารถหาไฟล์ที่จะอัพโหลด",
"Upload failed. Could not get file info." : "อัพโหลดล้มเหลว ไม่สามารถรับข้อมูลไฟล์",
"Invalid directory." : "ไดเร็กทอรี่ไม่ถูกต้อง",
@@ -38,20 +32,25 @@
"Download" : "ดาวน์โหลด",
"Rename" : "เปลี่ยนชื่อ",
"Delete" : "ลบ",
+ "Disconnect storage" : "ยกเลิกการเชื่อมต่อการจัดเก็บข้อมูล",
+ "Unshare" : "ยกเลิกการแชร์",
"Details" : "รายละเอียด",
"Select" : "เลือก",
"Pending" : "อยู่ระหว่างดำเนินการ",
"Unable to determine date" : "ไม่สามารถกำหนดวัน",
"This operation is forbidden" : "การดำเนินการนี้ถูกห้าม",
"This directory is unavailable, please check the logs or contact the administrator" : "ไม่สามารถใช้งานไดเรกทอรีนี้โปรดตรวจสอบบันทึกหรือติดต่อผู้ดูแลระบบ",
- "Error moving file." : "ข้อผิดพลาดในการเคลื่อนย้ายไฟล์",
- "Error moving file" : "ข้อผิดพลาดในการเคลื่อนย้ายไฟล์",
- "Error" : "ข้อผิดพลาด",
- "{new_name} already exists" : "{new_name} มีอยู่แล้วในระบบ",
- "Could not rename file" : "ไม่สามารถเปลี่ยนชื่อไฟล์",
- "Could not create file" : "ไม่สามารถสร้างไฟล์",
- "Could not create folder" : "ไม่สามารถสร้างโฟลเดอร์",
- "Error deleting file." : "เกิดข้อผิดพลาดในการลบไฟล์",
+ "Could not move \"{file}\", target exists" : "ไม่สามารถย้ายไฟล์ \"{file}\" ไม่มีไฟล์นั้นอยู่",
+ "Could not move \"{file}\"" : "ไม่สามารถย้ายไฟล์ \"{file}\"",
+ "{newName} already exists" : "{newName} มีอยู่แล้ว",
+ "Could not rename \"{fileName}\", it does not exist any more" : "ไม่สามารถเปลี่ยนชื่อไฟล์ \"{fileName}\" ไฟล์นั้นไม่มีอยู่",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "ชื่อโฟลเดอร์ \"{targetName}\" มีอยู่แล้วใน \"{dir}\" กรุณาใช้ชื่อที่แตกต่างกัน",
+ "Could not rename \"{fileName}\"" : "ไม่สามารถเปลี่ยนชื่อไฟล์ \"{fileName}\"",
+ "Could not create file \"{file}\"" : "ไม่สามารถสร้างไฟล์ \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "ไม่สามารถสร้างไฟล์ \"{file}\" เพราะมันมีอยู่แล้ว",
+ "Could not create folder \"{dir}\"" : "ไม่สามารถสร้างโฟลเดอร์ \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "ไม่สามารถสร้างโฟลเดอร์ \"{dir}\" เพราะมันมีอยู่แล้ว",
+ "Error deleting file \"{fileName}\"." : "เกิดข้อผิดพลาดขณะลบไฟล์ \"{fileName}\"",
"No entries in this folder match '{filter}'" : "ไม่มีรายการในโฟลเดอร์นี้ที่ตรงกับ '{filter}'",
"Name" : "ชื่อ",
"Size" : "ขนาด",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n ไบต์"],
"Favorited" : "รายการโปรด",
"Favorite" : "รายการโปรด",
- "Text file" : "ไฟล์ข้อความ",
- "New text file.txt" : "ไฟล์ข้อความใหม่ .txt",
"Folder" : "แฟ้มเอกสาร",
"New folder" : "โฟลเดอร์ใหม่",
"{newname} already exists" : "{newname} ถูกใช้ไปแล้ว",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "เปลี่ยนแปลงโดย %2$s",
"Deleted by %2$s" : "ลบโดย %2$s",
"Restored by %2$s" : "กู้คืนโดย %2$s",
- "%s could not be renamed as it has been deleted" : "%s ไม่สามารถเปลี่ยนชื่อเนื่องจากถูกลบไปแล้ว",
- "%s could not be renamed" : "%s ไม่สามารถเปลี่ยนชื่อ",
"Upload (max. %s)" : "อัพโหลด (สูงสุด %s)",
"File handling" : "การจัดการไฟล์",
"Maximum upload size" : "ขนาดไฟล์สูงสุดที่อัพโหลดได้",
"max. possible: " : "จำนวนสูงสุดที่สามารถทำได้: ",
"Save" : "บันทึก",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "กับ PHP-FPM อาจใช้เวลา 5 นาทีสำหรับการเปลี่ยนแปลงที่ถูกนำมาใช้",
+ "Missing permissions to edit from here." : "สิทธิ์ในการแก้ไขส่วนนี้หายไป",
"Settings" : "ตั้งค่า",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "ใช้ที่อยู่นี้เพื่อ <a href=\"%s\" target=\"_blank\">เข้าถึงไฟล์ของคุณผ่าน WebDAV</a>",
@@ -114,9 +111,9 @@
"Select all" : "เลือกทั้งหมด",
"Upload too large" : "ไฟล์ที่อัพโหลดมีขนาดใหญ่เกินไป",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "ไฟล์ที่คุณพยายามที่จะอัพโหลดมีขนาดเกินกว่าขนาดสูงสุดที่กำหนดไว้ให้อัพโหลดได้สำหรับเซิร์ฟเวอร์นี้",
- "Files are being scanned, please wait." : "ไฟล์กำลังอยู่ระหว่างการสแกน, กรุณารอสักครู่.",
- "Currently scanning" : "ปัจจุบันกำลังสแกน",
"No favorites" : "ไม่มีรายการโปรด",
- "Files and folders you mark as favorite will show up here" : "ไฟล์และโฟลเดอร์ที่คุณทำเครื่องหมายเป็นรายการโปรดจะปรากฏขึ้นที่นี่"
+ "Files and folders you mark as favorite will show up here" : "ไฟล์และโฟลเดอร์ที่คุณทำเครื่องหมายเป็นรายการโปรดจะปรากฏขึ้นที่นี่",
+ "Text file" : "ไฟล์ข้อความ",
+ "New text file.txt" : "ไฟล์ข้อความใหม่ .txt"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/tr.js b/apps/files/l10n/tr.js
index b2c4fd56df9..2fbb71b373c 100644
--- a/apps/files/l10n/tr.js
+++ b/apps/files/l10n/tr.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Depolama mevcut değil",
"Storage invalid" : "Depolama geçersiz",
"Unknown error" : "Bilinmeyen hata",
- "Could not move %s - File with this name already exists" : "%s taşınamadı. Bu isimde dosya zaten mevcut",
- "Could not move %s" : "%s taşınamadı",
- "Permission denied" : "Erişim reddedildi",
- "The target folder has been moved or deleted." : "Hedef klasör taşındı veya silindi.",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s ismi zaten %s klasöründe kullanılıyor. Lütfen farklı bir isim seçin.",
- "Error when creating the file" : "Dosya oluşturulurken hata",
- "Error when creating the folder" : "Klasör oluşturulurken hata",
"Unable to set upload directory." : "Yükleme dizini ayarlanamadı.",
"Invalid Token" : "Geçersiz Belirteç",
"No file was uploaded. Unknown error" : "Dosya yüklenmedi. Bilinmeyen hata",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Geçici bir dizin eksik",
"Failed to write to disk" : "Diske yazılamadı",
"Not enough storage available" : "Yeterli disk alanı yok",
+ "The target folder has been moved or deleted." : "Hedef klasör taşındı veya silindi.",
"Upload failed. Could not find uploaded file" : "Yükleme başarısız. Yüklenen dosya bulunamadı",
"Upload failed. Could not get file info." : "Yükleme başarısız. Dosya bilgisi alınamadı.",
"Invalid directory." : "Geçersiz dizin.",
@@ -40,20 +34,14 @@ OC.L10N.register(
"Download" : "İndir",
"Rename" : "Yeniden adlandır",
"Delete" : "Sil",
+ "Disconnect storage" : "Depolama bağlantısını kes",
+ "Unshare" : "Paylaşmayı Kaldır",
"Details" : "Ayrıntılar",
"Select" : "Seç",
"Pending" : "Bekliyor",
"Unable to determine date" : "Tarih tespit edilemedi",
"This operation is forbidden" : "Bu işlem yasak",
"This directory is unavailable, please check the logs or contact the administrator" : "Bu dizine yazılamıyor, lütfen günlüğü kontrol edin veya yönetici ile iletişime geçin",
- "Error moving file." : "Dosya taşıma hatası.",
- "Error moving file" : "Dosya taşıma hatası",
- "Error" : "Hata",
- "{new_name} already exists" : "{new_name} zaten mevcut",
- "Could not rename file" : "Dosya adlandırılamadı",
- "Could not create file" : "Dosya oluşturulamadı",
- "Could not create folder" : "Klasör oluşturulamadı",
- "Error deleting file." : "Dosya silinirken hata.",
"No entries in this folder match '{filter}'" : "Bu klasörde hiçbir girdi '{filter}' ile eşleşmiyor",
"Name" : "İsim",
"Size" : "Boyut",
@@ -75,8 +63,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n bayt","%n bayt"],
"Favorited" : "Sık kullanılanlara eklendi",
"Favorite" : "Sık kullanılan",
- "Text file" : "Metin dosyası",
- "New text file.txt" : "Yeni metin dosyası.txt",
"Folder" : "Klasör",
"New folder" : "Yeni klasör",
"{newname} already exists" : "{newname} zaten mevcut",
@@ -99,13 +85,13 @@ OC.L10N.register(
"Changed by %2$s" : "%2$s tarafından değiştirildi",
"Deleted by %2$s" : "%2$s tarafından silindi",
"Restored by %2$s" : "%2$s tarafından geri yüklendi",
- "%s could not be renamed as it has been deleted" : "%s, silindiği için adlandırılamadı",
- "%s could not be renamed" : "%s yeniden adlandırılamadı",
"Upload (max. %s)" : "Yükle (azami: %s)",
"File handling" : "Dosya işlemleri",
"Maximum upload size" : "Azami yükleme boyutu",
"max. possible: " : "mümkün olan en fazla: ",
"Save" : "Kaydet",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM ile değişikliklerin uygulanması 5 dakika sürebilir.",
+ "Missing permissions to edit from here." : "Buradan düzenleme için eksik yetki.",
"Settings" : "Ayarlar",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "<a href=\"%s\" target=\"_blank\">Dosyalarınıza WebDAV aracılığıyla erişmek için</a> bu adresi kullanın",
@@ -116,9 +102,9 @@ OC.L10N.register(
"Select all" : "Tümünü seç",
"Upload too large" : "Yükleme çok büyük",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Yüklemeye çalıştığınız dosyalar bu sunucudaki azami yükleme boyutunu aşıyor.",
- "Files are being scanned, please wait." : "Dosyalar taranıyor, lütfen bekleyin.",
- "Currently scanning" : "Şu anda taranan",
"No favorites" : "Sık kullanılan öge yok.",
- "Files and folders you mark as favorite will show up here" : "Sık kullanılan olarak işaretlediğiniz dosya ve klasörler burada gösterilecek"
+ "Files and folders you mark as favorite will show up here" : "Sık kullanılan olarak işaretlediğiniz dosya ve klasörler burada gösterilecek",
+ "Text file" : "Metin dosyası",
+ "New text file.txt" : "Yeni metin dosyası.txt"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files/l10n/tr.json b/apps/files/l10n/tr.json
index fcb87d74fa1..b2fd691a6a1 100644
--- a/apps/files/l10n/tr.json
+++ b/apps/files/l10n/tr.json
@@ -2,13 +2,6 @@
"Storage not available" : "Depolama mevcut değil",
"Storage invalid" : "Depolama geçersiz",
"Unknown error" : "Bilinmeyen hata",
- "Could not move %s - File with this name already exists" : "%s taşınamadı. Bu isimde dosya zaten mevcut",
- "Could not move %s" : "%s taşınamadı",
- "Permission denied" : "Erişim reddedildi",
- "The target folder has been moved or deleted." : "Hedef klasör taşındı veya silindi.",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s ismi zaten %s klasöründe kullanılıyor. Lütfen farklı bir isim seçin.",
- "Error when creating the file" : "Dosya oluşturulurken hata",
- "Error when creating the folder" : "Klasör oluşturulurken hata",
"Unable to set upload directory." : "Yükleme dizini ayarlanamadı.",
"Invalid Token" : "Geçersiz Belirteç",
"No file was uploaded. Unknown error" : "Dosya yüklenmedi. Bilinmeyen hata",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Geçici bir dizin eksik",
"Failed to write to disk" : "Diske yazılamadı",
"Not enough storage available" : "Yeterli disk alanı yok",
+ "The target folder has been moved or deleted." : "Hedef klasör taşındı veya silindi.",
"Upload failed. Could not find uploaded file" : "Yükleme başarısız. Yüklenen dosya bulunamadı",
"Upload failed. Could not get file info." : "Yükleme başarısız. Dosya bilgisi alınamadı.",
"Invalid directory." : "Geçersiz dizin.",
@@ -38,20 +32,14 @@
"Download" : "İndir",
"Rename" : "Yeniden adlandır",
"Delete" : "Sil",
+ "Disconnect storage" : "Depolama bağlantısını kes",
+ "Unshare" : "Paylaşmayı Kaldır",
"Details" : "Ayrıntılar",
"Select" : "Seç",
"Pending" : "Bekliyor",
"Unable to determine date" : "Tarih tespit edilemedi",
"This operation is forbidden" : "Bu işlem yasak",
"This directory is unavailable, please check the logs or contact the administrator" : "Bu dizine yazılamıyor, lütfen günlüğü kontrol edin veya yönetici ile iletişime geçin",
- "Error moving file." : "Dosya taşıma hatası.",
- "Error moving file" : "Dosya taşıma hatası",
- "Error" : "Hata",
- "{new_name} already exists" : "{new_name} zaten mevcut",
- "Could not rename file" : "Dosya adlandırılamadı",
- "Could not create file" : "Dosya oluşturulamadı",
- "Could not create folder" : "Klasör oluşturulamadı",
- "Error deleting file." : "Dosya silinirken hata.",
"No entries in this folder match '{filter}'" : "Bu klasörde hiçbir girdi '{filter}' ile eşleşmiyor",
"Name" : "İsim",
"Size" : "Boyut",
@@ -73,8 +61,6 @@
"_%n byte_::_%n bytes_" : ["%n bayt","%n bayt"],
"Favorited" : "Sık kullanılanlara eklendi",
"Favorite" : "Sık kullanılan",
- "Text file" : "Metin dosyası",
- "New text file.txt" : "Yeni metin dosyası.txt",
"Folder" : "Klasör",
"New folder" : "Yeni klasör",
"{newname} already exists" : "{newname} zaten mevcut",
@@ -97,13 +83,13 @@
"Changed by %2$s" : "%2$s tarafından değiştirildi",
"Deleted by %2$s" : "%2$s tarafından silindi",
"Restored by %2$s" : "%2$s tarafından geri yüklendi",
- "%s could not be renamed as it has been deleted" : "%s, silindiği için adlandırılamadı",
- "%s could not be renamed" : "%s yeniden adlandırılamadı",
"Upload (max. %s)" : "Yükle (azami: %s)",
"File handling" : "Dosya işlemleri",
"Maximum upload size" : "Azami yükleme boyutu",
"max. possible: " : "mümkün olan en fazla: ",
"Save" : "Kaydet",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM ile değişikliklerin uygulanması 5 dakika sürebilir.",
+ "Missing permissions to edit from here." : "Buradan düzenleme için eksik yetki.",
"Settings" : "Ayarlar",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "<a href=\"%s\" target=\"_blank\">Dosyalarınıza WebDAV aracılığıyla erişmek için</a> bu adresi kullanın",
@@ -114,9 +100,9 @@
"Select all" : "Tümünü seç",
"Upload too large" : "Yükleme çok büyük",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Yüklemeye çalıştığınız dosyalar bu sunucudaki azami yükleme boyutunu aşıyor.",
- "Files are being scanned, please wait." : "Dosyalar taranıyor, lütfen bekleyin.",
- "Currently scanning" : "Şu anda taranan",
"No favorites" : "Sık kullanılan öge yok.",
- "Files and folders you mark as favorite will show up here" : "Sık kullanılan olarak işaretlediğiniz dosya ve klasörler burada gösterilecek"
+ "Files and folders you mark as favorite will show up here" : "Sık kullanılan olarak işaretlediğiniz dosya ve klasörler burada gösterilecek",
+ "Text file" : "Metin dosyası",
+ "New text file.txt" : "Yeni metin dosyası.txt"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/ug.js b/apps/files/l10n/ug.js
index 5e179c6e0d1..b587b590632 100644
--- a/apps/files/l10n/ug.js
+++ b/apps/files/l10n/ug.js
@@ -2,7 +2,6 @@ OC.L10N.register(
"files",
{
"Unknown error" : "يوچۇن خاتالىق",
- "Could not move %s" : "%s يۆتكىيەلمەيدۇ",
"No file was uploaded. Unknown error" : "ھېچقانداق ھۆججەت يۈكلەنمىدى. يوچۇن خاتالىق",
"No file was uploaded" : "ھېچقانداق ھۆججەت يۈكلەنمىدى",
"Missing a temporary folder" : "ۋاقىتلىق قىسقۇچ كەم.",
@@ -18,15 +17,13 @@ OC.L10N.register(
"Download" : "چۈشۈر",
"Rename" : "ئات ئۆزگەرت",
"Delete" : "ئۆچۈر",
+ "Unshare" : "ھەمبەھىرلىمە",
"Pending" : "كۈتۈۋاتىدۇ",
- "Error" : "خاتالىق",
- "{new_name} already exists" : "{new_name} مەۋجۇت",
"Name" : "ئاتى",
"Size" : "چوڭلۇقى",
"Modified" : "ئۆزگەرتكەن",
"New" : "يېڭى",
"Favorite" : "يىغقۇچ",
- "Text file" : "تېكىست ھۆججەت",
"Folder" : "قىسقۇچ",
"New folder" : "يېڭى قىسقۇچ",
"Upload" : "يۈكلە",
@@ -34,6 +31,7 @@ OC.L10N.register(
"Settings" : "تەڭشەكلەر",
"WebDAV" : "WebDAV",
"Cancel upload" : "يۈكلەشتىن ۋاز كەچ",
- "Upload too large" : "يۈكلەندىغىنى بەك چوڭ"
+ "Upload too large" : "يۈكلەندىغىنى بەك چوڭ",
+ "Text file" : "تېكىست ھۆججەت"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/ug.json b/apps/files/l10n/ug.json
index 4a4b06b559e..dd2e9c98ee5 100644
--- a/apps/files/l10n/ug.json
+++ b/apps/files/l10n/ug.json
@@ -1,6 +1,5 @@
{ "translations": {
"Unknown error" : "يوچۇن خاتالىق",
- "Could not move %s" : "%s يۆتكىيەلمەيدۇ",
"No file was uploaded. Unknown error" : "ھېچقانداق ھۆججەت يۈكلەنمىدى. يوچۇن خاتالىق",
"No file was uploaded" : "ھېچقانداق ھۆججەت يۈكلەنمىدى",
"Missing a temporary folder" : "ۋاقىتلىق قىسقۇچ كەم.",
@@ -16,15 +15,13 @@
"Download" : "چۈشۈر",
"Rename" : "ئات ئۆزگەرت",
"Delete" : "ئۆچۈر",
+ "Unshare" : "ھەمبەھىرلىمە",
"Pending" : "كۈتۈۋاتىدۇ",
- "Error" : "خاتالىق",
- "{new_name} already exists" : "{new_name} مەۋجۇت",
"Name" : "ئاتى",
"Size" : "چوڭلۇقى",
"Modified" : "ئۆزگەرتكەن",
"New" : "يېڭى",
"Favorite" : "يىغقۇچ",
- "Text file" : "تېكىست ھۆججەت",
"Folder" : "قىسقۇچ",
"New folder" : "يېڭى قىسقۇچ",
"Upload" : "يۈكلە",
@@ -32,6 +29,7 @@
"Settings" : "تەڭشەكلەر",
"WebDAV" : "WebDAV",
"Cancel upload" : "يۈكلەشتىن ۋاز كەچ",
- "Upload too large" : "يۈكلەندىغىنى بەك چوڭ"
+ "Upload too large" : "يۈكلەندىغىنى بەك چوڭ",
+ "Text file" : "تېكىست ھۆججەت"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/uk.js b/apps/files/l10n/uk.js
index fc071f58279..bda024599f5 100644
--- a/apps/files/l10n/uk.js
+++ b/apps/files/l10n/uk.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "Сховище не доступне",
"Storage invalid" : "Неправильне сховище",
"Unknown error" : "Невідома помилка",
- "Could not move %s - File with this name already exists" : "Не вдалося перемістити %s - файл з таким ім'ям вже існує",
- "Could not move %s" : "Не вдалося перемістити %s",
- "Permission denied" : "Доступ заборонено",
- "The target folder has been moved or deleted." : "Теку призначення було переміщено або видалено.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Файл з ім'ям %s вже є у теці %s. Оберіть інше ім'я.",
- "Error when creating the file" : "Помилка створення файлу",
- "Error when creating the folder" : "Помилка створення теки",
"Unable to set upload directory." : "Не вдалося встановити каталог вивантаження.",
"Invalid Token" : "Неприпустимий маркер",
"No file was uploaded. Unknown error" : "Файл не був вивантажений. Невідома помилка",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "Відсутній тимчасовий каталог",
"Failed to write to disk" : "Помилка запису на диск",
"Not enough storage available" : "Місця більше немає",
+ "The target folder has been moved or deleted." : "Теку призначення було переміщено або видалено.",
"Upload failed. Could not find uploaded file" : "Вивантаження не вдалося. Неможливо знайти вивантажений файл.",
"Upload failed. Could not get file info." : "Вивантаження не вдалося. Неможливо отримати інформацію про файл.",
"Invalid directory." : "Невірний каталог.",
@@ -40,19 +34,13 @@ OC.L10N.register(
"Download" : "Завантажити",
"Rename" : "Перейменувати",
"Delete" : "Видалити",
+ "Disconnect storage" : "Від’єднати сховище",
+ "Unshare" : "Закрити спільний доступ",
"Details" : "Деталі",
"Select" : "Оберіть",
"Pending" : "Очікування",
"Unable to determine date" : "Неможливо визначити дату",
"This operation is forbidden" : "Ця операція заборонена",
- "Error moving file." : "Помилка переміщення файлу.",
- "Error moving file" : "Помилка переміщення файлу",
- "Error" : "Помилка",
- "{new_name} already exists" : "{new_name} вже існує",
- "Could not rename file" : "Неможливо перейменувати файл",
- "Could not create file" : "Не вдалося створити файл",
- "Could not create folder" : "Не вдалося створити теку",
- "Error deleting file." : "Помилка видалення файлу.",
"No entries in this folder match '{filter}'" : "Нічого не знайдено в цій теці '{filter}'",
"Name" : "Ім'я",
"Size" : "Розмір",
@@ -70,7 +58,6 @@ OC.L10N.register(
"_matches '{filter}'_::_match '{filter}'_" : ["знайдено '{filter}'","знайдено '{filter}'","знайдено '{filter}'"],
"Favorited" : "Улюблений",
"Favorite" : "Улюблений",
- "Text file" : "Текстовий файл",
"Folder" : "Тека",
"New folder" : "Нова тека",
"Upload" : "Вивантажити",
@@ -89,8 +76,6 @@ OC.L10N.register(
"%2$s deleted %1$s" : "%2$s видалено %1$s",
"You restored %1$s" : "Вами відновлено %1$s",
"%2$s restored %1$s" : "%2$s відновлено %1$s",
- "%s could not be renamed as it has been deleted" : "%s не можна перейменувати, оскільки його видалено",
- "%s could not be renamed" : "%s не можна перейменувати",
"Upload (max. %s)" : "Вивантаження (макс. %s)",
"File handling" : "Робота з файлами",
"Maximum upload size" : "Максимальний розмір вивантажень",
@@ -106,9 +91,8 @@ OC.L10N.register(
"Select all" : "Вибрати всі",
"Upload too large" : "Файл занадто великий",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Файли,що ви намагаєтесь вивантажити перевищують максимальний дозволений розмір файлів на цьому сервері.",
- "Files are being scanned, please wait." : "Файли перевіряються, зачекайте, будь-ласка.",
- "Currently scanning" : "Триває перевірка",
"No favorites" : "Немає улюблених",
- "Files and folders you mark as favorite will show up here" : "Файли і теки, які ви позначили як улюблені, з’являться тут"
+ "Files and folders you mark as favorite will show up here" : "Файли і теки, які ви позначили як улюблені, з’являться тут",
+ "Text file" : "Текстовий файл"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files/l10n/uk.json b/apps/files/l10n/uk.json
index 651b65df99c..17c055d5539 100644
--- a/apps/files/l10n/uk.json
+++ b/apps/files/l10n/uk.json
@@ -2,13 +2,6 @@
"Storage not available" : "Сховище не доступне",
"Storage invalid" : "Неправильне сховище",
"Unknown error" : "Невідома помилка",
- "Could not move %s - File with this name already exists" : "Не вдалося перемістити %s - файл з таким ім'ям вже існує",
- "Could not move %s" : "Не вдалося перемістити %s",
- "Permission denied" : "Доступ заборонено",
- "The target folder has been moved or deleted." : "Теку призначення було переміщено або видалено.",
- "The name %s is already used in the folder %s. Please choose a different name." : "Файл з ім'ям %s вже є у теці %s. Оберіть інше ім'я.",
- "Error when creating the file" : "Помилка створення файлу",
- "Error when creating the folder" : "Помилка створення теки",
"Unable to set upload directory." : "Не вдалося встановити каталог вивантаження.",
"Invalid Token" : "Неприпустимий маркер",
"No file was uploaded. Unknown error" : "Файл не був вивантажений. Невідома помилка",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "Відсутній тимчасовий каталог",
"Failed to write to disk" : "Помилка запису на диск",
"Not enough storage available" : "Місця більше немає",
+ "The target folder has been moved or deleted." : "Теку призначення було переміщено або видалено.",
"Upload failed. Could not find uploaded file" : "Вивантаження не вдалося. Неможливо знайти вивантажений файл.",
"Upload failed. Could not get file info." : "Вивантаження не вдалося. Неможливо отримати інформацію про файл.",
"Invalid directory." : "Невірний каталог.",
@@ -38,19 +32,13 @@
"Download" : "Завантажити",
"Rename" : "Перейменувати",
"Delete" : "Видалити",
+ "Disconnect storage" : "Від’єднати сховище",
+ "Unshare" : "Закрити спільний доступ",
"Details" : "Деталі",
"Select" : "Оберіть",
"Pending" : "Очікування",
"Unable to determine date" : "Неможливо визначити дату",
"This operation is forbidden" : "Ця операція заборонена",
- "Error moving file." : "Помилка переміщення файлу.",
- "Error moving file" : "Помилка переміщення файлу",
- "Error" : "Помилка",
- "{new_name} already exists" : "{new_name} вже існує",
- "Could not rename file" : "Неможливо перейменувати файл",
- "Could not create file" : "Не вдалося створити файл",
- "Could not create folder" : "Не вдалося створити теку",
- "Error deleting file." : "Помилка видалення файлу.",
"No entries in this folder match '{filter}'" : "Нічого не знайдено в цій теці '{filter}'",
"Name" : "Ім'я",
"Size" : "Розмір",
@@ -68,7 +56,6 @@
"_matches '{filter}'_::_match '{filter}'_" : ["знайдено '{filter}'","знайдено '{filter}'","знайдено '{filter}'"],
"Favorited" : "Улюблений",
"Favorite" : "Улюблений",
- "Text file" : "Текстовий файл",
"Folder" : "Тека",
"New folder" : "Нова тека",
"Upload" : "Вивантажити",
@@ -87,8 +74,6 @@
"%2$s deleted %1$s" : "%2$s видалено %1$s",
"You restored %1$s" : "Вами відновлено %1$s",
"%2$s restored %1$s" : "%2$s відновлено %1$s",
- "%s could not be renamed as it has been deleted" : "%s не можна перейменувати, оскільки його видалено",
- "%s could not be renamed" : "%s не можна перейменувати",
"Upload (max. %s)" : "Вивантаження (макс. %s)",
"File handling" : "Робота з файлами",
"Maximum upload size" : "Максимальний розмір вивантажень",
@@ -104,9 +89,8 @@
"Select all" : "Вибрати всі",
"Upload too large" : "Файл занадто великий",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Файли,що ви намагаєтесь вивантажити перевищують максимальний дозволений розмір файлів на цьому сервері.",
- "Files are being scanned, please wait." : "Файли перевіряються, зачекайте, будь-ласка.",
- "Currently scanning" : "Триває перевірка",
"No favorites" : "Немає улюблених",
- "Files and folders you mark as favorite will show up here" : "Файли і теки, які ви позначили як улюблені, з’являться тут"
+ "Files and folders you mark as favorite will show up here" : "Файли і теки, які ви позначили як улюблені, з’являться тут",
+ "Text file" : "Текстовий файл"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files/l10n/ur_PK.js b/apps/files/l10n/ur_PK.js
index 2265e52d771..094511db425 100644
--- a/apps/files/l10n/ur_PK.js
+++ b/apps/files/l10n/ur_PK.js
@@ -5,7 +5,7 @@ OC.L10N.register(
"Close" : "بند ",
"Download" : "ڈاؤن لوڈ،",
"Delete" : "حذف کریں",
- "Error" : "ایرر",
+ "Unshare" : "شئیرنگ ختم کریں",
"Name" : "اسم",
"Save" : "حفظ",
"Settings" : "ترتیبات"
diff --git a/apps/files/l10n/ur_PK.json b/apps/files/l10n/ur_PK.json
index e8eb736811c..3c859bb452d 100644
--- a/apps/files/l10n/ur_PK.json
+++ b/apps/files/l10n/ur_PK.json
@@ -3,7 +3,7 @@
"Close" : "بند ",
"Download" : "ڈاؤن لوڈ،",
"Delete" : "حذف کریں",
- "Error" : "ایرر",
+ "Unshare" : "شئیرنگ ختم کریں",
"Name" : "اسم",
"Save" : "حفظ",
"Settings" : "ترتیبات"
diff --git a/apps/files/l10n/vi.js b/apps/files/l10n/vi.js
index e51ae0b46f3..953604a945d 100644
--- a/apps/files/l10n/vi.js
+++ b/apps/files/l10n/vi.js
@@ -4,11 +4,6 @@ OC.L10N.register(
"Storage not available" : "Lưu trữ không có sẵn",
"Storage invalid" : "Lưu trữ không hợp lệ",
"Unknown error" : "Lỗi chưa biết",
- "Could not move %s - File with this name already exists" : "Không thể di chuyển %s - Đã có tên tập tin này trên hệ thống",
- "Could not move %s" : "Không thể di chuyển %s",
- "The name %s is already used in the folder %s. Please choose a different name." : "Tên %s đã được sử dụng trong thư mục %s. Hãy chọn tên khác.",
- "Error when creating the file" : "Lỗi khi tạo file",
- "Error when creating the folder" : "Lỗi khi tạo thư mục",
"Unable to set upload directory." : "Không thể thiết lập thư mục tải lên.",
"Invalid Token" : "Xác thực không hợp lệ",
"No file was uploaded. Unknown error" : "Không có tập tin nào được tải lên. Lỗi không xác định",
@@ -35,16 +30,10 @@ OC.L10N.register(
"Download" : "Tải về",
"Rename" : "Sửa tên",
"Delete" : "Xóa",
+ "Unshare" : "Bỏ chia sẻ",
"Details" : "Chi tiết",
"Select" : "Chọn",
"Pending" : "Đang chờ",
- "Error moving file" : "Lỗi di chuyển tập tin",
- "Error" : "Lỗi",
- "{new_name} already exists" : "{new_name} đã tồn tại",
- "Could not rename file" : "Không thể đổi tên file",
- "Could not create file" : "Không thể tạo file",
- "Could not create folder" : "Không thể tạo thư mục",
- "Error deleting file." : "Lỗi xóa file,",
"Name" : "Tên",
"Size" : "Kích cỡ",
"Modified" : "Thay đổi",
@@ -58,11 +47,9 @@ OC.L10N.register(
"Your storage is full, files can not be updated or synced anymore!" : "Your storage is full, files can not be updated or synced anymore!",
"Your storage is almost full ({usedSpacePercent}%)" : "Your storage is almost full ({usedSpacePercent}%)",
"Favorite" : "Ưu thích",
- "Text file" : "Tập tin văn bản",
"Folder" : "Thư mục",
"New folder" : "Tạo thư mục",
"Upload" : "Tải lên",
- "%s could not be renamed" : "%s không thể đổi tên",
"File handling" : "Xử lý tập tin",
"Maximum upload size" : "Kích thước tối đa ",
"max. possible: " : "tối đa cho phép:",
@@ -74,6 +61,6 @@ OC.L10N.register(
"Select all" : "Chọn tất cả",
"Upload too large" : "Tập tin tải lên quá lớn",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Các tập tin bạn đang tải lên vượt quá kích thước tối đa cho phép trên máy chủ .",
- "Files are being scanned, please wait." : "Tập tin đang được quét ,vui lòng chờ."
+ "Text file" : "Tập tin văn bản"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/vi.json b/apps/files/l10n/vi.json
index bd6250322de..40c64f01ff4 100644
--- a/apps/files/l10n/vi.json
+++ b/apps/files/l10n/vi.json
@@ -2,11 +2,6 @@
"Storage not available" : "Lưu trữ không có sẵn",
"Storage invalid" : "Lưu trữ không hợp lệ",
"Unknown error" : "Lỗi chưa biết",
- "Could not move %s - File with this name already exists" : "Không thể di chuyển %s - Đã có tên tập tin này trên hệ thống",
- "Could not move %s" : "Không thể di chuyển %s",
- "The name %s is already used in the folder %s. Please choose a different name." : "Tên %s đã được sử dụng trong thư mục %s. Hãy chọn tên khác.",
- "Error when creating the file" : "Lỗi khi tạo file",
- "Error when creating the folder" : "Lỗi khi tạo thư mục",
"Unable to set upload directory." : "Không thể thiết lập thư mục tải lên.",
"Invalid Token" : "Xác thực không hợp lệ",
"No file was uploaded. Unknown error" : "Không có tập tin nào được tải lên. Lỗi không xác định",
@@ -33,16 +28,10 @@
"Download" : "Tải về",
"Rename" : "Sửa tên",
"Delete" : "Xóa",
+ "Unshare" : "Bỏ chia sẻ",
"Details" : "Chi tiết",
"Select" : "Chọn",
"Pending" : "Đang chờ",
- "Error moving file" : "Lỗi di chuyển tập tin",
- "Error" : "Lỗi",
- "{new_name} already exists" : "{new_name} đã tồn tại",
- "Could not rename file" : "Không thể đổi tên file",
- "Could not create file" : "Không thể tạo file",
- "Could not create folder" : "Không thể tạo thư mục",
- "Error deleting file." : "Lỗi xóa file,",
"Name" : "Tên",
"Size" : "Kích cỡ",
"Modified" : "Thay đổi",
@@ -56,11 +45,9 @@
"Your storage is full, files can not be updated or synced anymore!" : "Your storage is full, files can not be updated or synced anymore!",
"Your storage is almost full ({usedSpacePercent}%)" : "Your storage is almost full ({usedSpacePercent}%)",
"Favorite" : "Ưu thích",
- "Text file" : "Tập tin văn bản",
"Folder" : "Thư mục",
"New folder" : "Tạo thư mục",
"Upload" : "Tải lên",
- "%s could not be renamed" : "%s không thể đổi tên",
"File handling" : "Xử lý tập tin",
"Maximum upload size" : "Kích thước tối đa ",
"max. possible: " : "tối đa cho phép:",
@@ -72,6 +59,6 @@
"Select all" : "Chọn tất cả",
"Upload too large" : "Tập tin tải lên quá lớn",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Các tập tin bạn đang tải lên vượt quá kích thước tối đa cho phép trên máy chủ .",
- "Files are being scanned, please wait." : "Tập tin đang được quét ,vui lòng chờ."
+ "Text file" : "Tập tin văn bản"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/zh_CN.js b/apps/files/l10n/zh_CN.js
index e3f113d82fa..c9a07a0199c 100644
--- a/apps/files/l10n/zh_CN.js
+++ b/apps/files/l10n/zh_CN.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "存储空间不可用",
"Storage invalid" : "存储空间无效",
"Unknown error" : "未知错误",
- "Could not move %s - File with this name already exists" : "无法移动 %s - 同名文件已存在",
- "Could not move %s" : "无法移动 %s",
- "Permission denied" : "拒绝访问",
- "The target folder has been moved or deleted." : "目标文件夹已经被移动或删除。",
- "The name %s is already used in the folder %s. Please choose a different name." : "文件名 %s 是已经在 %s 中存在的名称。请使用其他名称。",
- "Error when creating the file" : "创建文件时出错",
- "Error when creating the folder" : "创建文件夹出错",
"Unable to set upload directory." : "无法设置上传文件夹。",
"Invalid Token" : "无效密匙",
"No file was uploaded. Unknown error" : "没有文件被上传。未知错误",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "缺少临时目录",
"Failed to write to disk" : "写入磁盘失败",
"Not enough storage available" : "没有足够的存储空间",
+ "The target folder has been moved or deleted." : "目标文件夹已经被移动或删除。",
"Upload failed. Could not find uploaded file" : "上传失败。未发现上传的文件",
"Upload failed. Could not get file info." : "上传失败。无法获取文件信息。",
"Invalid directory." : "无效文件夹。",
@@ -40,20 +34,25 @@ OC.L10N.register(
"Download" : "下载",
"Rename" : "重命名",
"Delete" : "删除",
+ "Disconnect storage" : "断开储存连接",
+ "Unshare" : "取消共享",
"Details" : "详细信息",
"Select" : "选择",
"Pending" : "等待",
"Unable to determine date" : "无法确定日期",
"This operation is forbidden" : "操作被禁止",
"This directory is unavailable, please check the logs or contact the administrator" : "此目录不可用,请检查日志或联系管理员",
- "Error moving file." : "移动文件出错。",
- "Error moving file" : "移动文件错误",
- "Error" : "错误",
- "{new_name} already exists" : "{new_name} 已存在",
- "Could not rename file" : "不能重命名文件",
- "Could not create file" : "不能创建文件",
- "Could not create folder" : "不能创建文件夹",
- "Error deleting file." : "删除文件出错。",
+ "Could not move \"{file}\", target exists" : "不能移动 \"{file}\",目标已存在。",
+ "Could not move \"{file}\"" : "不能移动 \"{file}\"",
+ "{newName} already exists" : "{newname} 已经存在",
+ "Could not rename \"{fileName}\", it does not exist any more" : "不能重命名 \"{fileName}\",此文件已经不存在",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "在文件夹 \"{dir}\" 中已经存在 \"{targetName}\" 。请换一个名字试下。",
+ "Could not rename \"{fileName}\"" : "不能重命名 \"{fileName}\"",
+ "Could not create file \"{file}\"" : "不能创建文件 \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "不能创建文件 \"{file}\" ,因为它已经存在",
+ "Could not create folder \"{dir}\"" : "不能创建文件夹 \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "不能创建文件夹 \"{dir}\" ,因为它已经存在",
+ "Error deleting file \"{fileName}\"." : "删除文件 \"{fileName}\" 时出错。",
"No entries in this folder match '{filter}'" : "此文件夹中无项目匹配“{filter}”",
"Name" : "名称",
"Size" : "大小",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n 字节"],
"Favorited" : "已收藏",
"Favorite" : "收藏",
- "Text file" : "文本文件",
- "New text file.txt" : "创建文本文件 .txt",
"Folder" : "文件夹",
"New folder" : "增加文件夹",
"{newname} already exists" : "{newname} 已经存在",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "被 %2$s 更改",
"Deleted by %2$s" : "被 %2$s 删除",
"Restored by %2$s" : "被 %2$s 恢复",
- "%s could not be renamed as it has been deleted" : "%s 已经被删除,无法重命名 ",
- "%s could not be renamed" : "%s 不能被重命名",
"Upload (max. %s)" : "上传 (最大 %s)",
"File handling" : "文件处理",
"Maximum upload size" : "最大上传大小",
"max. possible: " : "最大允许: ",
"Save" : "保存",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "对于 PHP-FPM 这个值改变后可能需要 5 分钟才会生效。",
+ "Missing permissions to edit from here." : "没有从这里进行编辑的权限",
"Settings" : "设置",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "使用这个地址 <a href=\"%s\" target=\"_blank\">通过 WebDAV 访问您的文件</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "全部选择",
"Upload too large" : "上传文件过大",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "您正尝试上传的文件超过了此服务器可以上传的最大容量限制",
- "Files are being scanned, please wait." : "文件正在被扫描,请稍候。",
- "Currently scanning" : "正在扫描",
"No favorites" : "无收藏",
- "Files and folders you mark as favorite will show up here" : "收藏的文件和文件夹会在这里显示"
+ "Files and folders you mark as favorite will show up here" : "收藏的文件和文件夹会在这里显示",
+ "Text file" : "文本文件",
+ "New text file.txt" : "创建文本文件 .txt"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/zh_CN.json b/apps/files/l10n/zh_CN.json
index 177be39683c..1ae61d0119b 100644
--- a/apps/files/l10n/zh_CN.json
+++ b/apps/files/l10n/zh_CN.json
@@ -2,13 +2,6 @@
"Storage not available" : "存储空间不可用",
"Storage invalid" : "存储空间无效",
"Unknown error" : "未知错误",
- "Could not move %s - File with this name already exists" : "无法移动 %s - 同名文件已存在",
- "Could not move %s" : "无法移动 %s",
- "Permission denied" : "拒绝访问",
- "The target folder has been moved or deleted." : "目标文件夹已经被移动或删除。",
- "The name %s is already used in the folder %s. Please choose a different name." : "文件名 %s 是已经在 %s 中存在的名称。请使用其他名称。",
- "Error when creating the file" : "创建文件时出错",
- "Error when creating the folder" : "创建文件夹出错",
"Unable to set upload directory." : "无法设置上传文件夹。",
"Invalid Token" : "无效密匙",
"No file was uploaded. Unknown error" : "没有文件被上传。未知错误",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "缺少临时目录",
"Failed to write to disk" : "写入磁盘失败",
"Not enough storage available" : "没有足够的存储空间",
+ "The target folder has been moved or deleted." : "目标文件夹已经被移动或删除。",
"Upload failed. Could not find uploaded file" : "上传失败。未发现上传的文件",
"Upload failed. Could not get file info." : "上传失败。无法获取文件信息。",
"Invalid directory." : "无效文件夹。",
@@ -38,20 +32,25 @@
"Download" : "下载",
"Rename" : "重命名",
"Delete" : "删除",
+ "Disconnect storage" : "断开储存连接",
+ "Unshare" : "取消共享",
"Details" : "详细信息",
"Select" : "选择",
"Pending" : "等待",
"Unable to determine date" : "无法确定日期",
"This operation is forbidden" : "操作被禁止",
"This directory is unavailable, please check the logs or contact the administrator" : "此目录不可用,请检查日志或联系管理员",
- "Error moving file." : "移动文件出错。",
- "Error moving file" : "移动文件错误",
- "Error" : "错误",
- "{new_name} already exists" : "{new_name} 已存在",
- "Could not rename file" : "不能重命名文件",
- "Could not create file" : "不能创建文件",
- "Could not create folder" : "不能创建文件夹",
- "Error deleting file." : "删除文件出错。",
+ "Could not move \"{file}\", target exists" : "不能移动 \"{file}\",目标已存在。",
+ "Could not move \"{file}\"" : "不能移动 \"{file}\"",
+ "{newName} already exists" : "{newname} 已经存在",
+ "Could not rename \"{fileName}\", it does not exist any more" : "不能重命名 \"{fileName}\",此文件已经不存在",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "在文件夹 \"{dir}\" 中已经存在 \"{targetName}\" 。请换一个名字试下。",
+ "Could not rename \"{fileName}\"" : "不能重命名 \"{fileName}\"",
+ "Could not create file \"{file}\"" : "不能创建文件 \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "不能创建文件 \"{file}\" ,因为它已经存在",
+ "Could not create folder \"{dir}\"" : "不能创建文件夹 \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "不能创建文件夹 \"{dir}\" ,因为它已经存在",
+ "Error deleting file \"{fileName}\"." : "删除文件 \"{fileName}\" 时出错。",
"No entries in this folder match '{filter}'" : "此文件夹中无项目匹配“{filter}”",
"Name" : "名称",
"Size" : "大小",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n 字节"],
"Favorited" : "已收藏",
"Favorite" : "收藏",
- "Text file" : "文本文件",
- "New text file.txt" : "创建文本文件 .txt",
"Folder" : "文件夹",
"New folder" : "增加文件夹",
"{newname} already exists" : "{newname} 已经存在",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "被 %2$s 更改",
"Deleted by %2$s" : "被 %2$s 删除",
"Restored by %2$s" : "被 %2$s 恢复",
- "%s could not be renamed as it has been deleted" : "%s 已经被删除,无法重命名 ",
- "%s could not be renamed" : "%s 不能被重命名",
"Upload (max. %s)" : "上传 (最大 %s)",
"File handling" : "文件处理",
"Maximum upload size" : "最大上传大小",
"max. possible: " : "最大允许: ",
"Save" : "保存",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "对于 PHP-FPM 这个值改变后可能需要 5 分钟才会生效。",
+ "Missing permissions to edit from here." : "没有从这里进行编辑的权限",
"Settings" : "设置",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "使用这个地址 <a href=\"%s\" target=\"_blank\">通过 WebDAV 访问您的文件</a>",
@@ -114,9 +111,9 @@
"Select all" : "全部选择",
"Upload too large" : "上传文件过大",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "您正尝试上传的文件超过了此服务器可以上传的最大容量限制",
- "Files are being scanned, please wait." : "文件正在被扫描,请稍候。",
- "Currently scanning" : "正在扫描",
"No favorites" : "无收藏",
- "Files and folders you mark as favorite will show up here" : "收藏的文件和文件夹会在这里显示"
+ "Files and folders you mark as favorite will show up here" : "收藏的文件和文件夹会在这里显示",
+ "Text file" : "文本文件",
+ "New text file.txt" : "创建文本文件 .txt"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/l10n/zh_HK.js b/apps/files/l10n/zh_HK.js
index 3a984b345ce..8ecae84be99 100644
--- a/apps/files/l10n/zh_HK.js
+++ b/apps/files/l10n/zh_HK.js
@@ -9,7 +9,7 @@ OC.L10N.register(
"Download" : "下載",
"Rename" : "重新命名",
"Delete" : "刪除",
- "Error" : "錯誤",
+ "Unshare" : "取消分享",
"Name" : "名稱",
"Size" : "大小",
"{dirs} and {files}" : "{dirs} 和 {files}",
diff --git a/apps/files/l10n/zh_HK.json b/apps/files/l10n/zh_HK.json
index 8b6572bc376..798dbe13abe 100644
--- a/apps/files/l10n/zh_HK.json
+++ b/apps/files/l10n/zh_HK.json
@@ -7,7 +7,7 @@
"Download" : "下載",
"Rename" : "重新命名",
"Delete" : "刪除",
- "Error" : "錯誤",
+ "Unshare" : "取消分享",
"Name" : "名稱",
"Size" : "大小",
"{dirs} and {files}" : "{dirs} 和 {files}",
diff --git a/apps/files/l10n/zh_TW.js b/apps/files/l10n/zh_TW.js
index c38488d3087..0f013be694f 100644
--- a/apps/files/l10n/zh_TW.js
+++ b/apps/files/l10n/zh_TW.js
@@ -4,13 +4,6 @@ OC.L10N.register(
"Storage not available" : "無法存取儲存空間",
"Storage invalid" : "無效的儲存空間",
"Unknown error" : "未知的錯誤",
- "Could not move %s - File with this name already exists" : "無法移動 %s ,同名的檔案已經存在",
- "Could not move %s" : "無法移動 %s",
- "Permission denied" : "存取被拒",
- "The target folder has been moved or deleted." : "目標資料夾已經被搬移或刪除",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s 已經被使用於資料夾 %s ,請換一個名字",
- "Error when creating the file" : "建立檔案失敗",
- "Error when creating the folder" : "建立資料夾失敗",
"Unable to set upload directory." : "無法設定上傳目錄",
"Invalid Token" : "無效的 token",
"No file was uploaded. Unknown error" : "沒有檔案被上傳,原因未知",
@@ -22,6 +15,7 @@ OC.L10N.register(
"Missing a temporary folder" : "找不到暫存資料夾",
"Failed to write to disk" : "寫入硬碟失敗",
"Not enough storage available" : "儲存空間不足",
+ "The target folder has been moved or deleted." : "目標資料夾已經被搬移或刪除",
"Upload failed. Could not find uploaded file" : "上傳失敗,找不到上傳的檔案",
"Upload failed. Could not get file info." : "上傳失敗,無法取得檔案資訊",
"Invalid directory." : "無效的資料夾",
@@ -35,25 +29,30 @@ OC.L10N.register(
"Total file size {size1} exceeds upload limit {size2}" : "檔案大小總和 {size1} 超過上傳限制 {size2}",
"Not enough free space, you are uploading {size1} but only {size2} is left" : "可用空間不足,你正要上傳 {size1} 可是只剩下 {size2}",
"Could not get result from server." : "無法從伺服器取回結果",
- "File upload is in progress. Leaving the page now will cancel the upload." : "檔案上傳中,離開此頁面將會取消上傳。",
+ "File upload is in progress. Leaving the page now will cancel the upload." : "檔案上傳中,離開此頁面將會取消上傳",
"Actions" : "動作",
"Download" : "下載",
"Rename" : "重新命名",
"Delete" : "刪除",
+ "Disconnect storage" : "斷開儲存空間連接",
+ "Unshare" : "取消分享",
"Details" : "詳細資料",
"Select" : "選擇",
"Pending" : "等候中",
"Unable to determine date" : "無法確定日期",
"This operation is forbidden" : "此動作被禁止",
"This directory is unavailable, please check the logs or contact the administrator" : "這個目錄無法存取,請檢查伺服器記錄檔或聯絡管理員",
- "Error moving file." : "移動檔案發生錯誤",
- "Error moving file" : "移動檔案失敗",
- "Error" : "錯誤",
- "{new_name} already exists" : "{new_name} 已經存在",
- "Could not rename file" : "無法重新命名",
- "Could not create file" : "無法建立檔案",
- "Could not create folder" : "無法建立資料夾",
- "Error deleting file." : "刪除檔案發生錯誤",
+ "Could not move \"{file}\", target exists" : "無法移動 \"{file}\",目標已經存在",
+ "Could not move \"{file}\"" : "無法移動 \"{file}\"",
+ "{newName} already exists" : "{newName} 已經存在",
+ "Could not rename \"{fileName}\", it does not exist any more" : "無法命名檔案 \"{fileName}\",因為此檔案已經不存在",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "此名稱 \"{targetName}\" 在這資料夾 \"{dir}\" 已經被使用。請重新選擇不同的名稱",
+ "Could not rename \"{fileName}\"" : "無法重新命名 \"{fileName}\"",
+ "Could not create file \"{file}\"" : "無法建立檔案 \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "無法建立檔案 \"{file}\",因為此檔案已存在",
+ "Could not create folder \"{dir}\"" : "無法建立資料夾 \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "無法建立資料夾 \"{dir}\",因為此資料夾已存在",
+ "Error deleting file \"{fileName}\"." : "刪除 \"{fileName}\" 出錯",
"No entries in this folder match '{filter}'" : "在此資料夾中沒有項目與 '{filter}' 相符",
"Name" : "名稱",
"Size" : "大小",
@@ -75,8 +74,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n 位元組"],
"Favorited" : "已加入最愛",
"Favorite" : "我的最愛",
- "Text file" : "文字檔",
- "New text file.txt" : "新文字檔.txt",
"Folder" : "資料夾",
"New folder" : "新資料夾",
"{newname} already exists" : "{newname} 已經存在",
@@ -99,13 +96,13 @@ OC.L10N.register(
"Changed by %2$s" : "由 %2$s 改動",
"Deleted by %2$s" : "由 %2$s 刪除",
"Restored by %2$s" : "由 %2$s 還原",
- "%s could not be renamed as it has been deleted" : "%s 已經被刪除了所以無法重新命名",
- "%s could not be renamed" : "無法重新命名 %s",
"Upload (max. %s)" : "上傳(至多 %s)",
"File handling" : "檔案處理",
"Maximum upload size" : "上傳限制",
"max. possible: " : "最大允許:",
"Save" : "儲存",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "如果使用 PHP-FPM ,此設定值需要5分鐘左右才會生效。",
+ "Missing permissions to edit from here." : "您沒有在此編輯的權限",
"Settings" : "設定",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "使用這個地址<a href=\"%s\" target=\"_blank\">來透過 WebDAV 存取檔案</a>",
@@ -116,9 +113,9 @@ OC.L10N.register(
"Select all" : "全選",
"Upload too large" : "上傳過大",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "您試圖上傳的檔案大小超過伺服器的限制",
- "Files are being scanned, please wait." : "正在掃描檔案,請稍等",
- "Currently scanning" : "正在掃描",
"No favorites" : "沒有最愛",
- "Files and folders you mark as favorite will show up here" : "您標記為最愛的檔案與資料夾將會顯示在這裡"
+ "Files and folders you mark as favorite will show up here" : "您標記為最愛的檔案與資料夾將會顯示在這裡",
+ "Text file" : "文字檔",
+ "New text file.txt" : "新文字檔.txt"
},
"nplurals=1; plural=0;");
diff --git a/apps/files/l10n/zh_TW.json b/apps/files/l10n/zh_TW.json
index 8a408b5ffad..1258145c71f 100644
--- a/apps/files/l10n/zh_TW.json
+++ b/apps/files/l10n/zh_TW.json
@@ -2,13 +2,6 @@
"Storage not available" : "無法存取儲存空間",
"Storage invalid" : "無效的儲存空間",
"Unknown error" : "未知的錯誤",
- "Could not move %s - File with this name already exists" : "無法移動 %s ,同名的檔案已經存在",
- "Could not move %s" : "無法移動 %s",
- "Permission denied" : "存取被拒",
- "The target folder has been moved or deleted." : "目標資料夾已經被搬移或刪除",
- "The name %s is already used in the folder %s. Please choose a different name." : "%s 已經被使用於資料夾 %s ,請換一個名字",
- "Error when creating the file" : "建立檔案失敗",
- "Error when creating the folder" : "建立資料夾失敗",
"Unable to set upload directory." : "無法設定上傳目錄",
"Invalid Token" : "無效的 token",
"No file was uploaded. Unknown error" : "沒有檔案被上傳,原因未知",
@@ -20,6 +13,7 @@
"Missing a temporary folder" : "找不到暫存資料夾",
"Failed to write to disk" : "寫入硬碟失敗",
"Not enough storage available" : "儲存空間不足",
+ "The target folder has been moved or deleted." : "目標資料夾已經被搬移或刪除",
"Upload failed. Could not find uploaded file" : "上傳失敗,找不到上傳的檔案",
"Upload failed. Could not get file info." : "上傳失敗,無法取得檔案資訊",
"Invalid directory." : "無效的資料夾",
@@ -33,25 +27,30 @@
"Total file size {size1} exceeds upload limit {size2}" : "檔案大小總和 {size1} 超過上傳限制 {size2}",
"Not enough free space, you are uploading {size1} but only {size2} is left" : "可用空間不足,你正要上傳 {size1} 可是只剩下 {size2}",
"Could not get result from server." : "無法從伺服器取回結果",
- "File upload is in progress. Leaving the page now will cancel the upload." : "檔案上傳中,離開此頁面將會取消上傳。",
+ "File upload is in progress. Leaving the page now will cancel the upload." : "檔案上傳中,離開此頁面將會取消上傳",
"Actions" : "動作",
"Download" : "下載",
"Rename" : "重新命名",
"Delete" : "刪除",
+ "Disconnect storage" : "斷開儲存空間連接",
+ "Unshare" : "取消分享",
"Details" : "詳細資料",
"Select" : "選擇",
"Pending" : "等候中",
"Unable to determine date" : "無法確定日期",
"This operation is forbidden" : "此動作被禁止",
"This directory is unavailable, please check the logs or contact the administrator" : "這個目錄無法存取,請檢查伺服器記錄檔或聯絡管理員",
- "Error moving file." : "移動檔案發生錯誤",
- "Error moving file" : "移動檔案失敗",
- "Error" : "錯誤",
- "{new_name} already exists" : "{new_name} 已經存在",
- "Could not rename file" : "無法重新命名",
- "Could not create file" : "無法建立檔案",
- "Could not create folder" : "無法建立資料夾",
- "Error deleting file." : "刪除檔案發生錯誤",
+ "Could not move \"{file}\", target exists" : "無法移動 \"{file}\",目標已經存在",
+ "Could not move \"{file}\"" : "無法移動 \"{file}\"",
+ "{newName} already exists" : "{newName} 已經存在",
+ "Could not rename \"{fileName}\", it does not exist any more" : "無法命名檔案 \"{fileName}\",因為此檔案已經不存在",
+ "The name \"{targetName}\" is already used in the folder \"{dir}\". Please choose a different name." : "此名稱 \"{targetName}\" 在這資料夾 \"{dir}\" 已經被使用。請重新選擇不同的名稱",
+ "Could not rename \"{fileName}\"" : "無法重新命名 \"{fileName}\"",
+ "Could not create file \"{file}\"" : "無法建立檔案 \"{file}\"",
+ "Could not create file \"{file}\" because it already exists" : "無法建立檔案 \"{file}\",因為此檔案已存在",
+ "Could not create folder \"{dir}\"" : "無法建立資料夾 \"{dir}\"",
+ "Could not create folder \"{dir}\" because it already exists" : "無法建立資料夾 \"{dir}\",因為此資料夾已存在",
+ "Error deleting file \"{fileName}\"." : "刪除 \"{fileName}\" 出錯",
"No entries in this folder match '{filter}'" : "在此資料夾中沒有項目與 '{filter}' 相符",
"Name" : "名稱",
"Size" : "大小",
@@ -73,8 +72,6 @@
"_%n byte_::_%n bytes_" : ["%n 位元組"],
"Favorited" : "已加入最愛",
"Favorite" : "我的最愛",
- "Text file" : "文字檔",
- "New text file.txt" : "新文字檔.txt",
"Folder" : "資料夾",
"New folder" : "新資料夾",
"{newname} already exists" : "{newname} 已經存在",
@@ -97,13 +94,13 @@
"Changed by %2$s" : "由 %2$s 改動",
"Deleted by %2$s" : "由 %2$s 刪除",
"Restored by %2$s" : "由 %2$s 還原",
- "%s could not be renamed as it has been deleted" : "%s 已經被刪除了所以無法重新命名",
- "%s could not be renamed" : "無法重新命名 %s",
"Upload (max. %s)" : "上傳(至多 %s)",
"File handling" : "檔案處理",
"Maximum upload size" : "上傳限制",
"max. possible: " : "最大允許:",
"Save" : "儲存",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "如果使用 PHP-FPM ,此設定值需要5分鐘左右才會生效。",
+ "Missing permissions to edit from here." : "您沒有在此編輯的權限",
"Settings" : "設定",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "使用這個地址<a href=\"%s\" target=\"_blank\">來透過 WebDAV 存取檔案</a>",
@@ -114,9 +111,9 @@
"Select all" : "全選",
"Upload too large" : "上傳過大",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "您試圖上傳的檔案大小超過伺服器的限制",
- "Files are being scanned, please wait." : "正在掃描檔案,請稍等",
- "Currently scanning" : "正在掃描",
"No favorites" : "沒有最愛",
- "Files and folders you mark as favorite will show up here" : "您標記為最愛的檔案與資料夾將會顯示在這裡"
+ "Files and folders you mark as favorite will show up here" : "您標記為最愛的檔案與資料夾將會顯示在這裡",
+ "Text file" : "文字檔",
+ "New text file.txt" : "新文字檔.txt"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files/lib/activity.php b/apps/files/lib/activity.php
index f3bbff48640..8d53074da14 100644
--- a/apps/files/lib/activity.php
+++ b/apps/files/lib/activity.php
@@ -2,8 +2,9 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,7 +23,8 @@
namespace OCA\Files;
-use OC\L10N\Factory;
+use OCP\IDBConnection;
+use OCP\L10N\IFactory;
use OCP\Activity\IExtension;
use OCP\Activity\IManager;
use OCP\IConfig;
@@ -43,7 +45,7 @@ class Activity implements IExtension {
/** @var IL10N */
protected $l;
- /** @var Factory */
+ /** @var IFactory */
protected $languageFactory;
/** @var IURLGenerator */
@@ -52,6 +54,9 @@ class Activity implements IExtension {
/** @var \OCP\Activity\IManager */
protected $activityManager;
+ /** @var \OCP\IDBConnection */
+ protected $connection;
+
/** @var \OCP\IConfig */
protected $config;
@@ -59,18 +64,20 @@ class Activity implements IExtension {
protected $helper;
/**
- * @param Factory $languageFactory
+ * @param IFactory $languageFactory
* @param IURLGenerator $URLGenerator
* @param IManager $activityManager
* @param ActivityHelper $helper
+ * @param IDBConnection $connection
* @param IConfig $config
*/
- public function __construct(Factory $languageFactory, IURLGenerator $URLGenerator, IManager $activityManager, ActivityHelper $helper, IConfig $config) {
+ public function __construct(IFactory $languageFactory, IURLGenerator $URLGenerator, IManager $activityManager, ActivityHelper $helper, IDBConnection $connection, IConfig $config) {
$this->languageFactory = $languageFactory;
$this->URLGenerator = $URLGenerator;
$this->l = $this->getL10N();
$this->activityManager = $activityManager;
$this->helper = $helper;
+ $this->connection = $connection;
$this->config = $config;
}
@@ -160,7 +167,7 @@ class Activity implements IExtension {
* @param string $text
* @param IL10N $l
* @param array $params
- * @return bool|string
+ * @return string|false
*/
protected function translateLong($text, IL10N $l, array $params) {
switch ($text) {
@@ -192,7 +199,7 @@ class Activity implements IExtension {
* @param string $text
* @param IL10N $l
* @param array $params
- * @return bool|string
+ * @return string|false
*/
protected function translateShort($text, IL10N $l, array $params) {
switch ($text) {
@@ -379,6 +386,7 @@ class Activity implements IExtension {
*/
$parameters = $fileQueryList = [];
$parameters[] = self::APP_FILES;
+ $parameters[] = self::APP_FILES;
$fileQueryList[] = '(`type` <> ? AND `type` <> ?)';
$parameters[] = self::TYPE_SHARE_CREATED;
@@ -390,13 +398,15 @@ class Activity implements IExtension {
}
foreach ($favorites['folders'] as $favorite) {
$fileQueryList[] = '`file` LIKE ?';
- $parameters[] = $favorite . '/%';
+ $parameters[] = $this->connection->escapeLikeParameter($favorite) . '/%';
}
- $parameters[] = self::APP_FILES;
-
return [
- ' CASE WHEN `app` = ? THEN (' . implode(' OR ', $fileQueryList) . ') ELSE `app` <> ? END ',
+ ' CASE '
+ . 'WHEN `app` <> ? THEN 1 '
+ . 'WHEN `app` = ? AND (' . implode(' OR ', $fileQueryList) . ') THEN 1 '
+ . 'ELSE 0 '
+ . 'END = 1 ',
$parameters,
];
}
diff --git a/apps/files/lib/activityhelper.php b/apps/files/lib/activityhelper.php
index f9ff722b1c2..046dd59bc76 100644
--- a/apps/files/lib/activityhelper.php
+++ b/apps/files/lib/activityhelper.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/lib/app.php b/apps/files/lib/app.php
index 5bd8c127586..981c41ff413 100644
--- a/apps/files/lib/app.php
+++ b/apps/files/lib/app.php
@@ -1,13 +1,11 @@
<?php
/**
- * @author Björn Schießle <schiessle@owncloud.com>
* @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,107 +27,21 @@ namespace OCA\Files;
class App {
/**
- * @var \OC_L10N
- */
- private $l10n;
-
- /**
* @var \OCP\INavigationManager
*/
private static $navigationManager;
/**
- * @var \OC\Files\View
- */
- private $view;
-
- public function __construct($view, $l10n) {
- $this->view = $view;
- $this->l10n = $l10n;
- }
-
- /**
* Returns the app's navigation manager
*
* @return \OCP\INavigationManager
*/
public static function getNavigationManager() {
+ // TODO: move this into a service in the Application class
if (self::$navigationManager === null) {
self::$navigationManager = new \OC\NavigationManager();
}
return self::$navigationManager;
}
- /**
- * rename a file
- *
- * @param string $dir
- * @param string $oldname
- * @param string $newname
- * @return array
- */
- public function rename($dir, $oldname, $newname) {
- $result = array(
- 'success' => false,
- 'data' => NULL
- );
-
- try {
- // check if the new name is conform to file name restrictions
- $this->view->verifyPath($dir, $newname);
- } catch (\OCP\Files\InvalidPathException $ex) {
- $result['data'] = array(
- 'message' => $this->l10n->t($ex->getMessage()),
- 'code' => 'invalidname',
- );
- return $result;
- }
-
- $normalizedOldPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $oldname);
- $normalizedNewPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $newname);
-
- // rename to non-existing folder is denied
- if (!$this->view->file_exists($normalizedOldPath)) {
- $result['data'] = array(
- 'message' => $this->l10n->t('%s could not be renamed as it has been deleted', array($oldname)),
- 'code' => 'sourcenotfound',
- 'oldname' => $oldname,
- 'newname' => $newname,
- );
- }else if (!$this->view->file_exists($dir)) {
- $result['data'] = array('message' => (string)$this->l10n->t(
- 'The target folder has been moved or deleted.',
- array($dir)),
- 'code' => 'targetnotfound'
- );
- // rename to existing file is denied
- } else if ($this->view->file_exists($normalizedNewPath)) {
-
- $result['data'] = array(
- 'message' => $this->l10n->t(
- "The name %s is already used in the folder %s. Please choose a different name.",
- array($newname, $dir))
- );
- } else if (
- // rename to "." is denied
- $newname !== '.' and
- // THEN try to rename
- $this->view->rename($normalizedOldPath, $normalizedNewPath)
- ) {
- // successful rename
- $meta = $this->view->getFileInfo($normalizedNewPath);
- $meta = \OCA\Files\Helper::populateTags(array($meta));
- $fileInfo = \OCA\Files\Helper::formatFileInfo(current($meta));
- $fileInfo['path'] = dirname($normalizedNewPath);
- $result['success'] = true;
- $result['data'] = $fileInfo;
- } else {
- // rename failed
- $result['data'] = array(
- 'message' => $this->l10n->t('%s could not be renamed', array($oldname))
- );
- }
- return $result;
- }
-
}
diff --git a/apps/files/lib/backgroundjob/deleteorphanedtagsjob.php b/apps/files/lib/backgroundjob/deleteorphanedtagsjob.php
new file mode 100644
index 00000000000..33f455b5b40
--- /dev/null
+++ b/apps/files/lib/backgroundjob/deleteorphanedtagsjob.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files\BackgroundJob;
+
+use OC\BackgroundJob\TimedJob;
+
+/**
+ * Delete all share entries that have no matching entries in the file cache table.
+ */
+class DeleteOrphanedTagsJob extends TimedJob {
+
+ /** @var \OCP\IDBConnection */
+ protected $connection;
+
+ /** @var \OCP\ILogger */
+ protected $logger;
+
+ /**
+ * Default interval in minutes
+ *
+ * @var int $defaultIntervalMin
+ **/
+ protected $defaultIntervalMin = 60;
+
+ /**
+ * sets the correct interval for this timed job
+ */
+ public function __construct() {
+ $this->interval = $this->defaultIntervalMin * 60;
+ $this->connection = \OC::$server->getDatabaseConnection();
+ $this->logger = \OC::$server->getLogger();
+ }
+
+ /**
+ * Makes the background job do its work
+ *
+ * @param array $argument unused argument
+ */
+ public function run($argument) {
+ $this->cleanSystemTags();
+ $this->cleanUserTags();
+ }
+
+ /**
+ * Deleting orphaned system tag mappings
+ *
+ * @return int Number of deleted entries
+ */
+ protected function cleanSystemTags() {
+ $subQuery = $this->connection->getQueryBuilder();
+ $subQuery->select($subQuery->expr()->literal('1'))
+ ->from('filecache', 'f')
+ ->where($subQuery->expr()->eq('objectid', 'f.fileid'));
+
+ $query = $this->connection->getQueryBuilder();
+ $deletedEntries = $query->delete('systemtag_object_mapping')
+ ->where($query->expr()->eq('objecttype', $query->expr()->literal('files')))
+ ->andWhere($query->expr()->isNull($query->createFunction('(' . $subQuery->getSql() . ')')))
+ ->execute();
+
+ $this->logger->debug("$deletedEntries orphaned system tag relations deleted", ['app' => 'DeleteOrphanedTagsJob']);
+ return $deletedEntries;
+ }
+
+ /**
+ * Deleting orphaned user tag mappings
+ *
+ * @return int Number of deleted entries
+ */
+ protected function cleanUserTags() {
+ $subQuery = $this->connection->getQueryBuilder();
+ $subQuery->select($subQuery->expr()->literal('1'))
+ ->from('filecache', 'f')
+ ->where($subQuery->expr()->eq('objid', 'f.fileid'));
+
+ $query = $this->connection->getQueryBuilder();
+ $deletedEntries = $query->delete('vcategory_to_object')
+ ->where($query->expr()->eq('type', $query->expr()->literal('files')))
+ ->andWhere($query->expr()->isNull($query->createFunction('(' . $subQuery->getSql() . ')')))
+ ->execute();
+
+ $this->logger->debug("$deletedEntries orphaned user tag relations deleted", ['app' => 'DeleteOrphanedTagsJob']);
+ return $deletedEntries;
+ }
+
+}
diff --git a/apps/files/lib/backgroundjob/scanfiles.php b/apps/files/lib/backgroundjob/scanfiles.php
new file mode 100644
index 00000000000..dcc180bcfbe
--- /dev/null
+++ b/apps/files/lib/backgroundjob/scanfiles.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files\BackgroundJob;
+
+use OC\Files\Utils\Scanner;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\ILogger;
+use OCP\IUser;
+use OCP\IUserManager;
+
+/**
+ * Class ScanFiles is a background job used to run the file scanner over the user
+ * accounts to ensure integrity of the file cache.
+ *
+ * @package OCA\Files\BackgroundJob
+ */
+class ScanFiles extends \OC\BackgroundJob\TimedJob {
+ /** @var IConfig */
+ private $config;
+ /** @var IUserManager */
+ private $userManager;
+ /** @var IDBConnection */
+ private $dbConnection;
+ /** @var ILogger */
+ private $logger;
+ /** Amount of users that should get scanned per execution */
+ const USERS_PER_SESSION = 500;
+
+ /**
+ * @param IConfig|null $config
+ * @param IUserManager|null $userManager
+ * @param IDBConnection|null $dbConnection
+ * @param ILogger|null $logger
+ */
+ public function __construct(IConfig $config = null,
+ IUserManager $userManager = null,
+ IDBConnection $dbConnection = null,
+ ILogger $logger = null) {
+ // Run once per 10 minutes
+ $this->setInterval(60 * 10);
+
+ if (is_null($userManager) || is_null($config)) {
+ $this->fixDIForJobs();
+ } else {
+ $this->config = $config;
+ $this->userManager = $userManager;
+ $this->logger = $logger;
+ }
+ }
+
+ protected function fixDIForJobs() {
+ $this->config = \OC::$server->getConfig();
+ $this->userManager = \OC::$server->getUserManager();
+ $this->logger = \OC::$server->getLogger();
+ }
+
+ /**
+ * @param IUser $user
+ */
+ protected function runScanner(IUser $user) {
+ try {
+ $scanner = new Scanner(
+ $user->getUID(),
+ $this->dbConnection,
+ $this->logger
+ );
+ $scanner->backgroundScan('');
+ } catch (\Exception $e) {
+ $this->logger->logException($e, ['app' => 'files']);
+ }
+ \OC_Util::tearDownFS();
+ }
+
+ /**
+ * @param $argument
+ * @throws \Exception
+ */
+ protected function run($argument) {
+ $offset = $this->config->getAppValue('files', 'cronjob_scan_files', 0);
+ $users = $this->userManager->search('', self::USERS_PER_SESSION, $offset);
+ if (!count($users)) {
+ // No users found, reset offset and retry
+ $offset = 0;
+ $users = $this->userManager->search('', self::USERS_PER_SESSION);
+ }
+
+ $offset += self::USERS_PER_SESSION;
+ $this->config->setAppValue('files', 'cronjob_scan_files', $offset);
+
+ foreach ($users as $user) {
+ $this->runScanner($user);
+ }
+ }
+}
diff --git a/apps/files/lib/capabilities.php b/apps/files/lib/capabilities.php
index 14fb07a9d86..7d50b51bb97 100644
--- a/apps/files/lib/capabilities.php
+++ b/apps/files/lib/capabilities.php
@@ -4,7 +4,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php
index fb14cea731f..d21a65afcee 100644
--- a/apps/files/lib/helper.php
+++ b/apps/files/lib/helper.php
@@ -6,11 +6,12 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -66,15 +67,15 @@ class Helper {
*/
public static function determineIcon($file) {
if($file['type'] === 'dir') {
- $icon = \OC_Helper::mimetypeIcon('dir');
+ $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir');
// TODO: move this part to the client side, using mountType
if ($file->isShared()) {
- $icon = \OC_Helper::mimetypeIcon('dir-shared');
+ $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-shared');
} elseif ($file->isMounted()) {
- $icon = \OC_Helper::mimetypeIcon('dir-external');
+ $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-external');
}
}else{
- $icon = \OC_Helper::mimetypeIcon($file->getMimetype());
+ $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon($file->getMimetype());
}
return substr($icon, 0, -3) . 'svg';
@@ -139,9 +140,6 @@ class Helper {
$entry['parentId'] = $i['parent'];
$entry['mtime'] = $i['mtime'] * 1000;
// only pick out the needed attributes
- if (\OC::$server->getPreviewManager()->isAvailable($i)) {
- $entry['isPreviewAvailable'] = true;
- }
$entry['name'] = $i->getName();
$entry['permissions'] = $i['permissions'];
$entry['mimetype'] = $i['mimetype'];
diff --git a/apps/files/list.php b/apps/files/list.php
index f11becf5721..6d2c463a2d9 100644
--- a/apps/files/list.php
+++ b/apps/files/list.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/service/tagservice.php b/apps/files/service/tagservice.php
index 1999d97e1af..e1425c46615 100644
--- a/apps/files/service/tagservice.php
+++ b/apps/files/service/tagservice.php
@@ -2,9 +2,10 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -91,7 +92,7 @@ class TagService {
/**
* Get all files for the given tag
*
- * @param array $tagName tag name to filter by
+ * @param string $tagName tag name to filter by
* @return FileInfo[] list of matching files
* @throws \Exception if the tag does not exist
*/
diff --git a/apps/files/simplelist.php b/apps/files/simplelist.php
index 80cf8c4a205..2e65eedd1b3 100644
--- a/apps/files/simplelist.php
+++ b/apps/files/simplelist.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/templates/list.php b/apps/files/templates/list.php
index 7ebf80ee8b2..ea3e6c61d4a 100644
--- a/apps/files/templates/list.php
+++ b/apps/files/templates/list.php
@@ -1,16 +1,5 @@
<div id="controls">
<div class="actions creatable hidden">
- <?php /*
- Only show upload button for public page
- */ ?>
- <?php if(isset($_['dirToken'])):?>
- <div id="upload" class="button upload"
- title="<?php isset($_['uploadMaxHumanFilesize']) ? p($l->t('Upload (max. %s)', array($_['uploadMaxHumanFilesize']))) : '' ?>">
- <label for="file_upload_start" class="svg icon-upload">
- <span class="hidden-visually"><?php p($l->t('Upload'))?></span>
- </label>
- </div>
- <?php endif; ?>
<div id="uploadprogresswrapper">
<div id="uploadprogressbar"></div>
<button class="stop icon-close" style="display:none">
@@ -64,7 +53,7 @@
<span id="selectedActionsList" class="selectedActions">
<a href="" class="download">
<img class="svg" alt=""
- src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>" />
+ src="<?php print_unescaped(image_path("core", "actions/download.svg")); ?>" />
<?php p($l->t('Download'))?>
</a>
</span>
@@ -78,7 +67,7 @@
<span class="selectedActions"><a href="" class="delete-selected">
<?php p($l->t('Delete'))?>
<img class="svg" alt=""
- src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
+ src="<?php print_unescaped(image_path("core", "actions/delete.svg")); ?>" />
</a></span>
</th>
</tr>
@@ -99,11 +88,3 @@
<?php p($l->t('The files you are trying to upload exceed the maximum size for file uploads on this server.'));?>
</p>
</div>
-<div id="scanning-message">
- <h3>
- <?php p($l->t('Files are being scanned, please wait.'));?> <span id='scan-count'></span>
- </h3>
- <p>
- <?php p($l->t('Currently scanning'));?> <span id='scan-current'></span>
- </p>
-</div>
diff --git a/apps/files/tests/activitytest.php b/apps/files/tests/activitytest.php
index cdb1d21bcd8..5e73ff0b5dd 100644
--- a/apps/files/tests/activitytest.php
+++ b/apps/files/tests/activitytest.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,24 +25,30 @@ namespace OCA\Files\Tests;
use OCA\Files\Activity;
use Test\TestCase;
+/**
+ * Class ActivityTest
+ *
+ * @group DB
+ * @package OCA\Files\Tests
+ */
class ActivityTest extends TestCase {
/** @var \OC\ActivityManager */
private $activityManager;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
+ /** @var \OCP\IRequest|\PHPUnit_Framework_MockObject_MockObject */
protected $request;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
+ /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject */
protected $session;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
+ /** @var \OCP\IConfig|\PHPUnit_Framework_MockObject_MockObject */
protected $config;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
+ /** @var \OCA\Files\ActivityHelper|\PHPUnit_Framework_MockObject_MockObject */
protected $activityHelper;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
+ /** @var \OCP\L10N\IFactory|\PHPUnit_Framework_MockObject_MockObject */
protected $l10nFactory;
/** @var \OCA\Files\Activity */
@@ -70,7 +76,7 @@ class ActivityTest extends TestCase {
$this->config
);
- $this->l10nFactory = $this->getMockBuilder('OC\L10N\Factory')
+ $this->l10nFactory = $this->getMockBuilder('OCP\L10N\IFactory')
->disableOriginalConstructor()
->getMock();
$deL10n = $this->getMockBuilder('OC_L10N')
@@ -95,6 +101,7 @@ class ActivityTest extends TestCase {
$this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(),
$this->activityManager,
$this->activityHelper,
+ \OC::$server->getDatabaseConnection(),
$this->config
);
@@ -290,16 +297,16 @@ class ActivityTest extends TestCase {
'items' => [],
'folders' => [],
],
- ' CASE WHEN `app` = ? THEN ((`type` <> ? AND `type` <> ?)) ELSE `app` <> ? END ',
- ['files', Activity::TYPE_SHARE_CREATED, Activity::TYPE_SHARE_CHANGED, 'files']
+ ' CASE WHEN `app` <> ? THEN 1 WHEN `app` = ? AND ((`type` <> ? AND `type` <> ?)) THEN 1 ELSE 0 END = 1 ',
+ ['files', 'files', Activity::TYPE_SHARE_CREATED, Activity::TYPE_SHARE_CHANGED]
],
[
[
'items' => ['file.txt', 'folder'],
'folders' => ['folder'],
],
- ' CASE WHEN `app` = ? THEN ((`type` <> ? AND `type` <> ?) OR `file` = ? OR `file` = ? OR `file` LIKE ?) ELSE `app` <> ? END ',
- ['files', Activity::TYPE_SHARE_CREATED, Activity::TYPE_SHARE_CHANGED, 'file.txt', 'folder', 'folder/%', 'files']
+ ' CASE WHEN `app` <> ? THEN 1 WHEN `app` = ? AND ((`type` <> ? AND `type` <> ?) OR `file` = ? OR `file` = ? OR `file` LIKE ?) THEN 1 ELSE 0 END = 1 ',
+ ['files', 'files', Activity::TYPE_SHARE_CREATED, Activity::TYPE_SHARE_CHANGED, 'file.txt', 'folder', 'folder/%']
],
];
}
@@ -333,6 +340,21 @@ class ActivityTest extends TestCase {
$result = $this->activityExtension->getQueryForFilter('all');
$this->assertEquals([$query, $parameters], $result);
+
+ $this->executeQueryForFilter($result);
+ }
+
+ public function executeQueryForFilter(array $result) {
+ list($resultQuery, $resultParameters) = $result;
+ $resultQuery = str_replace('`file`', '`user`', $resultQuery);
+ $resultQuery = str_replace('`type`', '`key`', $resultQuery);
+
+ $connection = \OC::$server->getDatabaseConnection();
+ // Test the query on the privatedata table, because the activity table
+ // does not exist in core
+ $result = $connection->executeQuery('SELECT * FROM `*PREFIX*privatedata` WHERE ' . $resultQuery, $resultParameters);
+ $rows = $result->fetchAll();
+ $result->closeCursor();
}
protected function mockUserSession($user) {
diff --git a/apps/files/tests/ajax_rename.php b/apps/files/tests/ajax_rename.php
deleted file mode 100644
index 859c7042b89..00000000000
--- a/apps/files/tests/ajax_rename.php
+++ /dev/null
@@ -1,232 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-class Test_OC_Files_App_Rename extends \Test\TestCase {
- private static $user;
-
- /**
- * @var PHPUnit_Framework_MockObject_MockObject
- */
- private $viewMock;
-
- /**
- * @var \OCA\Files\App
- */
- private $files;
-
- protected function setUp() {
- parent::setUp();
-
- // mock OC_L10n
- if (!self::$user) {
- self::$user = uniqid();
- }
- \OC_User::createUser(self::$user, 'password');
- $this->loginAsUser(self::$user);
-
- $l10nMock = $this->getMock('\OC_L10N', array('t'), array(), '', false);
- $l10nMock->expects($this->any())
- ->method('t')
- ->will($this->returnArgument(0));
- $viewMock = $this->getMock('\OC\Files\View', array('rename', 'normalizePath', 'getFileInfo', 'file_exists'), array(), '', false);
- $viewMock->expects($this->any())
- ->method('normalizePath')
- ->will($this->returnArgument(0));
- $viewMock->expects($this->any())
- ->method('rename')
- ->will($this->returnValue(true));
- $this->viewMock = $viewMock;
- $this->files = new \OCA\Files\App($viewMock, $l10nMock);
- }
-
- protected function tearDown() {
- $result = \OC_User::deleteUser(self::$user);
- $this->assertTrue($result);
-
- $this->logout();
- parent::tearDown();
- }
-
- /**
- * test rename of file/folder
- */
- function testRenameFolder() {
- $dir = '/';
- $oldname = 'oldname';
- $newname = 'newname';
-
- $this->viewMock->expects($this->any())
- ->method('file_exists')
- ->with($this->anything())
- ->will($this->returnValueMap(array(
- array('/', true),
- array('/oldname', true)
- )));
-
-
- $this->viewMock->expects($this->any())
- ->method('getFileInfo')
- ->will($this->returnValue(new \OC\Files\FileInfo(
- '/new_name',
- new \OC\Files\Storage\Local(array('datadir' => '/')),
- '/',
- array(
- 'fileid' => 123,
- 'type' => 'dir',
- 'mimetype' => 'httpd/unix-directory',
- 'mtime' => 0,
- 'permissions' => 31,
- 'size' => 18,
- 'etag' => 'abcdef',
- 'directory' => '/',
- 'name' => 'new_name',
- ), null)));
-
- $result = $this->files->rename($dir, $oldname, $newname);
-
- $this->assertTrue($result['success']);
- $this->assertEquals(123, $result['data']['id']);
- $this->assertEquals('new_name', $result['data']['name']);
- $this->assertEquals(18, $result['data']['size']);
- $this->assertEquals('httpd/unix-directory', $result['data']['mimetype']);
- $this->assertEquals('abcdef', $result['data']['etag']);
- $this->assertFalse(isset($result['data']['tags']));
- $this->assertEquals('/', $result['data']['path']);
- }
-
- /**
- * test rename of file with tag
- */
- function testRenameFileWithTag() {
- $taggerMock = $this->getMock('\OCP\ITags');
- $taggerMock->expects($this->any())
- ->method('getTagsForObjects')
- ->with(array(123))
- ->will($this->returnValue(array(123 => array('tag1', 'tag2'))));
- $tagManagerMock = $this->getMock('\OCP\ITagManager');
- $tagManagerMock->expects($this->any())
- ->method('load')
- ->with('files')
- ->will($this->returnValue($taggerMock));
- $oldTagManager = \OC::$server->query('TagManager');
- \OC::$server->registerService('TagManager', function ($c) use ($tagManagerMock) {
- return $tagManagerMock;
- });
-
- $dir = '/';
- $oldname = 'oldname.txt';
- $newname = 'newname.txt';
-
- $this->viewMock->expects($this->any())
- ->method('file_exists')
- ->with($this->anything())
- ->will($this->returnValueMap(array(
- array('/', true),
- array('/oldname.txt', true)
- )));
-
-
- $this->viewMock->expects($this->any())
- ->method('getFileInfo')
- ->will($this->returnValue(new \OC\Files\FileInfo(
- '/new_name.txt',
- new \OC\Files\Storage\Local(array('datadir' => '/')),
- '/',
- array(
- 'fileid' => 123,
- 'type' => 'file',
- 'mimetype' => 'text/plain',
- 'mtime' => 0,
- 'permissions' => 31,
- 'size' => 18,
- 'etag' => 'abcdef',
- 'directory' => '/',
- 'name' => 'new_name.txt',
- ), null)));
-
- $result = $this->files->rename($dir, $oldname, $newname);
-
- $this->assertTrue($result['success']);
- $this->assertEquals(123, $result['data']['id']);
- $this->assertEquals('new_name.txt', $result['data']['name']);
- $this->assertEquals(18, $result['data']['size']);
- $this->assertEquals('text/plain', $result['data']['mimetype']);
- $this->assertEquals('abcdef', $result['data']['etag']);
- $this->assertEquals(array('tag1', 'tag2'), $result['data']['tags']);
- $this->assertEquals('/', $result['data']['path']);
-
- \OC::$server->registerService('TagManager', function ($c) use ($oldTagManager) {
- return $oldTagManager;
- });
- }
-
- /**
- * Test rename inside a folder that doesn't exist any more
- */
- function testRenameInNonExistingFolder() {
- $dir = '/unexist';
- $oldname = 'oldname';
- $newname = 'newname';
-
- $this->viewMock->expects($this->at(0))
- ->method('file_exists')
- ->with('/unexist/oldname')
- ->will($this->returnValue(false));
-
- $this->viewMock->expects($this->any())
- ->method('getFileInfo')
- ->will($this->returnValue(array(
- 'fileid' => 123,
- 'type' => 'dir',
- 'mimetype' => 'httpd/unix-directory',
- 'size' => 18,
- 'etag' => 'abcdef',
- 'directory' => '/unexist',
- 'name' => 'new_name',
- )));
-
- $result = $this->files->rename($dir, $oldname, $newname);
-
- $this->assertFalse($result['success']);
- $this->assertEquals('sourcenotfound', $result['data']['code']);
- }
-
- /**
- * Test move to invalid name
- */
- function testRenameToInvalidName() {
- $dir = '/';
- $oldname = 'oldname';
- $newname = 'abc\\';
-
- $result = $this->files->rename($dir, $oldname, $newname);
-
- $this->assertFalse($result['success']);
- $this->assertEquals('File name contains at least one invalid character', $result['data']['message']);
- $this->assertEquals('invalidname', $result['data']['code']);
- }
-}
diff --git a/apps/files/tests/backgroundjob/DeleteOrphanedTagsJobTest.php b/apps/files/tests/backgroundjob/DeleteOrphanedTagsJobTest.php
new file mode 100644
index 00000000000..d2e9d77cb20
--- /dev/null
+++ b/apps/files/tests/backgroundjob/DeleteOrphanedTagsJobTest.php
@@ -0,0 +1,158 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files\Tests\BackgroundJob;
+
+use OCA\Files\BackgroundJob\DeleteOrphanedTagsJob;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+
+/**
+ * Class DeleteOrphanedTagsJobTest
+ *
+ * @group DB
+ *
+ * @package Test\BackgroundJob
+ */
+class DeleteOrphanedTagsJobTest extends \Test\TestCase {
+
+ /** @var \OCP\IDBConnection */
+ protected $connection;
+
+ protected function setup() {
+ parent::setUp();
+ $this->connection = \OC::$server->getDatabaseConnection();
+ }
+
+ protected function cleanMapping($table) {
+ $query = $this->connection->getQueryBuilder();
+ $query->delete($table)->execute();
+ }
+
+ protected function getMappings($table) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from($table);
+ $result = $query->execute();
+ $mapping = $result->fetchAll();
+ $result->closeCursor();
+
+ return $mapping;
+ }
+
+ /**
+ * Test clearing orphaned system tag mappings
+ */
+ public function testClearSystemTagMappings() {
+ $this->cleanMapping('systemtag_object_mapping');
+
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('filecache')
+ ->values([
+ 'storage' => $query->createNamedParameter(1337, IQueryBuilder::PARAM_INT),
+ 'path' => $query->createNamedParameter('apps/files/tests/deleteorphanedtagsjobtest.php'),
+ 'path_hash' => $query->createNamedParameter(md5('apps/files/tests/deleteorphanedtagsjobtest.php')),
+ ])->execute();
+ $fileId = $query->getLastInsertId();
+
+ // Existing file
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('systemtag_object_mapping')
+ ->values([
+ 'objectid' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT),
+ 'objecttype' => $query->createNamedParameter('files'),
+ 'systemtagid' => $query->createNamedParameter(1337, IQueryBuilder::PARAM_INT),
+ ])->execute();
+
+ // Non-existing file
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('systemtag_object_mapping')
+ ->values([
+ 'objectid' => $query->createNamedParameter($fileId + 1, IQueryBuilder::PARAM_INT),
+ 'objecttype' => $query->createNamedParameter('files'),
+ 'systemtagid' => $query->createNamedParameter(1337, IQueryBuilder::PARAM_INT),
+ ])->execute();
+
+ $mapping = $this->getMappings('systemtag_object_mapping');
+ $this->assertCount(2, $mapping);
+
+ $job = new DeleteOrphanedTagsJob();
+ $this->invokePrivate($job, 'cleanSystemTags');
+
+ $mapping = $this->getMappings('systemtag_object_mapping');
+ $this->assertCount(1, $mapping);
+
+ $query = $this->connection->getQueryBuilder();
+ $query->delete('filecache')
+ ->where($query->expr()->eq('fileid', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)))
+ ->execute();
+ $this->cleanMapping('systemtag_object_mapping');
+ }
+
+ /**
+ * Test clearing orphaned system tag mappings
+ */
+ public function testClearUserTagMappings() {
+ $this->cleanMapping('vcategory_to_object');
+
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('filecache')
+ ->values([
+ 'storage' => $query->createNamedParameter(1337, IQueryBuilder::PARAM_INT),
+ 'path' => $query->createNamedParameter('apps/files/tests/deleteorphanedtagsjobtest.php'),
+ 'path_hash' => $query->createNamedParameter(md5('apps/files/tests/deleteorphanedtagsjobtest.php')),
+ ])->execute();
+ $fileId = $query->getLastInsertId();
+
+ // Existing file
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('vcategory_to_object')
+ ->values([
+ 'objid' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT),
+ 'type' => $query->createNamedParameter('files'),
+ 'categoryid' => $query->createNamedParameter(1337, IQueryBuilder::PARAM_INT),
+ ])->execute();
+
+ // Non-existing file
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('vcategory_to_object')
+ ->values([
+ 'objid' => $query->createNamedParameter($fileId + 1, IQueryBuilder::PARAM_INT),
+ 'type' => $query->createNamedParameter('files'),
+ 'categoryid' => $query->createNamedParameter(1337, IQueryBuilder::PARAM_INT),
+ ])->execute();
+
+ $mapping = $this->getMappings('vcategory_to_object');
+ $this->assertCount(2, $mapping);
+
+ $job = new DeleteOrphanedTagsJob();
+ $this->invokePrivate($job, 'cleanUserTags');
+
+ $mapping = $this->getMappings('vcategory_to_object');
+ $this->assertCount(1, $mapping);
+
+ $query = $this->connection->getQueryBuilder();
+ $query->delete('filecache')
+ ->where($query->expr()->eq('fileid', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)))
+ ->execute();
+ $this->cleanMapping('vcategory_to_object');
+ }
+
+}
diff --git a/apps/files/tests/backgroundjob/ScanFilesTest.php b/apps/files/tests/backgroundjob/ScanFilesTest.php
new file mode 100644
index 00000000000..eab28071b70
--- /dev/null
+++ b/apps/files/tests/backgroundjob/ScanFilesTest.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\Files\Tests\BackgroundJob;
+
+use Test\TestCase;
+use OCP\IConfig;
+use OCP\IUserManager;
+use OCA\Files\BackgroundJob\ScanFiles;
+
+/**
+ * Class ScanFilesTest
+ *
+ * @package OCA\Files\Tests\BackgroundJob
+ */
+class ScanFilesTest extends TestCase {
+ /** @var IConfig */
+ private $config;
+ /** @var IUserManager */
+ private $userManager;
+ /** @var ScanFiles */
+ private $scanFiles;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->config = $this->getMock('\OCP\IConfig');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+
+ $this->scanFiles = $this->getMockBuilder('\OCA\Files\BackgroundJob\ScanFiles')
+ ->setConstructorArgs([
+ $this->config,
+ $this->userManager,
+ ])
+ ->setMethods(['runScanner'])
+ ->getMock();
+ }
+
+ public function testRunWithoutUsers() {
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('files', 'cronjob_scan_files', 0)
+ ->will($this->returnValue(50));
+ $this->userManager
+ ->expects($this->at(0))
+ ->method('search')
+ ->with('', 500, 50)
+ ->will($this->returnValue([]));
+ $this->userManager
+ ->expects($this->at(1))
+ ->method('search')
+ ->with('', 500)
+ ->will($this->returnValue([]));
+ $this->config
+ ->expects($this->at(1))
+ ->method('setAppValue')
+ ->with('files', 'cronjob_scan_files', 500);
+
+ $this->invokePrivate($this->scanFiles, 'run', [[]]);
+ }
+
+ public function testRunWithUsers() {
+ $fakeUser = $this->getMock('\OCP\IUser');
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('files', 'cronjob_scan_files', 0)
+ ->will($this->returnValue(50));
+ $this->userManager
+ ->expects($this->at(0))
+ ->method('search')
+ ->with('', 500, 50)
+ ->will($this->returnValue([
+ $fakeUser
+ ]));
+ $this->config
+ ->expects($this->at(1))
+ ->method('setAppValue')
+ ->with('files', 'cronjob_scan_files', 550);
+ $this->scanFiles
+ ->expects($this->once())
+ ->method('runScanner')
+ ->with($fakeUser);
+
+ $this->invokePrivate($this->scanFiles, 'run', [[]]);
+ }
+
+ public function testRunWithUsersAndOffsetAtEndOfUserList() {
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('files', 'cronjob_scan_files', 0)
+ ->will($this->returnValue(50));
+ $this->userManager
+ ->expects($this->at(0))
+ ->method('search')
+ ->with('', 500, 50)
+ ->will($this->returnValue([]));
+ $this->userManager
+ ->expects($this->at(1))
+ ->method('search')
+ ->with('', 500)
+ ->will($this->returnValue([]));
+ $this->config
+ ->expects($this->at(1))
+ ->method('setAppValue')
+ ->with('files', 'cronjob_scan_files', 500);
+ $this->scanFiles
+ ->expects($this->never())
+ ->method('runScanner');
+
+ $this->invokePrivate($this->scanFiles, 'run', [[]]);
+ }
+
+}
diff --git a/apps/files/tests/command/deleteorphanedfilestest.php b/apps/files/tests/command/deleteorphanedfilestest.php
index a667dba99fc..ff29942bc4a 100644
--- a/apps/files/tests/command/deleteorphanedfilestest.php
+++ b/apps/files/tests/command/deleteorphanedfilestest.php
@@ -2,8 +2,9 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +26,13 @@ namespace OCA\Files\Tests\Command;
use OCA\Files\Command\DeleteOrphanedFiles;
use OCP\Files\StorageNotAvailableException;
+/**
+ * Class DeleteOrphanedFilesTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files\Tests\Command
+ */
class DeleteOrphanedFilesTest extends \Test\TestCase {
/**
diff --git a/apps/files/tests/controller/ViewControllerTest.php b/apps/files/tests/controller/ViewControllerTest.php
index 028dfce8c58..b5df3cfc904 100644
--- a/apps/files/tests/controller/ViewControllerTest.php
+++ b/apps/files/tests/controller/ViewControllerTest.php
@@ -2,7 +2,7 @@
/**
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -245,6 +245,9 @@ class ViewControllerTest extends TestCase {
],
]
);
+ $policy = new Http\ContentSecurityPolicy();
+ $policy->addAllowedFrameDomain('\'self\'');
+ $expected->setContentSecurityPolicy($policy);
$this->assertEquals($expected, $this->viewController->index('MyDir', 'MyView'));
}
}
diff --git a/apps/files/tests/controller/apicontrollertest.php b/apps/files/tests/controller/apicontrollertest.php
index fb728d5eff0..6fb8340ead8 100644
--- a/apps/files/tests/controller/apicontrollertest.php
+++ b/apps/files/tests/controller/apicontrollertest.php
@@ -3,8 +3,9 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -92,6 +93,7 @@ class ApiControllerTest extends TestCase {
[
'mtime' => 55,
'mimetype' => 'application/pdf',
+ 'permissions' => 31,
'size' => 1234,
'etag' => 'MyEtag',
],
@@ -111,7 +113,7 @@ class ApiControllerTest extends TestCase {
'parentId' => null,
'mtime' => 55000,
'name' => 'root.txt',
- 'permissions' => null,
+ 'permissions' => 31,
'mimetype' => 'application/pdf',
'size' => 1234,
'type' => 'file',
@@ -139,6 +141,7 @@ class ApiControllerTest extends TestCase {
[
'mtime' => 55,
'mimetype' => 'application/pdf',
+ 'permissions' => 31,
'size' => 1234,
'etag' => 'MyEtag',
],
@@ -155,6 +158,7 @@ class ApiControllerTest extends TestCase {
[
'mtime' => 999,
'mimetype' => 'application/binary',
+ 'permissions' => 31,
'size' => 9876,
'etag' => 'SubEtag',
],
@@ -174,7 +178,7 @@ class ApiControllerTest extends TestCase {
'parentId' => null,
'mtime' => 55000,
'name' => 'root.txt',
- 'permissions' => null,
+ 'permissions' => 31,
'mimetype' => 'application/pdf',
'size' => 1234,
'type' => 'file',
@@ -191,7 +195,7 @@ class ApiControllerTest extends TestCase {
'parentId' => null,
'mtime' => 999000,
'name' => 'root.txt',
- 'permissions' => null,
+ 'permissions' => 31,
'mimetype' => 'application/binary',
'size' => 9876,
'type' => 'file',
diff --git a/apps/files/tests/helper.php b/apps/files/tests/helper.php
index 027152a1bb2..654ec8332ed 100644
--- a/apps/files/tests/helper.php
+++ b/apps/files/tests/helper.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files/tests/js/favoritesfilelistspec.js b/apps/files/tests/js/favoritesfilelistspec.js
index 608ddaca18b..1c833d334e2 100644
--- a/apps/files/tests/js/favoritesfilelistspec.js
+++ b/apps/files/tests/js/favoritesfilelistspec.js
@@ -100,8 +100,7 @@ describe('OCA.Files.FavoritesFileList tests', function() {
expect($tr.attr('data-mtime')).toEqual('11111000');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Fsomedir&files=test.txt'
+ '/remote.php/webdav/somedir/test.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('test.txt');
});
diff --git a/apps/files/tests/js/fileUploadSpec.js b/apps/files/tests/js/fileUploadSpec.js
index a49a5d4e2e0..0483d4649d4 100644
--- a/apps/files/tests/js/fileUploadSpec.js
+++ b/apps/files/tests/js/fileUploadSpec.js
@@ -19,6 +19,8 @@
*
*/
+/* global FileList */
+
describe('OC.Upload tests', function() {
var $dummyUploader;
var testFile;
@@ -100,7 +102,7 @@ describe('OC.Upload tests', function() {
expect(failStub.calledOnce).toEqual(true);
expect(failStub.getCall(0).args[1].textStatus).toEqual('sizeexceedlimit');
expect(failStub.getCall(0).args[1].errorThrown).toEqual(
- 'Total file size 5 kB exceeds upload limit 1000 B'
+ 'Total file size 5 KB exceeds upload limit 1000 B'
);
});
it('does not add file if it exceeds free space', function() {
@@ -113,7 +115,7 @@ describe('OC.Upload tests', function() {
expect(failStub.calledOnce).toEqual(true);
expect(failStub.getCall(0).args[1].textStatus).toEqual('notenoughspace');
expect(failStub.getCall(0).args[1].errorThrown).toEqual(
- 'Not enough free space, you are uploading 5 kB but only 1000 B is left'
+ 'Not enough free space, you are uploading 5 KB but only 1000 B is left'
);
});
});
diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js
index d29164c5136..a905a4d969d 100644
--- a/apps/files/tests/js/fileactionsSpec.js
+++ b/apps/files/tests/js/fileactionsSpec.js
@@ -584,7 +584,7 @@ describe('OCA.Files.FileActions tests', function() {
expect(busyStub.calledWith('testName.txt', true)).toEqual(true);
expect(handleDownloadStub.calledOnce).toEqual(true);
expect(handleDownloadStub.getCall(0).args[0]).toEqual(
- OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt'
+ OC.webroot + '/remote.php/webdav/subdir/testName.txt'
);
busyStub.reset();
handleDownloadStub.yield();
diff --git a/apps/files/tests/js/fileactionsmenuSpec.js b/apps/files/tests/js/fileactionsmenuSpec.js
index dee542458b6..3028db2b3ac 100644
--- a/apps/files/tests/js/fileactionsmenuSpec.js
+++ b/apps/files/tests/js/fileactionsmenuSpec.js
@@ -20,7 +20,7 @@
*/
describe('OCA.Files.FileActionsMenu tests', function() {
- var fileList, fileActions, menu, actionStub, $tr;
+ var fileList, fileActions, menu, actionStub, menuContext, $tr;
beforeEach(function() {
// init horrible parameters
@@ -80,7 +80,7 @@ describe('OCA.Files.FileActionsMenu tests', function() {
};
$tr = fileList.add(fileData);
- var menuContext = {
+ menuContext = {
$file: $tr,
fileList: fileList,
fileActions: fileActions,
@@ -189,6 +189,22 @@ describe('OCA.Files.FileActionsMenu tests', function() {
var yactionIndex = menu.$el.find('a[data-action=Yaction]').closest('li').index();
expect(wactionIndex).toBeLessThan(yactionIndex);
});
+ it('calls displayName function', function() {
+ var displayNameStub = sinon.stub().returns('Test');
+
+ fileActions.registerAction({
+ name: 'Something',
+ displayName: displayNameStub,
+ mime: 'text/plain',
+ permissions: OC.PERMISSION_ALL
+ });
+
+ menu.render();
+
+ expect(displayNameStub.calledOnce).toEqual(true);
+ expect(displayNameStub.calledWith(menuContext)).toEqual(true);
+ expect(menu.$el.find('a[data-action=Something]').text()).toEqual('Test');
+ });
});
describe('action handler', function() {
@@ -237,8 +253,8 @@ describe('OCA.Files.FileActionsMenu tests', function() {
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Fsubdir&files=testName.txt');
+ '/remote.php/webdav/subdir/testName.txt'
+ );
redirectStub.restore();
});
it('takes the file\'s path into account when clicking download', function() {
@@ -269,8 +285,7 @@ describe('OCA.Files.FileActionsMenu tests', function() {
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(
- OC.webroot + '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Fanotherpath%2Fthere&files=testName.txt'
+ OC.webroot + '/remote.php/webdav/anotherpath/there/testName.txt'
);
redirectStub.restore();
});
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index 05e6fcc6122..1b2dd12213b 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -20,8 +20,11 @@
*/
describe('OCA.Files.FileList tests', function() {
- var testFiles, alertStub, notificationStub, fileList, pageSizeStub;
+ var FileInfo = OC.Files.FileInfo;
+ var testFiles, testRoot, notificationStub, fileList, pageSizeStub;
var bcResizeStub;
+ var filesClient;
+ var redirectStub;
/**
* Generate test file data
@@ -38,21 +41,29 @@ describe('OCA.Files.FileList tests', function() {
name += '0';
}
name += i + '.txt';
- files.push({
+ files.push(new FileInfo({
id: i,
type: 'file',
name: name,
mimetype: 'text/plain',
size: i * 2,
etag: 'abc'
- });
+ }));
}
return files;
}
beforeEach(function() {
- alertStub = sinon.stub(OC.dialogs, 'alert');
- notificationStub = sinon.stub(OC.Notification, 'show');
+ filesClient = new OC.Files.Client({
+ host: 'localhost',
+ port: 80,
+ // FIXME: uncomment after fixing the test OC.webroot
+ //root: OC.webroot + '/remote.php/webdav',
+ root: '/remote.php/webdav',
+ useHTTPS: false
+ });
+ redirectStub = sinon.stub(OC, 'redirect');
+ notificationStub = sinon.stub(OC.Notification, 'showTemporary');
// prevent resize algo to mess up breadcrumb order while
// testing
bcResizeStub = sinon.stub(OCA.Files.BreadCrumb.prototype, '_resize');
@@ -93,7 +104,17 @@ describe('OCA.Files.FileList tests', function() {
'</div>'
);
- testFiles = [{
+ testRoot = new FileInfo({
+ // root entry
+ id: 99,
+ type: 'dir',
+ name: '/subdir',
+ mimetype: 'httpd/unix-directory',
+ size: 1200000,
+ etag: 'a0b0c0d0',
+ permissions: OC.PERMISSION_ALL
+ });
+ testFiles = [new FileInfo({
id: 1,
type: 'file',
name: 'One.txt',
@@ -102,7 +123,7 @@ describe('OCA.Files.FileList tests', function() {
size: 12,
etag: 'abc',
permissions: OC.PERMISSION_ALL
- }, {
+ }), new FileInfo({
id: 2,
type: 'file',
name: 'Two.jpg',
@@ -111,7 +132,7 @@ describe('OCA.Files.FileList tests', function() {
size: 12049,
etag: 'def',
permissions: OC.PERMISSION_ALL
- }, {
+ }), new FileInfo({
id: 3,
type: 'file',
name: 'Three.pdf',
@@ -120,7 +141,7 @@ describe('OCA.Files.FileList tests', function() {
size: 58009,
etag: '123',
permissions: OC.PERMISSION_ALL
- }, {
+ }), new FileInfo({
id: 4,
type: 'dir',
name: 'somedir',
@@ -129,9 +150,11 @@ describe('OCA.Files.FileList tests', function() {
size: 250,
etag: '456',
permissions: OC.PERMISSION_ALL
- }];
+ })];
pageSizeStub = sinon.stub(OCA.Files.FileList.prototype, 'pageSize').returns(20);
- fileList = new OCA.Files.FileList($('#app-content-files'));
+ fileList = new OCA.Files.FileList($('#app-content-files'), {
+ filesClient: filesClient
+ });
});
afterEach(function() {
testFiles = undefined;
@@ -141,9 +164,9 @@ describe('OCA.Files.FileList tests', function() {
fileList = undefined;
notificationStub.restore();
- alertStub.restore();
bcResizeStub.restore();
pageSizeStub.restore();
+ redirectStub.restore();
});
describe('Getters', function() {
it('Returns the current directory', function() {
@@ -166,15 +189,14 @@ describe('OCA.Files.FileList tests', function() {
clock.restore();
});
it('generates file element with correct attributes when calling add() with file data', function() {
- var fileData = {
+ var fileData = new FileInfo({
id: 18,
- type: 'file',
name: 'testName.txt',
mimetype: 'text/plain',
- size: '1234',
+ size: 1234,
etag: 'a01234c',
- mtime: '123456'
- };
+ mtime: 123456
+ });
var $tr = fileList.add(fileData);
expect($tr).toBeDefined();
@@ -188,23 +210,22 @@ describe('OCA.Files.FileList tests', function() {
expect($tr.attr('data-mime')).toEqual('text/plain');
expect($tr.attr('data-mtime')).toEqual('123456');
expect($tr.find('a.name').attr('href'))
- .toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt');
+ .toEqual(OC.webroot + '/remote.php/webdav/subdir/testName.txt');
expect($tr.find('.nametext').text().trim()).toEqual('testName.txt');
- expect($tr.find('.filesize').text()).toEqual('1 kB');
+ expect($tr.find('.filesize').text()).toEqual('1 KB');
expect($tr.find('.date').text()).not.toEqual('?');
expect(fileList.findFileEl('testName.txt')[0]).toEqual($tr[0]);
});
it('generates dir element with correct attributes when calling add() with dir data', function() {
- var fileData = {
+ var fileData = new FileInfo({
id: 19,
- type: 'dir',
name: 'testFolder',
mimetype: 'httpd/unix-directory',
- size: '1234',
+ size: 1234,
etag: 'a01234c',
- mtime: '123456'
- };
+ mtime: 123456
+ });
var $tr = fileList.add(fileData);
expect($tr).toBeDefined();
@@ -218,7 +239,7 @@ describe('OCA.Files.FileList tests', function() {
expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
expect($tr.attr('data-mtime')).toEqual('123456');
- expect($tr.find('.filesize').text()).toEqual('1 kB');
+ expect($tr.find('.filesize').text()).toEqual('1 KB');
expect($tr.find('.date').text()).not.toEqual('?');
expect(fileList.findFileEl('testFolder')[0]).toEqual($tr[0]);
@@ -275,7 +296,7 @@ describe('OCA.Files.FileList tests', function() {
size: '0'
};
var $tr = fileList.add(fileData);
- expect($tr.find('.filesize').text()).toEqual('0 kB');
+ expect($tr.find('.filesize').text()).toEqual('0 KB');
});
it('generates file element with unknown date when mtime invalid', function() {
var fileData = {
@@ -297,7 +318,6 @@ describe('OCA.Files.FileList tests', function() {
expect($tr.index()).toEqual(4);
});
it('inserts files in a sorted manner when insert option is enabled', function() {
- var $tr;
for (var i = 0; i < testFiles.length; i++) {
fileList.add(testFiles[i]);
}
@@ -404,7 +424,7 @@ describe('OCA.Files.FileList tests', function() {
expect($summary.find('.info').text()).toEqual('1 folder and 2 files');
expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false);
expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false);
- expect($summary.find('.filesize').text()).toEqual('69 kB');
+ expect($summary.find('.filesize').text()).toEqual('69 KB');
expect(fileList.isEmpty).toEqual(false);
});
it('Shows empty content when removing last file', function() {
@@ -423,28 +443,31 @@ describe('OCA.Files.FileList tests', function() {
});
});
describe('Deleting files', function() {
+ var deferredDelete;
+ var deleteStub;
+
+ beforeEach(function() {
+ deferredDelete = $.Deferred();
+ deleteStub = sinon.stub(filesClient, 'remove').returns(deferredDelete.promise());
+ });
+ afterEach(function() {
+ deleteStub.restore();
+ });
+
function doDelete() {
- var request, query;
// note: normally called from FileActions
fileList.do_delete(['One.txt', 'Two.jpg']);
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
-
- query = fakeServer.requests[0].requestBody;
- expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir', files: '["One.txt","Two.jpg"]'});
+ expect(deleteStub.calledTwice).toEqual(true);
+ expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(deleteStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
}
it('calls delete.php, removes the deleted entries and updates summary', function() {
var $summary;
fileList.setFiles(testFiles);
doDelete();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
+ deferredDelete.resolve(200);
expect(fileList.findFileEl('One.txt').length).toEqual(0);
expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
@@ -456,7 +479,7 @@ describe('OCA.Files.FileList tests', function() {
expect($summary.find('.info').text()).toEqual('1 folder and 1 file');
expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false);
expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false);
- expect($summary.find('.filesize').text()).toEqual('57 kB');
+ expect($summary.find('.filesize').text()).toEqual('57 KB');
expect(fileList.isEmpty).toEqual(false);
expect($('#filestable thead th').hasClass('hidden')).toEqual(false);
expect($('#emptycontent').hasClass('hidden')).toEqual(true);
@@ -482,11 +505,7 @@ describe('OCA.Files.FileList tests', function() {
fileList.setFiles([testFiles[0], testFiles[1]]);
doDelete();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
+ deferredDelete.resolve(200);
expect(fileList.$fileList.find('tr').length).toEqual(0);
@@ -501,21 +520,41 @@ describe('OCA.Files.FileList tests', function() {
fileList.setFiles(testFiles);
doDelete();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'error', data: {message: 'WOOT'}})
- );
+ deferredDelete.reject(403);
// files are still in the list
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(fileList.findFileEl('Two.jpg').length).toEqual(1);
expect(fileList.$fileList.find('tr').length).toEqual(4);
- expect(notificationStub.calledOnce).toEqual(true);
+ expect(notificationStub.calledTwice).toEqual(true);
+ });
+ it('remove file from list if delete call returned 404 not found', function() {
+ fileList.setFiles(testFiles);
+ doDelete();
+
+ deferredDelete.reject(404);
+
+ // files are still in the list
+ expect(fileList.findFileEl('One.txt').length).toEqual(0);
+ expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
+ expect(fileList.$fileList.find('tr').length).toEqual(2);
+
+ expect(notificationStub.notCalled).toEqual(true);
});
});
describe('Renaming files', function() {
+ var deferredRename;
+ var renameStub;
+
+ beforeEach(function() {
+ deferredRename = $.Deferred();
+ renameStub = sinon.stub(filesClient, 'move').returns(deferredRename.promise());
+ });
+ afterEach(function() {
+ renameStub.restore();
+ });
+
function doCancelRename() {
var $input;
for (var i = 0; i < testFiles.length; i++) {
@@ -530,10 +569,10 @@ describe('OCA.Files.FileList tests', function() {
// trigger submit because triggering blur doesn't work in all browsers
$input.closest('form').trigger('submit');
- expect(fakeServer.requests.length).toEqual(0);
+ expect(renameStub.notCalled).toEqual(true);
}
function doRename() {
- var $input, request;
+ var $input;
for (var i = 0; i < testFiles.length; i++) {
var file = testFiles[i];
@@ -548,83 +587,61 @@ describe('OCA.Files.FileList tests', function() {
// trigger submit because triggering blur doesn't work in all browsers
$input.closest('form').trigger('submit');
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url.substr(0, request.url.indexOf('?'))).toEqual(OC.webroot + '/index.php/apps/files/ajax/rename.php');
- expect(OC.parseQueryString(request.url)).toEqual({'dir': '/some/subdir', newname: 'Tu_after_three.txt', file: 'One.txt'});
+ expect(renameStub.calledOnce).toEqual(true);
+ expect(renameStub.getCall(0).args[0]).toEqual('/some/subdir/One.txt');
+ expect(renameStub.getCall(0).args[1]).toEqual('/some/subdir/Tu_after_three.txt');
}
it('Inserts renamed file entry at correct position if rename ajax call suceeded', function() {
doRename();
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Tu_after_three.txt',
- type: 'file'
- }
- }));
+ deferredRename.resolve(201);
// element stays renamed
expect(fileList.findFileEl('One.txt').length).toEqual(0);
expect(fileList.findFileEl('Tu_after_three.txt').length).toEqual(1);
- expect(fileList.findFileEl('Tu_after_three.txt').index()).toEqual(2); // after Two.txt
+ expect(fileList.findFileEl('Tu_after_three.txt').index()).toEqual(2); // after Two.jpg
- expect(alertStub.notCalled).toEqual(true);
+ expect(notificationStub.notCalled).toEqual(true);
});
it('Reverts file entry if rename ajax call failed', function() {
doRename();
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'error',
- data: {
- message: 'Something went wrong'
- }
- }));
+ deferredRename.reject(403);
// element was reverted
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(fileList.findFileEl('One.txt').index()).toEqual(1); // after somedir
expect(fileList.findFileEl('Tu_after_three.txt').length).toEqual(0);
- expect(alertStub.calledOnce).toEqual(true);
+ expect(notificationStub.calledOnce).toEqual(true);
});
it('Correctly updates file link after rename', function() {
var $tr;
doRename();
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Tu_after_three.txt'
- }
- }));
+ deferredRename.resolve(201);
$tr = fileList.findFileEl('Tu_after_three.txt');
- expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=Tu_after_three.txt');
+ expect($tr.find('a.name').attr('href'))
+ .toEqual(OC.webroot + '/remote.php/webdav/some/subdir/Tu_after_three.txt');
});
it('Triggers "fileActionsReady" event after rename', function() {
var handler = sinon.stub();
fileList.$fileList.on('fileActionsReady', handler);
doRename();
expect(handler.notCalled).toEqual(true);
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Tu_after_three.txt'
- }
- }));
+
+ deferredRename.resolve(201);
+
expect(handler.calledOnce).toEqual(true);
expect(fileList.$fileList.find('.test').length).toEqual(0);
});
it('Leaves the summary alone when reinserting renamed element', function() {
var $summary = $('#filestable .summary');
doRename();
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Tu_after_three.txt'
- }
- }));
+
+ deferredRename.resolve(201);
+
expect($summary.find('.info').text()).toEqual('1 folder and 3 files');
});
it('Leaves the summary alone when cancel renaming', function() {
@@ -668,7 +685,7 @@ describe('OCA.Files.FileList tests', function() {
// trigger submit does not send server request
$input.closest('form').trigger('submit');
- expect(fakeServer.requests.length).toEqual(0);
+ expect(renameStub.notCalled).toEqual(true);
// simulate escape key
$input.trigger(new $.Event('keyup', {keyCode: 27}));
@@ -694,12 +711,7 @@ describe('OCA.Files.FileList tests', function() {
expect(OC.TestUtil.getImageUrl(fileList.findFileEl('Tu_after_three.txt').find('.thumbnail')))
.toEqual(OC.imagePath('core', 'loading.gif'));
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'error',
- data: {
- message: 'Something went wrong'
- }
- }));
+ deferredRename.reject(409);
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
@@ -707,25 +719,27 @@ describe('OCA.Files.FileList tests', function() {
});
});
describe('Moving files', function() {
+ var deferredMove;
+ var moveStub;
+
beforeEach(function() {
+ deferredMove = $.Deferred();
+ moveStub = sinon.stub(filesClient, 'move').returns(deferredMove.promise());
+
fileList.setFiles(testFiles);
});
+ afterEach(function() {
+ moveStub.restore();
+ });
+
it('Moves single file to target folder', function() {
- var request;
fileList.move('One.txt', '/somedir');
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+ expect(moveStub.calledOnce).toEqual(true);
+ expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'One.txt',
- type: 'file'
- }
- }));
+ deferredMove.resolve(201);
expect(fileList.findFileEl('One.txt').length).toEqual(0);
@@ -736,95 +750,84 @@ describe('OCA.Files.FileList tests', function() {
expect(notificationStub.notCalled).toEqual(true);
});
it('Moves list of files to target folder', function() {
- var request;
+ var deferredMove1 = $.Deferred();
+ var deferredMove2 = $.Deferred();
+ moveStub.onCall(0).returns(deferredMove1.promise());
+ moveStub.onCall(1).returns(deferredMove2.promise());
+
fileList.move(['One.txt', 'Two.jpg'], '/somedir');
- expect(fakeServer.requests.length).toEqual(2);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+ expect(moveStub.calledTwice).toEqual(true);
+ expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');
+ expect(moveStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
+ expect(moveStub.getCall(1).args[1]).toEqual('/somedir/Two.jpg');
- request = fakeServer.requests[1];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'Two.jpg', target: '/somedir'});
-
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'One.txt',
- type: 'file'
- }
- }));
+ deferredMove1.resolve(201);
expect(fileList.findFileEl('One.txt').length).toEqual(0);
- // folder size has increased
+ // folder size has increased during move
expect(fileList.findFileEl('somedir').data('size')).toEqual(262);
expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('262 B');
- fakeServer.requests[1].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Two.jpg',
- type: 'file'
- }
- }));
+ deferredMove2.resolve(201);
expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
// folder size has increased
expect(fileList.findFileEl('somedir').data('size')).toEqual(12311);
- expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('12 kB');
+ expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('12 KB');
expect(notificationStub.notCalled).toEqual(true);
});
it('Shows notification if a file could not be moved', function() {
- var request;
fileList.move('One.txt', '/somedir');
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+ expect(moveStub.calledOnce).toEqual(true);
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'error',
- data: {
- message: 'Error while moving file'
- }
- }));
+ deferredMove.reject(409);
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(notificationStub.calledOnce).toEqual(true);
- expect(notificationStub.getCall(0).args[0]).toEqual('Error while moving file');
+ expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');
});
it('Restores thumbnail if a file could not be moved', function() {
- var request;
fileList.move('One.txt', '/somedir');
expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
.toEqual(OC.imagePath('core', 'loading.gif'));
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
+ expect(moveStub.calledOnce).toEqual(true);
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'error',
- data: {
- message: 'Error while moving file'
- }
- }));
+ deferredMove.reject(409);
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(notificationStub.calledOnce).toEqual(true);
- expect(notificationStub.getCall(0).args[0]).toEqual('Error while moving file');
+ expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');
expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
.toEqual(OC.imagePath('core', 'filetypes/text.svg'));
});
});
+ describe('Update file', function() {
+ it('does not change summary', function() {
+ var $summary = $('#filestable .summary');
+ var fileData = new FileInfo({
+ type: 'file',
+ name: 'test file',
+ });
+ var $tr = fileList.add(fileData);
+
+ expect($summary.find('.info').text()).toEqual('0 folders and 1 file');
+
+ var model = fileList.getModelForFile('test file');
+ model.set({size: '100'});
+ expect($summary.find('.info').text()).toEqual('0 folders and 1 file');
+ });
+ })
describe('List rendering', function() {
it('renders a list of files using add()', function() {
expect(fileList.files.length).toEqual(0);
@@ -840,7 +843,7 @@ describe('OCA.Files.FileList tests', function() {
$summary = $('#filestable .summary');
expect($summary.hasClass('hidden')).toEqual(false);
expect($summary.find('.info').text()).toEqual('1 folder and 3 files');
- expect($summary.find('.filesize').text()).toEqual('69 kB');
+ expect($summary.find('.filesize').text()).toEqual('69 KB');
});
it('shows headers, summary and hide empty content message after setting files', function(){
fileList.setFiles(testFiles);
@@ -878,7 +881,7 @@ describe('OCA.Files.FileList tests', function() {
name: 'testFile.txt',
directory: '/current dir'
};
- var $tr = fileList.add(fileData);
+ fileList.add(fileData);
expect(fileList.findFileEl('testFile.txt').length).toEqual(1);
});
it('triggers "fileActionsReady" event after update', function() {
@@ -1143,69 +1146,85 @@ describe('OCA.Files.FileList tests', function() {
afterEach(function() {
previewLoadStub.restore();
});
- it('renders default icon for file when none provided and no preview is available', function() {
+ it('renders default file icon when none provided and no mime type is set', function() {
var fileData = {
- type: 'file',
name: 'testFile.txt'
};
var $tr = fileList.add(fileData);
var $imgDiv = $tr.find('td.filename .thumbnail');
expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
- expect(previewLoadStub.notCalled).toEqual(true);
+ // tries to load preview
+ expect(previewLoadStub.calledOnce).toEqual(true);
});
- it('renders default icon for dir when none provided and no preview is available', function() {
+ it('renders default icon for folder when none provided', function() {
var fileData = {
- type: 'dir',
- name: 'test dir'
+ name: 'test dir',
+ mimetype: 'httpd/unix-directory'
};
+
var $tr = fileList.add(fileData);
var $imgDiv = $tr.find('td.filename .thumbnail');
expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/folder.svg');
+ // no preview since it's a directory
expect(previewLoadStub.notCalled).toEqual(true);
});
it('renders provided icon for file when provided', function() {
- var fileData = {
+ var fileData = new FileInfo({
type: 'file',
name: 'test file',
icon: OC.webroot + '/core/img/filetypes/application-pdf.svg',
mimetype: 'application/pdf'
- };
+ });
var $tr = fileList.add(fileData);
var $imgDiv = $tr.find('td.filename .thumbnail');
expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/application-pdf.svg');
+ // try loading preview
+ expect(previewLoadStub.calledOnce).toEqual(true);
+ });
+ it('renders provided icon for file when provided', function() {
+ var fileData = new FileInfo({
+ name: 'somefile.pdf',
+ icon: OC.webroot + '/core/img/filetypes/application-pdf.svg'
+ });
+
+ var $tr = fileList.add(fileData);
+ var $imgDiv = $tr.find('td.filename .thumbnail');
+ expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/application-pdf.svg');
+ // try loading preview
+ expect(previewLoadStub.calledOnce).toEqual(true);
+ });
+ it('renders provided icon for folder when provided', function() {
+ var fileData = new FileInfo({
+ name: 'some folder',
+ mimetype: 'httpd/unix-directory',
+ icon: OC.webroot + '/core/img/filetypes/folder-alt.svg'
+ });
+
+ var $tr = fileList.add(fileData);
+ var $imgDiv = $tr.find('td.filename .thumbnail');
+ expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/folder-alt.svg');
+ // do not load preview for folders
expect(previewLoadStub.notCalled).toEqual(true);
});
- it('renders preview when no icon was provided and preview is available', function() {
+ it('renders preview when no icon was provided', function() {
var fileData = {
type: 'file',
- name: 'test file',
- isPreviewAvailable: true
+ name: 'test file'
};
var $tr = fileList.add(fileData);
var $td = $tr.find('td.filename');
- expect(OC.TestUtil.getImageUrl($td.find('.thumbnail'))).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
+ expect(OC.TestUtil.getImageUrl($td.find('.thumbnail')))
+ .toEqual(OC.webroot + '/core/img/filetypes/file.svg');
expect(previewLoadStub.calledOnce).toEqual(true);
// third argument is callback
previewLoadStub.getCall(0).args[0].callback(OC.webroot + '/somepath.png');
expect(OC.TestUtil.getImageUrl($td.find('.thumbnail'))).toEqual(OC.webroot + '/somepath.png');
});
- it('renders default file type icon when no icon was provided and no preview is available', function() {
- var fileData = {
- type: 'file',
- name: 'test file',
- isPreviewAvailable: false
- };
- var $tr = fileList.add(fileData);
- var $imgDiv = $tr.find('td.filename .thumbnail');
- expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
- expect(previewLoadStub.notCalled).toEqual(true);
- });
it('does not render preview for directories', function() {
var fileData = {
type: 'dir',
mimetype: 'httpd/unix-directory',
- name: 'test dir',
- isPreviewAvailable: true
+ name: 'test dir'
};
var $tr = fileList.add(fileData);
var $td = $tr.find('td.filename');
@@ -1217,7 +1236,6 @@ describe('OCA.Files.FileList tests', function() {
type: 'dir',
mimetype: 'httpd/unix-directory',
name: 'test dir',
- isPreviewAvailable: true,
mountType: 'external-root'
};
var $tr = fileList.add(fileData);
@@ -1230,7 +1248,6 @@ describe('OCA.Files.FileList tests', function() {
type: 'dir',
mimetype: 'httpd/unix-directory',
name: 'test dir',
- isPreviewAvailable: true,
mountType: 'external'
};
var $tr = fileList.add(fileData);
@@ -1278,75 +1295,47 @@ describe('OCA.Files.FileList tests', function() {
});
});
describe('loading file list', function() {
+ var deferredList;
+ var getFolderContentsStub;
+
beforeEach(function() {
- var data = {
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- };
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2F(subdir|anothersubdir)/, [
- 200, {
- "Content-Type": "application/json"
- },
- JSON.stringify(data)
- ]);
+ deferredList = $.Deferred();
+ getFolderContentsStub = sinon.stub(filesClient, 'getFolderContents').returns(deferredList.promise());
+ });
+ afterEach(function() {
+ getFolderContentsStub.restore();
});
it('fetches file list from server and renders it when reload() is called', function() {
fileList.reload();
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = url.substr(url.indexOf('?') + 1);
- expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir', sort: 'name', sortdirection: 'asc'});
- fakeServer.respond();
+ expect(getFolderContentsStub.calledOnce).toEqual(true);
+ expect(getFolderContentsStub.calledWith('/subdir')).toEqual(true);
+ deferredList.resolve(200, [testRoot].concat(testFiles));
expect($('#fileList tr').length).toEqual(4);
expect(fileList.findFileEl('One.txt').length).toEqual(1);
});
it('switches dir and fetches file list when calling changeDirectory()', function() {
fileList.changeDirectory('/anothersubdir');
expect(fileList.getCurrentDirectory()).toEqual('/anothersubdir');
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = url.substr(url.indexOf('?') + 1);
- expect(OC.parseQueryString(query)).toEqual({'dir': '/anothersubdir', sort: 'name', sortdirection: 'asc'});
- fakeServer.respond();
+ expect(getFolderContentsStub.calledOnce).toEqual(true);
+ expect(getFolderContentsStub.calledWith('/anothersubdir')).toEqual(true);
});
it('converts backslashes to slashes when calling changeDirectory()', function() {
fileList.changeDirectory('/another\\subdir');
expect(fileList.getCurrentDirectory()).toEqual('/another/subdir');
});
it('switches to root dir when current directory does not exist', function() {
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [
- 404, {
- "Content-Type": "application/json"
- },
- ''
- ]);
fileList.changeDirectory('/unexist');
- fakeServer.respond();
+ deferredList.reject(404);
expect(fileList.getCurrentDirectory()).toEqual('/');
});
it('switches to root dir when current directory is forbidden', function() {
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [
- 403, {
- "Content-Type": "application/json"
- },
- ''
- ]);
fileList.changeDirectory('/unexist');
- fakeServer.respond();
+ deferredList.reject(403);
expect(fileList.getCurrentDirectory()).toEqual('/');
});
it('switches to root dir when current directory is unavailable', function() {
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [
- 500, {
- "Content-Type": "application/json"
- },
- ''
- ]);
fileList.changeDirectory('/unexist');
- fakeServer.respond();
+ deferredList.reject(500);
expect(fileList.getCurrentDirectory()).toEqual('/');
});
it('shows mask before loading file list then hides it at the end', function() {
@@ -1355,7 +1344,7 @@ describe('OCA.Files.FileList tests', function() {
fileList.changeDirectory('/anothersubdir');
expect(showMaskStub.calledOnce).toEqual(true);
expect(hideMaskStub.calledOnce).toEqual(false);
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
expect(showMaskStub.calledOnce).toEqual(true);
expect(hideMaskStub.calledOnce).toEqual(true);
showMaskStub.restore();
@@ -1365,6 +1354,7 @@ describe('OCA.Files.FileList tests', function() {
var handler = sinon.stub();
$('#app-content-files').on('changeDirectory', handler);
fileList.changeDirectory('/somedir');
+ deferredList.resolve(200, [testRoot].concat(testFiles));
expect(handler.calledOnce).toEqual(true);
expect(handler.getCall(0).args[0].dir).toEqual('/somedir');
});
@@ -1375,31 +1365,27 @@ describe('OCA.Files.FileList tests', function() {
it('refreshes breadcrumb after update', function() {
var setDirSpy = sinon.spy(fileList.breadcrumb, 'setDirectory');
fileList.changeDirectory('/anothersubdir');
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
expect(fileList.breadcrumb.setDirectory.calledOnce).toEqual(true);
expect(fileList.breadcrumb.setDirectory.calledWith('/anothersubdir')).toEqual(true);
setDirSpy.restore();
+ getFolderContentsStub.restore();
});
});
describe('breadcrumb events', function() {
+ var deferredList;
+ var getFolderContentsStub;
+
beforeEach(function() {
- var data = {
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- };
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2Fsubdir/, [
- 200, {
- "Content-Type": "application/json"
- },
- JSON.stringify(data)
- ]);
+ deferredList = $.Deferred();
+ getFolderContentsStub = sinon.stub(filesClient, 'getFolderContents').returns(deferredList.promise());
+ });
+ afterEach(function() {
+ getFolderContentsStub.restore();
});
it('clicking on root breadcrumb changes directory to root', function() {
fileList.changeDirectory('/subdir/two/three with space/four/five');
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
var changeDirStub = sinon.stub(fileList, 'changeDirectory');
fileList.breadcrumb.$el.find('.crumb:eq(0)').trigger({type: 'click', which: 1});
@@ -1409,7 +1395,7 @@ describe('OCA.Files.FileList tests', function() {
});
it('clicking on breadcrumb changes directory', function() {
fileList.changeDirectory('/subdir/two/three with space/four/five');
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
var changeDirStub = sinon.stub(fileList, 'changeDirectory');
fileList.breadcrumb.$el.find('.crumb:eq(3)').trigger({type: 'click', which: 1});
@@ -1418,9 +1404,10 @@ describe('OCA.Files.FileList tests', function() {
changeDirStub.restore();
});
it('dropping files on breadcrumb calls move operation', function() {
- var request, query, testDir = '/subdir/two/three with space/four/five';
+ var testDir = '/subdir/two/three with space/four/five';
+ var moveStub = sinon.stub(filesClient, 'move').returns($.Deferred().promise());
fileList.changeDirectory(testDir);
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
var $crumb = fileList.breadcrumb.$el.find('.crumb:eq(3)');
// no idea what this is but is required by the handler
var ui = {
@@ -1436,33 +1423,18 @@ describe('OCA.Files.FileList tests', function() {
// simulate drop event
fileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui);
- // will trigger two calls to move.php (first one was previous list.php)
- expect(fakeServer.requests.length).toEqual(3);
-
- request = fakeServer.requests[1];
- expect(request.method).toEqual('POST');
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- query = OC.parseQueryString(request.requestBody);
- expect(query).toEqual({
- target: '/subdir/two/three with space',
- dir: testDir,
- file: 'One.txt'
- });
-
- request = fakeServer.requests[2];
- expect(request.method).toEqual('POST');
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- query = OC.parseQueryString(request.requestBody);
- expect(query).toEqual({
- target: '/subdir/two/three with space',
- dir: testDir,
- file: 'Two.jpg'
- });
+ expect(moveStub.callCount).toEqual(2);
+ expect(moveStub.getCall(0).args[0]).toEqual(testDir + '/One.txt');
+ expect(moveStub.getCall(0).args[1]).toEqual('/subdir/two/three with space/One.txt');
+ expect(moveStub.getCall(1).args[0]).toEqual(testDir + '/Two.jpg');
+ expect(moveStub.getCall(1).args[1]).toEqual('/subdir/two/three with space/Two.jpg');
+ moveStub.restore();
});
it('dropping files on same dir breadcrumb does nothing', function() {
var testDir = '/subdir/two/three with space/four/five';
+ var moveStub = sinon.stub(filesClient, 'move').returns($.Deferred().promise());
fileList.changeDirectory(testDir);
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
var $crumb = fileList.breadcrumb.$el.find('.crumb:last');
// no idea what this is but is required by the handler
var ui = {
@@ -1479,21 +1451,26 @@ describe('OCA.Files.FileList tests', function() {
fileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui);
// no extra server request
- expect(fakeServer.requests.length).toEqual(1);
+ expect(moveStub.notCalled).toEqual(true);
});
});
describe('Download Url', function() {
it('returns correct download URL for single files', function() {
- expect(fileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=some%20file.txt');
- expect(fileList.getDownloadUrl('some file.txt', '/anotherpath/abc')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fanotherpath%2Fabc&files=some%20file.txt');
+ expect(fileList.getDownloadUrl('some file.txt'))
+ .toEqual(OC.webroot + '/remote.php/webdav/subdir/some%20file.txt');
+ expect(fileList.getDownloadUrl('some file.txt', '/anotherpath/abc'))
+ .toEqual(OC.webroot + '/remote.php/webdav/anotherpath/abc/some%20file.txt');
$('#dir').val('/');
- expect(fileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=some%20file.txt');
+ expect(fileList.getDownloadUrl('some file.txt'))
+ .toEqual(OC.webroot + '/remote.php/webdav/some%20file.txt');
});
it('returns correct download URL for multiple files', function() {
- expect(fileList.getDownloadUrl(['a b c.txt', 'd e f.txt'])).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22a%20b%20c.txt%22%2C%22d%20e%20f.txt%22%5D');
+ expect(fileList.getDownloadUrl(['a b c.txt', 'd e f.txt']))
+ .toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22a%20b%20c.txt%22%2C%22d%20e%20f.txt%22%5D');
});
it('returns the correct ajax URL', function() {
- expect(fileList.getAjaxUrl('test', {a:1, b:'x y'})).toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y');
+ expect(fileList.getAjaxUrl('test', {a:1, b:'x y'}))
+ .toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y');
});
});
describe('File selection', function() {
@@ -1672,24 +1649,17 @@ describe('OCA.Files.FileList tests', function() {
});
it('Selection is cleared when switching dirs', function() {
$('.select-all').click();
- var data = {
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- };
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php/, [
- 200, {
- "Content-Type": "application/json"
- },
- JSON.stringify(data)
- ]
- );
+ var deferredList = $.Deferred();
+ var getFolderContentsStub = sinon.stub(filesClient, 'getFolderContents').returns(deferredList.promise());
+
fileList.changeDirectory('/');
- fakeServer.respond();
+
+ deferredList.resolve(200, [testRoot].concat(testFiles));
+
expect($('.select-all').prop('checked')).toEqual(false);
expect(_.pluck(fileList.getSelectedFiles(), 'name')).toEqual([]);
+
+ getFolderContentsStub.restore();
});
it('getSelectedFiles returns the selected files even when they are on the next page', function() {
var selectedFiles;
@@ -1735,16 +1705,6 @@ describe('OCA.Files.FileList tests', function() {
});
});
describe('Selection overlay', function() {
- it('show delete action according to directory permissions', function() {
- fileList.setFiles(testFiles);
- $('#permissions').val(OC.PERMISSION_READ | OC.PERMISSION_DELETE);
- $('.select-all').click();
- expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(false);
- $('.select-all').click();
- $('#permissions').val(OC.PERMISSION_READ);
- $('.select-all').click();
- expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(true);
- });
it('show doesnt show the delete action if one or more files are not deletable', function () {
fileList.setFiles(testFiles);
$('#permissions').val(OC.PERMISSION_READ | OC.PERMISSION_DELETE);
@@ -1796,6 +1756,12 @@ describe('OCA.Files.FileList tests', function() {
etag: '456',
permissions: OC.PERMISSION_ALL
});
+ expect(files[0].id).toEqual(1);
+ expect(files[0].name).toEqual('One.txt');
+ expect(files[1].id).toEqual(3);
+ expect(files[1].name).toEqual('Three.pdf');
+ expect(files[2].id).toEqual(4);
+ expect(files[2].name).toEqual('somedir');
});
it('Removing a file removes it from the selection', function() {
fileList.remove('Three.pdf');
@@ -1824,7 +1790,6 @@ describe('OCA.Files.FileList tests', function() {
});
describe('Download', function() {
it('Opens download URL when clicking "Download"', function() {
- var redirectStub = sinon.stub(OC, 'redirect');
$('.selectedActions .download').click();
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22One.txt%22%2C%22Three.pdf%22%2C%22somedir%22%5D');
@@ -1833,54 +1798,53 @@ describe('OCA.Files.FileList tests', function() {
it('Downloads root folder when all selected in root folder', function() {
$('#dir').val('/');
$('.select-all').click();
- var redirectStub = sinon.stub(OC, 'redirect');
$('.selectedActions .download').click();
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=');
- redirectStub.restore();
});
it('Downloads parent folder when all selected in subfolder', function() {
$('.select-all').click();
- var redirectStub = sinon.stub(OC, 'redirect');
$('.selectedActions .download').click();
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=subdir');
- redirectStub.restore();
});
});
describe('Delete', function() {
+ var deleteStub, deferredDelete;
+ beforeEach(function() {
+ deferredDelete = $.Deferred();
+ deleteStub = sinon.stub(filesClient, 'remove').returns(deferredDelete.promise());
+ });
+ afterEach(function() {
+ deleteStub.restore();
+ });
it('Deletes selected files when "Delete" clicked', function() {
- var request;
$('.selectedActions .delete-selected').click();
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
- expect(OC.parseQueryString(request.requestBody))
- .toEqual({'dir': '/subdir', files: '["One.txt","Three.pdf","somedir"]'});
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
+
+ expect(deleteStub.callCount).toEqual(3);
+ expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(deleteStub.getCall(1).args[0]).toEqual('/subdir/Three.pdf');
+ expect(deleteStub.getCall(2).args[0]).toEqual('/subdir/somedir');
+
+ deferredDelete.resolve(204);
+
expect(fileList.findFileEl('One.txt').length).toEqual(0);
expect(fileList.findFileEl('Three.pdf').length).toEqual(0);
expect(fileList.findFileEl('somedir').length).toEqual(0);
expect(fileList.findFileEl('Two.jpg').length).toEqual(1);
});
it('Deletes all files when all selected when "Delete" clicked', function() {
- var request;
$('.select-all').click();
$('.selectedActions .delete-selected').click();
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
- expect(OC.parseQueryString(request.requestBody))
- .toEqual({'dir': '/subdir', allfiles: 'true'});
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
+
+ expect(deleteStub.callCount).toEqual(4);
+ expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(deleteStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
+ expect(deleteStub.getCall(2).args[0]).toEqual('/subdir/Three.pdf');
+ expect(deleteStub.getCall(3).args[0]).toEqual('/subdir/somedir');
+
+ deferredDelete.resolve(204);
+
expect(fileList.isEmpty).toEqual(true);
});
});
@@ -2118,30 +2082,6 @@ describe('OCA.Files.FileList tests', function() {
});
});
describe('Sorting files', function() {
- it('Sorts by name by default', function() {
- fileList.reload();
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
- expect(query.sort).toEqual('name');
- expect(query.sortdirection).toEqual('asc');
- });
- it('Reloads file list with a different sort when clicking on column header of unsorted column', function() {
- fileList.$el.find('.column-size .columntitle').click();
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
- expect(query.sort).toEqual('size');
- expect(query.sortdirection).toEqual('desc');
- });
- it('Toggles sort direction when clicking on already sorted column', function() {
- fileList.$el.find('.column-name .columntitle').click();
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
- expect(query.sort).toEqual('name');
- expect(query.sortdirection).toEqual('desc');
- });
it('Toggles the sort indicator when clicking on a column header', function() {
var ASC_CLASS = fileList.SORT_INDICATOR_ASC_CLASS;
var DESC_CLASS = fileList.SORT_INDICATOR_DESC_CLASS;
@@ -2191,28 +2131,15 @@ describe('OCA.Files.FileList tests', function() {
it('Uses correct sort comparator when inserting files', function() {
testFiles.sort(OCA.Files.FileList.Comparators.size);
testFiles.reverse(); //default is descending
- // this will make it reload the testFiles with the correct sorting
+ fileList.setFiles(testFiles);
fileList.$el.find('.column-size .columntitle').click();
- expect(fakeServer.requests.length).toEqual(1);
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- })
- );
- var newFileData = {
+ var newFileData = new FileInfo({
id: 999,
- type: 'file',
name: 'new file.txt',
mimetype: 'text/plain',
size: 40001,
etag: '999'
- };
+ });
fileList.add(newFileData);
expect(fileList.findFileEl('Three.pdf').index()).toEqual(0);
expect(fileList.findFileEl('new file.txt').index()).toEqual(1);
@@ -2224,41 +2151,18 @@ describe('OCA.Files.FileList tests', function() {
});
it('Uses correct reversed sort comparator when inserting files', function() {
testFiles.sort(OCA.Files.FileList.Comparators.size);
- // this will make it reload the testFiles with the correct sorting
+ fileList.setFiles(testFiles);
fileList.$el.find('.column-size .columntitle').click();
- expect(fakeServer.requests.length).toEqual(1);
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- })
- );
+
// reverse sort
fileList.$el.find('.column-size .columntitle').click();
- fakeServer.requests[1].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- })
- );
- var newFileData = {
+ var newFileData = new FileInfo({
id: 999,
- type: 'file',
name: 'new file.txt',
mimetype: 'text/plain',
size: 40001,
etag: '999'
- };
+ });
fileList.add(newFileData);
expect(fileList.findFileEl('One.txt').index()).toEqual(0);
expect(fileList.findFileEl('somedir').index()).toEqual(1);
@@ -2290,87 +2194,96 @@ describe('OCA.Files.FileList tests', function() {
});
describe('create file', function() {
var deferredCreate;
+ var deferredInfo;
+ var createStub;
+ var getFileInfoStub;
beforeEach(function() {
deferredCreate = $.Deferred();
+ deferredInfo = $.Deferred();
+ createStub = sinon.stub(filesClient, 'putFileContents')
+ .returns(deferredCreate.promise());
+ getFileInfoStub = sinon.stub(filesClient, 'getFileInfo')
+ .returns(deferredInfo.promise());
+ });
+ afterEach(function() {
+ createStub.restore();
+ getFileInfoStub.restore();
});
it('creates file with given name and adds it to the list', function() {
- var deferred = fileList.createFile('test file.txt');
- var successStub = sinon.stub();
- var failureStub = sinon.stub();
+ fileList.createFile('test.txt');
- deferred.done(successStub);
- deferred.fail(failureStub);
+ expect(createStub.calledOnce).toEqual(true);
+ expect(createStub.getCall(0).args[0]).toEqual('/subdir/test.txt');
+ expect(createStub.getCall(0).args[2]).toEqual({
+ contentType: 'text/plain',
+ overwrite: true
+ });
- expect(fakeServer.requests.length).toEqual(1);
- expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('/apps/files/ajax/newfile.php'));
+ deferredCreate.resolve(200);
- var query = fakeServer.requests[0].requestBody;
- expect(OC.parseQueryString(query)).toEqual({
- dir: '/subdir',
- filename: 'test file.txt'
- });
+ expect(getFileInfoStub.calledOnce).toEqual(true);
+ expect(getFileInfoStub.getCall(0).args[0]).toEqual('/subdir/test.txt');
- fakeServer.requests[0].respond(
+ deferredInfo.resolve(
200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- path: '/subdir',
- name: 'test file.txt',
- mimetype: 'text/plain'
- }
+ new FileInfo({
+ path: '/subdir',
+ name: 'test.txt',
+ mimetype: 'text/plain'
})
);
- var $tr = fileList.findFileEl('test file.txt');
+ var $tr = fileList.findFileEl('test.txt');
expect($tr.length).toEqual(1);
expect($tr.attr('data-mime')).toEqual('text/plain');
-
- expect(successStub.calledOnce).toEqual(true);
- expect(failureStub.notCalled).toEqual(true);
});
// TODO: error cases
// TODO: unique name cases
});
- describe('create directory', function() {
- it('creates directory with given name and adds it to the list', function() {
- var deferred = fileList.createDirectory('test directory');
- var successStub = sinon.stub();
- var failureStub = sinon.stub();
-
- deferred.done(successStub);
- deferred.fail(failureStub);
-
- expect(fakeServer.requests.length).toEqual(1);
- expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('/apps/files/ajax/newfolder.php'));
- var query = fakeServer.requests[0].requestBody;
- expect(OC.parseQueryString(query)).toEqual({
- dir: '/subdir',
- foldername: 'test directory'
- });
+ describe('create folder', function() {
+ var deferredCreate;
+ var deferredInfo;
+ var createStub;
+ var getFileInfoStub;
+
+ beforeEach(function() {
+ deferredCreate = $.Deferred();
+ deferredInfo = $.Deferred();
+ createStub = sinon.stub(filesClient, 'createDirectory')
+ .returns(deferredCreate.promise());
+ getFileInfoStub = sinon.stub(filesClient, 'getFileInfo')
+ .returns(deferredInfo.promise());
+ });
+ afterEach(function() {
+ createStub.restore();
+ getFileInfoStub.restore();
+ });
+
+ it('creates folder with given name and adds it to the list', function() {
+ fileList.createDirectory('sub dir');
+
+ expect(createStub.calledOnce).toEqual(true);
+ expect(createStub.getCall(0).args[0]).toEqual('/subdir/sub dir');
+
+ deferredCreate.resolve(200);
+
+ expect(getFileInfoStub.calledOnce).toEqual(true);
+ expect(getFileInfoStub.getCall(0).args[0]).toEqual('/subdir/sub dir');
- fakeServer.requests[0].respond(
+ deferredInfo.resolve(
200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- path: '/subdir',
- name: 'test directory',
- mimetype: 'httpd/unix-directory'
- }
+ new FileInfo({
+ path: '/subdir',
+ name: 'sub dir',
+ mimetype: 'httpd/unix-directory'
})
);
- var $tr = fileList.findFileEl('test directory');
+ var $tr = fileList.findFileEl('sub dir');
expect($tr.length).toEqual(1);
expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
-
- expect(successStub.calledOnce).toEqual(true);
- expect(failureStub.notCalled).toEqual(true);
});
// TODO: error cases
// TODO: unique name cases
@@ -2481,48 +2394,81 @@ describe('OCA.Files.FileList tests', function() {
expect(ev.result).not.toEqual(false);
});
it('drop on a folder row inside the table triggers upload to target folder', function() {
- var ev, formData;
+ var ev;
ev = dropOn(fileList.findFileEl('somedir').find('td:eq(2)'), uploadData);
expect(ev.result).not.toEqual(false);
expect(uploadData.targetDir).toEqual('/subdir/somedir');
});
it('drop on a breadcrumb inside the table triggers upload to target folder', function() {
- var ev, formData;
+ var ev;
fileList.changeDirectory('a/b/c/d');
ev = dropOn(fileList.$el.find('.crumb:eq(2)'), uploadData);
expect(ev.result).not.toEqual(false);
expect(uploadData.targetDir).toEqual('/a/b');
});
+ it('renders upload indicator element for folders only', function() {
+ fileList.add({
+ name: 'afolder',
+ type: 'dir',
+ mime: 'httpd/unix-directory'
+ });
+ fileList.add({
+ name: 'afile.txt',
+ type: 'file',
+ mime: 'text/plain'
+ });
+
+ expect(fileList.findFileEl('afolder').find('.uploadtext').length).toEqual(1);
+ expect(fileList.findFileEl('afile.txt').find('.uploadtext').length).toEqual(0);
+ });
});
});
- describe('Handeling errors', function () {
- var redirectStub;
+ describe('Handling errors', function () {
+ var deferredList;
+ var getFolderContentsStub;
- beforeEach(function () {
- redirectStub = sinon.stub(OC, 'redirect');
-
- fileList = new OCA.Files.FileList($('#app-content-files'));
+ beforeEach(function() {
+ deferredList = $.Deferred();
+ getFolderContentsStub =
+ sinon.stub(filesClient, 'getFolderContents');
+ getFolderContentsStub.onCall(0).returns(deferredList.promise());
+ getFolderContentsStub.onCall(1).returns($.Deferred().promise());
+ fileList.reload();
});
- afterEach(function () {
+ afterEach(function() {
+ getFolderContentsStub.restore();
fileList = undefined;
+ });
+ it('redirects to files app in case of auth error', function () {
+ deferredList.reject(401, 'Authentication error');
- redirectStub.restore();
+ expect(redirectStub.calledOnce).toEqual(true);
+ expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files');
+ expect(getFolderContentsStub.calledOnce).toEqual(true);
});
- it('reloads the page on authentication errors', function () {
- fileList.reload();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'error',
- data: {
- 'error': 'authentication_error'
- }
- })
- );
- expect(redirectStub.calledWith(OC.generateUrl('apps/files'))).toEqual(true);
+ it('redirects to root folder in case of forbidden access', function () {
+ deferredList.reject(403);
+
+ expect(fileList.getCurrentDirectory()).toEqual('/');
+ expect(getFolderContentsStub.calledTwice).toEqual(true);
+ });
+ it('redirects to root folder and shows notification in case of internal server error', function () {
+ expect(notificationStub.notCalled).toEqual(true);
+ deferredList.reject(500);
+
+ expect(fileList.getCurrentDirectory()).toEqual('/');
+ expect(getFolderContentsStub.calledTwice).toEqual(true);
+ expect(notificationStub.calledOnce).toEqual(true);
+ });
+ it('redirects to root folder and shows notification in case of storage not available', function () {
+ expect(notificationStub.notCalled).toEqual(true);
+ deferredList.reject(503, 'Storage not available');
+
+ expect(fileList.getCurrentDirectory()).toEqual('/');
+ expect(getFolderContentsStub.calledTwice).toEqual(true);
+ expect(notificationStub.calledOnce).toEqual(true);
});
});
describe('showFileBusyState', function() {
@@ -2609,4 +2555,34 @@ describe('OCA.Files.FileList tests', function() {
expect(newFileMenuStub.notCalled).toEqual(true);
});
});
+ describe('mount type detection', function() {
+ function testMountType(dirInfoId, dirInfoMountType, inputMountType, expectedMountType) {
+ var $tr;
+ fileList.dirInfo.id = dirInfoId;
+ fileList.dirInfo.mountType = dirInfoMountType;
+ $tr = fileList.add({
+ type: 'dir',
+ mimetype: 'httpd/unix-directory',
+ name: 'test dir',
+ mountType: inputMountType
+ });
+
+ expect($tr.attr('data-mounttype')).toEqual(expectedMountType);
+ }
+
+ it('leaves mount type as is if no parent exists', function() {
+ testMountType(null, null, 'external', 'external');
+ testMountType(null, null, 'shared', 'shared');
+ });
+ it('detects share root if parent exists', function() {
+ testMountType(123, null, 'shared', 'shared-root');
+ testMountType(123, 'shared', 'shared', 'shared');
+ testMountType(123, 'shared-root', 'shared', 'shared');
+ });
+ it('detects external storage root if parent exists', function() {
+ testMountType(123, null, 'external', 'external-root');
+ testMountType(123, 'external', 'external', 'external');
+ testMountType(123, 'external-root', 'external', 'external');
+ });
+ });
});
diff --git a/apps/files/tests/js/filesSpec.js b/apps/files/tests/js/filesSpec.js
index 30e6675c155..b7627d59fdf 100644
--- a/apps/files/tests/js/filesSpec.js
+++ b/apps/files/tests/js/filesSpec.js
@@ -76,11 +76,11 @@ describe('OCA.Files.Files tests', function() {
describe('getDownloadUrl', function() {
it('returns the ajax download URL when filename and dir specified', function() {
var url = Files.getDownloadUrl('test file.txt', '/subdir');
- expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=test%20file.txt');
+ expect(url).toEqual(OC.webroot + '/remote.php/webdav/subdir/test%20file.txt');
});
- it('returns the ajax download URL when filename and root dir specific', function() {
+ it('returns the webdav download URL when filename and root dir specified', function() {
var url = Files.getDownloadUrl('test file.txt', '/');
- expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=test%20file.txt');
+ expect(url).toEqual(OC.webroot + '/remote.php/webdav/test%20file.txt');
});
it('returns the ajax download URL when multiple files specified', function() {
var url = Files.getDownloadUrl(['test file.txt', 'abc.txt'], '/subdir');
diff --git a/apps/files/tests/js/filesummarySpec.js b/apps/files/tests/js/filesummarySpec.js
index ae5ff95fc0c..ec94c28acb6 100644
--- a/apps/files/tests/js/filesummarySpec.js
+++ b/apps/files/tests/js/filesummarySpec.js
@@ -40,7 +40,7 @@ describe('OCA.Files.FileSummary tests', function() {
});
expect($container.hasClass('hidden')).toEqual(false);
expect($container.find('.info').text()).toEqual('5 folders and 2 files');
- expect($container.find('.filesize').text()).toEqual('250 kB');
+ expect($container.find('.filesize').text()).toEqual('250 KB');
});
it('hides summary when no files or folders', function() {
var s = new FileSummary($container);
@@ -63,7 +63,7 @@ describe('OCA.Files.FileSummary tests', function() {
s.update();
expect($container.hasClass('hidden')).toEqual(false);
expect($container.find('.info').text()).toEqual('6 folders and 3 files');
- expect($container.find('.filesize').text()).toEqual('500 kB');
+ expect($container.find('.filesize').text()).toEqual('500 KB');
expect(s.summary.totalDirs).toEqual(6);
expect(s.summary.totalFiles).toEqual(3);
expect(s.summary.totalSize).toEqual(512100);
@@ -80,7 +80,7 @@ describe('OCA.Files.FileSummary tests', function() {
s.update();
expect($container.hasClass('hidden')).toEqual(false);
expect($container.find('.info').text()).toEqual('4 folders and 1 file');
- expect($container.find('.filesize').text()).toEqual('125 kB');
+ expect($container.find('.filesize').text()).toEqual('125 KB');
expect(s.summary.totalDirs).toEqual(4);
expect(s.summary.totalFiles).toEqual(1);
expect(s.summary.totalSize).toEqual(127900);
@@ -96,7 +96,7 @@ describe('OCA.Files.FileSummary tests', function() {
});
expect($container.hasClass('hidden')).toEqual(false);
expect($container.find('.info').text()).toEqual('5 folders and 2 files match \'foo\'');
- expect($container.find('.filesize').text()).toEqual('250 kB');
+ expect($container.find('.filesize').text()).toEqual('250 KB');
});
it('hides filtered summary when no files or folders', function() {
var s = new FileSummary($container);
@@ -123,7 +123,7 @@ describe('OCA.Files.FileSummary tests', function() {
s.update();
expect($container.hasClass('hidden')).toEqual(false);
expect($container.find('.info').text()).toEqual('6 folders and 3 files match \'foo\'');
- expect($container.find('.filesize').text()).toEqual('500 kB');
+ expect($container.find('.filesize').text()).toEqual('500 KB');
expect(s.summary.totalDirs).toEqual(6);
expect(s.summary.totalFiles).toEqual(3);
expect(s.summary.totalSize).toEqual(512103);
@@ -143,7 +143,7 @@ describe('OCA.Files.FileSummary tests', function() {
s.update();
expect($container.hasClass('hidden')).toEqual(false);
expect($container.find('.info').text()).toEqual('4 folders and 1 file match \'foo\'');
- expect($container.find('.filesize').text()).toEqual('125 kB');
+ expect($container.find('.filesize').text()).toEqual('125 KB');
expect(s.summary.totalDirs).toEqual(4);
expect(s.summary.totalFiles).toEqual(1);
expect(s.summary.totalSize).toEqual(127903);
diff --git a/apps/files/tests/js/newfilemenuSpec.js b/apps/files/tests/js/newfilemenuSpec.js
index 3d89a997eb2..20f617d24d6 100644
--- a/apps/files/tests/js/newfilemenuSpec.js
+++ b/apps/files/tests/js/newfilemenuSpec.js
@@ -46,7 +46,7 @@ describe('OCA.Files.NewFileMenu', function() {
describe('rendering', function() {
it('renders menu items', function() {
var $items = menu.$el.find('.menuitem');
- expect($items.length).toEqual(3);
+ expect($items.length).toEqual(2);
// label points to the file_upload_start item
var $item = $items.eq(0);
expect($item.is('label')).toEqual(true);
@@ -55,39 +55,26 @@ describe('OCA.Files.NewFileMenu', function() {
});
describe('New file/folder', function() {
var $input;
- var createFileStub;
var createDirectoryStub;
beforeEach(function() {
- createFileStub = sinon.stub(FileList.prototype, 'createFile');
createDirectoryStub = sinon.stub(FileList.prototype, 'createDirectory');
menu.$el.find('.menuitem').eq(1).click();
$input = menu.$el.find('form.filenameform input');
});
afterEach(function() {
- createFileStub.restore();
createDirectoryStub.restore();
});
it('sets default text in field', function() {
expect($input.length).toEqual(1);
- expect($input.val()).toEqual('New text file.txt');
- });
- it('creates file when enter is pressed', function() {
- $input.val('somefile.txt');
- $input.trigger(new $.Event('keyup', {keyCode: 13}));
- $input.parent('form').submit();
-
- expect(createFileStub.calledOnce).toEqual(true);
- expect(createFileStub.getCall(0).args[0]).toEqual('somefile.txt');
- expect(createDirectoryStub.notCalled).toEqual(true);
+ expect($input.val()).toEqual('New folder');
});
it('prevents entering invalid file names', function() {
$input.val('..');
$input.trigger(new $.Event('keyup', {keyCode: 13}));
$input.closest('form').submit();
- expect(createFileStub.notCalled).toEqual(true);
expect(createDirectoryStub.notCalled).toEqual(true);
});
it('prevents entering file names that already exist', function() {
@@ -96,16 +83,10 @@ describe('OCA.Files.NewFileMenu', function() {
$input.trigger(new $.Event('keyup', {keyCode: 13}));
$input.closest('form').submit();
- expect(createFileStub.notCalled).toEqual(true);
expect(createDirectoryStub.notCalled).toEqual(true);
inListStub.restore();
});
- it('switching fields removes the previous form', function() {
- menu.$el.find('.menuitem').eq(2).click();
- expect(menu.$el.find('form').length).toEqual(1);
- });
it('creates directory when clicking on create directory field', function() {
- menu.$el.find('.menuitem').eq(2).click();
$input = menu.$el.find('form.filenameform input');
$input.val('some folder');
$input.trigger(new $.Event('keyup', {keyCode: 13}));
@@ -113,7 +94,55 @@ describe('OCA.Files.NewFileMenu', function() {
expect(createDirectoryStub.calledOnce).toEqual(true);
expect(createDirectoryStub.getCall(0).args[0]).toEqual('some folder');
- expect(createFileStub.notCalled).toEqual(true);
+ });
+ });
+ describe('custom entries', function() {
+ var oldPlugins;
+ var plugin;
+ var actionStub;
+
+ beforeEach(function() {
+ oldPlugins = _.extend({}, OC.Plugins._plugins);
+ actionStub = sinon.stub();
+ plugin = {
+ attach: function(menu) {
+ menu.addMenuEntry({
+ id: 'file',
+ displayName: t('files_texteditor', 'Text file'),
+ templateName: t('files_texteditor', 'New text file.txt'),
+ iconClass: 'icon-filetype-text',
+ fileType: 'file',
+ actionHandler: actionStub
+ });
+ }
+ };
+
+ OC.Plugins.register('OCA.Files.NewFileMenu', plugin);
+ menu = new OCA.Files.NewFileMenu({
+ fileList: fileList
+ });
+ menu.showAt($trigger);
+ });
+ afterEach(function() {
+ OC.Plugins._plugins = oldPlugins;
+ });
+ it('renders custom menu items', function() {
+ expect(menu.$el.find('.menuitem').length).toEqual(3);
+ expect(menu.$el.find('.menuitem[data-action=file]').length).toEqual(1);
+ });
+ it('calls action handler when clicking on custom item', function() {
+ menu.$el.find('.menuitem').eq(2).click();
+ var $input = menu.$el.find('form.filenameform input');
+ $input.val('some name');
+ $input.trigger(new $.Event('keyup', {keyCode: 13}));
+ $input.closest('form').submit();
+
+ expect(actionStub.calledOnce).toEqual(true);
+ expect(actionStub.getCall(0).args[0]).toEqual('some name');
+ });
+ it('switching fields removes the previous form', function() {
+ menu.$el.find('.menuitem').eq(2).click();
+ expect(menu.$el.find('form').length).toEqual(1);
});
});
});
diff --git a/apps/files/tests/service/tagservice.php b/apps/files/tests/service/tagservice.php
index 147e698aaaa..5fcf64b1352 100644
--- a/apps/files/tests/service/tagservice.php
+++ b/apps/files/tests/service/tagservice.php
@@ -1,8 +1,10 @@
<?php
/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,6 +24,13 @@ namespace OCA\Files;
use \OCA\Files\Service\TagService;
+/**
+ * Class TagServiceTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files
+ */
class TagServiceTest extends \Test\TestCase {
/**
@@ -47,7 +56,7 @@ class TagServiceTest extends \Test\TestCase {
protected function setUp() {
parent::setUp();
$this->user = $this->getUniqueId('user');
- \OC_User::createUser($this->user, 'test');
+ \OC::$server->getUserManager()->createUser($this->user, 'test');
\OC_User::setUserId($this->user);
\OC_Util::setupFS($this->user);
/**
@@ -75,7 +84,8 @@ class TagServiceTest extends \Test\TestCase {
protected function tearDown() {
\OC_User::setUserId('');
- \OC_User::deleteUser($this->user);
+ $user = \OC::$server->getUserManager()->get($this->user);
+ if ($user !== null) { $user->delete(); }
}
public function testUpdateFileTags() {
diff --git a/apps/files_external/ajax/applicable.php b/apps/files_external/ajax/applicable.php
index 7f1b4dc9221..5d30dfdbb51 100644
--- a/apps/files_external/ajax/applicable.php
+++ b/apps/files_external/ajax/applicable.php
@@ -2,9 +2,9 @@
/**
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/ajax/oauth1.php b/apps/files_external/ajax/oauth1.php
index 3d6736b3b59..ea7db2523a8 100644
--- a/apps/files_external/ajax/oauth1.php
+++ b/apps/files_external/ajax/oauth1.php
@@ -4,10 +4,10 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/ajax/oauth2.php b/apps/files_external/ajax/oauth2.php
index fbe60e16e26..b110cba9fe0 100644
--- a/apps/files_external/ajax/oauth2.php
+++ b/apps/files_external/ajax/oauth2.php
@@ -6,10 +6,11 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Vincent Petry <pvince81@owncloud.com>
* @author Volkan Gezer <volkangezer@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php
index a7d8f4f668d..c8d90f02f29 100644
--- a/apps/files_external/appinfo/app.php
+++ b/apps/files_external/appinfo/app.php
@@ -1,16 +1,16 @@
<?php
/**
* @author Christian Berendt <berendt@b1-systems.de>
- * @author j-ed <juergen@eisfair.org>
* @author Jan-Christoph Borchardt <hey@jancborchardt.net>
+ * @author j-ed <juergen@eisfair.org>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Ross Nicoll <jrn@jrn.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -45,12 +45,9 @@ require_once __DIR__ . '/../3rdparty/autoload.php';
\OC_Mount_Config::$app = new \OCA\Files_external\Appinfo\Application();
$appContainer = \OC_Mount_Config::$app->getContainer();
-$l = \OC::$server->getL10N('files_external');
+\OC_Mount_Config::$app->registerSettings();
-OCP\App::registerAdmin('files_external', 'settings');
-if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == 'yes') {
- OCP\App::registerPersonal('files_external', 'personal');
-}
+$l = \OC::$server->getL10N('files_external');
\OCA\Files\App::getNavigationManager()->add([
"id" => 'extstoragemounts',
@@ -60,8 +57,5 @@ if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == '
"name" => $l->t('External storage')
]);
-// connecting hooks
-OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook');
-
$mountProvider = $appContainer->query('OCA\Files_External\Config\ConfigAdapter');
\OC::$server->getMountProviderCollection()->registerProvider($mountProvider);
diff --git a/apps/files_external/appinfo/application.php b/apps/files_external/appinfo/application.php
index 1d6e0d03400..d6552fa680c 100644
--- a/apps/files_external/appinfo/application.php
+++ b/apps/files_external/appinfo/application.php
@@ -1,12 +1,12 @@
<?php
/**
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Ross Nicoll <jrn@jrn.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +26,7 @@
namespace OCA\Files_External\AppInfo;
use \OCP\AppFramework\App;
+use OCP\AppFramework\IAppContainer;
use \OCP\IContainer;
use \OCA\Files_External\Service\BackendService;
@@ -33,9 +34,13 @@ use \OCA\Files_External\Service\BackendService;
* @package OCA\Files_External\Appinfo
*/
class Application extends App {
- public function __construct(array $urlParams=array()) {
+ public function __construct(array $urlParams = array()) {
parent::__construct('files_external', $urlParams);
+ $this->getContainer()->registerService('OCP\Files\Config\IUserMountCache', function (IAppContainer $c) {
+ return $c->getServer()->query('UserMountCache');
+ });
+
$this->loadBackends();
$this->loadAuthMechanisms();
@@ -46,6 +51,19 @@ class Application extends App {
}
/**
+ * Register settings templates
+ */
+ public function registerSettings() {
+ $container = $this->getContainer();
+ $backendService = $container->query('OCA\\Files_External\\Service\\BackendService');
+
+ \OCP\App::registerAdmin('files_external', 'settings');
+ if ($backendService->isUserMountingAllowed()) {
+ \OCP\App::registerPersonal('files_external', 'personal');
+ }
+ }
+
+ /**
* Load storage backends provided by this app
*/
protected function loadBackends() {
@@ -90,6 +108,9 @@ class Application extends App {
// AuthMechanism::SCHEME_PASSWORD mechanisms
$container->query('OCA\Files_External\Lib\Auth\Password\Password'),
$container->query('OCA\Files_External\Lib\Auth\Password\SessionCredentials'),
+ $container->query('OCA\Files_External\Lib\Auth\Password\LoginCredentials'),
+ $container->query('OCA\Files_External\Lib\Auth\Password\UserProvided'),
+ $container->query('OCA\Files_External\Lib\Auth\Password\GlobalAuth'),
// AuthMechanism::SCHEME_OAUTH1 mechanisms
$container->query('OCA\Files_External\Lib\Auth\OAuth1\OAuth1'),
diff --git a/apps/files_external/appinfo/database.xml b/apps/files_external/appinfo/database.xml
new file mode 100644
index 00000000000..2c3615a4d4c
--- /dev/null
+++ b/apps/files_external/appinfo/database.xml
@@ -0,0 +1,216 @@
+<database>
+ <name>*dbname*</name>
+ <create>true</create>
+ <overwrite>false</overwrite>
+ <charset>utf8</charset>
+ <table>
+ <name>*dbprefix*external_mounts</name>
+ <declaration>
+ <field>
+ <name>mount_id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <length>6</length>
+ </field>
+ <field>
+ <name>mount_point</name>
+ <type>text</type>
+ <length>128</length>
+ <notnull>true</notnull>
+ </field>
+ <field>
+ <name>storage_backend</name>
+ <type>text</type>
+ <length>64</length>
+ <notnull>true</notnull>
+ </field>
+ <field>
+ <name>auth_backend</name>
+ <type>text</type>
+ <length>64</length>
+ <notnull>true</notnull>
+ </field>
+ <field>
+ <name>priority</name>
+ <type>integer</type>
+ <default>100</default>
+ <length>4</length>
+ <notnull>true</notnull>
+ </field>
+ <!-- admin = 1, personal = 2-->
+ <field>
+ <name>type</name>
+ <type>integer</type>
+ <length>4</length>
+ <notnull>true</notnull>
+ </field>
+ </declaration>
+ </table>
+ <table>
+ <name>*dbprefix*external_applicable</name>
+ <declaration>
+ <field>
+ <name>applicable_id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <length>6</length>
+ </field>
+ <field>
+ <!--foreign key: external_mounts.mount_id-->
+ <name>mount_id</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <length>6</length>
+ </field>
+ <field>
+ <!-- possible mount types: global = 1, group = 2, user = 3 -->
+ <name>type</name>
+ <type>integer</type>
+ <length>4</length>
+ <notnull>true</notnull>
+ </field>
+ <field>
+ <!-- user_id, group_id or null for global mounts -->
+ <name>value</name>
+ <type>text</type>
+ <length>64</length>
+ </field>
+ <index>
+ <field>
+ <name>mount_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ <index>
+ <field>
+ <name>type</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>value</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ <index>
+ <unique>true</unique>
+ <field>
+ <name>type</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>value</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>mount_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ </declaration>
+ </table>
+ <table>
+ <name>*dbprefix*external_config</name>
+ <declaration>
+ <field>
+ <name>config_id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <length>6</length>
+ </field>
+ <field>
+ <!--foreign key: external_mounts.mount_id-->
+ <name>mount_id</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <length>6</length>
+ </field>
+ <field>
+ <name>key</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+ <field>
+ <name>value</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>4096</length>
+ </field>
+
+ <index>
+ <field>
+ <name>mount_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ <index>
+ <unique>true</unique>
+ <field>
+ <name>mount_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>key</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ </declaration>
+ </table>
+ <table>
+ <name>*dbprefix*external_options</name>
+ <declaration>
+ <field>
+ <name>option_id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <length>6</length>
+ </field>
+ <field>
+ <!--foreign key: external_mounts.mount_id-->
+ <name>mount_id</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <length>6</length>
+ </field>
+ <field>
+ <name>key</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+ <field>
+ <name>value</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>256</length>
+ </field>
+
+ <index>
+ <field>
+ <name>mount_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ <index>
+ <name>option_mount_key</name>
+ <unique>true</unique>
+ <field>
+ <name>mount_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>key</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ </declaration>
+ </table>
+</database>
diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml
index bb494a2eaba..1cd4f602075 100644
--- a/apps/files_external/appinfo/info.xml
+++ b/apps/files_external/appinfo/info.xml
@@ -9,18 +9,17 @@
</description>
<licence>AGPL</licence>
<author>Robin Appelman, Michael Gapczynski, Vincent Petry</author>
- <shipped>true</shipped>
<documentation>
<admin>admin-external-storage</admin>
</documentation>
<rememberlogin>false</rememberlogin>
- <version>0.4.0</version>
+ <version>0.5.2</version>
<types>
<filesystem/>
</types>
<ocsid>166048</ocsid>
<dependencies>
- <owncloud min-version="9.0" />
+ <owncloud min-version="9.0" max-version="9.0" />
</dependencies>
</info>
diff --git a/apps/files_external/appinfo/register_command.php b/apps/files_external/appinfo/register_command.php
new file mode 100644
index 00000000000..929becce77a
--- /dev/null
+++ b/apps/files_external/appinfo/register_command.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+use OCA\Files_External\Command\ListCommand;
+use OCA\Files_External\Command\Config;
+use OCA\Files_External\Command\Option;
+use OCA\Files_External\Command\Applicable;
+use OCA\Files_External\Command\Import;
+use OCA\Files_External\Command\Export;
+use OCA\Files_External\Command\Delete;
+
+$userManager = OC::$server->getUserManager();
+$userSession = OC::$server->getUserSession();
+$groupManager = OC::$server->getGroupManager();
+
+$app = \OC_Mount_Config::$app;
+
+$globalStorageService = $app->getContainer()->query('\OCA\Files_external\Service\GlobalStoragesService');
+$userStorageService = $app->getContainer()->query('\OCA\Files_external\Service\UserStoragesService');
+$importLegacyStorageService = $app->getContainer()->query('\OCA\Files_external\Service\ImportLegacyStoragesService');
+$backendService = $app->getContainer()->query('OCA\Files_External\Service\BackendService');
+
+/** @var Symfony\Component\Console\Application $application */
+$application->add(new ListCommand($globalStorageService, $userStorageService, $userSession, $userManager));
+$application->add(new Config($globalStorageService));
+$application->add(new Option($globalStorageService));
+$application->add(new Applicable($globalStorageService, $userManager, $groupManager));
+$application->add(new Import($globalStorageService, $userStorageService, $userSession, $userManager, $importLegacyStorageService, $backendService));
+$application->add(new Export($globalStorageService, $userStorageService, $userSession, $userManager));
+$application->add(new Delete($globalStorageService, $userStorageService, $userSession, $userManager));
diff --git a/apps/files_external/appinfo/routes.php b/apps/files_external/appinfo/routes.php
index 39ded1dc2ec..d5b927c0227 100644
--- a/apps/files_external/appinfo/routes.php
+++ b/apps/files_external/appinfo/routes.php
@@ -3,12 +3,12 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Ross Nicoll <jrn@jrn.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -36,6 +36,7 @@ namespace OCA\Files_External\AppInfo;
'resources' => array(
'global_storages' => array('url' => '/globalstorages'),
'user_storages' => array('url' => '/userstorages'),
+ 'user_global_storages' => array('url' => '/userglobalstorages'),
),
'routes' => array(
array(
@@ -43,7 +44,12 @@ namespace OCA\Files_External\AppInfo;
'url' => '/ajax/public_key.php',
'verb' => 'POST',
'requirements' => array()
- )
+ ),
+ [
+ 'name' => 'Ajax#saveGlobalCredentials',
+ 'url' => '/globalcredentials',
+ 'verb' => 'POST'
+ ]
)
)
);
diff --git a/apps/files_external/appinfo/update.php b/apps/files_external/appinfo/update.php
new file mode 100644
index 00000000000..8cc2422c7ff
--- /dev/null
+++ b/apps/files_external/appinfo/update.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+$installedVersion = \OC::$server->getConfig()->getAppValue('files_external', 'installed_version');
+
+$app = new \OCA\Files_external\Appinfo\Application();
+
+// Migration to db config
+if (version_compare($installedVersion, '0.5.0', '<')) {
+ $migrator = $app->getContainer()->query('OCA\Files_external\Migration\StorageMigrator');
+ $migrator->migrateGlobal();
+}
diff --git a/apps/files_external/command/applicable.php b/apps/files_external/command/applicable.php
new file mode 100644
index 00000000000..7e6c99d2915
--- /dev/null
+++ b/apps/files_external/command/applicable.php
@@ -0,0 +1,157 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_external\NotFoundException;
+use OCA\Files_external\Service\GlobalStoragesService;
+use OCP\IGroupManager;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Helper\TableHelper;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Applicable extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ protected $globalService;
+
+ /**
+ * @var IUserManager
+ */
+ private $userManager;
+
+ /**
+ * @var IGroupManager
+ */
+ private $groupManager;
+
+ function __construct(
+ GlobalStoragesService $globalService,
+ IUserManager $userManager,
+ IGroupManager $groupManager
+ ) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ $this->userManager = $userManager;
+ $this->groupManager = $groupManager;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:applicable')
+ ->setDescription('Manage applicable users and groups for a mount')
+ ->addArgument(
+ 'mount_id',
+ InputArgument::REQUIRED,
+ 'The id of the mount to edit'
+ )->addOption(
+ 'add-user',
+ null,
+ InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
+ 'user to add as applicable'
+ )->addOption(
+ 'remove-user',
+ null,
+ InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
+ 'user to remove as applicable'
+ )->addOption(
+ 'add-group',
+ null,
+ InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
+ 'group to add as applicable'
+ )->addOption(
+ 'remove-group',
+ null,
+ InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
+ 'group to remove as applicable'
+ )->addOption(
+ 'remove-all',
+ null,
+ InputOption::VALUE_NONE,
+ 'Set the mount to be globally applicable'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $mountId = $input->getArgument('mount_id');
+ try {
+ $mount = $this->globalService->getStorage($mountId);
+ } catch (NotFoundException $e) {
+ $output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts</error>');
+ return 404;
+ }
+
+ if ($mount->getType() === StorageConfig::MOUNT_TYPE_PERSONAl) {
+ $output->writeln('<error>Can\'t change applicables on personal mounts</error>');
+ return 1;
+ }
+
+ $addUsers = $input->getOption('add-user');
+ $removeUsers = $input->getOption('remove-user');
+ $addGroups = $input->getOption('add-group');
+ $removeGroups = $input->getOption('remove-group');
+
+ $applicableUsers = $mount->getApplicableUsers();
+ $applicableGroups = $mount->getApplicableGroups();
+
+ if ((count($addUsers) + count($removeUsers) + count($addGroups) + count($removeGroups) > 0) || $input->getOption('remove-all')) {
+ foreach ($addUsers as $addUser) {
+ if (!$this->userManager->userExists($addUser)) {
+ $output->writeln('<error>User "' . $addUser . '" not found</error>');
+ return 404;
+ }
+ }
+ foreach ($addGroups as $addGroup) {
+ if (!$this->groupManager->groupExists($addGroup)) {
+ $output->writeln('<error>Group "' . $addGroup . '" not found</error>');
+ return 404;
+ }
+ }
+
+ if ($input->getOption('remove-all')) {
+ $applicableUsers = [];
+ $applicableGroups = [];
+ } else {
+ $applicableUsers = array_unique(array_merge($applicableUsers, $addUsers));
+ $applicableUsers = array_values(array_diff($applicableUsers, $removeUsers));
+ $applicableGroups = array_unique(array_merge($applicableGroups, $addGroups));
+ $applicableGroups = array_values(array_diff($applicableGroups, $removeGroups));
+ }
+ $mount->setApplicableUsers($applicableUsers);
+ $mount->setApplicableGroups($applicableGroups);
+ $this->globalService->updateStorage($mount);
+ }
+
+ $this->writeArrayInOutputFormat($input, $output, [
+ 'users' => $applicableUsers,
+ 'groups' => $applicableGroups
+ ]);
+ }
+}
diff --git a/apps/files_external/command/config.php b/apps/files_external/command/config.php
new file mode 100644
index 00000000000..1403c24b345
--- /dev/null
+++ b/apps/files_external/command/config.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_external\NotFoundException;
+use OCA\Files_external\Service\GlobalStoragesService;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Helper\TableHelper;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Config extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ protected $globalService;
+
+ function __construct(GlobalStoragesService $globalService) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:config')
+ ->setDescription('Manage backend configuration for a mount')
+ ->addArgument(
+ 'mount_id',
+ InputArgument::REQUIRED,
+ 'The id of the mount to edit'
+ )->addArgument(
+ 'key',
+ InputArgument::REQUIRED,
+ 'key of the config option to set/get'
+ )->addArgument(
+ 'value',
+ InputArgument::OPTIONAL,
+ 'value to set the config option to, when no value is provided the existing value will be printed'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $mountId = $input->getArgument('mount_id');
+ $key = $input->getArgument('key');
+ try {
+ $mount = $this->globalService->getStorage($mountId);
+ } catch (NotFoundException $e) {
+ $output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
+ return 404;
+ }
+
+ $value = $input->getArgument('value');
+ if ($value) {
+ $this->setOption($mount, $key, $value, $output);
+ } else {
+ $this->getOption($mount, $key, $output);
+ }
+ }
+
+ /**
+ * @param StorageConfig $mount
+ * @param string $key
+ * @param OutputInterface $output
+ */
+ protected function getOption(StorageConfig $mount, $key, OutputInterface $output) {
+ if ($key === 'mountpoint' || $key === 'mount_point') {
+ $value = $mount->getMountPoint();
+ } else {
+ $value = $mount->getBackendOption($key);
+ }
+ if (!is_string($value)) { // show bools and objects correctly
+ $value = json_encode($value);
+ }
+ $output->writeln($value);
+ }
+
+ /**
+ * @param StorageConfig $mount
+ * @param string $key
+ * @param string $value
+ * @param OutputInterface $output
+ */
+ protected function setOption(StorageConfig $mount, $key, $value, OutputInterface $output) {
+ $decoded = json_decode($value, true);
+ if (!is_null($decoded)) {
+ $value = $decoded;
+ }
+ if ($key === 'mountpoint' || $key === 'mount_point') {
+ $mount->setMountPoint($value);
+ } else {
+ $mount->setBackendOption($key, $value);
+ }
+ $this->globalService->updateStorage($mount);
+ }
+}
diff --git a/apps/files_external/command/delete.php b/apps/files_external/command/delete.php
new file mode 100644
index 00000000000..bdbfcf8bb55
--- /dev/null
+++ b/apps/files_external/command/delete.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_external\NotFoundException;
+use OCA\Files_external\Service\GlobalStoragesService;
+use OCA\Files_external\Service\UserStoragesService;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Helper\TableHelper;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
+
+class Delete extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ protected $globalService;
+
+ /**
+ * @var UserStoragesService
+ */
+ protected $userService;
+
+ /**
+ * @var IUserSession
+ */
+ protected $userSession;
+
+ /**
+ * @var IUserManager
+ */
+ protected $userManager;
+
+ function __construct(GlobalStoragesService $globalService, UserStoragesService $userService, IUserSession $userSession, IUserManager $userManager) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ $this->userService = $userService;
+ $this->userSession = $userSession;
+ $this->userManager = $userManager;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:delete')
+ ->setDescription('Delete an external mount')
+ ->addArgument(
+ 'mount_id',
+ InputArgument::REQUIRED,
+ 'The id of the mount to edit'
+ )->addOption(
+ 'yes',
+ 'y',
+ InputOption::VALUE_NONE,
+ 'Skip confirmation'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $mountId = $input->getArgument('mount_id');
+ try {
+ $mount = $this->globalService->getStorage($mountId);
+ } catch (NotFoundException $e) {
+ $output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
+ return 404;
+ }
+
+ $noConfirm = $input->getOption('yes');
+
+ if (!$noConfirm) {
+ $listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
+ $listInput = new ArrayInput([], $listCommand->getDefinition());
+ $listInput->setOption('output', $input->getOption('output'));
+ $listCommand->listMounts(null, [$mount], $listInput, $output);
+
+ $questionHelper = $this->getHelper('question');
+ $question = new ConfirmationQuestion('Delete this mount? [y/N] ', false);
+
+ if (!$questionHelper->ask($input, $output, $question)) {
+ return;
+ }
+ }
+
+ $this->globalService->removeStorage($mountId);
+ }
+}
diff --git a/apps/files_external/command/export.php b/apps/files_external/command/export.php
new file mode 100644
index 00000000000..371061ba626
--- /dev/null
+++ b/apps/files_external/command/export.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Helper\TableHelper;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\Input;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Export extends ListCommand {
+
+ protected function configure() {
+ $this
+ ->setName('files_external:export')
+ ->setDescription('Export mount configurations')
+ ->addArgument(
+ 'user_id',
+ InputArgument::OPTIONAL,
+ 'user id to export the personal mounts for, if no user is provided admin mounts will be exported'
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
+ $listInput = new ArrayInput([], $listCommand->getDefinition());
+ $listInput->setArgument('user_id', $input->getArgument('user_id'));
+ $listInput->setOption('output', 'json_pretty');
+ $listInput->setOption('show-password', true);
+ $listInput->setOption('full', true);
+ $listCommand->execute($listInput, $output);
+ }
+}
diff --git a/apps/files_external/command/import.php b/apps/files_external/command/import.php
new file mode 100644
index 00000000000..fe27051359c
--- /dev/null
+++ b/apps/files_external/command/import.php
@@ -0,0 +1,227 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OC\User\NoUserException;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_External\Service\BackendService;
+use OCA\Files_external\Service\GlobalStoragesService;
+use OCA\Files_external\Service\ImportLegacyStoragesService;
+use OCA\Files_external\Service\UserStoragesService;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Helper\TableHelper;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\Input;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Import extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ private $globalService;
+
+ /**
+ * @var UserStoragesService
+ */
+ private $userService;
+
+ /**
+ * @var IUserSession
+ */
+ private $userSession;
+
+ /**
+ * @var IUserManager
+ */
+ private $userManager;
+
+ /** @var ImportLegacyStoragesService */
+ private $importLegacyStorageService;
+
+ /** @var BackendService */
+ private $backendService;
+
+ function __construct(GlobalStoragesService $globalService,
+ UserStoragesService $userService,
+ IUserSession $userSession,
+ IUserManager $userManager,
+ ImportLegacyStoragesService $importLegacyStorageService,
+ BackendService $backendService
+ ) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ $this->userService = $userService;
+ $this->userSession = $userSession;
+ $this->userManager = $userManager;
+ $this->importLegacyStorageService = $importLegacyStorageService;
+ $this->backendService = $backendService;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:import')
+ ->setDescription('Import mount configurations')
+ ->addOption(
+ 'user',
+ null,
+ InputOption::VALUE_OPTIONAL,
+ 'user to add the mount configurations for, if not set the mount will be added as system mount'
+ )
+ ->addArgument(
+ 'path',
+ InputArgument::REQUIRED,
+ 'path to a json file containing the mounts to import, use "-" to read from stdin'
+ )
+ ->addOption(
+ 'dry',
+ null,
+ InputOption::VALUE_NONE,
+ 'Don\'t save the imported mounts, only list the new mounts'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $user = $input->getOption('user');
+ $path = $input->getArgument('path');
+ if ($path === '-') {
+ $json = file_get_contents('php://stdin');
+ } else {
+ if (!file_exists($path)) {
+ $output->writeln('<error>File not found: ' . $path . '</error>');
+ return 1;
+ }
+ $json = file_get_contents($path);
+ }
+ if (!is_string($json) || strlen($json) < 2) {
+ $output->writeln('<error>Error while reading json</error>');
+ return 1;
+ }
+ $data = json_decode($json, true);
+ if (!is_array($data)) {
+ $output->writeln('<error>Error while parsing json</error>');
+ return 1;
+ }
+
+ $isLegacy = isset($data['user']) || isset($data['group']);
+ if ($isLegacy) {
+ $this->importLegacyStorageService->setData($data);
+ $mounts = $this->importLegacyStorageService->getAllStorages();
+ foreach ($mounts as $mount) {
+ if ($mount->getBackendOption('password') === false) {
+ $output->writeln('<error>Failed to decrypt password</error>');
+ return 1;
+ }
+ }
+ } else {
+ if (!isset($data[0])) { //normalize to an array of mounts
+ $data = [$data];
+ }
+ $mounts = array_map([$this, 'parseData'], $data);
+ }
+
+ if ($user) {
+ // ensure applicables are correct for personal mounts
+ foreach ($mounts as $mount) {
+ $mount->setApplicableGroups([]);
+ $mount->setApplicableUsers([$user]);
+ }
+ }
+
+ $storageService = $this->getStorageService($user);
+
+ $existingMounts = $storageService->getAllStorages();
+
+ foreach ($mounts as $mount) {
+ foreach ($existingMounts as $existingMount) {
+ if (
+ $existingMount->getMountPoint() === $mount->getMountPoint() &&
+ $existingMount->getApplicableGroups() === $mount->getApplicableGroups() &&
+ $existingMount->getApplicableUsers() == $mount->getApplicableUsers() &&
+ $existingMount->getBackendOptions() == $mount->getBackendOptions()
+ ) {
+ $output->writeln("<error>Duplicate mount (" . $mount->getMountPoint() . ")</error>");
+ return 1;
+ }
+ }
+ }
+
+ if ($input->getOption('dry')) {
+ if (count($mounts) === 0) {
+ $output->writeln('<error>No mounts to be imported</error>');
+ return 1;
+ }
+ $listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
+ $listInput = new ArrayInput([], $listCommand->getDefinition());
+ $listInput->setOption('output', $input->getOption('output'));
+ $listInput->setOption('show-password', true);
+ $listCommand->listMounts($user, $mounts, $listInput, $output);
+ } else {
+ foreach ($mounts as $mount) {
+ $storageService->addStorage($mount);
+ }
+ }
+ return 0;
+ }
+
+ private function parseData(array $data) {
+ $mount = new StorageConfig($data['mount_id']);
+ $mount->setMountPoint($data['mount_point']);
+ $mount->setBackend($this->getBackendByClass($data['storage']));
+ $authBackends = $this->backendService->getAuthMechanismsByScheme([$data['authentication_type']]);
+ $mount->setAuthMechanism(current($authBackends));
+ $mount->setBackendOptions($data['configuration']);
+ $mount->setMountOptions($data['options']);
+ $mount->setApplicableUsers(isset($data['applicable_users']) ? $data['applicable_users'] : []);
+ $mount->setApplicableGroups(isset($data['applicable_groups']) ? $data['applicable_groups'] : []);
+ return $mount;
+ }
+
+ private function getBackendByClass($className) {
+ $backends = $this->backendService->getBackends();
+ foreach ($backends as $backend) {
+ if ($backend->getStorageClass() === $className) {
+ return $backend;
+ }
+ }
+ }
+
+ protected function getStorageService($userId) {
+ if (!empty($userId)) {
+ $user = $this->userManager->get($userId);
+ if (is_null($user)) {
+ throw new NoUserException("user $userId not found");
+ }
+ $this->userSession->setUser($user);
+ return $this->userService;
+ } else {
+ return $this->globalService;
+ }
+ }
+}
diff --git a/apps/files_external/command/listcommand.php b/apps/files_external/command/listcommand.php
new file mode 100644
index 00000000000..c978ae5cfcb
--- /dev/null
+++ b/apps/files_external/command/listcommand.php
@@ -0,0 +1,248 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OC\User\NoUserException;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_external\Service\GlobalStoragesService;
+use OCA\Files_external\Service\UserStoragesService;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class ListCommand extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ protected $globalService;
+
+ /**
+ * @var UserStoragesService
+ */
+ protected $userService;
+
+ /**
+ * @var IUserSession
+ */
+ protected $userSession;
+
+ /**
+ * @var IUserManager
+ */
+ protected $userManager;
+
+ function __construct(GlobalStoragesService $globalService, UserStoragesService $userService, IUserSession $userSession, IUserManager $userManager) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ $this->userService = $userService;
+ $this->userSession = $userSession;
+ $this->userManager = $userManager;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:list')
+ ->setDescription('List configured mounts')
+ ->addArgument(
+ 'user_id',
+ InputArgument::OPTIONAL,
+ 'user id to list the personal mounts for, if no user is provided admin mounts will be listed'
+ )->addOption(
+ 'show-password',
+ null,
+ InputOption::VALUE_NONE,
+ 'show passwords and secrets'
+ )->addOption(
+ 'full',
+ null,
+ InputOption::VALUE_NONE,
+ 'don\'t truncate long values in table output'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $userId = $input->getArgument('user_id');
+ $storageService = $this->getStorageService($userId);
+
+ /** @var $mounts StorageConfig[] */
+ $mounts = $storageService->getAllStorages();
+
+ $this->listMounts($userId, $mounts, $input, $output);
+ }
+
+ /**
+ * @param $userId $userId
+ * @param StorageConfig[] $mounts
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ */
+ public function listMounts($userId, array $mounts, InputInterface $input, OutputInterface $output){
+ $outputType = $input->getOption('output');
+ if (count($mounts) === 0) {
+ if ($outputType === self::OUTPUT_FORMAT_JSON || $outputType === self::OUTPUT_FORMAT_JSON_PRETTY) {
+ $output->writeln('[]');
+ } else {
+ if ($userId) {
+ $output->writeln("<info>No mounts configured by $userId</info>");
+ } else {
+ $output->writeln("<info>No admin mounts configured</info>");
+ }
+ }
+ return;
+ }
+
+ $headers = ['Mount ID', 'Mount Point', 'Storage', 'Authentication Type', 'Configuration', 'Options'];
+
+ if (!$userId) {
+ $headers[] = 'Applicable Users';
+ $headers[] = 'Applicable Groups';
+ }
+
+ if (!$input->getOption('show-password')) {
+ $hideKeys = ['password', 'refresh_token', 'token', 'client_secret', 'public_key', 'private_key'];
+ foreach ($mounts as $mount) {
+ $config = $mount->getBackendOptions();
+ foreach ($config as $key => $value) {
+ if (in_array($key, $hideKeys)) {
+ $mount->setBackendOption($key, '***');
+ }
+ }
+ }
+ }
+
+ if ($outputType === self::OUTPUT_FORMAT_JSON || $outputType === self::OUTPUT_FORMAT_JSON_PRETTY) {
+ $keys = array_map(function ($header) {
+ return strtolower(str_replace(' ', '_', $header));
+ }, $headers);
+
+ $pairs = array_map(function (StorageConfig $config) use ($keys, $userId) {
+ $values = [
+ $config->getId(),
+ $config->getMountPoint(),
+ $config->getBackend()->getStorageClass(),
+ $config->getAuthMechanism()->getScheme(),
+ $config->getBackendOptions(),
+ $config->getMountOptions()
+ ];
+ if (!$userId) {
+ $values[] = $config->getApplicableUsers();
+ $values[] = $config->getApplicableGroups();
+ }
+
+ return array_combine($keys, $values);
+ }, $mounts);
+ if ($outputType === self::OUTPUT_FORMAT_JSON) {
+ $output->writeln(json_encode(array_values($pairs)));
+ } else {
+ $output->writeln(json_encode(array_values($pairs), JSON_PRETTY_PRINT));
+ }
+ } else {
+ $full = $input->getOption('full');
+ $defaultMountOptions = [
+ 'encrypt' => true,
+ 'previews' => true,
+ 'filesystem_check_changes' => 1
+ ];
+ $rows = array_map(function (StorageConfig $config) use ($userId, $defaultMountOptions, $full) {
+ $storageConfig = $config->getBackendOptions();
+ $keys = array_keys($storageConfig);
+ $values = array_values($storageConfig);
+
+ if (!$full) {
+ $values = array_map(function ($value) {
+ if (is_string($value) && strlen($value) > 32) {
+ return substr($value, 0, 6) . '...' . substr($value, -6, 6);
+ } else {
+ return $value;
+ }
+ }, $values);
+ }
+
+ $configStrings = array_map(function ($key, $value) {
+ return $key . ': ' . json_encode($value);
+ }, $keys, $values);
+ $configString = implode(', ', $configStrings);
+
+ $mountOptions = $config->getMountOptions();
+ // hide defaults
+ foreach ($mountOptions as $key => $value) {
+ if ($value === $defaultMountOptions[$key]) {
+ unset($mountOptions[$key]);
+ }
+ }
+ $keys = array_keys($mountOptions);
+ $values = array_values($mountOptions);
+
+ $optionsStrings = array_map(function ($key, $value) {
+ return $key . ': ' . json_encode($value);
+ }, $keys, $values);
+ $optionsString = implode(', ', $optionsStrings);
+
+ $values = [
+ $config->getId(),
+ $config->getMountPoint(),
+ $config->getBackend()->getText(),
+ $config->getAuthMechanism()->getText(),
+ $configString,
+ $optionsString
+ ];
+
+ if (!$userId) {
+ $applicableUsers = implode(', ', $config->getApplicableUsers());
+ $applicableGroups = implode(', ', $config->getApplicableGroups());
+ if ($applicableUsers === '' && $applicableGroups === '') {
+ $applicableUsers = 'All';
+ }
+ $values[] = $applicableUsers;
+ $values[] = $applicableGroups;
+ }
+
+ return $values;
+ }, $mounts);
+
+ $table = new Table($output);
+ $table->setHeaders($headers);
+ $table->setRows($rows);
+ $table->render();
+ }
+ }
+
+ protected function getStorageService($userId) {
+ if (!empty($userId)) {
+ $user = $this->userManager->get($userId);
+ if (is_null($user)) {
+ throw new NoUserException("user $userId not found");
+ }
+ $this->userSession->setUser($user);
+ return $this->userService;
+ } else {
+ return $this->globalService;
+ }
+ }
+}
diff --git a/apps/files_external/command/option.php b/apps/files_external/command/option.php
new file mode 100644
index 00000000000..292005134cb
--- /dev/null
+++ b/apps/files_external/command/option.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_external\Service\GlobalStoragesService;
+use OCA\Files_external\Service\UserStoragesService;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Helper\TableHelper;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Option extends Config {
+ protected function configure() {
+ $this
+ ->setName('files_external:option')
+ ->setDescription('Manage mount options for a mount')
+ ->addArgument(
+ 'mount_id',
+ InputArgument::REQUIRED,
+ 'The id of the mount to edit'
+ )->addArgument(
+ 'key',
+ InputArgument::REQUIRED,
+ 'key of the mount option to set/get'
+ )->addArgument(
+ 'value',
+ InputArgument::OPTIONAL,
+ 'value to set the mount option to, when no value is provided the existing value will be printed'
+ );
+ }
+
+ /**
+ * @param StorageConfig $mount
+ * @param string $key
+ * @param OutputInterface $output
+ */
+ protected function getOption(StorageConfig $mount, $key, OutputInterface $output) {
+ $value = $mount->getMountOption($key);
+ if (!is_string($value)) { // show bools and objects correctly
+ $value = json_encode($value);
+ }
+ $output->writeln($value);
+ }
+
+ /**
+ * @param StorageConfig $mount
+ * @param string $key
+ * @param string $value
+ * @param OutputInterface $output
+ */
+ protected function setOption(StorageConfig $mount, $key, $value, OutputInterface $output) {
+ $decoded = json_decode($value, true);
+ if (!is_null($decoded)) {
+ $value = $decoded;
+ }
+ $mount->setMountOption($key, $value);
+ $this->globalService->updateStorage($mount);
+ }
+}
diff --git a/apps/files_external/controller/ajaxcontroller.php b/apps/files_external/controller/ajaxcontroller.php
index b278d66c1c0..86c1b657c91 100644
--- a/apps/files_external/controller/ajaxcontroller.php
+++ b/apps/files_external/controller/ajaxcontroller.php
@@ -1,10 +1,10 @@
<?php
/**
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Ross Nicoll <jrn@jrn.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +23,7 @@
namespace OCA\Files_External\Controller;
+use OCA\Files_External\Lib\Auth\Password\GlobalAuth;
use OCP\AppFramework\Controller;
use OCP\IRequest;
use OCP\AppFramework\Http\JSONResponse;
@@ -31,10 +32,13 @@ use OCA\Files_External\Lib\Auth\PublicKey\RSA;
class AjaxController extends Controller {
/** @var RSA */
private $rsaMechanism;
+ /** @var GlobalAuth */
+ private $globalAuth;
- public function __construct($appName, IRequest $request, RSA $rsaMechanism) {
+ public function __construct($appName, IRequest $request, RSA $rsaMechanism, GlobalAuth $globalAuth) {
parent::__construct($appName, $request);
$this->rsaMechanism = $rsaMechanism;
+ $this->globalAuth = $globalAuth;
}
private function generateSshKeys() {
@@ -61,4 +65,8 @@ class AjaxController extends Controller {
));
}
+ public function saveGlobalCredentials($uid, $user, $password) {
+ $this->globalAuth->saveAuth($uid, $user, $password);
+ return true;
+ }
}
diff --git a/apps/files_external/controller/globalstoragescontroller.php b/apps/files_external/controller/globalstoragescontroller.php
index e36d1fb2c03..069e41a96b8 100644
--- a/apps/files_external/controller/globalstoragescontroller.php
+++ b/apps/files_external/controller/globalstoragescontroller.php
@@ -1,9 +1,9 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +24,7 @@ namespace OCA\Files_External\Controller;
use \OCP\IConfig;
+use OCP\ILogger;
use \OCP\IUserSession;
use \OCP\IRequest;
use \OCP\IL10N;
@@ -46,18 +47,21 @@ class GlobalStoragesController extends StoragesController {
* @param IRequest $request request object
* @param IL10N $l10n l10n service
* @param GlobalStoragesService $globalStoragesService storage service
+ * @param ILogger $logger
*/
public function __construct(
$AppName,
IRequest $request,
IL10N $l10n,
- GlobalStoragesService $globalStoragesService
+ GlobalStoragesService $globalStoragesService,
+ ILogger $logger
) {
parent::__construct(
$AppName,
$request,
$l10n,
- $globalStoragesService
+ $globalStoragesService,
+ $logger
);
}
diff --git a/apps/files_external/controller/storagescontroller.php b/apps/files_external/controller/storagescontroller.php
index 048f3588ed7..65ceba21454 100644
--- a/apps/files_external/controller/storagescontroller.php
+++ b/apps/files_external/controller/storagescontroller.php
@@ -1,9 +1,10 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Jesús Macias <jmacias@solidgear.es>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,8 @@ namespace OCA\Files_External\Controller;
use \OCP\IConfig;
+use OCP\ILogger;
+use OCP\IUser;
use \OCP\IUserSession;
use \OCP\IRequest;
use \OCP\IL10N;
@@ -59,22 +62,30 @@ abstract class StoragesController extends Controller {
protected $service;
/**
+ * @var ILogger
+ */
+ protected $logger;
+
+ /**
* Creates a new storages controller.
*
* @param string $AppName application name
* @param IRequest $request request object
* @param IL10N $l10n l10n service
* @param StoragesService $storagesService storage service
+ * @param ILogger $logger
*/
public function __construct(
$AppName,
IRequest $request,
IL10N $l10n,
- StoragesService $storagesService
+ StoragesService $storagesService,
+ ILogger $logger
) {
parent::__construct($AppName, $request);
$this->l10n = $l10n;
$this->service = $storagesService;
+ $this->logger = $logger;
}
/**
@@ -113,6 +124,7 @@ abstract class StoragesController extends Controller {
$priority
);
} catch (\InvalidArgumentException $e) {
+ $this->logger->logException($e);
return new DataResponse(
[
'message' => (string)$this->l10n->t('Invalid backend or authentication mechanism class')
@@ -126,7 +138,7 @@ abstract class StoragesController extends Controller {
* Validate storage config
*
* @param StorageConfig $storage storage config
- *
+ *1
* @return DataResponse|null returns response in case of validation error
*/
protected function validate(StorageConfig $storage) {
@@ -211,6 +223,15 @@ abstract class StoragesController extends Controller {
return null;
}
+ protected function manipulateStorageConfig(StorageConfig $storage) {
+ /** @var AuthMechanism */
+ $authMechanism = $storage->getAuthMechanism();
+ $authMechanism->manipulateStorageConfig($storage);
+ /** @var Backend */
+ $backend = $storage->getBackend();
+ $backend->manipulateStorageConfig($storage);
+ }
+
/**
* Check whether the given storage is available / valid.
*
@@ -221,13 +242,10 @@ abstract class StoragesController extends Controller {
*/
protected function updateStorageStatus(StorageConfig &$storage) {
try {
- /** @var AuthMechanism */
- $authMechanism = $storage->getAuthMechanism();
- $authMechanism->manipulateStorageConfig($storage);
+ $this->manipulateStorageConfig($storage);
+
/** @var Backend */
$backend = $storage->getBackend();
- $backend->manipulateStorageConfig($storage);
-
// update status (can be time-consuming)
$storage->setStatus(
\OC_Mount_Config::getBackendStatus(
@@ -237,25 +255,40 @@ abstract class StoragesController extends Controller {
)
);
} catch (InsufficientDataForMeaningfulAnswerException $e) {
+ $status = $e->getCode() ? $e->getCode() : StorageNotAvailableException::STATUS_INDETERMINATE;
$storage->setStatus(
- \OC_Mount_Config::STATUS_INDETERMINATE,
+ $status,
$this->l10n->t('Insufficient data: %s', [$e->getMessage()])
);
} catch (StorageNotAvailableException $e) {
$storage->setStatus(
- \OC_Mount_Config::STATUS_ERROR,
- $e->getMessage()
+ $e->getCode(),
+ $this->l10n->t('%s', [$e->getMessage()])
);
} catch (\Exception $e) {
// FIXME: convert storage exceptions to StorageNotAvailableException
$storage->setStatus(
- \OC_Mount_Config::STATUS_ERROR,
+ StorageNotAvailableException::STATUS_ERROR,
get_class($e).': '.$e->getMessage()
);
}
}
/**
+ * Get all storage entries
+ *
+ * @return DataResponse
+ */
+ public function index() {
+ $storages = $this->service->getStorages();
+
+ return new DataResponse(
+ $storages,
+ Http::STATUS_OK
+ );
+ }
+
+ /**
* Get an external storage entry.
*
* @param int $id storage id
diff --git a/apps/files_external/controller/userglobalstoragescontroller.php b/apps/files_external/controller/userglobalstoragescontroller.php
new file mode 100644
index 00000000000..c6b51d94047
--- /dev/null
+++ b/apps/files_external/controller/userglobalstoragescontroller.php
@@ -0,0 +1,200 @@
+<?php
+/**
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Controller;
+
+use OCA\Files_External\Lib\Auth\AuthMechanism;
+use OCA\Files_External\Lib\Auth\IUserProvided;
+use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
+use OCP\ILogger;
+use \OCP\IRequest;
+use \OCP\IL10N;
+use \OCP\AppFramework\Http\DataResponse;
+use \OCP\AppFramework\Http;
+use \OCA\Files_external\Service\UserGlobalStoragesService;
+use \OCA\Files_external\NotFoundException;
+use \OCA\Files_external\Lib\StorageConfig;
+use \OCA\Files_External\Lib\Backend\Backend;
+use OCP\IUserSession;
+
+/**
+ * User global storages controller
+ */
+class UserGlobalStoragesController extends StoragesController {
+ /**
+ * @var IUserSession
+ */
+ private $userSession;
+
+ /**
+ * Creates a new user global storages controller.
+ *
+ * @param string $AppName application name
+ * @param IRequest $request request object
+ * @param IL10N $l10n l10n service
+ * @param UserGlobalStoragesService $userGlobalStoragesService storage service
+ * @param IUserSession $userSession
+ */
+ public function __construct(
+ $AppName,
+ IRequest $request,
+ IL10N $l10n,
+ UserGlobalStoragesService $userGlobalStoragesService,
+ IUserSession $userSession,
+ ILogger $logger
+ ) {
+ parent::__construct(
+ $AppName,
+ $request,
+ $l10n,
+ $userGlobalStoragesService,
+ $logger
+ );
+ $this->userSession = $userSession;
+ }
+
+ /**
+ * Get all storage entries
+ *
+ * @return DataResponse
+ *
+ * @NoAdminRequired
+ */
+ public function index() {
+ $storages = $this->service->getUniqueStorages();
+
+ // remove configuration data, this must be kept private
+ foreach ($storages as $storage) {
+ $this->sanitizeStorage($storage);
+ }
+
+ return new DataResponse(
+ $storages,
+ Http::STATUS_OK
+ );
+ }
+
+ protected function manipulateStorageConfig(StorageConfig $storage) {
+ /** @var AuthMechanism */
+ $authMechanism = $storage->getAuthMechanism();
+ $authMechanism->manipulateStorageConfig($storage, $this->userSession->getUser());
+ /** @var Backend */
+ $backend = $storage->getBackend();
+ $backend->manipulateStorageConfig($storage, $this->userSession->getUser());
+ }
+
+ /**
+ * Get an external storage entry.
+ *
+ * @param int $id storage id
+ * @return DataResponse
+ *
+ * @NoAdminRequired
+ */
+ public function show($id) {
+ try {
+ $storage = $this->service->getStorage($id);
+
+ $this->updateStorageStatus($storage);
+ } catch (NotFoundException $e) {
+ return new DataResponse(
+ [
+ 'message' => (string)$this->l10n->t('Storage with id "%i" not found', array($id))
+ ],
+ Http::STATUS_NOT_FOUND
+ );
+ }
+
+ $this->sanitizeStorage($storage);
+
+ return new DataResponse(
+ $storage,
+ Http::STATUS_OK
+ );
+ }
+
+ /**
+ * Update an external storage entry.
+ * Only allows setting user provided backend fields
+ *
+ * @param int $id storage id
+ * @param array $backendOptions backend-specific options
+ *
+ * @return DataResponse
+ *
+ * @NoAdminRequired
+ */
+ public function update(
+ $id,
+ $backendOptions
+ ) {
+ try {
+ $storage = $this->service->getStorage($id);
+ $authMechanism = $storage->getAuthMechanism();
+ if ($authMechanism instanceof IUserProvided) {
+ $authMechanism->saveBackendOptions($this->userSession->getUser(), $id, $backendOptions);
+ $authMechanism->manipulateStorageConfig($storage, $this->userSession->getUser());
+ } else {
+ return new DataResponse(
+ [
+ 'message' => (string)$this->l10n->t('Storage with id "%i" is not user editable', array($id))
+ ],
+ Http::STATUS_FORBIDDEN
+ );
+ }
+ } catch (NotFoundException $e) {
+ return new DataResponse(
+ [
+ 'message' => (string)$this->l10n->t('Storage with id "%i" not found', array($id))
+ ],
+ Http::STATUS_NOT_FOUND
+ );
+ }
+
+ $this->updateStorageStatus($storage);
+ $this->sanitizeStorage($storage);
+
+ return new DataResponse(
+ $storage,
+ Http::STATUS_OK
+ );
+
+ }
+
+ /**
+ * Remove sensitive data from a StorageConfig before returning it to the user
+ *
+ * @param StorageConfig $storage
+ */
+ protected function sanitizeStorage(StorageConfig $storage) {
+ $storage->setBackendOptions([]);
+ $storage->setMountOptions([]);
+
+ if ($storage->getAuthMechanism() instanceof IUserProvided) {
+ try {
+ $storage->getAuthMechanism()->manipulateStorageConfig($storage, $this->userSession->getUser());
+ } catch (InsufficientDataForMeaningfulAnswerException $e) {
+ // not configured yet
+ }
+ }
+ }
+
+}
diff --git a/apps/files_external/controller/userstoragescontroller.php b/apps/files_external/controller/userstoragescontroller.php
index 71d1f7cca46..2a2a0bc63a6 100644
--- a/apps/files_external/controller/userstoragescontroller.php
+++ b/apps/files_external/controller/userstoragescontroller.php
@@ -1,9 +1,9 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,7 +23,10 @@
namespace OCA\Files_External\Controller;
+use OCA\Files_External\Lib\Auth\AuthMechanism;
use \OCP\IConfig;
+use OCP\ILogger;
+use OCP\IUser;
use \OCP\IUserSession;
use \OCP\IRequest;
use \OCP\IL10N;
@@ -41,25 +44,56 @@ use \OCA\Files_External\Lib\Backend\Backend;
*/
class UserStoragesController extends StoragesController {
/**
+ * @var IUserSession
+ */
+ private $userSession;
+
+ /**
* Creates a new user storages controller.
*
* @param string $AppName application name
* @param IRequest $request request object
* @param IL10N $l10n l10n service
* @param UserStoragesService $userStoragesService storage service
+ * @param IUserSession $userSession
+ * @param ILogger $logger
*/
public function __construct(
$AppName,
IRequest $request,
IL10N $l10n,
- UserStoragesService $userStoragesService
+ UserStoragesService $userStoragesService,
+ IUserSession $userSession,
+ ILogger $logger
) {
parent::__construct(
$AppName,
$request,
$l10n,
- $userStoragesService
+ $userStoragesService,
+ $logger
);
+ $this->userSession = $userSession;
+ }
+
+ protected function manipulateStorageConfig(StorageConfig $storage) {
+ /** @var AuthMechanism */
+ $authMechanism = $storage->getAuthMechanism();
+ $authMechanism->manipulateStorageConfig($storage, $this->userSession->getUser());
+ /** @var Backend */
+ $backend = $storage->getBackend();
+ $backend->manipulateStorageConfig($storage, $this->userSession->getUser());
+ }
+
+ /**
+ * Get all storage entries
+ *
+ * @NoAdminRequired
+ *
+ * @return DataResponse
+ */
+ public function index() {
+ return parent::index();
}
/**
diff --git a/apps/files_external/css/external.css b/apps/files_external/css/external.css
new file mode 100644
index 00000000000..bf57ec88053
--- /dev/null
+++ b/apps/files_external/css/external.css
@@ -0,0 +1,8 @@
+#filestable tbody tr.externalDisabledRow {
+ background-color: #CCC;
+}
+
+
+#filestable tbody tr.externalErroredRow {
+ background-color: #F2DEDE;
+}
diff --git a/apps/files_external/css/settings.css b/apps/files_external/css/settings.css
index 35c7a395c58..c96c0cb97b9 100644
--- a/apps/files_external/css/settings.css
+++ b/apps/files_external/css/settings.css
@@ -1,4 +1,10 @@
-td.status > span {
+#externalStorage td.status {
+ /* overwrite conflicting core styles */
+ display: table-cell;
+ vertical-align: middle;
+}
+
+#externalStorage td.status > span {
display: inline-block;
height: 16px;
width: 16px;
diff --git a/apps/files_external/js/app.js b/apps/files_external/js/app.js
index bf853f926dc..d3ce2010ecd 100644
--- a/apps/files_external/js/app.js
+++ b/apps/files_external/js/app.js
@@ -54,7 +54,7 @@ OCA.External.App = {
// folder in the files app instead of opening it directly
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
OCA.Files.App.setActiveView('files', {silent: true});
- OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true);
+ OCA.Files.App.fileList.changeDirectory(OC.joinPaths(context.$file.attr('data-path'), filename), true, true);
});
fileActions.setDefault('dir', 'Open');
return fileActions;
@@ -73,5 +73,42 @@ $(document).ready(function() {
$('#app-content-extstoragemounts').on('hide', function() {
OCA.External.App.removeList();
});
+
+ /* Status Manager */
+ if ($('#filesApp').val()) {
+
+ $('#app-content-files')
+ .add('#app-content-extstoragemounts')
+ .on('changeDirectory', function(e){
+ if (e.dir === '/') {
+ var mount_point = e.previousDir.split('/', 2)[1];
+ // Every time that we return to / root folder from a mountpoint, mount_point status is rechecked
+ OCA.External.StatusManager.getMountPointList(function() {
+ OCA.External.StatusManager.recheckConnectivityForMount([mount_point], true);
+ });
+ }
+ })
+ .on('fileActionsReady', function(e){
+ if ($.isArray(e.$files)) {
+ if (OCA.External.StatusManager.mountStatus === null ||
+ OCA.External.StatusManager.mountPointList === null ||
+ _.size(OCA.External.StatusManager.mountStatus) !== _.size(OCA.External.StatusManager.mountPointList)) {
+ // Will be the very first check when the files view will be loaded
+ OCA.External.StatusManager.launchFullConnectivityCheckOneByOne();
+ } else {
+ // When we change between general files view and external files view
+ OCA.External.StatusManager.getMountPointList(function(){
+ var fileNames = [];
+ $.each(e.$files, function(key, value){
+ fileNames.push(value.attr('data-file'));
+ });
+ // Recheck if launched but work from cache
+ OCA.External.StatusManager.recheckConnectivityForMount(fileNames, false);
+ });
+ }
+ }
+ });
+ }
+ /* End Status Manager */
});
diff --git a/apps/files_external/js/oauth1.js b/apps/files_external/js/oauth1.js
index 47aca36871f..e2ba25ebf8e 100644
--- a/apps/files_external/js/oauth1.js
+++ b/apps/files_external/js/oauth1.js
@@ -1,6 +1,6 @@
$(document).ready(function() {
- OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme) {
+ OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) {
if (authMechanism === 'oauth1::oauth1') {
var config = $tr.find('.configuration');
config.append($(document.createElement('input'))
@@ -10,39 +10,41 @@ $(document).ready(function() {
.attr('name', 'oauth1_grant')
);
- var configured = $tr.find('[data-parameter="configured"]');
- if ($(configured).val() == 'true') {
- $tr.find('.configuration input').attr('disabled', 'disabled');
- $tr.find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
- } else {
- var app_key = $tr.find('.configuration [data-parameter="app_key"]').val();
- var app_secret = $tr.find('.configuration [data-parameter="app_secret"]').val();
- if (app_key != '' && app_secret != '') {
- var pos = window.location.search.indexOf('oauth_token') + 12;
- var token = $tr.find('.configuration [data-parameter="token"]');
- if (pos != -1 && window.location.search.substr(pos, $(token).val().length) == $(token).val()) {
- var token_secret = $tr.find('.configuration [data-parameter="token_secret"]');
- var statusSpan = $tr.find('.status span');
- statusSpan.removeClass();
- statusSpan.addClass('waiting');
- $.post(OC.filePath('files_external', 'ajax', 'oauth1.php'), { step: 2, app_key: app_key, app_secret: app_secret, request_token: $(token).val(), request_token_secret: $(token_secret).val() }, function(result) {
- if (result && result.status == 'success') {
- $(token).val(result.access_token);
- $(token_secret).val(result.access_token_secret);
- $(configured).val('true');
- OCA.External.Settings.mountConfig.saveStorageConfig($tr, function(status) {
- if (status) {
- $tr.find('.configuration input').attr('disabled', 'disabled');
- $tr.find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
- }
- });
- } else {
- OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring OAuth1'));
- }
- });
+ onCompletion.then(function() {
+ var configured = $tr.find('[data-parameter="configured"]');
+ if ($(configured).val() == 'true') {
+ $tr.find('.configuration input').attr('disabled', 'disabled');
+ $tr.find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
+ } else {
+ var app_key = $tr.find('.configuration [data-parameter="app_key"]').val();
+ var app_secret = $tr.find('.configuration [data-parameter="app_secret"]').val();
+ if (app_key != '' && app_secret != '') {
+ var pos = window.location.search.indexOf('oauth_token') + 12;
+ var token = $tr.find('.configuration [data-parameter="token"]');
+ if (pos != -1 && window.location.search.substr(pos, $(token).val().length) == $(token).val()) {
+ var token_secret = $tr.find('.configuration [data-parameter="token_secret"]');
+ var statusSpan = $tr.find('.status span');
+ statusSpan.removeClass();
+ statusSpan.addClass('waiting');
+ $.post(OC.filePath('files_external', 'ajax', 'oauth1.php'), { step: 2, app_key: app_key, app_secret: app_secret, request_token: $(token).val(), request_token_secret: $(token_secret).val() }, function(result) {
+ if (result && result.status == 'success') {
+ $(token).val(result.access_token);
+ $(token_secret).val(result.access_token_secret);
+ $(configured).val('true');
+ OCA.External.Settings.mountConfig.saveStorageConfig($tr, function(status) {
+ if (status) {
+ $tr.find('.configuration input').attr('disabled', 'disabled');
+ $tr.find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
+ }
+ });
+ } else {
+ OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring OAuth1'));
+ }
+ });
+ }
}
}
- }
+ });
}
});
diff --git a/apps/files_external/js/oauth2.js b/apps/files_external/js/oauth2.js
index 84941437420..2556bf45cae 100644
--- a/apps/files_external/js/oauth2.js
+++ b/apps/files_external/js/oauth2.js
@@ -1,6 +1,6 @@
$(document).ready(function() {
- OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme) {
+ OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) {
if (authMechanism === 'oauth2::oauth2') {
var config = $tr.find('.configuration');
config.append($(document.createElement('input'))
@@ -10,54 +10,56 @@ $(document).ready(function() {
.attr('name', 'oauth2_grant')
);
- var configured = $tr.find('[data-parameter="configured"]');
- if ($(configured).val() == 'true') {
- $tr.find('.configuration input').attr('disabled', 'disabled');
- $tr.find('.configuration').append($('<span/>').attr('id', 'access')
- .text(t('files_external', 'Access granted')));
- } else {
- var client_id = $tr.find('.configuration [data-parameter="client_id"]').val();
- var client_secret = $tr.find('.configuration [data-parameter="client_secret"]')
- .val();
- if (client_id != '' && client_secret != '') {
- var params = {};
- window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
- params[key] = value;
- });
- if (params['code'] !== undefined) {
- var token = $tr.find('.configuration [data-parameter="token"]');
- var statusSpan = $tr.find('.status span');
- statusSpan.removeClass();
- statusSpan.addClass('waiting');
- $.post(OC.filePath('files_external', 'ajax', 'oauth2.php'),
- {
- step: 2,
- client_id: client_id,
- client_secret: client_secret,
- redirect: location.protocol + '//' + location.host + location.pathname,
- code: params['code'],
- }, function(result) {
- if (result && result.status == 'success') {
- $(token).val(result.data.token);
- $(configured).val('true');
- OCA.External.Settings.mountConfig.saveStorageConfig($tr, function(status) {
- if (status) {
- $tr.find('.configuration input').attr('disabled', 'disabled');
- $tr.find('.configuration').append($('<span/>')
- .attr('id', 'access')
- .text(t('files_external', 'Access granted')));
- }
- });
- } else {
- OC.dialogs.alert(result.data.message,
- t('files_external', 'Error configuring OAuth2')
- );
+ onCompletion.then(function() {
+ var configured = $tr.find('[data-parameter="configured"]');
+ if ($(configured).val() == 'true') {
+ $tr.find('.configuration input').attr('disabled', 'disabled');
+ $tr.find('.configuration').append($('<span/>').attr('id', 'access')
+ .text(t('files_external', 'Access granted')));
+ } else {
+ var client_id = $tr.find('.configuration [data-parameter="client_id"]').val();
+ var client_secret = $tr.find('.configuration [data-parameter="client_secret"]')
+ .val();
+ if (client_id != '' && client_secret != '') {
+ var params = {};
+ window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
+ params[key] = value;
+ });
+ if (params['code'] !== undefined) {
+ var token = $tr.find('.configuration [data-parameter="token"]');
+ var statusSpan = $tr.find('.status span');
+ statusSpan.removeClass();
+ statusSpan.addClass('waiting');
+ $.post(OC.filePath('files_external', 'ajax', 'oauth2.php'),
+ {
+ step: 2,
+ client_id: client_id,
+ client_secret: client_secret,
+ redirect: location.protocol + '//' + location.host + location.pathname,
+ code: params['code'],
+ }, function(result) {
+ if (result && result.status == 'success') {
+ $(token).val(result.data.token);
+ $(configured).val('true');
+ OCA.External.Settings.mountConfig.saveStorageConfig($tr, function(status) {
+ if (status) {
+ $tr.find('.configuration input').attr('disabled', 'disabled');
+ $tr.find('.configuration').append($('<span/>')
+ .attr('id', 'access')
+ .text(t('files_external', 'Access granted')));
+ }
+ });
+ } else {
+ OC.dialogs.alert(result.data.message,
+ t('files_external', 'Error configuring OAuth2')
+ );
+ }
}
- }
- );
+ );
+ }
}
}
- }
+ });
}
});
diff --git a/apps/files_external/js/public_key.js b/apps/files_external/js/public_key.js
index a8546067452..5f9658381f0 100644
--- a/apps/files_external/js/public_key.js
+++ b/apps/files_external/js/public_key.js
@@ -1,10 +1,16 @@
$(document).ready(function() {
- OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme) {
+ OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) {
if (scheme === 'publickey') {
var config = $tr.find('.configuration');
if ($(config).find('[name="public_key_generate"]').length === 0) {
setupTableRow($tr, config);
+ onCompletion.then(function() {
+ // If there's no private key, build one
+ if (0 === $(config).find('[data-parameter="private_key"]').val().length) {
+ generateKeys($tr);
+ }
+ });
}
}
});
@@ -22,10 +28,6 @@ $(document).ready(function() {
.attr('value', t('files_external', 'Generate keys'))
.attr('name', 'public_key_generate')
);
- // If there's no private key, build one
- if (0 === $(config).find('[data-parameter="private_key"]').val().length) {
- generateKeys(tr);
- }
}
function generateKeys(tr) {
@@ -33,7 +35,7 @@ $(document).ready(function() {
$.post(OC.filePath('files_external', 'ajax', 'public_key.php'), {}, function(result) {
if (result && result.status === 'success') {
- $(config).find('[data-parameter="public_key"]').val(result.data.public_key);
+ $(config).find('[data-parameter="public_key"]').val(result.data.public_key).keyup();
$(config).find('[data-parameter="private_key"]').val(result.data.private_key);
OCA.External.Settings.mountConfig.saveStorageConfig(tr, function() {
// Nothing to do
diff --git a/apps/files_external/js/rollingqueue.js b/apps/files_external/js/rollingqueue.js
new file mode 100644
index 00000000000..58cb0fb22f0
--- /dev/null
+++ b/apps/files_external/js/rollingqueue.js
@@ -0,0 +1,137 @@
+/**
+ * ownCloud
+ *
+ * @author Juan Pablo Villafañez Ramos <jvillafanez@owncloud.com>
+ * @author Jesus Macias Portela <jesus@owncloud.com>
+ * @copyright (C) 2014 ownCloud, Inc.
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(){
+/**
+ * Launch several functions at thee same time. The number of functions
+ * running at the same time is controlled by the queueWindow param
+ *
+ * The function list come in the following format:
+ *
+ * var flist = [
+ * {
+ * funcName: function () {
+ * var d = $.Deferred();
+ * setTimeout(function(){d.resolve();}, 1000);
+ * return d;
+ * }
+ * },
+ * {
+ * funcName: $.get,
+ * funcArgs: [
+ * OC.filePath('files_external', 'ajax', 'connectivityCheck.php'),
+ * {},
+ * function () {
+ * console.log('titoooo');
+ * }
+ * ]
+ * },
+ * {
+ * funcName: $.get,
+ * funcArgs: [
+ * OC.filePath('files_external', 'ajax', 'connectivityCheck.php')
+ * ],
+ * done: function () {
+ * console.log('yuupi');
+ * },
+ * always: function () {
+ * console.log('always done');
+ * }
+ * }
+ *];
+ *
+ * functions MUST implement the deferred interface
+ *
+ * @param functionList list of functions that the queue will run
+ * (check example above for the expected format)
+ * @param queueWindow specify the number of functions that will
+ * be executed at the same time
+ */
+var RollingQueue = function (functionList, queueWindow, callback) {
+ this.queueWindow = queueWindow || 1;
+ this.functionList = functionList;
+ this.callback = callback;
+ this.counter = 0;
+ this.runQueue = function() {
+ this.callbackCalled = false;
+ this.deferredsList = [];
+ if (!$.isArray(this.functionList)) {
+ throw "functionList must be an array";
+ }
+
+ for (i = 0; i < this.queueWindow; i++) {
+ this.launchNext();
+ }
+ };
+
+ this.hasNext = function() {
+ return (this.counter in this.functionList);
+ };
+
+ this.launchNext = function() {
+ var currentCounter = this.counter++;
+ if (currentCounter in this.functionList) {
+ var funcData = this.functionList[currentCounter];
+ if ($.isFunction(funcData.funcName)) {
+ var defObj = funcData.funcName.apply(funcData.funcName, funcData.funcArgs);
+ this.deferredsList.push(defObj);
+ if ($.isFunction(funcData.done)) {
+ defObj.done(funcData.done);
+ }
+
+ if ($.isFunction(funcData.fail)) {
+ defObj.fail(funcData.fail);
+ }
+
+ if ($.isFunction(funcData.always)) {
+ defObj.always(funcData.always);
+ }
+
+ if (this.hasNext()) {
+ var self = this;
+ defObj.always(function(){
+ _.defer($.proxy(function(){
+ self.launchNext();
+ }, self));
+ });
+ } else {
+ if (!this.callbackCalled) {
+ this.callbackCalled = true;
+ if ($.isFunction(this.callback)) {
+ $.when.apply($, this.deferredsList)
+ .always($.proxy(function(){
+ this.callback();
+ }, this)
+ );
+ }
+ }
+ }
+ return defObj;
+ }
+ }
+ return false;
+ };
+};
+
+if (!OCA.External) {
+ OCA.External = {};
+}
+
+if (!OCA.External.StatusManager) {
+ OCA.External.StatusManager = {};
+}
+
+OCA.External.StatusManager.RollingQueue = RollingQueue;
+
+})(); \ No newline at end of file
diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js
index a839f396b9b..0837555f534 100644
--- a/apps/files_external/js/settings.js
+++ b/apps/files_external/js/settings.js
@@ -23,11 +23,14 @@ var MOUNT_OPTIONS_DROPDOWN_TEMPLATE =
' <label for="mountOptionsPreviews">{{t "files_external" "Enable previews"}}</label>' +
' </div>' +
' <div class="optionRow">' +
+ ' <input id="mountOptionsSharing" name="enable_sharing" type="checkbox" value="true" checked="checked"/>' +
+ ' <label for="mountOptionsSharing">{{t "files_external" "Enable sharing"}}</label>' +
+ ' </div>' +
+ ' <div class="optionRow">' +
' <label for="mountOptionsFilesystemCheck">{{t "files_external" "Check for changes"}}</label>' +
' <select id="mountOptionsFilesystemCheck" name="filesystem_check_changes" data-type="int">' +
' <option value="0">{{t "files_external" "Never"}}</option>' +
' <option value="1" selected="selected">{{t "files_external" "Once every direct access"}}</option>' +
- ' <option value="2">{{t "files_external" "Every time the filesystem is used"}}</option>' +
' </select>' +
' </div>' +
'</div>';
@@ -36,10 +39,10 @@ var MOUNT_OPTIONS_DROPDOWN_TEMPLATE =
templates therefore they are duplicated here
t("files_external", "Enable encryption")
t("files_external", "Enable previews")
+ t("files_external", "Enable sharing")
t("files_external", "Check for changes")
t("files_external", "Never")
t("files_external", "Once every direct access")
- t("files_external", "Every time the filesystem is used")
*/
/**
@@ -61,10 +64,24 @@ function highlightBorder($element, highlight) {
return highlight;
}
+function isInputValid($input) {
+ var optional = $input.hasClass('optional');
+ switch ($input.attr('type')) {
+ case 'text':
+ case 'password':
+ if ($input.val() === '' && !optional) {
+ return false;
+ }
+ break;
+ }
+ return true;
+}
+
function highlightInput($input) {
- if ($input.attr('type') === 'text' || $input.attr('type') === 'password') {
- return highlightBorder($input,
- ($input.val() === '' && !$input.hasClass('optional')));
+ switch ($input.attr('type')) {
+ case 'text':
+ case 'password':
+ return highlightBorder($input, !isInputValid($input));
}
}
@@ -194,6 +211,12 @@ StorageConfig.Status = {
ERROR: 1,
INDETERMINATE: 2
};
+StorageConfig.Visibility = {
+ NONE: 0,
+ PERSONAL: 1,
+ ADMIN: 2,
+ DEFAULT: 3
+};
/**
* @memberof OCA.External.Settings
*/
@@ -345,6 +368,9 @@ StorageConfig.prototype = {
if (this.mountPoint === '') {
return false;
}
+ if (!this.backend) {
+ return false;
+ }
if (this.errors) {
return false;
}
@@ -421,6 +447,21 @@ UserStorageConfig.prototype = _.extend({}, StorageConfig.prototype,
});
/**
+ * @class OCA.External.Settings.UserGlobalStorageConfig
+ * @augments OCA.External.Settings.StorageConfig
+ *
+ * @classdesc User external storage config
+ */
+var UserGlobalStorageConfig = function (id) {
+ this.id = id;
+};
+UserGlobalStorageConfig.prototype = _.extend({}, StorageConfig.prototype,
+ /** @lends OCA.External.Settings.UserStorageConfig.prototype */ {
+
+ _url: 'apps/files_external/userglobalstorages'
+});
+
+/**
* @class OCA.External.Settings.MountOptionsDropdown
*
* @classdesc Dropdown for mount options
@@ -460,7 +501,6 @@ MountOptionsDropdown.prototype = {
var $el = $(template());
this.$el = $el;
- $el.addClass('hidden');
this.setOptions(mountOptions, enabledOptions);
@@ -547,6 +587,19 @@ MountOptionsDropdown.prototype = {
var MountConfigListView = function($el, options) {
this.initialize($el, options);
};
+
+MountConfigListView.ParameterFlags = {
+ OPTIONAL: 1,
+ USER_PROVIDED: 2
+};
+
+MountConfigListView.ParameterTypes = {
+ TEXT: 0,
+ BOOLEAN: 1,
+ PASSWORD: 2,
+ HIDDEN: 3
+};
+
/**
* @memberOf OCA.External.Settings
*/
@@ -623,36 +676,7 @@ MountConfigListView.prototype = _.extend({
this._allBackends = this.$el.find('.selectBackend').data('configurations');
this._allAuthMechanisms = this.$el.find('#addMountPoint .authentication').data('mechanisms');
- //initialize hidden input field with list of users and groups
- this.$el.find('tr:not(#addMountPoint)').each(function(i,tr) {
- var $tr = $(tr);
- var $applicable = $tr.find('.applicable');
- if ($applicable.length > 0) {
- var groups = $applicable.data('applicable-groups');
- var groupsId = [];
- $.each(groups, function () {
- groupsId.push(this + '(group)');
- });
- var users = $applicable.data('applicable-users');
- if (users.indexOf('all') > -1 || users === '') {
- $tr.find('.applicableUsers').val('');
- } else {
- $tr.find('.applicableUsers').val(groupsId.concat(users).join(','));
- }
- }
- });
-
- addSelect2(this.$el.find('tr:not(#addMountPoint) .applicableUsers'), this._userListLimit);
- this.$el.tooltip({
- selector: '.status span',
- container: 'body'
- });
-
this._initEvents();
-
- this.$el.find('tbody tr:not(#addMountPoint)').each(function(i, tr) {
- self.recheckStorageConfig($(tr));
- });
},
/**
@@ -661,7 +685,7 @@ MountConfigListView.prototype = _.extend({
*/
whenSelectBackend: function(callback) {
this.$el.find('tbody tr:not(#addMountPoint)').each(function(i, tr) {
- var backend = $(tr).find('.backend').data('class');
+ var backend = $(tr).find('.backend').data('identifier');
callback($(tr), backend);
});
this.on('selectBackend', callback);
@@ -725,103 +749,263 @@ MountConfigListView.prototype = _.extend({
_onSelectBackend: function(event) {
var $target = $(event.target);
- var $el = this.$el;
var $tr = $target.closest('tr');
- $el.find('tbody').append($tr.clone());
- $el.find('tbody tr').last().find('.mountPoint input').val('');
- $tr.data('constructing', true);
- var selected = $target.find('option:selected').text();
- var backend = $target.val();
- $tr.find('.backend').text(selected);
- if ($tr.find('.mountPoint input').val() === '') {
- $tr.find('.mountPoint input').val(this._suggestMountPoint(selected));
+
+ var storageConfig = new this._storageConfigClass();
+ storageConfig.mountPoint = $tr.find('.mountPoint input').val();
+ storageConfig.backend = $target.val();
+ $tr.find('.mountPoint input').val('');
+
+ var onCompletion = jQuery.Deferred();
+ $tr = this.newStorage(storageConfig, onCompletion);
+ onCompletion.resolve();
+
+ $tr.find('td.configuration').children().not('[type=hidden]').first().focus();
+ this.saveStorageConfig($tr);
+ },
+
+ _onSelectAuthMechanism: function(event) {
+ var $target = $(event.target);
+ var $tr = $target.closest('tr');
+ var authMechanism = $target.val();
+
+ var onCompletion = jQuery.Deferred();
+ this.configureAuthMechanism($tr, authMechanism, onCompletion);
+ onCompletion.resolve();
+
+ this.saveStorageConfig($tr);
+ },
+
+ /**
+ * Configure the storage config with a new authentication mechanism
+ *
+ * @param {jQuery} $tr config row
+ * @param {string} authMechanism
+ * @param {jQuery.Deferred} onCompletion
+ */
+ configureAuthMechanism: function($tr, authMechanism, onCompletion) {
+ var authMechanismConfiguration = this._allAuthMechanisms[authMechanism];
+ var $td = $tr.find('td.configuration');
+ $td.find('.auth-param').remove();
+
+ $.each(authMechanismConfiguration['configuration'], _.partial(
+ this.writeParameterInput, $td, _, _, ['auth-param']
+ ).bind(this));
+
+ this.trigger('selectAuthMechanism',
+ $tr, authMechanism, authMechanismConfiguration['scheme'], onCompletion
+ );
+ },
+
+ /**
+ * Create a config row for a new storage
+ *
+ * @param {StorageConfig} storageConfig storage config to pull values from
+ * @param {jQuery.Deferred} onCompletion
+ * @return {jQuery} created row
+ */
+ newStorage: function(storageConfig, onCompletion) {
+ var mountPoint = storageConfig.mountPoint;
+ var backend = this._allBackends[storageConfig.backend];
+
+ // FIXME: Replace with a proper Handlebar template
+ var $tr = this.$el.find('tr#addMountPoint');
+ this.$el.find('tbody').append($tr.clone());
+
+ $tr.data('storageConfig', storageConfig);
+ $tr.find('td').last().attr('class', 'remove');
+ $tr.find('td.mountOptionsToggle').removeClass('hidden');
+ $tr.find('td').last().removeAttr('style');
+ $tr.removeAttr('id');
+ $tr.find('select#selectBackend');
+ addSelect2($tr.find('.applicableUsers'), this._userListLimit);
+
+ if (storageConfig.id) {
+ $tr.data('id', storageConfig.id);
}
- $tr.addClass(backend);
- $tr.find('.backend').data('class', backend);
- var backendConfiguration = this._allBackends[backend];
+
+ $tr.find('.backend').text(backend.name);
+ if (mountPoint === '') {
+ mountPoint = this._suggestMountPoint(backend.name);
+ }
+ $tr.find('.mountPoint input').val(mountPoint);
+ $tr.addClass(backend.identifier);
+ $tr.find('.backend').data('identifier', backend.identifier);
var selectAuthMechanism = $('<select class="selectAuthMechanism"></select>');
- $.each(this._allAuthMechanisms, function(authClass, authMechanism) {
- if (backendConfiguration['authSchemes'][authMechanism['scheme']]) {
+ var neededVisibility = (this._isPersonal) ? StorageConfig.Visibility.PERSONAL : StorageConfig.Visibility.ADMIN;
+ $.each(this._allAuthMechanisms, function(authIdentifier, authMechanism) {
+ if (backend.authSchemes[authMechanism.scheme] && (authMechanism.visibility & neededVisibility)) {
selectAuthMechanism.append(
- $('<option value="'+authClass+'" data-scheme="'+authMechanism['scheme']+'">'+authMechanism['name']+'</option>')
+ $('<option value="'+authMechanism.identifier+'" data-scheme="'+authMechanism.scheme+'">'+authMechanism.name+'</option>')
);
}
});
+ if (storageConfig.authMechanism) {
+ selectAuthMechanism.val(storageConfig.authMechanism);
+ } else {
+ storageConfig.authMechanism = selectAuthMechanism.val();
+ }
$tr.find('td.authentication').append(selectAuthMechanism);
var $td = $tr.find('td.configuration');
- $.each(backendConfiguration['configuration'], _.partial(this.writeParameterInput, $td));
-
- this.trigger('selectBackend', $tr, backend);
+ $.each(backend.configuration, _.partial(this.writeParameterInput, $td).bind(this));
+
+ this.trigger('selectBackend', $tr, backend.identifier, onCompletion);
+ this.configureAuthMechanism($tr, storageConfig.authMechanism, onCompletion);
+
+ if (storageConfig.backendOptions) {
+ $td.children().each(function() {
+ var input = $(this);
+ var val = storageConfig.backendOptions[input.data('parameter')];
+ if (val !== undefined) {
+ input.val(storageConfig.backendOptions[input.data('parameter')]);
+ highlightInput(input);
+ }
+ });
+ }
- selectAuthMechanism.trigger('change'); // generate configuration parameters for auth mechanism
+ var applicable = [];
+ if (storageConfig.applicableUsers) {
+ applicable = applicable.concat(storageConfig.applicableUsers);
+ }
+ if (storageConfig.applicableGroups) {
+ applicable = applicable.concat(
+ _.map(storageConfig.applicableGroups, function(group) {
+ return group+'(group)';
+ })
+ );
+ }
+ $tr.find('.applicableUsers').val(applicable).trigger('change');
- var priorityEl = $('<input type="hidden" class="priority" value="' + backendConfiguration['priority'] + '" />');
+ var priorityEl = $('<input type="hidden" class="priority" value="' + backend.priority + '" />');
$tr.append(priorityEl);
- $td.children().not('[type=hidden]').first().focus();
- // FIXME default backend mount options
- $tr.find('input.mountOptions').val(JSON.stringify({
- 'encrypt': true,
- 'previews': true,
- 'filesystem_check_changes': 1
- }));
-
- $tr.find('td').last().attr('class', 'remove');
- $tr.find('td.mountOptionsToggle').removeClass('hidden');
- $tr.find('td').last().removeAttr('style');
- $tr.removeAttr('id');
- $target.remove();
- addSelect2($tr.find('.applicableUsers'), this._userListLimit);
+ if (storageConfig.mountOptions) {
+ $tr.find('input.mountOptions').val(JSON.stringify(storageConfig.mountOptions));
+ } else {
+ // FIXME default backend mount options
+ $tr.find('input.mountOptions').val(JSON.stringify({
+ 'encrypt': true,
+ 'previews': true,
+ 'enable_sharing': true,
+ 'filesystem_check_changes': 1
+ }));
+ }
- $tr.removeData('constructing');
- this.saveStorageConfig($tr);
+ return $tr;
},
- _onSelectAuthMechanism: function(event) {
- var $target = $(event.target);
- var $tr = $target.closest('tr');
+ /**
+ * Load storages into config rows
+ */
+ loadStorages: function() {
+ var self = this;
- var authMechanism = $target.val();
- var authMechanismConfiguration = this._allAuthMechanisms[authMechanism];
- var $td = $tr.find('td.configuration');
- $td.find('.auth-param').remove();
+ if (this._isPersonal) {
+ // load userglobal storages
+ $.ajax({
+ type: 'GET',
+ url: OC.generateUrl('apps/files_external/userglobalstorages'),
+ contentType: 'application/json',
+ success: function(result) {
+ var onCompletion = jQuery.Deferred();
+ $.each(result, function(i, storageParams) {
+ var storageConfig;
+ var isUserGlobal = storageParams.type === 'system' && self._isPersonal;
+ storageParams.mountPoint = storageParams.mountPoint.substr(1); // trim leading slash
+ if (isUserGlobal) {
+ storageConfig = new UserGlobalStorageConfig();
+ } else {
+ storageConfig = new self._storageConfigClass();
+ }
+ _.extend(storageConfig, storageParams);
+ var $tr = self.newStorage(storageConfig, onCompletion);
- $.each(authMechanismConfiguration['configuration'], _.partial(
- this.writeParameterInput, $td, _, _, ['auth-param']
- ));
+ // userglobal storages must be at the top of the list
+ $tr.detach();
+ self.$el.prepend($tr);
- this.trigger('selectAuthMechanism',
- $tr, authMechanism, authMechanismConfiguration['scheme']
- );
+ var $authentication = $tr.find('.authentication');
+ $authentication.text($authentication.find('select option:selected').text());
- if ($tr.data('constructing') !== true) {
- // row is ready, trigger recheck
- this.saveStorageConfig($tr);
+ // disable any other inputs
+ $tr.find('.mountOptionsToggle, .remove').empty();
+ $tr.find('input:not(.user_provided), select:not(.user_provided)').attr('disabled', 'disabled');
+
+ if (isUserGlobal) {
+ $tr.find('.configuration').find(':not(.user_provided)').remove();
+ } else {
+ // userglobal storages do not expose configuration data
+ $tr.find('.configuration').text(t('files_external', 'Admin defined'));
+ }
+ });
+ onCompletion.resolve();
+ }
+ });
}
+
+ var url = this._storageConfigClass.prototype._url;
+
+ $.ajax({
+ type: 'GET',
+ url: OC.generateUrl(url),
+ contentType: 'application/json',
+ success: function(result) {
+ var onCompletion = jQuery.Deferred();
+ $.each(result, function(i, storageParams) {
+ storageParams.mountPoint = storageParams.mountPoint.substr(1); // trim leading slash
+ var storageConfig = new self._storageConfigClass();
+ _.extend(storageConfig, storageParams);
+ var $tr = self.newStorage(storageConfig, onCompletion);
+ self.recheckStorageConfig($tr);
+ });
+ onCompletion.resolve();
+ }
+ });
},
+ /**
+ * @param {jQuery} $td
+ * @param {string} parameter
+ * @param {string} placeholder
+ * @param {Array} classes
+ * @return {jQuery} newly created input
+ */
writeParameterInput: function($td, parameter, placeholder, classes) {
+ var hasFlag = function(flag) {
+ return (placeholder.flags & flag) === flag;
+ };
classes = $.isArray(classes) ? classes : [];
classes.push('added');
- if (placeholder.indexOf('&') === 0) {
+ if (hasFlag(MountConfigListView.ParameterFlags.OPTIONAL)) {
classes.push('optional');
- placeholder = placeholder.substring(1);
}
+
+ if (hasFlag(MountConfigListView.ParameterFlags.USER_PROVIDED)) {
+ if (this._isPersonal) {
+ classes.push('user_provided');
+ } else {
+ return;
+ }
+ }
+
var newElement;
- if (placeholder.indexOf('*') === 0) {
- newElement = $('<input type="password" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+placeholder.substring(1)+'" />');
- } else if (placeholder.indexOf('!') === 0) {
+
+ var trimmedPlaceholder = placeholder.value;
+ if (placeholder.type === MountConfigListView.ParameterTypes.PASSWORD) {
+ newElement = $('<input type="password" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+ trimmedPlaceholder+'" />');
+ } else if (placeholder.type === MountConfigListView.ParameterTypes.BOOLEAN) {
var checkboxId = _.uniqueId('checkbox_');
- newElement = $('<input type="checkbox" id="'+checkboxId+'" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" /><label for="'+checkboxId+'">'+placeholder.substring(1)+'</label>');
- } else if (placeholder.indexOf('#') === 0) {
+ newElement = $('<input type="checkbox" id="'+checkboxId+'" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" /><label for="'+checkboxId+'">'+ trimmedPlaceholder+'</label>');
+ } else if (placeholder.type === MountConfigListView.ParameterTypes.HIDDEN) {
newElement = $('<input type="hidden" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" />');
} else {
- newElement = $('<input type="text" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+placeholder+'" />');
+ newElement = $('<input type="text" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+ trimmedPlaceholder+'" />');
}
highlightInput(newElement);
$td.append(newElement);
+ return newElement;
},
/**
@@ -831,14 +1015,19 @@ MountConfigListView.prototype = _.extend({
* @return {OCA.External.StorageConfig} storage model instance
*/
getStorageConfig: function($tr) {
- var storageId = parseInt($tr.attr('data-id'), 10);
+ var storageId = $tr.data('id');
if (!storageId) {
// new entry
storageId = null;
}
- var storage = new this._storageConfigClass(storageId);
+
+ var storage = $tr.data('storageConfig');
+ if (!storage) {
+ storage = new this._storageConfigClass(storageId);
+ }
+ storage.errors = null;
storage.mountPoint = $tr.find('.mountPoint input').val();
- storage.backend = $tr.find('.backend').data('class');
+ storage.backend = $tr.find('.backend').data('identifier');
storage.authMechanism = $tr.find('.selectAuthMechanism').val();
var classOptions = {};
@@ -850,7 +1039,7 @@ MountConfigListView.prototype = _.extend({
if ($input.attr('type') === 'button') {
return;
}
- if ($input.val() === '' && !$input.hasClass('optional')) {
+ if (!isInputValid($input) && !$input.hasClass('optional')) {
missingOptions.push(parameter);
return;
}
@@ -878,7 +1067,7 @@ MountConfigListView.prototype = _.extend({
var users = [];
var multiselect = getSelection($tr);
$.each(multiselect, function(index, value) {
- var pos = value.indexOf('(group)');
+ var pos = (value.indexOf)?value.indexOf('(group)'): -1;
if (pos !== -1) {
groups.push(value.substr(0, pos));
} else {
@@ -941,7 +1130,7 @@ MountConfigListView.prototype = _.extend({
saveStorageConfig:function($tr, callback, concurrentTimer) {
var self = this;
var storage = this.getStorageConfig($tr);
- if (!storage.validate()) {
+ if (!storage || !storage.validate()) {
return false;
}
@@ -951,8 +1140,8 @@ MountConfigListView.prototype = _.extend({
if (concurrentTimer === undefined
|| $tr.data('save-timer') === concurrentTimer
) {
- self.updateStatus($tr, result.status, result.statusMessage);
- $tr.attr('data-id', result.id);
+ self.updateStatus($tr, result.status);
+ $tr.data('id', result.id);
if (_.isFunction(callback)) {
callback(storage);
@@ -1054,12 +1243,12 @@ MountConfigListView.prototype = _.extend({
}
return defaultMountPoint + append;
},
-
+
/**
* Toggles the mount options dropdown
*
* @param {Object} $tr configuration row
- */
+ */
_showMountOptionsDropdown: function($tr) {
if (this._preventNextDropdown) {
// prevented because the click was on the toggle
@@ -1070,7 +1259,7 @@ MountConfigListView.prototype = _.extend({
var storage = this.getStorageConfig($tr);
var $toggle = $tr.find('.mountOptionsToggle');
var dropDown = new MountOptionsDropdown();
- var enabledOptions = ['previews', 'filesystem_check_changes'];
+ var enabledOptions = ['previews', 'filesystem_check_changes', 'enable_sharing'];
if (this._encryptionEnabled) {
enabledOptions.push('encrypt');
}
@@ -1106,13 +1295,7 @@ $(document).ready(function() {
var mountConfigListView = new MountConfigListView($('#externalStorage'), {
encryptionEnabled: encryptionEnabled
});
-
- $('#sslCertificate').on('click', 'td.remove>img', function() {
- var $tr = $(this).closest('tr');
- $.post(OC.filePath('files_external', 'ajax', 'removeRootCertificate.php'), {cert: $tr.attr('id')});
- $tr.remove();
- return true;
- });
+ mountConfigListView.loadStorages();
// TODO: move this into its own View class
var $allowUserMounting = $('#allowUserMounting');
@@ -1155,6 +1338,33 @@ $(document).ready(function() {
}
});
+ $('#global_credentials').on('submit', function() {
+ var $form = $(this);
+ var uid = $form.find('[name=uid]').val();
+ var user = $form.find('[name=username]').val();
+ var password = $form.find('[name=password]').val();
+ var $submit = $form.find('[type=submit]');
+ $submit.val(t('files_external', 'Saving...'));
+ $.ajax({
+ type: 'POST',
+ contentType: 'application/json',
+ data: JSON.stringify({
+ uid: uid,
+ user: user,
+ password: password
+ }),
+ url: OC.generateUrl('apps/files_external/globalcredentials'),
+ dataType: 'json',
+ success: function() {
+ $submit.val(t('files_external', 'Saved'));
+ setTimeout(function(){
+ $submit.val(t('files_external', 'Save'));
+ }, 2500);
+ }
+ });
+ return false;
+ });
+
// global instance
OCA.External.Settings.mountConfig = mountConfigListView;
diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js
new file mode 100644
index 00000000000..33d2ea104be
--- /dev/null
+++ b/apps/files_external/js/statusmanager.js
@@ -0,0 +1,610 @@
+/**
+ * ownCloud
+ *
+ * @author Juan Pablo Villafañez Ramos <jvillafanez@owncloud.com>
+ * @author Jesus Macias Portela <jesus@owncloud.com>
+ * @copyright (C) 2014 ownCloud, Inc.
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+if (!OCA.External) {
+ OCA.External = {};
+}
+
+if (!OCA.External.StatusManager) {
+ OCA.External.StatusManager = {};
+}
+
+OCA.External.StatusManager = {
+
+ mountStatus: null,
+ mountPointList: null,
+
+ /**
+ * Function
+ * @param {callback} afterCallback
+ */
+
+ getMountStatus: function (afterCallback) {
+ var self = this;
+ if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) {
+ return;
+ }
+
+ if (self.mountStatus) {
+ afterCallback(self.mountStatus);
+ }
+ },
+
+ /**
+ * Function Check mount point status from cache
+ * @param {string} mount_point
+ */
+
+ getMountPointListElement: function (mount_point) {
+ var element;
+ $.each(this.mountPointList, function (key, value) {
+ if (value.mount_point === mount_point) {
+ element = value;
+ return false;
+ }
+ });
+ return element;
+ },
+
+ /**
+ * Function Check mount point status from cache
+ * @param {string} mount_point
+ * @param {string} mount_point
+ */
+
+ getMountStatusForMount: function (mountData, afterCallback) {
+ var self = this;
+ if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) {
+ return $.Deferred().resolve();
+ }
+
+ var defObj;
+ if (self.mountStatus[mountData.mount_point]) {
+ defObj = $.Deferred();
+ afterCallback(mountData, self.mountStatus[mountData.mount_point]);
+ defObj.resolve(); // not really useful, but it'll keep the same behaviour
+ } else {
+ defObj = $.ajax({
+ type: 'GET',
+ url: OC.webroot + '/index.php/apps/files_external/' + ((mountData.type === 'personal') ? 'userstorages' : 'userglobalstorages') + '/' + mountData.id,
+ success: function (response) {
+ if (response && response.status === 0) {
+ self.mountStatus[mountData.mount_point] = response;
+ } else {
+ var statusCode = response.status ? response.status : 1;
+ var statusMessage = response.statusMessage ? response.statusMessage : t('files_external', 'Empty response from the server')
+ // failure response with error message
+ self.mountStatus[mountData.mount_point] = {
+ type: mountData.type,
+ status: statusCode,
+ id: mountData.id,
+ error: statusMessage,
+ userProvided: response.userProvided
+ };
+ }
+ afterCallback(mountData, self.mountStatus[mountData.mount_point]);
+ },
+ error: function (jqxhr, state, error) {
+ var message;
+ if (mountData.location === 3) {
+ // In this case the error is because mount point use Login credentials and don't exist in the session
+ message = t('files_external', 'Couldn\'t access. Please logout and login to activate this mount point');
+ } else {
+ message = t('files_external', 'Couldn\'t get the information from the ownCloud server: {code} {type}', {
+ code: jqxhr.status,
+ type: error
+ });
+ }
+ self.mountStatus[mountData.mount_point] = {
+ type: mountData.type,
+ status: 1,
+ location: mountData.location,
+ error: message
+ };
+ afterCallback(mountData, self.mountStatus[mountData.mount_point]);
+ }
+ });
+ }
+ return defObj;
+ },
+
+ /**
+ * Function to get external mount point list from the files_external API
+ * @param {function} afterCallback function to be executed
+ */
+
+ getMountPointList: function (afterCallback) {
+ var self = this;
+ if (typeof afterCallback !== 'function' || self.isGetMountPointListRunning) {
+ return;
+ }
+
+ if (self.mountPointList) {
+ afterCallback(self.mountPointList);
+ } else {
+ self.isGetMountPointListRunning = true;
+ $.ajax({
+ type: 'GET',
+ url: OC.linkToOCS('apps/files_external/api/v1') + 'mounts?format=json',
+ success: function (response) {
+ self.mountPointList = [];
+ _.each(response.ocs.data, function (mount) {
+ var element = {};
+ element.mount_point = mount.name;
+ element.type = mount.scope;
+ element.location = "";
+ element.id = mount.id;
+ element.backendText = mount.backend;
+ element.backend = mount.class;
+
+ self.mountPointList.push(element);
+ });
+ afterCallback(self.mountPointList);
+ },
+ error: function (jqxhr, state, error) {
+ self.mountPointList = [];
+ OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the list of external mount points: {type}', {type: error}));
+ },
+ complete: function () {
+ self.isGetMountPointListRunning = false;
+ }
+ });
+ }
+ },
+
+ /**
+ * Function to manage action when a mountpoint status = 1 (Errored). Show a dialog to be redirected to settings page.
+ * @param {string} name MountPoint Name
+ */
+
+ manageMountPointError: function (name) {
+ this.getMountStatus($.proxy(function (allMountStatus) {
+ if (allMountStatus.hasOwnProperty(name) && allMountStatus[name].status > 0 && allMountStatus[name].status < 7) {
+ var mountData = allMountStatus[name];
+ if (mountData.type === "system") {
+ if (mountData.userProvided) {
+ // personal mount whit credentials problems
+ this.showCredentialsDialog(name, mountData);
+ } else {
+ OC.dialogs.confirm(t('files_external', 'There was an error with message: ') + mountData.error + '. Do you want to review mount point config in admin settings page?', t('files_external', 'External mount error'), function (e) {
+ if (e === true) {
+ OC.redirect(OC.generateUrl('/settings/admin#files_external'));
+ }
+ });
+ }
+ } else {
+ OC.dialogs.confirm(t('files_external', 'There was an error with message: ') + mountData.error + '. Do you want to review mount point config in personal settings page?', t('files_external', 'External mount error'), function (e) {
+ if (e === true) {
+ OC.redirect(OC.generateUrl('/settings/personal#' + t('files_external', 'external-storage')));
+ }
+ });
+ }
+ }
+ }, this));
+ },
+
+ /**
+ * Function to process a mount point in relation with their status, Called from Async Queue.
+ * @param {object} mountData
+ * @param {object} mountStatus
+ */
+
+ processMountStatusIndividual: function (mountData, mountStatus) {
+
+ var mountPoint = mountData.mount_point;
+ if (mountStatus.status > 0) {
+ var trElement = FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(mountPoint));
+
+ var route = OCA.External.StatusManager.Utils.getIconRoute(trElement) + '-error';
+
+ if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) {
+ OCA.External.StatusManager.Utils.showIconError(mountPoint, $.proxy(OCA.External.StatusManager.manageMountPointError, OCA.External.StatusManager), route);
+ }
+ return false;
+ } else {
+ if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) {
+ OCA.External.StatusManager.Utils.restoreFolder(mountPoint);
+ OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true);
+ }
+ return true;
+ }
+ },
+
+ /**
+ * Function to process a mount point in relation with their status
+ * @param {object} mountData
+ * @param {object} mountStatus
+ */
+
+ processMountList: function (mountList) {
+ var elementList = null;
+ $.each(mountList, function (name, value) {
+ var trElement = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(value.mount_point) + '\"]'); //FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(value.mount_point));
+ trElement.attr('data-external-backend', value.backend);
+ if (elementList) {
+ elementList = elementList.add(trElement);
+ } else {
+ elementList = trElement;
+ }
+ });
+
+ if (elementList instanceof $) {
+ if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) {
+ // Put their custom icon
+ OCA.External.StatusManager.Utils.changeFolderIcon(elementList);
+ // Save default view
+ OCA.External.StatusManager.Utils.storeDefaultFolderIconAndBgcolor(elementList);
+ // Disable row until check status
+ elementList.addClass('externalDisabledRow');
+ OCA.External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false);
+ }
+ }
+ },
+
+ /**
+ * Function to process the whole mount point list in relation with their status (Async queue)
+ */
+
+ launchFullConnectivityCheckOneByOne: function () {
+ var self = this;
+ this.getMountPointList(function (list) {
+ // check if we have a list first
+ if (list === undefined && !self.emptyWarningShown) {
+ self.emptyWarningShown = true;
+ OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the list of Windows network drive mount points: empty response from the server'));
+ return;
+ }
+ if (list && list.length > 0) {
+ self.processMountList(list);
+
+ if (!self.mountStatus) {
+ self.mountStatus = {};
+ }
+
+ var ajaxQueue = [];
+ $.each(list, function (key, value) {
+ var queueElement = {
+ funcName: $.proxy(self.getMountStatusForMount, self),
+ funcArgs: [value,
+ $.proxy(self.processMountStatusIndividual, self)]
+ };
+ ajaxQueue.push(queueElement);
+ });
+
+ var rolQueue = new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4, function () {
+ if (!self.notificationHasShown) {
+ var showNotification = false;
+ $.each(self.mountStatus, function (key, value) {
+ if (value.status === 1) {
+ self.notificationHasShown = true;
+ showNotification = true;
+ }
+ });
+ if (showNotification) {
+ OC.Notification.showTemporary(t('files_external', 'Some of the configured external mount points are not connected. Please click on the red row(s) for more information'));
+ }
+ }
+ });
+ rolQueue.runQueue();
+ }
+ });
+ },
+
+
+ /**
+ * Function to process a mount point list in relation with their status (Async queue)
+ * @param {object} mountListData
+ * @param {boolean} recheck delete cached info and force api call to check mount point status
+ */
+
+ launchPartialConnectivityCheck: function (mountListData, recheck) {
+ if (mountListData.length === 0) {
+ return;
+ }
+
+ var self = this;
+ var ajaxQueue = [];
+ $.each(mountListData, function (key, value) {
+ if (recheck && value.mount_point in self.mountStatus) {
+ delete self.mountStatus[value.mount_point];
+ }
+ var queueElement = {
+ funcName: $.proxy(self.getMountStatusForMount, self),
+ funcArgs: [value,
+ $.proxy(self.processMountStatusIndividual, self)]
+ };
+ ajaxQueue.push(queueElement);
+ });
+ new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4).runQueue();
+ },
+
+
+ /**
+ * Function to relaunch some mount point status check
+ * @param {string} mountListNames
+ * @param {boolean} recheck delete cached info and force api call to check mount point status
+ */
+
+ recheckConnectivityForMount: function (mountListNames, recheck) {
+ if (mountListNames.length === 0) {
+ return;
+ }
+
+ var self = this;
+ var mountListData = [];
+
+ if (!self.mountStatus) {
+ self.mountStatus = {};
+ }
+
+ $.each(mountListNames, function (key, value) {
+ var mountData = self.getMountPointListElement(value);
+ if (mountData) {
+ mountListData.push(mountData);
+ }
+ });
+
+ // for all mounts in the list, delete the cached status values
+ if (recheck) {
+ $.each(mountListData, function (key, value) {
+ if (value.mount_point in self.mountStatus) {
+ delete self.mountStatus[value.mount_point];
+ }
+ });
+ }
+
+ self.processMountList(mountListData);
+ self.launchPartialConnectivityCheck(mountListData, recheck);
+ },
+
+ credentialsDialogTemplate:
+ '<div id="files_external_div_form"><div>' +
+ '<div>{{credentials_text}}</div>' +
+ '<form>' +
+ '<input type="text" name="username" placeholder="{{placeholder_username}}"/>' +
+ '<input type="password" name="password" placeholder="{{placeholder_password}}"/>' +
+ '</form>' +
+ '</div></div>',
+
+ /**
+ * Function to display custom dialog to enter credentials
+ * @param mountPoint
+ * @param mountData
+ */
+ showCredentialsDialog: function (mountPoint, mountData) {
+ var template = Handlebars.compile(OCA.External.StatusManager.credentialsDialogTemplate);
+ var dialog = $(template({
+ credentials_text: t('files_external', 'Please enter the credentials for the {mount} mount', {
+ 'mount': mountPoint
+ }),
+ placeholder_username: t('files_external', 'Username'),
+ placeholder_password: t('files_external', 'Password')
+ }));
+
+ $('body').append(dialog);
+
+ var apply = function () {
+ var username = dialog.find('[name=username]').val();
+ var password = dialog.find('[name=password]').val();
+ var endpoint = OC.generateUrl('apps/files_external/userglobalstorages/{id}', {
+ id: mountData.id
+ });
+ $('.oc-dialog-close').hide();
+ $.ajax({
+ type: 'PUT',
+ url: endpoint,
+ data: {
+ backendOptions: {
+ user: username,
+ password: password
+ }
+ },
+ success: function (data) {
+ OC.Notification.showTemporary(t('files_external', 'Credentials saved'));
+ dialog.ocdialog('close');
+ /* Trigger status check again */
+ OCA.External.StatusManager.recheckConnectivityForMount([OC.basename(data.mountPoint)], true);
+ },
+ error: function () {
+ $('.oc-dialog-close').show();
+ OC.Notification.showTemporary(t('files_external', 'Credentials saving failed'));
+ }
+ });
+ return false;
+ };
+
+ var ocdialogParams = {
+ modal: true,
+ title: t('files_external', 'Credentials required'),
+ buttons: [{
+ text: t('files_external', 'Save'),
+ click: apply,
+ closeOnEscape: true
+ }],
+ closeOnExcape: true
+ };
+
+ dialog.ocdialog(ocdialogParams)
+ .bind('ocdialogclose', function () {
+ dialog.ocdialog('destroy').remove();
+ });
+
+ dialog.find('form').on('submit', apply);
+ dialog.find('form input:first').focus();
+ dialog.find('form input').keyup(function (e) {
+ if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) {
+ $(e.target).closest('form').submit();
+ return false;
+ } else {
+ return true;
+ }
+ });
+ }
+};
+
+OCA.External.StatusManager.Utils = {
+
+ showIconError: function (folder, clickAction, errorImageUrl) {
+ var imageUrl = "url(" + errorImageUrl + ")";
+ var trFolder = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); //FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(folder));
+ this.changeFolderIcon(folder, imageUrl);
+ this.toggleLink(folder, false, clickAction);
+ trFolder.addClass('externalErroredRow');
+ },
+
+ /**
+ * @param folder string with the folder or jQuery element pointing to the tr element
+ */
+ storeDefaultFolderIconAndBgcolor: function (folder) {
+ var trFolder;
+ if (folder instanceof $) {
+ trFolder = folder;
+ } else {
+ trFolder = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); //FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(folder)); //$('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]');
+ }
+ trFolder.each(function () {
+ var thisElement = $(this);
+ if (thisElement.data('oldbgcolor') === undefined) {
+ thisElement.data('oldbgcolor', thisElement.css('background-color'));
+ }
+ });
+
+ var icon = trFolder.find('td:first-child div.thumbnail');
+ icon.each(function () {
+ var thisElement = $(this);
+ if (thisElement.data('oldImage') === undefined) {
+ thisElement.data('oldImage', thisElement.css('background-image'));
+ }
+ });
+ },
+
+ /**
+ * @param folder string with the folder or jQuery element pointing to the tr element
+ */
+ restoreFolder: function (folder) {
+ var trFolder;
+ if (folder instanceof $) {
+ trFolder = folder;
+ } else {
+ // cant use here FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(folder)); return incorrect instance of filelist
+ trFolder = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]');
+ }
+ trFolder.removeClass('externalErroredRow').removeClass('externalDisabledRow');
+ tdChilds = trFolder.find("td:first-child div.thumbnail");
+ tdChilds.each(function () {
+ var thisElement = $(this);
+ thisElement.css('background-image', thisElement.data('oldImage'));
+ });
+ },
+
+ /**
+ * @param folder string with the folder or jQuery element pointing to the first td element
+ * of the tr matching the folder name
+ */
+ changeFolderIcon: function (filename) {
+ var file;
+ var route;
+ if (filename instanceof $) {
+ //trElementList
+ $.each(filename, function (index) {
+ route = OCA.External.StatusManager.Utils.getIconRoute($(this));
+ $(this).attr("data-icon", route);
+ $(this).find('td:first-child div.thumbnail').css('background-image', "url(" + route + ")").css('display', 'none').css('display', 'inline');
+ });
+ } else {
+ file = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child div.thumbnail");
+ parentTr = file.parents('tr:first');
+ route = OCA.External.StatusManager.Utils.getIconRoute(parentTr);
+ parentTr.attr("data-icon", route);
+ file.css('background-image', "url(" + route + ")").css('display', 'none').css('display', 'inline');
+ }
+ },
+
+ /**
+ * @param backend string with the name of the external storage backend
+ * of the tr matching the folder name
+ */
+ getIconRoute: function (tr) {
+ var icon = OC.imagePath('core', 'filetypes/folder-external');
+ var backend = null;
+
+ if (tr instanceof $) {
+ backend = tr.attr('data-external-backend');
+ }
+
+ switch (backend) {
+ case 'windows_network_drive':
+ icon = OC.imagePath('windows_network_drive', 'folder-windows');
+ break;
+ case 'sharepoint':
+ icon = OC.imagePath('sharepoint', 'folder-sharepoint');
+ break;
+ }
+
+ return icon;
+ },
+
+ toggleLink: function (filename, active, action) {
+ var link;
+ if (filename instanceof $) {
+ link = filename;
+ } else {
+ link = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child a.name");
+ }
+ if (active) {
+ link.off('click.connectivity');
+ OCA.Files.App.fileList.fileActions.display(link.parent(), true, OCA.Files.App.fileList);
+ } else {
+ link.find('.fileactions, .nametext .action').remove(); // from files/js/fileactions (display)
+ link.off('click.connectivity');
+ link.on('click.connectivity', function (e) {
+ if (action && $.isFunction(action)) {
+ action(filename);
+ }
+ e.preventDefault();
+ return false;
+ });
+ }
+ },
+
+ isCorrectViewAndRootFolder: function () {
+ // correct views = files & extstoragemounts
+ if (OCA.Files.App.getActiveView() === 'files' || OCA.Files.App.getActiveView() === 'extstoragemounts') {
+ return OCA.Files.App.getCurrentAppContainer().find('#dir').val() === '/';
+ }
+ return false;
+ },
+
+ /* escape a selector expression for jQuery */
+ jqSelEscape: function (expression) {
+ if (expression) {
+ return expression.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&');
+ }
+ return null;
+ },
+
+ /* Copied from http://stackoverflow.com/questions/2631001/javascript-test-for-existence-of-nested-object-key */
+ checkNested: function (cobj /*, level1, level2, ... levelN*/) {
+ var args = Array.prototype.slice.call(arguments),
+ obj = args.shift();
+
+ for (var i = 0; i < args.length; i++) {
+ if (!obj || !obj.hasOwnProperty(args[i])) {
+ return false;
+ }
+ obj = obj[args[i]];
+ }
+ return true;
+ }
+};
diff --git a/apps/files_external/l10n/ast.js b/apps/files_external/l10n/ast.js
index b663657e029..f67309631e8 100644
--- a/apps/files_external/l10n/ast.js
+++ b/apps/files_external/l10n/ast.js
@@ -53,8 +53,8 @@ OC.L10N.register(
"Folder name" : "Nome de la carpeta",
"Configuration" : "Configuración",
"Available for" : "Disponible pa",
- "Delete" : "Desaniciar",
"Add storage" : "Amestar almacenamientu",
+ "Delete" : "Desaniciar",
"Allow users to mount the following external storage" : "Permitir a los usuarios montar el siguiente almacenamientu esternu"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/ast.json b/apps/files_external/l10n/ast.json
index 0e98fe5a24a..b4bc4355bc4 100644
--- a/apps/files_external/l10n/ast.json
+++ b/apps/files_external/l10n/ast.json
@@ -51,8 +51,8 @@
"Folder name" : "Nome de la carpeta",
"Configuration" : "Configuración",
"Available for" : "Disponible pa",
- "Delete" : "Desaniciar",
"Add storage" : "Amestar almacenamientu",
+ "Delete" : "Desaniciar",
"Allow users to mount the following external storage" : "Permitir a los usuarios montar el siguiente almacenamientu esternu"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/az.js b/apps/files_external/l10n/az.js
index 700e36a4aef..42c9a496185 100644
--- a/apps/files_external/l10n/az.js
+++ b/apps/files_external/l10n/az.js
@@ -57,9 +57,9 @@ OC.L10N.register(
"Folder name" : "Qovluq adı",
"Configuration" : "Konfiqurasiya",
"Available for" : "Üçün mövcuddur",
+ "Add storage" : "Deponu əlavə et",
"Advanced settings" : "İrəliləmiş quraşdırmalar",
"Delete" : "Sil",
- "Add storage" : "Deponu əlavə et",
"Allow users to mount the following external storage" : "Göstərilən kənar deponun bərkidilməsi üçün istifadəçilərə izin ver"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/az.json b/apps/files_external/l10n/az.json
index 6cccabb2dd6..4e01cdf954c 100644
--- a/apps/files_external/l10n/az.json
+++ b/apps/files_external/l10n/az.json
@@ -55,9 +55,9 @@
"Folder name" : "Qovluq adı",
"Configuration" : "Konfiqurasiya",
"Available for" : "Üçün mövcuddur",
+ "Add storage" : "Deponu əlavə et",
"Advanced settings" : "İrəliləmiş quraşdırmalar",
"Delete" : "Sil",
- "Add storage" : "Deponu əlavə et",
"Allow users to mount the following external storage" : "Göstərilən kənar deponun bərkidilməsi üçün istifadəçilərə izin ver"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/bg_BG.js b/apps/files_external/l10n/bg_BG.js
index f14b13d2a0e..cc52682f956 100644
--- a/apps/files_external/l10n/bg_BG.js
+++ b/apps/files_external/l10n/bg_BG.js
@@ -59,9 +59,9 @@ OC.L10N.register(
"Folder name" : "Име на папката",
"Configuration" : "Настройки",
"Available for" : "Достъпно за",
+ "Add storage" : "Добави дисково пространство",
"Advanced settings" : "Разширени настройки",
"Delete" : "Изтрий",
- "Add storage" : "Добави дисково пространство",
"Allow users to mount the following external storage" : "Разреши на потребителите да прикачват следното външно дисково пространство"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/bg_BG.json b/apps/files_external/l10n/bg_BG.json
index 6cce8fd5cfa..df3fe1c20e8 100644
--- a/apps/files_external/l10n/bg_BG.json
+++ b/apps/files_external/l10n/bg_BG.json
@@ -57,9 +57,9 @@
"Folder name" : "Име на папката",
"Configuration" : "Настройки",
"Available for" : "Достъпно за",
+ "Add storage" : "Добави дисково пространство",
"Advanced settings" : "Разширени настройки",
"Delete" : "Изтрий",
- "Add storage" : "Добави дисково пространство",
"Allow users to mount the following external storage" : "Разреши на потребителите да прикачват следното външно дисково пространство"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/ca.js b/apps/files_external/l10n/ca.js
index b14057ea420..ff11ac0228b 100644
--- a/apps/files_external/l10n/ca.js
+++ b/apps/files_external/l10n/ca.js
@@ -18,7 +18,6 @@ OC.L10N.register(
"Check for changes" : "Comproveu si hi ha canvis",
"Never" : "Mai",
"Once every direct access" : "Un cop cada accés directe",
- "Every time the filesystem is used" : "Cada vegada que s'utilitza el sistema d'arxius",
"All users. Type to select user or group." : "Tots els usuaris. Escriu per seleccionar un usuari o grup.",
"(group)" : "(grup)",
"Saved" : "Desat",
@@ -66,9 +65,9 @@ OC.L10N.register(
"Folder name" : "Nom de la carpeta",
"Configuration" : "Configuració",
"Available for" : "Disponible per",
+ "Add storage" : "Afegeix emmagatzemament",
"Advanced settings" : "Configuració avançada",
"Delete" : "Esborra",
- "Add storage" : "Afegeix emmagatzemament",
"Allow users to mount the following external storage" : "Permet als usuaris muntar els dispositius externs següents"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/ca.json b/apps/files_external/l10n/ca.json
index cce51970c18..a64721a4bf5 100644
--- a/apps/files_external/l10n/ca.json
+++ b/apps/files_external/l10n/ca.json
@@ -16,7 +16,6 @@
"Check for changes" : "Comproveu si hi ha canvis",
"Never" : "Mai",
"Once every direct access" : "Un cop cada accés directe",
- "Every time the filesystem is used" : "Cada vegada que s'utilitza el sistema d'arxius",
"All users. Type to select user or group." : "Tots els usuaris. Escriu per seleccionar un usuari o grup.",
"(group)" : "(grup)",
"Saved" : "Desat",
@@ -64,9 +63,9 @@
"Folder name" : "Nom de la carpeta",
"Configuration" : "Configuració",
"Available for" : "Disponible per",
+ "Add storage" : "Afegeix emmagatzemament",
"Advanced settings" : "Configuració avançada",
"Delete" : "Esborra",
- "Add storage" : "Afegeix emmagatzemament",
"Allow users to mount the following external storage" : "Permet als usuaris muntar els dispositius externs següents"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/cs_CZ.js b/apps/files_external/l10n/cs_CZ.js
index 3e9a14f9998..2021edbbe09 100644
--- a/apps/files_external/l10n/cs_CZ.js
+++ b/apps/files_external/l10n/cs_CZ.js
@@ -17,6 +17,8 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "Neuspokojivé parametry služby",
"Unsatisfied authentication mechanism parameters" : "Neuspokojivé parametry ověřovacího mechanismu",
"Insufficient data: %s" : "Nedostatečná data: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Úložiště s id \"%i\" uživatelé nemohou upravovat",
"Personal" : "Osobní",
"System" : "Systém",
"Grant access" : "Povolit přístup",
@@ -27,13 +29,22 @@ OC.L10N.register(
"Error generating key pair" : "Chyba při vytváření páru klíčů",
"Enable encryption" : "Povolit šifrování",
"Enable previews" : "Povolit náhledy",
+ "Enable sharing" : "Povolit sdílení",
"Check for changes" : "Zkontrolovat změny",
"Never" : "Nikdy",
"Once every direct access" : "Jednou pro každý přímý přístup",
- "Every time the filesystem is used" : "Pokaždé když je použit souborový systém",
"All users. Type to select user or group." : "Všichni uživatelé. Začněte psát pro výběr uživatelů a skupin.",
"(group)" : "(skupina)",
+ "Admin defined" : "Nastaveno administrátorem",
"Saved" : "Uloženo",
+ "Empty response from the server" : "Prázdná odpověď serveru",
+ "Couldn't access. Please logout and login to activate this mount point" : "Nelze připojit. Pro aktivaci tohoto přípojného bodu se prosím odhlašte a znovu přihlašte",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Nelze obdržet informaci z ownCloud serveru: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Nelze obdržet seznam vzdálených přípojných bodů: {type}",
+ "There was an error with message: " : "Došlo k chybě s tímto hlášením:",
+ "External mount error" : "Chyba vzdáleného úložiště",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Nelze obdržet seznam síťových úložišť systému Windows: prázdná odpověď serveru",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Některá z nastavených vzdálených úložišť nejsou připojena. Pro více informací prosím klikněte na červenou šipku(y)",
"Access key" : "Přístupový klíč",
"Secret key" : "Tajný klíč",
"Builtin" : "Zabudované",
@@ -51,8 +62,10 @@ OC.L10N.register(
"Identity endpoint URL" : "Identifikační koncový bod URL",
"Rackspace" : "Rackspace",
"API key" : "Klíč API",
+ "Log-in credentials, save in database" : "Přihlašovací údaje, ukládat do databáze",
"Username and password" : "Uživatelské jméno a heslo",
- "Session credentials" : "Přihlašovací údaje sezení",
+ "Log-in credentials, save in session" : "Přihlašovací údaje, ukládat v sezení",
+ "User entered, store in database" : "Zadané uživatelem, ukládat v databázi",
"RSA public key" : "RSA veřejný klíč",
"Public key" : "Veřejný klíč",
"Amazon S3" : "Amazon S3",
@@ -99,9 +112,9 @@ OC.L10N.register(
"Authentication" : "Ověření",
"Configuration" : "Nastavení",
"Available for" : "Dostupné pro",
+ "Add storage" : "Přidat úložiště",
"Advanced settings" : "Pokročilá nastavení",
"Delete" : "Smazat",
- "Add storage" : "Přidat úložiště",
"Allow users to mount external storage" : "Povolit uživatelům připojení externího úložiště",
"Allow users to mount the following external storage" : "Povolit uživatelů připojit následující externí úložiště"
},
diff --git a/apps/files_external/l10n/cs_CZ.json b/apps/files_external/l10n/cs_CZ.json
index 4c6f940666e..fbec266dc9b 100644
--- a/apps/files_external/l10n/cs_CZ.json
+++ b/apps/files_external/l10n/cs_CZ.json
@@ -15,6 +15,8 @@
"Unsatisfied backend parameters" : "Neuspokojivé parametry služby",
"Unsatisfied authentication mechanism parameters" : "Neuspokojivé parametry ověřovacího mechanismu",
"Insufficient data: %s" : "Nedostatečná data: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Úložiště s id \"%i\" uživatelé nemohou upravovat",
"Personal" : "Osobní",
"System" : "Systém",
"Grant access" : "Povolit přístup",
@@ -25,13 +27,22 @@
"Error generating key pair" : "Chyba při vytváření páru klíčů",
"Enable encryption" : "Povolit šifrování",
"Enable previews" : "Povolit náhledy",
+ "Enable sharing" : "Povolit sdílení",
"Check for changes" : "Zkontrolovat změny",
"Never" : "Nikdy",
"Once every direct access" : "Jednou pro každý přímý přístup",
- "Every time the filesystem is used" : "Pokaždé když je použit souborový systém",
"All users. Type to select user or group." : "Všichni uživatelé. Začněte psát pro výběr uživatelů a skupin.",
"(group)" : "(skupina)",
+ "Admin defined" : "Nastaveno administrátorem",
"Saved" : "Uloženo",
+ "Empty response from the server" : "Prázdná odpověď serveru",
+ "Couldn't access. Please logout and login to activate this mount point" : "Nelze připojit. Pro aktivaci tohoto přípojného bodu se prosím odhlašte a znovu přihlašte",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Nelze obdržet informaci z ownCloud serveru: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Nelze obdržet seznam vzdálených přípojných bodů: {type}",
+ "There was an error with message: " : "Došlo k chybě s tímto hlášením:",
+ "External mount error" : "Chyba vzdáleného úložiště",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Nelze obdržet seznam síťových úložišť systému Windows: prázdná odpověď serveru",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Některá z nastavených vzdálených úložišť nejsou připojena. Pro více informací prosím klikněte na červenou šipku(y)",
"Access key" : "Přístupový klíč",
"Secret key" : "Tajný klíč",
"Builtin" : "Zabudované",
@@ -49,8 +60,10 @@
"Identity endpoint URL" : "Identifikační koncový bod URL",
"Rackspace" : "Rackspace",
"API key" : "Klíč API",
+ "Log-in credentials, save in database" : "Přihlašovací údaje, ukládat do databáze",
"Username and password" : "Uživatelské jméno a heslo",
- "Session credentials" : "Přihlašovací údaje sezení",
+ "Log-in credentials, save in session" : "Přihlašovací údaje, ukládat v sezení",
+ "User entered, store in database" : "Zadané uživatelem, ukládat v databázi",
"RSA public key" : "RSA veřejný klíč",
"Public key" : "Veřejný klíč",
"Amazon S3" : "Amazon S3",
@@ -97,9 +110,9 @@
"Authentication" : "Ověření",
"Configuration" : "Nastavení",
"Available for" : "Dostupné pro",
+ "Add storage" : "Přidat úložiště",
"Advanced settings" : "Pokročilá nastavení",
"Delete" : "Smazat",
- "Add storage" : "Přidat úložiště",
"Allow users to mount external storage" : "Povolit uživatelům připojení externího úložiště",
"Allow users to mount the following external storage" : "Povolit uživatelů připojit následující externí úložiště"
},"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
diff --git a/apps/files_external/l10n/da.js b/apps/files_external/l10n/da.js
index ba5d572a206..70f43819496 100644
--- a/apps/files_external/l10n/da.js
+++ b/apps/files_external/l10n/da.js
@@ -29,7 +29,6 @@ OC.L10N.register(
"Check for changes" : "Tjek for ændringer",
"Never" : "Aldrig",
"Once every direct access" : "Kun ved hver direkte tilgang",
- "Every time the filesystem is used" : "Hver gang filsystemet benyttes",
"All users. Type to select user or group." : "Alle brugere. Indtast for at vælge bruger eller gruppe.",
"(group)" : "(gruppe)",
"Saved" : "Gemt",
@@ -51,7 +50,6 @@ OC.L10N.register(
"Rackspace" : "Hyldeplads",
"API key" : "API nøgle",
"Username and password" : "Brugernavn og kodeord",
- "Session credentials" : "Brugeroplysninger for session",
"RSA public key" : "RSA offentlig nøgle",
"Public key" : "Offentlig nøgle",
"Amazon S3" : "Amazon S3",
@@ -98,9 +96,9 @@ OC.L10N.register(
"Authentication" : "Godkendelse",
"Configuration" : "Opsætning",
"Available for" : "Tilgængelig for",
+ "Add storage" : "Tilføj lager",
"Advanced settings" : "Avancerede indstillinger",
"Delete" : "Slet",
- "Add storage" : "Tilføj lager",
"Allow users to mount the following external storage" : "Tillad brugere at montere følgende som eksternt lager"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/da.json b/apps/files_external/l10n/da.json
index c819040bc74..aaeaaa58ae0 100644
--- a/apps/files_external/l10n/da.json
+++ b/apps/files_external/l10n/da.json
@@ -27,7 +27,6 @@
"Check for changes" : "Tjek for ændringer",
"Never" : "Aldrig",
"Once every direct access" : "Kun ved hver direkte tilgang",
- "Every time the filesystem is used" : "Hver gang filsystemet benyttes",
"All users. Type to select user or group." : "Alle brugere. Indtast for at vælge bruger eller gruppe.",
"(group)" : "(gruppe)",
"Saved" : "Gemt",
@@ -49,7 +48,6 @@
"Rackspace" : "Hyldeplads",
"API key" : "API nøgle",
"Username and password" : "Brugernavn og kodeord",
- "Session credentials" : "Brugeroplysninger for session",
"RSA public key" : "RSA offentlig nøgle",
"Public key" : "Offentlig nøgle",
"Amazon S3" : "Amazon S3",
@@ -96,9 +94,9 @@
"Authentication" : "Godkendelse",
"Configuration" : "Opsætning",
"Available for" : "Tilgængelig for",
+ "Add storage" : "Tilføj lager",
"Advanced settings" : "Avancerede indstillinger",
"Delete" : "Slet",
- "Add storage" : "Tilføj lager",
"Allow users to mount the following external storage" : "Tillad brugere at montere følgende som eksternt lager"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/de.js b/apps/files_external/l10n/de.js
index c26322495d6..41b86dbeb48 100644
--- a/apps/files_external/l10n/de.js
+++ b/apps/files_external/l10n/de.js
@@ -10,10 +10,12 @@ OC.L10N.register(
"Storage with id \"%i\" not found" : "Der Speicher mit der ID „%i“ wurde nicht gefunden",
"Invalid mount point" : "Ungültiger mount point",
"Invalid storage backend \"%s\"" : "Ungültiges Speicher-Backend „%s“",
+ "%s" : "%s",
"Personal" : "Persönlich",
"System" : "System",
"Grant access" : "Zugriff gestatten",
"Access granted" : "Zugriff gestattet",
+ "Error configuring OAuth1" : "Fehler beim konfigurieren von OAuth1",
"Error configuring OAuth2" : "Fehler beim Einrichten von OAuth2",
"Generate keys" : "Schlüssel erzeugen",
"Error generating key pair" : "Fehler beim Erzeugen des Schlüsselpaares",
@@ -22,10 +24,11 @@ OC.L10N.register(
"Check for changes" : "Auf Änderungen überprüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem Direktzugriff",
- "Every time the filesystem is used" : "Immer, wenn das Dateisystem benutzt wird",
"All users. Type to select user or group." : "Alle Benutzer. Benutzer oder Gruppe zur Auswahl eingeben.",
"(group)" : "(group)",
+ "Admin defined" : "Administrator festlegen",
"Saved" : "Gespeichert",
+ "There was an error with message: " : "Es ist ein Fehler mit folgender Meldung aufgetreten:",
"Access key" : "Zugangsschlüssel",
"Secret key" : "Geheimer Schlüssel",
"None" : "Keine",
@@ -38,6 +41,8 @@ OC.L10N.register(
"OpenStack" : "OpenStack",
"Username" : "Benutzername",
"Password" : "Passwort",
+ "Tenant name" : "Name des Mieters",
+ "Rackspace" : "Rackspace",
"API key" : "API-Schlüssel",
"Username and password" : "Benutzername und Passwort",
"RSA public key" : "RSA öffentlicher Schlüssel",
@@ -70,6 +75,7 @@ OC.L10N.register(
"SMB / CIFS using OC login" : "SMB / CIFS mit OC-Login",
"Username as share" : "Benutzername als Freigabe",
"OpenStack Object Storage" : "Openstack-Objektspeicher",
+ "Service name" : "Service Name",
"<b>Note:</b> " : "<b>Hinweis:</b> ",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Hinweis:</b> Die cURL-Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wende Dich zur Installation an Deinen Systemadministrator.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Hinweis:</b> Die FTP Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wende Dich sich zur Installation an Deinen Systemadministrator.",
@@ -84,9 +90,10 @@ OC.L10N.register(
"Authentication" : "Authentifizierung",
"Configuration" : "Konfiguration",
"Available for" : "Verfügbar für",
+ "Add storage" : "Speicher hinzufügen",
"Advanced settings" : "Erweiterte Einstellungen",
"Delete" : "Löschen",
- "Add storage" : "Speicher hinzufügen",
- "Allow users to mount the following external storage" : "Erlaube es Benutzern, den folgenden externen Speicher einzubinden"
+ "Allow users to mount external storage" : "Benutzern erlauben, externen Speicher einzubinden",
+ "Allow users to mount the following external storage" : "Benutzern erlauben, den oder die folgenden externen Speicher einzubinden:"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/de.json b/apps/files_external/l10n/de.json
index adec32d072b..2b50a822507 100644
--- a/apps/files_external/l10n/de.json
+++ b/apps/files_external/l10n/de.json
@@ -8,10 +8,12 @@
"Storage with id \"%i\" not found" : "Der Speicher mit der ID „%i“ wurde nicht gefunden",
"Invalid mount point" : "Ungültiger mount point",
"Invalid storage backend \"%s\"" : "Ungültiges Speicher-Backend „%s“",
+ "%s" : "%s",
"Personal" : "Persönlich",
"System" : "System",
"Grant access" : "Zugriff gestatten",
"Access granted" : "Zugriff gestattet",
+ "Error configuring OAuth1" : "Fehler beim konfigurieren von OAuth1",
"Error configuring OAuth2" : "Fehler beim Einrichten von OAuth2",
"Generate keys" : "Schlüssel erzeugen",
"Error generating key pair" : "Fehler beim Erzeugen des Schlüsselpaares",
@@ -20,10 +22,11 @@
"Check for changes" : "Auf Änderungen überprüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem Direktzugriff",
- "Every time the filesystem is used" : "Immer, wenn das Dateisystem benutzt wird",
"All users. Type to select user or group." : "Alle Benutzer. Benutzer oder Gruppe zur Auswahl eingeben.",
"(group)" : "(group)",
+ "Admin defined" : "Administrator festlegen",
"Saved" : "Gespeichert",
+ "There was an error with message: " : "Es ist ein Fehler mit folgender Meldung aufgetreten:",
"Access key" : "Zugangsschlüssel",
"Secret key" : "Geheimer Schlüssel",
"None" : "Keine",
@@ -36,6 +39,8 @@
"OpenStack" : "OpenStack",
"Username" : "Benutzername",
"Password" : "Passwort",
+ "Tenant name" : "Name des Mieters",
+ "Rackspace" : "Rackspace",
"API key" : "API-Schlüssel",
"Username and password" : "Benutzername und Passwort",
"RSA public key" : "RSA öffentlicher Schlüssel",
@@ -68,6 +73,7 @@
"SMB / CIFS using OC login" : "SMB / CIFS mit OC-Login",
"Username as share" : "Benutzername als Freigabe",
"OpenStack Object Storage" : "Openstack-Objektspeicher",
+ "Service name" : "Service Name",
"<b>Note:</b> " : "<b>Hinweis:</b> ",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Hinweis:</b> Die cURL-Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wende Dich zur Installation an Deinen Systemadministrator.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Hinweis:</b> Die FTP Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wende Dich sich zur Installation an Deinen Systemadministrator.",
@@ -82,9 +88,10 @@
"Authentication" : "Authentifizierung",
"Configuration" : "Konfiguration",
"Available for" : "Verfügbar für",
+ "Add storage" : "Speicher hinzufügen",
"Advanced settings" : "Erweiterte Einstellungen",
"Delete" : "Löschen",
- "Add storage" : "Speicher hinzufügen",
- "Allow users to mount the following external storage" : "Erlaube es Benutzern, den folgenden externen Speicher einzubinden"
+ "Allow users to mount external storage" : "Benutzern erlauben, externen Speicher einzubinden",
+ "Allow users to mount the following external storage" : "Benutzern erlauben, den oder die folgenden externen Speicher einzubinden:"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/de_DE.js b/apps/files_external/l10n/de_DE.js
index c30fcb95919..ef860918474 100644
--- a/apps/files_external/l10n/de_DE.js
+++ b/apps/files_external/l10n/de_DE.js
@@ -7,10 +7,12 @@ OC.L10N.register(
"Storage with id \"%i\" not found" : "Der Speicher mit der ID „%i“ wurde nicht gefunden",
"Invalid mount point" : "Ungültiger mount point",
"Invalid storage backend \"%s\"" : "Ungültiges Speicher-Backend „%s“",
+ "Insufficient data: %s" : "Unzureichende Daten: %s",
"Personal" : "Persönlich",
"System" : "System",
"Grant access" : "Zugriff gestatten",
"Access granted" : "Zugriff gestattet",
+ "Error configuring OAuth1" : "Fehler beim Konfigurieren von OAuth1",
"Generate keys" : "Schlüssel erzeugen",
"Error generating key pair" : "Fehler beim Erzeugen des Schlüsselpaares",
"Enable encryption" : "Verschlüsselung aktivieren",
@@ -18,7 +20,6 @@ OC.L10N.register(
"Check for changes" : "Auf Änderungen überprüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem Direktzugriff",
- "Every time the filesystem is used" : "Immer, wenn das Dateisystem benutzt wird",
"All users. Type to select user or group." : "Alle Benutzer. Benutzer oder Gruppe zur Auswahl eingeben.",
"(group)" : "(group)",
"Saved" : "Gespeichert",
@@ -30,6 +31,7 @@ OC.L10N.register(
"Username" : "Benutzername",
"Password" : "Passwort",
"API key" : "API-Schlüssel",
+ "Username and password" : "Benutzername und Passwort",
"Public key" : "Öffentlicher Schlüssel",
"Amazon S3" : "Amazon S3",
"Bucket" : "Bucket",
@@ -43,17 +45,23 @@ OC.L10N.register(
"Remote subfolder" : "Entfernter Unterordner",
"Secure https://" : "Sicheres https://",
"Dropbox" : "Dropbox",
+ "FTP" : "FTP",
"Host" : "Host",
"Secure ftps://" : "Sicheres ftps://",
+ "Google Drive" : "Google Drive",
"Local" : "Lokal",
"Location" : "Ort",
"ownCloud" : "ownCloud",
+ "SFTP" : "SFTP",
"Root" : "Root",
"SFTP with secret key login" : "SFTP mit dem Login über einen geheimen Schlüssel",
+ "SMB / CIFS" : "SMB / CIFS",
"Share" : "Share",
+ "Domain" : "Domain",
"SMB / CIFS using OC login" : "SMB / CIFS mit OC-Login",
"Username as share" : "Benutzername als Freigabe",
"OpenStack Object Storage" : "Openstack-Objektspeicher",
+ "Service name" : "Dienst Name",
"<b>Note:</b> " : "<b>Hinweis:</b> ",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Hinweis:</b> Die cURL-Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wenden Sie sich zur Installation an Ihren Systemadministrator.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Hinweis:</b> Die FTP Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wenden Sie sich zur Installation an Ihren Systemadministrator.",
@@ -65,11 +73,13 @@ OC.L10N.register(
"Scope" : "Anwendungsbereich",
"External Storage" : "Externer Speicher",
"Folder name" : "Ordnername",
+ "Authentication" : "Authentifizierung",
"Configuration" : "Konfiguration",
"Available for" : "Verfügbar für",
+ "Add storage" : "Speicher hinzufügen",
"Advanced settings" : "Erweiterte Einstellungen",
"Delete" : "Löschen",
- "Add storage" : "Speicher hinzufügen",
- "Allow users to mount the following external storage" : "Erlauben Sie Benutzern, folgende externe Speicher einzubinden"
+ "Allow users to mount external storage" : "Erlauben Sie den Benutzern externen Speicher hinzuzufügen",
+ "Allow users to mount the following external storage" : "Benutzern erlauben, den oder die folgenden externen Speicher einzubinden:"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/de_DE.json b/apps/files_external/l10n/de_DE.json
index 7fec06bf90f..75a84334764 100644
--- a/apps/files_external/l10n/de_DE.json
+++ b/apps/files_external/l10n/de_DE.json
@@ -5,10 +5,12 @@
"Storage with id \"%i\" not found" : "Der Speicher mit der ID „%i“ wurde nicht gefunden",
"Invalid mount point" : "Ungültiger mount point",
"Invalid storage backend \"%s\"" : "Ungültiges Speicher-Backend „%s“",
+ "Insufficient data: %s" : "Unzureichende Daten: %s",
"Personal" : "Persönlich",
"System" : "System",
"Grant access" : "Zugriff gestatten",
"Access granted" : "Zugriff gestattet",
+ "Error configuring OAuth1" : "Fehler beim Konfigurieren von OAuth1",
"Generate keys" : "Schlüssel erzeugen",
"Error generating key pair" : "Fehler beim Erzeugen des Schlüsselpaares",
"Enable encryption" : "Verschlüsselung aktivieren",
@@ -16,7 +18,6 @@
"Check for changes" : "Auf Änderungen überprüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem Direktzugriff",
- "Every time the filesystem is used" : "Immer, wenn das Dateisystem benutzt wird",
"All users. Type to select user or group." : "Alle Benutzer. Benutzer oder Gruppe zur Auswahl eingeben.",
"(group)" : "(group)",
"Saved" : "Gespeichert",
@@ -28,6 +29,7 @@
"Username" : "Benutzername",
"Password" : "Passwort",
"API key" : "API-Schlüssel",
+ "Username and password" : "Benutzername und Passwort",
"Public key" : "Öffentlicher Schlüssel",
"Amazon S3" : "Amazon S3",
"Bucket" : "Bucket",
@@ -41,17 +43,23 @@
"Remote subfolder" : "Entfernter Unterordner",
"Secure https://" : "Sicheres https://",
"Dropbox" : "Dropbox",
+ "FTP" : "FTP",
"Host" : "Host",
"Secure ftps://" : "Sicheres ftps://",
+ "Google Drive" : "Google Drive",
"Local" : "Lokal",
"Location" : "Ort",
"ownCloud" : "ownCloud",
+ "SFTP" : "SFTP",
"Root" : "Root",
"SFTP with secret key login" : "SFTP mit dem Login über einen geheimen Schlüssel",
+ "SMB / CIFS" : "SMB / CIFS",
"Share" : "Share",
+ "Domain" : "Domain",
"SMB / CIFS using OC login" : "SMB / CIFS mit OC-Login",
"Username as share" : "Benutzername als Freigabe",
"OpenStack Object Storage" : "Openstack-Objektspeicher",
+ "Service name" : "Dienst Name",
"<b>Note:</b> " : "<b>Hinweis:</b> ",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Hinweis:</b> Die cURL-Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wenden Sie sich zur Installation an Ihren Systemadministrator.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Hinweis:</b> Die FTP Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wenden Sie sich zur Installation an Ihren Systemadministrator.",
@@ -63,11 +71,13 @@
"Scope" : "Anwendungsbereich",
"External Storage" : "Externer Speicher",
"Folder name" : "Ordnername",
+ "Authentication" : "Authentifizierung",
"Configuration" : "Konfiguration",
"Available for" : "Verfügbar für",
+ "Add storage" : "Speicher hinzufügen",
"Advanced settings" : "Erweiterte Einstellungen",
"Delete" : "Löschen",
- "Add storage" : "Speicher hinzufügen",
- "Allow users to mount the following external storage" : "Erlauben Sie Benutzern, folgende externe Speicher einzubinden"
+ "Allow users to mount external storage" : "Erlauben Sie den Benutzern externen Speicher hinzuzufügen",
+ "Allow users to mount the following external storage" : "Benutzern erlauben, den oder die folgenden externen Speicher einzubinden:"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/el.js b/apps/files_external/l10n/el.js
index a83c241af7a..c04d3d015d3 100644
--- a/apps/files_external/l10n/el.js
+++ b/apps/files_external/l10n/el.js
@@ -17,6 +17,7 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "Ελλιπείς παράμετροι συστήματος",
"Unsatisfied authentication mechanism parameters" : "Ελλιπείς παράμετροι μηχανισμού πιστοποίησης",
"Insufficient data: %s" : "Μη επαρκή δεδομένα: %s",
+ "%s" : "%s",
"Personal" : "Προσωπικά",
"System" : "Σύστημα",
"Grant access" : "Παροχή πρόσβασης",
@@ -30,7 +31,6 @@ OC.L10N.register(
"Check for changes" : "Έλεγχος για αλλαγές",
"Never" : "Ποτέ",
"Once every direct access" : "Σε κάθε απευθείας πρόσβαση",
- "Every time the filesystem is used" : "Κάθε φορά που χρησιμοποιείται το σύστημα αρχείων",
"All users. Type to select user or group." : "Όλοι οι χρήστες. Πληκτρολογήστε για να επιλέξετε χρήστη ή ομάδα.",
"(group)" : "(ομάδα)",
"Saved" : "Αποθηκεύτηκαν",
@@ -52,7 +52,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "Κλειδί Google API",
"Username and password" : "Όνομα χρήστη και κωδικός πρόσβασης",
- "Session credentials" : "Διαπιστευτήρια συνεδρίας",
"RSA public key" : "Δημόσιο κλειδί RSA",
"Public key" : "Δημόσιο κλειδί",
"Amazon S3" : "Amazon S3",
@@ -99,9 +98,9 @@ OC.L10N.register(
"Authentication" : "Πιστοποίηση",
"Configuration" : "Ρυθμίσεις",
"Available for" : "Διαθέσιμο για",
+ "Add storage" : "Προσθηκη αποθηκευσης",
"Advanced settings" : "Ρυθμίσεις για προχωρημένους",
"Delete" : "Διαγραφή",
- "Add storage" : "Προσθηκη αποθηκευσης",
"Allow users to mount external storage" : "Να επιτρέπεται στους χρήστες η σύνδεση εξωτερικού χώρου",
"Allow users to mount the following external storage" : "Χορήγηση άδειας στους χρήστες να συνδέσουν τα παρακάτω εξωτερικά μέσα αποθήκευσης"
},
diff --git a/apps/files_external/l10n/el.json b/apps/files_external/l10n/el.json
index 32f223cf8c0..98a6d18bfc3 100644
--- a/apps/files_external/l10n/el.json
+++ b/apps/files_external/l10n/el.json
@@ -15,6 +15,7 @@
"Unsatisfied backend parameters" : "Ελλιπείς παράμετροι συστήματος",
"Unsatisfied authentication mechanism parameters" : "Ελλιπείς παράμετροι μηχανισμού πιστοποίησης",
"Insufficient data: %s" : "Μη επαρκή δεδομένα: %s",
+ "%s" : "%s",
"Personal" : "Προσωπικά",
"System" : "Σύστημα",
"Grant access" : "Παροχή πρόσβασης",
@@ -28,7 +29,6 @@
"Check for changes" : "Έλεγχος για αλλαγές",
"Never" : "Ποτέ",
"Once every direct access" : "Σε κάθε απευθείας πρόσβαση",
- "Every time the filesystem is used" : "Κάθε φορά που χρησιμοποιείται το σύστημα αρχείων",
"All users. Type to select user or group." : "Όλοι οι χρήστες. Πληκτρολογήστε για να επιλέξετε χρήστη ή ομάδα.",
"(group)" : "(ομάδα)",
"Saved" : "Αποθηκεύτηκαν",
@@ -50,7 +50,6 @@
"Rackspace" : "Rackspace",
"API key" : "Κλειδί Google API",
"Username and password" : "Όνομα χρήστη και κωδικός πρόσβασης",
- "Session credentials" : "Διαπιστευτήρια συνεδρίας",
"RSA public key" : "Δημόσιο κλειδί RSA",
"Public key" : "Δημόσιο κλειδί",
"Amazon S3" : "Amazon S3",
@@ -97,9 +96,9 @@
"Authentication" : "Πιστοποίηση",
"Configuration" : "Ρυθμίσεις",
"Available for" : "Διαθέσιμο για",
+ "Add storage" : "Προσθηκη αποθηκευσης",
"Advanced settings" : "Ρυθμίσεις για προχωρημένους",
"Delete" : "Διαγραφή",
- "Add storage" : "Προσθηκη αποθηκευσης",
"Allow users to mount external storage" : "Να επιτρέπεται στους χρήστες η σύνδεση εξωτερικού χώρου",
"Allow users to mount the following external storage" : "Χορήγηση άδειας στους χρήστες να συνδέσουν τα παρακάτω εξωτερικά μέσα αποθήκευσης"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/files_external/l10n/en_GB.js b/apps/files_external/l10n/en_GB.js
index 9829bd3e8c7..adba5abf88c 100644
--- a/apps/files_external/l10n/en_GB.js
+++ b/apps/files_external/l10n/en_GB.js
@@ -18,7 +18,6 @@ OC.L10N.register(
"Check for changes" : "Check for changes",
"Never" : "Never",
"Once every direct access" : "Once every direct access",
- "Every time the filesystem is used" : "Every time the filesystem is used",
"All users. Type to select user or group." : "All users. Type to select user or group.",
"(group)" : "(group)",
"Saved" : "Saved",
@@ -67,9 +66,9 @@ OC.L10N.register(
"Folder name" : "Folder name",
"Configuration" : "Configuration",
"Available for" : "Available for",
+ "Add storage" : "Add storage",
"Advanced settings" : "Advanced settings",
"Delete" : "Delete",
- "Add storage" : "Add storage",
"Allow users to mount the following external storage" : "Allow users to mount the following external storage"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/en_GB.json b/apps/files_external/l10n/en_GB.json
index 88467528431..04d43cf4854 100644
--- a/apps/files_external/l10n/en_GB.json
+++ b/apps/files_external/l10n/en_GB.json
@@ -16,7 +16,6 @@
"Check for changes" : "Check for changes",
"Never" : "Never",
"Once every direct access" : "Once every direct access",
- "Every time the filesystem is used" : "Every time the filesystem is used",
"All users. Type to select user or group." : "All users. Type to select user or group.",
"(group)" : "(group)",
"Saved" : "Saved",
@@ -65,9 +64,9 @@
"Folder name" : "Folder name",
"Configuration" : "Configuration",
"Available for" : "Available for",
+ "Add storage" : "Add storage",
"Advanced settings" : "Advanced settings",
"Delete" : "Delete",
- "Add storage" : "Add storage",
"Allow users to mount the following external storage" : "Allow users to mount the following external storage"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/eo.js b/apps/files_external/l10n/eo.js
index ce3dd21c012..ddab2360a6d 100644
--- a/apps/files_external/l10n/eo.js
+++ b/apps/files_external/l10n/eo.js
@@ -38,8 +38,8 @@ OC.L10N.register(
"Folder name" : "Dosierujnomo",
"Configuration" : "Agordo",
"Available for" : "Disponebla por",
- "Delete" : "Forigi",
"Add storage" : "Aldoni memorilon",
+ "Delete" : "Forigi",
"Allow users to mount the following external storage" : "Permesi uzantojn munti la jenajn malenajn memorilojn"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/eo.json b/apps/files_external/l10n/eo.json
index d8c620d24c2..ec91f40abac 100644
--- a/apps/files_external/l10n/eo.json
+++ b/apps/files_external/l10n/eo.json
@@ -36,8 +36,8 @@
"Folder name" : "Dosierujnomo",
"Configuration" : "Agordo",
"Available for" : "Disponebla por",
- "Delete" : "Forigi",
"Add storage" : "Aldoni memorilon",
+ "Delete" : "Forigi",
"Allow users to mount the following external storage" : "Permesi uzantojn munti la jenajn malenajn memorilojn"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/es.js b/apps/files_external/l10n/es.js
index 5415e8963cd..8a49dd4ec05 100644
--- a/apps/files_external/l10n/es.js
+++ b/apps/files_external/l10n/es.js
@@ -1,13 +1,23 @@
OC.L10N.register(
"files_external",
{
+ "Fetching request tokens failed. Verify that your app key and secret are correct." : "Falló al acceder a los tokens solicitados. Verifique que su clave de app y la clave secreta sean correctas.",
+ "Fetching access tokens failed. Verify that your app key and secret are correct." : "Falló al acceder a los tokens solicitados. Verifique que su clave de app y la clave secreta sean correctas.",
+ "Please provide a valid app key and secret." : "Por favor facilite una clave de app y una clave secreta válidas.",
"Step 1 failed. Exception: %s" : "El paso 1 falló. Excepción: %s",
"Step 2 failed. Exception: %s" : "El paso 2 falló. Excepción: %s",
"External storage" : "Almacenamiento externo",
"Storage with id \"%i\" not found" : "No se ha encontrado almacenamiento con id \"%i\"",
+ "Invalid backend or authentication mechanism class" : "Sistema o mecanismo de autentificación inválido",
"Invalid mount point" : "Punto de montaje no válido",
+ "Objectstore forbidden" : "Objeto de almacenaje prohibido",
"Invalid storage backend \"%s\"" : "Motor de almacenamiento no válido «%s»",
- "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autenticación \"%s\"",
+ "Not permitted to use backend \"%s\"" : "No se permite usar el mecanismo \"%s\"",
+ "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autentificación \"%s\"",
+ "Unsatisfied backend parameters" : "Los parámetros del sistema no son válidos",
+ "Unsatisfied authentication mechanism parameters" : "Los parámetros del mecanismo de autentificación no son válidos",
+ "Insufficient data: %s" : "Datos insuficientes: %s",
+ "%s" : "%s",
"Personal" : "Personal",
"System" : "Sistema",
"Grant access" : "Conceder acceso",
@@ -21,12 +31,21 @@ OC.L10N.register(
"Check for changes" : "Comprobar si hay cambios",
"Never" : "Nunca",
"Once every direct access" : "Una vez cada acceso directo",
- "Every time the filesystem is used" : "Cada vez que filesystem es utilizado",
"All users. Type to select user or group." : "Todos los usuarios. Teclee para seleccionar un usuario o grupo.",
"(group)" : "(grupo)",
+ "Admin defined" : "Admin definido",
"Saved" : "Guardado",
+ "Empty response from the server" : "Respuesta vacía desde el servidor",
+ "Couldn't access. Please logout and login to activate this mount point" : "No se puede acceder. Por favor cierra sesión e iníciala de nuevo para activar este punto de montaje",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "No se puede obtener información acerca del servidor de OwnCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "No se puede obtener la lista de los puntos de montaje externos: {type}",
+ "There was an error with message: " : "Hubo un error con el mensaje:",
+ "External mount error" : "Error de montaje externo",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "No se puede obtener la lista de unidades de red y sus puntos de montaje de Windows: respuesta vacía desde el servidor",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Algunos de los puntos de montaje externos configurados no están conectados. Por favor, haga clic en la fila roja (s) para obtener más información",
"Access key" : "Clave de acceso",
"Secret key" : "Clave secreta",
+ "Builtin" : "Incorporado",
"None" : "Ninguno",
"OAuth1" : "OAuth1",
"App key" : "App principal",
@@ -34,12 +53,14 @@ OC.L10N.register(
"OAuth2" : "OAuth2",
"Client ID" : "ID de Cliente",
"Client secret" : "Cliente secreto",
+ "OpenStack" : "OpenStack",
"Username" : "Nombre de usuario",
"Password" : "Contraseña",
"Tenant name" : "Nombre del inquilino",
+ "Identity endpoint URL" : "Identidad de punto final URL",
+ "Rackspace" : "Espacio de Rack",
"API key" : "Clave API",
"Username and password" : "Nombre de usuario y contraseña",
- "Session credentials" : "Credenciales de la sesión",
"RSA public key" : "Clave pública RSA",
"Public key" : "Clave pública",
"Amazon S3" : "Amazon S3",
@@ -71,6 +92,7 @@ OC.L10N.register(
"Username as share" : "Nombre de usuario como compartir",
"OpenStack Object Storage" : "Almacenamiento de objeto OpenStack",
"Service name" : "Nombre del servicio",
+ "Request timeout (seconds)" : "Tiempo agotado para petición (segundos)",
"<b>Note:</b> " : "<b>Nota:</b> ",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Nota:</b> El soporte de cURL en PHP no está activado o instalado. No se puede montar %s. Pídale al administrador del sistema que lo instale.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Nota:</b> El soporte de FTP en PHP no está activado o instalado. No se puede montar %s. Pídale al administrador del sistema que lo instale.",
@@ -82,12 +104,13 @@ OC.L10N.register(
"Scope" : "Ámbito",
"External Storage" : "Almacenamiento externo",
"Folder name" : "Nombre de la carpeta",
- "Authentication" : "Autenticación",
+ "Authentication" : "Autentificación",
"Configuration" : "Configuración",
"Available for" : "Disponible para",
+ "Add storage" : "Añadir almacenamiento",
"Advanced settings" : "Configuración avanzada",
"Delete" : "Eliminar",
- "Add storage" : "Añadir almacenamiento",
+ "Allow users to mount external storage" : "Permitir a los usuarios montar un almacenamiento externo",
"Allow users to mount the following external storage" : "Permitir a los usuarios montar el siguiente almacenamiento externo"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/es.json b/apps/files_external/l10n/es.json
index 10cbf0c974a..c3b81338776 100644
--- a/apps/files_external/l10n/es.json
+++ b/apps/files_external/l10n/es.json
@@ -1,11 +1,21 @@
{ "translations": {
+ "Fetching request tokens failed. Verify that your app key and secret are correct." : "Falló al acceder a los tokens solicitados. Verifique que su clave de app y la clave secreta sean correctas.",
+ "Fetching access tokens failed. Verify that your app key and secret are correct." : "Falló al acceder a los tokens solicitados. Verifique que su clave de app y la clave secreta sean correctas.",
+ "Please provide a valid app key and secret." : "Por favor facilite una clave de app y una clave secreta válidas.",
"Step 1 failed. Exception: %s" : "El paso 1 falló. Excepción: %s",
"Step 2 failed. Exception: %s" : "El paso 2 falló. Excepción: %s",
"External storage" : "Almacenamiento externo",
"Storage with id \"%i\" not found" : "No se ha encontrado almacenamiento con id \"%i\"",
+ "Invalid backend or authentication mechanism class" : "Sistema o mecanismo de autentificación inválido",
"Invalid mount point" : "Punto de montaje no válido",
+ "Objectstore forbidden" : "Objeto de almacenaje prohibido",
"Invalid storage backend \"%s\"" : "Motor de almacenamiento no válido «%s»",
- "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autenticación \"%s\"",
+ "Not permitted to use backend \"%s\"" : "No se permite usar el mecanismo \"%s\"",
+ "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autentificación \"%s\"",
+ "Unsatisfied backend parameters" : "Los parámetros del sistema no son válidos",
+ "Unsatisfied authentication mechanism parameters" : "Los parámetros del mecanismo de autentificación no son válidos",
+ "Insufficient data: %s" : "Datos insuficientes: %s",
+ "%s" : "%s",
"Personal" : "Personal",
"System" : "Sistema",
"Grant access" : "Conceder acceso",
@@ -19,12 +29,21 @@
"Check for changes" : "Comprobar si hay cambios",
"Never" : "Nunca",
"Once every direct access" : "Una vez cada acceso directo",
- "Every time the filesystem is used" : "Cada vez que filesystem es utilizado",
"All users. Type to select user or group." : "Todos los usuarios. Teclee para seleccionar un usuario o grupo.",
"(group)" : "(grupo)",
+ "Admin defined" : "Admin definido",
"Saved" : "Guardado",
+ "Empty response from the server" : "Respuesta vacía desde el servidor",
+ "Couldn't access. Please logout and login to activate this mount point" : "No se puede acceder. Por favor cierra sesión e iníciala de nuevo para activar este punto de montaje",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "No se puede obtener información acerca del servidor de OwnCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "No se puede obtener la lista de los puntos de montaje externos: {type}",
+ "There was an error with message: " : "Hubo un error con el mensaje:",
+ "External mount error" : "Error de montaje externo",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "No se puede obtener la lista de unidades de red y sus puntos de montaje de Windows: respuesta vacía desde el servidor",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Algunos de los puntos de montaje externos configurados no están conectados. Por favor, haga clic en la fila roja (s) para obtener más información",
"Access key" : "Clave de acceso",
"Secret key" : "Clave secreta",
+ "Builtin" : "Incorporado",
"None" : "Ninguno",
"OAuth1" : "OAuth1",
"App key" : "App principal",
@@ -32,12 +51,14 @@
"OAuth2" : "OAuth2",
"Client ID" : "ID de Cliente",
"Client secret" : "Cliente secreto",
+ "OpenStack" : "OpenStack",
"Username" : "Nombre de usuario",
"Password" : "Contraseña",
"Tenant name" : "Nombre del inquilino",
+ "Identity endpoint URL" : "Identidad de punto final URL",
+ "Rackspace" : "Espacio de Rack",
"API key" : "Clave API",
"Username and password" : "Nombre de usuario y contraseña",
- "Session credentials" : "Credenciales de la sesión",
"RSA public key" : "Clave pública RSA",
"Public key" : "Clave pública",
"Amazon S3" : "Amazon S3",
@@ -69,6 +90,7 @@
"Username as share" : "Nombre de usuario como compartir",
"OpenStack Object Storage" : "Almacenamiento de objeto OpenStack",
"Service name" : "Nombre del servicio",
+ "Request timeout (seconds)" : "Tiempo agotado para petición (segundos)",
"<b>Note:</b> " : "<b>Nota:</b> ",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Nota:</b> El soporte de cURL en PHP no está activado o instalado. No se puede montar %s. Pídale al administrador del sistema que lo instale.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Nota:</b> El soporte de FTP en PHP no está activado o instalado. No se puede montar %s. Pídale al administrador del sistema que lo instale.",
@@ -80,12 +102,13 @@
"Scope" : "Ámbito",
"External Storage" : "Almacenamiento externo",
"Folder name" : "Nombre de la carpeta",
- "Authentication" : "Autenticación",
+ "Authentication" : "Autentificación",
"Configuration" : "Configuración",
"Available for" : "Disponible para",
+ "Add storage" : "Añadir almacenamiento",
"Advanced settings" : "Configuración avanzada",
"Delete" : "Eliminar",
- "Add storage" : "Añadir almacenamiento",
+ "Allow users to mount external storage" : "Permitir a los usuarios montar un almacenamiento externo",
"Allow users to mount the following external storage" : "Permitir a los usuarios montar el siguiente almacenamiento externo"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/es_AR.js b/apps/files_external/l10n/es_AR.js
index fd242104c8c..7fb87f1a1d3 100644
--- a/apps/files_external/l10n/es_AR.js
+++ b/apps/files_external/l10n/es_AR.js
@@ -22,7 +22,7 @@ OC.L10N.register(
"External Storage" : "Almacenamiento externo",
"Folder name" : "Nombre de la carpeta",
"Configuration" : "Configuración",
- "Delete" : "Borrar",
- "Add storage" : "Añadir almacenamiento"
+ "Add storage" : "Añadir almacenamiento",
+ "Delete" : "Borrar"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/es_AR.json b/apps/files_external/l10n/es_AR.json
index d9e91a3af47..9fb735f7a3a 100644
--- a/apps/files_external/l10n/es_AR.json
+++ b/apps/files_external/l10n/es_AR.json
@@ -20,7 +20,7 @@
"External Storage" : "Almacenamiento externo",
"Folder name" : "Nombre de la carpeta",
"Configuration" : "Configuración",
- "Delete" : "Borrar",
- "Add storage" : "Añadir almacenamiento"
+ "Add storage" : "Añadir almacenamiento",
+ "Delete" : "Borrar"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/es_MX.js b/apps/files_external/l10n/es_MX.js
index 9682e360a58..c805ce16662 100644
--- a/apps/files_external/l10n/es_MX.js
+++ b/apps/files_external/l10n/es_MX.js
@@ -21,7 +21,7 @@ OC.L10N.register(
"External Storage" : "Almacenamiento externo",
"Folder name" : "Nombre de la carpeta",
"Configuration" : "Configuración",
- "Delete" : "Eliminar",
- "Add storage" : "Añadir almacenamiento"
+ "Add storage" : "Añadir almacenamiento",
+ "Delete" : "Eliminar"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/es_MX.json b/apps/files_external/l10n/es_MX.json
index 81b2f408d11..1df9bf70436 100644
--- a/apps/files_external/l10n/es_MX.json
+++ b/apps/files_external/l10n/es_MX.json
@@ -19,7 +19,7 @@
"External Storage" : "Almacenamiento externo",
"Folder name" : "Nombre de la carpeta",
"Configuration" : "Configuración",
- "Delete" : "Eliminar",
- "Add storage" : "Añadir almacenamiento"
+ "Add storage" : "Añadir almacenamiento",
+ "Delete" : "Eliminar"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/et_EE.js b/apps/files_external/l10n/et_EE.js
index ae66daa37a6..989ff604952 100644
--- a/apps/files_external/l10n/et_EE.js
+++ b/apps/files_external/l10n/et_EE.js
@@ -7,10 +7,14 @@ OC.L10N.register(
"Storage with id \"%i\" not found" : "Salvestuskohta ID-ga \"%i\" ei leitud",
"Invalid mount point" : "Vigane ühenduspunkt",
"Invalid storage backend \"%s\"" : "Vigane salvestuskoha taustsüsteem \"%s\"",
+ "Unsatisfied backend parameters" : "Rahuldamata taustarakenduse parameetrid",
+ "%s" : "%s",
"Personal" : "Isiklik",
"System" : "Süsteem",
"Grant access" : "Anna ligipääs",
"Access granted" : "Ligipääs on antud",
+ "Error configuring OAuth1" : "OAuth1 seadistamise tõrge",
+ "Error configuring OAuth2" : "OAuth2 seadistamise tõrge",
"Generate keys" : "Loo võtmed",
"Error generating key pair" : "Viga võtmepaari loomisel",
"Enable encryption" : "Luba krüpteerimine",
@@ -18,21 +22,28 @@ OC.L10N.register(
"Check for changes" : "Otsi uuendusi",
"Never" : "Mitte kunagi",
"Once every direct access" : "Kord iga otsese pöördumise korral",
- "Every time the filesystem is used" : "Iga kord, kui failisüsteemi kasutatakse",
"All users. Type to select user or group." : "Kõik kasutajad. Kirjuta, et valida kasutaja või grupp.",
"(group)" : "(grupp)",
+ "Admin defined" : "Admini poolt määratud",
"Saved" : "Salvestatud",
+ "Couldn't get the list of external mount points: {type}" : "Välise ühenduspunkti hankimine ebaõnnestus: {type}",
+ "There was an error with message: " : "Sõnumiga tekkis tõrge:",
+ "External mount error" : "Välise seostamise tõrge",
+ "Access key" : "Ligipääsuvõti",
+ "Secret key" : "Salavõti",
"Builtin" : "Sisseehitatud",
"None" : "Pole",
"OAuth1" : "OAuth1",
"App key" : "Rakenduse võti",
"App secret" : "Rakenduse salasõna",
+ "OAuth2" : "OAuth2",
"Client ID" : "Kliendi ID",
"Client secret" : "Kliendi salasõna",
"OpenStack" : "OpenStack",
"Username" : "Kasutajanimi",
"Password" : "Parool",
"API key" : "API võti",
+ "RSA public key" : "RSA avalik võti",
"Public key" : "Avalik võti",
"Amazon S3" : "Amazon S3",
"Bucket" : "Korv",
@@ -77,9 +88,9 @@ OC.L10N.register(
"Authentication" : "Autentimine",
"Configuration" : "Seadistamine",
"Available for" : "Saadaval",
+ "Add storage" : "Lisa andmehoidla",
"Advanced settings" : "Lisavalikud",
"Delete" : "Kustuta",
- "Add storage" : "Lisa andmehoidla",
"Allow users to mount the following external storage" : "Võimalda kasutajatel ühendada järgmist välist andmehoidlat"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/et_EE.json b/apps/files_external/l10n/et_EE.json
index f2cc31e46e1..ad8e87e55f9 100644
--- a/apps/files_external/l10n/et_EE.json
+++ b/apps/files_external/l10n/et_EE.json
@@ -5,10 +5,14 @@
"Storage with id \"%i\" not found" : "Salvestuskohta ID-ga \"%i\" ei leitud",
"Invalid mount point" : "Vigane ühenduspunkt",
"Invalid storage backend \"%s\"" : "Vigane salvestuskoha taustsüsteem \"%s\"",
+ "Unsatisfied backend parameters" : "Rahuldamata taustarakenduse parameetrid",
+ "%s" : "%s",
"Personal" : "Isiklik",
"System" : "Süsteem",
"Grant access" : "Anna ligipääs",
"Access granted" : "Ligipääs on antud",
+ "Error configuring OAuth1" : "OAuth1 seadistamise tõrge",
+ "Error configuring OAuth2" : "OAuth2 seadistamise tõrge",
"Generate keys" : "Loo võtmed",
"Error generating key pair" : "Viga võtmepaari loomisel",
"Enable encryption" : "Luba krüpteerimine",
@@ -16,21 +20,28 @@
"Check for changes" : "Otsi uuendusi",
"Never" : "Mitte kunagi",
"Once every direct access" : "Kord iga otsese pöördumise korral",
- "Every time the filesystem is used" : "Iga kord, kui failisüsteemi kasutatakse",
"All users. Type to select user or group." : "Kõik kasutajad. Kirjuta, et valida kasutaja või grupp.",
"(group)" : "(grupp)",
+ "Admin defined" : "Admini poolt määratud",
"Saved" : "Salvestatud",
+ "Couldn't get the list of external mount points: {type}" : "Välise ühenduspunkti hankimine ebaõnnestus: {type}",
+ "There was an error with message: " : "Sõnumiga tekkis tõrge:",
+ "External mount error" : "Välise seostamise tõrge",
+ "Access key" : "Ligipääsuvõti",
+ "Secret key" : "Salavõti",
"Builtin" : "Sisseehitatud",
"None" : "Pole",
"OAuth1" : "OAuth1",
"App key" : "Rakenduse võti",
"App secret" : "Rakenduse salasõna",
+ "OAuth2" : "OAuth2",
"Client ID" : "Kliendi ID",
"Client secret" : "Kliendi salasõna",
"OpenStack" : "OpenStack",
"Username" : "Kasutajanimi",
"Password" : "Parool",
"API key" : "API võti",
+ "RSA public key" : "RSA avalik võti",
"Public key" : "Avalik võti",
"Amazon S3" : "Amazon S3",
"Bucket" : "Korv",
@@ -75,9 +86,9 @@
"Authentication" : "Autentimine",
"Configuration" : "Seadistamine",
"Available for" : "Saadaval",
+ "Add storage" : "Lisa andmehoidla",
"Advanced settings" : "Lisavalikud",
"Delete" : "Kustuta",
- "Add storage" : "Lisa andmehoidla",
"Allow users to mount the following external storage" : "Võimalda kasutajatel ühendada järgmist välist andmehoidlat"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/eu.js b/apps/files_external/l10n/eu.js
index 599229a92b3..58742552e76 100644
--- a/apps/files_external/l10n/eu.js
+++ b/apps/files_external/l10n/eu.js
@@ -52,8 +52,8 @@ OC.L10N.register(
"Folder name" : "Karpetaren izena",
"Configuration" : "Konfigurazioa",
"Available for" : "Hauentzat eskuragarri",
- "Delete" : "Ezabatu",
"Add storage" : "Gehitu biltegiratzea",
+ "Delete" : "Ezabatu",
"Allow users to mount the following external storage" : "Baimendu erabiltzaileak hurrengo kanpo biltegiratzeak muntatzen"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/eu.json b/apps/files_external/l10n/eu.json
index 5a568893060..f039441b464 100644
--- a/apps/files_external/l10n/eu.json
+++ b/apps/files_external/l10n/eu.json
@@ -50,8 +50,8 @@
"Folder name" : "Karpetaren izena",
"Configuration" : "Konfigurazioa",
"Available for" : "Hauentzat eskuragarri",
- "Delete" : "Ezabatu",
"Add storage" : "Gehitu biltegiratzea",
+ "Delete" : "Ezabatu",
"Allow users to mount the following external storage" : "Baimendu erabiltzaileak hurrengo kanpo biltegiratzeak muntatzen"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/fa.js b/apps/files_external/l10n/fa.js
index a18f7cdcf5c..0c1076fc994 100644
--- a/apps/files_external/l10n/fa.js
+++ b/apps/files_external/l10n/fa.js
@@ -57,8 +57,8 @@ OC.L10N.register(
"Authentication" : "احراز هویت",
"Configuration" : "پیکربندی",
"Available for" : "در دسترس برای",
+ "Add storage" : "اضافه کردن حافظه",
"Advanced settings" : "تنظیمات پیشرفته",
- "Delete" : "حذف",
- "Add storage" : "اضافه کردن حافظه"
+ "Delete" : "حذف"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_external/l10n/fa.json b/apps/files_external/l10n/fa.json
index 4bc16f72f54..056bad259a6 100644
--- a/apps/files_external/l10n/fa.json
+++ b/apps/files_external/l10n/fa.json
@@ -55,8 +55,8 @@
"Authentication" : "احراز هویت",
"Configuration" : "پیکربندی",
"Available for" : "در دسترس برای",
+ "Add storage" : "اضافه کردن حافظه",
"Advanced settings" : "تنظیمات پیشرفته",
- "Delete" : "حذف",
- "Add storage" : "اضافه کردن حافظه"
+ "Delete" : "حذف"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/fi_FI.js b/apps/files_external/l10n/fi_FI.js
index f91dec93310..ec969586d6d 100644
--- a/apps/files_external/l10n/fi_FI.js
+++ b/apps/files_external/l10n/fi_FI.js
@@ -6,6 +6,7 @@ OC.L10N.register(
"External storage" : "Ulkoinen tallennustila",
"Storage with id \"%i\" not found" : "Tallennustilaa tunnisteella \"%i\" ei löytynyt",
"Invalid mount point" : "Virheellinen liitoskohta",
+ "%s" : "%s",
"Personal" : "Henkilökohtainen",
"System" : "Järjestelmä",
"Grant access" : "Salli pääsy",
@@ -19,10 +20,18 @@ OC.L10N.register(
"Check for changes" : "Tarkista muutokset",
"Never" : "Ei koskaan",
"Once every direct access" : "Kerran aina suoran käytön yhteydessä",
- "Every time the filesystem is used" : "Aina kun tiedostojärjestelmää käytetään",
"All users. Type to select user or group." : "Kaikki käyttäjät. Kirjoita valitaksesi käyttäjän tai ryhmän.",
"(group)" : "(ryhmä)",
+ "Admin defined" : "Ylläpitäjän määrittämä",
"Saved" : "Tallennettu",
+ "Empty response from the server" : "Tyhjä vastaus palvelimelta",
+ "Couldn't access. Please logout and login to activate this mount point" : "Käyttö epäonnistui. Kirjaudu ulos ja takaisin sisään aktivoidaksesi tämän liitospisteen",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Tietojen saaminen ownCloud-palvelimelta epäonnistui: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Erillisten liitospisteiden listauksen noutaminen epäonnistui: {type}",
+ "There was an error with message: " : "Tapahtui virhe viestillä:",
+ "External mount error" : "Ulkoinen liitosvirhe",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Windows-verkkoasemien liitospisteiden listauksen noutaminen epäonnistui: tyhjä vastaus palvelimelta",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Jotkin määritetyt erilliset liitospisteet eivät ole yhdistettynä. Napsauta punaisia rivejä saadaksesi lisätietoja",
"Builtin" : "Sisäänrakennettu",
"None" : "Ei mitään",
"OAuth1" : "OAuth1",
@@ -36,7 +45,10 @@ OC.L10N.register(
"Password" : "Salasana",
"Rackspace" : "Rackspace",
"API key" : "API-avain",
+ "Log-in credentials, save in database" : "Kirjautumistiedot, tallenna tietokantaan",
"Username and password" : "Käyttäjätunnus ja salasana",
+ "Log-in credentials, save in session" : "Kirjautumistiedot, tallenna istuntoon",
+ "User entered, store in database" : "Käyttäjän määrittämä, tallenna tietokantaan",
"RSA public key" : "Julkinen RSA-avain",
"Public key" : "Julkinen avain",
"Amazon S3" : "Amazon S3",
@@ -56,6 +68,7 @@ OC.L10N.register(
"Location" : "Sijainti",
"ownCloud" : "ownCloud",
"SFTP" : "SFTP",
+ "SFTP with secret key login" : "SFTP salaisen avaimen kirjautumisella",
"SMB / CIFS" : "SMB / CIFS",
"Share" : "Jaa",
"SMB / CIFS using OC login" : "SMB / CIFS käyttäen OC-kirjautumista",
@@ -76,9 +89,9 @@ OC.L10N.register(
"Authentication" : "Tunnistautuminen",
"Configuration" : "Asetukset",
"Available for" : "Saatavuus",
+ "Add storage" : "Lisää tallennustila",
"Advanced settings" : "Lisäasetukset",
"Delete" : "Poista",
- "Add storage" : "Lisää tallennustila",
"Allow users to mount external storage" : "Salli käyttäjien liittää erillisiä tallennustiloja",
"Allow users to mount the following external storage" : "Salli käyttäjien liittää seuraavat erilliset tallennusvälineet"
},
diff --git a/apps/files_external/l10n/fi_FI.json b/apps/files_external/l10n/fi_FI.json
index a2033b4c578..8c39acff034 100644
--- a/apps/files_external/l10n/fi_FI.json
+++ b/apps/files_external/l10n/fi_FI.json
@@ -4,6 +4,7 @@
"External storage" : "Ulkoinen tallennustila",
"Storage with id \"%i\" not found" : "Tallennustilaa tunnisteella \"%i\" ei löytynyt",
"Invalid mount point" : "Virheellinen liitoskohta",
+ "%s" : "%s",
"Personal" : "Henkilökohtainen",
"System" : "Järjestelmä",
"Grant access" : "Salli pääsy",
@@ -17,10 +18,18 @@
"Check for changes" : "Tarkista muutokset",
"Never" : "Ei koskaan",
"Once every direct access" : "Kerran aina suoran käytön yhteydessä",
- "Every time the filesystem is used" : "Aina kun tiedostojärjestelmää käytetään",
"All users. Type to select user or group." : "Kaikki käyttäjät. Kirjoita valitaksesi käyttäjän tai ryhmän.",
"(group)" : "(ryhmä)",
+ "Admin defined" : "Ylläpitäjän määrittämä",
"Saved" : "Tallennettu",
+ "Empty response from the server" : "Tyhjä vastaus palvelimelta",
+ "Couldn't access. Please logout and login to activate this mount point" : "Käyttö epäonnistui. Kirjaudu ulos ja takaisin sisään aktivoidaksesi tämän liitospisteen",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Tietojen saaminen ownCloud-palvelimelta epäonnistui: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Erillisten liitospisteiden listauksen noutaminen epäonnistui: {type}",
+ "There was an error with message: " : "Tapahtui virhe viestillä:",
+ "External mount error" : "Ulkoinen liitosvirhe",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Windows-verkkoasemien liitospisteiden listauksen noutaminen epäonnistui: tyhjä vastaus palvelimelta",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Jotkin määritetyt erilliset liitospisteet eivät ole yhdistettynä. Napsauta punaisia rivejä saadaksesi lisätietoja",
"Builtin" : "Sisäänrakennettu",
"None" : "Ei mitään",
"OAuth1" : "OAuth1",
@@ -34,7 +43,10 @@
"Password" : "Salasana",
"Rackspace" : "Rackspace",
"API key" : "API-avain",
+ "Log-in credentials, save in database" : "Kirjautumistiedot, tallenna tietokantaan",
"Username and password" : "Käyttäjätunnus ja salasana",
+ "Log-in credentials, save in session" : "Kirjautumistiedot, tallenna istuntoon",
+ "User entered, store in database" : "Käyttäjän määrittämä, tallenna tietokantaan",
"RSA public key" : "Julkinen RSA-avain",
"Public key" : "Julkinen avain",
"Amazon S3" : "Amazon S3",
@@ -54,6 +66,7 @@
"Location" : "Sijainti",
"ownCloud" : "ownCloud",
"SFTP" : "SFTP",
+ "SFTP with secret key login" : "SFTP salaisen avaimen kirjautumisella",
"SMB / CIFS" : "SMB / CIFS",
"Share" : "Jaa",
"SMB / CIFS using OC login" : "SMB / CIFS käyttäen OC-kirjautumista",
@@ -74,9 +87,9 @@
"Authentication" : "Tunnistautuminen",
"Configuration" : "Asetukset",
"Available for" : "Saatavuus",
+ "Add storage" : "Lisää tallennustila",
"Advanced settings" : "Lisäasetukset",
"Delete" : "Poista",
- "Add storage" : "Lisää tallennustila",
"Allow users to mount external storage" : "Salli käyttäjien liittää erillisiä tallennustiloja",
"Allow users to mount the following external storage" : "Salli käyttäjien liittää seuraavat erilliset tallennusvälineet"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/files_external/l10n/fr.js b/apps/files_external/l10n/fr.js
index 1389cd1233b..cc1c1bc693c 100644
--- a/apps/files_external/l10n/fr.js
+++ b/apps/files_external/l10n/fr.js
@@ -17,6 +17,8 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "Paramètres manquants pour le service",
"Unsatisfied authentication mechanism parameters" : "Paramètres manquants pour la méthode d'authentification",
"Insufficient data: %s" : "Données insuffisantes : %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Le support de stockage d'id \"%i\" n'est pas modifiable par les utilisateurs",
"Personal" : "Personnel",
"System" : "Système",
"Grant access" : "Autoriser l'accès",
@@ -30,10 +32,18 @@ OC.L10N.register(
"Check for changes" : "Rechercher les modifications",
"Never" : "Jamais",
"Once every direct access" : "Une fois à chaque accès direct",
- "Every time the filesystem is used" : "Chaque fois que le système de fichiers est utilisé",
"All users. Type to select user or group." : "Tous les utilisateurs. Cliquez ici pour restreindre.",
"(group)" : "(groupe)",
+ "Admin defined" : "Défini par l'administrateur",
"Saved" : "Sauvegardé",
+ "Empty response from the server" : "Réponse vide du serveur",
+ "Couldn't access. Please logout and login to activate this mount point" : "Impossible d'accéder. Veuillez vous déconnecter et vous reconnecter pour activer ce point de montage.",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Impossible d'obtenir l'information depuis le serveur ownCloud : {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Impossible de récupérer la liste des points de montage externes : {type}",
+ "There was an error with message: " : "Il y a eu une erreur avec le message :",
+ "External mount error" : "Erreur de point de montage externe",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Impossible d'obtenir la liste des points de montage des disques réseaux Windows : Réponse vide du serveur",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Certains points de montage externes configurés ne sont pas connectés. Veuillez cliquer sur la(les) ligne(s) rouge(s) pour plus d'informations",
"Access key" : "Clé d'accès",
"Secret key" : "Clé secrète",
"Builtin" : "Intégré",
@@ -52,7 +62,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "Clé API",
"Username and password" : "Nom d'utilisateur et mot de passe",
- "Session credentials" : "Informations d'identification de session",
"RSA public key" : "Clé publique RSA",
"Public key" : "Clef publique",
"Amazon S3" : "Amazon S3",
@@ -99,9 +108,9 @@ OC.L10N.register(
"Authentication" : "Authentification",
"Configuration" : "Configuration",
"Available for" : "Disponible pour",
+ "Add storage" : "Ajouter un support de stockage",
"Advanced settings" : "Paramètres avancés",
"Delete" : "Supprimer",
- "Add storage" : "Ajouter un support de stockage",
"Allow users to mount external storage" : "Autoriser les utilisateurs à monter des espaces de stockage externes",
"Allow users to mount the following external storage" : "Autoriser les utilisateurs à monter les stockages externes suivants"
},
diff --git a/apps/files_external/l10n/fr.json b/apps/files_external/l10n/fr.json
index 9d078bf13fc..47a70fcd12a 100644
--- a/apps/files_external/l10n/fr.json
+++ b/apps/files_external/l10n/fr.json
@@ -15,6 +15,8 @@
"Unsatisfied backend parameters" : "Paramètres manquants pour le service",
"Unsatisfied authentication mechanism parameters" : "Paramètres manquants pour la méthode d'authentification",
"Insufficient data: %s" : "Données insuffisantes : %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Le support de stockage d'id \"%i\" n'est pas modifiable par les utilisateurs",
"Personal" : "Personnel",
"System" : "Système",
"Grant access" : "Autoriser l'accès",
@@ -28,10 +30,18 @@
"Check for changes" : "Rechercher les modifications",
"Never" : "Jamais",
"Once every direct access" : "Une fois à chaque accès direct",
- "Every time the filesystem is used" : "Chaque fois que le système de fichiers est utilisé",
"All users. Type to select user or group." : "Tous les utilisateurs. Cliquez ici pour restreindre.",
"(group)" : "(groupe)",
+ "Admin defined" : "Défini par l'administrateur",
"Saved" : "Sauvegardé",
+ "Empty response from the server" : "Réponse vide du serveur",
+ "Couldn't access. Please logout and login to activate this mount point" : "Impossible d'accéder. Veuillez vous déconnecter et vous reconnecter pour activer ce point de montage.",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Impossible d'obtenir l'information depuis le serveur ownCloud : {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Impossible de récupérer la liste des points de montage externes : {type}",
+ "There was an error with message: " : "Il y a eu une erreur avec le message :",
+ "External mount error" : "Erreur de point de montage externe",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Impossible d'obtenir la liste des points de montage des disques réseaux Windows : Réponse vide du serveur",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Certains points de montage externes configurés ne sont pas connectés. Veuillez cliquer sur la(les) ligne(s) rouge(s) pour plus d'informations",
"Access key" : "Clé d'accès",
"Secret key" : "Clé secrète",
"Builtin" : "Intégré",
@@ -50,7 +60,6 @@
"Rackspace" : "Rackspace",
"API key" : "Clé API",
"Username and password" : "Nom d'utilisateur et mot de passe",
- "Session credentials" : "Informations d'identification de session",
"RSA public key" : "Clé publique RSA",
"Public key" : "Clef publique",
"Amazon S3" : "Amazon S3",
@@ -97,9 +106,9 @@
"Authentication" : "Authentification",
"Configuration" : "Configuration",
"Available for" : "Disponible pour",
+ "Add storage" : "Ajouter un support de stockage",
"Advanced settings" : "Paramètres avancés",
"Delete" : "Supprimer",
- "Add storage" : "Ajouter un support de stockage",
"Allow users to mount external storage" : "Autoriser les utilisateurs à monter des espaces de stockage externes",
"Allow users to mount the following external storage" : "Autoriser les utilisateurs à monter les stockages externes suivants"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
diff --git a/apps/files_external/l10n/gl.js b/apps/files_external/l10n/gl.js
index 5827a6ab57f..26e54ee7453 100644
--- a/apps/files_external/l10n/gl.js
+++ b/apps/files_external/l10n/gl.js
@@ -18,7 +18,6 @@ OC.L10N.register(
"Check for changes" : "Comprobar se hai cambios",
"Never" : "Nunca",
"Once every direct access" : "Unha vez cada acceso directo",
- "Every time the filesystem is used" : "Cada vez que se utiliza o sistema de ficheiros",
"All users. Type to select user or group." : "Todos os usuarios. Escriba para seleccionar usuario ou grupo.",
"(group)" : "(grupo)",
"Saved" : "Gardado",
@@ -67,9 +66,9 @@ OC.L10N.register(
"Folder name" : "Nome do cartafol",
"Configuration" : "Configuración",
"Available for" : "Dispoñíbel para",
+ "Add storage" : "Engadir almacenamento",
"Advanced settings" : "Axustes avanzados",
"Delete" : "Eliminar",
- "Add storage" : "Engadir almacenamento",
"Allow users to mount the following external storage" : "Permitirlle aos usuarios montar o seguinte almacenamento externo"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/gl.json b/apps/files_external/l10n/gl.json
index 29dde23c329..e9be28bfa18 100644
--- a/apps/files_external/l10n/gl.json
+++ b/apps/files_external/l10n/gl.json
@@ -16,7 +16,6 @@
"Check for changes" : "Comprobar se hai cambios",
"Never" : "Nunca",
"Once every direct access" : "Unha vez cada acceso directo",
- "Every time the filesystem is used" : "Cada vez que se utiliza o sistema de ficheiros",
"All users. Type to select user or group." : "Todos os usuarios. Escriba para seleccionar usuario ou grupo.",
"(group)" : "(grupo)",
"Saved" : "Gardado",
@@ -65,9 +64,9 @@
"Folder name" : "Nome do cartafol",
"Configuration" : "Configuración",
"Available for" : "Dispoñíbel para",
+ "Add storage" : "Engadir almacenamento",
"Advanced settings" : "Axustes avanzados",
"Delete" : "Eliminar",
- "Add storage" : "Engadir almacenamento",
"Allow users to mount the following external storage" : "Permitirlle aos usuarios montar o seguinte almacenamento externo"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/he.js b/apps/files_external/l10n/he.js
index 613f2688ee4..20b61065241 100644
--- a/apps/files_external/l10n/he.js
+++ b/apps/files_external/l10n/he.js
@@ -1,26 +1,121 @@
OC.L10N.register(
"files_external",
{
+ "Fetching request tokens failed. Verify that your app key and secret are correct." : "אחזור מחרוזת כניסה נכשל. יש לוודא שמפתח היישום והסוד נכונים.",
+ "Fetching access tokens failed. Verify that your app key and secret are correct." : "אחזור מחרוזת כניסה נכשל. יש לוודא שמפתח היישום והסוד נכונים.",
+ "Please provide a valid app key and secret." : "יש לספק מפתח יישום וסוד תקניים.",
+ "Step 1 failed. Exception: %s" : "שלב 1 נכשל. חריג: %s",
+ "Step 2 failed. Exception: %s" : "שלב 2 נכשל. חריג: %s",
+ "External storage" : "אחסון חיצוני",
+ "Storage with id \"%i\" not found" : "אחסון עם מספר זיהוי \"%i\" לא אותר",
+ "Invalid backend or authentication mechanism class" : "צד אחורי או סוג מנגנון אימות לא חוקי",
+ "Invalid mount point" : "נקודת עגינה לא חוקית",
+ "Objectstore forbidden" : "Objectstore חסום",
+ "Invalid storage backend \"%s\"" : "צד אחורי של האחסון אינו תקין \"%s\"",
+ "Not permitted to use backend \"%s\"" : "השימוש בצד אחורי \"%s\" אינו מותר",
+ "Not permitted to use authentication mechanism \"%s\"" : "השימוש במכניזם אימות \"%s\" אינו מותר",
+ "Unsatisfied backend parameters" : "פרמטרים צד אחורי אינם מספקים",
+ "Unsatisfied authentication mechanism parameters" : "פרמטרים של מכניזם אימות אינם מספקים",
+ "Insufficient data: %s" : "מידע לא מספק: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "האחסון עם זהות \"%i\" לא ניתן לעריכה",
"Personal" : "אישי",
+ "System" : "מערכת",
"Grant access" : "הענקת גישה",
"Access granted" : "הוענקה גישה",
+ "Error configuring OAuth1" : "שגיאה בתצורת OAuth1",
+ "Error configuring OAuth2" : "שגיאה בתצורת OAuth2",
+ "Generate keys" : "יצירת מפתחות",
+ "Error generating key pair" : "שגיאה ביצירת זוג מפתחות",
+ "Enable encryption" : "אפשר הצפנה",
+ "Enable previews" : "מאפשר תצוגות מקדימות",
+ "Enable sharing" : "הפעלת שיתוף",
+ "Check for changes" : "בדיקה אחר שינויים",
+ "Never" : "לעולם לא",
+ "Once every direct access" : "פעם אחת כל כניסה ישירה",
+ "All users. Type to select user or group." : "כל המשתמשים. יש להקיש לבחירת משתמש או קבוצה.",
+ "(group)" : "(קבוצה)",
+ "Admin defined" : "הוגדר מנהל",
"Saved" : "נשמר",
+ "Empty response from the server" : "תגובה ריקה מהשרת",
+ "Couldn't access. Please logout and login to activate this mount point" : "לא ניתן להכנס. יש להתנתק ולהתחבר כדי להפעיל את נקודת העיגון הזו",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "לא ניתן היה לקבל את המידע משרת ה- ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "לא ניתן היה לקבל את רשימת נקודות העיגון החיצוניות: {type}",
+ "There was an error with message: " : "התרחשה שגיאה עם הודעה: ",
+ "External mount error" : "שגיאת עגינה חיצונית",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "לא ניתן היה לקבל את רשימת נקודות העיגון של כונן הרשת של Window: תגובה ריקה מהשרת",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "חלק מנקודות העיגון החיצוניות שהוגדרו אינן מחוברות. יש ללחוץ על השורה/ות האדומה/ות למידע נוסף",
+ "Access key" : "מפתח כניסה",
+ "Secret key" : "מפתח סודי",
+ "Builtin" : "מובנה",
"None" : "כלום",
+ "OAuth1" : "OAuth1",
+ "App key" : "מפתח יישום",
+ "App secret" : "סוד יישום",
+ "OAuth2" : "OAuth2",
+ "Client ID" : "זיהוי לקוח",
+ "Client secret" : "סוד לקוח",
+ "OpenStack" : "OpenStack",
"Username" : "שם משתמש",
"Password" : "סיסמא",
- "Port" : "פורט",
+ "Tenant name" : "שם דייר",
+ "Identity endpoint URL" : "זהות נתיב נקודת קצה",
+ "Rackspace" : "חץ אחורה",
+ "API key" : "מפתח API",
+ "Log-in credentials, save in database" : "אישורי התחברות, נשמרים במסד הנתונים",
+ "Username and password" : "שם משתמש וסיסמא",
+ "Log-in credentials, save in session" : "אישורי התחברות, נשמרים במידע שיחה - סשן",
+ "User entered, store in database" : "משתמש התחבר, נשמר במסד הנתונים",
+ "RSA public key" : "מפתח ציבורי RSA",
+ "Public key" : "מפתח ציבורי",
+ "Amazon S3" : "אמזון S3",
+ "Bucket" : "סל",
+ "Hostname" : "שם מארח",
+ "Port" : "שער",
"Region" : "אזור",
+ "Enable SSL" : "הפעלת SSL",
+ "Enable Path Style" : "אהפעלת סגנון נתיב",
"WebDAV" : "WebDAV",
- "URL" : "כתובת",
+ "URL" : "נתיב אינטרנט",
+ "Remote subfolder" : "תיקיית משנה רחוקה",
+ "Secure https://" : "פרוטוקול מאובטח https://",
+ "Dropbox" : "דרופבוקס",
+ "FTP" : "FTP",
"Host" : "מארח",
+ "Secure ftps://" : "פרוטוקול מאובטח ftps://",
+ "Google Drive" : "גוגל דרייב",
"Local" : "מקומי",
"Location" : "מיקום",
"ownCloud" : "ownCloud",
+ "SFTP" : "SFTP",
+ "Root" : "נתיב ראשי",
+ "SFTP with secret key login" : "SFTP עם מפתח כניסה סודי",
+ "SMB / CIFS" : "SMB / CIFS",
"Share" : "שיתוף",
+ "Domain" : "שם תחום",
+ "SMB / CIFS using OC login" : "SMB / CIFS בשימוש עם כניסת OC",
+ "Username as share" : "שם משתמש כשיתוף",
+ "OpenStack Object Storage" : "אחסון אובייקט OpenStack",
+ "Service name" : "שם שירות",
+ "Request timeout (seconds)" : "פסק זמן מבוקש (שניות)",
+ "<b>Note:</b> " : "<b>הערה:</b> ",
+ "<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>הערה:</b> תמיכת ה- cURL ב- PHP אינה מופעלת או מותקנת. חיבור של %s אינו אפשרי. יש לבקש ממנהל המערכת להתקין אותה.",
+ "<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>הערה:</b> תמיכת ה- FTP ב- PHP אינה מופעלת או מותקנת. חיבור של %s אינו אפשרי. יש לבקש ממנהל המערכת להתקין אותה.",
+ "<b>Note:</b> \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>הערה:</b> \"%s\" אינו מותקן. חיבור של %s אינו אפשרי. יש לבקש ממנהל המערכת להתקין אותה.",
+ "No external storage configured" : "לא מוגדר אחסון חיצוני",
+ "You can add external storages in the personal settings" : "ניתן להוסיף אחסונים חיצוניים בהגדרות האישיות",
"Name" : "שם",
+ "Storage type" : "סוג אחסון",
+ "Scope" : "היקף",
"External Storage" : "אחסון חיצוני",
"Folder name" : "שם התיקייה",
+ "Authentication" : "אימות",
"Configuration" : "הגדרות",
- "Delete" : "מחיקה"
+ "Available for" : "זמין עבור",
+ "Add storage" : "הוספת אחסון",
+ "Advanced settings" : "הגדרות מתקדמות",
+ "Delete" : "מחיקה",
+ "Allow users to mount external storage" : "מאפשר למשתמשים לחבר אחסון חיצוני",
+ "Allow users to mount the following external storage" : "מאפשר למשתמשים לחבר אחסון חיצוני הבא"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/he.json b/apps/files_external/l10n/he.json
index 928329f1d4e..5f4d4c46ac5 100644
--- a/apps/files_external/l10n/he.json
+++ b/apps/files_external/l10n/he.json
@@ -1,24 +1,119 @@
{ "translations": {
+ "Fetching request tokens failed. Verify that your app key and secret are correct." : "אחזור מחרוזת כניסה נכשל. יש לוודא שמפתח היישום והסוד נכונים.",
+ "Fetching access tokens failed. Verify that your app key and secret are correct." : "אחזור מחרוזת כניסה נכשל. יש לוודא שמפתח היישום והסוד נכונים.",
+ "Please provide a valid app key and secret." : "יש לספק מפתח יישום וסוד תקניים.",
+ "Step 1 failed. Exception: %s" : "שלב 1 נכשל. חריג: %s",
+ "Step 2 failed. Exception: %s" : "שלב 2 נכשל. חריג: %s",
+ "External storage" : "אחסון חיצוני",
+ "Storage with id \"%i\" not found" : "אחסון עם מספר זיהוי \"%i\" לא אותר",
+ "Invalid backend or authentication mechanism class" : "צד אחורי או סוג מנגנון אימות לא חוקי",
+ "Invalid mount point" : "נקודת עגינה לא חוקית",
+ "Objectstore forbidden" : "Objectstore חסום",
+ "Invalid storage backend \"%s\"" : "צד אחורי של האחסון אינו תקין \"%s\"",
+ "Not permitted to use backend \"%s\"" : "השימוש בצד אחורי \"%s\" אינו מותר",
+ "Not permitted to use authentication mechanism \"%s\"" : "השימוש במכניזם אימות \"%s\" אינו מותר",
+ "Unsatisfied backend parameters" : "פרמטרים צד אחורי אינם מספקים",
+ "Unsatisfied authentication mechanism parameters" : "פרמטרים של מכניזם אימות אינם מספקים",
+ "Insufficient data: %s" : "מידע לא מספק: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "האחסון עם זהות \"%i\" לא ניתן לעריכה",
"Personal" : "אישי",
+ "System" : "מערכת",
"Grant access" : "הענקת גישה",
"Access granted" : "הוענקה גישה",
+ "Error configuring OAuth1" : "שגיאה בתצורת OAuth1",
+ "Error configuring OAuth2" : "שגיאה בתצורת OAuth2",
+ "Generate keys" : "יצירת מפתחות",
+ "Error generating key pair" : "שגיאה ביצירת זוג מפתחות",
+ "Enable encryption" : "אפשר הצפנה",
+ "Enable previews" : "מאפשר תצוגות מקדימות",
+ "Enable sharing" : "הפעלת שיתוף",
+ "Check for changes" : "בדיקה אחר שינויים",
+ "Never" : "לעולם לא",
+ "Once every direct access" : "פעם אחת כל כניסה ישירה",
+ "All users. Type to select user or group." : "כל המשתמשים. יש להקיש לבחירת משתמש או קבוצה.",
+ "(group)" : "(קבוצה)",
+ "Admin defined" : "הוגדר מנהל",
"Saved" : "נשמר",
+ "Empty response from the server" : "תגובה ריקה מהשרת",
+ "Couldn't access. Please logout and login to activate this mount point" : "לא ניתן להכנס. יש להתנתק ולהתחבר כדי להפעיל את נקודת העיגון הזו",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "לא ניתן היה לקבל את המידע משרת ה- ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "לא ניתן היה לקבל את רשימת נקודות העיגון החיצוניות: {type}",
+ "There was an error with message: " : "התרחשה שגיאה עם הודעה: ",
+ "External mount error" : "שגיאת עגינה חיצונית",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "לא ניתן היה לקבל את רשימת נקודות העיגון של כונן הרשת של Window: תגובה ריקה מהשרת",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "חלק מנקודות העיגון החיצוניות שהוגדרו אינן מחוברות. יש ללחוץ על השורה/ות האדומה/ות למידע נוסף",
+ "Access key" : "מפתח כניסה",
+ "Secret key" : "מפתח סודי",
+ "Builtin" : "מובנה",
"None" : "כלום",
+ "OAuth1" : "OAuth1",
+ "App key" : "מפתח יישום",
+ "App secret" : "סוד יישום",
+ "OAuth2" : "OAuth2",
+ "Client ID" : "זיהוי לקוח",
+ "Client secret" : "סוד לקוח",
+ "OpenStack" : "OpenStack",
"Username" : "שם משתמש",
"Password" : "סיסמא",
- "Port" : "פורט",
+ "Tenant name" : "שם דייר",
+ "Identity endpoint URL" : "זהות נתיב נקודת קצה",
+ "Rackspace" : "חץ אחורה",
+ "API key" : "מפתח API",
+ "Log-in credentials, save in database" : "אישורי התחברות, נשמרים במסד הנתונים",
+ "Username and password" : "שם משתמש וסיסמא",
+ "Log-in credentials, save in session" : "אישורי התחברות, נשמרים במידע שיחה - סשן",
+ "User entered, store in database" : "משתמש התחבר, נשמר במסד הנתונים",
+ "RSA public key" : "מפתח ציבורי RSA",
+ "Public key" : "מפתח ציבורי",
+ "Amazon S3" : "אמזון S3",
+ "Bucket" : "סל",
+ "Hostname" : "שם מארח",
+ "Port" : "שער",
"Region" : "אזור",
+ "Enable SSL" : "הפעלת SSL",
+ "Enable Path Style" : "אהפעלת סגנון נתיב",
"WebDAV" : "WebDAV",
- "URL" : "כתובת",
+ "URL" : "נתיב אינטרנט",
+ "Remote subfolder" : "תיקיית משנה רחוקה",
+ "Secure https://" : "פרוטוקול מאובטח https://",
+ "Dropbox" : "דרופבוקס",
+ "FTP" : "FTP",
"Host" : "מארח",
+ "Secure ftps://" : "פרוטוקול מאובטח ftps://",
+ "Google Drive" : "גוגל דרייב",
"Local" : "מקומי",
"Location" : "מיקום",
"ownCloud" : "ownCloud",
+ "SFTP" : "SFTP",
+ "Root" : "נתיב ראשי",
+ "SFTP with secret key login" : "SFTP עם מפתח כניסה סודי",
+ "SMB / CIFS" : "SMB / CIFS",
"Share" : "שיתוף",
+ "Domain" : "שם תחום",
+ "SMB / CIFS using OC login" : "SMB / CIFS בשימוש עם כניסת OC",
+ "Username as share" : "שם משתמש כשיתוף",
+ "OpenStack Object Storage" : "אחסון אובייקט OpenStack",
+ "Service name" : "שם שירות",
+ "Request timeout (seconds)" : "פסק זמן מבוקש (שניות)",
+ "<b>Note:</b> " : "<b>הערה:</b> ",
+ "<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>הערה:</b> תמיכת ה- cURL ב- PHP אינה מופעלת או מותקנת. חיבור של %s אינו אפשרי. יש לבקש ממנהל המערכת להתקין אותה.",
+ "<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>הערה:</b> תמיכת ה- FTP ב- PHP אינה מופעלת או מותקנת. חיבור של %s אינו אפשרי. יש לבקש ממנהל המערכת להתקין אותה.",
+ "<b>Note:</b> \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>הערה:</b> \"%s\" אינו מותקן. חיבור של %s אינו אפשרי. יש לבקש ממנהל המערכת להתקין אותה.",
+ "No external storage configured" : "לא מוגדר אחסון חיצוני",
+ "You can add external storages in the personal settings" : "ניתן להוסיף אחסונים חיצוניים בהגדרות האישיות",
"Name" : "שם",
+ "Storage type" : "סוג אחסון",
+ "Scope" : "היקף",
"External Storage" : "אחסון חיצוני",
"Folder name" : "שם התיקייה",
+ "Authentication" : "אימות",
"Configuration" : "הגדרות",
- "Delete" : "מחיקה"
+ "Available for" : "זמין עבור",
+ "Add storage" : "הוספת אחסון",
+ "Advanced settings" : "הגדרות מתקדמות",
+ "Delete" : "מחיקה",
+ "Allow users to mount external storage" : "מאפשר למשתמשים לחבר אחסון חיצוני",
+ "Allow users to mount the following external storage" : "מאפשר למשתמשים לחבר אחסון חיצוני הבא"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/hr.js b/apps/files_external/l10n/hr.js
index 4ab71f76ffb..8c632eba518 100644
--- a/apps/files_external/l10n/hr.js
+++ b/apps/files_external/l10n/hr.js
@@ -50,8 +50,8 @@ OC.L10N.register(
"Folder name" : "Naziv mape",
"Configuration" : "Konfiguracija",
"Available for" : "Dostupno za",
- "Delete" : "Izbrišite",
"Add storage" : "Dodajte spremište",
+ "Delete" : "Izbrišite",
"Allow users to mount the following external storage" : "Dopustite korisnicima postavljanje sljedećeg vanjskog spremišta"
},
"nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;");
diff --git a/apps/files_external/l10n/hr.json b/apps/files_external/l10n/hr.json
index e8b8dcd3f61..610a42d46e2 100644
--- a/apps/files_external/l10n/hr.json
+++ b/apps/files_external/l10n/hr.json
@@ -48,8 +48,8 @@
"Folder name" : "Naziv mape",
"Configuration" : "Konfiguracija",
"Available for" : "Dostupno za",
- "Delete" : "Izbrišite",
"Add storage" : "Dodajte spremište",
+ "Delete" : "Izbrišite",
"Allow users to mount the following external storage" : "Dopustite korisnicima postavljanje sljedećeg vanjskog spremišta"
},"pluralForm" :"nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/hu_HU.js b/apps/files_external/l10n/hu_HU.js
index 0a307f8a609..4eb93dab872 100644
--- a/apps/files_external/l10n/hu_HU.js
+++ b/apps/files_external/l10n/hu_HU.js
@@ -2,19 +2,39 @@ OC.L10N.register(
"files_external",
{
"External storage" : "Külső tárolók",
+ "%s" : "%s",
"Personal" : "Személyes",
"System" : "Rendszer",
"Grant access" : "Megadom a hozzáférést",
"Access granted" : "Érvényes hozzáférés",
+ "Generate keys" : "Kulcsok generálása",
+ "Error generating key pair" : "Hiba történt a kulcspár generálása közben",
"Enable encryption" : "Titkosítás engedélyezése",
+ "Enable previews" : "Előnézet engedélyezése",
+ "Check for changes" : "Változások keresése",
+ "Never" : "Soha",
+ "Once every direct access" : "Minden közvetlen elérésnél",
+ "All users. Type to select user or group." : "Összes felhasználó. Írj be egy felhasználót vagy csoportot.",
"(group)" : "(csoport)",
+ "Admin defined" : "Adminisztrátor definiálva",
"Saved" : "Elmentve",
+ "Empty response from the server" : "Üres válasz a szervertől",
+ "Couldn't access. Please logout and login to activate this mount point" : "Nem férhető hozzá. Kérjük próbálj meg ki- és bejelentkezni a csatolási pont aktiválásához.",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Nem sikerült lekérdezni az információkat az ownCloud szerverről: {code} {type}",
+ "There was an error with message: " : "Hiba történt ezzel az üzenettel:",
+ "External mount error" : "Külső csatolási hiba",
+ "Access key" : "Hozzáférési kulcs",
+ "Secret key" : "Titkos kulcs",
"None" : "Egyik sem",
"App key" : "App kulcs",
"App secret" : "App titkos kulcs",
+ "Client secret" : "Kliens titkos",
"Username" : "Felhasználónév",
"Password" : "Jelszó",
"API key" : "API kulcs",
+ "Username and password" : "Felhasználónév és jelszó",
+ "RSA public key" : "RSA publikus kulcs",
+ "Public key" : "Publikus kulcs",
"Amazon S3" : "Amazon S3",
"Bucket" : "Bucket",
"Hostname" : "Hosztnév",
@@ -25,21 +45,41 @@ OC.L10N.register(
"URL" : "URL",
"Remote subfolder" : "Távoli alkönyvtár",
"Secure https://" : "Biztonságos https://",
+ "Dropbox" : "Dropbox",
+ "FTP" : "FTP",
"Host" : "Kiszolgáló",
"Secure ftps://" : "Biztonságos ftps://",
+ "Google Drive" : "Google Drive",
"Local" : "Helyi",
"Location" : "Hely",
"ownCloud" : "ownCloud",
+ "SFTP" : "SFTP",
+ "Root" : "Gyökér",
+ "SFTP with secret key login" : "SFTP titkos kulcs belépéssel",
+ "SMB / CIFS" : "SMB / CIFS",
"Share" : "Megosztás",
+ "Domain" : "Domain",
+ "SMB / CIFS using OC login" : "SMB / CIFS OC belépéssel",
"Username as share" : "Felhasználónév és megosztás",
+ "Service name" : "Szolgáltatás neve",
+ "Request timeout (seconds)" : "Időtúllépés (másodperc)",
"<b>Note:</b> " : "<b>Megjegyzés:</b>",
+ "<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Megjegyzés:</b> A cURL támogatás, a PHP-ban nincs engedélyezve vagy telepítve. %s csatolása lehetetlen. Kérd meg a rendszergazdádat, hogy telepítse.",
+ "<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Megjegyzés:</b> Az FTP támogatás, a PHP-ban nincs engedélyezve vagy telepítve. %s csatolása lehetetlen. Kérd meg a rendszergazdádat, hogy telepítse.",
+ "<b>Note:</b> \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Megjegyzés:</b> %s nincs telepítve. %s csatolása lehetetlen. Kérd meg a rendszergazdádat, hogy telepítse.",
+ "No external storage configured" : "Nincs külső tároló beállítva.",
+ "You can add external storages in the personal settings" : "Hozzáadhatsz külső tárolókat a személyes beállítások közt.",
"Name" : "Név",
"Storage type" : "Tároló típusa",
"External Storage" : "Külső tárolási szolgáltatások becsatolása",
"Folder name" : "Mappanév",
+ "Authentication" : "Azonisítás",
"Configuration" : "Beállítások",
"Available for" : "Elérhető számukra",
+ "Add storage" : "Tároló becsatolása",
+ "Advanced settings" : "Haladó beállítások",
"Delete" : "Törlés",
- "Add storage" : "Tároló becsatolása"
+ "Allow users to mount external storage" : "Külső tárolók engedélyezése a felhasználók részére",
+ "Allow users to mount the following external storage" : "A felhasználók számára engedélyezett külső tárolók:"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/hu_HU.json b/apps/files_external/l10n/hu_HU.json
index 4012c0eb490..bc50176e5a3 100644
--- a/apps/files_external/l10n/hu_HU.json
+++ b/apps/files_external/l10n/hu_HU.json
@@ -1,18 +1,38 @@
{ "translations": {
"External storage" : "Külső tárolók",
+ "%s" : "%s",
"Personal" : "Személyes",
"System" : "Rendszer",
"Grant access" : "Megadom a hozzáférést",
"Access granted" : "Érvényes hozzáférés",
+ "Generate keys" : "Kulcsok generálása",
+ "Error generating key pair" : "Hiba történt a kulcspár generálása közben",
"Enable encryption" : "Titkosítás engedélyezése",
+ "Enable previews" : "Előnézet engedélyezése",
+ "Check for changes" : "Változások keresése",
+ "Never" : "Soha",
+ "Once every direct access" : "Minden közvetlen elérésnél",
+ "All users. Type to select user or group." : "Összes felhasználó. Írj be egy felhasználót vagy csoportot.",
"(group)" : "(csoport)",
+ "Admin defined" : "Adminisztrátor definiálva",
"Saved" : "Elmentve",
+ "Empty response from the server" : "Üres válasz a szervertől",
+ "Couldn't access. Please logout and login to activate this mount point" : "Nem férhető hozzá. Kérjük próbálj meg ki- és bejelentkezni a csatolási pont aktiválásához.",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Nem sikerült lekérdezni az információkat az ownCloud szerverről: {code} {type}",
+ "There was an error with message: " : "Hiba történt ezzel az üzenettel:",
+ "External mount error" : "Külső csatolási hiba",
+ "Access key" : "Hozzáférési kulcs",
+ "Secret key" : "Titkos kulcs",
"None" : "Egyik sem",
"App key" : "App kulcs",
"App secret" : "App titkos kulcs",
+ "Client secret" : "Kliens titkos",
"Username" : "Felhasználónév",
"Password" : "Jelszó",
"API key" : "API kulcs",
+ "Username and password" : "Felhasználónév és jelszó",
+ "RSA public key" : "RSA publikus kulcs",
+ "Public key" : "Publikus kulcs",
"Amazon S3" : "Amazon S3",
"Bucket" : "Bucket",
"Hostname" : "Hosztnév",
@@ -23,21 +43,41 @@
"URL" : "URL",
"Remote subfolder" : "Távoli alkönyvtár",
"Secure https://" : "Biztonságos https://",
+ "Dropbox" : "Dropbox",
+ "FTP" : "FTP",
"Host" : "Kiszolgáló",
"Secure ftps://" : "Biztonságos ftps://",
+ "Google Drive" : "Google Drive",
"Local" : "Helyi",
"Location" : "Hely",
"ownCloud" : "ownCloud",
+ "SFTP" : "SFTP",
+ "Root" : "Gyökér",
+ "SFTP with secret key login" : "SFTP titkos kulcs belépéssel",
+ "SMB / CIFS" : "SMB / CIFS",
"Share" : "Megosztás",
+ "Domain" : "Domain",
+ "SMB / CIFS using OC login" : "SMB / CIFS OC belépéssel",
"Username as share" : "Felhasználónév és megosztás",
+ "Service name" : "Szolgáltatás neve",
+ "Request timeout (seconds)" : "Időtúllépés (másodperc)",
"<b>Note:</b> " : "<b>Megjegyzés:</b>",
+ "<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Megjegyzés:</b> A cURL támogatás, a PHP-ban nincs engedélyezve vagy telepítve. %s csatolása lehetetlen. Kérd meg a rendszergazdádat, hogy telepítse.",
+ "<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Megjegyzés:</b> Az FTP támogatás, a PHP-ban nincs engedélyezve vagy telepítve. %s csatolása lehetetlen. Kérd meg a rendszergazdádat, hogy telepítse.",
+ "<b>Note:</b> \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Megjegyzés:</b> %s nincs telepítve. %s csatolása lehetetlen. Kérd meg a rendszergazdádat, hogy telepítse.",
+ "No external storage configured" : "Nincs külső tároló beállítva.",
+ "You can add external storages in the personal settings" : "Hozzáadhatsz külső tárolókat a személyes beállítások közt.",
"Name" : "Név",
"Storage type" : "Tároló típusa",
"External Storage" : "Külső tárolási szolgáltatások becsatolása",
"Folder name" : "Mappanév",
+ "Authentication" : "Azonisítás",
"Configuration" : "Beállítások",
"Available for" : "Elérhető számukra",
+ "Add storage" : "Tároló becsatolása",
+ "Advanced settings" : "Haladó beállítások",
"Delete" : "Törlés",
- "Add storage" : "Tároló becsatolása"
+ "Allow users to mount external storage" : "Külső tárolók engedélyezése a felhasználók részére",
+ "Allow users to mount the following external storage" : "A felhasználók számára engedélyezett külső tárolók:"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/hy.js b/apps/files_external/l10n/hy.js
index 9996681f88b..1092d48d575 100644
--- a/apps/files_external/l10n/hy.js
+++ b/apps/files_external/l10n/hy.js
@@ -2,11 +2,14 @@ OC.L10N.register(
"files_external",
{
"Personal" : "Անձնական",
+ "Never" : "Երբեք",
+ "Username" : "Օգտանուն",
"Password" : "Գաղտնաբառ",
"URL" : "URL",
"Dropbox" : "Dropbox",
"Share" : "Կիսվել",
"Name" : "Անուն",
+ "Folder name" : "Պանակի անուն",
"Delete" : "Ջնջել"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/hy.json b/apps/files_external/l10n/hy.json
index ac5a0edf013..1fecd4f3da1 100644
--- a/apps/files_external/l10n/hy.json
+++ b/apps/files_external/l10n/hy.json
@@ -1,10 +1,13 @@
{ "translations": {
"Personal" : "Անձնական",
+ "Never" : "Երբեք",
+ "Username" : "Օգտանուն",
"Password" : "Գաղտնաբառ",
"URL" : "URL",
"Dropbox" : "Dropbox",
"Share" : "Կիսվել",
"Name" : "Անուն",
+ "Folder name" : "Պանակի անուն",
"Delete" : "Ջնջել"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/id.js b/apps/files_external/l10n/id.js
index b01e13e6085..15f33571ee6 100644
--- a/apps/files_external/l10n/id.js
+++ b/apps/files_external/l10n/id.js
@@ -29,7 +29,6 @@ OC.L10N.register(
"Check for changes" : "Periksa perubahan",
"Never" : "Jangan pernah",
"Once every direct access" : "Setiap kali akses langsung",
- "Every time the filesystem is used" : "Setiap kali sistem berkas digunakan",
"All users. Type to select user or group." : "Semua pengguna. Ketik untuk memilih pengguna atau grup.",
"(group)" : "(grup)",
"Saved" : "Disimpan",
@@ -51,7 +50,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "Kunci API",
"Username and password" : "Nama pengguna dan sandi",
- "Session credentials" : "Kredensial sesi",
"RSA public key" : "Kunci publik RSA",
"Public key" : "Kunci Public",
"Amazon S3" : "Amazon S3",
@@ -98,9 +96,9 @@ OC.L10N.register(
"Authentication" : "Otentikasi",
"Configuration" : "Konfigurasi",
"Available for" : "Tersedia untuk",
+ "Add storage" : "Tambahkan penyimpanan",
"Advanced settings" : "Pengaturan Lanjutan",
"Delete" : "Hapus",
- "Add storage" : "Tambahkan penyimpanan",
"Allow users to mount the following external storage" : "Izinkan pengguna untuk mengaitkan penyimpanan eksternal berikut"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_external/l10n/id.json b/apps/files_external/l10n/id.json
index 383850199ac..00f78599006 100644
--- a/apps/files_external/l10n/id.json
+++ b/apps/files_external/l10n/id.json
@@ -27,7 +27,6 @@
"Check for changes" : "Periksa perubahan",
"Never" : "Jangan pernah",
"Once every direct access" : "Setiap kali akses langsung",
- "Every time the filesystem is used" : "Setiap kali sistem berkas digunakan",
"All users. Type to select user or group." : "Semua pengguna. Ketik untuk memilih pengguna atau grup.",
"(group)" : "(grup)",
"Saved" : "Disimpan",
@@ -49,7 +48,6 @@
"Rackspace" : "Rackspace",
"API key" : "Kunci API",
"Username and password" : "Nama pengguna dan sandi",
- "Session credentials" : "Kredensial sesi",
"RSA public key" : "Kunci publik RSA",
"Public key" : "Kunci Public",
"Amazon S3" : "Amazon S3",
@@ -96,9 +94,9 @@
"Authentication" : "Otentikasi",
"Configuration" : "Konfigurasi",
"Available for" : "Tersedia untuk",
+ "Add storage" : "Tambahkan penyimpanan",
"Advanced settings" : "Pengaturan Lanjutan",
"Delete" : "Hapus",
- "Add storage" : "Tambahkan penyimpanan",
"Allow users to mount the following external storage" : "Izinkan pengguna untuk mengaitkan penyimpanan eksternal berikut"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/it.js b/apps/files_external/l10n/it.js
index 8e126abe93b..b6fad31111d 100644
--- a/apps/files_external/l10n/it.js
+++ b/apps/files_external/l10n/it.js
@@ -17,6 +17,8 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "Parametri del motore non soddisfatti",
"Unsatisfied authentication mechanism parameters" : "Parametri del meccanismo di autenticazione non soddisfatti",
"Insufficient data: %s" : "Dati insufficienti: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "L'archiviazione con ID \"%i\" non è modificabile dall'utente",
"Personal" : "Personale",
"System" : "Sistema",
"Grant access" : "Concedi l'accesso",
@@ -27,13 +29,22 @@ OC.L10N.register(
"Error generating key pair" : "Errore durante la generazione della coppia di chiavi",
"Enable encryption" : "Abilita cifratura",
"Enable previews" : "Abilita le anteprime",
+ "Enable sharing" : "Abilita condivisione",
"Check for changes" : "Controlla le modifiche",
"Never" : "Mai",
"Once every direct access" : "Una volta per ogni accesso diretto",
- "Every time the filesystem is used" : "Ogni volta che il filesystem viene utilizzato",
"All users. Type to select user or group." : "Tutti gli utenti. Digita per selezionare utente o gruppo.",
"(group)" : "(gruppo)",
+ "Admin defined" : "Definito dall'amministratore",
"Saved" : "Salvato",
+ "Empty response from the server" : "Risposta vuota dal server",
+ "Couldn't access. Please logout and login to activate this mount point" : "Impossibile accedere. Chiudi la sessione e accedi nuovamente per attivare questo punto di mount",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Impossibile ottenere le informazioni dal server ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Impossibile ottenere l'elenco dei punti di mount esterni: {type}",
+ "There was an error with message: " : "Si è verificato un errore con il messaggio:",
+ "External mount error" : "Errore di mount esterno",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Impossibile ottenere l'elenco dei punti di mount delle unità di rete Windows: risposta vuota dal server",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Alcuni dei punti di mount esterni configurati non sono connessi. Fai clic sulle righe rosse per ulteriori informazioni",
"Access key" : "Chiave di accesso",
"Secret key" : "Chiave segreta",
"Builtin" : "Integrata",
@@ -51,8 +62,10 @@ OC.L10N.register(
"Identity endpoint URL" : "URL endpoint delle identità",
"Rackspace" : "Rackspace",
"API key" : "Chiave API",
+ "Log-in credentials, save in database" : "Credenziali di accesso, salva nel database",
"Username and password" : "Nome utente e password",
- "Session credentials" : "Credenziali di sessione",
+ "Log-in credentials, save in session" : "Credenziali di accesso, salva nella sessione",
+ "User entered, store in database" : "Digitate dall'utente, memorizza nel database",
"RSA public key" : "Chiave pubblica RSA",
"Public key" : "Chiave pubblica",
"Amazon S3" : "Amazon S3",
@@ -99,9 +112,9 @@ OC.L10N.register(
"Authentication" : "Autenticazione",
"Configuration" : "Configurazione",
"Available for" : "Disponibile per",
+ "Add storage" : "Aggiungi archiviazione",
"Advanced settings" : "Impostazioni avanzate",
"Delete" : "Elimina",
- "Add storage" : "Aggiungi archiviazione",
"Allow users to mount external storage" : "Consenti agli utenti di montare archiviazioni esterne",
"Allow users to mount the following external storage" : "Consenti agli utenti di montare la seguente archiviazione esterna"
},
diff --git a/apps/files_external/l10n/it.json b/apps/files_external/l10n/it.json
index e21cf5973d2..e253c22b6b1 100644
--- a/apps/files_external/l10n/it.json
+++ b/apps/files_external/l10n/it.json
@@ -15,6 +15,8 @@
"Unsatisfied backend parameters" : "Parametri del motore non soddisfatti",
"Unsatisfied authentication mechanism parameters" : "Parametri del meccanismo di autenticazione non soddisfatti",
"Insufficient data: %s" : "Dati insufficienti: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "L'archiviazione con ID \"%i\" non è modificabile dall'utente",
"Personal" : "Personale",
"System" : "Sistema",
"Grant access" : "Concedi l'accesso",
@@ -25,13 +27,22 @@
"Error generating key pair" : "Errore durante la generazione della coppia di chiavi",
"Enable encryption" : "Abilita cifratura",
"Enable previews" : "Abilita le anteprime",
+ "Enable sharing" : "Abilita condivisione",
"Check for changes" : "Controlla le modifiche",
"Never" : "Mai",
"Once every direct access" : "Una volta per ogni accesso diretto",
- "Every time the filesystem is used" : "Ogni volta che il filesystem viene utilizzato",
"All users. Type to select user or group." : "Tutti gli utenti. Digita per selezionare utente o gruppo.",
"(group)" : "(gruppo)",
+ "Admin defined" : "Definito dall'amministratore",
"Saved" : "Salvato",
+ "Empty response from the server" : "Risposta vuota dal server",
+ "Couldn't access. Please logout and login to activate this mount point" : "Impossibile accedere. Chiudi la sessione e accedi nuovamente per attivare questo punto di mount",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Impossibile ottenere le informazioni dal server ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Impossibile ottenere l'elenco dei punti di mount esterni: {type}",
+ "There was an error with message: " : "Si è verificato un errore con il messaggio:",
+ "External mount error" : "Errore di mount esterno",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Impossibile ottenere l'elenco dei punti di mount delle unità di rete Windows: risposta vuota dal server",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Alcuni dei punti di mount esterni configurati non sono connessi. Fai clic sulle righe rosse per ulteriori informazioni",
"Access key" : "Chiave di accesso",
"Secret key" : "Chiave segreta",
"Builtin" : "Integrata",
@@ -49,8 +60,10 @@
"Identity endpoint URL" : "URL endpoint delle identità",
"Rackspace" : "Rackspace",
"API key" : "Chiave API",
+ "Log-in credentials, save in database" : "Credenziali di accesso, salva nel database",
"Username and password" : "Nome utente e password",
- "Session credentials" : "Credenziali di sessione",
+ "Log-in credentials, save in session" : "Credenziali di accesso, salva nella sessione",
+ "User entered, store in database" : "Digitate dall'utente, memorizza nel database",
"RSA public key" : "Chiave pubblica RSA",
"Public key" : "Chiave pubblica",
"Amazon S3" : "Amazon S3",
@@ -97,9 +110,9 @@
"Authentication" : "Autenticazione",
"Configuration" : "Configurazione",
"Available for" : "Disponibile per",
+ "Add storage" : "Aggiungi archiviazione",
"Advanced settings" : "Impostazioni avanzate",
"Delete" : "Elimina",
- "Add storage" : "Aggiungi archiviazione",
"Allow users to mount external storage" : "Consenti agli utenti di montare archiviazioni esterne",
"Allow users to mount the following external storage" : "Consenti agli utenti di montare la seguente archiviazione esterna"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/files_external/l10n/ja.js b/apps/files_external/l10n/ja.js
index 4481c7fdd2e..f14c07808ca 100644
--- a/apps/files_external/l10n/ja.js
+++ b/apps/files_external/l10n/ja.js
@@ -17,6 +17,8 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "バックエンドのためのパラメーターが不十分です。",
"Unsatisfied authentication mechanism parameters" : "認証のためのパラメータが不十分です",
"Insufficient data: %s" : "データが不足しています: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "ストレージID \"%i\" はユーザーが編集できません",
"Personal" : "個人",
"System" : "システム",
"Grant access" : "アクセスを許可",
@@ -30,10 +32,18 @@ OC.L10N.register(
"Check for changes" : "変更点を確認",
"Never" : "更新無",
"Once every direct access" : "直指定時のみ",
- "Every time the filesystem is used" : "ファイルシステム利用時には毎回",
"All users. Type to select user or group." : "すべてのユーザー。ユーザー、グループを追加",
"(group)" : "(グループ)",
+ "Admin defined" : "管理者設定済",
"Saved" : "保存されました",
+ "Empty response from the server" : "サーバーから空の応答がありました",
+ "Couldn't access. Please logout and login to activate this mount point" : "アクセス出来ませんでした。このマウントポイントを有効にするには一度ログアウトしてからログインしてください。",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "ownCloud サーバーから情報を取得出来ませんでした。: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "外部マウントポイントのリストを取得出来ませんでした。: {type}",
+ "There was an error with message: " : "メッセージ付きのエラーが発生しました:",
+ "External mount error" : "外部マウントエラー",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Windows ネットワークドライブのマウントポイントリストを取得出来ませんでした:サーバーから空の応答がありました",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "いくつかの設定済み外部マウントポイントに接続できませんでした。詳細情報は赤い行をクリックしてください",
"Access key" : "アクセスキー",
"Secret key" : "シークレットキー",
"Builtin" : "ビルトイン",
@@ -52,7 +62,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "APIキー",
"Username and password" : "ユーザー名とパスワード",
- "Session credentials" : "セッション資格情報",
"RSA public key" : "RSA公開鍵",
"Public key" : "公開鍵",
"Amazon S3" : "Amazon S3",
@@ -72,7 +81,7 @@ OC.L10N.register(
"Secure ftps://" : "Secure ftps://",
"Google Drive" : "Google Drive",
"Local" : "ローカル",
- "Location" : "位置",
+ "Location" : "場所",
"ownCloud" : "ownCloud",
"SFTP" : "SFTP",
"Root" : "ルート",
@@ -99,9 +108,9 @@ OC.L10N.register(
"Authentication" : "認証",
"Configuration" : "設定",
"Available for" : "利用可能",
+ "Add storage" : "ストレージを追加",
"Advanced settings" : "詳細設定",
"Delete" : "削除",
- "Add storage" : "ストレージを追加",
"Allow users to mount external storage" : "ユーザーに外部ストレージの接続を許可する",
"Allow users to mount the following external storage" : "ユーザーに以下の外部ストレージのマウントを許可する"
},
diff --git a/apps/files_external/l10n/ja.json b/apps/files_external/l10n/ja.json
index 5573c11fe84..df6f7f44618 100644
--- a/apps/files_external/l10n/ja.json
+++ b/apps/files_external/l10n/ja.json
@@ -15,6 +15,8 @@
"Unsatisfied backend parameters" : "バックエンドのためのパラメーターが不十分です。",
"Unsatisfied authentication mechanism parameters" : "認証のためのパラメータが不十分です",
"Insufficient data: %s" : "データが不足しています: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "ストレージID \"%i\" はユーザーが編集できません",
"Personal" : "個人",
"System" : "システム",
"Grant access" : "アクセスを許可",
@@ -28,10 +30,18 @@
"Check for changes" : "変更点を確認",
"Never" : "更新無",
"Once every direct access" : "直指定時のみ",
- "Every time the filesystem is used" : "ファイルシステム利用時には毎回",
"All users. Type to select user or group." : "すべてのユーザー。ユーザー、グループを追加",
"(group)" : "(グループ)",
+ "Admin defined" : "管理者設定済",
"Saved" : "保存されました",
+ "Empty response from the server" : "サーバーから空の応答がありました",
+ "Couldn't access. Please logout and login to activate this mount point" : "アクセス出来ませんでした。このマウントポイントを有効にするには一度ログアウトしてからログインしてください。",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "ownCloud サーバーから情報を取得出来ませんでした。: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "外部マウントポイントのリストを取得出来ませんでした。: {type}",
+ "There was an error with message: " : "メッセージ付きのエラーが発生しました:",
+ "External mount error" : "外部マウントエラー",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Windows ネットワークドライブのマウントポイントリストを取得出来ませんでした:サーバーから空の応答がありました",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "いくつかの設定済み外部マウントポイントに接続できませんでした。詳細情報は赤い行をクリックしてください",
"Access key" : "アクセスキー",
"Secret key" : "シークレットキー",
"Builtin" : "ビルトイン",
@@ -50,7 +60,6 @@
"Rackspace" : "Rackspace",
"API key" : "APIキー",
"Username and password" : "ユーザー名とパスワード",
- "Session credentials" : "セッション資格情報",
"RSA public key" : "RSA公開鍵",
"Public key" : "公開鍵",
"Amazon S3" : "Amazon S3",
@@ -70,7 +79,7 @@
"Secure ftps://" : "Secure ftps://",
"Google Drive" : "Google Drive",
"Local" : "ローカル",
- "Location" : "位置",
+ "Location" : "場所",
"ownCloud" : "ownCloud",
"SFTP" : "SFTP",
"Root" : "ルート",
@@ -97,9 +106,9 @@
"Authentication" : "認証",
"Configuration" : "設定",
"Available for" : "利用可能",
+ "Add storage" : "ストレージを追加",
"Advanced settings" : "詳細設定",
"Delete" : "削除",
- "Add storage" : "ストレージを追加",
"Allow users to mount external storage" : "ユーザーに外部ストレージの接続を許可する",
"Allow users to mount the following external storage" : "ユーザーに以下の外部ストレージのマウントを許可する"
},"pluralForm" :"nplurals=1; plural=0;"
diff --git a/apps/files_external/l10n/ka_GE.js b/apps/files_external/l10n/ka_GE.js
index 824295cb93d..e82c778862e 100644
--- a/apps/files_external/l10n/ka_GE.js
+++ b/apps/files_external/l10n/ka_GE.js
@@ -21,7 +21,7 @@ OC.L10N.register(
"External Storage" : "ექსტერნალ საცავი",
"Folder name" : "ფოლდერის სახელი",
"Configuration" : "კონფიგურაცია",
- "Delete" : "წაშლა",
- "Add storage" : "საცავის დამატება"
+ "Add storage" : "საცავის დამატება",
+ "Delete" : "წაშლა"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_external/l10n/ka_GE.json b/apps/files_external/l10n/ka_GE.json
index 73ad2cfd0c5..a706d42225b 100644
--- a/apps/files_external/l10n/ka_GE.json
+++ b/apps/files_external/l10n/ka_GE.json
@@ -19,7 +19,7 @@
"External Storage" : "ექსტერნალ საცავი",
"Folder name" : "ფოლდერის სახელი",
"Configuration" : "კონფიგურაცია",
- "Delete" : "წაშლა",
- "Add storage" : "საცავის დამატება"
+ "Add storage" : "საცავის დამატება",
+ "Delete" : "წაშლა"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/km.js b/apps/files_external/l10n/km.js
index 7a5c6cb86c8..e5aad9697ae 100644
--- a/apps/files_external/l10n/km.js
+++ b/apps/files_external/l10n/km.js
@@ -19,7 +19,7 @@ OC.L10N.register(
"External Storage" : "ឃ្លាំងផ្ទុក​ខាងក្រៅ",
"Folder name" : "ឈ្មោះ​ថត",
"Configuration" : "ការ​កំណត់​សណ្ឋាន",
- "Delete" : "លុប",
- "Add storage" : "បន្ថែម​ឃ្លាំងផ្ទុក"
+ "Add storage" : "បន្ថែម​ឃ្លាំងផ្ទុក",
+ "Delete" : "លុប"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_external/l10n/km.json b/apps/files_external/l10n/km.json
index 0375b5bfee2..71213394d53 100644
--- a/apps/files_external/l10n/km.json
+++ b/apps/files_external/l10n/km.json
@@ -17,7 +17,7 @@
"External Storage" : "ឃ្លាំងផ្ទុក​ខាងក្រៅ",
"Folder name" : "ឈ្មោះ​ថត",
"Configuration" : "ការ​កំណត់​សណ្ឋាន",
- "Delete" : "លុប",
- "Add storage" : "បន្ថែម​ឃ្លាំងផ្ទុក"
+ "Add storage" : "បន្ថែម​ឃ្លាំងផ្ទុក",
+ "Delete" : "លុប"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/ko.js b/apps/files_external/l10n/ko.js
index 9028a3e2986..df30d86ca13 100644
--- a/apps/files_external/l10n/ko.js
+++ b/apps/files_external/l10n/ko.js
@@ -30,7 +30,6 @@ OC.L10N.register(
"Check for changes" : "변경 사항 감시",
"Never" : "하지 않음",
"Once every direct access" : "한 번 직접 접근할 때마다",
- "Every time the filesystem is used" : "파일 시스템을 사용할 때마다",
"All users. Type to select user or group." : "모든 사용자입니다. 사용자나 그룹을 선택하려면 입력하십시오",
"(group)" : "(그룹)",
"Saved" : "저장됨",
@@ -52,7 +51,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "API 키",
"Username and password" : "사용자 이름과 암호",
- "Session credentials" : "세션 접근 정보",
"RSA public key" : "RSA 공개 키",
"Public key" : "공개 키",
"Amazon S3" : "Amazon S3",
@@ -99,9 +97,9 @@ OC.L10N.register(
"Authentication" : "인증",
"Configuration" : "설정",
"Available for" : "다음으로 사용 가능",
+ "Add storage" : "저장소 추가",
"Advanced settings" : "고급 설정",
"Delete" : "삭제",
- "Add storage" : "저장소 추가",
"Allow users to mount external storage" : "사용자가 외부 저장소를 마운트하도록 허용",
"Allow users to mount the following external storage" : "사용자가 다음 외부 저장소를 마운트할 수 있도록 허용"
},
diff --git a/apps/files_external/l10n/ko.json b/apps/files_external/l10n/ko.json
index d27fdfcae30..a5f4b4946ca 100644
--- a/apps/files_external/l10n/ko.json
+++ b/apps/files_external/l10n/ko.json
@@ -28,7 +28,6 @@
"Check for changes" : "변경 사항 감시",
"Never" : "하지 않음",
"Once every direct access" : "한 번 직접 접근할 때마다",
- "Every time the filesystem is used" : "파일 시스템을 사용할 때마다",
"All users. Type to select user or group." : "모든 사용자입니다. 사용자나 그룹을 선택하려면 입력하십시오",
"(group)" : "(그룹)",
"Saved" : "저장됨",
@@ -50,7 +49,6 @@
"Rackspace" : "Rackspace",
"API key" : "API 키",
"Username and password" : "사용자 이름과 암호",
- "Session credentials" : "세션 접근 정보",
"RSA public key" : "RSA 공개 키",
"Public key" : "공개 키",
"Amazon S3" : "Amazon S3",
@@ -97,9 +95,9 @@
"Authentication" : "인증",
"Configuration" : "설정",
"Available for" : "다음으로 사용 가능",
+ "Add storage" : "저장소 추가",
"Advanced settings" : "고급 설정",
"Delete" : "삭제",
- "Add storage" : "저장소 추가",
"Allow users to mount external storage" : "사용자가 외부 저장소를 마운트하도록 허용",
"Allow users to mount the following external storage" : "사용자가 다음 외부 저장소를 마운트할 수 있도록 허용"
},"pluralForm" :"nplurals=1; plural=0;"
diff --git a/apps/files_external/l10n/lt_LT.js b/apps/files_external/l10n/lt_LT.js
index b6d334d792d..3a871070f45 100644
--- a/apps/files_external/l10n/lt_LT.js
+++ b/apps/files_external/l10n/lt_LT.js
@@ -1,6 +1,9 @@
OC.L10N.register(
"files_external",
{
+ "Fetching request tokens failed. Verify that your app key and secret are correct." : "Nepavyko atsiųsti užklausos žymės. Patikrinkite savo programos raktą ir paslaptį.",
+ "Step 1 failed. Exception: %s" : "1 žingsnio klaida: %s",
+ "Step 2 failed. Exception: %s" : "2 žingsnio klaida: %s",
"External storage" : "Išorinė saugykla",
"Personal" : "Asmeniniai",
"Grant access" : "Suteikti priėjimą",
@@ -22,7 +25,7 @@ OC.L10N.register(
"External Storage" : "Išorinės saugyklos",
"Folder name" : "Katalogo pavadinimas",
"Configuration" : "Konfigūracija",
- "Delete" : "Ištrinti",
- "Add storage" : "Pridėti saugyklą"
+ "Add storage" : "Pridėti saugyklą",
+ "Delete" : "Ištrinti"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_external/l10n/lt_LT.json b/apps/files_external/l10n/lt_LT.json
index f1c46b145ee..854f753acaf 100644
--- a/apps/files_external/l10n/lt_LT.json
+++ b/apps/files_external/l10n/lt_LT.json
@@ -1,4 +1,7 @@
{ "translations": {
+ "Fetching request tokens failed. Verify that your app key and secret are correct." : "Nepavyko atsiųsti užklausos žymės. Patikrinkite savo programos raktą ir paslaptį.",
+ "Step 1 failed. Exception: %s" : "1 žingsnio klaida: %s",
+ "Step 2 failed. Exception: %s" : "2 žingsnio klaida: %s",
"External storage" : "Išorinė saugykla",
"Personal" : "Asmeniniai",
"Grant access" : "Suteikti priėjimą",
@@ -20,7 +23,7 @@
"External Storage" : "Išorinės saugyklos",
"Folder name" : "Katalogo pavadinimas",
"Configuration" : "Konfigūracija",
- "Delete" : "Ištrinti",
- "Add storage" : "Pridėti saugyklą"
+ "Add storage" : "Pridėti saugyklą",
+ "Delete" : "Ištrinti"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/lv.js b/apps/files_external/l10n/lv.js
index 6590706fa2a..d6733a1d9c0 100644
--- a/apps/files_external/l10n/lv.js
+++ b/apps/files_external/l10n/lv.js
@@ -21,7 +21,7 @@ OC.L10N.register(
"External Storage" : "Ārējā krātuve",
"Folder name" : "Mapes nosaukums",
"Configuration" : "Konfigurācija",
- "Delete" : "Dzēst",
- "Add storage" : "Pievienot krātuvi"
+ "Add storage" : "Pievienot krātuvi",
+ "Delete" : "Dzēst"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);");
diff --git a/apps/files_external/l10n/lv.json b/apps/files_external/l10n/lv.json
index 4e27db77737..57fe7cbc048 100644
--- a/apps/files_external/l10n/lv.json
+++ b/apps/files_external/l10n/lv.json
@@ -19,7 +19,7 @@
"External Storage" : "Ārējā krātuve",
"Folder name" : "Mapes nosaukums",
"Configuration" : "Konfigurācija",
- "Delete" : "Dzēst",
- "Add storage" : "Pievienot krātuvi"
+ "Add storage" : "Pievienot krātuvi",
+ "Delete" : "Dzēst"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/nb_NO.js b/apps/files_external/l10n/nb_NO.js
index ecafac048c0..fc791fe60ab 100644
--- a/apps/files_external/l10n/nb_NO.js
+++ b/apps/files_external/l10n/nb_NO.js
@@ -16,6 +16,8 @@ OC.L10N.register(
"Not permitted to use authentication mechanism \"%s\"" : "Ikke tillatt å bruke autentiseringsmekanisme \"%s\"",
"Unsatisfied backend parameters" : "Noen server-parameter mangler",
"Unsatisfied authentication mechanism parameters" : "Noen parametre for autentiseringsmekanisme mangler",
+ "Insufficient data: %s" : "Utilstrekkelige data: %s",
+ "%s" : "%s",
"Personal" : "Personlig",
"System" : "System",
"Grant access" : "Gi tilgang",
@@ -29,10 +31,18 @@ OC.L10N.register(
"Check for changes" : "Se etter endringer",
"Never" : "Aldri",
"Once every direct access" : "En gang pr. direkte aksess",
- "Every time the filesystem is used" : "Hver gang filsystemet brukes",
"All users. Type to select user or group." : "Alle brukere. Tast for å velge bruker eller gruppe.",
"(group)" : "(gruppe)",
+ "Admin defined" : "Admin-definert",
"Saved" : "Lagret",
+ "Empty response from the server" : "Tomt svar fra serveren",
+ "Couldn't access. Please logout and login to activate this mount point" : "Fikk ikke tilgang. Vennligst logg ut og inn igjen for å aktivere dette oppkoblingspunktet.",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Klarte ikke å hente informasjon fra ownCloud-serveren: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Klarte ikke å hente listen over eksterne oppkoblingspunkter: {type}",
+ "There was an error with message: " : "Det oppstod en feil med melding: ",
+ "External mount error" : "Ekstern oppkoblingsfeil",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Klarte ikke å hente listen over oppkoblingspunkter for Windows nettverk-disker: tomt svar fra serveren",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Noen av de konfigurerte eksterne oppkoblingspunktene er ikke tilkoblet. Klikk på de røde raden(e) for mer informasjon.",
"Access key" : "Tilgangsnøkkel",
"Secret key" : "Hemmelig nøkkel",
"Builtin" : "Innebygget",
@@ -51,7 +61,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "API-nøkkel",
"Username and password" : "Brukernavn og passord",
- "Session credentials" : "Påloggingsdetaljer for økt",
"RSA public key" : "RSA offentlig nøkkel",
"Public key" : "Offentlig nøkkel",
"Amazon S3" : "Amazon S3",
@@ -98,9 +107,10 @@ OC.L10N.register(
"Authentication" : "Autentisering",
"Configuration" : "Konfigurasjon",
"Available for" : "Tilgjengelig for",
+ "Add storage" : "Legg til lagringsplass",
"Advanced settings" : "Avanserte innstillinger",
"Delete" : "Slett",
- "Add storage" : "Legg til lagringsplass",
+ "Allow users to mount external storage" : "Tillat at brukere kobler opp eksterne lagre",
"Allow users to mount the following external storage" : "Tillat brukere å koble opp følgende eksterne lagring"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/nb_NO.json b/apps/files_external/l10n/nb_NO.json
index 9a7a2ae6287..0e956952948 100644
--- a/apps/files_external/l10n/nb_NO.json
+++ b/apps/files_external/l10n/nb_NO.json
@@ -14,6 +14,8 @@
"Not permitted to use authentication mechanism \"%s\"" : "Ikke tillatt å bruke autentiseringsmekanisme \"%s\"",
"Unsatisfied backend parameters" : "Noen server-parameter mangler",
"Unsatisfied authentication mechanism parameters" : "Noen parametre for autentiseringsmekanisme mangler",
+ "Insufficient data: %s" : "Utilstrekkelige data: %s",
+ "%s" : "%s",
"Personal" : "Personlig",
"System" : "System",
"Grant access" : "Gi tilgang",
@@ -27,10 +29,18 @@
"Check for changes" : "Se etter endringer",
"Never" : "Aldri",
"Once every direct access" : "En gang pr. direkte aksess",
- "Every time the filesystem is used" : "Hver gang filsystemet brukes",
"All users. Type to select user or group." : "Alle brukere. Tast for å velge bruker eller gruppe.",
"(group)" : "(gruppe)",
+ "Admin defined" : "Admin-definert",
"Saved" : "Lagret",
+ "Empty response from the server" : "Tomt svar fra serveren",
+ "Couldn't access. Please logout and login to activate this mount point" : "Fikk ikke tilgang. Vennligst logg ut og inn igjen for å aktivere dette oppkoblingspunktet.",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Klarte ikke å hente informasjon fra ownCloud-serveren: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Klarte ikke å hente listen over eksterne oppkoblingspunkter: {type}",
+ "There was an error with message: " : "Det oppstod en feil med melding: ",
+ "External mount error" : "Ekstern oppkoblingsfeil",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Klarte ikke å hente listen over oppkoblingspunkter for Windows nettverk-disker: tomt svar fra serveren",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Noen av de konfigurerte eksterne oppkoblingspunktene er ikke tilkoblet. Klikk på de røde raden(e) for mer informasjon.",
"Access key" : "Tilgangsnøkkel",
"Secret key" : "Hemmelig nøkkel",
"Builtin" : "Innebygget",
@@ -49,7 +59,6 @@
"Rackspace" : "Rackspace",
"API key" : "API-nøkkel",
"Username and password" : "Brukernavn og passord",
- "Session credentials" : "Påloggingsdetaljer for økt",
"RSA public key" : "RSA offentlig nøkkel",
"Public key" : "Offentlig nøkkel",
"Amazon S3" : "Amazon S3",
@@ -96,9 +105,10 @@
"Authentication" : "Autentisering",
"Configuration" : "Konfigurasjon",
"Available for" : "Tilgjengelig for",
+ "Add storage" : "Legg til lagringsplass",
"Advanced settings" : "Avanserte innstillinger",
"Delete" : "Slett",
- "Add storage" : "Legg til lagringsplass",
+ "Allow users to mount external storage" : "Tillat at brukere kobler opp eksterne lagre",
"Allow users to mount the following external storage" : "Tillat brukere å koble opp følgende eksterne lagring"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/nds.js b/apps/files_external/l10n/nds.js
index f7f1da30c60..b4649fe681a 100644
--- a/apps/files_external/l10n/nds.js
+++ b/apps/files_external/l10n/nds.js
@@ -29,7 +29,6 @@ OC.L10N.register(
"Check for changes" : "Auf Änderungen prüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem direkten Zugriff",
- "Every time the filesystem is used" : "Bei jeder Verwendung des Dateisystems",
"All users. Type to select user or group." : "Alle Benutzer. Tippe, um eine Benutzergruppe auszuwählen.",
"(group)" : "(Gruppe)",
"Saved" : "Gespeichert",
@@ -48,7 +47,6 @@ OC.L10N.register(
"Password" : "Passwort",
"API key" : "API Schlüssel",
"Username and password" : "Benutzername und Passwort",
- "Session credentials" : "Anmeldedaten der Sitzung",
"RSA public key" : "Öffentlicher RSA Schlüssel",
"Public key" : "Öffentlicher Schlüssel",
"Amazon S3" : "Amazon S3",
@@ -93,9 +91,9 @@ OC.L10N.register(
"Authentication" : "Authentifizierung",
"Configuration" : "Konfiguration",
"Available for" : "Verfügbar für",
+ "Add storage" : "Speicher hinzufügen",
"Advanced settings" : "Erweiterte Einstellungen",
"Delete" : "Löschen",
- "Add storage" : "Speicher hinzufügen",
"Allow users to mount the following external storage" : "Erlaube Benutzern folgenden externen Speicher einzuhängen"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/nds.json b/apps/files_external/l10n/nds.json
index bfadfc0c123..75e36016384 100644
--- a/apps/files_external/l10n/nds.json
+++ b/apps/files_external/l10n/nds.json
@@ -27,7 +27,6 @@
"Check for changes" : "Auf Änderungen prüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem direkten Zugriff",
- "Every time the filesystem is used" : "Bei jeder Verwendung des Dateisystems",
"All users. Type to select user or group." : "Alle Benutzer. Tippe, um eine Benutzergruppe auszuwählen.",
"(group)" : "(Gruppe)",
"Saved" : "Gespeichert",
@@ -46,7 +45,6 @@
"Password" : "Passwort",
"API key" : "API Schlüssel",
"Username and password" : "Benutzername und Passwort",
- "Session credentials" : "Anmeldedaten der Sitzung",
"RSA public key" : "Öffentlicher RSA Schlüssel",
"Public key" : "Öffentlicher Schlüssel",
"Amazon S3" : "Amazon S3",
@@ -91,9 +89,9 @@
"Authentication" : "Authentifizierung",
"Configuration" : "Konfiguration",
"Available for" : "Verfügbar für",
+ "Add storage" : "Speicher hinzufügen",
"Advanced settings" : "Erweiterte Einstellungen",
"Delete" : "Löschen",
- "Add storage" : "Speicher hinzufügen",
"Allow users to mount the following external storage" : "Erlaube Benutzern folgenden externen Speicher einzuhängen"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/nl.js b/apps/files_external/l10n/nl.js
index 57481ce4176..a3f3ca9a566 100644
--- a/apps/files_external/l10n/nl.js
+++ b/apps/files_external/l10n/nl.js
@@ -17,6 +17,8 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "Onvoldoende backend parameters",
"Unsatisfied authentication mechanism parameters" : "Onvoldoende authenticatiemechanisme parameters",
"Insufficient data: %s" : "Onvoldoende gegevens: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Opslag met id \"%i\" is niet te bewerken door gebruiker",
"Personal" : "Persoonlijk",
"System" : "Systeem",
"Grant access" : "Sta toegang toe",
@@ -30,10 +32,18 @@ OC.L10N.register(
"Check for changes" : "Controleren op wijzigingen",
"Never" : "Nooit",
"Once every direct access" : "Een keer bij elke directe toegang",
- "Every time the filesystem is used" : "Elke keer bij gebruik bestandssysteem",
"All users. Type to select user or group." : "Alle gebruikers. Tikken om een gebruiker of groep te selecteren.",
"(group)" : "(groep)",
+ "Admin defined" : "Beheerder gedefinieerd",
"Saved" : "Bewaard",
+ "Empty response from the server" : "Lege reactie van de server",
+ "Couldn't access. Please logout and login to activate this mount point" : "Geen toegang. Log uit en opnieuw in om dit koppelpunt te activeren",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Kon geen informatie van de ownCloud server krijgen: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Kon geen overzicht met externe koppelpunten krijgen: {type}",
+ "There was an error with message: " : "Er was een fout met de volgende melding:",
+ "External mount error" : "Extern koppelpunt fout",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Kon geen overzicht met Windows netwerk koppelpunten krijgen: lege reactie van de server",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Sommige van de geconfigureerde koppelpunten zijn niet verbonden. Klok op de rode rij(en) voor meer informatie",
"Access key" : "Access Key",
"Secret key" : "Geheime sleutel",
"Builtin" : "Ingebouwd",
@@ -52,7 +62,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "API sleutel",
"Username and password" : "Gebruikersnaam en wachtwoord",
- "Session credentials" : "Sessie inloggegevens",
"RSA public key" : "RSA publieke sleutel",
"Public key" : "Publieke sleutel",
"Amazon S3" : "Amazon S3",
@@ -99,9 +108,9 @@ OC.L10N.register(
"Authentication" : "Authenticatie",
"Configuration" : "Configuratie",
"Available for" : "Beschikbaar voor",
+ "Add storage" : "Toevoegen opslag",
"Advanced settings" : "Geavanceerde instellingen",
"Delete" : "Verwijder",
- "Add storage" : "Toevoegen opslag",
"Allow users to mount external storage" : "Sta gebruikers toe om een externe opslag aan te koppelen",
"Allow users to mount the following external storage" : "Sta gebruikers toe de volgende externe opslag aan te koppelen"
},
diff --git a/apps/files_external/l10n/nl.json b/apps/files_external/l10n/nl.json
index fc80c3bbb2c..8654cdc662d 100644
--- a/apps/files_external/l10n/nl.json
+++ b/apps/files_external/l10n/nl.json
@@ -15,6 +15,8 @@
"Unsatisfied backend parameters" : "Onvoldoende backend parameters",
"Unsatisfied authentication mechanism parameters" : "Onvoldoende authenticatiemechanisme parameters",
"Insufficient data: %s" : "Onvoldoende gegevens: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Opslag met id \"%i\" is niet te bewerken door gebruiker",
"Personal" : "Persoonlijk",
"System" : "Systeem",
"Grant access" : "Sta toegang toe",
@@ -28,10 +30,18 @@
"Check for changes" : "Controleren op wijzigingen",
"Never" : "Nooit",
"Once every direct access" : "Een keer bij elke directe toegang",
- "Every time the filesystem is used" : "Elke keer bij gebruik bestandssysteem",
"All users. Type to select user or group." : "Alle gebruikers. Tikken om een gebruiker of groep te selecteren.",
"(group)" : "(groep)",
+ "Admin defined" : "Beheerder gedefinieerd",
"Saved" : "Bewaard",
+ "Empty response from the server" : "Lege reactie van de server",
+ "Couldn't access. Please logout and login to activate this mount point" : "Geen toegang. Log uit en opnieuw in om dit koppelpunt te activeren",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Kon geen informatie van de ownCloud server krijgen: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Kon geen overzicht met externe koppelpunten krijgen: {type}",
+ "There was an error with message: " : "Er was een fout met de volgende melding:",
+ "External mount error" : "Extern koppelpunt fout",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Kon geen overzicht met Windows netwerk koppelpunten krijgen: lege reactie van de server",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Sommige van de geconfigureerde koppelpunten zijn niet verbonden. Klok op de rode rij(en) voor meer informatie",
"Access key" : "Access Key",
"Secret key" : "Geheime sleutel",
"Builtin" : "Ingebouwd",
@@ -50,7 +60,6 @@
"Rackspace" : "Rackspace",
"API key" : "API sleutel",
"Username and password" : "Gebruikersnaam en wachtwoord",
- "Session credentials" : "Sessie inloggegevens",
"RSA public key" : "RSA publieke sleutel",
"Public key" : "Publieke sleutel",
"Amazon S3" : "Amazon S3",
@@ -97,9 +106,9 @@
"Authentication" : "Authenticatie",
"Configuration" : "Configuratie",
"Available for" : "Beschikbaar voor",
+ "Add storage" : "Toevoegen opslag",
"Advanced settings" : "Geavanceerde instellingen",
"Delete" : "Verwijder",
- "Add storage" : "Toevoegen opslag",
"Allow users to mount external storage" : "Sta gebruikers toe om een externe opslag aan te koppelen",
"Allow users to mount the following external storage" : "Sta gebruikers toe de volgende externe opslag aan te koppelen"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/files_external/l10n/oc.js b/apps/files_external/l10n/oc.js
index a45aebf81ba..716326f1cae 100644
--- a/apps/files_external/l10n/oc.js
+++ b/apps/files_external/l10n/oc.js
@@ -30,7 +30,6 @@ OC.L10N.register(
"Check for changes" : "Recercar las modificacions",
"Never" : "Pas jamai",
"Once every direct access" : "Un còp a cada accès dirècte",
- "Every time the filesystem is used" : "A cada còp que lo sistèma de fichièrs es utilizat",
"All users. Type to select user or group." : "Totes los utilizaires. Clicatz aicí per restrénher.",
"(group)" : "(grop)",
"Saved" : "Enregistrat",
@@ -52,7 +51,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "Clau API",
"Username and password" : "Nom d'utilizaire e senhal",
- "Session credentials" : "Informacions d'identificacion de session",
"RSA public key" : "Clau publica RSA",
"Public key" : "Clau publica",
"Amazon S3" : "Amazon S3",
@@ -99,9 +97,9 @@ OC.L10N.register(
"Authentication" : "Autentificacion",
"Configuration" : "Configuracion",
"Available for" : "Disponible per",
+ "Add storage" : "Apondre un supòrt d'emmagazinatge",
"Advanced settings" : "Paramètres avançats",
"Delete" : "Suprimir",
- "Add storage" : "Apondre un supòrt d'emmagazinatge",
"Allow users to mount external storage" : "Autorizar los utilizaires a montar l'espaci d'emmagazinatge extèrne",
"Allow users to mount the following external storage" : "Autorizar los utilizaires a montar los emmagazinatges extèrnes seguents"
},
diff --git a/apps/files_external/l10n/oc.json b/apps/files_external/l10n/oc.json
index c49326a955f..bc882de1456 100644
--- a/apps/files_external/l10n/oc.json
+++ b/apps/files_external/l10n/oc.json
@@ -28,7 +28,6 @@
"Check for changes" : "Recercar las modificacions",
"Never" : "Pas jamai",
"Once every direct access" : "Un còp a cada accès dirècte",
- "Every time the filesystem is used" : "A cada còp que lo sistèma de fichièrs es utilizat",
"All users. Type to select user or group." : "Totes los utilizaires. Clicatz aicí per restrénher.",
"(group)" : "(grop)",
"Saved" : "Enregistrat",
@@ -50,7 +49,6 @@
"Rackspace" : "Rackspace",
"API key" : "Clau API",
"Username and password" : "Nom d'utilizaire e senhal",
- "Session credentials" : "Informacions d'identificacion de session",
"RSA public key" : "Clau publica RSA",
"Public key" : "Clau publica",
"Amazon S3" : "Amazon S3",
@@ -97,9 +95,9 @@
"Authentication" : "Autentificacion",
"Configuration" : "Configuracion",
"Available for" : "Disponible per",
+ "Add storage" : "Apondre un supòrt d'emmagazinatge",
"Advanced settings" : "Paramètres avançats",
"Delete" : "Suprimir",
- "Add storage" : "Apondre un supòrt d'emmagazinatge",
"Allow users to mount external storage" : "Autorizar los utilizaires a montar l'espaci d'emmagazinatge extèrne",
"Allow users to mount the following external storage" : "Autorizar los utilizaires a montar los emmagazinatges extèrnes seguents"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
diff --git a/apps/files_external/l10n/pl.js b/apps/files_external/l10n/pl.js
index 1f7cc6b1979..523a913d1f2 100644
--- a/apps/files_external/l10n/pl.js
+++ b/apps/files_external/l10n/pl.js
@@ -18,7 +18,6 @@ OC.L10N.register(
"Check for changes" : "Sprawdź zmiany",
"Never" : "Nigdy",
"Once every direct access" : "Jeden raz przy każdym dostępie",
- "Every time the filesystem is used" : "Każdorazowo, kiedy system plików jest w użyciu",
"All users. Type to select user or group." : "Wszyscy użytkownicy. Zacznij pisać, aby wybrać użytkownika lub grupę.",
"(group)" : "(grupa)",
"Saved" : "Zapisano",
@@ -67,9 +66,9 @@ OC.L10N.register(
"Folder name" : "Nazwa folderu",
"Configuration" : "Konfiguracja",
"Available for" : "Dostępne przez",
+ "Add storage" : "Dodaj zasoby dyskowe",
"Advanced settings" : "Ustawienia zaawansowane",
"Delete" : "Usuń",
- "Add storage" : "Dodaj zasoby dyskowe",
"Allow users to mount the following external storage" : "Pozwól użytkownikom montować następujące zewnętrzne zasoby dyskowe"
},
"nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_external/l10n/pl.json b/apps/files_external/l10n/pl.json
index 5b5059a5d18..25d379cc730 100644
--- a/apps/files_external/l10n/pl.json
+++ b/apps/files_external/l10n/pl.json
@@ -16,7 +16,6 @@
"Check for changes" : "Sprawdź zmiany",
"Never" : "Nigdy",
"Once every direct access" : "Jeden raz przy każdym dostępie",
- "Every time the filesystem is used" : "Każdorazowo, kiedy system plików jest w użyciu",
"All users. Type to select user or group." : "Wszyscy użytkownicy. Zacznij pisać, aby wybrać użytkownika lub grupę.",
"(group)" : "(grupa)",
"Saved" : "Zapisano",
@@ -65,9 +64,9 @@
"Folder name" : "Nazwa folderu",
"Configuration" : "Konfiguracja",
"Available for" : "Dostępne przez",
+ "Add storage" : "Dodaj zasoby dyskowe",
"Advanced settings" : "Ustawienia zaawansowane",
"Delete" : "Usuń",
- "Add storage" : "Dodaj zasoby dyskowe",
"Allow users to mount the following external storage" : "Pozwól użytkownikom montować następujące zewnętrzne zasoby dyskowe"
},"pluralForm" :"nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/pt_BR.js b/apps/files_external/l10n/pt_BR.js
index 92bc16355d3..b98c7efe0a4 100644
--- a/apps/files_external/l10n/pt_BR.js
+++ b/apps/files_external/l10n/pt_BR.js
@@ -17,6 +17,8 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "Parâmetros de back-end não-atendidos",
"Unsatisfied authentication mechanism parameters" : "Parâmetros de mecanismos de autenticação não satisfeitos",
"Insufficient data: %s" : "Dados insuficientes: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Armazenamento com ID \"%i\" não é editável pelo usuário",
"Personal" : "Pessoal",
"System" : "Sistema",
"Grant access" : "Permitir acesso",
@@ -27,13 +29,22 @@ OC.L10N.register(
"Error generating key pair" : "Erro ao gerar um par de chaves",
"Enable encryption" : "Ativar criptografia",
"Enable previews" : "Habilitar visualizações prévias",
+ "Enable sharing" : "Habilitar compartilhamento",
"Check for changes" : "Verifique se há alterações",
"Never" : "Nunca",
"Once every direct access" : "Uma vez a cada acesso direto",
- "Every time the filesystem is used" : "Toda vez que o sistema de arquivos é usado",
"All users. Type to select user or group." : "Todos os usuários. Digite para selecionar usuário ou grupo.",
"(group)" : "(grupo)",
+ "Admin defined" : "Definido pelo administrador",
"Saved" : "Salvo",
+ "Empty response from the server" : "Resposta vazia a partir do servidor",
+ "Couldn't access. Please logout and login to activate this mount point" : "Não foi possível acessar. Por favor, desconectar e conectar novamente para ativar este ponto de montagem",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Não foi possível obter as informações do servidor ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Não foi possível obter a lista de pontos de montagem externos: {type}",
+ "There was an error with message: " : "Houve um erro com a mensagem:",
+ "External mount error" : "Erro de montagem externa",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Não foi possível obter a lista unidades de pontos de montagem da rede do Windows: resposta vazia a partir do servidor",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Alguns dos pontos de montagem externos configurados não estão conectados. Por favor clique na linha vermelha(s) para mais informações",
"Access key" : "Chave da acesso",
"Secret key" : "Chave secreta",
"Builtin" : "Construídas em",
@@ -51,8 +62,10 @@ OC.L10N.register(
"Identity endpoint URL" : "Identidade pontofinal URL",
"Rackspace" : "Espaço em rack",
"API key" : "Chave API",
+ "Log-in credentials, save in database" : "Credenciais de login, salvos no banco de dados",
"Username and password" : "Nome de Usuário e senha",
- "Session credentials" : "Credenciais de Sessão",
+ "Log-in credentials, save in session" : "Credenciais de login, guardados em sessão",
+ "User entered, store in database" : "Usuário digitou, armazenar em banco de dados",
"RSA public key" : "Chave pública RSA",
"Public key" : "Chave pública",
"Amazon S3" : "Amazon S3",
@@ -99,9 +112,9 @@ OC.L10N.register(
"Authentication" : "Autenticação",
"Configuration" : "Configuração",
"Available for" : "Disponível para",
+ "Add storage" : "Adicionar Armazenamento",
"Advanced settings" : "Configurações avançadas",
"Delete" : "Excluir",
- "Add storage" : "Adicionar Armazenamento",
"Allow users to mount external storage" : "Permitir que usuários montem armazenamento externo",
"Allow users to mount the following external storage" : "Permitir que usuários montem o seguinte armazenamento externo"
},
diff --git a/apps/files_external/l10n/pt_BR.json b/apps/files_external/l10n/pt_BR.json
index bb6e0a96cff..3e351013fd1 100644
--- a/apps/files_external/l10n/pt_BR.json
+++ b/apps/files_external/l10n/pt_BR.json
@@ -15,6 +15,8 @@
"Unsatisfied backend parameters" : "Parâmetros de back-end não-atendidos",
"Unsatisfied authentication mechanism parameters" : "Parâmetros de mecanismos de autenticação não satisfeitos",
"Insufficient data: %s" : "Dados insuficientes: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Armazenamento com ID \"%i\" não é editável pelo usuário",
"Personal" : "Pessoal",
"System" : "Sistema",
"Grant access" : "Permitir acesso",
@@ -25,13 +27,22 @@
"Error generating key pair" : "Erro ao gerar um par de chaves",
"Enable encryption" : "Ativar criptografia",
"Enable previews" : "Habilitar visualizações prévias",
+ "Enable sharing" : "Habilitar compartilhamento",
"Check for changes" : "Verifique se há alterações",
"Never" : "Nunca",
"Once every direct access" : "Uma vez a cada acesso direto",
- "Every time the filesystem is used" : "Toda vez que o sistema de arquivos é usado",
"All users. Type to select user or group." : "Todos os usuários. Digite para selecionar usuário ou grupo.",
"(group)" : "(grupo)",
+ "Admin defined" : "Definido pelo administrador",
"Saved" : "Salvo",
+ "Empty response from the server" : "Resposta vazia a partir do servidor",
+ "Couldn't access. Please logout and login to activate this mount point" : "Não foi possível acessar. Por favor, desconectar e conectar novamente para ativar este ponto de montagem",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Não foi possível obter as informações do servidor ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Não foi possível obter a lista de pontos de montagem externos: {type}",
+ "There was an error with message: " : "Houve um erro com a mensagem:",
+ "External mount error" : "Erro de montagem externa",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Não foi possível obter a lista unidades de pontos de montagem da rede do Windows: resposta vazia a partir do servidor",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Alguns dos pontos de montagem externos configurados não estão conectados. Por favor clique na linha vermelha(s) para mais informações",
"Access key" : "Chave da acesso",
"Secret key" : "Chave secreta",
"Builtin" : "Construídas em",
@@ -49,8 +60,10 @@
"Identity endpoint URL" : "Identidade pontofinal URL",
"Rackspace" : "Espaço em rack",
"API key" : "Chave API",
+ "Log-in credentials, save in database" : "Credenciais de login, salvos no banco de dados",
"Username and password" : "Nome de Usuário e senha",
- "Session credentials" : "Credenciais de Sessão",
+ "Log-in credentials, save in session" : "Credenciais de login, guardados em sessão",
+ "User entered, store in database" : "Usuário digitou, armazenar em banco de dados",
"RSA public key" : "Chave pública RSA",
"Public key" : "Chave pública",
"Amazon S3" : "Amazon S3",
@@ -97,9 +110,9 @@
"Authentication" : "Autenticação",
"Configuration" : "Configuração",
"Available for" : "Disponível para",
+ "Add storage" : "Adicionar Armazenamento",
"Advanced settings" : "Configurações avançadas",
"Delete" : "Excluir",
- "Add storage" : "Adicionar Armazenamento",
"Allow users to mount external storage" : "Permitir que usuários montem armazenamento externo",
"Allow users to mount the following external storage" : "Permitir que usuários montem o seguinte armazenamento externo"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
diff --git a/apps/files_external/l10n/pt_PT.js b/apps/files_external/l10n/pt_PT.js
index 4e8b3245e66..ef75f504bcf 100644
--- a/apps/files_external/l10n/pt_PT.js
+++ b/apps/files_external/l10n/pt_PT.js
@@ -10,11 +10,15 @@ OC.L10N.register(
"Storage with id \"%i\" not found" : "Não foi encontrado o armazenamento com a id. \"%i\"",
"Invalid backend or authentication mechanism class" : "Parâmetros do mecanismo de autenticação inválidos",
"Invalid mount point" : "Ponto de montagem inválido",
+ "Objectstore forbidden" : "Objectstore proibido",
"Invalid storage backend \"%s\"" : "Backend de armazenamento inválido \"%s\"",
"Not permitted to use backend \"%s\"" : "Não é permitido utilizar a interface \"%s\"",
"Not permitted to use authentication mechanism \"%s\"" : "Não é permitido utilizar o mecanismo de autenticação \"%s\"",
+ "Unsatisfied backend parameters" : "Parâmetros backend insatisfeitos",
"Unsatisfied authentication mechanism parameters" : "Parâmetros do mecanismo de autenticação inválidos",
"Insufficient data: %s" : "Dados insuficientes: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Armazenamento com id \"%i\" não é editável pelo utilizador",
"Personal" : "Pessoal",
"System" : "Sistema",
"Grant access" : "Conceder acesso",
@@ -25,13 +29,22 @@ OC.L10N.register(
"Error generating key pair" : "Erro ao gerar chave par",
"Enable encryption" : "Ative a encriptação",
"Enable previews" : "Ative as pré-visualizações",
+ "Enable sharing" : "Ativar partilha",
"Check for changes" : "Verifique as suas alterações",
"Never" : "Nunca",
"Once every direct access" : "Uma vez em cada acesso direto",
- "Every time the filesystem is used" : "De todas as vezes que o sistema de ficheiros é usado",
"All users. Type to select user or group." : "Todos os utilizadores. Digite para selecionar o utilizador ou grupo.",
"(group)" : "(grupo)",
+ "Admin defined" : "Administrador definido",
"Saved" : "Guardado",
+ "Empty response from the server" : "Resposta vazia a partir do servidor",
+ "Couldn't access. Please logout and login to activate this mount point" : "Não foi possível aceder. Por favor, faça logout e login para ativar este ponto de montagem",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Não foi possível recolher a informação do servidor ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Não foi possível conseguir a lista de pontos de montagem externos: {type}",
+ "There was an error with message: " : "Houve um erro com a mensagem:",
+ "External mount error" : "Erro de montagem externa",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Não foi possível conseguir a lista de pontos de montagem Windows na rede: resposta vazia do servidor",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Alguns dos pontos de montagem externos configurados não estão conectados. Por favor, clique na fila vermelha para mais informação",
"Access key" : "Código de acesso",
"Secret key" : "Código secreto",
"Builtin" : "Integrado",
@@ -42,11 +55,17 @@ OC.L10N.register(
"OAuth2" : "OAuth2",
"Client ID" : "Id. do Cliente",
"Client secret" : "Segredo do cliente\\\\",
+ "OpenStack" : "OpenStack",
"Username" : "Nome de utilizador",
"Password" : "Palavra-passe",
+ "Tenant name" : "Nome do locatário",
+ "Identity endpoint URL" : "Identidade URL endpoint",
+ "Rackspace" : "Rackspace",
"API key" : "Chave API",
+ "Log-in credentials, save in database" : "Credenciais de login, guardar na base de dados",
"Username and password" : "Nome de utilizador e palavra-passe",
- "Session credentials" : "Credenciais da sessão",
+ "Log-in credentials, save in session" : "Credenciais de login, guardar na sessão",
+ "User entered, store in database" : "Utilizador introduzido, guardar na base de dados",
"RSA public key" : "Chave pública RSA",
"Public key" : "Chave pública",
"Amazon S3" : "Amazon S3",
@@ -70,6 +89,7 @@ OC.L10N.register(
"ownCloud" : "ownCloud",
"SFTP" : "SFTP",
"Root" : "Root",
+ "SFTP with secret key login" : "SFTP com login por chave secreta",
"SMB / CIFS" : "SMB / CIFS",
"Share" : "Compartilhar",
"Domain" : "Domínio",
@@ -92,9 +112,10 @@ OC.L10N.register(
"Authentication" : "Autenticação",
"Configuration" : "Configuração",
"Available for" : "Disponível para ",
+ "Add storage" : "Adicionar armazenamento",
"Advanced settings" : "Definições avançadas",
"Delete" : "Apagar",
- "Add storage" : "Adicionar armazenamento",
+ "Allow users to mount external storage" : "Permitir que os utilizadores montem armazenamento externo",
"Allow users to mount the following external storage" : "Permitir que os utilizadores montem o seguinte armazenamento externo"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/pt_PT.json b/apps/files_external/l10n/pt_PT.json
index 51333429106..686802379ee 100644
--- a/apps/files_external/l10n/pt_PT.json
+++ b/apps/files_external/l10n/pt_PT.json
@@ -8,11 +8,15 @@
"Storage with id \"%i\" not found" : "Não foi encontrado o armazenamento com a id. \"%i\"",
"Invalid backend or authentication mechanism class" : "Parâmetros do mecanismo de autenticação inválidos",
"Invalid mount point" : "Ponto de montagem inválido",
+ "Objectstore forbidden" : "Objectstore proibido",
"Invalid storage backend \"%s\"" : "Backend de armazenamento inválido \"%s\"",
"Not permitted to use backend \"%s\"" : "Não é permitido utilizar a interface \"%s\"",
"Not permitted to use authentication mechanism \"%s\"" : "Não é permitido utilizar o mecanismo de autenticação \"%s\"",
+ "Unsatisfied backend parameters" : "Parâmetros backend insatisfeitos",
"Unsatisfied authentication mechanism parameters" : "Parâmetros do mecanismo de autenticação inválidos",
"Insufficient data: %s" : "Dados insuficientes: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Armazenamento com id \"%i\" não é editável pelo utilizador",
"Personal" : "Pessoal",
"System" : "Sistema",
"Grant access" : "Conceder acesso",
@@ -23,13 +27,22 @@
"Error generating key pair" : "Erro ao gerar chave par",
"Enable encryption" : "Ative a encriptação",
"Enable previews" : "Ative as pré-visualizações",
+ "Enable sharing" : "Ativar partilha",
"Check for changes" : "Verifique as suas alterações",
"Never" : "Nunca",
"Once every direct access" : "Uma vez em cada acesso direto",
- "Every time the filesystem is used" : "De todas as vezes que o sistema de ficheiros é usado",
"All users. Type to select user or group." : "Todos os utilizadores. Digite para selecionar o utilizador ou grupo.",
"(group)" : "(grupo)",
+ "Admin defined" : "Administrador definido",
"Saved" : "Guardado",
+ "Empty response from the server" : "Resposta vazia a partir do servidor",
+ "Couldn't access. Please logout and login to activate this mount point" : "Não foi possível aceder. Por favor, faça logout e login para ativar este ponto de montagem",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Não foi possível recolher a informação do servidor ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Não foi possível conseguir a lista de pontos de montagem externos: {type}",
+ "There was an error with message: " : "Houve um erro com a mensagem:",
+ "External mount error" : "Erro de montagem externa",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Não foi possível conseguir a lista de pontos de montagem Windows na rede: resposta vazia do servidor",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Alguns dos pontos de montagem externos configurados não estão conectados. Por favor, clique na fila vermelha para mais informação",
"Access key" : "Código de acesso",
"Secret key" : "Código secreto",
"Builtin" : "Integrado",
@@ -40,11 +53,17 @@
"OAuth2" : "OAuth2",
"Client ID" : "Id. do Cliente",
"Client secret" : "Segredo do cliente\\\\",
+ "OpenStack" : "OpenStack",
"Username" : "Nome de utilizador",
"Password" : "Palavra-passe",
+ "Tenant name" : "Nome do locatário",
+ "Identity endpoint URL" : "Identidade URL endpoint",
+ "Rackspace" : "Rackspace",
"API key" : "Chave API",
+ "Log-in credentials, save in database" : "Credenciais de login, guardar na base de dados",
"Username and password" : "Nome de utilizador e palavra-passe",
- "Session credentials" : "Credenciais da sessão",
+ "Log-in credentials, save in session" : "Credenciais de login, guardar na sessão",
+ "User entered, store in database" : "Utilizador introduzido, guardar na base de dados",
"RSA public key" : "Chave pública RSA",
"Public key" : "Chave pública",
"Amazon S3" : "Amazon S3",
@@ -68,6 +87,7 @@
"ownCloud" : "ownCloud",
"SFTP" : "SFTP",
"Root" : "Root",
+ "SFTP with secret key login" : "SFTP com login por chave secreta",
"SMB / CIFS" : "SMB / CIFS",
"Share" : "Compartilhar",
"Domain" : "Domínio",
@@ -90,9 +110,10 @@
"Authentication" : "Autenticação",
"Configuration" : "Configuração",
"Available for" : "Disponível para ",
+ "Add storage" : "Adicionar armazenamento",
"Advanced settings" : "Definições avançadas",
"Delete" : "Apagar",
- "Add storage" : "Adicionar armazenamento",
+ "Allow users to mount external storage" : "Permitir que os utilizadores montem armazenamento externo",
"Allow users to mount the following external storage" : "Permitir que os utilizadores montem o seguinte armazenamento externo"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/ro.js b/apps/files_external/l10n/ro.js
index d8ba040824c..cc3a065a21d 100644
--- a/apps/files_external/l10n/ro.js
+++ b/apps/files_external/l10n/ro.js
@@ -29,8 +29,8 @@ OC.L10N.register(
"External Storage" : "Stocare externă",
"Folder name" : "Denumire director",
"Configuration" : "Configurație",
- "Delete" : "Șterge",
"Add storage" : "Adauga stocare",
+ "Delete" : "Șterge",
"Allow users to mount the following external storage" : "Permite utilizatorilor să monteze următoarea unitate de stocare"
},
"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));");
diff --git a/apps/files_external/l10n/ro.json b/apps/files_external/l10n/ro.json
index cbe2826def4..2f1f8e32883 100644
--- a/apps/files_external/l10n/ro.json
+++ b/apps/files_external/l10n/ro.json
@@ -27,8 +27,8 @@
"External Storage" : "Stocare externă",
"Folder name" : "Denumire director",
"Configuration" : "Configurație",
- "Delete" : "Șterge",
"Add storage" : "Adauga stocare",
+ "Delete" : "Șterge",
"Allow users to mount the following external storage" : "Permite utilizatorilor să monteze următoarea unitate de stocare"
},"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/ru.js b/apps/files_external/l10n/ru.js
index 5550ea780ab..989f2e82a41 100644
--- a/apps/files_external/l10n/ru.js
+++ b/apps/files_external/l10n/ru.js
@@ -16,6 +16,9 @@ OC.L10N.register(
"Not permitted to use authentication mechanism \"%s\"" : "Не допускается использование механизма авторизации \"%s\"",
"Unsatisfied backend parameters" : "Недопустимые настройки бэкенда",
"Unsatisfied authentication mechanism parameters" : "Недопустимые настройки механизма авторизации",
+ "Insufficient data: %s" : "Недостаточно данных: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Пользователь не может редактировать хранилище \"%i\"",
"Personal" : "Личное",
"System" : "Система",
"Grant access" : "Предоставить доступ",
@@ -26,13 +29,22 @@ OC.L10N.register(
"Error generating key pair" : "Ошибка создания ключевой пары",
"Enable encryption" : "Включить шифрование",
"Enable previews" : "Включить предпросмотр",
+ "Enable sharing" : "Включить общий доступ",
"Check for changes" : "Проверять изменения",
"Never" : "Никогда",
"Once every direct access" : "Один раз при прямом доступе",
- "Every time the filesystem is used" : "Каждый раз при обращении к файловой системе",
"All users. Type to select user or group." : "Все пользователи. Введите имя пользователя или группы.",
"(group)" : "(группа)",
+ "Admin defined" : "Админ определен",
"Saved" : "Сохранено",
+ "Empty response from the server" : "Пустой ответ от сервера",
+ "Couldn't access. Please logout and login to activate this mount point" : "Не удалось получить доступ. Пожалуйста, выйти и войдите чтобы активировать эту точку монтирования",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Не удалось получить информацию от сервера OwnCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Не удалось получить список внешних точек монтирования: {type}",
+ "There was an error with message: " : "Обнаружена ошибка в сообщении:",
+ "External mount error" : "Ошибка внешнего монтажа",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Не удалось получить список окон сетевого диска точки монтирования: пустой ответ от сервера",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Некоторые из настроенных внешних точек монтирования не подключены. Для получения дополнительной информации, пожалуйста нажмите на красную строку (ы)",
"Access key" : "Ключ доступа",
"Secret key" : "Секретный ключ",
"Builtin" : "Встроенный",
@@ -50,8 +62,10 @@ OC.L10N.register(
"Identity endpoint URL" : "Удостоверение конечной точки URL",
"Rackspace" : "Rackspace",
"API key" : "Ключ API",
+ "Log-in credentials, save in database" : "Учетные данные, хранить в базе данных",
"Username and password" : "Имя пользователя и пароль",
- "Session credentials" : "Учетные данные сессии",
+ "Log-in credentials, save in session" : "Учетные данные, хранить в сессии",
+ "User entered, store in database" : "Введенные пользователем, хранить в базе данных",
"RSA public key" : "Открытый ключ RSA",
"Public key" : "Открытый ключ",
"Amazon S3" : "Amazon S3",
@@ -98,9 +112,10 @@ OC.L10N.register(
"Authentication" : "Авторизация",
"Configuration" : "Конфигурация",
"Available for" : "Доступно для",
+ "Add storage" : "Добавить хранилище",
"Advanced settings" : "Расширенные настройки",
"Delete" : "Удалить",
- "Add storage" : "Добавить хранилище",
+ "Allow users to mount external storage" : "Разрешить пользователями монтировать внешние накопители",
"Allow users to mount the following external storage" : "Разрешить пользователям монтировать следующие сервисы хранения данных"
},
"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/apps/files_external/l10n/ru.json b/apps/files_external/l10n/ru.json
index 52792a3f09a..53595aee4a5 100644
--- a/apps/files_external/l10n/ru.json
+++ b/apps/files_external/l10n/ru.json
@@ -14,6 +14,9 @@
"Not permitted to use authentication mechanism \"%s\"" : "Не допускается использование механизма авторизации \"%s\"",
"Unsatisfied backend parameters" : "Недопустимые настройки бэкенда",
"Unsatisfied authentication mechanism parameters" : "Недопустимые настройки механизма авторизации",
+ "Insufficient data: %s" : "Недостаточно данных: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Пользователь не может редактировать хранилище \"%i\"",
"Personal" : "Личное",
"System" : "Система",
"Grant access" : "Предоставить доступ",
@@ -24,13 +27,22 @@
"Error generating key pair" : "Ошибка создания ключевой пары",
"Enable encryption" : "Включить шифрование",
"Enable previews" : "Включить предпросмотр",
+ "Enable sharing" : "Включить общий доступ",
"Check for changes" : "Проверять изменения",
"Never" : "Никогда",
"Once every direct access" : "Один раз при прямом доступе",
- "Every time the filesystem is used" : "Каждый раз при обращении к файловой системе",
"All users. Type to select user or group." : "Все пользователи. Введите имя пользователя или группы.",
"(group)" : "(группа)",
+ "Admin defined" : "Админ определен",
"Saved" : "Сохранено",
+ "Empty response from the server" : "Пустой ответ от сервера",
+ "Couldn't access. Please logout and login to activate this mount point" : "Не удалось получить доступ. Пожалуйста, выйти и войдите чтобы активировать эту точку монтирования",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "Не удалось получить информацию от сервера OwnCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "Не удалось получить список внешних точек монтирования: {type}",
+ "There was an error with message: " : "Обнаружена ошибка в сообщении:",
+ "External mount error" : "Ошибка внешнего монтажа",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "Не удалось получить список окон сетевого диска точки монтирования: пустой ответ от сервера",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Некоторые из настроенных внешних точек монтирования не подключены. Для получения дополнительной информации, пожалуйста нажмите на красную строку (ы)",
"Access key" : "Ключ доступа",
"Secret key" : "Секретный ключ",
"Builtin" : "Встроенный",
@@ -48,8 +60,10 @@
"Identity endpoint URL" : "Удостоверение конечной точки URL",
"Rackspace" : "Rackspace",
"API key" : "Ключ API",
+ "Log-in credentials, save in database" : "Учетные данные, хранить в базе данных",
"Username and password" : "Имя пользователя и пароль",
- "Session credentials" : "Учетные данные сессии",
+ "Log-in credentials, save in session" : "Учетные данные, хранить в сессии",
+ "User entered, store in database" : "Введенные пользователем, хранить в базе данных",
"RSA public key" : "Открытый ключ RSA",
"Public key" : "Открытый ключ",
"Amazon S3" : "Amazon S3",
@@ -96,9 +110,10 @@
"Authentication" : "Авторизация",
"Configuration" : "Конфигурация",
"Available for" : "Доступно для",
+ "Add storage" : "Добавить хранилище",
"Advanced settings" : "Расширенные настройки",
"Delete" : "Удалить",
- "Add storage" : "Добавить хранилище",
+ "Allow users to mount external storage" : "Разрешить пользователями монтировать внешние накопители",
"Allow users to mount the following external storage" : "Разрешить пользователям монтировать следующие сервисы хранения данных"
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/sk_SK.js b/apps/files_external/l10n/sk_SK.js
index 41f9c866196..72fb57a1e0b 100644
--- a/apps/files_external/l10n/sk_SK.js
+++ b/apps/files_external/l10n/sk_SK.js
@@ -29,7 +29,6 @@ OC.L10N.register(
"Check for changes" : "Zisťovať zmeny",
"Never" : "Nikdy",
"Once every direct access" : "S každým priamym prístupom",
- "Every time the filesystem is used" : "Vždy keď je použitý súborový systém",
"All users. Type to select user or group." : "Všetci používatelia. Začnite písať pre výber používateľa alebo skupinu.",
"(group)" : "(skupina)",
"Saved" : "Uložené",
@@ -51,7 +50,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "API kľúč",
"Username and password" : "Meno a heslo",
- "Session credentials" : "Pihlasovacie údaje sezóny",
"RSA public key" : "RSA verejný kľúč",
"Public key" : "Verejný kľúč",
"Amazon S3" : "Amazon S3",
@@ -97,9 +95,9 @@ OC.L10N.register(
"Authentication" : "Autentifikácia",
"Configuration" : "Nastavenia",
"Available for" : "K dispozícii pre",
+ "Add storage" : "Pridať úložisko",
"Advanced settings" : "Rozšírené nastavenia",
"Delete" : "Zmazať",
- "Add storage" : "Pridať úložisko",
"Allow users to mount the following external storage" : "Povoliť používateľom pripojiť tieto externé úložiská"
},
"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;");
diff --git a/apps/files_external/l10n/sk_SK.json b/apps/files_external/l10n/sk_SK.json
index 4072136fa53..267eb5b48b9 100644
--- a/apps/files_external/l10n/sk_SK.json
+++ b/apps/files_external/l10n/sk_SK.json
@@ -27,7 +27,6 @@
"Check for changes" : "Zisťovať zmeny",
"Never" : "Nikdy",
"Once every direct access" : "S každým priamym prístupom",
- "Every time the filesystem is used" : "Vždy keď je použitý súborový systém",
"All users. Type to select user or group." : "Všetci používatelia. Začnite písať pre výber používateľa alebo skupinu.",
"(group)" : "(skupina)",
"Saved" : "Uložené",
@@ -49,7 +48,6 @@
"Rackspace" : "Rackspace",
"API key" : "API kľúč",
"Username and password" : "Meno a heslo",
- "Session credentials" : "Pihlasovacie údaje sezóny",
"RSA public key" : "RSA verejný kľúč",
"Public key" : "Verejný kľúč",
"Amazon S3" : "Amazon S3",
@@ -95,9 +93,9 @@
"Authentication" : "Autentifikácia",
"Configuration" : "Nastavenia",
"Available for" : "K dispozícii pre",
+ "Add storage" : "Pridať úložisko",
"Advanced settings" : "Rozšírené nastavenia",
"Delete" : "Zmazať",
- "Add storage" : "Pridať úložisko",
"Allow users to mount the following external storage" : "Povoliť používateľom pripojiť tieto externé úložiská"
},"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/sl.js b/apps/files_external/l10n/sl.js
index f9513a5f11c..62b35ffab5e 100644
--- a/apps/files_external/l10n/sl.js
+++ b/apps/files_external/l10n/sl.js
@@ -7,10 +7,14 @@ OC.L10N.register(
"Storage with id \"%i\" not found" : "Shrambe z ID \"%i\" ni mogoče najti.",
"Invalid mount point" : "Neveljavna priklopna točka",
"Invalid storage backend \"%s\"" : "Neveljaven ozadnji program shrambe \"%s\"",
+ "Insufficient data: %s" : "Nepopolni podatki: %s",
+ "%s" : "%s",
"Personal" : "Osebno",
"System" : "Sistem",
"Grant access" : "Odobri dostop",
"Access granted" : "Dostop je odobren",
+ "Error configuring OAuth1" : "Napaka nastavljanja OAuth1",
+ "Error configuring OAuth2" : "Napaka nastavljanja OAuth2",
"Generate keys" : "Ustvari ključe",
"Error generating key pair" : "Prišlo je do napake med ustvarjanjem para ključev",
"Enable encryption" : "Omogoči šifriranje",
@@ -18,18 +22,27 @@ OC.L10N.register(
"Check for changes" : "Preveri za spremembe",
"Never" : "Nikoli",
"Once every direct access" : "Enkrat ob neposrednem dostopu",
- "Every time the filesystem is used" : "Kadarkoli je datotečni sistem v uporabi",
"All users. Type to select user or group." : "Vsi uporabniki. Skupino ali uporabnika je mogoče tudi izbrati.",
"(group)" : "(skupina)",
"Saved" : "Shranjeno",
+ "External mount error" : "Notranja napaka priklopa",
+ "Access key" : "Ključ za dostop",
+ "Secret key" : "Skriti ključ",
+ "Builtin" : "Vgrajeno",
"None" : "Brez",
+ "OAuth1" : "OAuth1",
"App key" : "Programski ključ",
"App secret" : "Skrivni programski ključ",
+ "OAuth2" : "OAuth2",
"Client ID" : "ID odjemalca",
"Client secret" : "Skrivni ključ odjemalca",
+ "OpenStack" : "OpenStack",
"Username" : "Uporabniško ime",
"Password" : "Geslo",
+ "Tenant name" : "Ime uporabnika",
"API key" : "Ključ API",
+ "Username and password" : "Uporabniško ime in geslo",
+ "RSA public key" : "Javni ključ RSA",
"Public key" : "Javni ključ",
"Amazon S3" : "Amazon S3",
"Bucket" : "Pomnilniško vedro",
@@ -43,17 +56,23 @@ OC.L10N.register(
"Remote subfolder" : "Oddaljena podrejena mapa",
"Secure https://" : "Varni način https://",
"Dropbox" : "Dropbox",
+ "FTP" : "FTP",
"Host" : "Gostitelj",
"Secure ftps://" : "Varni način ftps://",
+ "Google Drive" : "Google Drive",
"Local" : "Krajevno",
"Location" : "Mesto",
"ownCloud" : "ownCloud",
+ "SFTP" : "SFTP",
"Root" : "Koren",
- "SFTP with secret key login" : "Prijava preko protokola SFTP z geslom",
+ "SFTP with secret key login" : "Prijava prek protokola SFTP z geslom",
+ "SMB / CIFS" : "SMB / CIFS",
"Share" : "Souporaba",
+ "Domain" : "Domena",
"SMB / CIFS using OC login" : "SMB / CIFS z uporabo prijave OC",
"Username as share" : "Uporabniško ime za souporabo",
"OpenStack Object Storage" : "Shramba predmeta OpenStack",
+ "Service name" : "Ime storitve",
"<b>Note:</b> " : "<b>Opomba:</b> ",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Opomba:</b> Podpora za naslove cURL v PHP ni omogočena, ali pa ni ustrezno nameščenih programov. Priklapljanje %s ni mogoče. Za pomoč pri namestitvi se obrnite na sistemskega skrbnika.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Opomba:</b> Podpora za protokol FTP v PHP ni omogočena, ali pa ni ustrezno nameščenih programov. Priklapljanje %s ni mogoče. Za pomoč pri namestitvi se obrnite na sistemskega skrbnika.",
@@ -65,11 +84,13 @@ OC.L10N.register(
"Scope" : "Obseg",
"External Storage" : "Zunanja podatkovna shramba",
"Folder name" : "Ime mape",
+ "Authentication" : "Overitev",
"Configuration" : "Nastavitve",
"Available for" : "Na voljo za",
+ "Add storage" : "Dodaj shrambo",
"Advanced settings" : "Napredne nastavitve",
"Delete" : "Izbriši",
- "Add storage" : "Dodaj shrambo",
+ "Allow users to mount external storage" : "Dovoli uporabnikom priklapljanje zunanje shrambe",
"Allow users to mount the following external storage" : "Dovoli uporabnikom priklapljanje navedenih zunanjih shramb."
},
"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);");
diff --git a/apps/files_external/l10n/sl.json b/apps/files_external/l10n/sl.json
index ca97f27b234..3a806fbd25b 100644
--- a/apps/files_external/l10n/sl.json
+++ b/apps/files_external/l10n/sl.json
@@ -5,10 +5,14 @@
"Storage with id \"%i\" not found" : "Shrambe z ID \"%i\" ni mogoče najti.",
"Invalid mount point" : "Neveljavna priklopna točka",
"Invalid storage backend \"%s\"" : "Neveljaven ozadnji program shrambe \"%s\"",
+ "Insufficient data: %s" : "Nepopolni podatki: %s",
+ "%s" : "%s",
"Personal" : "Osebno",
"System" : "Sistem",
"Grant access" : "Odobri dostop",
"Access granted" : "Dostop je odobren",
+ "Error configuring OAuth1" : "Napaka nastavljanja OAuth1",
+ "Error configuring OAuth2" : "Napaka nastavljanja OAuth2",
"Generate keys" : "Ustvari ključe",
"Error generating key pair" : "Prišlo je do napake med ustvarjanjem para ključev",
"Enable encryption" : "Omogoči šifriranje",
@@ -16,18 +20,27 @@
"Check for changes" : "Preveri za spremembe",
"Never" : "Nikoli",
"Once every direct access" : "Enkrat ob neposrednem dostopu",
- "Every time the filesystem is used" : "Kadarkoli je datotečni sistem v uporabi",
"All users. Type to select user or group." : "Vsi uporabniki. Skupino ali uporabnika je mogoče tudi izbrati.",
"(group)" : "(skupina)",
"Saved" : "Shranjeno",
+ "External mount error" : "Notranja napaka priklopa",
+ "Access key" : "Ključ za dostop",
+ "Secret key" : "Skriti ključ",
+ "Builtin" : "Vgrajeno",
"None" : "Brez",
+ "OAuth1" : "OAuth1",
"App key" : "Programski ključ",
"App secret" : "Skrivni programski ključ",
+ "OAuth2" : "OAuth2",
"Client ID" : "ID odjemalca",
"Client secret" : "Skrivni ključ odjemalca",
+ "OpenStack" : "OpenStack",
"Username" : "Uporabniško ime",
"Password" : "Geslo",
+ "Tenant name" : "Ime uporabnika",
"API key" : "Ključ API",
+ "Username and password" : "Uporabniško ime in geslo",
+ "RSA public key" : "Javni ključ RSA",
"Public key" : "Javni ključ",
"Amazon S3" : "Amazon S3",
"Bucket" : "Pomnilniško vedro",
@@ -41,17 +54,23 @@
"Remote subfolder" : "Oddaljena podrejena mapa",
"Secure https://" : "Varni način https://",
"Dropbox" : "Dropbox",
+ "FTP" : "FTP",
"Host" : "Gostitelj",
"Secure ftps://" : "Varni način ftps://",
+ "Google Drive" : "Google Drive",
"Local" : "Krajevno",
"Location" : "Mesto",
"ownCloud" : "ownCloud",
+ "SFTP" : "SFTP",
"Root" : "Koren",
- "SFTP with secret key login" : "Prijava preko protokola SFTP z geslom",
+ "SFTP with secret key login" : "Prijava prek protokola SFTP z geslom",
+ "SMB / CIFS" : "SMB / CIFS",
"Share" : "Souporaba",
+ "Domain" : "Domena",
"SMB / CIFS using OC login" : "SMB / CIFS z uporabo prijave OC",
"Username as share" : "Uporabniško ime za souporabo",
"OpenStack Object Storage" : "Shramba predmeta OpenStack",
+ "Service name" : "Ime storitve",
"<b>Note:</b> " : "<b>Opomba:</b> ",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Opomba:</b> Podpora za naslove cURL v PHP ni omogočena, ali pa ni ustrezno nameščenih programov. Priklapljanje %s ni mogoče. Za pomoč pri namestitvi se obrnite na sistemskega skrbnika.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Opomba:</b> Podpora za protokol FTP v PHP ni omogočena, ali pa ni ustrezno nameščenih programov. Priklapljanje %s ni mogoče. Za pomoč pri namestitvi se obrnite na sistemskega skrbnika.",
@@ -63,11 +82,13 @@
"Scope" : "Obseg",
"External Storage" : "Zunanja podatkovna shramba",
"Folder name" : "Ime mape",
+ "Authentication" : "Overitev",
"Configuration" : "Nastavitve",
"Available for" : "Na voljo za",
+ "Add storage" : "Dodaj shrambo",
"Advanced settings" : "Napredne nastavitve",
"Delete" : "Izbriši",
- "Add storage" : "Dodaj shrambo",
+ "Allow users to mount external storage" : "Dovoli uporabnikom priklapljanje zunanje shrambe",
"Allow users to mount the following external storage" : "Dovoli uporabnikom priklapljanje navedenih zunanjih shramb."
},"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/sq.js b/apps/files_external/l10n/sq.js
index f8e5c5a27dc..1005519b4da 100644
--- a/apps/files_external/l10n/sq.js
+++ b/apps/files_external/l10n/sq.js
@@ -17,6 +17,8 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "Parametra mekanizmi shërbimi të paplotësuar",
"Unsatisfied authentication mechanism parameters" : "Parametra mekanizmi mirëfilltësimi të papërmbushur",
"Insufficient data: %s" : "Të dhëna të pamjaftueshme: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Depozita me id \"%i\" s’është e përpunueshme nga përdoruesi",
"Personal" : "Personale",
"System" : "Sistem",
"Grant access" : "Akordoji hyrje",
@@ -27,13 +29,22 @@ OC.L10N.register(
"Error generating key pair" : "Gabim gjatë prodhimit të çiftit të kyçeve",
"Enable encryption" : "Aktivizoni fshehtëzim",
"Enable previews" : "Aktivizoni paraparje",
+ "Enable sharing" : "Aktivizo ndarjet",
"Check for changes" : "Kontrollo për ndryshime",
"Never" : "Kurrë",
"Once every direct access" : "Çdo herë pas hyrjesh të drejtpërdrejta",
- "Every time the filesystem is used" : "Sa herë që përdoret sistemi i kartelave",
"All users. Type to select user or group." : "Krejt përdoruesit. Shtypni që të përzgjidhet përdorues ose grup.",
"(group)" : "(grup)",
+ "Admin defined" : "Përcaktuar nga përgjegjësi",
"Saved" : "U ruajt",
+ "Empty response from the server" : "Përgjigje e zbrazët prej shërbyesit",
+ "Couldn't access. Please logout and login to activate this mount point" : "S’fut dot. Ju lutemi, dilni dhe hyni që të aktivizohet kjo pikë montimi",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "S’u morën dot të dhëna nga shërbyesi ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "S’u mor dot lista e pikave të jashtme të montimit: {type}",
+ "There was an error with message: " : "Pati një gabim me këtë mesazh:",
+ "External mount error" : "Gabim i jashtëm montimi",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "S’u mor dot lista e pikave të montimit Windows network drive: përgjigje e zbrazët nga shërbyesi",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Disa nga pikat e jashtme të formësuara të montimit s’janë të lidhura. Ju lutemi, klikoni në shigjetën(at) e kuqe për më tepër të dhëna",
"Access key" : "Kyç hyrjesh",
"Secret key" : "Kyç i fshehtë",
"Builtin" : "I brendshëm",
@@ -47,10 +58,13 @@ OC.L10N.register(
"OpenStack" : "OpenStack",
"Username" : "Emër përdoruesi",
"Password" : "Fjalëkalim",
+ "Tenant name" : "Emër qiraxhiu",
"Rackspace" : "Rackspace",
"API key" : "Kyç API",
+ "Log-in credentials, save in database" : "Kredenciale hyrjesh, ruaje në bazën e të dhënave",
"Username and password" : "Emër përdoruesi dhe fjalëkalim",
- "Session credentials" : "Kredenciale sesioni",
+ "Log-in credentials, save in session" : "Kredenciale hyrjesh, ruaje në sesion",
+ "User entered, store in database" : "Përdoruesi u dha, ruajeni në bazën e të dhënave",
"RSA public key" : "Kyç publik RSA ",
"Public key" : "Kyç publik",
"Amazon S3" : "Amazon S3",
@@ -97,9 +111,9 @@ OC.L10N.register(
"Authentication" : "Mirëfilltësim",
"Configuration" : "Formësim",
"Available for" : "E gatshme për",
+ "Add storage" : "Shtoni depozitë",
"Advanced settings" : "Rregullime të mëtejshme",
"Delete" : "Fshije",
- "Add storage" : "Shtoni depozitë",
"Allow users to mount external storage" : "Lejoju përdoruesve të montojnë depozita të jashtme",
"Allow users to mount the following external storage" : "Lejoju përdoruesve të montojnë depozitën e jashtme vijuese"
},
diff --git a/apps/files_external/l10n/sq.json b/apps/files_external/l10n/sq.json
index 0da8e9406bb..5cadfb3acd0 100644
--- a/apps/files_external/l10n/sq.json
+++ b/apps/files_external/l10n/sq.json
@@ -15,6 +15,8 @@
"Unsatisfied backend parameters" : "Parametra mekanizmi shërbimi të paplotësuar",
"Unsatisfied authentication mechanism parameters" : "Parametra mekanizmi mirëfilltësimi të papërmbushur",
"Insufficient data: %s" : "Të dhëna të pamjaftueshme: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "Depozita me id \"%i\" s’është e përpunueshme nga përdoruesi",
"Personal" : "Personale",
"System" : "Sistem",
"Grant access" : "Akordoji hyrje",
@@ -25,13 +27,22 @@
"Error generating key pair" : "Gabim gjatë prodhimit të çiftit të kyçeve",
"Enable encryption" : "Aktivizoni fshehtëzim",
"Enable previews" : "Aktivizoni paraparje",
+ "Enable sharing" : "Aktivizo ndarjet",
"Check for changes" : "Kontrollo për ndryshime",
"Never" : "Kurrë",
"Once every direct access" : "Çdo herë pas hyrjesh të drejtpërdrejta",
- "Every time the filesystem is used" : "Sa herë që përdoret sistemi i kartelave",
"All users. Type to select user or group." : "Krejt përdoruesit. Shtypni që të përzgjidhet përdorues ose grup.",
"(group)" : "(grup)",
+ "Admin defined" : "Përcaktuar nga përgjegjësi",
"Saved" : "U ruajt",
+ "Empty response from the server" : "Përgjigje e zbrazët prej shërbyesit",
+ "Couldn't access. Please logout and login to activate this mount point" : "S’fut dot. Ju lutemi, dilni dhe hyni që të aktivizohet kjo pikë montimi",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "S’u morën dot të dhëna nga shërbyesi ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "S’u mor dot lista e pikave të jashtme të montimit: {type}",
+ "There was an error with message: " : "Pati një gabim me këtë mesazh:",
+ "External mount error" : "Gabim i jashtëm montimi",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "S’u mor dot lista e pikave të montimit Windows network drive: përgjigje e zbrazët nga shërbyesi",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Disa nga pikat e jashtme të formësuara të montimit s’janë të lidhura. Ju lutemi, klikoni në shigjetën(at) e kuqe për më tepër të dhëna",
"Access key" : "Kyç hyrjesh",
"Secret key" : "Kyç i fshehtë",
"Builtin" : "I brendshëm",
@@ -45,10 +56,13 @@
"OpenStack" : "OpenStack",
"Username" : "Emër përdoruesi",
"Password" : "Fjalëkalim",
+ "Tenant name" : "Emër qiraxhiu",
"Rackspace" : "Rackspace",
"API key" : "Kyç API",
+ "Log-in credentials, save in database" : "Kredenciale hyrjesh, ruaje në bazën e të dhënave",
"Username and password" : "Emër përdoruesi dhe fjalëkalim",
- "Session credentials" : "Kredenciale sesioni",
+ "Log-in credentials, save in session" : "Kredenciale hyrjesh, ruaje në sesion",
+ "User entered, store in database" : "Përdoruesi u dha, ruajeni në bazën e të dhënave",
"RSA public key" : "Kyç publik RSA ",
"Public key" : "Kyç publik",
"Amazon S3" : "Amazon S3",
@@ -95,9 +109,9 @@
"Authentication" : "Mirëfilltësim",
"Configuration" : "Formësim",
"Available for" : "E gatshme për",
+ "Add storage" : "Shtoni depozitë",
"Advanced settings" : "Rregullime të mëtejshme",
"Delete" : "Fshije",
- "Add storage" : "Shtoni depozitë",
"Allow users to mount external storage" : "Lejoju përdoruesve të montojnë depozita të jashtme",
"Allow users to mount the following external storage" : "Lejoju përdoruesve të montojnë depozitën e jashtme vijuese"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/files_external/l10n/sr.js b/apps/files_external/l10n/sr.js
index 02596d8ab22..a90d36b586f 100644
--- a/apps/files_external/l10n/sr.js
+++ b/apps/files_external/l10n/sr.js
@@ -18,7 +18,6 @@ OC.L10N.register(
"Check for changes" : "Провери измене",
"Never" : "никад",
"Once every direct access" : "једном при сваком директном приступу",
- "Every time the filesystem is used" : "сваки пут кад се фајл-систем користи",
"All users. Type to select user or group." : "Сви корисници. Куцајте за избор корисника или групе.",
"(group)" : "(група)",
"Saved" : "Сачувано",
@@ -66,9 +65,9 @@ OC.L10N.register(
"Folder name" : "Назив фасцикле",
"Configuration" : "Подешавање",
"Available for" : "Доступно за",
+ "Add storage" : "Додај складиште",
"Advanced settings" : "Напредне поставке",
"Delete" : "Обриши",
- "Add storage" : "Додај складиште",
"Allow users to mount the following external storage" : "Дозволи корисницима да монтирају следећа спољашња складишта"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_external/l10n/sr.json b/apps/files_external/l10n/sr.json
index f1c12eeb0f7..6c938e8a14c 100644
--- a/apps/files_external/l10n/sr.json
+++ b/apps/files_external/l10n/sr.json
@@ -16,7 +16,6 @@
"Check for changes" : "Провери измене",
"Never" : "никад",
"Once every direct access" : "једном при сваком директном приступу",
- "Every time the filesystem is used" : "сваки пут кад се фајл-систем користи",
"All users. Type to select user or group." : "Сви корисници. Куцајте за избор корисника или групе.",
"(group)" : "(група)",
"Saved" : "Сачувано",
@@ -64,9 +63,9 @@
"Folder name" : "Назив фасцикле",
"Configuration" : "Подешавање",
"Available for" : "Доступно за",
+ "Add storage" : "Додај складиште",
"Advanced settings" : "Напредне поставке",
"Delete" : "Обриши",
- "Add storage" : "Додај складиште",
"Allow users to mount the following external storage" : "Дозволи корисницима да монтирају следећа спољашња складишта"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/sr@latin.js b/apps/files_external/l10n/sr@latin.js
index 880a33c1614..0420189571c 100644
--- a/apps/files_external/l10n/sr@latin.js
+++ b/apps/files_external/l10n/sr@latin.js
@@ -48,8 +48,8 @@ OC.L10N.register(
"Folder name" : "Ime fascikle",
"Configuration" : "Podešavanje",
"Available for" : "Dostupno za",
- "Delete" : "Obriši",
"Add storage" : "Dodaj skladište",
+ "Delete" : "Obriši",
"Allow users to mount the following external storage" : "Omogući korisnicima da namontiraju sledeće spoljašnje skladište"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_external/l10n/sr@latin.json b/apps/files_external/l10n/sr@latin.json
index 760100867eb..3320ab2c863 100644
--- a/apps/files_external/l10n/sr@latin.json
+++ b/apps/files_external/l10n/sr@latin.json
@@ -46,8 +46,8 @@
"Folder name" : "Ime fascikle",
"Configuration" : "Podešavanje",
"Available for" : "Dostupno za",
- "Delete" : "Obriši",
"Add storage" : "Dodaj skladište",
+ "Delete" : "Obriši",
"Allow users to mount the following external storage" : "Omogući korisnicima da namontiraju sledeće spoljašnje skladište"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/sv.js b/apps/files_external/l10n/sv.js
index 09786533e87..f20b96caed8 100644
--- a/apps/files_external/l10n/sv.js
+++ b/apps/files_external/l10n/sv.js
@@ -53,8 +53,8 @@ OC.L10N.register(
"Folder name" : "Mappnamn",
"Configuration" : "Konfiguration",
"Available for" : "Tillgänglig för",
- "Delete" : "Radera",
"Add storage" : "Lägg till lagring",
+ "Delete" : "Radera",
"Allow users to mount the following external storage" : "Tillåt användare att montera följande extern lagring"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/sv.json b/apps/files_external/l10n/sv.json
index ddb7439cb8d..cd3dc13296d 100644
--- a/apps/files_external/l10n/sv.json
+++ b/apps/files_external/l10n/sv.json
@@ -51,8 +51,8 @@
"Folder name" : "Mappnamn",
"Configuration" : "Konfiguration",
"Available for" : "Tillgänglig för",
- "Delete" : "Radera",
"Add storage" : "Lägg till lagring",
+ "Delete" : "Radera",
"Allow users to mount the following external storage" : "Tillåt användare att montera följande extern lagring"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/th_TH.js b/apps/files_external/l10n/th_TH.js
index 55611a5531d..19ac36fa429 100644
--- a/apps/files_external/l10n/th_TH.js
+++ b/apps/files_external/l10n/th_TH.js
@@ -17,6 +17,8 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "พารามิเตอร์แบ็กเอนด์ไม่ได้รับอนุญาต",
"Unsatisfied authentication mechanism parameters" : "การรับรองความถูกต้องไม่เพียงพอ",
"Insufficient data: %s" : "ข้อมูลไม่เพียงพอ: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "พื้นที่เก็บข้อมูล รหัส \"%i\" ไม่อนุญาตให้ผู้ใช้แก้ไขข้อมูลได้",
"Personal" : "ส่วนตัว",
"System" : "ระบบ",
"Grant access" : "อนุญาตให้เข้าถึงได้",
@@ -27,13 +29,22 @@ OC.L10N.register(
"Error generating key pair" : "ข้อผิดพลาดในการสร้างคีย์แบบเป็นคู่",
"Enable encryption" : "เปิดใช้งานการเข้ารหัส",
"Enable previews" : "เปิดใช้งานการแสดงตัวอย่าง",
+ "Enable sharing" : "เปิดให้สามารถแชร์ได้",
"Check for changes" : "ตรวจสอบการเปลี่ยนแปลง",
"Never" : "ไม่เคย",
"Once every direct access" : "เมื่อทุกคนเข้าถึงโดยตรง",
- "Every time the filesystem is used" : "ทุกครั้งที่แฟ้มระบบถูกใช้งาน",
"All users. Type to select user or group." : "ผู้ใช้ทุกคน พิมพ์เพื่อเลือกผู้ใช้หรือกลุ่ม",
"(group)" : "(กลุ่ม)",
+ "Admin defined" : "ถูกกำหนดโดยผู้ดูแลระบบ",
"Saved" : "บันทึกแล้ว",
+ "Empty response from the server" : "ไม่มีการตอบสนองจากเซิร์ฟเวอร์",
+ "Couldn't access. Please logout and login to activate this mount point" : "ไม่สามารถเข้าถึง กรุณออกจากระบบและาเข้าสู่ระบบใหม่เพื่อเปิดใช้งานจุดเชื่อมต่อนี้",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "ไม่สามารถรับข้อมูลจากเซิร์ฟเวอร์ ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "ไม่สามารถรับรายชื่อของจุดเชื่อมต่อภายนอก: {type}",
+ "There was an error with message: " : "มีข้อความแสดงข้อผิดพลาด",
+ "External mount error" : "การติดจากตั้งภายนอกเกิดข้อผิดพลาด",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "ไม่สามารถรับรายชื่อไดรฟ์เครือข่ายของวินโดว์ส จุดที่ติดตั้ง: ไม่มีการตอบสนองจากเซิร์ฟเวอร์",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "การกำหนดค่าบางส่วนของจุดเชื่อมต่อภายนอกไม่ถูกเชื่อมต่อ กรุณาคลิกที่ตรงสีแดงสำหรับข้อมูลเพิ่มเติม",
"Access key" : "คีย์การเข้าถึง",
"Secret key" : "คีย์ลับ",
"Builtin" : "ในตัว",
@@ -51,8 +62,10 @@ OC.L10N.register(
"Identity endpoint URL" : "ตัวตนของ URL ปลายทาง",
"Rackspace" : "Rackspace",
"API key" : "รหัส API",
+ "Log-in credentials, save in database" : "ข้อมูลประจำตัวสำหรับเข้าสู่ระบบ, บันทึกลงในฐานข้อมูล",
"Username and password" : "ชื่อผู้ใช้และรหัสผ่าน",
- "Session credentials" : "ข้อมูลของเซสชั่น",
+ "Log-in credentials, save in session" : "ข้อมูลประจำตัวสำหรับเข้าสู่ระบบ, บันทึกลงในช่วงเวลาเข้าใช้งาน",
+ "User entered, store in database" : "เมื่อผู้ใช้กรอก, เก็บข้อมูลไว้ในฐานข้อมูล",
"RSA public key" : "RSA คีย์สาธารณะ",
"Public key" : "คีย์สาธารณะ",
"Amazon S3" : "Amazon S3",
@@ -99,9 +112,9 @@ OC.L10N.register(
"Authentication" : "รับรองความถูกต้อง",
"Configuration" : "การกำหนดค่า",
"Available for" : "สามารถใช้ได้สำหรับ",
+ "Add storage" : "เพิ่มพื้นที่จัดเก็บข้อมูล",
"Advanced settings" : "ตั้งค่าขั้นสูง",
"Delete" : "ลบ",
- "Add storage" : "เพิ่มพื้นที่จัดเก็บข้อมูล",
"Allow users to mount external storage" : "อนุญาตให้ผู้ใช้ติดตั้งการจัดเก็บข้อมูลภายนอก",
"Allow users to mount the following external storage" : "อนุญาตให้ผู้ใช้ติดตั้งจัดเก็บข้อมูลภายนอกต่อไปนี้"
},
diff --git a/apps/files_external/l10n/th_TH.json b/apps/files_external/l10n/th_TH.json
index 2db63df9df2..f3ef84f8a0f 100644
--- a/apps/files_external/l10n/th_TH.json
+++ b/apps/files_external/l10n/th_TH.json
@@ -15,6 +15,8 @@
"Unsatisfied backend parameters" : "พารามิเตอร์แบ็กเอนด์ไม่ได้รับอนุญาต",
"Unsatisfied authentication mechanism parameters" : "การรับรองความถูกต้องไม่เพียงพอ",
"Insufficient data: %s" : "ข้อมูลไม่เพียงพอ: %s",
+ "%s" : "%s",
+ "Storage with id \"%i\" is not user editable" : "พื้นที่เก็บข้อมูล รหัส \"%i\" ไม่อนุญาตให้ผู้ใช้แก้ไขข้อมูลได้",
"Personal" : "ส่วนตัว",
"System" : "ระบบ",
"Grant access" : "อนุญาตให้เข้าถึงได้",
@@ -25,13 +27,22 @@
"Error generating key pair" : "ข้อผิดพลาดในการสร้างคีย์แบบเป็นคู่",
"Enable encryption" : "เปิดใช้งานการเข้ารหัส",
"Enable previews" : "เปิดใช้งานการแสดงตัวอย่าง",
+ "Enable sharing" : "เปิดให้สามารถแชร์ได้",
"Check for changes" : "ตรวจสอบการเปลี่ยนแปลง",
"Never" : "ไม่เคย",
"Once every direct access" : "เมื่อทุกคนเข้าถึงโดยตรง",
- "Every time the filesystem is used" : "ทุกครั้งที่แฟ้มระบบถูกใช้งาน",
"All users. Type to select user or group." : "ผู้ใช้ทุกคน พิมพ์เพื่อเลือกผู้ใช้หรือกลุ่ม",
"(group)" : "(กลุ่ม)",
+ "Admin defined" : "ถูกกำหนดโดยผู้ดูแลระบบ",
"Saved" : "บันทึกแล้ว",
+ "Empty response from the server" : "ไม่มีการตอบสนองจากเซิร์ฟเวอร์",
+ "Couldn't access. Please logout and login to activate this mount point" : "ไม่สามารถเข้าถึง กรุณออกจากระบบและาเข้าสู่ระบบใหม่เพื่อเปิดใช้งานจุดเชื่อมต่อนี้",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "ไม่สามารถรับข้อมูลจากเซิร์ฟเวอร์ ownCloud: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "ไม่สามารถรับรายชื่อของจุดเชื่อมต่อภายนอก: {type}",
+ "There was an error with message: " : "มีข้อความแสดงข้อผิดพลาด",
+ "External mount error" : "การติดจากตั้งภายนอกเกิดข้อผิดพลาด",
+ "Couldn't get the list of Windows network drive mount points: empty response from the server" : "ไม่สามารถรับรายชื่อไดรฟ์เครือข่ายของวินโดว์ส จุดที่ติดตั้ง: ไม่มีการตอบสนองจากเซิร์ฟเวอร์",
+ "Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "การกำหนดค่าบางส่วนของจุดเชื่อมต่อภายนอกไม่ถูกเชื่อมต่อ กรุณาคลิกที่ตรงสีแดงสำหรับข้อมูลเพิ่มเติม",
"Access key" : "คีย์การเข้าถึง",
"Secret key" : "คีย์ลับ",
"Builtin" : "ในตัว",
@@ -49,8 +60,10 @@
"Identity endpoint URL" : "ตัวตนของ URL ปลายทาง",
"Rackspace" : "Rackspace",
"API key" : "รหัส API",
+ "Log-in credentials, save in database" : "ข้อมูลประจำตัวสำหรับเข้าสู่ระบบ, บันทึกลงในฐานข้อมูล",
"Username and password" : "ชื่อผู้ใช้และรหัสผ่าน",
- "Session credentials" : "ข้อมูลของเซสชั่น",
+ "Log-in credentials, save in session" : "ข้อมูลประจำตัวสำหรับเข้าสู่ระบบ, บันทึกลงในช่วงเวลาเข้าใช้งาน",
+ "User entered, store in database" : "เมื่อผู้ใช้กรอก, เก็บข้อมูลไว้ในฐานข้อมูล",
"RSA public key" : "RSA คีย์สาธารณะ",
"Public key" : "คีย์สาธารณะ",
"Amazon S3" : "Amazon S3",
@@ -97,9 +110,9 @@
"Authentication" : "รับรองความถูกต้อง",
"Configuration" : "การกำหนดค่า",
"Available for" : "สามารถใช้ได้สำหรับ",
+ "Add storage" : "เพิ่มพื้นที่จัดเก็บข้อมูล",
"Advanced settings" : "ตั้งค่าขั้นสูง",
"Delete" : "ลบ",
- "Add storage" : "เพิ่มพื้นที่จัดเก็บข้อมูล",
"Allow users to mount external storage" : "อนุญาตให้ผู้ใช้ติดตั้งการจัดเก็บข้อมูลภายนอก",
"Allow users to mount the following external storage" : "อนุญาตให้ผู้ใช้ติดตั้งจัดเก็บข้อมูลภายนอกต่อไปนี้"
},"pluralForm" :"nplurals=1; plural=0;"
diff --git a/apps/files_external/l10n/tr.js b/apps/files_external/l10n/tr.js
index 619e5975ed8..cb506b24c1f 100644
--- a/apps/files_external/l10n/tr.js
+++ b/apps/files_external/l10n/tr.js
@@ -16,6 +16,7 @@ OC.L10N.register(
"Not permitted to use authentication mechanism \"%s\"" : "\"%s\" kimlik doğrulama mekanizmasına izin verilmiyor",
"Unsatisfied backend parameters" : "Yetersiz arka uç parametreleri",
"Unsatisfied authentication mechanism parameters" : "Yetersiz kimlik doğrulama mekanizması parametreleri",
+ "Insufficient data: %s" : "Yetersiz veri: %s",
"Personal" : "Kişisel",
"System" : "Sistem",
"Grant access" : "Erişimi sağla",
@@ -29,7 +30,6 @@ OC.L10N.register(
"Check for changes" : "Değişiklikleri denetle",
"Never" : "Daha yeni",
"Once every direct access" : "Her doğrudan erişimde bir kez",
- "Every time the filesystem is used" : "Dosya sistemi her kullanıldığında",
"All users. Type to select user or group." : "Tüm kullanıcılar. Kullanıcı veya grup seçmek için yazın.",
"(group)" : "(grup)",
"Saved" : "Kaydedildi",
@@ -51,7 +51,6 @@ OC.L10N.register(
"Rackspace" : "Rackspace",
"API key" : "API anahtarı",
"Username and password" : "Kullanıcı adı ve parola",
- "Session credentials" : "Oturum bilgileri",
"RSA public key" : "RSA ortak anahtarı",
"Public key" : "Ortak anahtar",
"Amazon S3" : "Amazon S3",
@@ -98,9 +97,10 @@ OC.L10N.register(
"Authentication" : "Kimlik Doğrulama",
"Configuration" : "Yapılandırma",
"Available for" : "Kullanabilenler",
+ "Add storage" : "Depo ekle",
"Advanced settings" : "Gelişmiş ayarlar",
"Delete" : "Sil",
- "Add storage" : "Depo ekle",
+ "Allow users to mount external storage" : "Kullanıcılara harici depolama bağlamalarına izin ver",
"Allow users to mount the following external storage" : "Kullanıcıların aşağıdaki harici depolamayı bağlamalarına izin ver"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files_external/l10n/tr.json b/apps/files_external/l10n/tr.json
index cb315a333c2..1eeaafa433c 100644
--- a/apps/files_external/l10n/tr.json
+++ b/apps/files_external/l10n/tr.json
@@ -14,6 +14,7 @@
"Not permitted to use authentication mechanism \"%s\"" : "\"%s\" kimlik doğrulama mekanizmasına izin verilmiyor",
"Unsatisfied backend parameters" : "Yetersiz arka uç parametreleri",
"Unsatisfied authentication mechanism parameters" : "Yetersiz kimlik doğrulama mekanizması parametreleri",
+ "Insufficient data: %s" : "Yetersiz veri: %s",
"Personal" : "Kişisel",
"System" : "Sistem",
"Grant access" : "Erişimi sağla",
@@ -27,7 +28,6 @@
"Check for changes" : "Değişiklikleri denetle",
"Never" : "Daha yeni",
"Once every direct access" : "Her doğrudan erişimde bir kez",
- "Every time the filesystem is used" : "Dosya sistemi her kullanıldığında",
"All users. Type to select user or group." : "Tüm kullanıcılar. Kullanıcı veya grup seçmek için yazın.",
"(group)" : "(grup)",
"Saved" : "Kaydedildi",
@@ -49,7 +49,6 @@
"Rackspace" : "Rackspace",
"API key" : "API anahtarı",
"Username and password" : "Kullanıcı adı ve parola",
- "Session credentials" : "Oturum bilgileri",
"RSA public key" : "RSA ortak anahtarı",
"Public key" : "Ortak anahtar",
"Amazon S3" : "Amazon S3",
@@ -96,9 +95,10 @@
"Authentication" : "Kimlik Doğrulama",
"Configuration" : "Yapılandırma",
"Available for" : "Kullanabilenler",
+ "Add storage" : "Depo ekle",
"Advanced settings" : "Gelişmiş ayarlar",
"Delete" : "Sil",
- "Add storage" : "Depo ekle",
+ "Allow users to mount external storage" : "Kullanıcılara harici depolama bağlamalarına izin ver",
"Allow users to mount the following external storage" : "Kullanıcıların aşağıdaki harici depolamayı bağlamalarına izin ver"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/uk.js b/apps/files_external/l10n/uk.js
index f8ca8dc360c..702b3e328ce 100644
--- a/apps/files_external/l10n/uk.js
+++ b/apps/files_external/l10n/uk.js
@@ -61,9 +61,9 @@ OC.L10N.register(
"Folder name" : "Ім'я теки",
"Configuration" : "Налаштування",
"Available for" : "Доступний для",
+ "Add storage" : "Додати сховище",
"Advanced settings" : "Розширені налаштування",
"Delete" : "Видалити",
- "Add storage" : "Додати сховище",
"Allow users to mount the following external storage" : "Дозволити користувачам монтувати наступні зовнішні сховища"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_external/l10n/uk.json b/apps/files_external/l10n/uk.json
index c34d0d2c82f..cddda62118f 100644
--- a/apps/files_external/l10n/uk.json
+++ b/apps/files_external/l10n/uk.json
@@ -59,9 +59,9 @@
"Folder name" : "Ім'я теки",
"Configuration" : "Налаштування",
"Available for" : "Доступний для",
+ "Add storage" : "Додати сховище",
"Advanced settings" : "Розширені налаштування",
"Delete" : "Видалити",
- "Add storage" : "Додати сховище",
"Allow users to mount the following external storage" : "Дозволити користувачам монтувати наступні зовнішні сховища"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/vi.js b/apps/files_external/l10n/vi.js
index f3fdb39136c..65b3d492429 100644
--- a/apps/files_external/l10n/vi.js
+++ b/apps/files_external/l10n/vi.js
@@ -21,7 +21,7 @@ OC.L10N.register(
"External Storage" : "Lưu trữ ngoài",
"Folder name" : "Tên thư mục",
"Configuration" : "Cấu hình",
- "Delete" : "Xóa",
- "Add storage" : "Thêm bộ nhớ"
+ "Add storage" : "Thêm bộ nhớ",
+ "Delete" : "Xóa"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_external/l10n/vi.json b/apps/files_external/l10n/vi.json
index fdba39fc95e..031dddee8e3 100644
--- a/apps/files_external/l10n/vi.json
+++ b/apps/files_external/l10n/vi.json
@@ -19,7 +19,7 @@
"External Storage" : "Lưu trữ ngoài",
"Folder name" : "Tên thư mục",
"Configuration" : "Cấu hình",
- "Delete" : "Xóa",
- "Add storage" : "Thêm bộ nhớ"
+ "Add storage" : "Thêm bộ nhớ",
+ "Delete" : "Xóa"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/zh_CN.js b/apps/files_external/l10n/zh_CN.js
index 4b99fc170a2..ca35a97bb53 100644
--- a/apps/files_external/l10n/zh_CN.js
+++ b/apps/files_external/l10n/zh_CN.js
@@ -40,8 +40,8 @@ OC.L10N.register(
"Folder name" : "目录名称",
"Configuration" : "配置",
"Available for" : "可用于",
- "Delete" : "删除",
"Add storage" : "增加存储",
+ "Delete" : "删除",
"Allow users to mount the following external storage" : "允许用户挂载以下外部存储"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_external/l10n/zh_CN.json b/apps/files_external/l10n/zh_CN.json
index fddc688c5c2..53c1df78899 100644
--- a/apps/files_external/l10n/zh_CN.json
+++ b/apps/files_external/l10n/zh_CN.json
@@ -38,8 +38,8 @@
"Folder name" : "目录名称",
"Configuration" : "配置",
"Available for" : "可用于",
- "Delete" : "删除",
"Add storage" : "增加存储",
+ "Delete" : "删除",
"Allow users to mount the following external storage" : "允许用户挂载以下外部存储"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/zh_TW.js b/apps/files_external/l10n/zh_TW.js
index 61f224e4ffe..ff0857709e8 100644
--- a/apps/files_external/l10n/zh_TW.js
+++ b/apps/files_external/l10n/zh_TW.js
@@ -17,6 +17,7 @@ OC.L10N.register(
"Unsatisfied backend parameters" : "無法滿足後端所需的參數條件",
"Unsatisfied authentication mechanism parameters" : "無法滿足驗證機制所需的參數條件",
"Insufficient data: %s" : "資料不足: %s",
+ "%s" : "%s",
"Personal" : "個人",
"System" : "系統",
"Grant access" : "允許存取",
@@ -29,10 +30,13 @@ OC.L10N.register(
"Enable previews" : "啟動預覽",
"Check for changes" : "檢查變動",
"Never" : "絕不",
- "Every time the filesystem is used" : "每當檔案系統使用時",
"All users. Type to select user or group." : "所有人都可以使用,或者選擇特定使用者、群組",
"(group)" : "(群組)",
"Saved" : "已儲存",
+ "Couldn't access. Please logout and login to activate this mount point" : "無法存取。請重新登出再登入啟動此掛載點。",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "無法從ownCloud伺服器得到資訊: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "無法得到外部掛載點的列表: {type}",
+ "External mount error" : "外部掛載錯誤",
"Access key" : "存取金鑰",
"Secret key" : "私密金鑰",
"None" : "無",
@@ -93,9 +97,9 @@ OC.L10N.register(
"Authentication" : "驗證",
"Configuration" : "設定",
"Available for" : "可用的",
+ "Add storage" : "增加儲存區",
"Advanced settings" : "進階設定",
"Delete" : "刪除",
- "Add storage" : "增加儲存區",
"Allow users to mount external storage" : "允許使用者能自行掛載外部儲存",
"Allow users to mount the following external storage" : "允許使用者自行掛載以下的外部儲存"
},
diff --git a/apps/files_external/l10n/zh_TW.json b/apps/files_external/l10n/zh_TW.json
index b9aa234e89e..4fd9424bc6f 100644
--- a/apps/files_external/l10n/zh_TW.json
+++ b/apps/files_external/l10n/zh_TW.json
@@ -15,6 +15,7 @@
"Unsatisfied backend parameters" : "無法滿足後端所需的參數條件",
"Unsatisfied authentication mechanism parameters" : "無法滿足驗證機制所需的參數條件",
"Insufficient data: %s" : "資料不足: %s",
+ "%s" : "%s",
"Personal" : "個人",
"System" : "系統",
"Grant access" : "允許存取",
@@ -27,10 +28,13 @@
"Enable previews" : "啟動預覽",
"Check for changes" : "檢查變動",
"Never" : "絕不",
- "Every time the filesystem is used" : "每當檔案系統使用時",
"All users. Type to select user or group." : "所有人都可以使用,或者選擇特定使用者、群組",
"(group)" : "(群組)",
"Saved" : "已儲存",
+ "Couldn't access. Please logout and login to activate this mount point" : "無法存取。請重新登出再登入啟動此掛載點。",
+ "Couldn't get the information from the ownCloud server: {code} {type}" : "無法從ownCloud伺服器得到資訊: {code} {type}",
+ "Couldn't get the list of external mount points: {type}" : "無法得到外部掛載點的列表: {type}",
+ "External mount error" : "外部掛載錯誤",
"Access key" : "存取金鑰",
"Secret key" : "私密金鑰",
"None" : "無",
@@ -91,9 +95,9 @@
"Authentication" : "驗證",
"Configuration" : "設定",
"Available for" : "可用的",
+ "Add storage" : "增加儲存區",
"Advanced settings" : "進階設定",
"Delete" : "刪除",
- "Add storage" : "增加儲存區",
"Allow users to mount external storage" : "允許使用者能自行掛載外部儲存",
"Allow users to mount the following external storage" : "允許使用者自行掛載以下的外部儲存"
},"pluralForm" :"nplurals=1; plural=0;"
diff --git a/apps/files_external/lib/amazons3.php b/apps/files_external/lib/amazons3.php
index 4b867c005a7..cb2082ee38b 100644
--- a/apps/files_external/lib/amazons3.php
+++ b/apps/files_external/lib/amazons3.php
@@ -12,11 +12,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Philipp Kapfer <philipp.kapfer@gmx.at>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/api.php b/apps/files_external/lib/api.php
index af9b802e522..50a2f38c65b 100644
--- a/apps/files_external/lib/api.php
+++ b/apps/files_external/lib/api.php
@@ -1,11 +1,12 @@
<?php
/**
+ * @author Jesús Macias <jmacias@solidgear.es>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,7 +29,7 @@ class Api {
/**
* Formats the given mount config to a mount entry.
- *
+ *
* @param string $mountPoint mount point name, relative to the data dir
* @param array $mountConfig mount config to format
*
@@ -59,7 +60,9 @@ class Api {
'type' => 'dir',
'backend' => $mountConfig['backend'],
'scope' => ( $isSystemMount ? 'system' : 'personal' ),
- 'permissions' => $permissions
+ 'permissions' => $permissions,
+ 'id' => $mountConfig['id'],
+ 'class' => $mountConfig['class']
);
return $entry;
}
diff --git a/apps/files_external/lib/auth/amazons3/accesskey.php b/apps/files_external/lib/auth/amazons3/accesskey.php
index d265db6279f..296ed59a77a 100644
--- a/apps/files_external/lib/auth/amazons3/accesskey.php
+++ b/apps/files_external/lib/auth/amazons3/accesskey.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/auth/authmechanism.php b/apps/files_external/lib/auth/authmechanism.php
index e695cbbebd5..36e55de92c5 100644
--- a/apps/files_external/lib/auth/authmechanism.php
+++ b/apps/files_external/lib/auth/authmechanism.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -95,6 +95,7 @@ class AuthMechanism implements \JsonSerializable {
$data += $this->jsonSerializeIdentifier();
$data['scheme'] = $this->getScheme();
+ $data['visibility'] = $this->getVisibility();
return $data;
}
diff --git a/apps/files_external/lib/auth/builtin.php b/apps/files_external/lib/auth/builtin.php
index 8fb4c901cbc..8b43cb459cc 100644
--- a/apps/files_external/lib/auth/builtin.php
+++ b/apps/files_external/lib/auth/builtin.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/auth/iuserprovided.php b/apps/files_external/lib/auth/iuserprovided.php
new file mode 100644
index 00000000000..6b7eab4e2a7
--- /dev/null
+++ b/apps/files_external/lib/auth/iuserprovided.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth;
+
+use OCP\IUser;
+
+/**
+ * For auth mechanisms where the user needs to provide credentials
+ */
+interface IUserProvided {
+ /**
+ * @param IUser $user the user for which to save the user provided options
+ * @param int $mountId the mount id to save the options for
+ * @param array $options the user provided options
+ */
+ public function saveBackendOptions(IUser $user, $mountId, array $options);
+}
diff --git a/apps/files_external/lib/auth/nullmechanism.php b/apps/files_external/lib/auth/nullmechanism.php
index 399c8301c5a..06083729e59 100644
--- a/apps/files_external/lib/auth/nullmechanism.php
+++ b/apps/files_external/lib/auth/nullmechanism.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/auth/oauth1/oauth1.php b/apps/files_external/lib/auth/oauth1/oauth1.php
index 7bdd01d4c16..dd83c9a6a69 100644
--- a/apps/files_external/lib/auth/oauth1/oauth1.php
+++ b/apps/files_external/lib/auth/oauth1/oauth1.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/auth/oauth2/oauth2.php b/apps/files_external/lib/auth/oauth2/oauth2.php
index 7123f8c16e3..c89007b52ba 100644
--- a/apps/files_external/lib/auth/oauth2/oauth2.php
+++ b/apps/files_external/lib/auth/oauth2/oauth2.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/auth/openstack/openstack.php b/apps/files_external/lib/auth/openstack/openstack.php
index 757fdab9ea6..80bbb1299f7 100644
--- a/apps/files_external/lib/auth/openstack/openstack.php
+++ b/apps/files_external/lib/auth/openstack/openstack.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/auth/openstack/rackspace.php b/apps/files_external/lib/auth/openstack/rackspace.php
index 395b58e6fae..c968321ca6c 100644
--- a/apps/files_external/lib/auth/openstack/rackspace.php
+++ b/apps/files_external/lib/auth/openstack/rackspace.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/auth/password/globalauth.php b/apps/files_external/lib/auth/password/globalauth.php
new file mode 100644
index 00000000000..b1e52fb53ab
--- /dev/null
+++ b/apps/files_external/lib/auth/password/globalauth.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth\Password;
+
+use OCA\Files_External\Lib\Auth\IUserProvided;
+use OCA\Files_External\Lib\DefinitionParameter;
+use OCA\Files_External\Service\BackendService;
+use OCP\IL10N;
+use OCP\IUser;
+use OCA\Files_External\Lib\Auth\AuthMechanism;
+use OCA\Files_External\Lib\StorageConfig;
+use OCP\Security\ICredentialsManager;
+use OCP\Files\Storage;
+use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
+
+/**
+ * Global Username and Password
+ */
+class GlobalAuth extends AuthMechanism {
+
+ const CREDENTIALS_IDENTIFIER = 'password::global';
+
+ /** @var ICredentialsManager */
+ protected $credentialsManager;
+
+ public function __construct(IL10N $l, ICredentialsManager $credentialsManager) {
+ $this->credentialsManager = $credentialsManager;
+
+ $this
+ ->setIdentifier('password::global')
+ ->setVisibility(BackendService::VISIBILITY_DEFAULT)
+ ->setScheme(self::SCHEME_PASSWORD)
+ ->setText($l->t('Global Credentails'));
+ }
+
+ public function getAuth($uid) {
+ $auth = $this->credentialsManager->retrieve($uid, self::CREDENTIALS_IDENTIFIER);
+ if (!is_array($auth)) {
+ return [
+ 'user' => '',
+ 'password' => ''
+ ];
+ } else {
+ return $auth;
+ }
+ }
+
+ public function saveAuth($uid, $user, $password) {
+ $this->credentialsManager->store($uid, self::CREDENTIALS_IDENTIFIER, [
+ 'user' => $user,
+ 'password' => $password
+ ]);
+ }
+
+ public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
+ if ($storage->getType() === StorageConfig::MOUNT_TYPE_ADMIN) {
+ $uid = '';
+ } else {
+ $uid = $user->getUID();
+ }
+ $credentials = $this->credentialsManager->retrieve($uid, self::CREDENTIALS_IDENTIFIER);
+
+ if (is_array($credentials)) {
+ $storage->setBackendOption('user', $credentials['user']);
+ $storage->setBackendOption('password', $credentials['password']);
+ }
+ }
+
+}
diff --git a/apps/files_external/lib/auth/password/logincredentials.php b/apps/files_external/lib/auth/password/logincredentials.php
new file mode 100644
index 00000000000..25bd66fb41a
--- /dev/null
+++ b/apps/files_external/lib/auth/password/logincredentials.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth\Password;
+
+use \OCP\IL10N;
+use \OCP\IUser;
+use \OCA\Files_External\Lib\DefinitionParameter;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
+use \OCA\Files_External\Lib\StorageConfig;
+use \OCP\ISession;
+use \OCP\Security\ICredentialsManager;
+use \OCP\Files\Storage;
+use \OCA\Files_External\Lib\SessionStorageWrapper;
+use \OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
+
+/**
+ * Username and password from login credentials, saved in DB
+ */
+class LoginCredentials extends AuthMechanism {
+
+ const CREDENTIALS_IDENTIFIER = 'password::logincredentials/credentials';
+
+ /** @var ISession */
+ protected $session;
+
+ /** @var ICredentialsManager */
+ protected $credentialsManager;
+
+ public function __construct(IL10N $l, ISession $session, ICredentialsManager $credentialsManager) {
+ $this->session = $session;
+ $this->credentialsManager = $credentialsManager;
+
+ $this
+ ->setIdentifier('password::logincredentials')
+ ->setScheme(self::SCHEME_PASSWORD)
+ ->setText($l->t('Log-in credentials, save in database'))
+ ->addParameters([
+ ])
+ ;
+
+ \OCP\Util::connectHook('OC_User', 'post_login', $this, 'authenticate');
+ }
+
+ /**
+ * Hook listener on post login
+ *
+ * @param array $params
+ */
+ public function authenticate(array $params) {
+ $userId = $params['uid'];
+ $credentials = [
+ 'user' => $this->session->get('loginname'),
+ 'password' => $params['password']
+ ];
+ $this->credentialsManager->store($userId, self::CREDENTIALS_IDENTIFIER, $credentials);
+ }
+
+ public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
+ if (!isset($user)) {
+ throw new InsufficientDataForMeaningfulAnswerException('No login credentials saved');
+ }
+ $uid = $user->getUID();
+ $credentials = $this->credentialsManager->retrieve($uid, self::CREDENTIALS_IDENTIFIER);
+
+ if (!isset($credentials)) {
+ throw new InsufficientDataForMeaningfulAnswerException('No login credentials saved');
+ }
+
+ $storage->setBackendOption('user', $credentials['user']);
+ $storage->setBackendOption('password', $credentials['password']);
+ }
+
+}
diff --git a/apps/files_external/lib/auth/password/password.php b/apps/files_external/lib/auth/password/password.php
index d3444cb1419..3b1942cc4a8 100644
--- a/apps/files_external/lib/auth/password/password.php
+++ b/apps/files_external/lib/auth/password/password.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/auth/password/sessioncredentials.php b/apps/files_external/lib/auth/password/sessioncredentials.php
index 8e36ff5f1d8..d8e8443418a 100644
--- a/apps/files_external/lib/auth/password/sessioncredentials.php
+++ b/apps/files_external/lib/auth/password/sessioncredentials.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,6 +21,7 @@
namespace OCA\Files_External\Lib\Auth\Password;
+use \OCP\IUser;
use \OCP\IL10N;
use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
@@ -49,7 +50,7 @@ class SessionCredentials extends AuthMechanism {
$this
->setIdentifier('password::sessioncredentials')
->setScheme(self::SCHEME_PASSWORD)
- ->setText($l->t('Session credentials'))
+ ->setText($l->t('Log-in credentials, save in session'))
->addParameters([
])
;
@@ -66,7 +67,7 @@ class SessionCredentials extends AuthMechanism {
$this->session->set('password::sessioncredentials/credentials', $this->crypto->encrypt(json_encode($params)));
}
- public function manipulateStorageConfig(StorageConfig &$storage) {
+ public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
$encrypted = $this->session->get('password::sessioncredentials/credentials');
if (!isset($encrypted)) {
throw new InsufficientDataForMeaningfulAnswerException('No session credentials saved');
diff --git a/apps/files_external/lib/auth/password/userprovided.php b/apps/files_external/lib/auth/password/userprovided.php
new file mode 100644
index 00000000000..2f277163184
--- /dev/null
+++ b/apps/files_external/lib/auth/password/userprovided.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth\Password;
+
+use OCA\Files_External\Lib\Auth\IUserProvided;
+use OCA\Files_External\Lib\DefinitionParameter;
+use OCA\Files_External\Service\BackendService;
+use OCP\IL10N;
+use OCP\IUser;
+use OCA\Files_External\Lib\Auth\AuthMechanism;
+use OCA\Files_External\Lib\StorageConfig;
+use OCP\Security\ICredentialsManager;
+use OCP\Files\Storage;
+use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
+
+/**
+ * User provided Username and Password
+ */
+class UserProvided extends AuthMechanism implements IUserProvided {
+
+ const CREDENTIALS_IDENTIFIER_PREFIX = 'password::userprovided/';
+
+ /** @var ICredentialsManager */
+ protected $credentialsManager;
+
+ public function __construct(IL10N $l, ICredentialsManager $credentialsManager) {
+ $this->credentialsManager = $credentialsManager;
+
+ $this
+ ->setIdentifier('password::userprovided')
+ ->setVisibility(BackendService::VISIBILITY_ADMIN)
+ ->setScheme(self::SCHEME_PASSWORD)
+ ->setText($l->t('User entered, store in database'))
+ ->addParameters([
+ (new DefinitionParameter('user', $l->t('Username')))
+ ->setFlag(DefinitionParameter::FLAG_USER_PROVIDED),
+ (new DefinitionParameter('password', $l->t('Password')))
+ ->setType(DefinitionParameter::VALUE_PASSWORD)
+ ->setFlag(DefinitionParameter::FLAG_USER_PROVIDED),
+ ]);
+ }
+
+ private function getCredentialsIdentifier($storageId) {
+ return self::CREDENTIALS_IDENTIFIER_PREFIX . $storageId;
+ }
+
+ public function saveBackendOptions(IUser $user, $id, array $options) {
+ $this->credentialsManager->store($user->getUID(), $this->getCredentialsIdentifier($id), [
+ 'user' => $options['user'], // explicitly copy the fields we want instead of just passing the entire $options array
+ 'password' => $options['password'] // this way we prevent users from being able to modify any other field
+ ]);
+ }
+
+ public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
+ if (!isset($user)) {
+ throw new InsufficientDataForMeaningfulAnswerException('No credentials saved');
+ }
+ $uid = $user->getUID();
+ $credentials = $this->credentialsManager->retrieve($uid, $this->getCredentialsIdentifier($storage->getId()));
+
+ if (!isset($credentials)) {
+ throw new InsufficientDataForMeaningfulAnswerException('No credentials saved');
+ }
+
+ $storage->setBackendOption('user', $credentials['user']);
+ $storage->setBackendOption('password', $credentials['password']);
+ }
+
+}
diff --git a/apps/files_external/lib/auth/publickey/rsa.php b/apps/files_external/lib/auth/publickey/rsa.php
index 4e19f90c83b..9045f6818f9 100644
--- a/apps/files_external/lib/auth/publickey/rsa.php
+++ b/apps/files_external/lib/auth/publickey/rsa.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +26,7 @@ use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
use \OCA\Files_External\Lib\StorageConfig;
use \OCP\IConfig;
+use OCP\IUser;
use \phpseclib\Crypt\RSA as RSACrypt;
/**
@@ -55,7 +56,7 @@ class RSA extends AuthMechanism {
;
}
- public function manipulateStorageConfig(StorageConfig &$storage) {
+ public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
$auth = new RSACrypt();
$auth->setPassword($this->config->getSystemValue('secret', ''));
if (!$auth->loadKey($storage->getBackendOption('private_key'))) {
diff --git a/apps/files_external/lib/backend/amazons3.php b/apps/files_external/lib/backend/amazons3.php
index 538b53637e3..b2dedc10e4a 100644
--- a/apps/files_external/lib/backend/amazons3.php
+++ b/apps/files_external/lib/backend/amazons3.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/backend.php b/apps/files_external/lib/backend/backend.php
index 9868519ed4f..8fb84b0e835 100644
--- a/apps/files_external/lib/backend/backend.php
+++ b/apps/files_external/lib/backend/backend.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/dav.php b/apps/files_external/lib/backend/dav.php
index abc5103c70f..c6e9630be9e 100644
--- a/apps/files_external/lib/backend/dav.php
+++ b/apps/files_external/lib/backend/dav.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/dropbox.php b/apps/files_external/lib/backend/dropbox.php
index 01b7a62edbe..7a414731192 100644
--- a/apps/files_external/lib/backend/dropbox.php
+++ b/apps/files_external/lib/backend/dropbox.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/ftp.php b/apps/files_external/lib/backend/ftp.php
index 8f3dfffc77b..b2b83a27405 100644
--- a/apps/files_external/lib/backend/ftp.php
+++ b/apps/files_external/lib/backend/ftp.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/google.php b/apps/files_external/lib/backend/google.php
index 14b2815b6e5..93a8cd2177d 100644
--- a/apps/files_external/lib/backend/google.php
+++ b/apps/files_external/lib/backend/google.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/legacybackend.php b/apps/files_external/lib/backend/legacybackend.php
index 5ebf143f749..084758ff78a 100644
--- a/apps/files_external/lib/backend/legacybackend.php
+++ b/apps/files_external/lib/backend/legacybackend.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/local.php b/apps/files_external/lib/backend/local.php
index 7827055eeac..1db707e7247 100644
--- a/apps/files_external/lib/backend/local.php
+++ b/apps/files_external/lib/backend/local.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/owncloud.php b/apps/files_external/lib/backend/owncloud.php
index d10f0b3bd0b..e7da328c5f1 100644
--- a/apps/files_external/lib/backend/owncloud.php
+++ b/apps/files_external/lib/backend/owncloud.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/sftp.php b/apps/files_external/lib/backend/sftp.php
index d3fcd41d520..3e5ecb90131 100644
--- a/apps/files_external/lib/backend/sftp.php
+++ b/apps/files_external/lib/backend/sftp.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/sftp_key.php b/apps/files_external/lib/backend/sftp_key.php
index 8db5761c1b2..58dddedf784 100644
--- a/apps/files_external/lib/backend/sftp_key.php
+++ b/apps/files_external/lib/backend/sftp_key.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/backend/smb.php b/apps/files_external/lib/backend/smb.php
index aa91cf51e85..9b71636936a 100644
--- a/apps/files_external/lib/backend/smb.php
+++ b/apps/files_external/lib/backend/smb.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,6 +30,7 @@ use \OCA\Files_External\Lib\StorageConfig;
use \OCA\Files_External\Lib\LegacyDependencyCheckPolyfill;
use \OCA\Files_External\Lib\Auth\Password\Password;
+use OCP\IUser;
class SMB extends Backend {
@@ -56,8 +57,9 @@ class SMB extends Backend {
/**
* @param StorageConfig $storage
+ * @param IUser $user
*/
- public function manipulateStorageConfig(StorageConfig &$storage) {
+ public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
$user = $storage->getBackendOption('user');
if ($domain = $storage->getBackendOption('domain')) {
$storage->setBackendOption('user', $domain.'\\'.$user);
diff --git a/apps/files_external/lib/backend/smb_oc.php b/apps/files_external/lib/backend/smb_oc.php
index b84b0b9dcb1..ba38754ce5a 100644
--- a/apps/files_external/lib/backend/smb_oc.php
+++ b/apps/files_external/lib/backend/smb_oc.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,6 +30,7 @@ use \OCA\Files_External\Lib\Auth\Password\SessionCredentials;
use \OCA\Files_External\Lib\StorageConfig;
use \OCA\Files_External\Lib\LegacyDependencyCheckPolyfill;
use \OCA\Files_External\Lib\Backend\SMB;
+use OCP\IUser;
/**
* Deprecated SMB_OC class - use SMB with the password::sessioncredentials auth mechanism
@@ -59,7 +60,7 @@ class SMB_OC extends Backend {
;
}
- public function manipulateStorageConfig(StorageConfig &$storage) {
+ public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
$username_as_share = ($storage->getBackendOption('username_as_share') === true);
if ($username_as_share) {
diff --git a/apps/files_external/lib/backend/swift.php b/apps/files_external/lib/backend/swift.php
index 8c64c791ad8..d6e4ac12f9a 100644
--- a/apps/files_external/lib/backend/swift.php
+++ b/apps/files_external/lib/backend/swift.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 6c900f0f224..578a8d82b2f 100644
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -4,17 +4,19 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
* @author Frank Karlitschek <frank@owncloud.org>
+ * @author Jesús Macias <jmacias@solidgear.es>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Philipp Kapfer <philipp.kapfer@gmx.at>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -33,10 +35,10 @@
use phpseclib\Crypt\AES;
use \OCA\Files_External\Appinfo\Application;
-use \OCA\Files_External\Lib\BackendConfig;
-use \OCA\Files_External\Service\BackendService;
use \OCA\Files_External\Lib\Backend\LegacyBackend;
use \OCA\Files_External\Lib\StorageConfig;
+use \OCA\Files_External\Lib\Backend\Backend;
+use \OCP\Files\StorageNotAvailableException;
/**
* Class to configure mount.json globally and for users
@@ -49,11 +51,6 @@ class OC_Mount_Config {
const MOUNT_TYPE_USER = 'user';
const MOUNT_TYPE_PERSONAL = 'personal';
- // getBackendStatus return types
- const STATUS_SUCCESS = 0;
- const STATUS_ERROR = 1;
- const STATUS_INDETERMINATE = 2;
-
// whether to skip backend test (for unit tests, as this static class is not mockable)
public static $skipTest = false;
@@ -75,36 +72,6 @@ class OC_Mount_Config {
return true;
}
- /*
- * Hook that mounts the given user's visible mount points
- *
- * @param array $data
- */
- public static function initMountPointsHook($data) {
- if ($data['user']) {
- $user = \OC::$server->getUserManager()->get($data['user']);
- if (!$user) {
- \OC::$server->getLogger()->warning(
- 'Cannot init external mount points for non-existant user "' . $data['user'] . '".',
- ['app' => 'files_external']
- );
- return;
- }
- $userView = new \OC\Files\View('/' . $user->getUID() . '/files');
- $changePropagator = new \OC\Files\Cache\ChangePropagator($userView);
- $etagPropagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, \OC::$server->getConfig());
- $etagPropagator->propagateDirtyMountPoints();
- \OCP\Util::connectHook(
- \OC\Files\Filesystem::CLASSNAME,
- \OC\Files\Filesystem::signal_create_mount,
- $etagPropagator, 'updateHook');
- \OCP\Util::connectHook(
- \OC\Files\Filesystem::CLASSNAME,
- \OC\Files\Filesystem::signal_delete_mount,
- $etagPropagator, 'updateHook');
- }
- }
-
/**
* Returns the mount points for the given user.
* The mount point is relative to the data directory.
@@ -125,6 +92,7 @@ class OC_Mount_Config {
$userStoragesService->setUser($user);
foreach ($userGlobalStoragesService->getStorages() as $storage) {
+ /** @var \OCA\Files_external\Lib\StorageConfig $storage */
$mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
$mountEntry = self::prepareMountPointEntry($storage, false);
foreach ($mountEntry['options'] as &$option) {
@@ -244,24 +212,27 @@ class OC_Mount_Config {
*
* @param string $class backend class name
* @param array $options backend configuration options
+ * @param boolean $isPersonal
* @return int see self::STATUS_*
+ * @throws Exception
*/
public static function getBackendStatus($class, $options, $isPersonal) {
if (self::$skipTest) {
- return self::STATUS_SUCCESS;
+ return StorageNotAvailableException::STATUS_SUCCESS;
}
foreach ($options as &$option) {
$option = self::setUserVars(OCP\User::getUser(), $option);
}
if (class_exists($class)) {
try {
+ /** @var \OC\Files\Storage\Common $storage */
$storage = new $class($options);
try {
$result = $storage->test($isPersonal);
$storage->setAvailability($result);
if ($result) {
- return self::STATUS_SUCCESS;
+ return StorageNotAvailableException::STATUS_SUCCESS;
}
} catch (\Exception $e) {
$storage->setAvailability(false);
@@ -272,7 +243,7 @@ class OC_Mount_Config {
throw $exception;
}
}
- return self::STATUS_ERROR;
+ return StorageNotAvailableException::STATUS_ERROR;
}
/**
@@ -299,30 +270,10 @@ class OC_Mount_Config {
}
/**
- * Write the mount points to the config file
- *
- * @param string|null $user If not null, personal for $user, otherwise system
- * @param array $data Mount points
- */
- public static function writeData($user, $data) {
- if (isset($user)) {
- $file = \OC::$server->getUserManager()->get($user)->getHome() . '/mount.json';
- } else {
- $config = \OC::$server->getConfig();
- $datadir = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/');
- $file = $config->getSystemValue('mount_file', $datadir . '/mount.json');
- }
-
- $content = json_encode($data, JSON_PRETTY_PRINT);
- @file_put_contents($file, $content);
- @chmod($file, 0640);
- }
-
- /**
* Get backend dependency message
* TODO: move into AppFramework along with templates
*
- * @param BackendConfig[] $backends
+ * @param Backend[] $backends
* @return string
*/
public static function dependencyMessage($backends) {
@@ -361,11 +312,11 @@ class OC_Mount_Config {
private static function getSingleDependencyMessage(\OCP\IL10N $l, $module, $backend) {
switch (strtolower($module)) {
case 'curl':
- return $l->t('<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', $backend);
+ return (string)$l->t('<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', $backend);
case 'ftp':
- return $l->t('<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', $backend);
+ return (string)$l->t('<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', $backend);
default:
- return $l->t('<b>Note:</b> "%s" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it.', array($module, $backend));
+ return (string)$l->t('<b>Note:</b> "%s" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it.', array($module, $backend));
}
}
@@ -429,39 +380,9 @@ class OC_Mount_Config {
}
/**
- * Merges mount points
- *
- * @param array $data Existing mount points
- * @param array $mountPoint New mount point
- * @param string $mountType
- * @return array
- */
- private static function mergeMountPoints($data, $mountPoint, $mountType) {
- $applicable = key($mountPoint);
- $mountPath = key($mountPoint[$applicable]);
- if (isset($data[$mountType])) {
- if (isset($data[$mountType][$applicable])) {
- // Merge priorities
- if (isset($data[$mountType][$applicable][$mountPath])
- && isset($data[$mountType][$applicable][$mountPath]['priority'])
- && !isset($mountPoint[$applicable][$mountPath]['priority'])
- ) {
- $mountPoint[$applicable][$mountPath]['priority']
- = $data[$mountType][$applicable][$mountPath]['priority'];
- }
- $data[$mountType][$applicable]
- = array_merge($data[$mountType][$applicable], $mountPoint[$applicable]);
- } else {
- $data[$mountType] = array_merge($data[$mountType], $mountPoint);
- }
- } else {
- $data[$mountType] = $mountPoint;
- }
- return $data;
- }
-
- /**
* Returns the encryption cipher
+ *
+ * @return AES
*/
private static function getCipher() {
$cipher = new AES(AES::MODE_CBC);
@@ -473,6 +394,9 @@ class OC_Mount_Config {
* Computes a hash based on the given configuration.
* This is mostly used to find out whether configurations
* are the same.
+ *
+ * @param array $config
+ * @return string
*/
public static function makeConfigHash($config) {
$data = json_encode(
diff --git a/apps/files_external/lib/config/configadapter.php b/apps/files_external/lib/config/configadapter.php
index 3a04512e8a8..51c2debd726 100644
--- a/apps/files_external/lib/config/configadapter.php
+++ b/apps/files_external/lib/config/configadapter.php
@@ -2,9 +2,9 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +23,7 @@
namespace OCA\Files_External\Config;
+use OCA\Files_external\Migration\StorageMigrator;
use OCP\Files\Storage;
use OC\Files\Mount\MountPoint;
use OCP\Files\Storage\IStorageFactory;
@@ -32,7 +33,6 @@ use OCP\IUser;
use OCA\Files_external\Service\UserStoragesService;
use OCA\Files_External\Service\UserGlobalStoragesService;
use OCA\Files_External\Lib\StorageConfig;
-use OCP\Files\StorageNotAvailableException;
use OCA\Files_External\Lib\FailedStorage;
/**
@@ -45,17 +45,22 @@ class ConfigAdapter implements IMountProvider {
/** @var UserGlobalStoragesService */
private $userGlobalStoragesService;
+ /** @var StorageMigrator */
+ private $migrator;
/**
* @param UserStoragesService $userStoragesService
* @param UserGlobalStoragesService $userGlobalStoragesService
+ * @param StorageMigrator $migrator
*/
public function __construct(
UserStoragesService $userStoragesService,
- UserGlobalStoragesService $userGlobalStoragesService
+ UserGlobalStoragesService $userGlobalStoragesService,
+ StorageMigrator $migrator
) {
$this->userStoragesService = $userStoragesService;
$this->userGlobalStoragesService = $userGlobalStoragesService;
+ $this->migrator = $migrator;
}
/**
@@ -80,8 +85,8 @@ class ConfigAdapter implements IMountProvider {
$storage->setBackendOption('objectstore', new $objectClass($objectStore));
}
- $storage->getAuthMechanism()->manipulateStorageConfig($storage);
- $storage->getBackend()->manipulateStorageConfig($storage);
+ $storage->getAuthMechanism()->manipulateStorageConfig($storage, $user);
+ $storage->getBackend()->manipulateStorageConfig($storage, $user);
}
/**
@@ -109,6 +114,8 @@ class ConfigAdapter implements IMountProvider {
* @return \OCP\Files\Mount\IMountPoint[]
*/
public function getMountsForUser(IUser $user, IStorageFactory $loader) {
+ $this->migrator->migrateUser($user);
+
$mounts = [];
$this->userStoragesService->setUser($user);
@@ -123,9 +130,19 @@ class ConfigAdapter implements IMountProvider {
$impl = new FailedStorage(['exception' => $e]);
}
+ try {
+ $availability = $impl->getAvailability();
+ if (!$availability['available']) {
+ $impl = new FailedStorage(['exception' => null]);
+ }
+ } catch (\Exception $e) {
+ // propagate exception into filesystem
+ $impl = new FailedStorage(['exception' => $e]);
+ }
+
$mount = new MountPoint(
$impl,
- '/'.$user->getUID().'/files' . $storage->getMountPoint(),
+ '/' . $user->getUID() . '/files' . $storage->getMountPoint(),
null,
$loader,
$storage->getMountOptions()
@@ -146,7 +163,7 @@ class ConfigAdapter implements IMountProvider {
$this->userStoragesService,
$storage->getId(),
$impl,
- '/'.$user->getUID().'/files' . $storage->getMountPoint(),
+ '/' . $user->getUID() . '/files' . $storage->getMountPoint(),
null,
$loader,
$storage->getMountOptions()
diff --git a/apps/files_external/lib/definitionparameter.php b/apps/files_external/lib/definitionparameter.php
index 7f883e5fad1..27c6af0fcda 100644
--- a/apps/files_external/lib/definitionparameter.php
+++ b/apps/files_external/lib/definitionparameter.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,6 +35,7 @@ class DefinitionParameter implements \JsonSerializable {
/** Flag constants */
const FLAG_NONE = 0;
const FLAG_OPTIONAL = 1;
+ const FLAG_USER_PROVIDED = 2;
/** @var string name of parameter */
private $name;
@@ -121,7 +122,7 @@ class DefinitionParameter implements \JsonSerializable {
* @return bool
*/
public function isFlagSet($flag) {
- return (bool) $this->flags & $flag;
+ return (bool)($this->flags & $flag);
}
/**
@@ -130,26 +131,15 @@ class DefinitionParameter implements \JsonSerializable {
* @return string
*/
public function jsonSerialize() {
- $prefix = '';
- switch ($this->getType()) {
- case self::VALUE_BOOLEAN:
- $prefix = '!';
- break;
- case self::VALUE_PASSWORD:
- $prefix = '*';
- break;
- case self::VALUE_HIDDEN:
- $prefix = '#';
- break;
- }
-
- switch ($this->getFlags()) {
- case self::FLAG_OPTIONAL:
- $prefix = '&' . $prefix;
- break;
- }
+ return [
+ 'value' => $this->getText(),
+ 'flags' => $this->getFlags(),
+ 'type' => $this->getType()
+ ];
+ }
- return $prefix . $this->getText();
+ public function isOptional() {
+ return $this->isFlagSet(self::FLAG_OPTIONAL) || $this->isFlagSet(self::FLAG_USER_PROVIDED);
}
/**
@@ -160,28 +150,26 @@ class DefinitionParameter implements \JsonSerializable {
* @return bool success
*/
public function validateValue(&$value) {
- $optional = $this->getFlags() & self::FLAG_OPTIONAL;
-
switch ($this->getType()) {
- case self::VALUE_BOOLEAN:
- if (!is_bool($value)) {
- switch ($value) {
- case 'true':
- $value = true;
- break;
- case 'false':
- $value = false;
- break;
- default:
+ case self::VALUE_BOOLEAN:
+ if (!is_bool($value)) {
+ switch ($value) {
+ case 'true':
+ $value = true;
+ break;
+ case 'false':
+ $value = false;
+ break;
+ default:
+ return false;
+ }
+ }
+ break;
+ default:
+ if (!$value && !$this->isOptional()) {
return false;
}
- }
- break;
- default:
- if (!$value && !$optional) {
- return false;
- }
- break;
+ break;
}
return true;
}
diff --git a/apps/files_external/lib/dependencytrait.php b/apps/files_external/lib/dependencytrait.php
index f112f6c2e66..eed3ba1b327 100644
--- a/apps/files_external/lib/dependencytrait.php
+++ b/apps/files_external/lib/dependencytrait.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/dropbox.php b/apps/files_external/lib/dropbox.php
index df8a0255134..3c4022f24ce 100644
--- a/apps/files_external/lib/dropbox.php
+++ b/apps/files_external/lib/dropbox.php
@@ -5,12 +5,12 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Philipp Kapfer <philipp.kapfer@gmx.at>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Sascha Schmidt <realriot@realriot.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/etagpropagator.php b/apps/files_external/lib/etagpropagator.php
deleted file mode 100644
index 772a11ea36f..00000000000
--- a/apps/files_external/lib/etagpropagator.php
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-/**
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_External;
-
-use OC\Files\Filesystem;
-
-/**
- * Updates the etag of parent folders whenever a new external storage mount
- * point has been created or deleted. Updates need to be triggered using
- * the updateHook() method.
- *
- * There are two modes of operation:
- * - for personal mount points, the etag is propagated directly
- * - for system mount points, a dirty flag is saved in the configuration and
- * the etag will be updated the next time propagateDirtyMountPoints() is called
- */
-class EtagPropagator {
- /**
- * @var \OCP\IUser
- */
- protected $user;
-
- /**
- * @var \OC\Files\Cache\ChangePropagator
- */
- protected $changePropagator;
-
- /**
- * @var \OCP\IConfig
- */
- protected $config;
-
- /**
- * @param \OCP\IUser $user current user, must match the propagator's
- * user
- * @param \OC\Files\Cache\ChangePropagator $changePropagator change propagator
- * initialized with a view for $user
- * @param \OCP\IConfig $config
- */
- public function __construct($user, $changePropagator, $config) {
- $this->user = $user;
- $this->changePropagator = $changePropagator;
- $this->config = $config;
- }
-
- /**
- * Propagate the etag changes for all mountpoints marked as dirty and mark the mountpoints as clean
- *
- * @param int $time
- */
- public function propagateDirtyMountPoints($time = null) {
- if ($time === null) {
- $time = time();
- }
- $mountPoints = $this->getDirtyMountPoints();
- foreach ($mountPoints as $mountPoint) {
- $this->changePropagator->addChange($mountPoint);
- $this->config->setUserValue($this->user->getUID(), 'files_external', $mountPoint, $time);
- }
- if (count($mountPoints)) {
- $this->changePropagator->propagateChanges($time);
- }
- }
-
- /**
- * Get all mountpoints we need to update the etag for
- *
- * @return string[]
- */
- protected function getDirtyMountPoints() {
- $dirty = array();
- $mountPoints = $this->config->getAppKeys('files_external');
- foreach ($mountPoints as $mountPoint) {
- if (substr($mountPoint, 0, 1) === '/') {
- $updateTime = $this->config->getAppValue('files_external', $mountPoint);
- $userTime = $this->config->getUserValue($this->user->getUID(), 'files_external', $mountPoint);
- if ($updateTime > $userTime) {
- $dirty[] = $mountPoint;
- }
- }
- }
- return $dirty;
- }
-
- /**
- * @param string $mountPoint
- * @param int $time
- */
- protected function markDirty($mountPoint, $time = null) {
- if ($time === null) {
- $time = time();
- }
- $this->config->setAppValue('files_external', $mountPoint, $time);
- }
-
- /**
- * Update etags for mount points for known user
- * For global or group mount points, updating the etag for every user is not feasible
- * instead we mark the mount point as dirty and update the etag when the filesystem is loaded for the user
- * For personal mount points, the change is propagated directly
- *
- * @param array $params hook parameters
- * @param int $time update time to use when marking a mount point as dirty
- */
- public function updateHook($params, $time = null) {
- if ($time === null) {
- $time = time();
- }
- $users = $params[Filesystem::signal_param_users];
- $type = $params[Filesystem::signal_param_mount_type];
- $mountPoint = $params[Filesystem::signal_param_path];
- $mountPoint = Filesystem::normalizePath($mountPoint);
- if ($type === \OC_Mount_Config::MOUNT_TYPE_GROUP or $users === 'all') {
- $this->markDirty($mountPoint, $time);
- } else {
- $this->changePropagator->addChange($mountPoint);
- $this->changePropagator->propagateChanges($time);
- }
- }
-}
diff --git a/apps/files_external/lib/failedcache.php b/apps/files_external/lib/failedcache.php
new file mode 100644
index 00000000000..0f59495e595
--- /dev/null
+++ b/apps/files_external/lib/failedcache.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+use OC\Files\Cache\CacheEntry;
+use OCP\Constants;
+use OCP\Files\Cache\ICache;
+
+/**
+ * Storage placeholder to represent a missing precondition, storage unavailable
+ */
+class FailedCache implements ICache {
+
+ public function getNumericStorageId() {
+ return -1;
+ }
+
+ public function get($file) {
+ if ($file === '') {
+ return new CacheEntry([
+ 'fileid' => -1,
+ 'size' => 0,
+ 'mimetype' => 'httpd/unix-directory',
+ 'mimepart' => 'httpd',
+ 'permissions' => Constants::PERMISSION_READ,
+ 'mtime' => time()
+ ]);
+ } else {
+ return false;
+ }
+ }
+
+ public function getFolderContents($folder) {
+ return [];
+ }
+
+ public function getFolderContentsById($fileId) {
+ return [];
+ }
+
+ public function put($file, array $data) {
+ return;
+ }
+
+ public function insert($file, array $data) {
+ return;
+ }
+
+ public function update($id, array $data) {
+ return;
+ }
+
+ public function getId($file) {
+ return -1;
+ }
+
+ public function getParentId($file) {
+ return -1;
+ }
+
+ public function inCache($file) {
+ return false;
+ }
+
+ public function remove($file) {
+ return;
+ }
+
+ public function move($source, $target) {
+ return;
+ }
+
+ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
+ return;
+ }
+
+ public function clear() {
+ return;
+ }
+
+ public function getStatus($file) {
+ return ICache::NOT_FOUND;
+ }
+
+ public function search($pattern) {
+ return [];
+ }
+
+ public function searchByMime($mimetype) {
+ return [];
+ }
+
+ public function searchByTag($tag, $userId) {
+ return [];
+ }
+
+ public function getAll() {
+ return [];
+ }
+
+ public function getIncomplete() {
+ return [];
+ }
+
+ public function getPathById($id) {
+ return null;
+ }
+
+ public function normalize($path) {
+ return $path;
+ }
+}
diff --git a/apps/files_external/lib/failedstorage.php b/apps/files_external/lib/failedstorage.php
index c3181fd6b02..7bcbfc31902 100644
--- a/apps/files_external/lib/failedstorage.php
+++ b/apps/files_external/lib/failedstorage.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -174,7 +174,7 @@ class FailedStorage extends Common {
}
public function verifyPath($path, $fileName) {
- throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ return true;
}
public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
@@ -205,4 +205,7 @@ class FailedStorage extends Common {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
+ public function getCache($path = '', $storage = null) {
+ return new FailedCache();
+ }
}
diff --git a/apps/files_external/lib/frontenddefinitiontrait.php b/apps/files_external/lib/frontenddefinitiontrait.php
index d3b78aa56d4..fc47a9515f3 100644
--- a/apps/files_external/lib/frontenddefinitiontrait.php
+++ b/apps/files_external/lib/frontenddefinitiontrait.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -136,10 +136,12 @@ trait FrontendDefinitionTrait {
public function validateStorageDefinition(StorageConfig $storage) {
foreach ($this->getParameters() as $name => $parameter) {
$value = $storage->getBackendOption($name);
- if (!$parameter->validateValue($value)) {
- return false;
+ if (!is_null($value) || !$parameter->isOptional()) {
+ if (!$parameter->validateValue($value)) {
+ return false;
+ }
+ $storage->setBackendOption($name, $value);
}
- $storage->setBackendOption($name, $value);
}
return true;
}
diff --git a/apps/files_external/lib/ftp.php b/apps/files_external/lib/ftp.php
index f3631e53fa1..125888ef722 100644
--- a/apps/files_external/lib/ftp.php
+++ b/apps/files_external/lib/ftp.php
@@ -7,11 +7,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Philipp Kapfer <philipp.kapfer@gmx.at>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/google.php b/apps/files_external/lib/google.php
index eba2ee7f9b5..8a9ffaf7d37 100644
--- a/apps/files_external/lib/google.php
+++ b/apps/files_external/lib/google.php
@@ -10,11 +10,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Philipp Kapfer <philipp.kapfer@gmx.at>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -426,13 +426,23 @@ class Google extends \OC\Files\Storage\Common {
}
if (isset($downloadUrl)) {
$request = new \Google_Http_Request($downloadUrl, 'GET', null, null);
- $httpRequest = $this->client->getAuth()->authenticatedRequest($request);
- if ($httpRequest->getResponseHttpCode() == 200) {
- $tmpFile = \OCP\Files::tmpFile($ext);
- $data = $httpRequest->getResponseBody();
- file_put_contents($tmpFile, $data);
- return fopen($tmpFile, $mode);
+ $httpRequest = $this->client->getAuth()->sign($request);
+ // the library's service doesn't support streaming, so we use Guzzle instead
+ $client = \OC::$server->getHTTPClientService()->newClient();
+ try {
+ $response = $client->get($downloadUrl, [
+ 'headers' => $httpRequest->getRequestHeaders(),
+ 'stream' => true
+ ]);
+ } catch (RequestException $e) {
+ if ($e->getResponse()->getStatusCode() === 404) {
+ return false;
+ } else {
+ throw $e;
+ }
}
+
+ return $response->getBody();
}
}
return false;
diff --git a/apps/files_external/lib/identifiertrait.php b/apps/files_external/lib/identifiertrait.php
index 913e1899db8..c49f4fcbc8d 100644
--- a/apps/files_external/lib/identifiertrait.php
+++ b/apps/files_external/lib/identifiertrait.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/insufficientdataformeaningfulanswerexception.php b/apps/files_external/lib/insufficientdataformeaningfulanswerexception.php
index f77667cb70a..22d83ef56f4 100644
--- a/apps/files_external/lib/insufficientdataformeaningfulanswerexception.php
+++ b/apps/files_external/lib/insufficientdataformeaningfulanswerexception.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,4 +27,15 @@ use \OCP\Files\StorageNotAvailableException;
* Authentication mechanism or backend has insufficient data
*/
class InsufficientDataForMeaningfulAnswerException extends StorageNotAvailableException {
+ /**
+ * StorageNotAvailableException constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param \Exception $previous
+ * @since 6.0.0
+ */
+ public function __construct($message = '', $code = self::STATUS_INDETERMINATE, \Exception $previous = null) {
+ parent::__construct($message, $code, $previous);
+ }
}
diff --git a/apps/files_external/lib/legacydependencycheckpolyfill.php b/apps/files_external/lib/legacydependencycheckpolyfill.php
index bd0095debcd..7d6c0c4b45b 100644
--- a/apps/files_external/lib/legacydependencycheckpolyfill.php
+++ b/apps/files_external/lib/legacydependencycheckpolyfill.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/missingdependency.php b/apps/files_external/lib/missingdependency.php
index 9b25aeacc9b..a4a20dd1128 100644
--- a/apps/files_external/lib/missingdependency.php
+++ b/apps/files_external/lib/missingdependency.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/notfoundexception.php b/apps/files_external/lib/notfoundexception.php
index 4a92ae2e889..dd3dd1907a5 100644
--- a/apps/files_external/lib/notfoundexception.php
+++ b/apps/files_external/lib/notfoundexception.php
@@ -2,7 +2,7 @@
/**
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/owncloud.php b/apps/files_external/lib/owncloud.php
index 6e798ab8e33..c4824e6bd14 100644
--- a/apps/files_external/lib/owncloud.php
+++ b/apps/files_external/lib/owncloud.php
@@ -1,10 +1,10 @@
<?php
/**
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/personalmount.php b/apps/files_external/lib/personalmount.php
index 26f68ba32db..4761866fa1a 100644
--- a/apps/files_external/lib/personalmount.php
+++ b/apps/files_external/lib/personalmount.php
@@ -2,9 +2,10 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,12 +36,12 @@ class PersonalMount extends MountPoint implements MoveableMount {
protected $storagesService;
/** @var int */
- protected $storageId;
+ protected $numericStorageId;
/**
* @param UserStoragesService $storagesService
* @param int $storageId
- * @param string|\OC\Files\Storage\Storage $storage
+ * @param \OCP\Files\Storage $storage
* @param string $mountpoint
* @param array $arguments (optional) configuration for the storage backend
* @param \OCP\Files\Storage\IStorageFactory $loader
@@ -57,7 +58,7 @@ class PersonalMount extends MountPoint implements MoveableMount {
) {
parent::__construct($storage, $mountpoint, $arguments, $loader, $mountOptions);
$this->storagesService = $storagesService;
- $this->storageId = $storageId;
+ $this->numericStorageId = $storageId;
}
/**
@@ -67,7 +68,7 @@ class PersonalMount extends MountPoint implements MoveableMount {
* @return bool
*/
public function moveMount($target) {
- $storage = $this->storagesService->getStorage($this->storageId);
+ $storage = $this->storagesService->getStorage($this->numericStorageId);
// remove "/$user/files" prefix
$targetParts = explode('/', trim($target, '/'), 3);
$storage->setMountPoint($targetParts[2]);
@@ -82,7 +83,7 @@ class PersonalMount extends MountPoint implements MoveableMount {
* @return bool
*/
public function removeMount() {
- $this->storagesService->removeStorage($this->storageId);
+ $this->storagesService->removeStorage($this->numericStorageId);
return true;
}
}
diff --git a/apps/files_external/lib/prioritytrait.php b/apps/files_external/lib/prioritytrait.php
index 22f9fe275d8..9745015bef4 100644
--- a/apps/files_external/lib/prioritytrait.php
+++ b/apps/files_external/lib/prioritytrait.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/sessionstoragewrapper.php b/apps/files_external/lib/sessionstoragewrapper.php
index e45589c4472..c592cb87a34 100644
--- a/apps/files_external/lib/sessionstoragewrapper.php
+++ b/apps/files_external/lib/sessionstoragewrapper.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/sftp.php b/apps/files_external/lib/sftp.php
index f8651727fd2..09d743ff93d 100644
--- a/apps/files_external/lib/sftp.php
+++ b/apps/files_external/lib/sftp.php
@@ -8,12 +8,13 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Ross Nicoll <jrn@jrn.me.uk>
* @author SA <stephen@mthosting.net>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -84,6 +85,9 @@ class SFTP extends \OC\Files\Storage\Common {
$this->host = $parsedHost[0];
$this->port = $parsedHost[1];
+ if (!isset($params['user'])) {
+ throw new \UnexpectedValueException('no authentication parameters specified');
+ }
$this->user = $params['user'];
if (isset($params['public_key_auth'])) {
@@ -195,7 +199,7 @@ class SFTP extends \OC\Files\Storage\Common {
}
/**
- * @return bool|string
+ * @return string|false
*/
private function hostKeysPath() {
try {
diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php
index f58cd9849f2..50bd56f28ad 100644
--- a/apps/files_external/lib/smb.php
+++ b/apps/files_external/lib/smb.php
@@ -6,11 +6,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Philipp Kapfer <philipp.kapfer@gmx.at>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,6 +35,7 @@ use Icewind\SMB\NativeServer;
use Icewind\SMB\Server;
use Icewind\Streams\CallbackWrapper;
use Icewind\Streams\IteratorDirectory;
+use OC\Cache\CappedMemoryCache;
use OC\Files\Filesystem;
class SMB extends Common {
@@ -49,9 +50,14 @@ class SMB extends Common {
protected $share;
/**
+ * @var string
+ */
+ protected $root;
+
+ /**
* @var \Icewind\SMB\FileInfo[]
*/
- protected $statCache = array();
+ protected $statCache;
public function __construct($params) {
if (isset($params['host']) && isset($params['user']) && isset($params['password']) && isset($params['share'])) {
@@ -72,6 +78,7 @@ class SMB extends Common {
} else {
throw new \Exception('Invalid configuration');
}
+ $this->statCache = new CappedMemoryCache();
}
/**
@@ -190,7 +197,10 @@ class SMB extends Common {
return $this->share->read($fullPath);
case 'w':
case 'wb':
- return $this->share->write($fullPath);
+ $source = $this->share->write($fullPath);
+ return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
+ unset($this->statCache[$fullPath]);
+ });
case 'a':
case 'ab':
case 'r+':
@@ -220,7 +230,8 @@ class SMB extends Common {
}
$source = fopen($tmpFile, $mode);
$share = $this->share;
- return CallBackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
+ return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
+ unset($this->statCache[$fullPath]);
$share->put($tmpFile, $fullPath);
unlink($tmpFile);
});
@@ -298,7 +309,22 @@ class SMB extends Common {
* check if smbclient is installed
*/
public static function checkDependencies() {
- $smbClientExists = (bool)\OC_Helper::findBinaryPath('smbclient');
- return $smbClientExists ? true : array('smbclient');
+ return (
+ (bool)\OC_Helper::findBinaryPath('smbclient')
+ || Server::NativeAvailable()
+ ) ? true : ['smbclient'];
+ }
+
+ /**
+ * Test a storage for availability
+ *
+ * @return bool
+ */
+ public function test() {
+ try {
+ return parent::test();
+ } catch (Exception $e) {
+ return false;
+ }
}
}
diff --git a/apps/files_external/lib/storageconfig.php b/apps/files_external/lib/storageconfig.php
index 86a7e6ffa12..6f44b25a2e6 100644
--- a/apps/files_external/lib/storageconfig.php
+++ b/apps/files_external/lib/storageconfig.php
@@ -1,9 +1,11 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,6 +24,7 @@
namespace OCA\Files_external\Lib;
+use OCA\Files_External\Lib\Auth\IUserProvided;
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
@@ -29,6 +32,8 @@ use \OCA\Files_External\Lib\Auth\AuthMechanism;
* External storage configuration
*/
class StorageConfig implements \JsonSerializable {
+ const MOUNT_TYPE_ADMIN = 1;
+ const MOUNT_TYPE_PERSONAl = 2;
/**
* Storage config id
@@ -108,6 +113,13 @@ class StorageConfig implements \JsonSerializable {
private $mountOptions = [];
/**
+ * Whether it's a personal or admin mount
+ *
+ * @var int
+ */
+ private $type;
+
+ /**
* Creates a storage config
*
* @param int|null $id config id or null for a new config
@@ -163,7 +175,7 @@ class StorageConfig implements \JsonSerializable {
}
/**
- * @param Backend
+ * @param Backend $backend
*/
public function setBackend(Backend $backend) {
$this->backend= $backend;
@@ -177,7 +189,7 @@ class StorageConfig implements \JsonSerializable {
}
/**
- * @param AuthMechanism
+ * @param AuthMechanism $authMechanism
*/
public function setAuthMechanism(AuthMechanism $authMechanism) {
$this->authMechanism = $authMechanism;
@@ -302,6 +314,25 @@ class StorageConfig implements \JsonSerializable {
}
/**
+ * @param string $key
+ * @return mixed
+ */
+ public function getMountOption($key) {
+ if (isset($this->mountOptions[$key])) {
+ return $this->mountOptions[$key];
+ }
+ return null;
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ public function setMountOption($key, $value) {
+ $this->mountOptions[$key] = $value;
+ }
+
+ /**
* Gets the storage status, whether the config worked last time
*
* @return int $status status
@@ -331,6 +362,20 @@ class StorageConfig implements \JsonSerializable {
}
/**
+ * @return int self::MOUNT_TYPE_ADMIN or self::MOUNT_TYPE_PERSONAl
+ */
+ public function getType() {
+ return $this->type;
+ }
+
+ /**
+ * @param int $type self::MOUNT_TYPE_ADMIN or self::MOUNT_TYPE_PERSONAl
+ */
+ public function setType($type) {
+ $this->type = $type;
+ }
+
+ /**
* Serialize config to JSON
*
* @return array
@@ -362,6 +407,8 @@ class StorageConfig implements \JsonSerializable {
if (!is_null($this->statusMessage)) {
$result['statusMessage'] = $this->statusMessage;
}
+ $result['userProvided'] = $this->authMechanism instanceof IUserProvided;
+ $result['type'] = ($this->getType() === self::MOUNT_TYPE_PERSONAl) ? 'personal': 'system';
return $result;
}
}
diff --git a/apps/files_external/lib/storagemodifiertrait.php b/apps/files_external/lib/storagemodifiertrait.php
index 6d31ce8999a..30c2108feec 100644
--- a/apps/files_external/lib/storagemodifiertrait.php
+++ b/apps/files_external/lib/storagemodifiertrait.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,6 +21,7 @@
namespace OCA\Files_External\Lib;
+use \OCP\IUser;
use \OCP\Files\Storage;
use \OCA\Files_External\Lib\StorageConfig;
use \OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
@@ -45,10 +46,11 @@ trait StorageModifierTrait {
* Modify a StorageConfig parameters
*
* @param StorageConfig $storage
+ * @param IUser $user User the storage is being used as
* @throws InsufficientDataForMeaningfulAnswerException
* @throws StorageNotAvailableException
*/
- public function manipulateStorageConfig(StorageConfig &$storage) {
+ public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
}
/**
diff --git a/apps/files_external/lib/streamwrapper.php b/apps/files_external/lib/streamwrapper.php
index 387667a81a9..1f1e52aff75 100644
--- a/apps/files_external/lib/streamwrapper.php
+++ b/apps/files_external/lib/streamwrapper.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php
index e946e7feb77..1f092240b4d 100644
--- a/apps/files_external/lib/swift.php
+++ b/apps/files_external/lib/swift.php
@@ -9,11 +9,12 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Philipp Kapfer <philipp.kapfer@gmx.at>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Tim Dettrick <t.dettrick@uq.edu.au>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,6 +33,7 @@
namespace OC\Files\Storage;
+use Guzzle\Http\Url;
use Guzzle\Http\Exception\ClientErrorResponseException;
use Icewind\Streams\IteratorDirectory;
use OpenCloud;
@@ -123,7 +125,14 @@ class Swift extends \OC\Files\Storage\Common {
}
$this->id = 'swift::' . $params['user'] . md5($params['bucket']);
- $this->bucket = $params['bucket'];
+
+ $bucketUrl = Url::factory($params['bucket']);
+ if ($bucketUrl->isAbsolute()) {
+ $this->bucket = end(($bucketUrl->getPathSegments()));
+ $params['endpoint_url'] = $bucketUrl->addPath('..')->normalizePath();
+ } else {
+ $this->bucket = $params['bucket'];
+ }
if (empty($params['url'])) {
$params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
@@ -314,27 +323,24 @@ class Swift extends \OC\Files\Storage\Common {
switch ($mode) {
case 'r':
case 'rb':
- $tmpFile = \OCP\Files::tmpFile();
- self::$tmpFiles[$tmpFile] = $path;
try {
- $object = $this->getContainer()->getObject($path);
- } catch (ClientErrorResponseException $e) {
- \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
- return false;
- } catch (Exception\ObjectNotFoundException $e) {
- \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ $c = $this->getContainer();
+ $streamFactory = new \Guzzle\Stream\PhpStreamRequestFactory();
+ $streamInterface = $streamFactory->fromRequest(
+ $c->getClient()
+ ->get($c->getUrl($path)));
+ $streamInterface->rewind();
+ $stream = $streamInterface->getStream();
+ stream_context_set_option($stream, 'swift','content', $streamInterface);
+ if(!strrpos($streamInterface
+ ->getMetaData('wrapper_data')[0], '404 Not Found')) {
+ return $stream;
+ }
return false;
- }
- try {
- $objectContent = $object->getContent();
- $objectContent->rewind();
- $stream = $objectContent->getStream();
- file_put_contents($tmpFile, $stream);
- } catch (Exceptions\IOError $e) {
+ } catch (\Guzzle\Http\Exception\BadResponseException $e) {
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
return false;
}
- return fopen($tmpFile, 'r');
case 'w':
case 'wb':
case 'a':
@@ -354,9 +360,18 @@ class Swift extends \OC\Files\Storage\Common {
}
$tmpFile = \OCP\Files::tmpFile($ext);
\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
- if ($this->file_exists($path)) {
+ // Fetch existing file if required
+ if ($mode[0] !== 'w' && $this->file_exists($path)) {
+ if ($mode[0] === 'x') {
+ // File cannot already exist
+ return false;
+ }
$source = $this->fopen($path, 'r');
file_put_contents($tmpFile, $source);
+ // Seek to end if required
+ if ($mode[0] === 'a') {
+ fseek($tmpFile, 0, SEEK_END);
+ }
}
self::$tmpFiles[$tmpFile] = $path;
@@ -505,7 +520,16 @@ class Swift extends \OC\Files\Storage\Common {
$this->anchor = new OpenStack($this->params['url'], $settings);
}
- $this->connection = $this->anchor->objectStoreService($this->params['service_name'], $this->params['region']);
+ $connection = $this->anchor->objectStoreService($this->params['service_name'], $this->params['region']);
+
+ if (!empty($this->params['endpoint_url'])) {
+ $endpoint = $connection->getEndpoint();
+ $endpoint->setPublicUrl($this->params['endpoint_url']);
+ $endpoint->setPrivateUrl($this->params['endpoint_url']);
+ $connection->setEndpoint($endpoint);
+ }
+
+ $this->connection = $connection;
return $this->connection;
}
diff --git a/apps/files_external/lib/visibilitytrait.php b/apps/files_external/lib/visibilitytrait.php
index dfd2d323ca6..916c8e69d9c 100644
--- a/apps/files_external/lib/visibilitytrait.php
+++ b/apps/files_external/lib/visibilitytrait.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/list.php b/apps/files_external/list.php
index b98db79de89..15e05b0e35c 100644
--- a/apps/files_external/list.php
+++ b/apps/files_external/list.php
@@ -1,8 +1,9 @@
<?php
/**
+ * @author Jesús Macias <jmacias@solidgear.es>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +24,11 @@ OCP\User::checkLoggedIn();
$tmpl = new OCP\Template('files_external', 'list', '');
+/* Load Status Manager */
+\OCP\Util::addStyle('files_external', 'external');
+\OCP\Util::addScript('files_external', 'statusmanager');
+\OCP\Util::addScript('files_external', 'rollingqueue');
+
OCP\Util::addScript('files_external', 'app');
OCP\Util::addScript('files_external', 'mountsfilelist');
diff --git a/apps/files_external/migration/dummyusersession.php b/apps/files_external/migration/dummyusersession.php
new file mode 100644
index 00000000000..bb4ef19dace
--- /dev/null
+++ b/apps/files_external/migration/dummyusersession.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_external\Migration;
+
+use OCP\IUser;
+use OCP\IUserSession;
+
+class DummyUserSession implements IUserSession {
+
+ /**
+ * @var IUser
+ */
+ private $user;
+
+ public function login($user, $password) {
+ }
+
+ public function logout() {
+ }
+
+ public function setUser($user) {
+ $this->user = $user;
+ }
+
+ public function getUser() {
+ return $this->user;
+ }
+
+ public function isLoggedIn() {
+ return !is_null($this->user);
+ }
+}
diff --git a/apps/files_external/migration/storagemigrator.php b/apps/files_external/migration/storagemigrator.php
new file mode 100644
index 00000000000..ba81810a4fd
--- /dev/null
+++ b/apps/files_external/migration/storagemigrator.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_external\Migration;
+
+use OCA\Files_External\Service\BackendService;
+use OCA\Files_External\Service\DBConfigService;
+use OCA\Files_external\Service\GlobalLegacyStoragesService;
+use OCA\Files_external\Service\GlobalStoragesService;
+use OCA\Files_external\Service\LegacyStoragesService;
+use OCA\Files_external\Service\StoragesService;
+use OCA\Files_external\Service\UserLegacyStoragesService;
+use OCA\Files_external\Service\UserStoragesService;
+use OCP\Files\Config\IUserMountCache;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\ILogger;
+use OCP\IUser;
+use OCP\IUserSession;
+
+/**
+ * Migrate mount config from mount.json to the database
+ */
+class StorageMigrator {
+ /**
+ * @var BackendService
+ */
+ private $backendService;
+
+ /**
+ * @var DBConfigService
+ */
+ private $dbConfig;
+
+ /**
+ * @var IConfig
+ */
+ private $config;
+
+ /**
+ * @var IDBConnection
+ */
+ private $connection;
+
+ /**
+ * @var ILogger
+ */
+ private $logger;
+
+ /** @var IUserMountCache */
+ private $userMountCache;
+
+ /**
+ * StorageMigrator constructor.
+ *
+ * @param BackendService $backendService
+ * @param DBConfigService $dbConfig
+ * @param IConfig $config
+ * @param IDBConnection $connection
+ * @param ILogger $logger
+ * @param IUserMountCache $userMountCache
+ */
+ public function __construct(
+ BackendService $backendService,
+ DBConfigService $dbConfig,
+ IConfig $config,
+ IDBConnection $connection,
+ ILogger $logger,
+ IUserMountCache $userMountCache
+ ) {
+ $this->backendService = $backendService;
+ $this->dbConfig = $dbConfig;
+ $this->config = $config;
+ $this->connection = $connection;
+ $this->logger = $logger;
+ $this->userMountCache = $userMountCache;
+ }
+
+ private function migrate(LegacyStoragesService $legacyService, StoragesService $storageService) {
+ $existingStorage = $legacyService->getAllStorages();
+
+ $this->connection->beginTransaction();
+ try {
+ foreach ($existingStorage as $storage) {
+ $storageService->addStorage($storage);
+ }
+ $this->connection->commit();
+ } catch (\Exception $e) {
+ $this->logger->logException($e);
+ $this->connection->rollBack();
+ }
+ }
+
+ /**
+ * Migrate admin configured storages
+ */
+ public function migrateGlobal() {
+ $legacyService = new GlobalLegacyStoragesService($this->backendService);
+ $storageService = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->userMountCache);
+
+ $this->migrate($legacyService, $storageService);
+ }
+
+ /**
+ * Migrate personal storages configured by the current user
+ *
+ * @param IUser $user
+ */
+ public function migrateUser(IUser $user) {
+ $dummySession = new DummyUserSession();
+ $dummySession->setUser($user);
+ $userId = $user->getUID();
+ $userVersion = $this->config->getUserValue($userId, 'files_external', 'config_version', '0.0.0');
+ if (version_compare($userVersion, '0.5.0', '<')) {
+ $this->config->setUserValue($userId, 'files_external', 'config_version', '0.5.0');
+ $legacyService = new UserLegacyStoragesService($this->backendService, $dummySession);
+ $storageService = new UserStoragesService($this->backendService, $this->dbConfig, $dummySession, $this->userMountCache);
+
+ $this->migrate($legacyService, $storageService);
+ }
+ }
+}
diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php
index df15c3bd258..f180b7e8f5c 100644
--- a/apps/files_external/personal.php
+++ b/apps/files_external/personal.php
@@ -1,14 +1,13 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Lukas Reschke <lukas@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,32 +30,16 @@ use \OCA\Files_External\Service\BackendService;
$appContainer = \OC_Mount_Config::$app->getContainer();
$backendService = $appContainer->query('OCA\Files_External\Service\BackendService');
$userStoragesService = $appContainer->query('OCA\Files_external\Service\UserStoragesService');
-
-OCP\Util::addScript('files_external', 'settings');
-OCP\Util::addStyle('files_external', 'settings');
-
-$backends = array_filter($backendService->getAvailableBackends(), function($backend) {
- return $backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL);
-});
-$authMechanisms = array_filter($backendService->getAuthMechanisms(), function($authMechanism) {
- return $authMechanism->isVisibleFor(BackendService::VISIBILITY_PERSONAL);
-});
-foreach ($backends as $backend) {
- if ($backend->getCustomJs()) {
- \OCP\Util::addScript('files_external', $backend->getCustomJs());
- }
-}
-foreach ($authMechanisms as $authMechanism) {
- if ($authMechanism->getCustomJs()) {
- \OCP\Util::addScript('files_external', $authMechanism->getCustomJs());
- }
-}
+$globalAuth = $appContainer->query('OCA\Files_External\Lib\Auth\Password\GlobalAuth');
$tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
-$tmpl->assign('isAdminPage', false);
+$tmpl->assign('visibilityType', BackendService::VISIBILITY_PERSONAL);
$tmpl->assign('storages', $userStoragesService->getStorages());
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
-$tmpl->assign('backends', $backends);
-$tmpl->assign('authMechanisms', $authMechanisms);
+$tmpl->assign('backends', $backendService->getAvailableBackends());
+$tmpl->assign('authMechanisms', $backendService->getAuthMechanisms());
+$uid = \OC::$server->getUserSession()->getUser()->getUID();
+$tmpl->assign('globalCredentials', $globalAuth->getAuth($uid));
+$tmpl->assign('globalCredentialsUid', $uid);
return $tmpl->fetchPage();
diff --git a/apps/files_external/service/backendservice.php b/apps/files_external/service/backendservice.php
index b325517e58a..9b23a441c7c 100644
--- a/apps/files_external/service/backendservice.php
+++ b/apps/files_external/service/backendservice.php
@@ -1,8 +1,9 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/service/dbconfigservice.php b/apps/files_external/service/dbconfigservice.php
new file mode 100644
index 00000000000..d52bf51e4aa
--- /dev/null
+++ b/apps/files_external/service/dbconfigservice.php
@@ -0,0 +1,410 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Service;
+
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+
+/**
+ * Stores the mount config in the database
+ */
+class DBConfigService {
+ const MOUNT_TYPE_ADMIN = 1;
+ const MOUNT_TYPE_PERSONAl = 2;
+
+ const APPLICABLE_TYPE_GLOBAL = 1;
+ const APPLICABLE_TYPE_GROUP = 2;
+ const APPLICABLE_TYPE_USER = 3;
+
+ /**
+ * @var IDBConnection
+ */
+ private $connection;
+
+ /**
+ * DBConfigService constructor.
+ *
+ * @param IDBConnection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+ }
+
+ /**
+ * @param int $mountId
+ * @return array
+ */
+ public function getMountById($mountId) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type'])
+ ->from('external_mounts', 'm')
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ $mounts = $this->getMountsFromQuery($query);
+ if (count($mounts) > 0) {
+ return $mounts[0];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get admin defined mounts
+ *
+ * @return array
+ */
+ public function getAdminMounts() {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type'])
+ ->from('external_mounts')
+ ->where($builder->expr()->eq('type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, \PDO::PARAM_INT)));
+ return $this->getMountsFromQuery($query);
+ }
+
+ protected function getForQuery(IQueryBuilder $builder, $type, $value) {
+ $query = $builder->select(['m.mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'm.type'])
+ ->from('external_mounts', 'm')
+ ->innerJoin('m', 'external_applicable', 'a', 'm.mount_id = a.mount_id')
+ ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, \PDO::PARAM_INT)));
+
+ if (is_null($value)) {
+ $query = $query->andWhere($builder->expr()->isNull('a.value'));
+ } else {
+ $query = $query->andWhere($builder->expr()->eq('a.value', $builder->createNamedParameter($value)));
+ }
+
+ return $query;
+ }
+
+ /**
+ * Get mounts by applicable
+ *
+ * @param int $type any of the self::APPLICABLE_TYPE_ constants
+ * @param string|null $value user_id, group_id or null for global mounts
+ * @return array
+ */
+ public function getMountsFor($type, $value) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $this->getForQuery($builder, $type, $value);
+
+ return $this->getMountsFromQuery($query);
+ }
+
+ /**
+ * Get admin defined mounts by applicable
+ *
+ * @param int $type any of the self::APPLICABLE_TYPE_ constants
+ * @param string|null $value user_id, group_id or null for global mounts
+ * @return array
+ */
+ public function getAdminMountsFor($type, $value) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $this->getForQuery($builder, $type, $value);
+ $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, \PDO::PARAM_INT)));
+
+ return $this->getMountsFromQuery($query);
+ }
+
+ /**
+ * Get admin defined mounts for multiple applicable
+ *
+ * @param int $type any of the self::APPLICABLE_TYPE_ constants
+ * @param string[] $values user_ids or group_ids
+ * @return array
+ */
+ public function getAdminMountsForMultiple($type, array $values) {
+ $builder = $this->connection->getQueryBuilder();
+ $params = array_map(function ($value) use ($builder) {
+ return $builder->createNamedParameter($value, \PDO::PARAM_STR);
+ }, $values);
+
+ $query = $builder->select(['m.mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'm.type'])
+ ->from('external_mounts', 'm')
+ ->innerJoin('m', 'external_applicable', 'a', 'm.mount_id = a.mount_id')
+ ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, \PDO::PARAM_INT)))
+ ->andWhere($builder->expr()->in('a.value', $params));
+ $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, \PDO::PARAM_INT)));
+
+ return $this->getMountsFromQuery($query);
+ }
+
+ /**
+ * Get user defined mounts by applicable
+ *
+ * @param int $type any of the self::APPLICABLE_TYPE_ constants
+ * @param string|null $value user_id, group_id or null for global mounts
+ * @return array
+ */
+ public function getUserMountsFor($type, $value) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $this->getForQuery($builder, $type, $value);
+ $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_PERSONAl, \PDO::PARAM_INT)));
+
+ return $this->getMountsFromQuery($query);
+ }
+
+ /**
+ * Add a mount to the database
+ *
+ * @param string $mountPoint
+ * @param string $storageBackend
+ * @param string $authBackend
+ * @param int $priority
+ * @param int $type self::MOUNT_TYPE_ADMIN or self::MOUNT_TYPE_PERSONAL
+ * @return int the id of the new mount
+ */
+ public function addMount($mountPoint, $storageBackend, $authBackend, $priority, $type) {
+ if (!$priority) {
+ $priority = 100;
+ }
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->insert('external_mounts')
+ ->values([
+ 'mount_point' => $builder->createNamedParameter($mountPoint, \PDO::PARAM_STR),
+ 'storage_backend' => $builder->createNamedParameter($storageBackend, \PDO::PARAM_STR),
+ 'auth_backend' => $builder->createNamedParameter($authBackend, \PDO::PARAM_STR),
+ 'priority' => $builder->createNamedParameter($priority, \PDO::PARAM_INT),
+ 'type' => $builder->createNamedParameter($type, \PDO::PARAM_INT)
+ ]);
+ $query->execute();
+ return (int)$this->connection->lastInsertId('external_mounts');
+ }
+
+ /**
+ * Remove a mount from the database
+ *
+ * @param int $mountId
+ */
+ public function removeMount($mountId) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->delete('external_mounts')
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ $query->execute();
+
+ $query = $builder->delete('external_applicable')
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ $query->execute();
+
+ $query = $builder->delete('external_config')
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ $query->execute();
+
+ $query = $builder->delete('external_options')
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ $query->execute();
+ }
+
+ /**
+ * @param int $mountId
+ * @param string $newMountPoint
+ */
+ public function setMountPoint($mountId, $newMountPoint) {
+ $builder = $this->connection->getQueryBuilder();
+
+ $query = $builder->update('external_mounts')
+ ->set('mount_point', $builder->createNamedParameter($newMountPoint))
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+
+ $query->execute();
+ }
+
+ /**
+ * @param int $mountId
+ * @param string $newAuthBackend
+ */
+ public function setAuthBackend($mountId, $newAuthBackend) {
+ $builder = $this->connection->getQueryBuilder();
+
+ $query = $builder->update('external_mounts')
+ ->set('auth_backend', $builder->createNamedParameter($newAuthBackend))
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+
+ $query->execute();
+ }
+
+ /**
+ * @param int $mountId
+ * @param string $key
+ * @param string $value
+ */
+ public function setConfig($mountId, $key, $value) {
+ $count = $this->connection->insertIfNotExist('*PREFIX*external_config', [
+ 'mount_id' => $mountId,
+ 'key' => $key,
+ 'value' => $value
+ ], ['mount_id', 'key']);
+ if ($count === 0) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->update('external_config')
+ ->set('value', $builder->createNamedParameter($value, \PDO::PARAM_STR))
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)))
+ ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, \PDO::PARAM_STR)));
+ $query->execute();
+ }
+ }
+
+ /**
+ * @param int $mountId
+ * @param string $key
+ * @param string $value
+ */
+ public function setOption($mountId, $key, $value) {
+ $count = $this->connection->insertIfNotExist('*PREFIX*external_options', [
+ 'mount_id' => $mountId,
+ 'key' => $key,
+ 'value' => json_encode($value)
+ ], ['mount_id', 'key']);
+ if ($count === 0) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->update('external_options')
+ ->set('value', $builder->createNamedParameter(json_encode($value), \PDO::PARAM_STR))
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)))
+ ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, \PDO::PARAM_STR)));
+ $query->execute();
+ }
+ }
+
+ public function addApplicable($mountId, $type, $value) {
+ $this->connection->insertIfNotExist('*PREFIX*external_applicable', [
+ 'mount_id' => $mountId,
+ 'type' => $type,
+ 'value' => $value
+ ], ['mount_id', 'type', 'value']);
+ }
+
+ public function removeApplicable($mountId, $type, $value) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->delete('external_applicable')
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)))
+ ->andWhere($builder->expr()->eq('type', $builder->createNamedParameter($type, \PDO::PARAM_INT)));
+
+ if (is_null($value)) {
+ $query = $query->andWhere($builder->expr()->isNull('value'));
+ } else {
+ $query = $query->andWhere($builder->expr()->eq('value', $builder->createNamedParameter($value, \PDO::PARAM_STR)));
+ }
+
+ $query->execute();
+ }
+
+ private function getMountsFromQuery(IQueryBuilder $query) {
+ $result = $query->execute();
+ $mounts = $result->fetchAll();
+
+ $mountIds = array_map(function ($mount) {
+ return $mount['mount_id'];
+ }, $mounts);
+
+ $applicable = $this->getApplicableForMounts($mountIds);
+ $config = $this->getConfigForMounts($mountIds);
+ $options = $this->getOptionsForMounts($mountIds);
+
+ return array_map(function ($mount, $applicable, $config, $options) {
+ $mount['type'] = (int)$mount['type'];
+ $mount['priority'] = (int)$mount['priority'];
+ $mount['applicable'] = $applicable;
+ $mount['config'] = $config;
+ $mount['options'] = $options;
+ return $mount;
+ }, $mounts, $applicable, $config, $options);
+ }
+
+ /**
+ * Get mount options from a table grouped by mount id
+ *
+ * @param string $table
+ * @param string[] $fields
+ * @param int[] $mountIds
+ * @return array [$mountId => [['field1' => $value1, ...], ...], ...]
+ */
+ private function selectForMounts($table, array $fields, array $mountIds) {
+ if (count($mountIds) === 0) {
+ return [];
+ }
+ $builder = $this->connection->getQueryBuilder();
+ $fields[] = 'mount_id';
+ $placeHolders = array_map(function ($id) use ($builder) {
+ return $builder->createPositionalParameter($id, \PDO::PARAM_INT);
+ }, $mountIds);
+ $query = $builder->select($fields)
+ ->from($table)
+ ->where($builder->expr()->in('mount_id', $placeHolders));
+ $rows = $query->execute()->fetchAll();
+
+ $result = [];
+ foreach ($mountIds as $mountId) {
+ $result[$mountId] = [];
+ }
+ foreach ($rows as $row) {
+ if (isset($row['type'])) {
+ $row['type'] = (int)$row['type'];
+ }
+ $result[$row['mount_id']][] = $row;
+ }
+ return $result;
+ }
+
+ /**
+ * @param int[] $mountIds
+ * @return array [$id => [['type' => $type, 'value' => $value], ...], ...]
+ */
+ public function getApplicableForMounts($mountIds) {
+ return $this->selectForMounts('external_applicable', ['type', 'value'], $mountIds);
+ }
+
+ /**
+ * @param int[] $mountIds
+ * @return array [$id => ['key1' => $value1, ...], ...]
+ */
+ public function getConfigForMounts($mountIds) {
+ $mountConfigs = $this->selectForMounts('external_config', ['key', 'value'], $mountIds);
+ return array_map([$this, 'createKeyValueMap'], $mountConfigs);
+ }
+
+ /**
+ * @param int[] $mountIds
+ * @return array [$id => ['key1' => $value1, ...], ...]
+ */
+ public function getOptionsForMounts($mountIds) {
+ $mountOptions = $this->selectForMounts('external_options', ['key', 'value'], $mountIds);
+ $optionsMap = array_map([$this, 'createKeyValueMap'], $mountOptions);
+ return array_map(function (array $options) {
+ return array_map(function ($option) {
+ return json_decode($option);
+ }, $options);
+ }, $optionsMap);
+ }
+
+ /**
+ * @param array $keyValuePairs [['key'=>$key, 'value=>$value], ...]
+ * @return array ['key1' => $value1, ...]
+ */
+ private function createKeyValueMap(array $keyValuePairs) {
+ $keys = array_map(function ($pair) {
+ return $pair['key'];
+ }, $keyValuePairs);
+ $values = array_map(function ($pair) {
+ return $pair['value'];
+ }, $keyValuePairs);
+
+ return array_combine($keys, $values);
+ }
+}
diff --git a/apps/files_external/service/globallegacystoragesservice.php b/apps/files_external/service/globallegacystoragesservice.php
new file mode 100644
index 00000000000..ed9b1bcf075
--- /dev/null
+++ b/apps/files_external/service/globallegacystoragesservice.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_external\Service;
+
+/**
+ * Read admin defined mounts from the legacy mount.json
+ */
+class GlobalLegacyStoragesService extends LegacyStoragesService {
+ /**
+ * @param BackendService $backendService
+ */
+ public function __construct(BackendService $backendService) {
+ $this->backendService = $backendService;
+ }
+
+ /**
+ * Read legacy config data
+ *
+ * @return array list of mount configs
+ */
+ protected function readLegacyConfig() {
+ // read global config
+ return \OC_Mount_Config::readData();
+ }
+}
diff --git a/apps/files_external/service/globalstoragesservice.php b/apps/files_external/service/globalstoragesservice.php
index ec9b8e782fa..312d8417a92 100644
--- a/apps/files_external/service/globalstoragesservice.php
+++ b/apps/files_external/service/globalstoragesservice.php
@@ -1,10 +1,11 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -33,68 +34,6 @@ use \OCA\Files_external\NotFoundException;
* Service class to manage global external storages
*/
class GlobalStoragesService extends StoragesService {
-
- /**
- * Write the storages to the configuration.
- *
- * @param array $storages map of storage id to storage config
- */
- public function writeConfig($storages) {
- // let the horror begin
- $mountPoints = [];
- foreach ($storages as $storageConfig) {
- $mountPoint = $storageConfig->getMountPoint();
- $oldBackendOptions = $storageConfig->getBackendOptions();
- $storageConfig->setBackendOptions(
- \OC_Mount_Config::encryptPasswords(
- $oldBackendOptions
- )
- );
-
- // system mount
- $rootMountPoint = '/$user/files/' . ltrim($mountPoint, '/');
-
- $applicableUsers = $storageConfig->getApplicableUsers();
- $applicableGroups = $storageConfig->getApplicableGroups();
- foreach ($applicableUsers as $applicable) {
- $this->addMountPoint(
- $mountPoints,
- \OC_Mount_Config::MOUNT_TYPE_USER,
- $applicable,
- $rootMountPoint,
- $storageConfig
- );
- }
-
- foreach ($applicableGroups as $applicable) {
- $this->addMountPoint(
- $mountPoints,
- \OC_Mount_Config::MOUNT_TYPE_GROUP,
- $applicable,
- $rootMountPoint,
- $storageConfig
- );
- }
-
- // if neither "applicableGroups" or "applicableUsers" were set, use "all" user
- if (empty($applicableUsers) && empty($applicableGroups)) {
- $this->addMountPoint(
- $mountPoints,
- \OC_Mount_Config::MOUNT_TYPE_USER,
- 'all',
- $rootMountPoint,
- $storageConfig
- );
- }
-
- // restore old backend options where the password was not encrypted,
- // because we don't want to change the state of the original object
- $storageConfig->setBackendOptions($oldBackendOptions);
- }
-
- $this->writeLegacyConfig($mountPoints);
- }
-
/**
* Triggers $signal for all applicable users of the given
* storage
@@ -219,4 +158,8 @@ class GlobalStoragesService extends StoragesService {
public function getVisibilityType() {
return BackendService::VISIBILITY_ADMIN;
}
+
+ protected function isApplicable(StorageConfig $config) {
+ return true;
+ }
}
diff --git a/apps/files_external/service/importlegacystoragesservice.php b/apps/files_external/service/importlegacystoragesservice.php
new file mode 100644
index 00000000000..7219df314d7
--- /dev/null
+++ b/apps/files_external/service/importlegacystoragesservice.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_external\Service;
+
+class ImportLegacyStoragesService extends LegacyStoragesService {
+ private $data;
+
+ /**
+ * @param BackendService $backendService
+ */
+ public function __construct(BackendService $backendService) {
+ $this->backendService = $backendService;
+ }
+
+ public function setData($data) {
+ $this->data = $data;
+ }
+
+ /**
+ * Read legacy config data
+ *
+ * @return array list of mount configs
+ */
+ protected function readLegacyConfig() {
+ return $this->data;
+ }
+}
diff --git a/apps/files_external/service/legacystoragesservice.php b/apps/files_external/service/legacystoragesservice.php
new file mode 100644
index 00000000000..bab1008e561
--- /dev/null
+++ b/apps/files_external/service/legacystoragesservice.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_external\Service;
+
+use \OCA\Files_external\Lib\StorageConfig;
+
+/**
+ * Read mount config from legacy mount.json
+ */
+abstract class LegacyStoragesService {
+ /** @var BackendService */
+ protected $backendService;
+
+ /**
+ * Read legacy config data
+ *
+ * @return array list of mount configs
+ */
+ abstract protected function readLegacyConfig();
+
+ /**
+ * Copy legacy storage options into the given storage config object.
+ *
+ * @param StorageConfig $storageConfig storage config to populate
+ * @param string $mountType mount type
+ * @param string $applicable applicable user or group
+ * @param array $storageOptions legacy storage options
+ *
+ * @return StorageConfig populated storage config
+ */
+ protected function populateStorageConfigWithLegacyOptions(
+ &$storageConfig,
+ $mountType,
+ $applicable,
+ $storageOptions
+ ) {
+ $backend = $this->backendService->getBackend($storageOptions['backend']);
+ if (!$backend) {
+ throw new \UnexpectedValueException('Invalid backend ' . $storageOptions['backend']);
+ }
+ $storageConfig->setBackend($backend);
+ if (isset($storageOptions['authMechanism']) && $storageOptions['authMechanism'] !== 'builtin::builtin') {
+ $authMechanism = $this->backendService->getAuthMechanism($storageOptions['authMechanism']);
+ } else {
+ $authMechanism = $backend->getLegacyAuthMechanism($storageOptions);
+ $storageOptions['authMechanism'] = 'null'; // to make error handling easier
+ }
+ if (!$authMechanism) {
+ throw new \UnexpectedValueException('Invalid authentication mechanism ' . $storageOptions['authMechanism']);
+ }
+ $storageConfig->setAuthMechanism($authMechanism);
+ $storageConfig->setBackendOptions($storageOptions['options']);
+ if (isset($storageOptions['mountOptions'])) {
+ $storageConfig->setMountOptions($storageOptions['mountOptions']);
+ }
+ if (!isset($storageOptions['priority'])) {
+ $storageOptions['priority'] = $backend->getPriority();
+ }
+ $storageConfig->setPriority($storageOptions['priority']);
+ if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) {
+ $applicableUsers = $storageConfig->getApplicableUsers();
+ if ($applicable !== 'all') {
+ $applicableUsers[] = $applicable;
+ $storageConfig->setApplicableUsers($applicableUsers);
+ }
+ } else if ($mountType === \OC_Mount_Config::MOUNT_TYPE_GROUP) {
+ $applicableGroups = $storageConfig->getApplicableGroups();
+ $applicableGroups[] = $applicable;
+ $storageConfig->setApplicableGroups($applicableGroups);
+ }
+ return $storageConfig;
+ }
+
+ /**
+ * Read the external storages config
+ *
+ * @return StorageConfig[] map of storage id to storage config
+ */
+ public function getAllStorages() {
+ $mountPoints = $this->readLegacyConfig();
+ /**
+ * Here is the how the horribly messy mount point array looks like
+ * from the mount.json file:
+ *
+ * $storageOptions = $mountPoints[$mountType][$applicable][$mountPath]
+ *
+ * - $mountType is either "user" or "group"
+ * - $applicable is the name of a user or group (or the current user for personal mounts)
+ * - $mountPath is the mount point path (where the storage must be mounted)
+ * - $storageOptions is a map of storage options:
+ * - "priority": storage priority
+ * - "backend": backend identifier
+ * - "class": LEGACY backend class name
+ * - "options": backend-specific options
+ * - "authMechanism": authentication mechanism identifier
+ * - "mountOptions": mount-specific options (ex: disable previews, scanner, etc)
+ */
+ // group by storage id
+ /** @var StorageConfig[] $storages */
+ $storages = [];
+ // for storages without id (legacy), group by config hash for
+ // later processing
+ $storagesWithConfigHash = [];
+ foreach ($mountPoints as $mountType => $applicables) {
+ foreach ($applicables as $applicable => $mountPaths) {
+ foreach ($mountPaths as $rootMountPath => $storageOptions) {
+ $currentStorage = null;
+ /**
+ * Flag whether the config that was read already has an id.
+ * If not, it will use a config hash instead and generate
+ * a proper id later
+ *
+ * @var boolean
+ */
+ $hasId = false;
+ // the root mount point is in the format "/$user/files/the/mount/point"
+ // we remove the "/$user/files" prefix
+ $parts = explode('/', ltrim($rootMountPath, '/'), 3);
+ if (count($parts) < 3) {
+ // something went wrong, skip
+ \OCP\Util::writeLog(
+ 'files_external',
+ 'Could not parse mount point "' . $rootMountPath . '"',
+ \OCP\Util::ERROR
+ );
+ continue;
+ }
+ $relativeMountPath = rtrim($parts[2], '/');
+ // note: we cannot do this after the loop because the decrypted config
+ // options might be needed for the config hash
+ $storageOptions['options'] = \OC_Mount_Config::decryptPasswords($storageOptions['options']);
+ if (!isset($storageOptions['backend'])) {
+ $storageOptions['backend'] = $storageOptions['class']; // legacy compat
+ }
+ if (!isset($storageOptions['authMechanism'])) {
+ $storageOptions['authMechanism'] = null; // ensure config hash works
+ }
+ if (isset($storageOptions['id'])) {
+ $configId = (int)$storageOptions['id'];
+ if (isset($storages[$configId])) {
+ $currentStorage = $storages[$configId];
+ }
+ $hasId = true;
+ } else {
+ // missing id in legacy config, need to generate
+ // but at this point we don't know the max-id, so use
+ // first group it by config hash
+ $storageOptions['mountpoint'] = $rootMountPath;
+ $configId = \OC_Mount_Config::makeConfigHash($storageOptions);
+ if (isset($storagesWithConfigHash[$configId])) {
+ $currentStorage = $storagesWithConfigHash[$configId];
+ }
+ }
+ if (is_null($currentStorage)) {
+ // create new
+ $currentStorage = new StorageConfig($configId);
+ $currentStorage->setMountPoint($relativeMountPath);
+ }
+ try {
+ $this->populateStorageConfigWithLegacyOptions(
+ $currentStorage,
+ $mountType,
+ $applicable,
+ $storageOptions
+ );
+ if ($hasId) {
+ $storages[$configId] = $currentStorage;
+ } else {
+ $storagesWithConfigHash[$configId] = $currentStorage;
+ }
+ } catch (\UnexpectedValueException $e) {
+ // dont die if a storage backend doesn't exist
+ \OCP\Util::writeLog(
+ 'files_external',
+ 'Could not load storage: "' . $e->getMessage() . '"',
+ \OCP\Util::ERROR
+ );
+ }
+ }
+ }
+ }
+
+ // convert parameter values
+ foreach ($storages as $storage) {
+ $storage->getBackend()->validateStorageDefinition($storage);
+ $storage->getAuthMechanism()->validateStorageDefinition($storage);
+ }
+ return $storages;
+ }
+}
diff --git a/apps/files_external/service/storagesservice.php b/apps/files_external/service/storagesservice.php
index 41bb0ca9b80..678b91c0109 100644
--- a/apps/files_external/service/storagesservice.php
+++ b/apps/files_external/service/storagesservice.php
@@ -1,10 +1,13 @@
<?php
/**
+ * @author Jesús Macias <jmacias@solidgear.es>
* @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,14 +26,13 @@
namespace OCA\Files_external\Service;
-use \OCP\IUserSession;
use \OC\Files\Filesystem;
-
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_external\NotFoundException;
-use \OCA\Files_External\Service\BackendService;
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
+use OCP\Files\Config\IUserMountCache;
+use \OCP\Files\StorageNotAvailableException;
/**
* Service class to manage external storages
@@ -41,88 +43,68 @@ abstract class StoragesService {
protected $backendService;
/**
- * @param BackendService $backendService
+ * @var DBConfigService
*/
- public function __construct(BackendService $backendService) {
- $this->backendService = $backendService;
- }
+ protected $dbConfig;
/**
- * Read legacy config data
- *
- * @return array list of mount configs
+ * @var IUserMountCache
*/
- protected function readLegacyConfig() {
- // read global config
- return \OC_Mount_Config::readData();
- }
+ protected $userMountCache;
/**
- * Write legacy config data
- *
- * @param array $mountPoints
+ * @param BackendService $backendService
+ * @param DBConfigService $dbConfigService
+ * @param IUserMountCache $userMountCache
*/
- protected function writeLegacyConfig(array $mountPoints) {
- // write global config
- \OC_Mount_Config::writeData(null, $mountPoints);
+ public function __construct(BackendService $backendService, DBConfigService $dbConfigService, IUserMountCache $userMountCache) {
+ $this->backendService = $backendService;
+ $this->dbConfig = $dbConfigService;
+ $this->userMountCache = $userMountCache;
}
- /**
- * Copy legacy storage options into the given storage config object.
- *
- * @param StorageConfig $storageConfig storage config to populate
- * @param string $mountType mount type
- * @param string $applicable applicable user or group
- * @param array $storageOptions legacy storage options
- *
- * @return StorageConfig populated storage config
- */
- protected function populateStorageConfigWithLegacyOptions(
- &$storageConfig,
- $mountType,
- $applicable,
- $storageOptions
- ) {
- $backend = $this->backendService->getBackend($storageOptions['backend']);
- if (!$backend) {
- throw new \UnexpectedValueException('Invalid backend '.$storageOptions['backend']);
- }
- $storageConfig->setBackend($backend);
-
- if (isset($storageOptions['authMechanism']) && $storageOptions['authMechanism'] !== 'builtin::builtin') {
- $authMechanism = $this->backendService->getAuthMechanism($storageOptions['authMechanism']);
- } else {
- $authMechanism = $backend->getLegacyAuthMechanism($storageOptions);
- $storageOptions['authMechanism'] = 'null'; // to make error handling easier
- }
- if (!$authMechanism) {
- throw new \UnexpectedValueException('Invalid authentication mechanism '.$storageOptions['authMechanism']);
- }
- $storageConfig->setAuthMechanism($authMechanism);
+ protected function readDBConfig() {
+ return $this->dbConfig->getAdminMounts();
+ }
- $storageConfig->setBackendOptions($storageOptions['options']);
- if (isset($storageOptions['mountOptions'])) {
- $storageConfig->setMountOptions($storageOptions['mountOptions']);
- }
- if (!isset($storageOptions['priority'])) {
- $storageOptions['priority'] = $backend->getPriority();
- }
- $storageConfig->setPriority($storageOptions['priority']);
+ protected function getStorageConfigFromDBMount(array $mount) {
+ $applicableUsers = array_filter($mount['applicable'], function ($applicable) {
+ return $applicable['type'] === DBConfigService::APPLICABLE_TYPE_USER;
+ });
+ $applicableUsers = array_map(function ($applicable) {
+ return $applicable['value'];
+ }, $applicableUsers);
+
+ $applicableGroups = array_filter($mount['applicable'], function ($applicable) {
+ return $applicable['type'] === DBConfigService::APPLICABLE_TYPE_GROUP;
+ });
+ $applicableGroups = array_map(function ($applicable) {
+ return $applicable['value'];
+ }, $applicableGroups);
- if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) {
- $applicableUsers = $storageConfig->getApplicableUsers();
- if ($applicable !== 'all') {
- $applicableUsers[] = $applicable;
- $storageConfig->setApplicableUsers($applicableUsers);
- }
- } else if ($mountType === \OC_Mount_Config::MOUNT_TYPE_GROUP) {
- $applicableGroups = $storageConfig->getApplicableGroups();
- $applicableGroups[] = $applicable;
- $storageConfig->setApplicableGroups($applicableGroups);
+ try {
+ $config = $this->createStorage(
+ $mount['mount_point'],
+ $mount['storage_backend'],
+ $mount['auth_backend'],
+ $mount['config'],
+ $mount['options'],
+ array_values($applicableUsers),
+ array_values($applicableGroups),
+ $mount['priority']
+ );
+ $config->setType($mount['type']);
+ $config->setId((int)$mount['mount_id']);
+ return $config;
+ } catch (\UnexpectedValueException $e) {
+ // dont die if a storage backend doesn't exist
+ \OCP\Util::writeLog(
+ 'files_external',
+ 'Could not load storage: "' . $e->getMessage() . '"',
+ \OCP\Util::ERROR
+ );
+ return null;
}
-
-
- return $storageConfig;
}
/**
@@ -131,190 +113,20 @@ abstract class StoragesService {
* @return array map of storage id to storage config
*/
protected function readConfig() {
- $mountPoints = $this->readLegacyConfig();
-
- /**
- * Here is the how the horribly messy mount point array looks like
- * from the mount.json file:
- *
- * $storageOptions = $mountPoints[$mountType][$applicable][$mountPath]
- *
- * - $mountType is either "user" or "group"
- * - $applicable is the name of a user or group (or the current user for personal mounts)
- * - $mountPath is the mount point path (where the storage must be mounted)
- * - $storageOptions is a map of storage options:
- * - "priority": storage priority
- * - "backend": backend identifier
- * - "class": LEGACY backend class name
- * - "options": backend-specific options
- * - "authMechanism": authentication mechanism identifier
- * - "mountOptions": mount-specific options (ex: disable previews, scanner, etc)
- */
-
- // group by storage id
- $storages = [];
-
- // for storages without id (legacy), group by config hash for
- // later processing
- $storagesWithConfigHash = [];
-
- foreach ($mountPoints as $mountType => $applicables) {
- foreach ($applicables as $applicable => $mountPaths) {
- foreach ($mountPaths as $rootMountPath => $storageOptions) {
- $currentStorage = null;
-
- /**
- * Flag whether the config that was read already has an id.
- * If not, it will use a config hash instead and generate
- * a proper id later
- *
- * @var boolean
- */
- $hasId = false;
-
- // the root mount point is in the format "/$user/files/the/mount/point"
- // we remove the "/$user/files" prefix
- $parts = explode('/', ltrim($rootMountPath, '/'), 3);
- if (count($parts) < 3) {
- // something went wrong, skip
- \OCP\Util::writeLog(
- 'files_external',
- 'Could not parse mount point "' . $rootMountPath . '"',
- \OCP\Util::ERROR
- );
- continue;
- }
-
- $relativeMountPath = rtrim($parts[2], '/');
-
- // note: we cannot do this after the loop because the decrypted config
- // options might be needed for the config hash
- $storageOptions['options'] = \OC_Mount_Config::decryptPasswords($storageOptions['options']);
-
- if (!isset($storageOptions['backend'])) {
- $storageOptions['backend'] = $storageOptions['class']; // legacy compat
- }
- if (!isset($storageOptions['authMechanism'])) {
- $storageOptions['authMechanism'] = null; // ensure config hash works
- }
-
- if (isset($storageOptions['id'])) {
- $configId = (int)$storageOptions['id'];
- if (isset($storages[$configId])) {
- $currentStorage = $storages[$configId];
- }
- $hasId = true;
- } else {
- // missing id in legacy config, need to generate
- // but at this point we don't know the max-id, so use
- // first group it by config hash
- $storageOptions['mountpoint'] = $rootMountPath;
- $configId = \OC_Mount_Config::makeConfigHash($storageOptions);
- if (isset($storagesWithConfigHash[$configId])) {
- $currentStorage = $storagesWithConfigHash[$configId];
- }
- }
-
- if (is_null($currentStorage)) {
- // create new
- $currentStorage = new StorageConfig($configId);
- $currentStorage->setMountPoint($relativeMountPath);
- }
-
- $this->populateStorageConfigWithLegacyOptions(
- $currentStorage,
- $mountType,
- $applicable,
- $storageOptions
- );
-
- if ($hasId) {
- $storages[$configId] = $currentStorage;
- } else {
- $storagesWithConfigHash[$configId] = $currentStorage;
- }
- }
- }
- }
-
- // process storages with config hash, they must get a real id
- if (!empty($storagesWithConfigHash)) {
- $this->setRealStorageIds($storages, $storagesWithConfigHash);
- }
-
- // convert parameter values
- foreach ($storages as $storage) {
- $storage->getBackend()->validateStorageDefinition($storage);
- $storage->getAuthMechanism()->validateStorageDefinition($storage);
- }
-
- return $storages;
- }
-
- /**
- * Replace config hash ID with real IDs, for migrating legacy storages
- *
- * @param StorageConfig[] $storages Storages with real IDs
- * @param StorageConfig[] $storagesWithConfigHash Storages with config hash IDs
- */
- protected function setRealStorageIds(array &$storages, array $storagesWithConfigHash) {
- $nextId = $this->generateNextId($storages);
- foreach ($storagesWithConfigHash as $storage) {
- $storage->setId($nextId);
- $storages[$nextId] = $storage;
- $nextId++;
- }
-
- // re-save the config with the generated ids
- $this->writeConfig($storages);
- }
+ $mounts = $this->readDBConfig();
+ $configs = array_map([$this, 'getStorageConfigFromDBMount'], $mounts);
+ $configs = array_filter($configs, function ($config) {
+ return $config instanceof StorageConfig;
+ });
- /**
- * Add mount point into the messy mount point structure
- *
- * @param array $mountPoints messy array of mount points
- * @param string $mountType mount type
- * @param string $applicable single applicable user or group
- * @param string $rootMountPoint root mount point to use
- * @param array $storageConfig storage config to set to the mount point
- */
- protected function addMountPoint(&$mountPoints, $mountType, $applicable, $rootMountPoint, $storageConfig) {
- if (!isset($mountPoints[$mountType])) {
- $mountPoints[$mountType] = [];
- }
-
- if (!isset($mountPoints[$mountType][$applicable])) {
- $mountPoints[$mountType][$applicable] = [];
- }
-
- $options = [
- 'id' => $storageConfig->getId(),
- 'backend' => $storageConfig->getBackend()->getIdentifier(),
- //'class' => $storageConfig->getBackend()->getClass(),
- 'authMechanism' => $storageConfig->getAuthMechanism()->getIdentifier(),
- 'options' => $storageConfig->getBackendOptions(),
- ];
-
- if (!is_null($storageConfig->getPriority())) {
- $options['priority'] = $storageConfig->getPriority();
- }
-
- $mountOptions = $storageConfig->getMountOptions();
- if (!empty($mountOptions)) {
- $options['mountOptions'] = $mountOptions;
- }
+ $keys = array_map(function (StorageConfig $config) {
+ return $config->getId();
+ }, $configs);
- $mountPoints[$mountType][$applicable][$rootMountPoint] = $options;
+ return array_combine($keys, $configs);
}
/**
- * Write the storages to the configuration.
- *
- * @param array $storages map of storage id to storage config
- */
- abstract protected function writeConfig($storages);
-
- /**
* Get a storage with status
*
* @param int $id storage id
@@ -323,19 +135,32 @@ abstract class StoragesService {
* @throws NotFoundException if the storage with the given id was not found
*/
public function getStorage($id) {
- $allStorages = $this->readConfig();
+ $mount = $this->dbConfig->getMountById($id);
- if (!isset($allStorages[$id])) {
+ if (!is_array($mount)) {
throw new NotFoundException('Storage with id "' . $id . '" not found');
}
- return $allStorages[$id];
+ $config = $this->getStorageConfigFromDBMount($mount);
+ if ($this->isApplicable($config)) {
+ return $config;
+ } else {
+ throw new NotFoundException('Storage with id "' . $id . '" not found');
+ }
}
/**
+ * Check whether this storage service should provide access to a storage
+ *
+ * @param StorageConfig $config
+ * @return bool
+ */
+ abstract protected function isApplicable(StorageConfig $config);
+
+ /**
* Gets all storages, valid or not
*
- * @return array array of storage configs
+ * @return StorageConfig[] array of storage configs
*/
public function getAllStorages() {
return $this->readConfig();
@@ -344,7 +169,7 @@ abstract class StoragesService {
/**
* Gets all valid storages
*
- * @return array
+ * @return StorageConfig[]
*/
public function getStorages() {
return array_filter($this->getAllStorages(), [$this, 'validateStorage']);
@@ -383,26 +208,55 @@ abstract class StoragesService {
abstract public function getVisibilityType();
/**
+ * @return integer
+ */
+ protected function getType() {
+ return DBConfigService::MOUNT_TYPE_ADMIN;
+ }
+
+ /**
* Add new storage to the configuration
*
- * @param array $newStorage storage attributes
+ * @param StorageConfig $newStorage storage attributes
*
* @return StorageConfig storage config, with added id
*/
public function addStorage(StorageConfig $newStorage) {
$allStorages = $this->readConfig();
- $configId = $this->generateNextId($allStorages);
+ $configId = $this->dbConfig->addMount(
+ $newStorage->getMountPoint(),
+ $newStorage->getBackend()->getIdentifier(),
+ $newStorage->getAuthMechanism()->getIdentifier(),
+ $newStorage->getPriority(),
+ $this->getType()
+ );
+
$newStorage->setId($configId);
+ foreach ($newStorage->getApplicableUsers() as $user) {
+ $this->dbConfig->addApplicable($configId, DBConfigService::APPLICABLE_TYPE_USER, $user);
+ }
+ foreach ($newStorage->getApplicableGroups() as $group) {
+ $this->dbConfig->addApplicable($configId, DBConfigService::APPLICABLE_TYPE_GROUP, $group);
+ }
+ foreach ($newStorage->getBackendOptions() as $key => $value) {
+ $this->dbConfig->setConfig($configId, $key, $value);
+ }
+ foreach ($newStorage->getMountOptions() as $key => $value) {
+ $this->dbConfig->setOption($configId, $key, $value);
+ }
+
+ if (count($newStorage->getApplicableUsers()) === 0 && count($newStorage->getApplicableGroups()) === 0) {
+ $this->dbConfig->addApplicable($configId, DBConfigService::APPLICABLE_TYPE_GLOBAL, null);
+ }
+
// add new storage
$allStorages[$configId] = $newStorage;
- $this->writeConfig($allStorages);
-
$this->triggerHooks($newStorage, Filesystem::signal_create_mount);
- $newStorage->setStatus(\OC_Mount_Config::STATUS_SUCCESS);
+ $newStorage->setStatus(StorageNotAvailableException::STATUS_SUCCESS);
return $newStorage;
}
@@ -432,11 +286,11 @@ abstract class StoragesService {
) {
$backend = $this->backendService->getBackend($backendIdentifier);
if (!$backend) {
- throw new \InvalidArgumentException('Unable to get backend for '.$backendIdentifier);
+ throw new \InvalidArgumentException('Unable to get backend for ' . $backendIdentifier);
}
$authMechanism = $this->backendService->getAuthMechanism($authMechanismIdentifier);
if (!$authMechanism) {
- throw new \InvalidArgumentException('Unable to get authentication mechanism for '.$authMechanismIdentifier);
+ throw new \InvalidArgumentException('Unable to get authentication mechanism for ' . $authMechanismIdentifier);
}
$newStorage = new StorageConfig();
$newStorage->setMountPoint($mountPoint);
@@ -509,24 +363,76 @@ abstract class StoragesService {
* @throws NotFoundException if the given storage does not exist in the config
*/
public function updateStorage(StorageConfig $updatedStorage) {
- $allStorages = $this->readConfig();
-
$id = $updatedStorage->getId();
- if (!isset($allStorages[$id])) {
- throw new NotFoundException('Storage with id "' . $id . '" not found');
+
+ $existingMount = $this->dbConfig->getMountById($id);
+
+ if (!is_array($existingMount)) {
+ throw new NotFoundException('Storage with id "' . $id . '" not found while updating storage');
}
- $oldStorage = $allStorages[$id];
- // ensure objectstore is persistent
- if ($objectstore = $oldStorage->getBackendOption('objectstore')) {
- $updatedStorage->setBackendOption('objectstore', $objectstore);
+ $oldStorage = $this->getStorageConfigFromDBMount($existingMount);
+
+ $removedUsers = array_diff($oldStorage->getApplicableUsers(), $updatedStorage->getApplicableUsers());
+ $removedGroups = array_diff($oldStorage->getApplicableGroups(), $updatedStorage->getApplicableGroups());
+ $addedUsers = array_diff($updatedStorage->getApplicableUsers(), $oldStorage->getApplicableUsers());
+ $addedGroups = array_diff($updatedStorage->getApplicableGroups(), $oldStorage->getApplicableGroups());
+
+ $oldUserCount = count($oldStorage->getApplicableUsers());
+ $oldGroupCount = count($oldStorage->getApplicableGroups());
+ $newUserCount = count($updatedStorage->getApplicableUsers());
+ $newGroupCount = count($updatedStorage->getApplicableGroups());
+ $wasGlobal = ($oldUserCount + $oldGroupCount) === 0;
+ $isGlobal = ($newUserCount + $newGroupCount) === 0;
+
+ foreach ($removedUsers as $user) {
+ $this->dbConfig->removeApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, $user);
+ }
+ foreach ($removedGroups as $group) {
+ $this->dbConfig->removeApplicable($id, DBConfigService::APPLICABLE_TYPE_GROUP, $group);
+ }
+ foreach ($addedUsers as $user) {
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, $user);
+ }
+ foreach ($addedGroups as $group) {
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_GROUP, $group);
}
- $allStorages[$id] = $updatedStorage;
- $this->writeConfig($allStorages);
+ if ($wasGlobal && !$isGlobal) {
+ $this->dbConfig->removeApplicable($id, DBConfigService::APPLICABLE_TYPE_GLOBAL, null);
+ } else if (!$wasGlobal && $isGlobal) {
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_GLOBAL, null);
+ }
+
+ $changedConfig = array_diff_assoc($updatedStorage->getBackendOptions(), $oldStorage->getBackendOptions());
+ $changedOptions = array_diff_assoc($updatedStorage->getMountOptions(), $oldStorage->getMountOptions());
+
+ foreach ($changedConfig as $key => $value) {
+ $this->dbConfig->setConfig($id, $key, $value);
+ }
+ foreach ($changedOptions as $key => $value) {
+ $this->dbConfig->setOption($id, $key, $value);
+ }
+
+ if ($updatedStorage->getMountPoint() !== $oldStorage->getMountPoint()) {
+ $this->dbConfig->setMountPoint($id, $updatedStorage->getMountPoint());
+ }
+
+ if ($updatedStorage->getAuthMechanism()->getIdentifier() !== $oldStorage->getAuthMechanism()->getIdentifier()) {
+ $this->dbConfig->setAuthBackend($id, $updatedStorage->getAuthMechanism()->getIdentifier());
+ }
$this->triggerChangeHooks($oldStorage, $updatedStorage);
+ if (($wasGlobal && !$isGlobal) || count($removedGroups) > 0) { // to expensive to properly handle these on the fly
+ $this->userMountCache->remoteStorageMounts($this->getStorageId($updatedStorage));
+ } else {
+ $storageId = $this->getStorageId($updatedStorage);
+ foreach ($removedUsers as $userId) {
+ $this->userMountCache->removeUserStorageMount($storageId, $userId);
+ }
+ }
+
return $this->getStorage($id);
}
@@ -538,17 +444,15 @@ abstract class StoragesService {
* @throws NotFoundException if no storage was found with the given id
*/
public function removeStorage($id) {
- $allStorages = $this->readConfig();
+ $existingMount = $this->dbConfig->getMountById($id);
- if (!isset($allStorages[$id])) {
+ if (!is_array($existingMount)) {
throw new NotFoundException('Storage with id "' . $id . '" not found');
}
- $deletedStorage = $allStorages[$id];
- unset($allStorages[$id]);
-
- $this->writeConfig($allStorages);
+ $this->dbConfig->removeMount($id);
+ $deletedStorage = $this->getStorageConfigFromDBMount($existingMount);
$this->triggerHooks($deletedStorage, Filesystem::signal_delete_mount);
// delete oc_storages entries and oc_filecache
@@ -568,24 +472,6 @@ abstract class StoragesService {
}
/**
- * Generates a configuration id to use for a new configuration entry.
- *
- * @param array $allStorages array of all storage configs
- *
- * @return int id
- */
- protected function generateNextId($allStorages) {
- if (empty($allStorages)) {
- return 1;
- }
- // note: this will mess up with with concurrency,
- // but so did the mount.json. This horribly hack
- // will disappear once we move to DB tables to
- // store the config
- return (max(array_keys($allStorages)) + 1);
- }
-
- /**
* Returns the rusty storage id from oc_storages from the given storage config.
*
* @param StorageConfig $storageConfig
@@ -611,4 +497,25 @@ abstract class StoragesService {
return $storageImpl->getId();
}
+ /**
+ * Construct the storage implementation
+ *
+ * @param StorageConfig $storageConfig
+ * @return int
+ */
+ private function getStorageId(StorageConfig $storageConfig) {
+ try {
+ $class = $storageConfig->getBackend()->getStorageClass();
+ /** @var \OC\Files\Storage\Storage $storage */
+ $storage = new $class($storageConfig->getBackendOptions());
+
+ // auth mechanism should fire first
+ $storage = $storageConfig->getBackend()->wrapStorage($storage);
+ $storage = $storageConfig->getAuthMechanism()->wrapStorage($storage);
+
+ return $storage->getStorageCache()->getNumericId();
+ } catch (\Exception $e) {
+ return -1;
+ }
+ }
}
diff --git a/apps/files_external/service/userglobalstoragesservice.php b/apps/files_external/service/userglobalstoragesservice.php
index afe77e1e059..03c831fe971 100644
--- a/apps/files_external/service/userglobalstoragesservice.php
+++ b/apps/files_external/service/userglobalstoragesservice.php
@@ -1,8 +1,10 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +25,7 @@ namespace OCA\Files_External\Service;
use \OCA\Files_external\Service\GlobalStoragesService;
use \OCA\Files_External\Service\BackendService;
+use OCP\Files\Config\IUserMountCache;
use \OCP\IUserSession;
use \OCP\IGroupManager;
use \OCA\Files_External\Service\UserTrait;
@@ -41,15 +44,19 @@ class UserGlobalStoragesService extends GlobalStoragesService {
/**
* @param BackendService $backendService
+ * @param DBConfigService $dbConfig
* @param IUserSession $userSession
* @param IGroupManager $groupManager
+ * @param IUserMountCache $userMountCache
*/
public function __construct(
BackendService $backendService,
+ DBConfigService $dbConfig,
IUserSession $userSession,
- IGroupManager $groupManager
+ IGroupManager $groupManager,
+ IUserMountCache $userMountCache
) {
- parent::__construct($backendService);
+ parent::__construct($backendService, $dbConfig, $userMountCache);
$this->userSession = $userSession;
$this->groupManager = $groupManager;
}
@@ -67,46 +74,30 @@ class UserGlobalStoragesService extends GlobalStoragesService {
}
}
- /**
- * Read legacy config data
- *
- * @return array list of mount configs
- */
- protected function readLegacyConfig() {
- // read global config
- $data = parent::readLegacyConfig();
- $userId = $this->getUser()->getUID();
-
- // don't use array_filter() with ARRAY_FILTER_USE_KEY, it's PHP 5.6+
- if (isset($data[\OC_Mount_Config::MOUNT_TYPE_USER])) {
- $newData = [];
- foreach ($data[\OC_Mount_Config::MOUNT_TYPE_USER] as $key => $value) {
- if (strtolower($key) === strtolower($userId) || $key === 'all') {
- $newData[$key] = $value;
- }
- }
- $data[\OC_Mount_Config::MOUNT_TYPE_USER] = $newData;
+ protected function readDBConfig() {
+ $userMounts = $this->dbConfig->getAdminMountsFor(DBConfigService::APPLICABLE_TYPE_USER, $this->getUser()->getUID());
+ $globalMounts = $this->dbConfig->getAdminMountsFor(DBConfigService::APPLICABLE_TYPE_GLOBAL, null);
+ $groups = $this->groupManager->getUserGroupIds($this->getUser());
+ if (is_array($groups) && count($groups) !== 0) {
+ $groupMounts = $this->dbConfig->getAdminMountsForMultiple(DBConfigService::APPLICABLE_TYPE_GROUP, $groups);
+ } else {
+ $groupMounts = [];
}
+ return array_merge($userMounts, $groupMounts, $globalMounts);
+ }
- if (isset($data[\OC_Mount_Config::MOUNT_TYPE_GROUP])) {
- $newData = [];
- foreach ($data[\OC_Mount_Config::MOUNT_TYPE_GROUP] as $key => $value) {
- if ($this->groupManager->isInGroup($userId, $key)) {
- $newData[$key] = $value;
- }
- }
- $data[\OC_Mount_Config::MOUNT_TYPE_GROUP] = $newData;
- }
+ public function addStorage(StorageConfig $newStorage) {
+ throw new \DomainException('UserGlobalStoragesService writing disallowed');
+ }
- return $data;
+ public function updateStorage(StorageConfig $updatedStorage) {
+ throw new \DomainException('UserGlobalStoragesService writing disallowed');
}
/**
- * Write legacy config data
- *
- * @param array $mountPoints
+ * @param integer $id
*/
- protected function writeLegacyConfig(array $mountPoints) {
+ public function removeStorage($id) {
throw new \DomainException('UserGlobalStoragesService writing disallowed');
}
@@ -126,7 +117,7 @@ class UserGlobalStoragesService extends GlobalStoragesService {
$result = [];
foreach ($storagesByMountpoint as $storageList) {
- $storage = array_reduce($storageList, function($carry, $item) {
+ $storage = array_reduce($storageList, function ($carry, $item) {
if (isset($carry)) {
$carryPriorityType = $this->getPriorityType($carry);
$itemPriorityType = $this->getPriorityType($item);
@@ -166,4 +157,22 @@ class UserGlobalStoragesService extends GlobalStoragesService {
return 0;
}
+ protected function isApplicable(StorageConfig $config) {
+ $applicableUsers = $config->getApplicableUsers();
+ $applicableGroups = $config->getApplicableGroups();
+
+ if (count($applicableUsers) === 0 && count($applicableGroups) === 0) {
+ return true;
+ }
+ if (in_array($this->getUser()->getUID(), $applicableUsers, true)) {
+ return true;
+ }
+ $groupIds = $this->groupManager->getUserGroupIds($this->getUser());
+ foreach ($groupIds as $groupId) {
+ if (in_array($groupId, $applicableGroups, true)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/apps/files_external/service/userlegacystoragesservice.php b/apps/files_external/service/userlegacystoragesservice.php
new file mode 100644
index 00000000000..2f14857c633
--- /dev/null
+++ b/apps/files_external/service/userlegacystoragesservice.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_external\Service;
+
+use OCP\IUserSession;
+
+/**
+ * Read user defined mounts from the legacy mount.json
+ */
+class UserLegacyStoragesService extends LegacyStoragesService {
+ /**
+ * @var IUserSession
+ */
+ private $userSession;
+
+ /**
+ * @param BackendService $backendService
+ * @param IUserSession $userSession
+ */
+ public function __construct(BackendService $backendService, IUserSession $userSession) {
+ $this->backendService = $backendService;
+ $this->userSession = $userSession;
+ }
+
+ /**
+ * Read legacy config data
+ *
+ * @return array list of storage configs
+ */
+ protected function readLegacyConfig() {
+ // read user config
+ $user = $this->userSession->getUser()->getUID();
+ return \OC_Mount_Config::readData($user);
+ }
+}
diff --git a/apps/files_external/service/userstoragesservice.php b/apps/files_external/service/userstoragesservice.php
index a8cdf60ad9c..d4b04de609d 100644
--- a/apps/files_external/service/userstoragesservice.php
+++ b/apps/files_external/service/userstoragesservice.php
@@ -1,9 +1,10 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,6 +23,7 @@
namespace OCA\Files_external\Service;
+use OCP\Files\Config\IUserMountCache;
use \OCP\IUserSession;
use \OC\Files\Filesystem;
@@ -35,107 +37,28 @@ use \OCA\Files_External\Service\UserTrait;
* (aka personal storages)
*/
class UserStoragesService extends StoragesService {
-
use UserTrait;
/**
* Create a user storages service
*
* @param BackendService $backendService
+ * @param DBConfigService $dbConfig
* @param IUserSession $userSession user session
+ * @param IUserMountCache $userMountCache
*/
public function __construct(
BackendService $backendService,
- IUserSession $userSession
+ DBConfigService $dbConfig,
+ IUserSession $userSession,
+ IUserMountCache $userMountCache
) {
$this->userSession = $userSession;
- parent::__construct($backendService);
- }
-
- /**
- * Read legacy config data
- *
- * @return array list of storage configs
- */
- protected function readLegacyConfig() {
- // read user config
- $user = $this->getUser()->getUID();
- return \OC_Mount_Config::readData($user);
- }
-
- /**
- * Write legacy config data
- *
- * @param array $mountPoints
- */
- protected function writeLegacyConfig(array $mountPoints) {
- // write user config
- $user = $this->getUser()->getUID();
- \OC_Mount_Config::writeData($user, $mountPoints);
+ parent::__construct($backendService, $dbConfig, $userMountCache);
}
- /**
- * Read the external storages config
- *
- * @return array map of storage id to storage config
- */
- protected function readConfig() {
- $user = $this->getUser()->getUID();
- // TODO: in the future don't rely on the global config reading code
- $storages = parent::readConfig();
-
- $filteredStorages = [];
- foreach ($storages as $configId => $storage) {
- // filter out all bogus storages that aren't for the current user
- if (!in_array($user, $storage->getApplicableUsers())) {
- continue;
- }
-
- // clear applicable users, should not be used
- $storage->setApplicableUsers([]);
-
- // strip out unneeded applicableUser fields
- $filteredStorages[$configId] = $storage;
- }
-
- return $filteredStorages;
- }
-
- /**
- * Write the storages to the user's configuration.
- *
- * @param array $storages map of storage id to storage config
- */
- public function writeConfig($storages) {
- $user = $this->getUser()->getUID();
-
- // let the horror begin
- $mountPoints = [];
- foreach ($storages as $storageConfig) {
- $mountPoint = $storageConfig->getMountPoint();
- $oldBackendOptions = $storageConfig->getBackendOptions();
- $storageConfig->setBackendOptions(
- \OC_Mount_Config::encryptPasswords(
- $oldBackendOptions
- )
- );
-
- $rootMountPoint = '/' . $user . '/files/' . ltrim($mountPoint, '/');
-
- $this->addMountPoint(
- $mountPoints,
- \OC_Mount_Config::MOUNT_TYPE_USER,
- $user,
- $rootMountPoint,
- $storageConfig
- );
-
- // restore old backend options where the password was not encrypted,
- // because we don't want to change the state of the original object
- $storageConfig->setBackendOptions($oldBackendOptions);
- }
-
- $this->writeLegacyConfig($mountPoints);
+ protected function readDBConfig() {
+ return $this->dbConfig->getUserMountsFor(DBConfigService::APPLICABLE_TYPE_USER, $this->getUser()->getUID());
}
/**
@@ -173,6 +96,36 @@ class UserStoragesService extends StoragesService {
}
}
+ protected function getType() {
+ return DBConfigService::MOUNT_TYPE_PERSONAl;
+ }
+
+ /**
+ * Add new storage to the configuration
+ *
+ * @param StorageConfig $newStorage storage attributes
+ *
+ * @return StorageConfig storage config, with added id
+ */
+ public function addStorage(StorageConfig $newStorage) {
+ $newStorage->setApplicableUsers([$this->getUser()->getUID()]);
+ $config = parent::addStorage($newStorage);
+ return $config;
+ }
+
+ /**
+ * Update storage to the configuration
+ *
+ * @param StorageConfig $updatedStorage storage attributes
+ *
+ * @return StorageConfig storage config
+ * @throws NotFoundException if the given storage does not exist in the config
+ */
+ public function updateStorage(StorageConfig $updatedStorage) {
+ $updatedStorage->setApplicableUsers([$this->getUser()->getUID()]);
+ return parent::updateStorage($updatedStorage);
+ }
+
/**
* Get the visibility type for this controller, used in validation
*
@@ -181,4 +134,8 @@ class UserStoragesService extends StoragesService {
public function getVisibilityType() {
return BackendService::VISIBILITY_PERSONAL;
}
+
+ protected function isApplicable(StorageConfig $config) {
+ return ($config->getApplicableUsers() === [$this->getUser()->getUID()]) && $config->getType() === StorageConfig::MOUNT_TYPE_PERSONAl;
+ }
}
diff --git a/apps/files_external/service/usertrait.php b/apps/files_external/service/usertrait.php
index 924f358f939..536c0f67e1f 100644
--- a/apps/files_external/service/usertrait.php
+++ b/apps/files_external/service/usertrait.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/settings.php b/apps/files_external/settings.php
index 03ed363bdb2..a5265c500d9 100644
--- a/apps/files_external/settings.php
+++ b/apps/files_external/settings.php
@@ -2,14 +2,12 @@
/**
* @author Frank Karlitschek <frank@owncloud.org>
* @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -34,41 +32,20 @@ use \OCA\Files_External\Service\BackendService;
$appContainer = \OC_Mount_Config::$app->getContainer();
$backendService = $appContainer->query('OCA\Files_External\Service\BackendService');
$globalStoragesService = $appContainer->query('OCA\Files_external\Service\GlobalStoragesService');
-
-OCP\Util::addScript('files_external', 'settings');
-OCP\Util::addStyle('files_external', 'settings');
+$globalAuth = $appContainer->query('OCA\Files_External\Lib\Auth\Password\GlobalAuth');
\OC_Util::addVendorScript('select2/select2');
\OC_Util::addVendorStyle('select2/select2');
-$backends = array_filter($backendService->getAvailableBackends(), function($backend) {
- return $backend->isVisibleFor(BackendService::VISIBILITY_ADMIN);
-});
-$authMechanisms = array_filter($backendService->getAuthMechanisms(), function($authMechanism) {
- return $authMechanism->isVisibleFor(BackendService::VISIBILITY_ADMIN);
-});
-foreach ($backends as $backend) {
- if ($backend->getCustomJs()) {
- \OCP\Util::addScript('files_external', $backend->getCustomJs());
- }
-}
-foreach ($authMechanisms as $authMechanism) {
- if ($authMechanism->getCustomJs()) {
- \OCP\Util::addScript('files_external', $authMechanism->getCustomJs());
- }
-}
-
-$userBackends = array_filter($backendService->getAvailableBackends(), function($backend) {
- return $backend->isAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL);
-});
-
$tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
-$tmpl->assign('isAdminPage', true);
+$tmpl->assign('visibilityType', BackendService::VISIBILITY_ADMIN);
$tmpl->assign('storages', $globalStoragesService->getStorages());
-$tmpl->assign('backends', $backends);
-$tmpl->assign('authMechanisms', $authMechanisms);
-$tmpl->assign('userBackends', $userBackends);
+$tmpl->assign('backends', $backendService->getAvailableBackends());
+$tmpl->assign('authMechanisms', $backendService->getAuthMechanisms());
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed());
+$tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed());
+$tmpl->assign('globalCredentials', $globalAuth->getAuth(''));
+$tmpl->assign('globalCredentialsUid', '');
return $tmpl->fetchPage();
diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php
index cebf6cc4de0..8b453fe77c3 100644
--- a/apps/files_external/templates/settings.php
+++ b/apps/files_external/templates/settings.php
@@ -3,6 +3,21 @@
use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Service\BackendService;
+ script('files_external', 'settings');
+ style('files_external', 'settings');
+
+ // load custom JS
+ foreach ($_['backends'] as $backend) {
+ if ($backend->getCustomJs()) {
+ script('files_external', $backend->getCustomJs());
+ }
+ }
+ foreach ($_['authMechanisms'] as $authMechanism) {
+ if ($authMechanism->getCustomJs()) {
+ script('files_external', $authMechanism->getCustomJs());
+ }
+ }
+
function writeParameterInput($parameter, $options, $classes = []) {
$value = '';
if (isset($options[$parameter->getName()])) {
@@ -53,10 +68,25 @@
}
}
?>
-<form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
+<form autocomplete="false" class="section" action="#"
+ id="global_credentials">
<h2><?php p($l->t('External Storage')); ?></h2>
+ <p><?php p($l->t('Global Credentials')); ?></p>
+ <input type="text" name="username"
+ autocomplete="false"
+ value="<?php p($_['globalCredentials']['user']); ?>"
+ placeholder="<?php p($l->t('Username')) ?>"/>
+ <input type="password" name="password"
+ autocomplete="false"
+ value="<?php p($_['globalCredentials']['password']); ?>"
+ placeholder="<?php p($l->t('Password')) ?>"/>
+ <input type="hidden" name="uid"
+ value="<?php p($_['globalCredentialsUid']); ?>"/>
+ <input type="submit" value="<?php p($l->t('Save')) ?>"/>
+</form>
+<form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
<?php if (isset($_['dependencies']) and ($_['dependencies']<>'')) print_unescaped(''.$_['dependencies'].''); ?>
- <table id="externalStorage" class="grid" data-admin='<?php print_unescaped(json_encode($_['isAdminPage'])); ?>'>
+ <table id="externalStorage" class="grid" data-admin='<?php print_unescaped(json_encode($_['visibilityType'] === BackendService::VISIBILITY_ADMIN)); ?>'>
<thead>
<tr>
<th></th>
@@ -64,79 +94,12 @@
<th><?php p($l->t('External storage')); ?></th>
<th><?php p($l->t('Authentication')); ?></th>
<th><?php p($l->t('Configuration')); ?></th>
- <?php if ($_['isAdminPage']) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?>
+ <?php if ($_['visibilityType'] === BackendService::VISIBILITY_ADMIN) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?>
<th>&nbsp;</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
- <?php foreach ($_['storages'] as $storage): ?>
- <tr class="<?php p($storage->getBackend()->getIdentifier()); ?>" data-id="<?php p($storage->getId()); ?>">
- <td class="status">
- <span></span>
- </td>
- <td class="mountPoint"><input type="text" name="mountPoint"
- value="<?php p(ltrim($storage->getMountPoint(), '/')); ?>"
- data-mountpoint="<?php p(ltrim($storage->getMountPoint(), '/')); ?>"
- placeholder="<?php p($l->t('Folder name')); ?>" />
- </td>
- <td class="backend" data-class="<?php p($storage->getBackend()->getIdentifier()); ?>"><?php p($storage->getBackend()->getText()); ?>
- </td>
- <td class="authentication">
- <select class="selectAuthMechanism">
- <?php
- $authSchemes = $storage->getBackend()->getAuthSchemes();
- $authMechanisms = array_filter($_['authMechanisms'], function($mech) use ($authSchemes) {
- return isset($authSchemes[$mech->getScheme()]);
- });
- ?>
- <?php foreach ($authMechanisms as $mech): ?>
- <option value="<?php p($mech->getIdentifier()); ?>" data-scheme="<?php p($mech->getScheme());?>"
- <?php if ($mech->getIdentifier() === $storage->getAuthMechanism()->getIdentifier()): ?>selected<?php endif; ?>
- ><?php p($mech->getText()); ?></option>
- <?php endforeach; ?>
- </select>
- </td>
- <td class="configuration">
- <?php
- $options = $storage->getBackendOptions();
- foreach ($storage->getBackend()->getParameters() as $parameter) {
- writeParameterInput($parameter, $options);
- }
- foreach ($storage->getAuthMechanism()->getParameters() as $parameter) {
- writeParameterInput($parameter, $options, ['auth-param']);
- }
- ?>
- </td>
- <?php if ($_['isAdminPage']): ?>
- <td class="applicable"
- align="right"
- data-applicable-groups='<?php print_unescaped(json_encode($storage->getApplicableGroups())); ?>'
- data-applicable-users='<?php print_unescaped(json_encode($storage->getApplicableUsers())); ?>'>
- <input type="hidden" class="applicableUsers" style="width:20em;" value=""/>
- </td>
- <?php endif; ?>
- <td class="mountOptionsToggle">
- <img
- class="svg action"
- title="<?php p($l->t('Advanced settings')); ?>"
- alt="<?php p($l->t('Advanced settings')); ?>"
- src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>"
- />
- <input type="hidden" class="mountOptions" value="<?php p(json_encode($storage->getMountOptions())); ?>" />
- <?php if ($_['isAdminPage']): ?>
- <input type="hidden" class="priority" value="<?php p($storage->getPriority()); ?>" />
- <?php endif; ?>
- </td>
- <td class="remove">
- <img alt="<?php p($l->t('Delete')); ?>"
- title="<?php p($l->t('Delete')); ?>"
- class="svg action"
- src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"
- />
- </td>
- </tr>
- <?php endforeach; ?>
<tr id="addMountPoint">
<td class="status">
<span></span>
@@ -151,7 +114,9 @@
<?php p($l->t('Add storage')); ?>
</option>
<?php
- $sortedBackends = $_['backends'];
+ $sortedBackends = array_filter($_['backends'], function($backend) use ($_) {
+ return $backend->isVisibleFor($_['visibilityType']);
+ });
uasort($sortedBackends, function($a, $b) {
return strcasecmp($a->getText(), $b->getText());
});
@@ -164,7 +129,7 @@
</td>
<td class="authentication" data-mechanisms='<?php p(json_encode($_['authMechanisms'])); ?>'></td>
<td class="configuration"></td>
- <?php if ($_['isAdminPage']): ?>
+ <?php if ($_['visibilityType'] === BackendService::VISIBILITY_ADMIN): ?>
<td class="applicable" align="right">
<input type="hidden" class="applicableUsers" style="width:20em;" value="" />
</td>
@@ -189,7 +154,7 @@
</table>
<br />
- <?php if ($_['isAdminPage']): ?>
+ <?php if ($_['visibilityType'] === BackendService::VISIBILITY_ADMIN): ?>
<br />
<input type="checkbox" name="allowUserMounting" id="allowUserMounting" class="checkbox"
value="1" <?php if ($_['allowUserMounting'] == 'yes') print_unescaped(' checked="checked"'); ?> />
@@ -197,7 +162,12 @@
<p id="userMountingBackends"<?php if ($_['allowUserMounting'] != 'yes'): ?> class="hidden"<?php endif; ?>>
<?php p($l->t('Allow users to mount the following external storage')); ?><br />
- <?php $i = 0; foreach ($_['userBackends'] as $backend): ?>
+ <?php
+ $userBackends = array_filter($_['backends'], function($backend) {
+ return $backend->isAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL);
+ });
+ ?>
+ <?php $i = 0; foreach ($userBackends as $backend): ?>
<?php if ($deprecateTo = $backend->getDeprecateTo()): ?>
<input type="hidden" id="allowUserMountingBackends<?php p($i); ?>" name="allowUserMountingBackends[]" value="<?php p($backend->getIdentifier()); ?>" data-deprecate-to="<?php p($deprecateTo->getIdentifier()); ?>" />
<?php else: ?>
diff --git a/apps/files_external/tests/amazons3migration.php b/apps/files_external/tests/amazons3migration.php
index 3eba5bca644..679a880475e 100644
--- a/apps/files_external/tests/amazons3migration.php
+++ b/apps/files_external/tests/amazons3migration.php
@@ -3,9 +3,11 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +27,13 @@
namespace Test\Files\Storage;
+/**
+ * Class AmazonS3Migration
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class AmazonS3Migration extends \Test\TestCase {
/**
@@ -123,6 +132,9 @@ class AmazonS3Migration extends \Test\TestCase {
return $storages;
}
+ /**
+ * @param string $id
+ */
public function deleteStorage($id) {
$stmt = \OC::$server->getDatabaseConnection()->prepare(
'DELETE FROM `*PREFIX*storages` WHERE `id` = ?'
diff --git a/apps/files_external/tests/auth/authmechanismtest.php b/apps/files_external/tests/auth/authmechanismtest.php
index 6933cc988b1..789d1f62478 100644
--- a/apps/files_external/tests/auth/authmechanismtest.php
+++ b/apps/files_external/tests/auth/authmechanismtest.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/tests/backend/backendtest.php b/apps/files_external/tests/backend/backendtest.php
index 9e0e27c824b..50f6d975bf0 100644
--- a/apps/files_external/tests/backend/backendtest.php
+++ b/apps/files_external/tests/backend/backendtest.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/tests/backend/legacybackendtest.php b/apps/files_external/tests/backend/legacybackendtest.php
index 6c977522e9e..d825b7627b7 100644
--- a/apps/files_external/tests/backend/legacybackendtest.php
+++ b/apps/files_external/tests/backend/legacybackendtest.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/tests/backends/amazons3.php b/apps/files_external/tests/backends/amazons3.php
index c16581a4495..3b43f81a926 100644
--- a/apps/files_external/tests/backends/amazons3.php
+++ b/apps/files_external/tests/backends/amazons3.php
@@ -4,9 +4,10 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +26,13 @@
namespace Test\Files\Storage;
+/**
+ * Class AmazonS3
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class AmazonS3 extends Storage {
private $config;
diff --git a/apps/files_external/tests/backends/dropbox.php b/apps/files_external/tests/backends/dropbox.php
index 8765011532c..1bf8b4171fb 100644
--- a/apps/files_external/tests/backends/dropbox.php
+++ b/apps/files_external/tests/backends/dropbox.php
@@ -4,9 +4,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +26,13 @@
namespace Test\Files\Storage;
+/**
+ * Class Dropbox
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class Dropbox extends Storage {
private $config;
diff --git a/apps/files_external/tests/backends/ftp.php b/apps/files_external/tests/backends/ftp.php
index 20a5c275d29..868a022d38f 100644
--- a/apps/files_external/tests/backends/ftp.php
+++ b/apps/files_external/tests/backends/ftp.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +26,13 @@
namespace Test\Files\Storage;
+/**
+ * Class FTP
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class FTP extends Storage {
private $config;
diff --git a/apps/files_external/tests/backends/google.php b/apps/files_external/tests/backends/google.php
index 6ff235ac6af..7622f796407 100644
--- a/apps/files_external/tests/backends/google.php
+++ b/apps/files_external/tests/backends/google.php
@@ -6,8 +6,9 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,6 +29,13 @@ namespace Test\Files\Storage;
require_once 'files_external/lib/google.php';
+/**
+ * Class Google
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class Google extends Storage {
private $config;
diff --git a/apps/files_external/tests/backends/owncloud.php b/apps/files_external/tests/backends/owncloud.php
index 47e27870be2..a56e9b2a186 100644
--- a/apps/files_external/tests/backends/owncloud.php
+++ b/apps/files_external/tests/backends/owncloud.php
@@ -2,9 +2,10 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +24,13 @@
namespace Test\Files\Storage;
+/**
+ * Class OwnCloud
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class OwnCloud extends Storage {
private $config;
diff --git a/apps/files_external/tests/backends/sftp.php b/apps/files_external/tests/backends/sftp.php
index aaed2b3460a..608982adbc4 100644
--- a/apps/files_external/tests/backends/sftp.php
+++ b/apps/files_external/tests/backends/sftp.php
@@ -4,9 +4,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +26,13 @@
namespace Test\Files\Storage;
+/**
+ * Class SFTP
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class SFTP extends Storage {
/**
* @var \OC\Files\Storage\SFTP instance
diff --git a/apps/files_external/tests/backends/sftp_key.php b/apps/files_external/tests/backends/sftp_key.php
index 6e8ac9f7239..73c6a0b6432 100644
--- a/apps/files_external/tests/backends/sftp_key.php
+++ b/apps/files_external/tests/backends/sftp_key.php
@@ -2,9 +2,10 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Ross Nicoll <jrn@jrn.me.uk>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Viktor Szépe <viktor@szepe.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +24,13 @@
namespace Test\Files\Storage;
+/**
+ * Class SFTP_Key
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class SFTP_Key extends Storage {
private $config;
diff --git a/apps/files_external/tests/backends/smb.php b/apps/files_external/tests/backends/smb.php
index 0da86cb824f..f9a377c271b 100644
--- a/apps/files_external/tests/backends/smb.php
+++ b/apps/files_external/tests/backends/smb.php
@@ -3,9 +3,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,13 @@
namespace Test\Files\Storage;
+/**
+ * Class SMB
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class SMB extends Storage {
protected function setUp() {
diff --git a/apps/files_external/tests/backends/swift.php b/apps/files_external/tests/backends/swift.php
index 2e6670f84f8..9bdcd48ee68 100644
--- a/apps/files_external/tests/backends/swift.php
+++ b/apps/files_external/tests/backends/swift.php
@@ -2,11 +2,12 @@
/**
* @author Christian Berendt <berendt@b1-systems.de>
* @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +26,13 @@
namespace Test\Files\Storage;
+/**
+ * Class Swift
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class Swift extends Storage {
private $config;
@@ -32,28 +40,35 @@ class Swift extends Storage {
protected function setUp() {
parent::setUp();
- $this->config = include('files_external/tests/config.php');
- if (!is_array($this->config) or !isset($this->config['swift'])
- or !$this->config['swift']['run']) {
+ $this->config = include('files_external/tests/config.swift.php');
+ if (!is_array($this->config) or !$this->config['run']) {
$this->markTestSkipped('OpenStack Object Storage backend not configured');
}
- $this->instance = new \OC\Files\Storage\Swift($this->config['swift']);
+ $this->instance = new \OC\Files\Storage\Swift($this->config);
}
protected function tearDown() {
if ($this->instance) {
- $connection = $this->instance->getConnection();
- $container = $connection->getContainer($this->config['swift']['bucket']);
+ try {
+ $connection = $this->instance->getConnection();
+ $container = $connection->getContainer($this->config['bucket']);
- $objects = $container->objectList();
- while($object = $objects->next()) {
- $object->setName(str_replace('#','%23',$object->getName()));
- $object->delete();
- }
+ $objects = $container->objectList();
+ while($object = $objects->next()) {
+ $object->setName(str_replace('#','%23',$object->getName()));
+ $object->delete();
+ }
- $container->delete();
+ $container->delete();
+ } catch (\Guzzle\Http\Exception\ClientErrorResponseException $e) {
+ // container didn't exist, so we don't need to delete it
+ }
}
parent::tearDown();
}
+
+ public function testStat() {
+ $this->markTestSkipped('Swift doesn\'t update the parents folder mtime');
+ }
}
diff --git a/apps/files_external/tests/backends/webdav.php b/apps/files_external/tests/backends/webdav.php
index e2020da7c72..e1a710c94b4 100644
--- a/apps/files_external/tests/backends/webdav.php
+++ b/apps/files_external/tests/backends/webdav.php
@@ -3,9 +3,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,13 @@
namespace Test\Files\Storage;
+/**
+ * Class DAV
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class DAV extends Storage {
protected function setUp() {
diff --git a/apps/files_external/tests/command/applicabletest.php b/apps/files_external/tests/command/applicabletest.php
new file mode 100644
index 00000000000..64d41f6f245
--- /dev/null
+++ b/apps/files_external/tests/command/applicabletest.php
@@ -0,0 +1,168 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Tests\Command;
+
+use OCA\Files_External\Command\Applicable;
+
+class ApplicableTest extends CommandTest {
+ private function getInstance($storageService) {
+ /** @var \OCP\IUserManager|\PHPUnit_Framework_MockObject_MockObject $userManager */
+ $userManager = $this->getMock('\OCP\IUserManager');
+ /** @var \OCP\IGroupManager|\PHPUnit_Framework_MockObject_MockObject $groupManager */
+ $groupManager = $this->getMock('\OCP\IGroupManager');
+
+ $userManager->expects($this->any())
+ ->method('userExists')
+ ->will($this->returnValue(true));
+
+ $groupManager->expects($this->any())
+ ->method('groupExists')
+ ->will($this->returnValue(true));
+
+ return new Applicable($storageService, $userManager, $groupManager);
+ }
+
+ public function testListEmpty() {
+ $mount = $this->getMount(1, '', '');
+
+ $storageService = $this->getGlobalStorageService([$mount]);
+ $command = $this->getInstance($storageService);
+
+ $input = $this->getInput($command, [
+ 'mount_id' => 1
+ ], [
+ 'output' => 'json'
+ ]);
+
+ $result = json_decode($this->executeCommand($command, $input), true);
+
+ $this->assertEquals(['users' => [], 'groups' => []], $result);
+ }
+
+ public function testList() {
+ $mount = $this->getMount(1, '', '', '', [], [], ['test', 'asd']);
+
+ $storageService = $this->getGlobalStorageService([$mount]);
+ $command = $this->getInstance($storageService);
+
+ $input = $this->getInput($command, [
+ 'mount_id' => 1
+ ], [
+ 'output' => 'json'
+ ]);
+
+ $result = json_decode($this->executeCommand($command, $input), true);
+
+ $this->assertEquals(['users' => ['test', 'asd'], 'groups' => []], $result);
+ }
+
+ public function testAddSingle() {
+ $mount = $this->getMount(1, '', '', '', [], [], []);
+
+ $storageService = $this->getGlobalStorageService([$mount]);
+ $command = $this->getInstance($storageService);
+
+ $input = $this->getInput($command, [
+ 'mount_id' => 1
+ ], [
+ 'output' => 'json',
+ 'add-user' => ['foo']
+ ]);
+
+ $this->executeCommand($command, $input);
+
+ $this->assertEquals(['foo'], $mount->getApplicableUsers());
+ }
+
+ public function testAddDuplicate() {
+ $mount = $this->getMount(1, '', '', '', [], [], ['foo']);
+
+ $storageService = $this->getGlobalStorageService([$mount]);
+ $command = $this->getInstance($storageService);
+
+ $input = $this->getInput($command, [
+ 'mount_id' => 1
+ ], [
+ 'output' => 'json',
+ 'add-user' => ['foo', 'bar']
+ ]);
+
+ $this->executeCommand($command, $input);
+
+ $this->assertEquals(['foo', 'bar'], $mount->getApplicableUsers());
+ }
+
+ public function testRemoveSingle() {
+ $mount = $this->getMount(1, '', '', '', [], [], ['foo', 'bar']);
+
+ $storageService = $this->getGlobalStorageService([$mount]);
+ $command = $this->getInstance($storageService);
+
+ $input = $this->getInput($command, [
+ 'mount_id' => 1
+ ], [
+ 'output' => 'json',
+ 'remove-user' => ['bar']
+ ]);
+
+ $this->executeCommand($command, $input);
+
+ $this->assertEquals(['foo'], $mount->getApplicableUsers());
+ }
+
+ public function testRemoveNonExisting() {
+ $mount = $this->getMount(1, '', '', '', [], [], ['foo', 'bar']);
+
+ $storageService = $this->getGlobalStorageService([$mount]);
+ $command = $this->getInstance($storageService);
+
+ $input = $this->getInput($command, [
+ 'mount_id' => 1
+ ], [
+ 'output' => 'json',
+ 'remove-user' => ['bar', 'asd']
+ ]);
+
+ $this->executeCommand($command, $input);
+
+ $this->assertEquals(['foo'], $mount->getApplicableUsers());
+ }
+
+ public function testRemoveAddRemove() {
+ $mount = $this->getMount(1, '', '', '', [], [], ['foo', 'bar']);
+
+ $storageService = $this->getGlobalStorageService([$mount]);
+ $command = $this->getInstance($storageService);
+
+ $input = $this->getInput($command, [
+ 'mount_id' => 1
+ ], [
+ 'output' => 'json',
+ 'remove-user' => ['bar', 'asd'],
+ 'add-user' => ['test']
+ ]);
+
+ $this->executeCommand($command, $input);
+
+ $this->assertEquals(['foo', 'test'], $mount->getApplicableUsers());
+ }
+}
diff --git a/apps/files_external/tests/command/commandtest.php b/apps/files_external/tests/command/commandtest.php
new file mode 100644
index 00000000000..9a0afbd3681
--- /dev/null
+++ b/apps/files_external/tests/command/commandtest.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Tests\Command;
+
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_external\NotFoundException;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\Input;
+use Symfony\Component\Console\Output\BufferedOutput;
+use Test\TestCase;
+
+abstract class CommandTest extends TestCase {
+ /**
+ * @param StorageConfig[] $mounts
+ * @return \OCA\Files_external\Service\GlobalStoragesService|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected function getGlobalStorageService(array $mounts = []) {
+ $mock = $this->getMockBuilder('OCA\Files_external\Service\GlobalStoragesService')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->bindMounts($mock, $mounts);
+
+ return $mock;
+ }
+
+ /**
+ * @param \PHPUnit_Framework_MockObject_MockObject $mock
+ * @param StorageConfig[] $mounts
+ */
+ protected function bindMounts(\PHPUnit_Framework_MockObject_MockObject $mock, array $mounts) {
+ $mock->expects($this->any())
+ ->method('getStorage')
+ ->will($this->returnCallback(function ($id) use ($mounts) {
+ foreach ($mounts as $mount) {
+ if ($mount->getId() === $id) {
+ return $mount;
+ }
+ }
+ throw new NotFoundException();
+ }));
+ }
+
+ /**
+ * @param $id
+ * @param $mountPoint
+ * @param $backendClass
+ * @param string $applicableIdentifier
+ * @param array $config
+ * @param array $options
+ * @param array $users
+ * @param array $groups
+ * @return StorageConfig
+ */
+ protected function getMount($id, $mountPoint, $backendClass, $applicableIdentifier = 'password::password', $config = [], $options = [], $users = [], $groups = []) {
+ $mount = new StorageConfig($id);
+
+ $mount->setMountPoint($mountPoint);
+ $mount->setBackendOptions($config);
+ $mount->setMountOptions($options);
+ $mount->setApplicableUsers($users);
+ $mount->setApplicableGroups($groups);
+
+ return $mount;
+ }
+
+ protected function getInput(Command $command, array $arguments = [], array $options = []) {
+ $input = new ArrayInput([]);
+ $input->bind($command->getDefinition());
+ foreach ($arguments as $key => $value) {
+ $input->setArgument($key, $value);
+ }
+ foreach ($options as $key => $value) {
+ $input->setOption($key, $value);
+ }
+ return $input;
+ }
+
+ protected function executeCommand(Command $command, Input $input) {
+ $output = new BufferedOutput();
+ $this->invokePrivate($command, 'execute', [$input, $output]);
+ return $output->fetch();
+ }
+}
diff --git a/apps/files_external/tests/config.php b/apps/files_external/tests/config.php
index 19dad215a36..9784de7db15 100644
--- a/apps/files_external/tests/config.php
+++ b/apps/files_external/tests/config.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/tests/controller/globalstoragescontrollertest.php b/apps/files_external/tests/controller/globalstoragescontrollertest.php
index 37b5fed1481..9256569f22a 100644
--- a/apps/files_external/tests/controller/globalstoragescontrollertest.php
+++ b/apps/files_external/tests/controller/globalstoragescontrollertest.php
@@ -1,9 +1,9 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -41,7 +41,8 @@ class GlobalStoragesControllerTest extends StoragesControllerTest {
'files_external',
$this->getMock('\OCP\IRequest'),
$this->getMock('\OCP\IL10N'),
- $this->service
+ $this->service,
+ $this->getMock('\OCP\ILogger')
);
}
}
diff --git a/apps/files_external/tests/controller/storagescontrollertest.php b/apps/files_external/tests/controller/storagescontrollertest.php
index 8a7acf81009..97fe3cf5176 100644
--- a/apps/files_external/tests/controller/storagescontrollertest.php
+++ b/apps/files_external/tests/controller/storagescontrollertest.php
@@ -1,9 +1,10 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -48,6 +49,9 @@ abstract class StoragesControllerTest extends \Test\TestCase {
\OC_Mount_Config::$skipTest = false;
}
+ /**
+ * @return \OCA\Files_External\Lib\Backend\Backend
+ */
protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') {
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
@@ -59,6 +63,9 @@ abstract class StoragesControllerTest extends \Test\TestCase {
return $backend;
}
+ /**
+ * @return \OCA\Files_External\Lib\Auth\AuthMechanism
+ */
protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') {
$authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
->disableOriginalConstructor()
diff --git a/apps/files_external/tests/controller/userstoragescontrollertest.php b/apps/files_external/tests/controller/userstoragescontrollertest.php
index acb25d11d09..342f6b85385 100644
--- a/apps/files_external/tests/controller/userstoragescontrollertest.php
+++ b/apps/files_external/tests/controller/userstoragescontrollertest.php
@@ -1,9 +1,9 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -48,7 +48,9 @@ class UserStoragesControllerTest extends StoragesControllerTest {
'files_external',
$this->getMock('\OCP\IRequest'),
$this->getMock('\OCP\IL10N'),
- $this->service
+ $this->service,
+ $this->getMock('\OCP\IUserSession'),
+ $this->getMock('\OCP\ILogger')
);
}
diff --git a/apps/files_external/tests/definitionparameterttest.php b/apps/files_external/tests/definitionparameterttest.php
index 3983a805dad..e89058d5c78 100644
--- a/apps/files_external/tests/definitionparameterttest.php
+++ b/apps/files_external/tests/definitionparameterttest.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,18 +27,34 @@ class DefinitionParameterTest extends \Test\TestCase {
public function testJsonSerialization() {
$param = new Param('foo', 'bar');
- $this->assertEquals('bar', $param->jsonSerialize());
+ $this->assertEquals([
+ 'value' => 'bar',
+ 'flags' => 0,
+ 'type' => 0
+ ], $param->jsonSerialize());
$param->setType(Param::VALUE_BOOLEAN);
- $this->assertEquals('!bar', $param->jsonSerialize());
+ $this->assertEquals([
+ 'value' => 'bar',
+ 'flags' => 0,
+ 'type' => Param::VALUE_BOOLEAN
+ ], $param->jsonSerialize());
$param->setType(Param::VALUE_PASSWORD);
$param->setFlag(Param::FLAG_OPTIONAL);
- $this->assertEquals('&*bar', $param->jsonSerialize());
+ $this->assertEquals([
+ 'value' => 'bar',
+ 'flags' => Param::FLAG_OPTIONAL,
+ 'type' => Param::VALUE_PASSWORD
+ ], $param->jsonSerialize());
$param->setType(Param::VALUE_HIDDEN);
$param->setFlags(Param::FLAG_NONE);
- $this->assertEquals('#bar', $param->jsonSerialize());
+ $this->assertEquals([
+ 'value' => 'bar',
+ 'flags' => Param::FLAG_NONE,
+ 'type' => Param::VALUE_HIDDEN
+ ], $param->jsonSerialize());
}
public function validateValueProvider() {
diff --git a/apps/files_external/tests/env/entrypoint.sh b/apps/files_external/tests/env/entrypoint.sh
new file mode 100755
index 00000000000..6dd6ef23fb6
--- /dev/null
+++ b/apps/files_external/tests/env/entrypoint.sh
@@ -0,0 +1,274 @@
+#!/bin/bash
+set -e
+
+: ${CLUSTER:=ceph}
+: ${RGW_NAME:=$(hostname -s)}
+: ${MON_NAME:=$(hostname -s)}
+: ${RGW_CIVETWEB_PORT:=80}
+: ${OSD_SIZE:=100}
+
+: ${KEYSTONE_ADMIN_TOKEN:=admin}
+: ${KEYSTONE_ADMIN_PORT:=35357}
+: ${KEYSTONE_PUBLIC_PORT:=5001}
+
+: ${KEYSTONE_SERVICE:=${CLUSTER}}
+: ${KEYSTONE_ENDPOINT_REGION:=region}
+
+: ${KEYSTONE_ADMIN_USER:=admin}
+: ${KEYSTONE_ADMIN_TENANT:=admin}
+: ${KEYSTONE_ADMIN_PASS:=admin}
+
+ip_address=$(head -n1 /etc/hosts | cut -d" " -f1)
+: ${MON_IP:=${ip_address}}
+subnet=$(ip route | grep "src ${ip_address}" | cut -d" " -f1)
+: ${CEPH_NETWORK:=${subnet}}
+
+#######
+# MON #
+#######
+
+if [ ! -n "$CEPH_NETWORK" ]; then
+ echo "ERROR- CEPH_NETWORK must be defined as the name of the network for the OSDs"
+ exit 1
+fi
+
+if [ ! -n "$MON_IP" ]; then
+ echo "ERROR- MON_IP must be defined as the IP address of the monitor"
+ exit 1
+fi
+
+# bootstrap MON
+if [ ! -e /etc/ceph/ceph.conf ]; then
+ fsid=$(uuidgen)
+ cat <<ENDHERE >/etc/ceph/${CLUSTER}.conf
+[global]
+fsid = $fsid
+mon initial members = ${MON_NAME}
+mon host = ${MON_IP}
+auth cluster required = cephx
+auth service required = cephx
+auth client required = cephx
+osd crush chooseleaf type = 0
+osd journal size = 100
+osd pool default pg num = 8
+osd pool default pgp num = 8
+osd pool default size = 1
+public network = ${CEPH_NETWORK}
+cluster network = ${CEPH_NETWORK}
+debug ms = 1
+
+[mon]
+debug mon = 20
+debug paxos = 20
+debug auth = 20
+
+[osd]
+debug osd = 20
+debug filestore = 20
+debug journal = 20
+debug monc = 20
+
+[mds]
+debug mds = 20
+debug mds balancer = 20
+debug mds log = 20
+debug mds migrator = 20
+
+[client.radosgw.gateway]
+rgw keystone url = http://${MON_IP}:${KEYSTONE_ADMIN_PORT}
+rgw keystone admin token = ${KEYSTONE_ADMIN_TOKEN}
+rgw keystone accepted roles = _member_
+ENDHERE
+
+ # Generate administrator key
+ ceph-authtool /etc/ceph/${CLUSTER}.client.admin.keyring --create-keyring --gen-key -n client.admin --set-uid=0 --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow'
+
+ # Generate the mon. key
+ ceph-authtool /etc/ceph/${CLUSTER}.mon.keyring --create-keyring --gen-key -n mon. --cap mon 'allow *'
+
+ # Generate initial monitor map
+ monmaptool --create --add ${MON_NAME} ${MON_IP} --fsid ${fsid} /etc/ceph/monmap
+fi
+
+# If we don't have a monitor keyring, this is a new monitor
+if [ ! -e /var/lib/ceph/mon/${CLUSTER}-${MON_NAME}/keyring ]; then
+
+ if [ ! -e /etc/ceph/${CLUSTER}.client.admin.keyring ]; then
+ echo "ERROR- /etc/ceph/${CLUSTER}.client.admin.keyring must exist; get it from your existing mon"
+ exit 2
+ fi
+
+ if [ ! -e /etc/ceph/${CLUSTER}.mon.keyring ]; then
+ echo "ERROR- /etc/ceph/${CLUSTER}.mon.keyring must exist. You can extract it from your current monitor by running 'ceph auth get mon. -o /tmp/${CLUSTER}.mon.keyring'"
+ exit 3
+ fi
+
+ if [ ! -e /etc/ceph/monmap ]; then
+ echo "ERROR- /etc/ceph/monmap must exist. You can extract it from your current monitor by running 'ceph mon getmap -o /tmp/monmap'"
+ exit 4
+ fi
+
+ # Import the client.admin keyring and the monitor keyring into a new, temporary one
+ ceph-authtool /tmp/${CLUSTER}.mon.keyring --create-keyring --import-keyring /etc/ceph/${CLUSTER}.client.admin.keyring
+ ceph-authtool /tmp/${CLUSTER}.mon.keyring --import-keyring /etc/ceph/${CLUSTER}.mon.keyring
+
+ # Make the monitor directory
+ mkdir -p /var/lib/ceph/mon/${CLUSTER}-${MON_NAME}
+
+ # Prepare the monitor daemon's directory with the map and keyring
+ ceph-mon --mkfs -i ${MON_NAME} --monmap /etc/ceph/monmap --keyring /tmp/${CLUSTER}.mon.keyring
+
+ # Clean up the temporary key
+ rm /tmp/${CLUSTER}.mon.keyring
+fi
+
+# start MON
+ceph-mon -i ${MON_NAME} --public-addr ${MON_IP}:6789
+
+# change replica size
+ceph osd pool set rbd size 1
+
+
+#######
+# OSD #
+#######
+
+if [ ! -e /var/lib/ceph/osd/${CLUSTER}-0/keyring ]; then
+ # bootstrap OSD
+ mkdir -p /var/lib/ceph/osd/${CLUSTER}-0
+ # skip btrfs HACK if btrfs is already in place
+ if [ "$(stat -f /var/lib/ceph/osd/${CLUSTER}-0 2>/dev/null | grep btrfs | wc -l)" == "0" ]; then
+ # HACK create btrfs loopback device
+ echo "creating osd storage image"
+ dd if=/dev/zero of=/tmp/osddata bs=1M count=${OSD_SIZE}
+ mkfs.btrfs /tmp/osddata
+ echo "mounting via loopback"
+ mount -o loop /tmp/osddata /var/lib/ceph/osd/${CLUSTER}-0
+ echo "now mounted:"
+ mount
+ # end HACK
+ fi
+ echo "creating osd"
+ ceph osd create
+ echo "creating osd filesystem"
+ ceph-osd -i 0 --mkfs
+ echo "creating osd keyring"
+ ceph auth get-or-create osd.0 osd 'allow *' mon 'allow profile osd' -o /var/lib/ceph/osd/${CLUSTER}-0/keyring
+ echo "configuring osd crush"
+ ceph osd crush add 0 1 root=default host=$(hostname -s)
+ echo "adding osd keyring"
+ ceph-osd -i 0 -k /var/lib/ceph/osd/${CLUSTER}-0/keyring
+fi
+
+# start OSD
+echo "starting osd"
+ceph-osd --cluster=${CLUSTER} -i 0
+
+#sleep 10
+
+#######
+# MDS #
+#######
+
+if [ ! -e /var/lib/ceph/mds/${CLUSTER}-0/keyring ]; then
+ # create ceph filesystem
+ echo "creating osd pool"
+ ceph osd pool create cephfs_data 8
+ echo "creating osd pool metadata"
+ ceph osd pool create cephfs_metadata 8
+ echo "creating cephfs"
+ ceph fs new cephfs cephfs_metadata cephfs_data
+
+ # bootstrap MDS
+ mkdir -p /var/lib/ceph/mds/${CLUSTER}-0
+ echo "creating mds auth"
+ ceph auth get-or-create mds.0 mds 'allow' osd 'allow *' mon 'allow profile mds' > /var/lib/ceph/mds/${CLUSTER}-0/keyring
+fi
+
+# start MDS
+echo "starting mds"
+ceph-mds --cluster=${CLUSTER} -i 0
+
+#sleep 10
+
+
+#######
+# RGW #
+#######
+
+if [ ! -e /var/lib/ceph/radosgw/${RGW_NAME}/keyring ]; then
+ # bootstrap RGW
+ mkdir -p /var/lib/ceph/radosgw/${RGW_NAME}
+ echo "creating rgw auth"
+ ceph auth get-or-create client.radosgw.gateway osd 'allow rwx' mon 'allow rw' -o /var/lib/ceph/radosgw/${RGW_NAME}/keyring
+fi
+
+# start RGW
+echo "starting rgw"
+radosgw -c /etc/ceph/ceph.conf -n client.radosgw.gateway -k /var/lib/ceph/radosgw/${RGW_NAME}/keyring --rgw-socket-path="" --rgw-frontends="civetweb port=${RGW_CIVETWEB_PORT}"
+
+
+#######
+# API #
+#######
+
+# start ceph-rest-api
+echo "starting rest api"
+ceph-rest-api -n client.admin &
+
+############
+# Keystone #
+############
+
+if [ ! -e /etc/keystone/${CLUSTER}.conf ]; then
+ cat <<ENDHERE > /etc/keystone/${CLUSTER}.conf
+[DEFAULT]
+admin_token=${KEYSTONE_ADMIN_TOKEN}
+admin_port=${KEYSTONE_ADMIN_PORT}
+public_port=${KEYSTONE_PUBLIC_PORT}
+
+[database]
+connection = sqlite:////var/lib/keystone/keystone.db
+ENDHERE
+
+ # start Keystone
+ echo "starting keystone"
+ keystone-all --config-file /etc/keystone/${CLUSTER}.conf &
+
+ # wait until up
+ while ! nc ${MON_IP} ${KEYSTONE_ADMIN_PORT} </dev/null; do
+ sleep 1
+ done
+
+ export OS_SERVICE_TOKEN=${KEYSTONE_ADMIN_TOKEN}
+ export OS_SERVICE_ENDPOINT=http://${MON_IP}:${KEYSTONE_ADMIN_PORT}/v2.0
+
+ echo "creating keystone service ${KEYSTONE_SERVICE}"
+ keystone service-create --name ${KEYSTONE_SERVICE} --type object-store
+ echo "creating keystone endpoint ${KEYSTONE_SERVICE}"
+ keystone endpoint-create --service ${KEYSTONE_SERVICE} \
+ --region ${KEYSTONE_ENDPOINT_REGION} \
+ --publicurl http://${MON_IP}:${RGW_CIVETWEB_PORT}/swift/v1 \
+ --internalurl http://${MON_IP}:${RGW_CIVETWEB_PORT}/swift/v1 \
+ --adminurl http://${MON_IP}:${RGW_CIVETWEB_PORT}/swift/v1
+
+ echo "creating keystone user ${KEYSTONE_ADMIN_USER}"
+ keystone user-create --name=${KEYSTONE_ADMIN_USER} --pass=${KEYSTONE_ADMIN_PASS} --email=dev@null.com
+ echo "creating keystone tenant ${KEYSTONE_ADMIN_TENANT}"
+ keystone tenant-create --name=${KEYSTONE_ADMIN_TENANT} --description=admin
+ echo "adding keystone role _member_"
+ keystone user-role-add --user=${KEYSTONE_ADMIN_USER} --tenant=${KEYSTONE_ADMIN_TENANT} --role=_member_
+
+ echo "creating keystone role admin"
+ keystone role-create --name=admin
+ echo "adding keystone role admin"
+ keystone user-role-add --user=${KEYSTONE_ADMIN_USER} --tenant=${KEYSTONE_ADMIN_TENANT} --role=admin
+fi
+
+
+#########
+# WATCH #
+#########
+
+echo "watching ceph"
+exec ceph -w
diff --git a/apps/files_external/tests/env/start-amazons3-ceph.sh b/apps/files_external/tests/env/start-amazons3-ceph.sh
index 3b4a15da92a..20fa7e7bb2b 100755
--- a/apps/files_external/tests/env/start-amazons3-ceph.sh
+++ b/apps/files_external/tests/env/start-amazons3-ceph.sh
@@ -49,9 +49,12 @@ echo "${docker_image} container: $container"
# put container IDs into a file to drop them after the test run (keep in mind that multiple tests run in parallel on the same host)
echo $container >> $thisFolder/dockerContainerCeph.$EXECUTOR_NUMBER.amazons3
-# TODO find a way to determine the successful initialization inside the docker container
-echo "Waiting 20 seconds for ceph initialization ... "
-sleep 20
+echo -n "Waiting for ceph initialization"
+if ! "$thisFolder"/env/wait-for-connection ${host} ${port} 60; then
+ echo "[ERROR] Waited 60 seconds, no response" >&2
+ exit 1
+fi
+sleep 1
echo "Create ceph user"
docker exec $container radosgw-admin user create \
diff --git a/apps/files_external/tests/env/start-ftp-morrisjobke.sh b/apps/files_external/tests/env/start-ftp-morrisjobke.sh
index f1ab7f69952..3a5f6ffcb67 100755
--- a/apps/files_external/tests/env/start-ftp-morrisjobke.sh
+++ b/apps/files_external/tests/env/start-ftp-morrisjobke.sh
@@ -54,12 +54,16 @@ echo "ftp container: $container"
# put container IDs into a file to drop them after the test run (keep in mind that multiple tests run in parallel on the same host)
echo $container >> $thisFolder/dockerContainerMorrisJobke.$EXECUTOR_NUMBER.ftp
+echo -n "Waiting for ftp initialization"
+if ! "$thisFolder"/env/wait-for-connection ${host} 21 60; then
+ echo "[ERROR] Waited 60 seconds, no response" >&2
+ exit 1
+fi
+sleep 1
+
if [ -n "$DEBUG" ]; then
cat $thisFolder/config.ftp.php
cat $thisFolder/dockerContainerMorrisJobke.$EXECUTOR_NUMBER.ftp
fi
-# TODO find a way to determine the successful initialization inside the docker container
-echo "Waiting 5 seconds for ftp initialization ... "
-sleep 5
diff --git a/apps/files_external/tests/env/start-sftp-atmoz.sh b/apps/files_external/tests/env/start-sftp-atmoz.sh
index bebc7289250..0fc0c5c427f 100755
--- a/apps/files_external/tests/env/start-sftp-atmoz.sh
+++ b/apps/files_external/tests/env/start-sftp-atmoz.sh
@@ -54,15 +54,18 @@ echo "sftp container: $container"
# put container IDs into a file to drop them after the test run (keep in mind that multiple tests run in parallel on the same host)
echo $container >> $thisFolder/dockerContainerAtmoz.$EXECUTOR_NUMBER.sftp
+echo -n "Waiting for sftp initialization"
+if ! "$thisFolder"/env/wait-for-connection ${host} 22 60; then
+ echo "[ERROR] Waited 60 seconds, no response" >&2
+ exit 1
+fi
+sleep 1
+
if [ -n "$DEBUG" ]; then
cat $thisFolder/config.sftp.php
cat $thisFolder/dockerContainerAtmoz.$EXECUTOR_NUMBER.sftp
fi
-# TODO find a way to determine the successful initialization inside the docker container
-echo "Waiting 5 seconds for sftp initialization ... "
-sleep 5
-
# create folder "upload" with correct permissions
docker exec $container bash -c "mkdir /home/$user/upload && chown $user:users /home/$user/upload"
diff --git a/apps/files_external/tests/env/start-smb-silvershell.sh b/apps/files_external/tests/env/start-smb-silvershell.sh
index 41ba3b11a70..a7ff3f71eb1 100755
--- a/apps/files_external/tests/env/start-smb-silvershell.sh
+++ b/apps/files_external/tests/env/start-smb-silvershell.sh
@@ -52,12 +52,16 @@ echo "samba container: $container"
# put container IDs into a file to drop them after the test run (keep in mind that multiple tests run in parallel on the same host)
echo $container >> $thisFolder/dockerContainerSilvershell.$EXECUTOR_NUMBER.smb
+echo -n "Waiting for samba initialization"
+if ! "$thisFolder"/env/wait-for-connection ${host} 445 60; then
+ echo "[ERROR] Waited 60 seconds, no response" >&2
+ exit 1
+fi
+sleep 1
+
if [ -n "$DEBUG" ]; then
cat $thisFolder/config.smb.php
cat $thisFolder/dockerContainerSilvershell.$EXECUTOR_NUMBER.smb
fi
-# TODO find a way to determine the successful initialization inside the docker container
-echo "Waiting 5 seconds for smbd initialization ... "
-sleep 5
diff --git a/apps/files_external/tests/env/start-smb-windows.sh b/apps/files_external/tests/env/start-smb-windows.sh
index 2143d7e7499..a23c879dd96 100755
--- a/apps/files_external/tests/env/start-smb-windows.sh
+++ b/apps/files_external/tests/env/start-smb-windows.sh
@@ -19,6 +19,11 @@ user=smb-test
password=!owncloud123
host=WIN-9GTFAS08C15
+if ! "$thisFolder"/env/wait-for-connection ${host} 445; then
+ echo "[ERROR] Server not reachable" >&2
+ exit 1
+fi
+
cat > $thisFolder/config.smb.php <<DELIM
<?php
diff --git a/apps/files_external/tests/env/start-swift-ceph.sh b/apps/files_external/tests/env/start-swift-ceph.sh
new file mode 100755
index 00000000000..f3707aa39f6
--- /dev/null
+++ b/apps/files_external/tests/env/start-swift-ceph.sh
@@ -0,0 +1,90 @@
+#!/bin/bash
+#
+# ownCloud
+#
+# This script start a docker container to test the files_external tests
+# against. It will also change the files_external config to use the docker
+# container as testing environment. This is reverted in the stop step.W
+#
+# Set environment variable DEBUG to print config file
+#
+# @author Morris Jobke
+# @author Robin McCorkell
+# @copyright 2015 ownCloud
+
+if ! command -v docker >/dev/null 2>&1; then
+ echo "No docker executable found - skipped docker setup"
+ exit 0;
+fi
+
+echo "Docker executable found - setup docker"
+
+docker_image=xenopathic/ceph-keystone
+
+echo "Fetch recent ${docker_image} docker image"
+docker pull ${docker_image}
+
+# retrieve current folder to place the config in the parent folder
+thisFolder=`echo $0 | sed 's#env/start-swift-ceph\.sh##'`
+
+if [ -z "$thisFolder" ]; then
+ thisFolder="."
+fi;
+
+port=5001
+
+user=test
+pass=testing
+tenant=testenant
+region=testregion
+service=testceph
+endpointFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+container=`docker run -d \
+ -e KEYSTONE_PUBLIC_PORT=${port} \
+ -e KEYSTONE_ADMIN_USER=${user} \
+ -e KEYSTONE_ADMIN_PASS=${pass} \
+ -e KEYSTONE_ADMIN_TENANT=${tenant} \
+ -e KEYSTONE_ENDPOINT_REGION=${region} \
+ -e KEYSTONE_SERVICE=${service} \
+ -e OSD_SIZE=300 \
+ -v ${endpointFolder}/entrypoint.sh:/entrypoint.sh \
+ --privileged \
+ --entrypoint /entrypoint.sh ${docker_image}`
+
+host=`docker inspect --format="{{.NetworkSettings.IPAddress}}" $container`
+
+
+echo "${docker_image} container: $container"
+
+# put container IDs into a file to drop them after the test run (keep in mind that multiple tests run in parallel on the same host)
+echo $container >> $thisFolder/dockerContainerCeph.$EXECUTOR_NUMBER.swift
+
+echo -n "Waiting for ceph initialization"
+if ! "$thisFolder"/env/wait-for-connection ${host} 80 600; then
+ echo "[ERROR] Waited 600 seconds, no response" >&2
+ docker logs $container
+ exit 1
+fi
+sleep 1
+
+cat > $thisFolder/config.swift.php <<DELIM
+<?php
+
+return array(
+ 'run'=>true,
+ 'url'=>'http://$host:$port/v2.0',
+ 'user'=>'$user',
+ 'tenant'=>'$tenant',
+ 'password'=>'$pass',
+ 'service_name'=>'$service',
+ 'bucket'=>'swift',
+ 'region' => '$region',
+);
+
+DELIM
+
+if [ -n "$DEBUG" ]; then
+ cat $thisFolder/config.swift.php
+ cat $thisFolder/dockerContainerCeph.$EXECUTOR_NUMBER.swift
+fi
diff --git a/apps/files_external/tests/env/start-webdav-ownCloud.sh b/apps/files_external/tests/env/start-webdav-ownCloud.sh
index 6bf9142ee53..d992516d7b1 100755
--- a/apps/files_external/tests/env/start-webdav-ownCloud.sh
+++ b/apps/files_external/tests/env/start-webdav-ownCloud.sh
@@ -46,20 +46,23 @@ fi
container=`docker run -P $parameter -d -e ADMINLOGIN=test -e ADMINPWD=test morrisjobke/owncloud`
-# TODO find a way to determine the successful initialization inside the docker container
-echo "Waiting 30 seconds for ownCloud initialization ... "
-sleep 30
+host=`docker inspect --format="{{.NetworkSettings.IPAddress}}" $container`
-# get mapped port on host for internal port 80 - output is IP:PORT - we need to extract the port with 'cut'
-port=`docker port $container 80 | cut -f 2 -d :`
+echo -n "Waiting for ownCloud initialization"
+if ! "$thisFolder"/env/wait-for-connection ${host} 80 60; then
+ echo "[ERROR] Waited 60 seconds, no response" >&2
+ exit 1
+fi
+# wait at least 5 more seconds - sometimes the webserver still needs some additional time
+sleep 5
cat > $thisFolder/config.webdav.php <<DELIM
<?php
return array(
'run'=>true,
- 'host'=>'localhost:$port/owncloud/remote.php/webdav/',
+ 'host'=>'${host}:80/owncloud/remote.php/webdav/',
'user'=>'test',
'password'=>'test',
'root'=>'',
diff --git a/apps/files_external/tests/env/stop-swift-ceph.sh b/apps/files_external/tests/env/stop-swift-ceph.sh
new file mode 100755
index 00000000000..edac1389a78
--- /dev/null
+++ b/apps/files_external/tests/env/stop-swift-ceph.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# ownCloud
+#
+# This script stops the docker container the files_external tests were run
+# against. It will also revert the config changes done in start step.
+#
+# @author Morris Jobke
+# @author Robin McCorkell
+# @copyright 2015 ownCloud
+
+if ! command -v docker >/dev/null 2>&1; then
+ echo "No docker executable found - skipped docker stop"
+ exit 0;
+fi
+
+echo "Docker executable found - stop and remove docker containers"
+
+# retrieve current folder to remove the config from the parent folder
+thisFolder=`echo $0 | replace "env/stop-swift-ceph.sh" ""`
+
+if [ -z "$thisFolder" ]; then
+ thisFolder="."
+fi;
+
+# stopping and removing docker containers
+for container in `cat $thisFolder/dockerContainerCeph.$EXECUTOR_NUMBER.swift`; do
+ echo "Stopping and removing docker container $container"
+ # kills running container and removes it
+ docker rm -f $container
+done;
+
+# cleanup
+rm $thisFolder/config.swift.php
+rm $thisFolder/dockerContainerCeph.$EXECUTOR_NUMBER.swift
+
diff --git a/apps/files_external/tests/env/wait-for-connection b/apps/files_external/tests/env/wait-for-connection
new file mode 100755
index 00000000000..2c480fb733e
--- /dev/null
+++ b/apps/files_external/tests/env/wait-for-connection
@@ -0,0 +1,45 @@
+#!/usr/bin/php
+<?php
+
+$timeout = 60;
+
+switch ($argc) {
+case 4:
+ $timeout = (float)$argv[3];
+case 3:
+ $host = $argv[1];
+ $port = (int)$argv[2];
+ break;
+default:
+ fwrite(STDERR, 'Usage: '.$argv[0].' host port [timeout]'."\n");
+ exit(2);
+}
+
+if ($timeout < 0) {
+ fwrite(STDERR, 'Timeout must be greater than zero'."\n");
+ exit(2);
+}
+if ($port < 1) {
+ fwrite(STDERR, 'Port must be an integer greater than zero'."\n");
+ exit(2);
+}
+
+$socketTimeout = (float)ini_get('default_socket_timeout');
+if ($socketTimeout > $timeout) {
+ $socketTimeout = $timeout;
+}
+
+$stopTime = time() + $timeout;
+do {
+ $sock = @fsockopen($host, $port, $errno, $errstr, $socketTimeout);
+ if ($sock !== false) {
+ fclose($sock);
+ fwrite(STDOUT, "\n");
+ exit(0);
+ }
+ sleep(1);
+ fwrite(STDOUT, '.');
+} while (time() < $stopTime);
+
+fwrite(STDOUT, "\n");
+exit(1);
diff --git a/apps/files_external/tests/etagpropagator.php b/apps/files_external/tests/etagpropagator.php
deleted file mode 100644
index d45982cb40c..00000000000
--- a/apps/files_external/tests/etagpropagator.php
+++ /dev/null
@@ -1,343 +0,0 @@
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace Tests\Files_External;
-
-use OC\Files\Filesystem;
-use OC\User\User;
-
-class EtagPropagator extends \Test\TestCase {
- protected function getUser() {
- return new User($this->getUniqueID(), null);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Cache\ChangePropagator
- */
- protected function getChangePropagator() {
- return $this->getMockBuilder('\OC\Files\Cache\ChangePropagator')
- ->disableOriginalConstructor()
- ->getMock();
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject | \OCP\IConfig
- */
- protected function getConfig() {
- $appConfig = array();
- $userConfig = array();
- $mock = $this->getMockBuilder('\OCP\IConfig')
- ->disableOriginalConstructor()
- ->getMock();
-
- $mock->expects($this->any())
- ->method('getAppValue')
- ->will($this->returnCallback(function ($appId, $key, $default = null) use (&$appConfig) {
- if (isset($appConfig[$appId]) and isset($appConfig[$appId][$key])) {
- return $appConfig[$appId][$key];
- } else {
- return $default;
- }
- }));
- $mock->expects($this->any())
- ->method('setAppValue')
- ->will($this->returnCallback(function ($appId, $key, $value) use (&$appConfig) {
- if (!isset($appConfig[$appId])) {
- $appConfig[$appId] = array();
- }
- $appConfig[$appId][$key] = $value;
- }));
- $mock->expects($this->any())
- ->method('getAppKeys')
- ->will($this->returnCallback(function ($appId) use (&$appConfig) {
- if (!isset($appConfig[$appId])) {
- $appConfig[$appId] = array();
- }
- return array_keys($appConfig[$appId]);
- }));
-
- $mock->expects($this->any())
- ->method('getUserValue')
- ->will($this->returnCallback(function ($userId, $appId, $key, $default = null) use (&$userConfig) {
- if (isset($userConfig[$userId]) and isset($userConfig[$userId][$appId]) and isset($userConfig[$userId][$appId][$key])) {
- return $userConfig[$userId][$appId][$key];
- } else {
- return $default;
- }
- }));
- $mock->expects($this->any())
- ->method('setUserValue')
- ->will($this->returnCallback(function ($userId, $appId, $key, $value) use (&$userConfig) {
- if (!isset($userConfig[$userId])) {
- $userConfig[$userId] = array();
- }
- if (!isset($userConfig[$userId][$appId])) {
- $userConfig[$userId][$appId] = array();
- }
- $userConfig[$userId][$appId][$key] = $value;
- }));
-
- return $mock;
- }
-
- public function testSingleUserMount() {
- $time = time();
- $user = $this->getUser();
- $config = $this->getConfig();
- $changePropagator = $this->getChangePropagator();
- $propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
-
- $changePropagator->expects($this->once())
- ->method('addChange')
- ->with('/test');
- $changePropagator->expects($this->once())
- ->method('propagateChanges')
- ->with($time);
-
- $propagator->updateHook(array(
- Filesystem::signal_param_path => '/test',
- Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_USER,
- Filesystem::signal_param_users => $user->getUID(),
- ), $time);
- }
-
- public function testGlobalMountNoDirectUpdate() {
- $time = time();
- $user = $this->getUser();
- $config = $this->getConfig();
- $changePropagator = $this->getChangePropagator();
- $propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
-
- // not updated directly
- $changePropagator->expects($this->never())
- ->method('addChange');
- $changePropagator->expects($this->never())
- ->method('propagateChanges');
-
- $propagator->updateHook(array(
- Filesystem::signal_param_path => '/test',
- Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_USER,
- Filesystem::signal_param_users => 'all',
- ), $time);
-
- // mount point marked as dirty
- $this->assertEquals(array('/test'), $config->getAppKeys('files_external'));
- $this->assertEquals($time, $config->getAppValue('files_external', '/test'));
- }
-
- public function testGroupMountNoDirectUpdate() {
- $time = time();
- $user = $this->getUser();
- $config = $this->getConfig();
- $changePropagator = $this->getChangePropagator();
- $propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
-
- // not updated directly
- $changePropagator->expects($this->never())
- ->method('addChange');
- $changePropagator->expects($this->never())
- ->method('propagateChanges');
-
- $propagator->updateHook(array(
- Filesystem::signal_param_path => '/test',
- Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_GROUP,
- Filesystem::signal_param_users => 'test',
- ), $time);
-
- // mount point marked as dirty
- $this->assertEquals(array('/test'), $config->getAppKeys('files_external'));
- $this->assertEquals($time, $config->getAppValue('files_external', '/test'));
- }
-
- public function testGlobalMountNoDirtyMountPoint() {
- $time = time();
- $user = $this->getUser();
- $config = $this->getConfig();
- $changePropagator = $this->getChangePropagator();
- $propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
-
- $changePropagator->expects($this->never())
- ->method('addChange');
- $changePropagator->expects($this->never())
- ->method('propagateChanges');
-
- $propagator->propagateDirtyMountPoints($time);
-
- $this->assertEquals(0, $config->getUserValue($user->getUID(), 'files_external', '/test', 0));
- }
-
- public function testGlobalMountDirtyMountPointFirstTime() {
- $time = time();
- $user = $this->getUser();
- $config = $this->getConfig();
- $changePropagator = $this->getChangePropagator();
- $propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
-
- $config->setAppValue('files_external', '/test', $time - 10);
-
- $changePropagator->expects($this->once())
- ->method('addChange')
- ->with('/test');
- $changePropagator->expects($this->once())
- ->method('propagateChanges')
- ->with($time);
-
- $propagator->propagateDirtyMountPoints($time);
-
- $this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
- }
-
- public function testGlobalMountNonDirtyMountPoint() {
- $time = time();
- $user = $this->getUser();
- $config = $this->getConfig();
- $changePropagator = $this->getChangePropagator();
- $propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
-
- $config->setAppValue('files_external', '/test', $time - 10);
- $config->setUserValue($user->getUID(), 'files_external', '/test', $time - 10);
-
- $changePropagator->expects($this->never())
- ->method('addChange');
- $changePropagator->expects($this->never())
- ->method('propagateChanges');
-
- $propagator->propagateDirtyMountPoints($time);
-
- $this->assertEquals($time - 10, $config->getUserValue($user->getUID(), 'files_external', '/test'));
- }
-
- public function testGlobalMountNonDirtyMountPointOtherUser() {
- $time = time();
- $user = $this->getUser();
- $user2 = $this->getUser();
- $config = $this->getConfig();
- $changePropagator = $this->getChangePropagator();
- $propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
-
- $config->setAppValue('files_external', '/test', $time - 10);
- $config->setUserValue($user2->getUID(), 'files_external', '/test', $time - 10);
-
- $changePropagator->expects($this->once())
- ->method('addChange')
- ->with('/test');
- $changePropagator->expects($this->once())
- ->method('propagateChanges')
- ->with($time);
-
- $propagator->propagateDirtyMountPoints($time);
-
- $this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
- }
-
- public function testGlobalMountDirtyMountPointSecondTime() {
- $time = time();
- $user = $this->getUser();
- $config = $this->getConfig();
- $changePropagator = $this->getChangePropagator();
- $propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
-
- $config->setAppValue('files_external', '/test', $time - 10);
- $config->setUserValue($user->getUID(), 'files_external', '/test', $time - 20);
-
- $changePropagator->expects($this->once())
- ->method('addChange')
- ->with('/test');
- $changePropagator->expects($this->once())
- ->method('propagateChanges')
- ->with($time);
-
- $propagator->propagateDirtyMountPoints($time);
-
- $this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
- }
-
- public function testGlobalMountMultipleUsers() {
- $time = time();
- $config = $this->getConfig();
- $user1 = $this->getUser();
- $user2 = $this->getUser();
- $user3 = $this->getUser();
- $changePropagator1 = $this->getChangePropagator();
- $changePropagator2 = $this->getChangePropagator();
- $changePropagator3 = $this->getChangePropagator();
- $propagator1 = new \OCA\Files_External\EtagPropagator($user1, $changePropagator1, $config);
- $propagator2 = new \OCA\Files_External\EtagPropagator($user2, $changePropagator2, $config);
- $propagator3 = new \OCA\Files_External\EtagPropagator($user3, $changePropagator3, $config);
-
- $config->setAppValue('files_external', '/test', $time - 10);
-
- $changePropagator1->expects($this->once())
- ->method('addChange')
- ->with('/test');
- $changePropagator1->expects($this->once())
- ->method('propagateChanges')
- ->with($time);
-
- $propagator1->propagateDirtyMountPoints($time);
-
- $this->assertEquals($time, $config->getUserValue($user1->getUID(), 'files_external', '/test'));
- $this->assertEquals(0, $config->getUserValue($user2->getUID(), 'files_external', '/test', 0));
- $this->assertEquals(0, $config->getUserValue($user3->getUID(), 'files_external', '/test', 0));
-
- $changePropagator2->expects($this->once())
- ->method('addChange')
- ->with('/test');
- $changePropagator2->expects($this->once())
- ->method('propagateChanges')
- ->with($time);
-
- $propagator2->propagateDirtyMountPoints($time);
-
- $this->assertEquals($time, $config->getUserValue($user1->getUID(), 'files_external', '/test'));
- $this->assertEquals($time, $config->getUserValue($user2->getUID(), 'files_external', '/test', 0));
- $this->assertEquals(0, $config->getUserValue($user3->getUID(), 'files_external', '/test', 0));
- }
-
- public function testGlobalMountMultipleDirtyMountPoints() {
- $time = time();
- $user = $this->getUser();
- $config = $this->getConfig();
- $changePropagator = $this->getChangePropagator();
- $propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
-
- $config->setAppValue('files_external', '/test', $time - 10);
- $config->setAppValue('files_external', '/foo', $time - 50);
- $config->setAppValue('files_external', '/bar', $time - 70);
-
- $config->setUserValue($user->getUID(), 'files_external', '/foo', $time - 70);
- $config->setUserValue($user->getUID(), 'files_external', '/bar', $time - 70);
-
- $changePropagator->expects($this->exactly(2))
- ->method('addChange');
- $changePropagator->expects($this->once())
- ->method('propagateChanges')
- ->with($time);
-
- $propagator->propagateDirtyMountPoints($time);
-
- $this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
- $this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/foo'));
- $this->assertEquals($time - 70, $config->getUserValue($user->getUID(), 'files_external', '/bar'));
- }
-}
diff --git a/apps/files_external/tests/frontenddefinitiontraittest.php b/apps/files_external/tests/frontenddefinitiontraittest.php
index d446813fe92..27f49556330 100644
--- a/apps/files_external/tests/frontenddefinitiontraittest.php
+++ b/apps/files_external/tests/frontenddefinitiontraittest.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -61,6 +61,8 @@ class FrontendDefinitionTraitTest extends \Test\TestCase {
->getMock();
$param->method('getName')
->willReturn($name);
+ $param->method('isOptional')
+ ->willReturn(false);
$param->expects($this->once())
->method('validateValue')
->willReturn($valid);
diff --git a/apps/files_external/tests/js/settingsSpec.js b/apps/files_external/tests/js/settingsSpec.js
index 67a81277124..6f5bb2a8e3e 100644
--- a/apps/files_external/tests/js/settingsSpec.js
+++ b/apps/files_external/tests/js/settingsSpec.js
@@ -37,6 +37,7 @@ describe('OCA.External.Settings tests', function() {
'<option disable selected>Add storage</option>' +
'<option value="\\OC\\TestBackend">Test Backend</option>' +
'<option value="\\OC\\AnotherTestBackend">Another Test Backend</option>' +
+ '<option value="\\OC\\InputsTestBackend">Inputs test backend</option>' +
'</select>' +
'</td>' +
'<td class="authentication"></td>' +
@@ -54,10 +55,16 @@ describe('OCA.External.Settings tests', function() {
// within the DOM by the server template
$('#externalStorage .selectBackend:first').data('configurations', {
'\\OC\\TestBackend': {
- 'backend': 'Test Backend Name',
+ 'identifier': '\\OC\\TestBackend',
+ 'name': 'Test Backend',
'configuration': {
- 'field1': 'Display Name 1',
- 'field2': '&Display Name 2'
+ 'field1': {
+ 'value': 'Display Name 1'
+ },
+ 'field2': {
+ 'value': 'Display Name 2',
+ 'flags': 1
+ }
},
'authSchemes': {
'builtin': true,
@@ -65,25 +72,67 @@ describe('OCA.External.Settings tests', function() {
'priority': 11
},
'\\OC\\AnotherTestBackend': {
- 'backend': 'Another Test Backend Name',
+ 'identifier': '\\OC\\AnotherTestBackend',
+ 'name': 'Another Test Backend',
'configuration': {
- 'field1': 'Display Name 1',
- 'field2': '&Display Name 2'
+ 'field1': {
+ 'value': 'Display Name 1'
+ },
+ 'field2': {
+ 'value': 'Display Name 2',
+ 'flags': 1
+ }
},
'authSchemes': {
'builtin': true,
},
'priority': 12
+ },
+ '\\OC\\InputsTestBackend': {
+ 'identifier': '\\OC\\InputsTestBackend',
+ 'name': 'Inputs test backend',
+ 'configuration': {
+ 'field_text': {
+ 'value': 'Text field'
+ },
+ 'field_password': {
+ 'value': ',Password field',
+ 'type': 2
+ },
+ 'field_bool': {
+ 'value': 'Boolean field',
+ 'type': 1
+ },
+ 'field_hidden': {
+ 'value': 'Hidden field',
+ 'type': 3
+ },
+ 'field_text_optional': {
+ 'value': 'Text field optional',
+ 'flags': 1
+ },
+ 'field_password_optional': {
+ 'value': 'Password field optional',
+ 'flags': 1,
+ 'type': 2
+ }
+ },
+ 'authSchemes': {
+ 'builtin': true,
+ },
+ 'priority': 13
}
}
);
$('#externalStorage #addMountPoint .authentication:first').data('mechanisms', {
'mechanism1': {
+ 'identifier': 'mechanism1',
'name': 'Mechanism 1',
'configuration': {
},
'scheme': 'builtin',
+ 'visibility': 3
},
});
@@ -187,13 +236,70 @@ describe('OCA.External.Settings tests', function() {
expect(fakeServer.requests.length).toEqual(1);
});
// TODO: tests with "applicableUsers" and "applicableGroups"
- // TODO: test with non-optional config parameters
// TODO: test with missing mount point value
// TODO: test with personal mounts (no applicable fields)
// TODO: test save triggers: paste, keyup, checkbox
// TODO: test "custom" field with addScript
// TODO: status indicator
});
+ describe('validate storage configuration', function() {
+ var $tr;
+
+ beforeEach(function() {
+ $tr = view.$el.find('tr:first');
+ selectBackend('\\OC\\InputsTestBackend');
+ });
+
+ it('lists missing fields in storage errors', function() {
+ var storage = view.getStorageConfig($tr);
+
+ expect(storage.errors).toEqual({
+ backendOptions: ['field_text', 'field_password']
+ });
+ });
+
+ it('highlights missing non-optional fields', function() {
+ _.each([
+ 'field_text',
+ 'field_password'
+ ], function(param) {
+ expect($tr.find('input[data-parameter='+param+']').hasClass('warning-input')).toBe(true);
+ });
+ _.each([
+ 'field_bool',
+ 'field_hidden',
+ 'field_text_optional',
+ 'field_password_optional'
+ ], function(param) {
+ expect($tr.find('input[data-parameter='+param+']').hasClass('warning-input')).toBe(false);
+ });
+ });
+
+ it('validates correct storage', function() {
+ $tr.find('[name=mountPoint]').val('mountpoint');
+
+ $tr.find('input[data-parameter=field_text]').val('foo');
+ $tr.find('input[data-parameter=field_password]').val('bar');
+ $tr.find('input[data-parameter=field_text_optional]').val('foobar');
+ // don't set field_password_optional
+ $tr.find('input[data-parameter=field_hidden]').val('baz');
+
+ var storage = view.getStorageConfig($tr);
+
+ expect(storage.validate()).toBe(true);
+ });
+
+ it('checks missing mount point', function() {
+ $tr.find('[name=mountPoint]').val('');
+
+ $tr.find('input[data-parameter=field_text]').val('foo');
+ $tr.find('input[data-parameter=field_password]').val('bar');
+
+ var storage = view.getStorageConfig($tr);
+
+ expect(storage.validate()).toBe(false);
+ });
+ });
describe('update storage', function() {
// TODO
});
@@ -251,13 +357,14 @@ describe('OCA.External.Settings tests', function() {
// defaults to true
var $field = $td.find('.dropdown [name=previews]');
expect($field.prop('checked')).toEqual(true);
- $td.find('.dropdown [name=filesystem_check_changes]').val(2);
+ $td.find('.dropdown [name=filesystem_check_changes]').val(0);
$('body').mouseup();
expect(JSON.parse($tr.find('input.mountOptions').val())).toEqual({
encrypt: true,
previews: true,
- filesystem_check_changes: 2
+ enable_sharing: true,
+ filesystem_check_changes: 0
});
});
});
diff --git a/apps/files_external/tests/legacydependencycheckpolyfilltest.php b/apps/files_external/tests/legacydependencycheckpolyfilltest.php
index 41109b63c1e..4b1351a809d 100644
--- a/apps/files_external/tests/legacydependencycheckpolyfilltest.php
+++ b/apps/files_external/tests/legacydependencycheckpolyfilltest.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_external/tests/owncloudfunctions.php b/apps/files_external/tests/owncloudfunctions.php
index 4cfe83db950..019f988275e 100644
--- a/apps/files_external/tests/owncloudfunctions.php
+++ b/apps/files_external/tests/owncloudfunctions.php
@@ -2,10 +2,11 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,13 @@
namespace Test\Files\Storage;
+/**
+ * Class OwnCloudFunctions
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class OwnCloudFunctions extends \Test\TestCase {
function configUrlProvider() {
diff --git a/apps/files_external/tests/personalmounttest.php b/apps/files_external/tests/personalmounttest.php
new file mode 100644
index 00000000000..d82773ad749
--- /dev/null
+++ b/apps/files_external/tests/personalmounttest.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_external\Tests;
+
+use OC\Files\Mount\Manager;
+use OCA\Files_External\Lib\PersonalMount;
+use Test\TestCase;
+
+class PersonalMountTest extends TestCase {
+ public function testFindByStorageId() {
+ /** @var \OCA\Files_External\Service\UserStoragesService $storageService */
+ $storageService = $this->getMockBuilder('\OCA\Files_External\Service\UserStoragesService')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Storage')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $storage->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('dummy'));
+
+ $mount = new PersonalMount($storageService, 10, $storage, '/foo');
+
+ $mountManager = new Manager();
+ $mountManager->addMount($mount);
+
+ $this->assertEquals([$mount], $mountManager->findByStorageId('dummy'));
+ }
+}
diff --git a/apps/files_external/tests/service/backendservicetest.php b/apps/files_external/tests/service/backendservicetest.php
index 5097b479a5f..9b4e728de22 100644
--- a/apps/files_external/tests/service/backendservicetest.php
+++ b/apps/files_external/tests/service/backendservicetest.php
@@ -1,8 +1,9 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,6 +36,11 @@ class BackendServiceTest extends \Test\TestCase {
$this->l10n = $this->getMock('\OCP\IL10N');
}
+ /**
+ * @param string $class
+ *
+ * @return \OCA\Files_External\Lib\Backend\Backend
+ */
protected function getBackendMock($class) {
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
->disableOriginalConstructor()
diff --git a/apps/files_external/tests/service/dbconfigservicetest.php b/apps/files_external/tests/service/dbconfigservicetest.php
new file mode 100644
index 00000000000..41b5df73613
--- /dev/null
+++ b/apps/files_external/tests/service/dbconfigservicetest.php
@@ -0,0 +1,273 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Tests\Service;
+
+
+use OCA\Files_External\Service\DBConfigService;
+use OCP\IDBConnection;
+use Test\TestCase;
+
+/**
+ * @group DB
+ */
+class DBConfigServiceTest extends TestCase {
+ /**
+ * @var DBConfigService
+ */
+ private $dbConfig;
+
+ /**
+ * @var IDBConnection
+ */
+ private $connection;
+
+ private $mounts = [];
+
+ public function setUp() {
+ parent::setUp();
+ $this->connection = \OC::$server->getDatabaseConnection();
+ $this->dbConfig = new DBConfigService($this->connection);
+ }
+
+ public function tearDown() {
+ foreach ($this->mounts as $mount) {
+ $this->dbConfig->removeMount($mount);
+ }
+ $this->mounts = [];
+ }
+
+ private function addMount($mountPoint, $storageBackend, $authBackend, $priority, $type) {
+ $id = $this->dbConfig->addMount($mountPoint, $storageBackend, $authBackend, $priority, $type);
+ $this->mounts[] = $id;
+ return $id;
+ }
+
+ public function testAddSimpleMount() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals('/test', $mount['mount_point']);
+ $this->assertEquals('foo', $mount['storage_backend']);
+ $this->assertEquals('bar', $mount['auth_backend']);
+ $this->assertEquals(100, $mount['priority']);
+ $this->assertEquals(DBConfigService::MOUNT_TYPE_ADMIN, $mount['type']);
+ $this->assertEquals([], $mount['applicable']);
+ $this->assertEquals([], $mount['config']);
+ $this->assertEquals([], $mount['options']);
+ }
+
+ public function testAddApplicable() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals([
+ ['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id]
+ ], $mount['applicable']);
+
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_GROUP, 'bar');
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_GLOBAL, null);
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals([
+ ['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id],
+ ['type' => DBConfigService::APPLICABLE_TYPE_GROUP, 'value' => 'bar', 'mount_id' => $id],
+ ['type' => DBConfigService::APPLICABLE_TYPE_GLOBAL, 'value' => null, 'mount_id' => $id]
+ ], $mount['applicable']);
+ }
+
+ public function testAddApplicableDouble() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals([
+ ['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id]
+ ], $mount['applicable']);
+ }
+
+ public function testDeleteMount() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+
+ $this->dbConfig->removeMount($id);
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals(null, $mount);
+ }
+
+ public function testRemoveApplicable() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+ $this->dbConfig->removeApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals([], $mount['applicable']);
+ }
+
+ public function testRemoveApplicableGlobal() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_GLOBAL, null);
+ $this->dbConfig->removeApplicable($id, DBConfigService::APPLICABLE_TYPE_GLOBAL, null);
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals([
+ ['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id]
+ ], $mount['applicable']);
+ }
+
+ public function testSetConfig() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->dbConfig->setConfig($id, 'foo', 'bar');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals(['foo' => 'bar'], $mount['config']);
+
+ $this->dbConfig->setConfig($id, 'foo2', 'bar2');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals(['foo' => 'bar', 'foo2' => 'bar2'], $mount['config']);
+ }
+
+ public function testSetConfigOverwrite() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->dbConfig->setConfig($id, 'foo', 'bar');
+ $this->dbConfig->setConfig($id, 'asd', '1');
+ $this->dbConfig->setConfig($id, 'foo', 'qwerty');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals(['foo' => 'qwerty', 'asd' => '1'], $mount['config']);
+ }
+
+ public function testSetOption() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->dbConfig->setOption($id, 'foo', 'bar');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals(['foo' => 'bar'], $mount['options']);
+
+ $this->dbConfig->setOption($id, 'foo2', 'bar2');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals(['foo' => 'bar', 'foo2' => 'bar2'], $mount['options']);
+ }
+
+ public function testSetOptionOverwrite() {
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->dbConfig->setOption($id, 'foo', 'bar');
+ $this->dbConfig->setOption($id, 'asd', '1');
+ $this->dbConfig->setOption($id, 'foo', 'qwerty');
+
+ $mount = $this->dbConfig->getMountById($id);
+ $this->assertEquals(['foo' => 'qwerty', 'asd' => '1'], $mount['options']);
+ }
+
+ public function testGetMountsFor() {
+ $mounts = $this->dbConfig->getMountsFor(DBConfigService::APPLICABLE_TYPE_USER, 'test');
+ $this->assertEquals([], $mounts);
+
+ $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+
+ $mounts = $this->dbConfig->getMountsFor(DBConfigService::APPLICABLE_TYPE_USER, 'test');
+ $this->assertCount(1, $mounts);
+ $this->assertEquals($id, $mounts[0]['mount_id']);
+ $this->assertEquals([['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id]], $mounts[0]['applicable']);
+ }
+
+ public function testGetAdminMounts() {
+ $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->addMount('/test2', 'foo2', 'bar2', 100, DBConfigService::MOUNT_TYPE_PERSONAl);
+
+ $mounts = $this->dbConfig->getAdminMounts();
+ $this->assertCount(1, $mounts);
+ $this->assertEquals($id1, $mounts[0]['mount_id']);
+ }
+
+ public function testGetAdminMountsFor() {
+ $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->addMount('/test2', 'foo2', 'bar2', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $id3 = $this->addMount('/test3', 'foo3', 'bar3', 100, DBConfigService::MOUNT_TYPE_PERSONAl);
+
+ $this->dbConfig->addApplicable($id1, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+ $this->dbConfig->addApplicable($id3, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+
+ $mounts = $this->dbConfig->getAdminMountsFor(DBConfigService::APPLICABLE_TYPE_USER, 'test');
+ $this->assertCount(1, $mounts);
+ $this->assertEquals($id1, $mounts[0]['mount_id']);
+ $this->assertEquals([['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id1]], $mounts[0]['applicable']);
+ }
+
+ public function testGetUserMountsFor() {
+ $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $this->addMount('/test2', 'foo2', 'bar2', 100, DBConfigService::MOUNT_TYPE_PERSONAl);
+ $id3 = $this->addMount('/test3', 'foo3', 'bar3', 100, DBConfigService::MOUNT_TYPE_PERSONAl);
+
+ $this->dbConfig->addApplicable($id1, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+ $this->dbConfig->addApplicable($id3, DBConfigService::APPLICABLE_TYPE_USER, 'test');
+
+ $mounts = $this->dbConfig->getUserMountsFor(DBConfigService::APPLICABLE_TYPE_USER, 'test');
+ $this->assertCount(1, $mounts);
+ $this->assertEquals($id3, $mounts[0]['mount_id']);
+ $this->assertEquals([['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id3]], $mounts[0]['applicable']);
+ }
+
+ public function testGetAdminMountsForGlobal() {
+ $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+
+ $this->dbConfig->addApplicable($id1, DBConfigService::APPLICABLE_TYPE_GLOBAL, null);
+
+ $mounts = $this->dbConfig->getAdminMountsFor(DBConfigService::APPLICABLE_TYPE_GLOBAL, null);
+ $this->assertCount(1, $mounts);
+ $this->assertEquals($id1, $mounts[0]['mount_id']);
+ $this->assertEquals([['type' => DBConfigService::APPLICABLE_TYPE_GLOBAL, 'value' => null, 'mount_id' => $id1]], $mounts[0]['applicable']);
+ }
+
+ public function testSetMountPoint() {
+ $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $id2 = $this->addMount('/foo', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+
+ $this->dbConfig->setMountPoint($id1, '/asd');
+
+ $mount = $this->dbConfig->getMountById($id1);
+ $this->assertEquals('/asd', $mount['mount_point']);
+
+ // remains unchanged
+ $mount = $this->dbConfig->getMountById($id2);
+ $this->assertEquals('/foo', $mount['mount_point']);
+ }
+
+ public function testSetAuthBackend() {
+ $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+ $id2 = $this->addMount('/foo', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN);
+
+ $this->dbConfig->setAuthBackend($id1, 'none');
+
+ $mount = $this->dbConfig->getMountById($id1);
+ $this->assertEquals('none', $mount['auth_backend']);
+
+ // remains unchanged
+ $mount = $this->dbConfig->getMountById($id2);
+ $this->assertEquals('bar', $mount['auth_backend']);
+ }
+}
diff --git a/apps/files_external/tests/service/globalstoragesservicetest.php b/apps/files_external/tests/service/globalstoragesservicetest.php
index c129365913f..6cdfbef82d4 100644
--- a/apps/files_external/tests/service/globalstoragesservicetest.php
+++ b/apps/files_external/tests/service/globalstoragesservicetest.php
@@ -1,9 +1,10 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,10 +28,13 @@ use \OCA\Files_external\Service\GlobalStoragesService;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
+/**
+ * @group DB
+ */
class GlobalStoragesServiceTest extends StoragesServiceTest {
public function setUp() {
parent::setUp();
- $this->service = new GlobalStoragesService($this->backendService);
+ $this->service = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache);
}
public function tearDown() {
@@ -39,7 +43,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
}
protected function makeTestStorageData() {
- return $this->makeStorageConfig([
+ return $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
@@ -133,10 +137,9 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$storage = $this->makeStorageConfig($storageParams);
$newStorage = $this->service->addStorage($storage);
- $this->assertEquals(1, $newStorage->getId());
-
+ $baseId = $newStorage->getId();
- $newStorage = $this->service->getStorage(1);
+ $newStorage = $this->service->getStorage($baseId);
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackend(), $newStorage->getBackend());
@@ -145,12 +148,10 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers());
$this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups());
$this->assertEquals($storage->getPriority(), $newStorage->getPriority());
- $this->assertEquals(1, $newStorage->getId());
$this->assertEquals(0, $newStorage->getStatus());
- // next one gets id 2
$nextStorage = $this->service->addStorage($storage);
- $this->assertEquals(2, $nextStorage->getId());
+ $this->assertEquals($baseId + 1, $nextStorage->getId());
}
/**
@@ -173,19 +174,18 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
]);
$newStorage = $this->service->addStorage($storage);
- $this->assertEquals(1, $newStorage->getId());
+ $id = $newStorage->getId();
- $updatedStorage->setId(1);
+ $updatedStorage->setId($id);
$this->service->updateStorage($updatedStorage);
- $newStorage = $this->service->getStorage(1);
+ $newStorage = $this->service->getStorage($id);
$this->assertEquals($updatedStorage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($updatedStorage->getBackendOptions()['password'], $newStorage->getBackendOptions()['password']);
$this->assertEquals($updatedStorage->getApplicableUsers(), $newStorage->getApplicableUsers());
$this->assertEquals($updatedStorage->getApplicableGroups(), $newStorage->getApplicableGroups());
$this->assertEquals($updatedStorage->getPriority(), $newStorage->getPriority());
- $this->assertEquals(1, $newStorage->getId());
$this->assertEquals(0, $newStorage->getStatus());
}
@@ -442,7 +442,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$sourceApplicableGroups,
$updatedApplicableUsers,
$updatedApplicableGroups,
- $expectedCalls) {
+ $expectedCalls) {
$storage = $this->makeTestStorageData();
$storage->setApplicableUsers($sourceApplicableUsers);
@@ -601,7 +601,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
public function testHooksDeleteStorage(
$sourceApplicableUsers,
$sourceApplicableGroups,
- $expectedCalls) {
+ $expectedCalls) {
$storage = $this->makeTestStorageData();
$storage->setApplicableUsers($sourceApplicableUsers);
@@ -626,321 +626,4 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
}
}
- /**
- * Make sure it uses the correct format when reading/writing
- * the legacy config
- */
- public function testLegacyConfigConversionApplicableAll() {
- $configFile = $this->dataDir . '/mount.json';
-
- $storage = $this->makeTestStorageData();
- $storage = $this->service->addStorage($storage);
-
- $json = json_decode(file_get_contents($configFile), true);
-
- $this->assertCount(1, $json);
-
- $this->assertEquals([\OC_Mount_Config::MOUNT_TYPE_USER], array_keys($json));
- $this->assertEquals(['all'], array_keys($json[\OC_Mount_config::MOUNT_TYPE_USER]));
-
- $mountPointData = $json[\OC_Mount_config::MOUNT_TYPE_USER]['all'];
- $this->assertEquals(['/$user/files/mountpoint'], array_keys($mountPointData));
-
- $mountPointOptions = current($mountPointData);
- $this->assertEquals(1, $mountPointOptions['id']);
- $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
- $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
- $this->assertEquals(15, $mountPointOptions['priority']);
- $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
-
- $backendOptions = $mountPointOptions['options'];
- $this->assertEquals('value1', $backendOptions['option1']);
- $this->assertEquals('value2', $backendOptions['option2']);
- $this->assertEquals('', $backendOptions['password']);
- $this->assertNotEmpty($backendOptions['password_encrypted']);
- }
-
- /**
- * Make sure it uses the correct format when reading/writing
- * the legacy config
- */
- public function testLegacyConfigConversionApplicableUserAndGroup() {
- $configFile = $this->dataDir . '/mount.json';
-
- $storage = $this->makeTestStorageData();
- $storage->setApplicableUsers(['user1', 'user2']);
- $storage->setApplicableGroups(['group1', 'group2']);
-
- $storage = $this->service->addStorage($storage);
-
- $json = json_decode(file_get_contents($configFile), true);
-
- $this->assertCount(2, $json);
-
- $this->assertTrue(isset($json[\OC_Mount_Config::MOUNT_TYPE_USER]));
- $this->assertTrue(isset($json[\OC_Mount_Config::MOUNT_TYPE_GROUP]));
- $this->assertEquals(['user1', 'user2'], array_keys($json[\OC_Mount_config::MOUNT_TYPE_USER]));
- $this->assertEquals(['group1', 'group2'], array_keys($json[\OC_Mount_config::MOUNT_TYPE_GROUP]));
-
- // check that all options are the same for both users and both groups
- foreach ($json[\OC_Mount_Config::MOUNT_TYPE_USER] as $mountPointData) {
- $this->assertEquals(['/$user/files/mountpoint'], array_keys($mountPointData));
-
- $mountPointOptions = current($mountPointData);
-
- $this->assertEquals(1, $mountPointOptions['id']);
- $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
- $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
- $this->assertEquals(15, $mountPointOptions['priority']);
- $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
-
- $backendOptions = $mountPointOptions['options'];
- $this->assertEquals('value1', $backendOptions['option1']);
- $this->assertEquals('value2', $backendOptions['option2']);
- $this->assertEquals('', $backendOptions['password']);
- $this->assertNotEmpty($backendOptions['password_encrypted']);
- }
-
- foreach ($json[\OC_Mount_Config::MOUNT_TYPE_GROUP] as $mountPointData) {
- $this->assertEquals(['/$user/files/mountpoint'], array_keys($mountPointData));
-
- $mountPointOptions = current($mountPointData);
-
- $this->assertEquals(1, $mountPointOptions['id']);
- $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
- $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
- $this->assertEquals(15, $mountPointOptions['priority']);
- $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
-
- $backendOptions = $mountPointOptions['options'];
- $this->assertEquals('value1', $backendOptions['option1']);
- $this->assertEquals('value2', $backendOptions['option2']);
- $this->assertEquals('', $backendOptions['password']);
- $this->assertNotEmpty($backendOptions['password_encrypted']);
- }
- }
-
- /**
- * Test reading in a legacy config and generating config ids.
- */
- public function testReadLegacyConfigAndGenerateConfigId() {
- $configFile = $this->dataDir . '/mount.json';
-
- $legacyBackendOptions = [
- 'user' => 'someuser',
- 'password' => 'somepassword',
- ];
- $legacyBackendOptions = \OC_Mount_Config::encryptPasswords($legacyBackendOptions);
-
- $legacyConfig = [
- 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
- 'authMechanism' => 'identifier:\Auth\Mechanism',
- 'options' => $legacyBackendOptions,
- 'mountOptions' => ['preview' => false],
- ];
- // different mount options
- $legacyConfig2 = [
- 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
- 'authMechanism' => 'identifier:\Auth\Mechanism',
- 'options' => $legacyBackendOptions,
- 'mountOptions' => ['preview' => true],
- ];
-
- $legacyBackendOptions2 = $legacyBackendOptions;
- $legacyBackendOptions2 = ['user' => 'someuser2', 'password' => 'somepassword2'];
- $legacyBackendOptions2 = \OC_Mount_Config::encryptPasswords($legacyBackendOptions2);
-
- // different config
- $legacyConfig3 = [
- 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
- 'authMechanism' => 'identifier:\Auth\Mechanism',
- 'options' => $legacyBackendOptions2,
- 'mountOptions' => ['preview' => true],
- ];
-
- $json = [
- 'user' => [
- 'user1' => [
- '/$user/files/somemount' => $legacyConfig,
- ],
- // same config
- 'user2' => [
- '/$user/files/somemount' => $legacyConfig,
- ],
- // different mountOptions
- 'user3' => [
- '/$user/files/somemount' => $legacyConfig2,
- ],
- // different mount point
- 'user4' => [
- '/$user/files/anothermount' => $legacyConfig,
- ],
- // different storage config
- 'user5' => [
- '/$user/files/somemount' => $legacyConfig3,
- ],
- ],
- 'group' => [
- 'group1' => [
- // will get grouped with user configs
- '/$user/files/somemount' => $legacyConfig,
- ],
- ],
- ];
-
- file_put_contents($configFile, json_encode($json));
-
- $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB')
- ->expects($this->exactly(4))
- ->method('validateStorageDefinition');
- $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism')
- ->expects($this->exactly(4))
- ->method('validateStorageDefinition');
-
- $allStorages = $this->service->getAllStorages();
-
- $this->assertCount(4, $allStorages);
-
- $storage1 = $allStorages[1];
- $storage2 = $allStorages[2];
- $storage3 = $allStorages[3];
- $storage4 = $allStorages[4];
-
- $this->assertEquals('/somemount', $storage1->getMountPoint());
- $this->assertEquals('someuser', $storage1->getBackendOptions()['user']);
- $this->assertEquals('somepassword', $storage1->getBackendOptions()['password']);
- $this->assertEquals(['user1', 'user2'], $storage1->getApplicableUsers());
- $this->assertEquals(['group1'], $storage1->getApplicableGroups());
- $this->assertEquals(['preview' => false], $storage1->getMountOptions());
-
- $this->assertEquals('/somemount', $storage2->getMountPoint());
- $this->assertEquals('someuser', $storage2->getBackendOptions()['user']);
- $this->assertEquals('somepassword', $storage2->getBackendOptions()['password']);
- $this->assertEquals(['user3'], $storage2->getApplicableUsers());
- $this->assertEquals([], $storage2->getApplicableGroups());
- $this->assertEquals(['preview' => true], $storage2->getMountOptions());
-
- $this->assertEquals('/anothermount', $storage3->getMountPoint());
- $this->assertEquals('someuser', $storage3->getBackendOptions()['user']);
- $this->assertEquals('somepassword', $storage3->getBackendOptions()['password']);
- $this->assertEquals(['user4'], $storage3->getApplicableUsers());
- $this->assertEquals([], $storage3->getApplicableGroups());
- $this->assertEquals(['preview' => false], $storage3->getMountOptions());
-
- $this->assertEquals('/somemount', $storage4->getMountPoint());
- $this->assertEquals('someuser2', $storage4->getBackendOptions()['user']);
- $this->assertEquals('somepassword2', $storage4->getBackendOptions()['password']);
- $this->assertEquals(['user5'], $storage4->getApplicableUsers());
- $this->assertEquals([], $storage4->getApplicableGroups());
- $this->assertEquals(['preview' => true], $storage4->getMountOptions());
- }
-
- public function testReadLegacyConfigNoAuthMechanism() {
- $configFile = $this->dataDir . '/mount.json';
-
- $json = [
- 'user' => [
- 'user1' => [
- '/$user/files/somemount' => [
- 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
- 'authMechanism' => 'identifier:\Auth\Mechanism',
- 'options' => [],
- 'mountOptions' => [],
- ],
- '/$user/files/othermount' => [
- 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
- // no authMechanism
- 'options' => [],
- 'mountOptions' => [],
- ],
- ]
- ]
- ];
-
- file_put_contents($configFile, json_encode($json));
-
- $allStorages = $this->service->getAllStorages();
-
- $this->assertCount(2, $allStorages);
-
- $storage1 = $allStorages[1];
- $storage2 = $allStorages[2];
-
- $this->assertEquals('/somemount', $storage1->getMountPoint());
- $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage1->getBackend()->getIdentifier());
- $this->assertEquals('identifier:\Auth\Mechanism', $storage1->getAuthMechanism()->getIdentifier());
-
- $this->assertEquals('/othermount', $storage2->getMountPoint());
- $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage2->getBackend()->getIdentifier());
- $this->assertEquals('identifier:\Other\Auth\Mechanism', $storage2->getAuthMechanism()->getIdentifier());
- }
-
- public function testReadLegacyConfigClass() {
- $configFile = $this->dataDir . '/mount.json';
-
- $json = [
- 'user' => [
- 'user1' => [
- '/$user/files/somemount' => [
- 'class' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
- 'authMechanism' => 'identifier:\Auth\Mechanism',
- 'options' => [],
- 'mountOptions' => [],
- ],
- '/$user/files/othermount' => [
- 'class' => 'identifier:sftp_alias',
- 'authMechanism' => 'identifier:\Auth\Mechanism',
- 'options' => [],
- 'mountOptions' => [],
- ],
- ]
- ]
- ];
-
- file_put_contents($configFile, json_encode($json));
-
- $allStorages = $this->service->getAllStorages();
-
- $this->assertCount(2, $allStorages);
-
- $storage1 = $allStorages[1];
- $storage2 = $allStorages[2];
-
- $this->assertEquals('/somemount', $storage1->getMountPoint());
- $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage1->getBackend()->getIdentifier());
- $this->assertEquals('identifier:\Auth\Mechanism', $storage1->getAuthMechanism()->getIdentifier());
-
- $this->assertEquals('/othermount', $storage2->getMountPoint());
- $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage2->getBackend()->getIdentifier());
- $this->assertEquals('identifier:\Auth\Mechanism', $storage2->getAuthMechanism()->getIdentifier());
- }
-
- public function testReadEmptyMountPoint() {
- $configFile = $this->dataDir . '/mount.json';
-
- $json = [
- 'user' => [
- 'user1' => [
- '/$user/files/' => [
- 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
- 'authMechanism' => 'identifier:\Auth\Mechanism',
- 'options' => [],
- 'mountOptions' => [],
- ],
- ]
- ]
- ];
-
- file_put_contents($configFile, json_encode($json));
-
- $allStorages = $this->service->getAllStorages();
-
- $this->assertCount(1, $allStorages);
-
- $storage1 = $allStorages[1];
-
- $this->assertEquals('/', $storage1->getMountPoint());
- }
-
-
}
diff --git a/apps/files_external/tests/service/storagesservicetest.php b/apps/files_external/tests/service/storagesservicetest.php
index 7487ba459af..68671b599bd 100644
--- a/apps/files_external/tests/service/storagesservicetest.php
+++ b/apps/files_external/tests/service/storagesservicetest.php
@@ -1,9 +1,10 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,8 +26,29 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
-use \OCA\Files_External\Lib\BackendService;
+use OCA\Files_External\Service\BackendService;
+use OCA\Files_External\Service\DBConfigService;
+use OCA\Files_external\Service\StoragesService;
+class CleaningDBConfig extends DBConfigService {
+ private $mountIds = [];
+
+ public function addMount($mountPoint, $storageBackend, $authBackend, $priority, $type) {
+ $id = parent::addMount($mountPoint, $storageBackend, $authBackend, $priority, $type); // TODO: Change the autogenerated stub
+ $this->mountIds[] = $id;
+ return $id;
+ }
+
+ public function clean() {
+ foreach ($this->mountIds as $id) {
+ $this->removeMount($id);
+ }
+ }
+}
+
+/**
+ * @group DB
+ */
abstract class StoragesServiceTest extends \Test\TestCase {
/**
@@ -44,6 +66,9 @@ abstract class StoragesServiceTest extends \Test\TestCase {
*/
protected $dataDir;
+ /** @var CleaningDBConfig */
+ protected $dbConfig;
+
/**
* Hook calls
*
@@ -51,7 +76,14 @@ abstract class StoragesServiceTest extends \Test\TestCase {
*/
protected static $hookCalls;
+ /**
+ * @var \PHPUnit_Framework_MockObject_MockObject|\OCP\Files\Config\IUserMountCache
+ */
+ protected $mountCache;
+
public function setUp() {
+ parent::setUp();
+ $this->dbConfig = new CleaningDBConfig(\OC::$server->getDatabaseConnection());
self::$hookCalls = array();
$config = \OC::$server->getConfig();
$this->dataDir = $config->getSystemValue(
@@ -60,11 +92,13 @@ abstract class StoragesServiceTest extends \Test\TestCase {
);
\OC_Mount_Config::$skipTest = true;
+ $this->mountCache = $this->getMock('OCP\Files\Config\IUserMountCache');
+
// prepare BackendService mock
$this->backendService =
$this->getMockBuilder('\OCA\Files_External\Service\BackendService')
- ->disableOriginalConstructor()
- ->getMock();
+ ->disableOriginalConstructor()
+ ->getMock();
$authMechanisms = [
'identifier:\Auth\Mechanism' => $this->getAuthMechMock('null', '\Auth\Mechanism'),
@@ -72,14 +106,14 @@ abstract class StoragesServiceTest extends \Test\TestCase {
'identifier:\OCA\Files_External\Lib\Auth\NullMechanism' => $this->getAuthMechMock(),
];
$this->backendService->method('getAuthMechanism')
- ->will($this->returnCallback(function($class) use ($authMechanisms) {
+ ->will($this->returnCallback(function ($class) use ($authMechanisms) {
if (isset($authMechanisms[$class])) {
return $authMechanisms[$class];
}
return null;
}));
$this->backendService->method('getAuthMechanismsByScheme')
- ->will($this->returnCallback(function($schemes) use ($authMechanisms) {
+ ->will($this->returnCallback(function ($schemes) use ($authMechanisms) {
return array_filter($authMechanisms, function ($authMech) use ($schemes) {
return in_array($authMech->getScheme(), $schemes, true);
});
@@ -96,7 +130,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$backends['identifier:\OCA\Files_External\Lib\Backend\SFTP']->method('getLegacyAuthMechanism')
->willReturn($authMechanisms['identifier:\Other\Auth\Mechanism']);
$this->backendService->method('getBackend')
- ->will($this->returnCallback(function($backendClass) use ($backends) {
+ ->will($this->returnCallback(function ($backendClass) use ($backends) {
if (isset($backends[$backendClass])) {
return $backends[$backendClass];
}
@@ -116,7 +150,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$containerMock = $this->getMock('\OCP\AppFramework\IAppContainer');
$containerMock->method('query')
- ->will($this->returnCallback(function($name) {
+ ->will($this->returnCallback(function ($name) {
if ($name === 'OCA\Files_External\Service\BackendService') {
return $this->backendService;
}
@@ -132,6 +166,9 @@ abstract class StoragesServiceTest extends \Test\TestCase {
public function tearDown() {
\OC_Mount_Config::$skipTest = false;
self::$hookCalls = array();
+ if ($this->dbConfig) {
+ $this->dbConfig->clean();
+ }
}
protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') {
@@ -141,7 +178,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$backend->method('getStorageClass')
->willReturn($storageClass);
$backend->method('getIdentifier')
- ->willReturn('identifier:'.$class);
+ ->willReturn('identifier:' . $class);
return $backend;
}
@@ -152,7 +189,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$authMech->method('getScheme')
->willReturn($scheme);
$authMech->method('getIdentifier')
- ->willReturn('identifier:'.$class);
+ ->willReturn('identifier:' . $class);
return $authMech;
}
@@ -258,7 +295,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$storage->setBackendOptions($backendOptions);
$newStorage = $this->service->addStorage($storage);
- $this->assertEquals(1, $newStorage->getId());
+ $id = $newStorage->getId();
// manually trigger storage entry because normally it happens on first
// access, which isn't possible within this test
@@ -267,7 +304,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
// get numeric id for later check
$numericId = $storageCache->getNumericId();
- $newStorage = $this->service->removeStorage(1);
+ $this->service->removeStorage($id);
$caught = false;
try {
@@ -317,7 +354,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$priority
);
- $this->assertEquals('/'.$mountPoint, $storage->getMountPoint());
+ $this->assertEquals('/' . $mountPoint, $storage->getMountPoint());
$this->assertEquals($backend, $storage->getBackend());
$this->assertEquals($authMechanism, $storage->getAuthMechanism());
$this->assertEquals($backendOptions, $storage->getBackendOptions());
@@ -436,4 +473,33 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$params[Filesystem::signal_param_users]
);
}
+
+ public function testUpdateStorageMountPoint() {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
+
+ $storage = new StorageConfig();
+ $storage->setMountPoint('mountpoint');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
+ $storage->setBackendOptions(['password' => 'testPassword']);
+
+ $savedStorage = $this->service->addStorage($storage);
+
+ $newAuthMechanism = $this->backendService->getAuthMechanism('identifier:\Other\Auth\Mechanism');
+
+ $updatedStorage = new StorageConfig($savedStorage->getId());
+ $updatedStorage->setMountPoint('mountpoint2');
+ $updatedStorage->setBackend($backend);
+ $updatedStorage->setAuthMechanism($newAuthMechanism);
+ $updatedStorage->setBackendOptions(['password' => 'password2']);
+
+ $this->service->updateStorage($updatedStorage);
+
+ $savedStorage = $this->service->getStorage($updatedStorage->getId());
+
+ $this->assertEquals('/mountpoint2', $savedStorage->getMountPoint());
+ $this->assertEquals($newAuthMechanism, $savedStorage->getAuthMechanism());
+ $this->assertEquals('password2', $savedStorage->getBackendOption('password'));
+ }
}
diff --git a/apps/files_external/tests/service/userglobalstoragesservicetest.php b/apps/files_external/tests/service/userglobalstoragesservicetest.php
index e88764d0f78..baecf143c66 100644
--- a/apps/files_external/tests/service/userglobalstoragesservicetest.php
+++ b/apps/files_external/tests/service/userglobalstoragesservicetest.php
@@ -1,9 +1,10 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,17 +22,34 @@
*/
namespace OCA\Files_External\Tests\Service;
+use OCA\Files_external\NotFoundException;
+use OCA\Files_external\Service\StoragesService;
use \OCA\Files_External\Service\UserGlobalStoragesService;
use \OCP\IGroupManager;
use \OCA\Files_External\Lib\StorageConfig;
+use OCP\IUser;
+use Test\Traits\UserTrait;
+/**
+ * @group DB
+ */
class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
+ use UserTrait;
+ /** @var \OCP\IGroupManager|\PHPUnit_Framework_MockObject_MockObject groupManager */
protected $groupManager;
+ /**
+ * @var StoragesService
+ */
protected $globalStoragesService;
+ /**
+ * @var UserGlobalStoragesService
+ */
+ protected $service;
+
protected $user;
const USER_ID = 'test_user';
@@ -44,6 +62,7 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
$this->globalStoragesService = $this->service;
$this->user = new \OC\User\User(self::USER_ID, null);
+ /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject $userSession */
$userSession = $this->getMock('\OCP\IUserSession');
$userSession
->expects($this->any())
@@ -52,21 +71,31 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
$this->groupManager = $this->getMock('\OCP\IGroupManager');
$this->groupManager->method('isInGroup')
- ->will($this->returnCallback(function($userId, $groupId) {
+ ->will($this->returnCallback(function ($userId, $groupId) {
if ($userId === self::USER_ID) {
switch ($groupId) {
- case self::GROUP_ID:
- case self::GROUP_ID2:
- return true;
+ case self::GROUP_ID:
+ case self::GROUP_ID2:
+ return true;
}
}
return false;
}));
+ $this->groupManager->method('getUserGroupIds')
+ ->will($this->returnCallback(function (IUser $user) {
+ if ($user->getUID() === self::USER_ID) {
+ return [self::GROUP_ID, self::GROUP_ID2];
+ } else {
+ return [];
+ }
+ }));
$this->service = new UserGlobalStoragesService(
$this->backendService,
+ $this->dbConfig,
$userSession,
- $this->groupManager
+ $this->groupManager,
+ $this->mountCache
);
}
@@ -114,6 +143,13 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
$this->assertEquals('/mountpoint', $retrievedStorage->getMountPoint());
} else {
$this->assertEquals(0, count($storages));
+
+ try {
+ $this->service->getStorage($newStorage->getId());
+ $this->fail('Failed asserting that storage can\'t be accessed by id');
+ } catch (NotFoundException $e) {
+
+ }
}
}
@@ -156,6 +192,13 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
/**
* @expectedException \DomainException
+ */
+ public function testNonExistingStorage() {
+ parent::testNonExistingStorage();
+ }
+
+ /**
+ * @expectedException \DomainException
* @dataProvider deleteStorageDataProvider
*/
public function testDeleteStorage($backendOptions, $rustyStorageId, $expectedCountAfterDeletion) {
@@ -169,9 +212,16 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
$storage->setBackendOptions($backendOptions);
$newStorage = $this->globalStoragesService->addStorage($storage);
- $this->assertEquals(1, $newStorage->getId());
+ $id = $newStorage->getId();
+
+ $this->service->removeStorage($id);
+ }
- $this->service->removeStorage(1);
+ /**
+ * @expectedException \DomainException
+ */
+ public function testDeleteUnexistingStorage() {
+ parent::testDeleteUnexistingStorage();
}
public function getUniqueStoragesProvider() {
@@ -309,4 +359,8 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
$this->assertTrue(true);
}
+ public function testUpdateStorageMountPoint() {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
}
diff --git a/apps/files_external/tests/service/userstoragesservicetest.php b/apps/files_external/tests/service/userstoragesservicetest.php
index 78f9231c3d1..37423cb8d74 100644
--- a/apps/files_external/tests/service/userstoragesservicetest.php
+++ b/apps/files_external/tests/service/userstoragesservicetest.php
@@ -1,9 +1,10 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,39 +24,45 @@ namespace OCA\Files_external\Tests\Service;
use \OC\Files\Filesystem;
+use OCA\Files_external\Service\GlobalStoragesService;
+use OCA\Files_external\Service\StoragesService;
use \OCA\Files_external\Service\UserStoragesService;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
+use Test\Traits\UserTrait;
+/**
+ * @group DB
+ */
class UserStoragesServiceTest extends StoragesServiceTest {
+ use UserTrait;
+
+ private $user;
+
+ private $userId;
+
+ /**
+ * @var StoragesService
+ */
+ protected $globalStoragesService;
public function setUp() {
parent::setUp();
- $userManager = \OC::$server->getUserManager();
+ $this->globalStoragesService = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache);
$this->userId = $this->getUniqueID('user_');
- $this->user = $userManager->createUser(
- $this->userId,
- $this->userId
- );
+ $this->createUser($this->userId, $this->userId);
+ $this->user = \OC::$server->getUserManager()->get($this->userId);
+ /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject $userSession */
$userSession = $this->getMock('\OCP\IUserSession');
$userSession
->expects($this->any())
->method('getUser')
->will($this->returnValue($this->user));
- $this->service = new UserStoragesService($this->backendService, $userSession);
-
- // create home folder
- mkdir($this->dataDir . '/' . $this->userId . '/');
- }
-
- public function tearDown() {
- @unlink($this->dataDir . '/' . $this->userId . '/mount.json');
- $this->user->delete();
- parent::tearDown();
+ $this->service = new UserStoragesService($this->backendService, $this->dbConfig, $userSession, $this->mountCache);
}
private function makeTestStorageData() {
@@ -79,15 +86,14 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$newStorage = $this->service->addStorage($storage);
- $this->assertEquals(1, $newStorage->getId());
+ $id = $newStorage->getId();
- $newStorage = $this->service->getStorage(1);
+ $newStorage = $this->service->getStorage($id);
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackend(), $newStorage->getBackend());
$this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
- $this->assertEquals(1, $newStorage->getId());
$this->assertEquals(0, $newStorage->getStatus());
// hook called once for user
@@ -99,9 +105,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$this->userId
);
- // next one gets id 2
$nextStorage = $this->service->addStorage($storage);
- $this->assertEquals(2, $nextStorage->getId());
+ $this->assertEquals($id + 1, $nextStorage->getId());
}
public function testUpdateStorage() {
@@ -117,7 +122,6 @@ class UserStoragesServiceTest extends StoragesServiceTest {
]);
$newStorage = $this->service->addStorage($storage);
- $this->assertEquals(1, $newStorage->getId());
$backendOptions = $newStorage->getBackendOptions();
$backendOptions['password'] = 'anotherPassword';
@@ -128,10 +132,9 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$newStorage = $this->service->updateStorage($newStorage);
$this->assertEquals('anotherPassword', $newStorage->getBackendOptions()['password']);
+ $this->assertEquals([$this->userId], $newStorage->getApplicableUsers());
// these attributes are unused for user storages
- $this->assertEmpty($newStorage->getApplicableUsers());
$this->assertEmpty($newStorage->getApplicableGroups());
- $this->assertEquals(1, $newStorage->getId());
$this->assertEquals(0, $newStorage->getStatus());
// no hook calls
@@ -183,87 +186,23 @@ class UserStoragesServiceTest extends StoragesServiceTest {
}
/**
- * Make sure it uses the correct format when reading/writing
- * the legacy config
+ * @expectedException \OCA\Files_external\NotFoundException
*/
- public function testLegacyConfigConversion() {
- $configFile = $this->dataDir . '/' . $this->userId . '/mount.json';
-
- $storage = $this->makeTestStorageData();
- $storage = $this->service->addStorage($storage);
-
- $json = json_decode(file_get_contents($configFile), true);
+ public function testGetAdminStorage() {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
- $this->assertCount(1, $json);
+ $storage = new StorageConfig();
+ $storage->setMountPoint('mountpoint');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
+ $storage->setBackendOptions(['password' => 'testPassword']);
+ $storage->setApplicableUsers([$this->userId]);
- $this->assertEquals([\OC_Mount_Config::MOUNT_TYPE_USER], array_keys($json));
- $this->assertEquals([$this->userId], array_keys($json[\OC_Mount_config::MOUNT_TYPE_USER]));
+ $newStorage = $this->globalStoragesService->addStorage($storage);
- $mountPointData = $json[\OC_Mount_config::MOUNT_TYPE_USER][$this->userId];
- $this->assertEquals(['/' . $this->userId . '/files/mountpoint'], array_keys($mountPointData));
+ $this->assertInstanceOf('\OCA\Files_external\Lib\StorageConfig', $this->globalStoragesService->getStorage($newStorage->getId()));
- $mountPointOptions = current($mountPointData);
- $this->assertEquals(1, $mountPointOptions['id']);
- $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
- $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
- $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
-
- $backendOptions = $mountPointOptions['options'];
- $this->assertEquals('value1', $backendOptions['option1']);
- $this->assertEquals('value2', $backendOptions['option2']);
- $this->assertEquals('', $backendOptions['password']);
- $this->assertNotEmpty($backendOptions['password_encrypted']);
- }
-
- /**
- * Test reading in a legacy config and generating config ids.
- */
- public function testReadLegacyConfigAndGenerateConfigId() {
- $configFile = $this->dataDir . '/' . $this->userId . '/mount.json';
-
- $legacyBackendOptions = [
- 'user' => 'someuser',
- 'password' => 'somepassword',
- ];
- $legacyBackendOptions = \OC_Mount_Config::encryptPasswords($legacyBackendOptions);
-
- $legacyConfig = [
- 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
- 'authMechanism' => 'identifier:\Auth\Mechanism',
- 'options' => $legacyBackendOptions,
- 'mountOptions' => ['preview' => false],
- ];
- // different mount options
- $legacyConfig2 = [
- 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
- 'authMechanism' => 'identifier:\Auth\Mechanism',
- 'options' => $legacyBackendOptions,
- 'mountOptions' => ['preview' => true],
- ];
-
- $json = ['user' => []];
- $json['user'][$this->userId] = [
- '/$user/files/somemount' => $legacyConfig,
- '/$user/files/anothermount' => $legacyConfig2,
- ];
-
- file_put_contents($configFile, json_encode($json));
-
- $allStorages = $this->service->getAllStorages();
-
- $this->assertCount(2, $allStorages);
-
- $storage1 = $allStorages[1];
- $storage2 = $allStorages[2];
-
- $this->assertEquals('/somemount', $storage1->getMountPoint());
- $this->assertEquals('someuser', $storage1->getBackendOptions()['user']);
- $this->assertEquals('somepassword', $storage1->getBackendOptions()['password']);
- $this->assertEquals(['preview' => false], $storage1->getMountOptions());
-
- $this->assertEquals('/anothermount', $storage2->getMountPoint());
- $this->assertEquals('someuser', $storage2->getBackendOptions()['user']);
- $this->assertEquals('somepassword', $storage2->getBackendOptions()['password']);
- $this->assertEquals(['preview' => true], $storage2->getMountOptions());
+ $this->service->getStorage($newStorage->getId());
}
}
diff --git a/apps/files_external/tests/storageconfigtest.php b/apps/files_external/tests/storageconfigtest.php
index c987f7a84e2..d7f8d2b4d7d 100644
--- a/apps/files_external/tests/storageconfigtest.php
+++ b/apps/files_external/tests/storageconfigtest.php
@@ -1,9 +1,9 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/ajax/external.php b/apps/files_sharing/ajax/external.php
index 0f8a3d56cf0..1efe4356b4c 100644
--- a/apps/files_sharing/ajax/external.php
+++ b/apps/files_sharing/ajax/external.php
@@ -8,7 +8,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -40,6 +40,7 @@ if (OCA\Files_Sharing\Helper::isIncomingServer2serverShareEnabled() === false) {
$token = $_POST['token'];
$remote = $_POST['remote'];
$owner = $_POST['owner'];
+$ownerDisplayName = $_POST['ownerDisplayName'];
$name = $_POST['name'];
$password = $_POST['password'];
@@ -49,6 +50,14 @@ if(!\OCP\Util::isValidFileName($name)) {
exit();
}
+$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
+$currentServer = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
+if (\OC\Share\Helper::isSameUserOnSameServer($owner, $remote, $currentUser, $currentServer )) {
+ \OCP\JSON::error(array('data' => array('message' => $l->t('Not allowed to create a federated share with the same user server'))));
+ exit();
+}
+
+
$externalManager = new \OCA\Files_Sharing\External\Manager(
\OC::$server->getDatabaseConnection(),
\OC\Files\Filesystem::getMountManager(),
@@ -68,7 +77,7 @@ if (substr($remote, 0, 5) === 'https') {
}
}
-$mount = $externalManager->addShare($remote, $token, $password, $name, $owner, true);
+$mount = $externalManager->addShare($remote, $token, $password, $name, $ownerDisplayName, true);
/**
* @var \OCA\Files_Sharing\External\Storage $storage
diff --git a/apps/files_sharing/ajax/list.php b/apps/files_sharing/ajax/list.php
deleted file mode 100644
index c7f0bde5d4a..00000000000
--- a/apps/files_sharing/ajax/list.php
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <rullzer@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-OCP\JSON::checkAppEnabled('files_sharing');
-
-if(!isset($_GET['t'])){
- \OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
- \OCP\Util::writeLog('core-preview', 'No token parameter was passed', \OCP\Util::DEBUG);
- exit;
-}
-
-$token = $_GET['t'];
-
-$password = null;
-if (isset($_POST['password'])) {
- $password = $_POST['password'];
-}
-
-$relativePath = null;
-if (isset($_GET['dir'])) {
- $relativePath = $_GET['dir'];
-}
-
-$sortAttribute = isset( $_GET['sort'] ) ? $_GET['sort'] : 'name';
-$sortDirection = isset( $_GET['sortdirection'] ) ? ($_GET['sortdirection'] === 'desc') : false;
-
-$data = \OCA\Files_Sharing\Helper::setupFromToken($token, $relativePath, $password);
-
-$linkItem = $data['linkItem'];
-// Load the files
-$dir = $data['realPath'];
-
-$dir = \OC\Files\Filesystem::normalizePath($dir);
-if (!\OC\Files\Filesystem::is_dir($dir . '/')) {
- \OC_Response::setStatus(\OC_Response::STATUS_NOT_FOUND);
- \OCP\JSON::error(array('success' => false));
- exit();
-}
-
-$data = array();
-
-// make filelist
-$files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection);
-
-$formattedFiles = array();
-foreach ($files as $file) {
- $entry = \OCA\Files\Helper::formatFileInfo($file);
- // for now
- unset($entry['directory']);
- // do not disclose share owner
- unset($entry['shareOwner']);
- // do not disclose if something is a remote shares
- unset($entry['mountType']);
- unset($entry['icon']);
- $entry['permissions'] = \OCP\Constants::PERMISSION_READ;
- $formattedFiles[] = $entry;
-}
-
-$data['directory'] = $relativePath;
-$data['files'] = $formattedFiles;
-$data['dirToken'] = $linkItem['token'];
-
-$permissions = $linkItem['permissions'];
-
-// if globally disabled
-if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') {
- // only allow reading
- $permissions = \OCP\Constants::PERMISSION_READ;
-}
-
-$data['permissions'] = $permissions;
-
-OCP\JSON::success(array('data' => $data));
diff --git a/apps/files_sharing/ajax/publicpreview.php b/apps/files_sharing/ajax/publicpreview.php
index 2902969b21f..ac48ee01913 100644
--- a/apps/files_sharing/ajax/publicpreview.php
+++ b/apps/files_sharing/ajax/publicpreview.php
@@ -7,7 +7,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/ajax/shareinfo.php b/apps/files_sharing/ajax/shareinfo.php
index db6194d3f05..e531e84ebbc 100644
--- a/apps/files_sharing/ajax/shareinfo.php
+++ b/apps/files_sharing/ajax/shareinfo.php
@@ -5,7 +5,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/api/local.php b/apps/files_sharing/api/local.php
index bb5136a0c99..7d59d68ca6f 100644
--- a/apps/files_sharing/api/local.php
+++ b/apps/files_sharing/api/local.php
@@ -2,13 +2,14 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -64,9 +65,10 @@ class Local {
if ($shares === false) {
return new \OC_OCS_Result(null, 404, 'could not get shares');
} else {
+ $mimetypeDetector = \OC::$server->getMimeTypeDetector();
foreach ($shares as &$share) {
if ($share['item_type'] === 'file' && isset($share['path'])) {
- $share['mimetype'] = \OC_Helper::getFileNameMimeType($share['path']);
+ $share['mimetype'] = $mimetypeDetector->detectPath($share['path']);
if (\OC::$server->getPreviewManager()->isMimeSupported($share['mimetype'])) {
$share['isPreviewAvailable'] = true;
}
@@ -227,12 +229,14 @@ class Local {
private static function getFilesSharedWithMe() {
try {
$shares = \OCP\Share::getItemsSharedWith('file');
+ $mimetypeDetector = \OC::$server->getMimeTypeDetector();
foreach ($shares as &$share) {
if ($share['item_type'] === 'file') {
- $share['mimetype'] = \OC_Helper::getFileNameMimeType($share['file_target']);
+ $share['mimetype'] = $mimetypeDetector->detectPath($share['file_target']);
if (\OC::$server->getPreviewManager()->isMimeSupported($share['mimetype'])) {
$share['isPreviewAvailable'] = true;
}
+ unset($share['path']);
}
}
$result = new \OC_OCS_Result($shares);
diff --git a/apps/files_sharing/api/ocssharewrapper.php b/apps/files_sharing/api/ocssharewrapper.php
index 3ce2901dfb4..9f63e864cec 100644
--- a/apps/files_sharing/api/ocssharewrapper.php
+++ b/apps/files_sharing/api/ocssharewrapper.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,33 +26,22 @@ class OCSShareWrapper {
* @return Share20OCS
*/
private function getShare20OCS() {
- return new Share20OCS(new \OC\Share20\Manager(
- \OC::$server->getUserSession()->getUser(),
- \OC::$server->getUserManager(),
- \OC::$server->getGroupManager(),
- \OC::$server->getLogger(),
- \OC::$server->getAppConfig(),
- \OC::$server->getUserFolder(),
- new \OC\Share20\DefaultShareProvider(
- \OC::$server->getDatabaseConnection(),
- \OC::$server->getUserManager(),
- \OC::$server->getGroupManager(),
- \OC::$server->getUserFolder()
- )
- ),
- \OC::$server->getGroupManager(),
- \OC::$server->getUserManager(),
- \OC::$server->getRequest(),
- \OC::$server->getUserFolder(),
- \OC::$server->getURLGenerator());
+ return new Share20OCS(
+ \OC::$server->getShareManager(),
+ \OC::$server->getGroupManager(),
+ \OC::$server->getUserManager(),
+ \OC::$server->getRequest(),
+ \OC::$server->getRootFolder(),
+ \OC::$server->getURLGenerator(),
+ \OC::$server->getUserSession()->getUser());
}
public function getAllShares($params) {
- return \OCA\Files_Sharing\API\Local::getAllShares($params);
+ return $this->getShare20OCS()->getShares();
}
- public function createShare($params) {
- return \OCA\Files_Sharing\API\Local::createShare($params);
+ public function createShare() {
+ return $this->getShare20OCS()->createShare();
}
public function getShare($params) {
@@ -61,7 +50,8 @@ class OCSShareWrapper {
}
public function updateShare($params) {
- return \OCA\Files_Sharing\API\Local::updateShare($params);
+ $id = $params['id'];
+ return $this->getShare20OCS()->updateShare($id);
}
public function deleteShare($params) {
diff --git a/apps/files_sharing/api/remote.php b/apps/files_sharing/api/remote.php
index 41ebb6e2eab..06b2e6c1687 100644
--- a/apps/files_sharing/api/remote.php
+++ b/apps/files_sharing/api/remote.php
@@ -1,9 +1,10 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -98,7 +99,7 @@ class Remote {
*/
private static function extendShareInfo($share) {
$view = new \OC\Files\View('/' . \OC_User::getUser() . '/files/');
- $info = $view->getFileInfo($shares['mountpoint']);
+ $info = $view->getFileInfo($share['mountpoint']);
$share['mimetype'] = $info->getMimetype();
$share['mtime'] = $info->getMtime();
diff --git a/apps/files_sharing/api/server2server.php b/apps/files_sharing/api/server2server.php
index 93998ad774e..e1195cb9573 100644
--- a/apps/files_sharing/api/server2server.php
+++ b/apps/files_sharing/api/server2server.php
@@ -6,7 +6,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php
index aaf5a3c72b6..d7c5d004d9c 100644
--- a/apps/files_sharing/api/share20ocs.php
+++ b/apps/files_sharing/api/share20ocs.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,80 +20,107 @@
*/
namespace OCA\Files_Sharing\API;
-use OC\Share20\IShare;
+use OCP\IGroupManager;
+use OCP\IUserManager;
+use OCP\IRequest;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\Files\IRootFolder;
+use OCP\Share\IManager;
+
+use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\Exceptions\GenericShareException;
class Share20OCS {
- /** @var \OC\Share20\Manager */
+ /** @var IManager */
private $shareManager;
-
- /** @var \OCP\IGroupManager */
+ /** @var IGroupManager */
private $groupManager;
-
- /** @var \OCP\IUserManager */
+ /** @var IUserManager */
private $userManager;
-
- /** @var \OCP\IRequest */
+ /** @var IRequest */
private $request;
+ /** @var IRootFolder */
+ private $rootFolder;
+ /** @var IUrlGenerator */
+ private $urlGenerator;
+ /** @var IUser */
+ private $currentUser;
- /** @var \OCP\Files\Folder */
- private $userFolder;
-
- public function __construct(\OC\Share20\Manager $shareManager,
- \OCP\IGroupManager $groupManager,
- \OCP\IUserManager $userManager,
- \OCP\IRequest $request,
- \OCP\Files\Folder $userFolder,
- \OCP\IURLGenerator $urlGenerator) {
+ /**
+ * Share20OCS constructor.
+ *
+ * @param IManager $shareManager
+ * @param IGroupManager $groupManager
+ * @param IUserManager $userManager
+ * @param IRequest $request
+ * @param IRootFolder $rootFolder
+ * @param IURLGenerator $urlGenerator
+ * @param IUser $currentUser
+ */
+ public function __construct(
+ IManager $shareManager,
+ IGroupManager $groupManager,
+ IUserManager $userManager,
+ IRequest $request,
+ IRootFolder $rootFolder,
+ IURLGenerator $urlGenerator,
+ IUser $currentUser
+ ) {
$this->shareManager = $shareManager;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->request = $request;
- $this->userFolder = $userFolder;
+ $this->rootFolder = $rootFolder;
$this->urlGenerator = $urlGenerator;
+ $this->currentUser = $currentUser;
}
/**
* Convert an IShare to an array for OCS output
*
- * @param IShare $share
+ * @param \OCP\Share\IShare $share
* @return array
*/
- protected function formatShare($share) {
+ protected function formatShare(\OCP\Share\IShare $share) {
+ $sharedBy = $this->userManager->get($share->getSharedBy());
+ $shareOwner = $this->userManager->get($share->getShareOwner());
$result = [
'id' => $share->getId(),
'share_type' => $share->getShareType(),
- 'uid_owner' => $share->getSharedBy()->getUID(),
- 'displayname_owner' => $share->getSharedBy()->getDisplayName(),
+ 'uid_owner' => $share->getSharedBy(),
+ 'displayname_owner' => $sharedBy->getDisplayName(),
'permissions' => $share->getPermissions(),
- 'stime' => $share->getShareTime(),
- 'parent' => $share->getParent(),
+ 'stime' => $share->getShareTime()->getTimestamp(),
+ 'parent' => null,
'expiration' => null,
'token' => null,
+ 'uid_file_owner' => $share->getShareOwner(),
+ 'displayname_file_owner' => $shareOwner->getDisplayName(),
];
- $path = $share->getPath();
- $result['path'] = $this->userFolder->getRelativePath($path->getPath());
- if ($path instanceOf \OCP\Files\Folder) {
+ $node = $share->getNode();
+ $result['path'] = $this->rootFolder->getUserFolder($share->getShareOwner())->getRelativePath($node->getPath());
+ if ($node instanceOf \OCP\Files\Folder) {
$result['item_type'] = 'folder';
} else {
$result['item_type'] = 'file';
}
- $result['storage_id'] = $path->getStorage()->getId();
- $result['storage'] = \OC\Files\Cache\Storage::getNumericStorageId($path->getStorage()->getId());
- $result['item_source'] = $path->getId();
- $result['file_source'] = $path->getId();
- $result['file_parent'] = $path->getParent()->getId();
+ $result['storage_id'] = $node->getStorage()->getId();
+ $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
+ $result['item_source'] = $node->getId();
+ $result['file_source'] = $node->getId();
+ $result['file_parent'] = $node->getParent()->getId();
$result['file_target'] = $share->getTarget();
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
- $sharedWith = $share->getSharedWith();
+ $sharedWith = $this->userManager->get($share->getSharedWith());
$result['share_with'] = $sharedWith->getUID();
$result['share_with_displayname'] = $sharedWith->getDisplayName();
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
- $sharedWith = $share->getSharedWith();
- $result['share_with'] = $sharedWith->getGID();
- $result['share_with_displayname'] = $sharedWith->getGID();
+ $result['share_with'] = $share->getSharedWith();
+ $result['share_with_displayname'] = $share->getSharedWith();
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
$result['share_with'] = $share->getPassword();
@@ -125,14 +152,28 @@ class Share20OCS {
* @return \OC_OCS_Result
*/
public function getShare($id) {
+ // Try both our default, and our federated provider..
+ $share = null;
+
+ // First check if it is an internal share.
try {
- $share = $this->shareManager->getShareById($id);
- } catch (\OC\Share20\Exception\ShareNotFound $e) {
- return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
+ $share = $this->shareManager->getShareById('ocinternal:'.$id);
+ } catch (ShareNotFound $e) {
+ // Ignore for now
+ //return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
}
- $share = $this->formatShare($share);
- return new \OC_OCS_Result($share);
+ if ($share === null) {
+ //For now federated shares are handled by the old endpoint.
+ return \OCA\Files_Sharing\API\Local::getShare(['id' => $id]);
+ }
+
+ if ($this->canAccessShare($share)) {
+ $share = $this->formatShare($share);
+ return new \OC_OCS_Result($share);
+ } else {
+ return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
+ }
}
/**
@@ -142,26 +183,424 @@ class Share20OCS {
* @return \OC_OCS_Result
*/
public function deleteShare($id) {
+ // Try both our default and our federated provider
+ $share = null;
+
try {
- $share = $this->shareManager->getShareById($id);
- } catch (\OC\Share20\Exception\ShareNotFound $e) {
- return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
+ $share = $this->shareManager->getShareById('ocinternal:' . $id);
+ } catch (ShareNotFound $e) {
+ //Ignore for now
+ //return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
+ }
+
+ // Could not find the share as internal share... maybe it is a federated share
+ if ($share === null) {
+ return \OCA\Files_Sharing\API\Local::deleteShare(['id' => $id]);
+ }
+
+ if (!$this->canAccessShare($share)) {
+ return new \OC_OCS_Result(null, 404, 'could not delete share');
+ }
+
+ $this->shareManager->deleteShare($share);
+
+ return new \OC_OCS_Result();
+ }
+
+ /**
+ * @return \OC_OCS_Result
+ */
+ public function createShare() {
+ $share = $this->shareManager->newShare();
+
+ // Verify path
+ $path = $this->request->getParam('path', null);
+ if ($path === null) {
+ return new \OC_OCS_Result(null, 404, 'please specify a file or folder path');
+ }
+
+ $userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
+ try {
+ $path = $userFolder->get($path);
+ } catch (\OCP\Files\NotFoundException $e) {
+ return new \OC_OCS_Result(null, 404, 'wrong path, file/folder doesn\'t exist');
+ }
+
+ $share->setNode($path);
+
+ // Parse permissions (if available)
+ $permissions = $this->request->getParam('permissions', null);
+ if ($permissions === null) {
+ $permissions = \OCP\Constants::PERMISSION_ALL;
+ } else {
+ $permissions = (int)$permissions;
+ }
+
+ if ($permissions < 0 || $permissions > \OCP\Constants::PERMISSION_ALL) {
+ return new \OC_OCS_Result(null, 404, 'invalid permissions');
+ }
+
+ // Shares always require read permissions
+ $permissions |= \OCP\Constants::PERMISSION_READ;
+
+ if ($path instanceof \OCP\Files\File) {
+ // Single file shares should never have delete or create permissions
+ $permissions &= ~\OCP\Constants::PERMISSION_DELETE;
+ $permissions &= ~\OCP\Constants::PERMISSION_CREATE;
+ }
+
+ $shareWith = $this->request->getParam('shareWith', null);
+ $shareType = (int)$this->request->getParam('shareType', '-1');
+
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
+ // Valid user is required to share
+ if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
+ return new \OC_OCS_Result(null, 404, 'please specify a valid user');
+ }
+ $share->setSharedWith($shareWith);
+ $share->setPermissions($permissions);
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
+ // Valid group is required to share
+ if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
+ return new \OC_OCS_Result(null, 404, 'please specify a valid group');
+ }
+ $share->setSharedWith($shareWith);
+ $share->setPermissions($permissions);
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
+ //Can we even share links?
+ if (!$this->shareManager->shareApiAllowLinks()) {
+ return new \OC_OCS_Result(null, 404, 'public link sharing is disabled by the administrator');
+ }
+
+ $publicUpload = $this->request->getParam('publicUpload', null);
+ if ($publicUpload === 'true') {
+ // Check if public upload is allowed
+ if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
+ return new \OC_OCS_Result(null, 403, 'public upload disabled by the administrator');
+ }
+
+ // Public upload can only be set for folders
+ if ($path instanceof \OCP\Files\File) {
+ return new \OC_OCS_Result(null, 404, 'public upload is only possible for public shared folders');
+ }
+
+ $share->setPermissions(
+ \OCP\Constants::PERMISSION_READ |
+ \OCP\Constants::PERMISSION_CREATE |
+ \OCP\Constants::PERMISSION_UPDATE
+ );
+ } else {
+ $share->setPermissions(\OCP\Constants::PERMISSION_READ);
+ }
+
+ // Set password
+ $password = $this->request->getParam('password', '');
+
+ if ($password !== '') {
+ $share->setPassword($password);
+ }
+
+ //Expire date
+ $expireDate = $this->request->getParam('expireDate', '');
+
+ if ($expireDate !== '') {
+ try {
+ $expireDate = $this->parseDate($expireDate);
+ $share->setExpirationDate($expireDate);
+ } catch (\Exception $e) {
+ return new \OC_OCS_Result(null, 404, 'Invalid Date. Format must be YYYY-MM-DD.');
+ }
+ }
+
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
+ //fixme Remote shares are handled by old code path for now
+ return \OCA\Files_Sharing\API\Local::createShare([]);
+ } else {
+ return new \OC_OCS_Result(null, 400, "unknown share type");
+ }
+
+ $share->setShareType($shareType);
+ $share->setSharedBy($this->currentUser->getUID());
+
+ try {
+ $share = $this->shareManager->createShare($share);
+ } catch (GenericShareException $e) {
+ $code = $e->getCode() === 0 ? 403 : $e->getCode();
+ return new \OC_OCS_Result(null, $code, $e->getHint());
+ }catch (\Exception $e) {
+ return new \OC_OCS_Result(null, 403, $e->getMessage());
+ }
+
+ $share = $this->formatShare($share);
+ return new \OC_OCS_Result($share);
+ }
+
+ /**
+ * @param \OCP\Files\File|\OCP\Files\Folder $node
+ * @return \OC_OCS_Result
+ */
+ private function getSharedWithMe($node = null) {
+ $userShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
+ $groupShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
+
+ $shares = array_merge($userShares, $groupShares);
+
+ $formatted = [];
+ foreach ($shares as $share) {
+ if ($this->canAccessShare($share)) {
+ $formatted[] = $this->formatShare($share);
+ }
+ }
+
+ return new \OC_OCS_Result($formatted);
+ }
+
+ /**
+ * @param \OCP\Files\Folder $folder
+ * @return \OC_OCS_Result
+ */
+ private function getSharesInDir($folder) {
+ if (!($folder instanceof \OCP\Files\Folder)) {
+ return new \OC_OCS_Result(null, 400, "not a directory");
}
+ $nodes = $folder->getDirectoryListing();
+ /** @var \OCP\Share\IShare[] $shares */
+ $shares = [];
+ foreach ($nodes as $node) {
+ $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, false, -1, 0));
+ $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
+ $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $node, false, -1, 0));
+ //TODO: Add federated shares
+
+ }
+
+ $formatted = [];
+ foreach ($shares as $share) {
+ $formatted[] = $this->formatShare($share);
+ }
+
+ return new \OC_OCS_Result($formatted);
+ }
+
+ /**
+ * The getShares function.
+ *
+ * - Get shares by the current user
+ * - Get shares by the current user and reshares (?reshares=true)
+ * - Get shares with the current user (?shared_with_me=true)
+ * - Get shares for a specific path (?path=...)
+ * - Get all shares in a folder (?subfiles=true&path=..)
+ *
+ * @return \OC_OCS_Result
+ */
+ public function getShares() {
+ $sharedWithMe = $this->request->getParam('shared_with_me', null);
+ $reshares = $this->request->getParam('reshares', null);
+ $subfiles = $this->request->getParam('subfiles');
+ $path = $this->request->getParam('path', null);
+
+ if ($path !== null) {
+ $userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
+ try {
+ $path = $userFolder->get($path);
+ } catch (\OCP\Files\NotFoundException $e) {
+ return new \OC_OCS_Result(null, 404, 'wrong path, file/folder doesn\'t exist');
+ }
+ }
+
+ if ($sharedWithMe === 'true') {
+ return $this->getSharedWithMe($path);
+ }
+
+ if ($subfiles === 'true') {
+ return $this->getSharesInDir($path);
+ }
+
+ if ($reshares === 'true') {
+ $reshares = true;
+ } else {
+ $reshares = false;
+ }
+
+ // Get all shares
+ $userShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
+ $groupShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
+ $linkShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
+ //TODO: Add federated shares
+
+ $shares = array_merge($userShares, $groupShares, $linkShares);
+
+ $formatted = [];
+ foreach ($shares as $share) {
+ $formatted[] = $this->formatShare($share);
+ }
+
+ return new \OC_OCS_Result($formatted);
+ }
+
+ /**
+ * @param int $id
+ * @return \OC_OCS_Result
+ */
+ public function updateShare($id) {
+ // Try both our default and our federated provider
+ $share = null;
+
+ try {
+ $share = $this->shareManager->getShareById('ocinternal:' . $id);
+ } catch (ShareNotFound $e) {
+ //Ignore for now
+ //return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
+ }
+
+ // Could not find the share as internal share... maybe it is a federated share
+ if ($share === null) {
+ return \OCA\Files_Sharing\API\Local::updateShare(['id' => $id]);
+ }
+
+ if (!$this->canAccessShare($share)) {
+ return new \OC_OCS_Result(null, 404, 'wrong share Id, share doesn\'t exist.');
+ }
+
+ $permissions = $this->request->getParam('permissions', null);
+ $password = $this->request->getParam('password', null);
+ $publicUpload = $this->request->getParam('publicUpload', null);
+ $expireDate = $this->request->getParam('expireDate', null);
+
/*
- * FIXME
- * User the old code path for remote shares until we have our remoteshareprovider
+ * expirationdate, password and publicUpload only make sense for link shares
*/
- if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
- \OCA\Files_Sharing\API\Local::deleteShare(['id' => $id]);
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null) {
+ return new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given');
+ }
+
+ $newPermissions = null;
+ if ($publicUpload === 'true') {
+ $newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE;
+ } else if ($publicUpload === 'false') {
+ $newPermissions = \OCP\Constants::PERMISSION_READ;
+ }
+
+ if ($permissions !== null) {
+ $newPermissions = (int)$permissions;
+ }
+
+ if ($newPermissions !== null &&
+ $newPermissions !== \OCP\Constants::PERMISSION_READ &&
+ $newPermissions !== (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE)) {
+ return new \OC_OCS_Result(null, 400, 'can\'t change permission for public link share');
+ }
+
+ if ($newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE)) {
+ if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
+ return new \OC_OCS_Result(null, 403, 'public upload disabled by the administrator');
+ }
+
+ if (!($share->getNode() instanceof \OCP\Files\Folder)) {
+ return new \OC_OCS_Result(null, 400, "public upload is only possible for public shared folders");
+ }
+ }
+
+ if ($newPermissions !== null) {
+ $share->setPermissions($newPermissions);
+ }
+
+ if ($expireDate === '') {
+ $share->setExpirationDate(null);
+ } else if ($expireDate !== null) {
+ try {
+ $expireDate = $this->parseDate($expireDate);
+ } catch (\Exception $e) {
+ return new \OC_OCS_Result(null, 400, $e->getMessage());
+ }
+ $share->setExpirationDate($expireDate);
+ }
+
+ if ($password === '') {
+ $share->setPassword(null);
+ } else if ($password !== null) {
+ $share->setPassword($password);
+ }
+
+ } else {
+ // For other shares only permissions is valid.
+ if ($permissions === null) {
+ return new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given');
+ } else {
+ $permissions = (int)$permissions;
+ $share->setPermissions($permissions);
+ }
}
+
+
try {
- $this->shareManager->deleteShare($share);
- } catch (\OC\Share20\Exception\BackendError $e) {
- return new \OC_OCS_Result(null, 404, 'could not delete share');
+ $share = $this->shareManager->updateShare($share);
+ } catch (\Exception $e) {
+ return new \OC_OCS_Result(null, 400, $e->getMessage());
}
- return new \OC_OCS_Result();
+ return new \OC_OCS_Result($this->formatShare($share));
+ }
+
+ /**
+ * @param \OCP\Share\IShare $share
+ * @return bool
+ */
+ protected function canAccessShare(\OCP\Share\IShare $share) {
+ // A file with permissions 0 can't be accessed by us. So Don't show it
+ if ($share->getPermissions() === 0) {
+ return false;
+ }
+
+ // Owner of the file and the sharer of the file can always get share
+ if ($share->getShareOwner() === $this->currentUser->getUID() ||
+ $share->getSharedBy() === $this->currentUser->getUID()
+ ) {
+ return true;
+ }
+
+ // If the share is shared with you (or a group you are a member of)
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
+ $share->getSharedWith() === $this->currentUser->getUID()) {
+ return true;
+ }
+
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ $sharedWith = $this->groupManager->get($share->getSharedWith());
+ if ($sharedWith->inGroup($this->currentUser)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Make sure that the passed date is valid ISO 8601
+ * So YYYY-MM-DD
+ * If not throw an exception
+ *
+ * @param string $expireDate
+ *
+ * @throws \Exception
+ * @return \DateTime
+ */
+ private function parseDate($expireDate) {
+ try {
+ $date = new \DateTime($expireDate);
+ } catch (\Exception $e) {
+ throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
+ }
+
+ if ($date === false) {
+ throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
+ }
+
+ $date->setTime(0,0,0);
+
+ return $date;
}
}
diff --git a/apps/files_sharing/api/sharees.php b/apps/files_sharing/api/sharees.php
index 21f68d9b253..85cea2e4238 100644
--- a/apps/files_sharing/api/sharees.php
+++ b/apps/files_sharing/api/sharees.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -120,6 +120,7 @@ class Sharees {
protected function getUsers($search) {
$this->result['users'] = $this->result['exact']['users'] = $users = [];
+ $userGroups = [];
if ($this->shareWithGroupOnly) {
// Search in all the groups this user is part of
$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
@@ -171,13 +172,23 @@ class Sharees {
// user id and if so, we add that to the exact match list
$user = $this->userManager->get($search);
if ($user instanceof IUser) {
- array_push($this->result['exact']['users'], [
- 'label' => $user->getDisplayName(),
- 'value' => [
- 'shareType' => Share::SHARE_TYPE_USER,
- 'shareWith' => $user->getUID(),
- ],
- ]);
+ $addUser = true;
+
+ if ($this->shareWithGroupOnly) {
+ // Only add, if we have a common group
+ $commonGroups = array_intersect($userGroups, $this->groupManager->getUserGroupIds($user));
+ $addUser = !empty($commonGroups);
+ }
+
+ if ($addUser) {
+ array_push($this->result['exact']['users'], [
+ 'label' => $user->getDisplayName(),
+ 'value' => [
+ 'shareType' => Share::SHARE_TYPE_USER,
+ 'shareWith' => $user->getUID(),
+ ],
+ ]);
+ }
}
}
@@ -259,8 +270,15 @@ class Sharees {
$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
$foundRemoteById = false;
foreach ($addressBookContacts as $contact) {
+ if (isset($contact['isLocalSystemBook'])) {
+ continue;
+ }
if (isset($contact['CLOUD'])) {
- foreach ($contact['CLOUD'] as $cloudId) {
+ $cloudIds = $contact['CLOUD'];
+ if (!is_array($cloudIds)) {
+ $cloudIds = [$cloudIds];
+ }
+ foreach ($cloudIds as $cloudId) {
if (strtolower($contact['FN']) === $search || strtolower($cloudId) === $search) {
if (strtolower($cloudId) === $search) {
$foundRemoteById = true;
@@ -342,7 +360,7 @@ class Sharees {
$this->limit = (int) $perPage;
$this->offset = $perPage * ($page - 1);
- return $this->searchSharees(strtolower($search), $itemType, $shareTypes, $page, $perPage);
+ return $this->searchSharees($search, $itemType, $shareTypes, $page, $perPage);
}
/**
diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php
index 03e448be0af..7a418d179db 100644
--- a/apps/files_sharing/appinfo/app.php
+++ b/apps/files_sharing/appinfo/app.php
@@ -6,9 +6,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -42,7 +43,6 @@ $l = \OC::$server->getL10N('files_sharing');
$application = new Application();
$application->registerMountProviders();
-$application->setupPropagation();
\OCP\App::registerAdmin('files_sharing', 'settings-admin');
\OCP\App::registerPersonal('files_sharing', 'settings-personal');
@@ -58,7 +58,9 @@ $eventDispatcher->addListener(
function() {
\OCP\Util::addScript('files_sharing', 'share');
\OCP\Util::addScript('files_sharing', 'sharetabview');
- \OCP\Util::addScript('files_sharing', 'external');
+ if (\OC::$server->getConfig()->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'yes') {
+ \OCP\Util::addScript('files_sharing', 'external');
+ }
\OCP\Util::addStyle('files_sharing', 'sharetabview');
}
);
diff --git a/apps/files_sharing/appinfo/application.php b/apps/files_sharing/appinfo/application.php
index 545a9425083..e4a2262fece 100644
--- a/apps/files_sharing/appinfo/application.php
+++ b/apps/files_sharing/appinfo/application.php
@@ -4,9 +4,8 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,10 +24,7 @@
namespace OCA\Files_Sharing\AppInfo;
-use OCA\Files_Sharing\Helper;
use OCA\Files_Sharing\MountProvider;
-use OCA\Files_Sharing\Propagation\PropagationManager;
-use OCA\Files_Sharing\Propagation\GroupPropagationManager;
use OCP\AppFramework\App;
use OC\AppFramework\Utility\SimpleContainer;
use OCA\Files_Sharing\Controllers\ExternalSharesController;
@@ -51,13 +47,15 @@ class Application extends App {
return new ShareController(
$c->query('AppName'),
$c->query('Request'),
- $c->query('UserSession'),
- $server->getAppConfig(),
$server->getConfig(),
- $c->query('URLGenerator'),
- $c->query('UserManager'),
+ $server->getURLGenerator(),
+ $server->getUserManager(),
$server->getLogger(),
- $server->getActivityManager()
+ $server->getActivityManager(),
+ $server->getShareManager(),
+ $server->getSession(),
+ $server->getPreviewManager(),
+ $server->getRootFolder()
);
});
$container->registerService('ExternalSharesController', function (SimpleContainer $c) {
@@ -72,15 +70,6 @@ class Application extends App {
/**
* Core class wrappers
*/
- $container->registerService('UserSession', function (SimpleContainer $c) use ($server) {
- return $server->getUserSession();
- });
- $container->registerService('URLGenerator', function (SimpleContainer $c) use ($server) {
- return $server->getUrlGenerator();
- });
- $container->registerService('UserManager', function (SimpleContainer $c) use ($server) {
- return $server->getUserManager();
- });
$container->registerService('HttpClientService', function (SimpleContainer $c) use ($server) {
return $server->getHTTPClientService();
});
@@ -116,8 +105,7 @@ class Application extends App {
/** @var \OCP\IServerContainer $server */
$server = $c->query('ServerContainer');
return new MountProvider(
- $server->getConfig(),
- $c->query('PropagationManager')
+ $server->getConfig()
);
});
@@ -132,25 +120,6 @@ class Application extends App {
);
});
- $container->registerService('PropagationManager', function (IContainer $c) {
- /** @var \OCP\IServerContainer $server */
- $server = $c->query('ServerContainer');
- return new PropagationManager(
- $server->getUserSession(),
- $server->getConfig()
- );
- });
-
- $container->registerService('GroupPropagationManager', function (IContainer $c) {
- /** @var \OCP\IServerContainer $server */
- $server = $c->query('ServerContainer');
- return new GroupPropagationManager(
- $server->getUserSession(),
- $server->getGroupManager(),
- $c->query('PropagationManager')
- );
- });
-
/*
* Register capabilities
*/
@@ -164,11 +133,4 @@ class Application extends App {
$mountProviderCollection->registerProvider($this->getContainer()->query('MountProvider'));
$mountProviderCollection->registerProvider($this->getContainer()->query('ExternalMountProvider'));
}
-
- public function setupPropagation() {
- $propagationManager = $this->getContainer()->query('PropagationManager');
- \OCP\Util::connectHook('OC_Filesystem', 'setup', $propagationManager, 'globalSetup');
-
- $this->getContainer()->query('GroupPropagationManager')->globalSetup();
- }
}
diff --git a/apps/files_sharing/appinfo/info.xml b/apps/files_sharing/appinfo/info.xml
index 72e56456961..17826be47b4 100644
--- a/apps/files_sharing/appinfo/info.xml
+++ b/apps/files_sharing/appinfo/info.xml
@@ -9,14 +9,13 @@ Turning the feature off removes shared files and folders on the server for all s
</description>
<licence>AGPL</licence>
<author>Michael Gapczynski, Bjoern Schiessle</author>
- <shipped>true</shipped>
<default_enable/>
- <version>0.8.1</version>
+ <version>0.9.0</version>
<types>
<filesystem/>
</types>
<dependencies>
- <owncloud min-version="9.0" />
+ <owncloud min-version="9.0" max-version="9.0" />
</dependencies>
<public>
<files>public.php</files>
diff --git a/apps/files_sharing/appinfo/install.php b/apps/files_sharing/appinfo/install.php
index 5185ae883f3..33bbc8e2a84 100644
--- a/apps/files_sharing/appinfo/install.php
+++ b/apps/files_sharing/appinfo/install.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php
index 8755691c1e8..961206079be 100644
--- a/apps/files_sharing/appinfo/routes.php
+++ b/apps/files_sharing/appinfo/routes.php
@@ -8,7 +8,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/appinfo/update.php b/apps/files_sharing/appinfo/update.php
index 8bff20cc442..d754a95705c 100644
--- a/apps/files_sharing/appinfo/update.php
+++ b/apps/files_sharing/appinfo/update.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,10 +24,11 @@ use OCA\Files_Sharing\Migration;
$installedVersion = \OC::$server->getConfig()->getAppValue('files_sharing', 'installed_version');
-// Migration OC7 -> OC8
-if (version_compare($installedVersion, '0.6.0', '<')) {
- $m = new Migration();
- $m->addAcceptRow();
+// Migration OC8.2 -> OC9
+if (version_compare($installedVersion, '0.9.0', '<')) {
+ $m = new Migration(\OC::$server->getDatabaseConnection());
+ $m->removeReShares();
+ $m->updateInitiatorInfo();
}
\OC::$server->getJobList()->add('OCA\Files_sharing\Lib\DeleteOrphanedSharesJob');
diff --git a/apps/files_sharing/css/sharetabview.css b/apps/files_sharing/css/sharetabview.css
index 7597004e684..642c0909af3 100644
--- a/apps/files_sharing/css/sharetabview.css
+++ b/apps/files_sharing/css/sharetabview.css
@@ -28,7 +28,7 @@
width: 94%;
margin-left: 0;
}
-.shareTabView #shareWith {
+.shareTabView input[type="text"].shareWithField {
width: 80%;
}
diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js
index 3168e930829..af198208de2 100644
--- a/apps/files_sharing/js/app.js
+++ b/apps/files_sharing/js/app.js
@@ -142,7 +142,7 @@ OCA.Sharing.App = {
// folder in the files app instead of opening it directly
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
OCA.Files.App.setActiveView('files', {silent: true});
- OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true);
+ OCA.Files.App.fileList.changeDirectory(OC.joinPaths(context.$file.attr('data-path'), filename), true, true);
});
fileActions.setDefault('dir', 'Open');
return fileActions;
diff --git a/apps/files_sharing/js/external.js b/apps/files_sharing/js/external.js
index f658de307ab..45a6ef02758 100644
--- a/apps/files_sharing/js/external.js
+++ b/apps/files_sharing/js/external.js
@@ -19,7 +19,7 @@
*/
OCA.Sharing.showAddExternalDialog = function (share, passwordProtected, callback) {
var remote = share.remote;
- var owner = share.owner;
+ var owner = share.ownerDisplayName || share.owner;
var name = share.name;
var remoteClean = (remote.substr(0, 8) === 'https://') ? remote.substr(8) : remote.substr(7);
@@ -92,6 +92,7 @@
remote: share.remote,
token: share.token,
owner: share.owner,
+ ownerDisplayName: share.ownerDisplayName || share.owner,
name: share.name,
password: password}, function(result) {
if (result.status === 'error') {
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
index 246b639f652..bc609f04f79 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -48,8 +48,20 @@ OCA.Sharing.PublicApp = {
this._initialized = true;
this.initialDir = $('#dir').val();
+ var token = $('#sharingToken').val();
+
// file list mode ?
if ($el.find('#filestable').length) {
+ var filesClient = new OC.Files.Client({
+ host: OC.getHost(),
+ port: OC.getPort(),
+ userName: token,
+ // note: password not be required, the endpoint
+ // will recognize previous validation from the session
+ root: OC.getRootPath() + '/public.php/webdav',
+ useHTTPS: OC.getProtocol() === 'https'
+ });
+
this.fileList = new OCA.Files.FileList(
$el,
{
@@ -58,7 +70,8 @@ OCA.Sharing.PublicApp = {
dragOptions: dragOptions,
folderDropOptions: folderDropOptions,
fileActions: fileActions,
- detailsViewEnabled: false
+ detailsViewEnabled: false,
+ filesClient: filesClient
}
);
this.files = OCA.Files.Files;
@@ -88,14 +101,13 @@ OCA.Sharing.PublicApp = {
// dynamically load image previews
- var token = $('#sharingToken').val();
var bottomMargin = 350;
- var previewWidth = Math.ceil($(window).width() * window.devicePixelRatio);
- var previewHeight = Math.ceil(($(window).height() - bottomMargin) * window.devicePixelRatio);
+ var previewWidth = $(window).width();
+ var previewHeight = $(window).height() - bottomMargin;
previewHeight = Math.max(200, previewHeight);
var params = {
- x: previewWidth,
- y: previewHeight,
+ x: Math.ceil(previewWidth * window.devicePixelRatio),
+ y: Math.ceil(previewHeight * window.devicePixelRatio),
a: 'true',
file: encodeURIComponent(this.initialDir + $('#filename').val()),
t: token,
@@ -103,6 +115,10 @@ OCA.Sharing.PublicApp = {
};
var img = $('<img class="publicpreview" alt="">');
+ img.css({
+ 'max-width': previewWidth,
+ 'max-height': previewHeight
+ });
var fileSize = parseInt($('#filesize').val(), 10);
var maxGifSize = parseInt($('#maxSizeAnimateGif').val(), 10);
@@ -136,11 +152,14 @@ OCA.Sharing.PublicApp = {
if (this.fileList) {
// TODO: move this to a separate PublicFileList class that extends OCA.Files.FileList (+ unit tests)
- this.fileList.getDownloadUrl = function (filename, dir) {
- if ($.isArray(filename)) {
+ this.fileList.getDownloadUrl = function (filename, dir, isDir) {
+ var path = dir || this.getCurrentDirectory();
+ if (filename && !_.isArray(filename) && !isDir) {
+ return OC.getProtocol() + '://' + token + '@' + OC.getHost() + OC.getRootPath() + '/public.php/webdav' + OC.joinPaths(path, filename);
+ }
+ if (_.isArray(filename)) {
filename = JSON.stringify(filename);
}
- var path = dir || FileList.getCurrentDirectory();
var params = {
path: path,
files: filename
@@ -223,9 +242,10 @@ OCA.Sharing.PublicApp = {
var remote = $(this).find('input[type="text"]').val();
var token = $('#sharingToken').val();
var owner = $('#save').data('owner');
+ var ownerDisplayName = $('#save').data('owner-display-name');
var name = $('#save').data('name');
var isProtected = $('#save').data('protected') ? 1 : 0;
- OCA.Sharing.PublicApp._saveToOwnCloud(remote, token, owner, name, isProtected);
+ OCA.Sharing.PublicApp._saveToOwnCloud(remote, token, owner, ownerDisplayName, name, isProtected);
});
$('#remote_address').on("keyup paste", function() {
@@ -272,11 +292,15 @@ OCA.Sharing.PublicApp = {
this.fileList.changeDirectory(params.path || params.dir, false, true);
},
- _saveToOwnCloud: function (remote, token, owner, name, isProtected) {
+ _saveToOwnCloud: function (remote, token, owner, ownerDisplayName, name, isProtected) {
var location = window.location.protocol + '//' + window.location.host + OC.webroot;
+
+ if(remote.substr(-1) !== '/') {
+ remote += '/'
+ };
- var url = remote + '/index.php/apps/files#' + 'remote=' + encodeURIComponent(location) // our location is the remote for the other server
- + "&token=" + encodeURIComponent(token) + "&owner=" + encodeURIComponent(owner) + "&name=" + encodeURIComponent(name) + "&protected=" + isProtected;
+ var url = remote + 'index.php/apps/files#' + 'remote=' + encodeURIComponent(location) // our location is the remote for the other server
+ + "&token=" + encodeURIComponent(token) + "&owner=" + encodeURIComponent(owner) +"&ownerDisplayName=" + encodeURIComponent(ownerDisplayName) + "&name=" + encodeURIComponent(name) + "&protected=" + isProtected;
if (remote.indexOf('://') > 0) {
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index 63225a0d8ec..f8d89828f4d 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -45,12 +45,15 @@
if (fileData.type === 'file') {
// files can't be shared with delete permissions
sharePermissions = sharePermissions & ~OC.PERMISSION_DELETE;
+
+ // create permissions don't mean anything for files
+ sharePermissions = sharePermissions & ~OC.PERMISSION_CREATE;
}
tr.attr('data-share-permissions', sharePermissions);
if (fileData.shareOwner) {
tr.attr('data-share-owner', fileData.shareOwner);
// user should always be able to rename a mount point
- if (fileData.isShareMountPoint) {
+ if (fileData.mountType === 'shared-root') {
tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE);
}
}
@@ -68,6 +71,26 @@
return fileInfo;
};
+ var NS_OC = 'http://owncloud.org/ns';
+
+ var oldGetWebdavProperties = fileList._getWebdavProperties;
+ fileList._getWebdavProperties = function() {
+ var props = oldGetWebdavProperties.apply(this, arguments);
+ props.push('{' + NS_OC + '}owner-display-name');
+ return props;
+ };
+
+ fileList.filesClient.addFileInfoParser(function(response) {
+ var data = {};
+ var props = response.propStat[0].properties;
+ var permissionsProp = props['{' + NS_OC + '}permissions'];
+
+ if (permissionsProp && permissionsProp.indexOf('S') >= 0) {
+ data.shareOwner = props['{' + NS_OC + '}owner-display-name'];
+ }
+ return data;
+ });
+
// use delegate to catch the case with multiple file lists
fileList.$el.on('fileActionsReady', function(ev){
var fileList = ev.fileList;
diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js
index 68bfd63ec89..a799d4a94c2 100644
--- a/apps/files_sharing/js/sharedfilelist.js
+++ b/apps/files_sharing/js/sharedfilelist.js
@@ -231,6 +231,7 @@
files = _.chain(files)
// convert share data to file data
.map(function(share) {
+ // TODO: use OC.Files.FileInfo
var file = {
id: share.file_source,
icon: OC.MimeType.getIconUrl(share.mimetype),
@@ -242,9 +243,6 @@
}
else {
file.type = 'file';
- if (share.isPreviewAvailable) {
- file.isPreviewAvailable = true;
- }
}
file.share = {
id: share.id,
diff --git a/apps/files_sharing/l10n/cs_CZ.js b/apps/files_sharing/l10n/cs_CZ.js
index daa43cc46e8..f04d641d7d6 100644
--- a/apps/files_sharing/l10n/cs_CZ.js
+++ b/apps/files_sharing/l10n/cs_CZ.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "Sdílení mezi servery není povoleno",
"The mountpoint name contains invalid characters." : "Jméno přípojného bodu obsahuje nepovolené znaky.",
+ "Not allowed to create a federated share with the same user server" : "Není povoleno vytvořit propojené sdílení s tím samým serverem",
"Invalid or untrusted SSL certificate" : "Neplatný nebo nedůvěryhodný SSL certifikát",
"Could not authenticate to remote share, password might be wrong" : "Nezdařilo se ověření vzdáleného úložiště, pravděpodobně chybné heslo",
"Storage not valid" : "Úložiště není platné",
diff --git a/apps/files_sharing/l10n/cs_CZ.json b/apps/files_sharing/l10n/cs_CZ.json
index f1bd6fa4934..2e95e6c8788 100644
--- a/apps/files_sharing/l10n/cs_CZ.json
+++ b/apps/files_sharing/l10n/cs_CZ.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "Sdílení mezi servery není povoleno",
"The mountpoint name contains invalid characters." : "Jméno přípojného bodu obsahuje nepovolené znaky.",
+ "Not allowed to create a federated share with the same user server" : "Není povoleno vytvořit propojené sdílení s tím samým serverem",
"Invalid or untrusted SSL certificate" : "Neplatný nebo nedůvěryhodný SSL certifikát",
"Could not authenticate to remote share, password might be wrong" : "Nezdařilo se ověření vzdáleného úložiště, pravděpodobně chybné heslo",
"Storage not valid" : "Úložiště není platné",
diff --git a/apps/files_sharing/l10n/de.js b/apps/files_sharing/l10n/de.js
index 295c7cdbb76..1c5121fdde2 100644
--- a/apps/files_sharing/l10n/de.js
+++ b/apps/files_sharing/l10n/de.js
@@ -62,7 +62,7 @@ OC.L10N.register(
"Password" : "Passwort",
"No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden",
"Name" : "Name",
- "Share time" : "Zeitpunkt der Freigabe",
+ "Share time" : "Freigabezeitpunkt",
"Sorry, this link doesn’t seem to work anymore." : "Entschuldigung, dieser Link scheint nicht mehr zu funktionieren.",
"Reasons might be:" : "Gründe könnten sein:",
"the item was removed" : "Das Element wurde entfernt",
diff --git a/apps/files_sharing/l10n/de.json b/apps/files_sharing/l10n/de.json
index 690e7596ffc..48b2e81b681 100644
--- a/apps/files_sharing/l10n/de.json
+++ b/apps/files_sharing/l10n/de.json
@@ -60,7 +60,7 @@
"Password" : "Passwort",
"No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden",
"Name" : "Name",
- "Share time" : "Zeitpunkt der Freigabe",
+ "Share time" : "Freigabezeitpunkt",
"Sorry, this link doesn’t seem to work anymore." : "Entschuldigung, dieser Link scheint nicht mehr zu funktionieren.",
"Reasons might be:" : "Gründe könnten sein:",
"the item was removed" : "Das Element wurde entfernt",
diff --git a/apps/files_sharing/l10n/de_DE.js b/apps/files_sharing/l10n/de_DE.js
index 47243b8f81d..b1b4be9e5ad 100644
--- a/apps/files_sharing/l10n/de_DE.js
+++ b/apps/files_sharing/l10n/de_DE.js
@@ -40,8 +40,17 @@ OC.L10N.register(
"You shared %1$s with group %2$s" : "Sie haben %1$s mit der Gruppe %2$s geteilt",
"%2$s shared %1$s with you" : "%2$s hat %1$s mit Ihnen geteilt",
"You shared %1$s via link" : "Sie haben %1$s über einen Link geteilt",
+ "Downloaded via public link" : "Über den öffentlichen Link heruntergeladen",
+ "Shared with %2$s" : "Geteilt mit %2$s",
+ "Shared with group %2$s" : "Geteilt mit der Gruppe %2$s",
+ "Shared with %3$s by %2$s" : "Geteilt mit %3$s von %2$s",
+ "Shared with group %3$s by %2$s" : "Geteilt mit der Gruppe %3$s von %2$s",
+ "Shared via link by %2$s" : "Geteilt durch einen Link von %2$s",
+ "Shared by %2$s" : "Geteilt von %2$s",
+ "Shared via public link" : "Durch einen öffentlichen Link geteilt",
"Shares" : "Geteiltes",
"Accept" : "Akzeptieren",
+ "Decline" : "Ablehnen",
"Share with me through my #ownCloud Federated Cloud ID, see %s" : "Teilen Sie mit mir über meine #ownCloud Federated-Cloud-ID, siehe %s",
"Share with me through my #ownCloud Federated Cloud ID" : "Teilen Sie mit mir über meine #ownCloud Federated-Cloud-ID",
"This share is password-protected" : "Diese Freigabe ist durch ein Passwort geschützt",
@@ -49,7 +58,7 @@ OC.L10N.register(
"Password" : "Passwort",
"No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden",
"Name" : "Name",
- "Share time" : "Zeitpunkt der Freigabe",
+ "Share time" : "Freigabezeitpunkt",
"Sorry, this link doesn’t seem to work anymore." : "Entschuldigung, dieser Link scheint nicht mehr zu funktionieren.",
"Reasons might be:" : "Gründe könnten sein:",
"the item was removed" : "Das Element wurde entfernt",
@@ -67,6 +76,7 @@ OC.L10N.register(
"Federated Cloud" : "Federated Cloud",
"Your Federated Cloud ID:" : "Ihre Federated-Cloud-ID:",
"Share it:" : "Zum Teilen:",
+ "Add to your website" : "Zu Ihrer Website hinzufügen",
"Share with me via ownCloud" : "Teilen Sie mit mir über ownCloud",
"HTML Code:" : "HTML-Code:"
},
diff --git a/apps/files_sharing/l10n/de_DE.json b/apps/files_sharing/l10n/de_DE.json
index b63286de48d..7ed2c480284 100644
--- a/apps/files_sharing/l10n/de_DE.json
+++ b/apps/files_sharing/l10n/de_DE.json
@@ -38,8 +38,17 @@
"You shared %1$s with group %2$s" : "Sie haben %1$s mit der Gruppe %2$s geteilt",
"%2$s shared %1$s with you" : "%2$s hat %1$s mit Ihnen geteilt",
"You shared %1$s via link" : "Sie haben %1$s über einen Link geteilt",
+ "Downloaded via public link" : "Über den öffentlichen Link heruntergeladen",
+ "Shared with %2$s" : "Geteilt mit %2$s",
+ "Shared with group %2$s" : "Geteilt mit der Gruppe %2$s",
+ "Shared with %3$s by %2$s" : "Geteilt mit %3$s von %2$s",
+ "Shared with group %3$s by %2$s" : "Geteilt mit der Gruppe %3$s von %2$s",
+ "Shared via link by %2$s" : "Geteilt durch einen Link von %2$s",
+ "Shared by %2$s" : "Geteilt von %2$s",
+ "Shared via public link" : "Durch einen öffentlichen Link geteilt",
"Shares" : "Geteiltes",
"Accept" : "Akzeptieren",
+ "Decline" : "Ablehnen",
"Share with me through my #ownCloud Federated Cloud ID, see %s" : "Teilen Sie mit mir über meine #ownCloud Federated-Cloud-ID, siehe %s",
"Share with me through my #ownCloud Federated Cloud ID" : "Teilen Sie mit mir über meine #ownCloud Federated-Cloud-ID",
"This share is password-protected" : "Diese Freigabe ist durch ein Passwort geschützt",
@@ -47,7 +56,7 @@
"Password" : "Passwort",
"No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden",
"Name" : "Name",
- "Share time" : "Zeitpunkt der Freigabe",
+ "Share time" : "Freigabezeitpunkt",
"Sorry, this link doesn’t seem to work anymore." : "Entschuldigung, dieser Link scheint nicht mehr zu funktionieren.",
"Reasons might be:" : "Gründe könnten sein:",
"the item was removed" : "Das Element wurde entfernt",
@@ -65,6 +74,7 @@
"Federated Cloud" : "Federated Cloud",
"Your Federated Cloud ID:" : "Ihre Federated-Cloud-ID:",
"Share it:" : "Zum Teilen:",
+ "Add to your website" : "Zu Ihrer Website hinzufügen",
"Share with me via ownCloud" : "Teilen Sie mit mir über ownCloud",
"HTML Code:" : "HTML-Code:"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/files_sharing/l10n/es.js b/apps/files_sharing/l10n/es.js
index 650fb5c524a..da479f40975 100644
--- a/apps/files_sharing/l10n/es.js
+++ b/apps/files_sharing/l10n/es.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "Compartir entre servidores no está habilitado en este servidor",
"The mountpoint name contains invalid characters." : "El punto de montaje contiene caracteres inválidos.",
+ "Not allowed to create a federated share with the same user server" : "No se permite crear un recurso compartido federado con el mismo servidor de usuario",
"Invalid or untrusted SSL certificate" : "Certificado SSL inválido o no confiable",
"Could not authenticate to remote share, password might be wrong" : "No se ha podido autenticar para compartir remotamente, quizás esté mal la contraseña",
"Storage not valid" : "Almacenamiento inválido",
@@ -52,6 +53,7 @@ OC.L10N.register(
"Shared by %2$s" : "Compartido por %2$s",
"Shared via public link" : "Compartido vía enlace público",
"Shares" : "Compartidos",
+ "You received %2$s as a remote share from %1$s" : "Ha recibido %2$s como un recurso compartido de %1$s",
"Accept" : "Aceptar",
"Decline" : "Denegar",
"Share with me through my #ownCloud Federated Cloud ID, see %s" : "Compartirlo conmigo a través de mi ID Nube Federada #ownCloud, ver %s",
diff --git a/apps/files_sharing/l10n/es.json b/apps/files_sharing/l10n/es.json
index 6f963ab8fee..3b6f828b79a 100644
--- a/apps/files_sharing/l10n/es.json
+++ b/apps/files_sharing/l10n/es.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "Compartir entre servidores no está habilitado en este servidor",
"The mountpoint name contains invalid characters." : "El punto de montaje contiene caracteres inválidos.",
+ "Not allowed to create a federated share with the same user server" : "No se permite crear un recurso compartido federado con el mismo servidor de usuario",
"Invalid or untrusted SSL certificate" : "Certificado SSL inválido o no confiable",
"Could not authenticate to remote share, password might be wrong" : "No se ha podido autenticar para compartir remotamente, quizás esté mal la contraseña",
"Storage not valid" : "Almacenamiento inválido",
@@ -50,6 +51,7 @@
"Shared by %2$s" : "Compartido por %2$s",
"Shared via public link" : "Compartido vía enlace público",
"Shares" : "Compartidos",
+ "You received %2$s as a remote share from %1$s" : "Ha recibido %2$s como un recurso compartido de %1$s",
"Accept" : "Aceptar",
"Decline" : "Denegar",
"Share with me through my #ownCloud Federated Cloud ID, see %s" : "Compartirlo conmigo a través de mi ID Nube Federada #ownCloud, ver %s",
diff --git a/apps/files_sharing/l10n/es_AR.js b/apps/files_sharing/l10n/es_AR.js
index fac8b357506..f0e363b2f49 100644
--- a/apps/files_sharing/l10n/es_AR.js
+++ b/apps/files_sharing/l10n/es_AR.js
@@ -1,6 +1,7 @@
OC.L10N.register(
"files_sharing",
{
+ "Server to server sharing is not enabled on this server" : "Compartir entre servidores no está habilitado en este servidor",
"Cancel" : "Cancelar",
"Shared by" : "Compartido por",
"Sharing" : "Compartiendo",
diff --git a/apps/files_sharing/l10n/es_AR.json b/apps/files_sharing/l10n/es_AR.json
index 6a7316bff8c..7a6441c7bdf 100644
--- a/apps/files_sharing/l10n/es_AR.json
+++ b/apps/files_sharing/l10n/es_AR.json
@@ -1,4 +1,5 @@
{ "translations": {
+ "Server to server sharing is not enabled on this server" : "Compartir entre servidores no está habilitado en este servidor",
"Cancel" : "Cancelar",
"Shared by" : "Compartido por",
"Sharing" : "Compartiendo",
diff --git a/apps/files_sharing/l10n/et_EE.js b/apps/files_sharing/l10n/et_EE.js
index 6d02bdd6ced..2fcce251407 100644
--- a/apps/files_sharing/l10n/et_EE.js
+++ b/apps/files_sharing/l10n/et_EE.js
@@ -30,6 +30,8 @@ OC.L10N.register(
"You shared %1$s with group %2$s" : "Jagasid %1$s %2$s grupiga",
"%2$s shared %1$s with you" : "%2$s jagas sinuga %1$s",
"You shared %1$s via link" : "Jagasid %1$s lingiga",
+ "Downloaded via public link" : "Alla laetud avalikult lingilt",
+ "Shared with %2$s" : "Jagatud kasutajaga %2$s",
"Shares" : "Jagamised",
"Accept" : "Nõustu",
"Decline" : "Lükka tagasi",
diff --git a/apps/files_sharing/l10n/et_EE.json b/apps/files_sharing/l10n/et_EE.json
index 481a75210ee..34ddd9f1b15 100644
--- a/apps/files_sharing/l10n/et_EE.json
+++ b/apps/files_sharing/l10n/et_EE.json
@@ -28,6 +28,8 @@
"You shared %1$s with group %2$s" : "Jagasid %1$s %2$s grupiga",
"%2$s shared %1$s with you" : "%2$s jagas sinuga %1$s",
"You shared %1$s via link" : "Jagasid %1$s lingiga",
+ "Downloaded via public link" : "Alla laetud avalikult lingilt",
+ "Shared with %2$s" : "Jagatud kasutajaga %2$s",
"Shares" : "Jagamised",
"Accept" : "Nõustu",
"Decline" : "Lükka tagasi",
diff --git a/apps/files_sharing/l10n/fi_FI.js b/apps/files_sharing/l10n/fi_FI.js
index a87d6156d40..accd43020ff 100644
--- a/apps/files_sharing/l10n/fi_FI.js
+++ b/apps/files_sharing/l10n/fi_FI.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "Palvelimelta-palvelimelle-jakaminen ei ole käytössä tällä palvelimella",
"The mountpoint name contains invalid characters." : "Liitospisteen nimi sisältää virheellisiä merkkejä.",
+ "Not allowed to create a federated share with the same user server" : "Saman käyttäjäpalvelimen kanssa ei ole sallittua luoda federoitua jakoa",
"Invalid or untrusted SSL certificate" : "Virheellinen tai ei-luotettu SSL-varmenne",
"Could not authenticate to remote share, password might be wrong" : "Tunnistautuminen etäjakoa kohtaan epäonnistui. Salasana saattaa olla väärä",
"Storage not valid" : "Tallennustila ei ole kelvollinen",
diff --git a/apps/files_sharing/l10n/fi_FI.json b/apps/files_sharing/l10n/fi_FI.json
index 172b8476092..e321d64732f 100644
--- a/apps/files_sharing/l10n/fi_FI.json
+++ b/apps/files_sharing/l10n/fi_FI.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "Palvelimelta-palvelimelle-jakaminen ei ole käytössä tällä palvelimella",
"The mountpoint name contains invalid characters." : "Liitospisteen nimi sisältää virheellisiä merkkejä.",
+ "Not allowed to create a federated share with the same user server" : "Saman käyttäjäpalvelimen kanssa ei ole sallittua luoda federoitua jakoa",
"Invalid or untrusted SSL certificate" : "Virheellinen tai ei-luotettu SSL-varmenne",
"Could not authenticate to remote share, password might be wrong" : "Tunnistautuminen etäjakoa kohtaan epäonnistui. Salasana saattaa olla väärä",
"Storage not valid" : "Tallennustila ei ole kelvollinen",
diff --git a/apps/files_sharing/l10n/fr.js b/apps/files_sharing/l10n/fr.js
index 9d26127d472..bdf8ee8224a 100644
--- a/apps/files_sharing/l10n/fr.js
+++ b/apps/files_sharing/l10n/fr.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "Le partage de serveur à serveur n'est pas activé sur ce serveur",
"The mountpoint name contains invalid characters." : "Le nom du point de montage contient des caractères non valides.",
+ "Not allowed to create a federated share with the same user server" : "Non autorisé à créer un partage fédéré avec un utilisateur du même serveur",
"Invalid or untrusted SSL certificate" : "Certificat SSL non valable ou non fiable",
"Could not authenticate to remote share, password might be wrong" : "Impossible de s'authentifier au partage distant : le mot de passe en probablement incorrect",
"Storage not valid" : "Support de stockage non valide",
diff --git a/apps/files_sharing/l10n/fr.json b/apps/files_sharing/l10n/fr.json
index 0f1edc51dc7..6d30043fb84 100644
--- a/apps/files_sharing/l10n/fr.json
+++ b/apps/files_sharing/l10n/fr.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "Le partage de serveur à serveur n'est pas activé sur ce serveur",
"The mountpoint name contains invalid characters." : "Le nom du point de montage contient des caractères non valides.",
+ "Not allowed to create a federated share with the same user server" : "Non autorisé à créer un partage fédéré avec un utilisateur du même serveur",
"Invalid or untrusted SSL certificate" : "Certificat SSL non valable ou non fiable",
"Could not authenticate to remote share, password might be wrong" : "Impossible de s'authentifier au partage distant : le mot de passe en probablement incorrect",
"Storage not valid" : "Support de stockage non valide",
diff --git a/apps/files_sharing/l10n/he.js b/apps/files_sharing/l10n/he.js
index a9292dc8206..b229c8d5655 100644
--- a/apps/files_sharing/l10n/he.js
+++ b/apps/files_sharing/l10n/he.js
@@ -1,17 +1,88 @@
OC.L10N.register(
"files_sharing",
{
+ "Server to server sharing is not enabled on this server" : "שיתוף שרת לשרת לא מופעל בשרת זה",
+ "The mountpoint name contains invalid characters." : "שם ה- mountpoint מכיל תווים לא חוקיים.",
+ "Not allowed to create a federated share with the same user server" : "יצירת שיתוף מאוגד עם אותו שרת משתמש אסורה",
+ "Invalid or untrusted SSL certificate" : "תעודת SSL לא חוקית או לא בטוחה",
+ "Could not authenticate to remote share, password might be wrong" : "לא ניתן לאמת שיתוף חיצוני, ייתכן שהסיסמא שגוייה",
+ "Storage not valid" : "אחסון לא חוקי",
+ "Couldn't add remote share" : "לא ניתן להוסיף שיתוף חיצוני",
+ "Shared with you" : "שיתף/שיתפה אתך",
+ "Shared with others" : "משותף עם אחרים",
+ "Shared by link" : "משותף עם קישור",
+ "Nothing shared with you yet" : "עדיין לא שיתפו אתך דבר",
+ "Files and folders others share with you will show up here" : "קבצים ותיקיות שאחרים שיתפו אתך יוצגו כאן",
+ "Nothing shared yet" : "עדיין לא שותף דבר",
+ "Files and folders you share will show up here" : "קבצים ותיקיות ששיתפת יוצגו כאן",
+ "No shared links" : "אין קישורים משותפים",
+ "Files and folders you share by link will show up here" : "קבצים ותיקיות ששיתפת עם קישור יוצגו כאן",
+ "Do you want to add the remote share {name} from {owner}@{remote}?" : "האם לשתף את השיתוף החיצוני {name} שהתקבל מ- {owner}@{remote}?",
+ "Remote share" : "שיתוף חיצוני",
+ "Remote share password" : "סיסמת שיתוף חיצוני",
"Cancel" : "ביטול",
+ "Add remote share" : "הוספת שיתוף חיצוני",
+ "You can upload into this folder" : "ניתן להעלות לתיקייה זו",
+ "No ownCloud installation (7 or higher) found at {remote}" : "לא נמצאה התקנת ownCloud (גרסה 7 ומעלה) ב- {remote}",
+ "Invalid ownCloud url" : "נתיב ownCloud לא חוקי",
"Shared by" : "שותף על־ידי",
"Sharing" : "שיתוף",
"A file or folder has been <strong>shared</strong>" : "קובץ או תיקייה <strong>שותפו<strong/>",
+ "A file or folder was shared from <strong>another server</strong>" : "קובץ או תיקייה שותפו מ- <strong>שרת אחר</strong>",
+ "A public shared file or folder was <strong>downloaded</strong>" : "קובץ או תיקייה עם שיתוף ציבורי <strong>הורדו</strong>",
+ "You received a new remote share %2$s from %1$s" : "קבלת שיתוף חיצוני חדש %2$s מאת %1$s",
+ "You received a new remote share from %s" : "קבלת שיתוף חיצוני חדש מאת %s",
+ "%1$s accepted remote share %2$s" : "%1$s אישר/אישרה שיתוף חיצוני %2$s",
+ "%1$s declined remote share %2$s" : "%1$s סירב/סירבה שיתוף חיצוני %2$s",
+ "%1$s unshared %2$s from you" : "%1$s ביטל/ביטלה שיתוף %2$s אתך",
+ "Public shared folder %1$s was downloaded" : "תיקיית שיתוף ציבורית %1$s הורדה",
+ "Public shared file %1$s was downloaded" : "קובץ שיתוף ציבורי %1$s הורד",
"You shared %1$s with %2$s" : "שיתפת %1$s עם %2$s",
"You shared %1$s with group %2$s" : "שיתפת %1$s עם קבוצת %2$s",
+ "%2$s shared %1$s with %3$s" : "%2$s שיתף/שיתפה %1$s עם %3$s",
+ "%2$s shared %1$s with group %3$s" : "%2$s שיתף/שיתפה %1$s עם קבוצה %3$s",
+ "%2$s shared %1$s via link" : "%2$s שיתף/שיתפה %1$s על ידי קישור",
"%2$s shared %1$s with you" : "%2$s שיתפו %1$s אתך",
"You shared %1$s via link" : "שיתפת %1$s על בסיס קישור",
+ "Downloaded via public link" : "הורד על בסיס קישור ציבורי",
+ "Shared with %2$s" : "שיתף/שיתפה עם %2$s",
+ "Shared with group %2$s" : "שיתף/שיתפה עם קבוצה %2$s",
+ "Shared with %3$s by %2$s" : "שיתף/שיתפה עם %3$s על ידי %2$s",
+ "Shared with group %3$s by %2$s" : "שיתף/שיתפה עם קבוצה %3$s על ידי %2$s",
+ "Shared via link by %2$s" : "שיתף/שיתפה על בסיס קישור על ידי %2$s",
+ "Shared by %2$s" : "שיתף/שיתפה על ידי %2$s",
+ "Shared via public link" : "משותף על בסיס קישור ציבורי",
"Shares" : "שיתופים",
+ "You received %2$s as a remote share from %1$s" : "קבלת %2$s כשיתוף חיצוני מאת %1$s",
+ "Accept" : "אישור",
+ "Decline" : "סירוב",
+ "Share with me through my #ownCloud Federated Cloud ID, see %s" : "שיתוף איתי באמצעות מספר זהות שרת ה- #ownCloud המאוגד שלי, ניתן לראות %s",
+ "Share with me through my #ownCloud Federated Cloud ID" : "שיתוף איתי באמצעות מספר זהות שרת ה- #ownCloud המאוגד שלי",
+ "This share is password-protected" : "שיתוף זה מוגן סיסמא",
+ "The password is wrong. Try again." : "הסיסמא שגויה. יש לנסות שנית.",
"Password" : "סיסמא",
+ "No entries found in this folder" : "לא נמצאו כניסות לתיקייה זו",
"Name" : "שם",
- "Download" : "הורדה"
+ "Share time" : "זמן שיתוף",
+ "Sorry, this link doesn’t seem to work anymore." : "מצטערים, לא נראה שקישור זה עובד יותר. ",
+ "Reasons might be:" : "הסיבות יכולות להיות:",
+ "the item was removed" : "הפריט הוסר",
+ "the link expired" : "הקישור פג תוקף",
+ "sharing is disabled" : "השיתוף נוטרל",
+ "For more info, please ask the person who sent this link." : "למידע נוסף, יש לפנות לשולח קישור זה.",
+ "Add to your ownCloud" : "הוספה ל- ownCloud שלך",
+ "Download" : "הורדה",
+ "Download %s" : "הורדה %s",
+ "Direct link" : "קישור ישיר",
+ "Federated Cloud Sharing" : "ענן שיתוף מאוגד",
+ "Open documentation" : "תיעוד פתוח",
+ "Allow users on this server to send shares to other servers" : "מאפשר למשתמשים בשרת זה לשלוח שיתופים לשרתים אחרים",
+ "Allow users on this server to receive shares from other servers" : "מאפשר למשתמשים בשרת זה לקבל שיתופים משרתים אחרים",
+ "Federated Cloud" : "ענן מאוגד",
+ "Your Federated Cloud ID:" : "מספר זיהוי הענן המאוגד שלך:",
+ "Share it:" : "שיתוף שלו:",
+ "Add to your website" : "הוספה לאתר האינטרנט שלך",
+ "Share with me via ownCloud" : "שיתוף איתי באמצעות ownCloud",
+ "HTML Code:" : "קוד HTML:"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_sharing/l10n/he.json b/apps/files_sharing/l10n/he.json
index 9f9ab2593f2..cdd1471c007 100644
--- a/apps/files_sharing/l10n/he.json
+++ b/apps/files_sharing/l10n/he.json
@@ -1,15 +1,86 @@
{ "translations": {
+ "Server to server sharing is not enabled on this server" : "שיתוף שרת לשרת לא מופעל בשרת זה",
+ "The mountpoint name contains invalid characters." : "שם ה- mountpoint מכיל תווים לא חוקיים.",
+ "Not allowed to create a federated share with the same user server" : "יצירת שיתוף מאוגד עם אותו שרת משתמש אסורה",
+ "Invalid or untrusted SSL certificate" : "תעודת SSL לא חוקית או לא בטוחה",
+ "Could not authenticate to remote share, password might be wrong" : "לא ניתן לאמת שיתוף חיצוני, ייתכן שהסיסמא שגוייה",
+ "Storage not valid" : "אחסון לא חוקי",
+ "Couldn't add remote share" : "לא ניתן להוסיף שיתוף חיצוני",
+ "Shared with you" : "שיתף/שיתפה אתך",
+ "Shared with others" : "משותף עם אחרים",
+ "Shared by link" : "משותף עם קישור",
+ "Nothing shared with you yet" : "עדיין לא שיתפו אתך דבר",
+ "Files and folders others share with you will show up here" : "קבצים ותיקיות שאחרים שיתפו אתך יוצגו כאן",
+ "Nothing shared yet" : "עדיין לא שותף דבר",
+ "Files and folders you share will show up here" : "קבצים ותיקיות ששיתפת יוצגו כאן",
+ "No shared links" : "אין קישורים משותפים",
+ "Files and folders you share by link will show up here" : "קבצים ותיקיות ששיתפת עם קישור יוצגו כאן",
+ "Do you want to add the remote share {name} from {owner}@{remote}?" : "האם לשתף את השיתוף החיצוני {name} שהתקבל מ- {owner}@{remote}?",
+ "Remote share" : "שיתוף חיצוני",
+ "Remote share password" : "סיסמת שיתוף חיצוני",
"Cancel" : "ביטול",
+ "Add remote share" : "הוספת שיתוף חיצוני",
+ "You can upload into this folder" : "ניתן להעלות לתיקייה זו",
+ "No ownCloud installation (7 or higher) found at {remote}" : "לא נמצאה התקנת ownCloud (גרסה 7 ומעלה) ב- {remote}",
+ "Invalid ownCloud url" : "נתיב ownCloud לא חוקי",
"Shared by" : "שותף על־ידי",
"Sharing" : "שיתוף",
"A file or folder has been <strong>shared</strong>" : "קובץ או תיקייה <strong>שותפו<strong/>",
+ "A file or folder was shared from <strong>another server</strong>" : "קובץ או תיקייה שותפו מ- <strong>שרת אחר</strong>",
+ "A public shared file or folder was <strong>downloaded</strong>" : "קובץ או תיקייה עם שיתוף ציבורי <strong>הורדו</strong>",
+ "You received a new remote share %2$s from %1$s" : "קבלת שיתוף חיצוני חדש %2$s מאת %1$s",
+ "You received a new remote share from %s" : "קבלת שיתוף חיצוני חדש מאת %s",
+ "%1$s accepted remote share %2$s" : "%1$s אישר/אישרה שיתוף חיצוני %2$s",
+ "%1$s declined remote share %2$s" : "%1$s סירב/סירבה שיתוף חיצוני %2$s",
+ "%1$s unshared %2$s from you" : "%1$s ביטל/ביטלה שיתוף %2$s אתך",
+ "Public shared folder %1$s was downloaded" : "תיקיית שיתוף ציבורית %1$s הורדה",
+ "Public shared file %1$s was downloaded" : "קובץ שיתוף ציבורי %1$s הורד",
"You shared %1$s with %2$s" : "שיתפת %1$s עם %2$s",
"You shared %1$s with group %2$s" : "שיתפת %1$s עם קבוצת %2$s",
+ "%2$s shared %1$s with %3$s" : "%2$s שיתף/שיתפה %1$s עם %3$s",
+ "%2$s shared %1$s with group %3$s" : "%2$s שיתף/שיתפה %1$s עם קבוצה %3$s",
+ "%2$s shared %1$s via link" : "%2$s שיתף/שיתפה %1$s על ידי קישור",
"%2$s shared %1$s with you" : "%2$s שיתפו %1$s אתך",
"You shared %1$s via link" : "שיתפת %1$s על בסיס קישור",
+ "Downloaded via public link" : "הורד על בסיס קישור ציבורי",
+ "Shared with %2$s" : "שיתף/שיתפה עם %2$s",
+ "Shared with group %2$s" : "שיתף/שיתפה עם קבוצה %2$s",
+ "Shared with %3$s by %2$s" : "שיתף/שיתפה עם %3$s על ידי %2$s",
+ "Shared with group %3$s by %2$s" : "שיתף/שיתפה עם קבוצה %3$s על ידי %2$s",
+ "Shared via link by %2$s" : "שיתף/שיתפה על בסיס קישור על ידי %2$s",
+ "Shared by %2$s" : "שיתף/שיתפה על ידי %2$s",
+ "Shared via public link" : "משותף על בסיס קישור ציבורי",
"Shares" : "שיתופים",
+ "You received %2$s as a remote share from %1$s" : "קבלת %2$s כשיתוף חיצוני מאת %1$s",
+ "Accept" : "אישור",
+ "Decline" : "סירוב",
+ "Share with me through my #ownCloud Federated Cloud ID, see %s" : "שיתוף איתי באמצעות מספר זהות שרת ה- #ownCloud המאוגד שלי, ניתן לראות %s",
+ "Share with me through my #ownCloud Federated Cloud ID" : "שיתוף איתי באמצעות מספר זהות שרת ה- #ownCloud המאוגד שלי",
+ "This share is password-protected" : "שיתוף זה מוגן סיסמא",
+ "The password is wrong. Try again." : "הסיסמא שגויה. יש לנסות שנית.",
"Password" : "סיסמא",
+ "No entries found in this folder" : "לא נמצאו כניסות לתיקייה זו",
"Name" : "שם",
- "Download" : "הורדה"
+ "Share time" : "זמן שיתוף",
+ "Sorry, this link doesn’t seem to work anymore." : "מצטערים, לא נראה שקישור זה עובד יותר. ",
+ "Reasons might be:" : "הסיבות יכולות להיות:",
+ "the item was removed" : "הפריט הוסר",
+ "the link expired" : "הקישור פג תוקף",
+ "sharing is disabled" : "השיתוף נוטרל",
+ "For more info, please ask the person who sent this link." : "למידע נוסף, יש לפנות לשולח קישור זה.",
+ "Add to your ownCloud" : "הוספה ל- ownCloud שלך",
+ "Download" : "הורדה",
+ "Download %s" : "הורדה %s",
+ "Direct link" : "קישור ישיר",
+ "Federated Cloud Sharing" : "ענן שיתוף מאוגד",
+ "Open documentation" : "תיעוד פתוח",
+ "Allow users on this server to send shares to other servers" : "מאפשר למשתמשים בשרת זה לשלוח שיתופים לשרתים אחרים",
+ "Allow users on this server to receive shares from other servers" : "מאפשר למשתמשים בשרת זה לקבל שיתופים משרתים אחרים",
+ "Federated Cloud" : "ענן מאוגד",
+ "Your Federated Cloud ID:" : "מספר זיהוי הענן המאוגד שלך:",
+ "Share it:" : "שיתוף שלו:",
+ "Add to your website" : "הוספה לאתר האינטרנט שלך",
+ "Share with me via ownCloud" : "שיתוף איתי באמצעות ownCloud",
+ "HTML Code:" : "קוד HTML:"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_sharing/l10n/hu_HU.js b/apps/files_sharing/l10n/hu_HU.js
index c0d2d01b2c4..6471b491fac 100644
--- a/apps/files_sharing/l10n/hu_HU.js
+++ b/apps/files_sharing/l10n/hu_HU.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "A kiszolgálók közötti megosztás nincs engedélyezve ezen a kiszolgálón",
"The mountpoint name contains invalid characters." : "A csatlakozási pont neve érvénytelen karaktereket tartalmaz ",
+ "Not allowed to create a federated share with the same user server" : "Nem lehet létrehozni egy egyesített megosztást azonos felhasználóval és szerverrel",
"Invalid or untrusted SSL certificate" : "Érvénytelen vagy nem megbízható az SSL tanúsítvány",
"Could not authenticate to remote share, password might be wrong" : "Nem sikerült az azonosítás a távoli megosztáshoz. Lehet, hogy rossz a jelszó.",
"Storage not valid" : "Tároló nem érvényes",
diff --git a/apps/files_sharing/l10n/hu_HU.json b/apps/files_sharing/l10n/hu_HU.json
index a2e15c46c52..4c5501803ea 100644
--- a/apps/files_sharing/l10n/hu_HU.json
+++ b/apps/files_sharing/l10n/hu_HU.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "A kiszolgálók közötti megosztás nincs engedélyezve ezen a kiszolgálón",
"The mountpoint name contains invalid characters." : "A csatlakozási pont neve érvénytelen karaktereket tartalmaz ",
+ "Not allowed to create a federated share with the same user server" : "Nem lehet létrehozni egy egyesített megosztást azonos felhasználóval és szerverrel",
"Invalid or untrusted SSL certificate" : "Érvénytelen vagy nem megbízható az SSL tanúsítvány",
"Could not authenticate to remote share, password might be wrong" : "Nem sikerült az azonosítás a távoli megosztáshoz. Lehet, hogy rossz a jelszó.",
"Storage not valid" : "Tároló nem érvényes",
diff --git a/apps/files_sharing/l10n/it.js b/apps/files_sharing/l10n/it.js
index 8cd66b34d24..39f7ced4bbd 100644
--- a/apps/files_sharing/l10n/it.js
+++ b/apps/files_sharing/l10n/it.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "La condivisione tra server non è abilitata su questo server",
"The mountpoint name contains invalid characters." : "Il nome del punto di mount contiene caratteri non validi.",
+ "Not allowed to create a federated share with the same user server" : "Non è consentito creare una condivisione federata con lo stesso server dell'utente",
"Invalid or untrusted SSL certificate" : "Certificato SSL non valido o non attendibile",
"Could not authenticate to remote share, password might be wrong" : "Impossibile autenticarsi sulla condivisione remota, la password potrebbe essere errata",
"Storage not valid" : "Archiviazione non valida",
diff --git a/apps/files_sharing/l10n/it.json b/apps/files_sharing/l10n/it.json
index b93dafd7555..f40fbb4b232 100644
--- a/apps/files_sharing/l10n/it.json
+++ b/apps/files_sharing/l10n/it.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "La condivisione tra server non è abilitata su questo server",
"The mountpoint name contains invalid characters." : "Il nome del punto di mount contiene caratteri non validi.",
+ "Not allowed to create a federated share with the same user server" : "Non è consentito creare una condivisione federata con lo stesso server dell'utente",
"Invalid or untrusted SSL certificate" : "Certificato SSL non valido o non attendibile",
"Could not authenticate to remote share, password might be wrong" : "Impossibile autenticarsi sulla condivisione remota, la password potrebbe essere errata",
"Storage not valid" : "Archiviazione non valida",
diff --git a/apps/files_sharing/l10n/ja.js b/apps/files_sharing/l10n/ja.js
index b80be0c3315..e3427ea1f7b 100644
--- a/apps/files_sharing/l10n/ja.js
+++ b/apps/files_sharing/l10n/ja.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "このサーバーでは、サーバー間の共有が有効ではありません",
"The mountpoint name contains invalid characters." : "マウントポイント名 に不正な文字列が含まれています。",
+ "Not allowed to create a federated share with the same user server" : "同じユーザーのサーバーでフェデレーション共有を作成することは出来ません",
"Invalid or untrusted SSL certificate" : "無効または信頼できないSSL証明書",
"Could not authenticate to remote share, password might be wrong" : "リモート共有が認証できませんでした,パスワードが間違っているかもしれません",
"Storage not valid" : "ストレージが無効です",
@@ -26,9 +27,9 @@ OC.L10N.register(
"Invalid ownCloud url" : "無効なownCloud URL です",
"Shared by" : "共有者:",
"Sharing" : "共有",
- "A file or folder has been <strong>shared</strong>" : "ファイルまたはフォルダーが<strong>共有</strong>されました。",
- "A file or folder was shared from <strong>another server</strong>" : "ファイルまたはフォルダーが<strong>他のサーバー</strong>から共有されました。",
- "A public shared file or folder was <strong>downloaded</strong>" : "公開共有ファイルまたはフォルダーが<strong>ダウンロード</strong>されました。",
+ "A file or folder has been <strong>shared</strong>" : "ファイルまたはフォルダーが<strong>共有</strong>されたとき",
+ "A file or folder was shared from <strong>another server</strong>" : "ファイルまたはフォルダーが<strong>他のサーバー</strong>から共有されたとき",
+ "A public shared file or folder was <strong>downloaded</strong>" : "公開共有ファイルまたはフォルダーが<strong>ダウンロード</strong>されたとき",
"You received a new remote share %2$s from %1$s" : "%1$s から新しいリモート共有のリクエスト %2$s を受け取りました。",
"You received a new remote share from %s" : "%sからリモート共有のリクエストは\n届きました。",
"%1$s accepted remote share %2$s" : "%1$s は %2$s のリモート共有を承認しました。",
diff --git a/apps/files_sharing/l10n/ja.json b/apps/files_sharing/l10n/ja.json
index 8f9efffb782..9dc64e2b3ec 100644
--- a/apps/files_sharing/l10n/ja.json
+++ b/apps/files_sharing/l10n/ja.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "このサーバーでは、サーバー間の共有が有効ではありません",
"The mountpoint name contains invalid characters." : "マウントポイント名 に不正な文字列が含まれています。",
+ "Not allowed to create a federated share with the same user server" : "同じユーザーのサーバーでフェデレーション共有を作成することは出来ません",
"Invalid or untrusted SSL certificate" : "無効または信頼できないSSL証明書",
"Could not authenticate to remote share, password might be wrong" : "リモート共有が認証できませんでした,パスワードが間違っているかもしれません",
"Storage not valid" : "ストレージが無効です",
@@ -24,9 +25,9 @@
"Invalid ownCloud url" : "無効なownCloud URL です",
"Shared by" : "共有者:",
"Sharing" : "共有",
- "A file or folder has been <strong>shared</strong>" : "ファイルまたはフォルダーが<strong>共有</strong>されました。",
- "A file or folder was shared from <strong>another server</strong>" : "ファイルまたはフォルダーが<strong>他のサーバー</strong>から共有されました。",
- "A public shared file or folder was <strong>downloaded</strong>" : "公開共有ファイルまたはフォルダーが<strong>ダウンロード</strong>されました。",
+ "A file or folder has been <strong>shared</strong>" : "ファイルまたはフォルダーが<strong>共有</strong>されたとき",
+ "A file or folder was shared from <strong>another server</strong>" : "ファイルまたはフォルダーが<strong>他のサーバー</strong>から共有されたとき",
+ "A public shared file or folder was <strong>downloaded</strong>" : "公開共有ファイルまたはフォルダーが<strong>ダウンロード</strong>されたとき",
"You received a new remote share %2$s from %1$s" : "%1$s から新しいリモート共有のリクエスト %2$s を受け取りました。",
"You received a new remote share from %s" : "%sからリモート共有のリクエストは\n届きました。",
"%1$s accepted remote share %2$s" : "%1$s は %2$s のリモート共有を承認しました。",
diff --git a/apps/files_sharing/l10n/lt_LT.js b/apps/files_sharing/l10n/lt_LT.js
index 93848326605..517cc0915be 100644
--- a/apps/files_sharing/l10n/lt_LT.js
+++ b/apps/files_sharing/l10n/lt_LT.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "Serveris - serveris dalinimasis neįjungtas šiame serveryje",
"The mountpoint name contains invalid characters." : "Prijungimo taškas su neleistinais simboliais.",
+ "Not allowed to create a federated share with the same user server" : "Neleidžiama dalintis tarp serverių, nes vartotojas tame pačiame serveryje.",
"Invalid or untrusted SSL certificate" : "Netinkamas arba nepatikimas SSL sertifikatas",
"Could not authenticate to remote share, password might be wrong" : "Nepavyko identifikuotis serveryje, gal netinkamas slaptažodis",
"Storage not valid" : "Talpykla negalioja",
diff --git a/apps/files_sharing/l10n/lt_LT.json b/apps/files_sharing/l10n/lt_LT.json
index 6d777024052..923971c336b 100644
--- a/apps/files_sharing/l10n/lt_LT.json
+++ b/apps/files_sharing/l10n/lt_LT.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "Serveris - serveris dalinimasis neįjungtas šiame serveryje",
"The mountpoint name contains invalid characters." : "Prijungimo taškas su neleistinais simboliais.",
+ "Not allowed to create a federated share with the same user server" : "Neleidžiama dalintis tarp serverių, nes vartotojas tame pačiame serveryje.",
"Invalid or untrusted SSL certificate" : "Netinkamas arba nepatikimas SSL sertifikatas",
"Could not authenticate to remote share, password might be wrong" : "Nepavyko identifikuotis serveryje, gal netinkamas slaptažodis",
"Storage not valid" : "Talpykla negalioja",
diff --git a/apps/files_sharing/l10n/mk.js b/apps/files_sharing/l10n/mk.js
index a5de7fb5c09..5be22894b99 100644
--- a/apps/files_sharing/l10n/mk.js
+++ b/apps/files_sharing/l10n/mk.js
@@ -1,20 +1,44 @@
OC.L10N.register(
"files_sharing",
{
+ "Server to server sharing is not enabled on this server" : "Не е овозможено споделувањето од сервер на сервер на вашиот сервер",
+ "Invalid or untrusted SSL certificate" : "SSL сертификат кој е невалиден или недоверлив",
+ "Could not authenticate to remote share, password might be wrong" : "Не можам да се автентицирам на оддалеченото споделевање, веројатно лозинката не е исправна",
+ "Storage not valid" : "Сториџот не е валиден",
+ "Couldn't add remote share" : "Не можам да додадам оддалечено споделување",
"Shared with you" : "Споделено со тебе",
"Shared with others" : "Сподели со останатите",
"Shared by link" : "Споделено со врска",
+ "Nothing shared with you yet" : "Сеуште ништо не е споделено со вас",
+ "Nothing shared yet" : "Уште ништо не е споделено",
+ "No shared links" : "Нема споделени врски/линкови",
+ "Remote share" : "Оддалечено споделување",
+ "Remote share password" : "Лозинка за оддалечаното споделување",
"Cancel" : "Откажи",
+ "Add remote share" : "Додади оддалечно споделување",
+ "You can upload into this folder" : "Можете да прикачите во оваа папка",
+ "Invalid ownCloud url" : "Неисправен ownCloud url",
"Shared by" : "Споделено од",
"Sharing" : "Споделување",
"A file or folder has been <strong>shared</strong>" : "Датотека или фолдер беше <strong>споделен</strong>",
"You shared %1$s with %2$s" : "Вие споделивте %1$s со %2$s",
"You shared %1$s with group %2$s" : "Вие споделивте %1$s со групата %2$s",
"%2$s shared %1$s with you" : "%2$s споделено %1$s со вас",
+ "Downloaded via public link" : "Преземи преку јавен линк",
+ "Shared with %2$s" : "Споделено со %2$s",
+ "Shared with group %2$s" : "Споделено со група %2$s",
+ "Shared with %3$s by %2$s" : "Споделено со %3$s од %2$s",
+ "Shared with group %3$s by %2$s" : "Споделено со група %3$s од %2$s",
+ "Shared via link by %2$s" : "Споделено со врска/линк од %2$s",
+ "Shared by %2$s" : "Споделено од %2$s",
+ "Shared via public link" : "Споделено со јавна врска/линк",
"Shares" : "Споделувања",
+ "Accept" : "Прифати",
+ "Decline" : "Одбиј",
"This share is password-protected" : "Ова споделување е заштитено со лозинка",
"The password is wrong. Try again." : "Лозинката е грешна. Обиди се повторно.",
"Password" : "Лозинка",
+ "No entries found in this folder" : "Нема ништо во оваа папка",
"Name" : "Име",
"Share time" : "Сподели време",
"Sorry, this link doesn’t seem to work anymore." : "Извенете, но овој линк изгледа дека повеќе не функционира.",
@@ -23,8 +47,17 @@ OC.L10N.register(
"the link expired" : "времетраењето на линкот е изминато",
"sharing is disabled" : "споделувањето не е дозволено",
"For more info, please ask the person who sent this link." : "За повеќе информации, прашајте го лицето кое ви ја испратила врската.",
+ "Add to your ownCloud" : "Додади во вашиот ownCloud",
"Download" : "Преземи",
"Download %s" : "Преземи %s",
- "Direct link" : "Директна врска"
+ "Direct link" : "Директна врска",
+ "Federated Cloud Sharing" : "Федерирано клауд споделување",
+ "Open documentation" : "Отвори ја документацијата",
+ "Federated Cloud" : "Федериран клауд",
+ "Your Federated Cloud ID:" : "Вашиот федериран Cloud ID:",
+ "Share it:" : "Сподели го:",
+ "Add to your website" : "Додади на твојот веб сајт",
+ "Share with me via ownCloud" : "Сподели со мене преку ownCloud",
+ "HTML Code:" : "HTML код:"
},
"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;");
diff --git a/apps/files_sharing/l10n/mk.json b/apps/files_sharing/l10n/mk.json
index ad7eff6078b..40bcf9f8bde 100644
--- a/apps/files_sharing/l10n/mk.json
+++ b/apps/files_sharing/l10n/mk.json
@@ -1,18 +1,42 @@
{ "translations": {
+ "Server to server sharing is not enabled on this server" : "Не е овозможено споделувањето од сервер на сервер на вашиот сервер",
+ "Invalid or untrusted SSL certificate" : "SSL сертификат кој е невалиден или недоверлив",
+ "Could not authenticate to remote share, password might be wrong" : "Не можам да се автентицирам на оддалеченото споделевање, веројатно лозинката не е исправна",
+ "Storage not valid" : "Сториџот не е валиден",
+ "Couldn't add remote share" : "Не можам да додадам оддалечено споделување",
"Shared with you" : "Споделено со тебе",
"Shared with others" : "Сподели со останатите",
"Shared by link" : "Споделено со врска",
+ "Nothing shared with you yet" : "Сеуште ништо не е споделено со вас",
+ "Nothing shared yet" : "Уште ништо не е споделено",
+ "No shared links" : "Нема споделени врски/линкови",
+ "Remote share" : "Оддалечено споделување",
+ "Remote share password" : "Лозинка за оддалечаното споделување",
"Cancel" : "Откажи",
+ "Add remote share" : "Додади оддалечно споделување",
+ "You can upload into this folder" : "Можете да прикачите во оваа папка",
+ "Invalid ownCloud url" : "Неисправен ownCloud url",
"Shared by" : "Споделено од",
"Sharing" : "Споделување",
"A file or folder has been <strong>shared</strong>" : "Датотека или фолдер беше <strong>споделен</strong>",
"You shared %1$s with %2$s" : "Вие споделивте %1$s со %2$s",
"You shared %1$s with group %2$s" : "Вие споделивте %1$s со групата %2$s",
"%2$s shared %1$s with you" : "%2$s споделено %1$s со вас",
+ "Downloaded via public link" : "Преземи преку јавен линк",
+ "Shared with %2$s" : "Споделено со %2$s",
+ "Shared with group %2$s" : "Споделено со група %2$s",
+ "Shared with %3$s by %2$s" : "Споделено со %3$s од %2$s",
+ "Shared with group %3$s by %2$s" : "Споделено со група %3$s од %2$s",
+ "Shared via link by %2$s" : "Споделено со врска/линк од %2$s",
+ "Shared by %2$s" : "Споделено од %2$s",
+ "Shared via public link" : "Споделено со јавна врска/линк",
"Shares" : "Споделувања",
+ "Accept" : "Прифати",
+ "Decline" : "Одбиј",
"This share is password-protected" : "Ова споделување е заштитено со лозинка",
"The password is wrong. Try again." : "Лозинката е грешна. Обиди се повторно.",
"Password" : "Лозинка",
+ "No entries found in this folder" : "Нема ништо во оваа папка",
"Name" : "Име",
"Share time" : "Сподели време",
"Sorry, this link doesn’t seem to work anymore." : "Извенете, но овој линк изгледа дека повеќе не функционира.",
@@ -21,8 +45,17 @@
"the link expired" : "времетраењето на линкот е изминато",
"sharing is disabled" : "споделувањето не е дозволено",
"For more info, please ask the person who sent this link." : "За повеќе информации, прашајте го лицето кое ви ја испратила врската.",
+ "Add to your ownCloud" : "Додади во вашиот ownCloud",
"Download" : "Преземи",
"Download %s" : "Преземи %s",
- "Direct link" : "Директна врска"
+ "Direct link" : "Директна врска",
+ "Federated Cloud Sharing" : "Федерирано клауд споделување",
+ "Open documentation" : "Отвори ја документацијата",
+ "Federated Cloud" : "Федериран клауд",
+ "Your Federated Cloud ID:" : "Вашиот федериран Cloud ID:",
+ "Share it:" : "Сподели го:",
+ "Add to your website" : "Додади на твојот веб сајт",
+ "Share with me via ownCloud" : "Сподели со мене преку ownCloud",
+ "HTML Code:" : "HTML код:"
},"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"
} \ No newline at end of file
diff --git a/apps/files_sharing/l10n/nb_NO.js b/apps/files_sharing/l10n/nb_NO.js
index 4f7fb08ef16..bb6cd2e08c1 100644
--- a/apps/files_sharing/l10n/nb_NO.js
+++ b/apps/files_sharing/l10n/nb_NO.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "Server til server-deling er ikke aktivert på denne serveren",
"The mountpoint name contains invalid characters." : "Navnet på oppkoblingspunktet inneholder ugyldige tegn.",
+ "Not allowed to create a federated share with the same user server" : "Ikke tillatt å opprette en Sammenknyttet sky-deling med den samme bruker-serveren",
"Invalid or untrusted SSL certificate" : "Ugyldig eller ikke tiltrodd SSL-sertifikat",
"Could not authenticate to remote share, password might be wrong" : "Klarte ikke å autentisere mot ekstern deling. Passordet kan være feil",
"Storage not valid" : "Lagerplass ikke gyldig",
diff --git a/apps/files_sharing/l10n/nb_NO.json b/apps/files_sharing/l10n/nb_NO.json
index e75f095f354..5a4852691e2 100644
--- a/apps/files_sharing/l10n/nb_NO.json
+++ b/apps/files_sharing/l10n/nb_NO.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "Server til server-deling er ikke aktivert på denne serveren",
"The mountpoint name contains invalid characters." : "Navnet på oppkoblingspunktet inneholder ugyldige tegn.",
+ "Not allowed to create a federated share with the same user server" : "Ikke tillatt å opprette en Sammenknyttet sky-deling med den samme bruker-serveren",
"Invalid or untrusted SSL certificate" : "Ugyldig eller ikke tiltrodd SSL-sertifikat",
"Could not authenticate to remote share, password might be wrong" : "Klarte ikke å autentisere mot ekstern deling. Passordet kan være feil",
"Storage not valid" : "Lagerplass ikke gyldig",
diff --git a/apps/files_sharing/l10n/nl.js b/apps/files_sharing/l10n/nl.js
index 7b31b7c73e2..523213f6d9b 100644
--- a/apps/files_sharing/l10n/nl.js
+++ b/apps/files_sharing/l10n/nl.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "Server met server delen is niet geactiveerd op deze server",
"The mountpoint name contains invalid characters." : "De naam van het mountpoint bevat ongeldige karakters.",
+ "Not allowed to create a federated share with the same user server" : "Het is niet toegestaan om een gefedereerde share met dezelfde gebruikersserver te maken",
"Invalid or untrusted SSL certificate" : "Ongeldig of onvertrouwd SSL-certificaat",
"Could not authenticate to remote share, password might be wrong" : "Kon niet authenticeren bij externe share, misschien verkeerd wachtwoord",
"Storage not valid" : "Opslag ongeldig",
diff --git a/apps/files_sharing/l10n/nl.json b/apps/files_sharing/l10n/nl.json
index 92ba1c04268..e6501e874ea 100644
--- a/apps/files_sharing/l10n/nl.json
+++ b/apps/files_sharing/l10n/nl.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "Server met server delen is niet geactiveerd op deze server",
"The mountpoint name contains invalid characters." : "De naam van het mountpoint bevat ongeldige karakters.",
+ "Not allowed to create a federated share with the same user server" : "Het is niet toegestaan om een gefedereerde share met dezelfde gebruikersserver te maken",
"Invalid or untrusted SSL certificate" : "Ongeldig of onvertrouwd SSL-certificaat",
"Could not authenticate to remote share, password might be wrong" : "Kon niet authenticeren bij externe share, misschien verkeerd wachtwoord",
"Storage not valid" : "Opslag ongeldig",
diff --git a/apps/files_sharing/l10n/pt_BR.js b/apps/files_sharing/l10n/pt_BR.js
index d2dac6d5955..2faf1455480 100644
--- a/apps/files_sharing/l10n/pt_BR.js
+++ b/apps/files_sharing/l10n/pt_BR.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "Compartilhamento de servidor para servidor não está habilitado no servidor",
"The mountpoint name contains invalid characters." : "O nome do ponto de montagem contém caracteres inválidos.",
+ "Not allowed to create a federated share with the same user server" : "Não permitido para criar um compartilhamento associado com o mesmo servidor do usuário",
"Invalid or untrusted SSL certificate" : "Certificado SSL inválido ou não confiável",
"Could not authenticate to remote share, password might be wrong" : "Não foi possível autenticação com o compartilhamento remoto, a senha deve estar errada",
"Storage not valid" : "Armazenamento não válido",
@@ -27,8 +28,8 @@ OC.L10N.register(
"Shared by" : "Compartilhado por",
"Sharing" : "Compartilhamento",
"A file or folder has been <strong>shared</strong>" : "Um arquivo ou pasta foi <strong>compartilhado</strong> ",
- "A file or folder was shared from <strong>another server</strong>" : "Um arquivo ou pasta foi compartilhada a partir de <strong>outro servidor</strong>",
- "A public shared file or folder was <strong>downloaded</strong>" : "Um arquivo ou pasta compartilhada publicamente foi <strong>baixado</strong>",
+ "A file or folder was shared from <strong>another server</strong>" : "Um arquivo ou pasta foi compartilhado a partir de <strong>outro servidor</strong>",
+ "A public shared file or folder was <strong>downloaded</strong>" : "Um arquivo ou pasta compartilhado publicamente foi <strong>baixado</strong>",
"You received a new remote share %2$s from %1$s" : "Você recebeu um novo conpartilhamento remoto %2$s de %1$s",
"You received a new remote share from %s" : "Você recebeu um novo compartilhamento remoto de %s",
"%1$s accepted remote share %2$s" : "%1$s aceitou o compartilhamento remoto %2$s",
@@ -55,14 +56,14 @@ OC.L10N.register(
"You received %2$s as a remote share from %1$s" : "Você recebeu %2$s como um compartilhamento remoto de %1$s",
"Accept" : "Aceitar",
"Decline" : "Rejeitar",
- "Share with me through my #ownCloud Federated Cloud ID, see %s" : "Compartilhe comigo através do meu #ownCloud Nuvem Federados ID, veja %s",
- "Share with me through my #ownCloud Federated Cloud ID" : "Compartilhe comigo através do meu #ownCloud Nuvem Federados ID",
+ "Share with me through my #ownCloud Federated Cloud ID, see %s" : "Compartilhe comigo através do meu #ownCloud Nuvem ID Associada, veja %s",
+ "Share with me through my #ownCloud Federated Cloud ID" : "Compartilhe comigo através do meu #ownCloud Nuvem ID Associada",
"This share is password-protected" : "Este compartilhamento esta protegido por senha",
"The password is wrong. Try again." : "Senha incorreta. Tente novamente.",
"Password" : "Senha",
"No entries found in this folder" : "Nenhuma entrada foi encontrada nesta pasta",
"Name" : "Nome",
- "Share time" : "Tempo de compartilhamento",
+ "Share time" : "Data compartilhado",
"Sorry, this link doesn’t seem to work anymore." : "Desculpe, este link parece não mais funcionar.",
"Reasons might be:" : "As razões podem ser:",
"the item was removed" : "o item foi removido",
@@ -73,12 +74,12 @@ OC.L10N.register(
"Download" : "Baixar",
"Download %s" : "Baixar %s",
"Direct link" : "Link direto",
- "Federated Cloud Sharing" : "Compartilhamento de Nuvem Conglomerada",
+ "Federated Cloud Sharing" : "Compartilhamento de Nuvem Associada",
"Open documentation" : "Abrir documentação",
"Allow users on this server to send shares to other servers" : "Permitir que os usuários deste servidor enviem compartilhamentos para outros servidores",
"Allow users on this server to receive shares from other servers" : "Permitir que os usuários nesse servidor recebam compartilhamentos de outros servidores",
- "Federated Cloud" : "Nuvem Conglomerada",
- "Your Federated Cloud ID:" : "Seu Federados Nuvem ID:",
+ "Federated Cloud" : "Nuvem Associada",
+ "Your Federated Cloud ID:" : "Sua ID na Nuvem Associada:",
"Share it:" : "Compartilhe:",
"Add to your website" : "Adicione ao seu website",
"Share with me via ownCloud" : "Compartilhe comigo via ownCloud",
diff --git a/apps/files_sharing/l10n/pt_BR.json b/apps/files_sharing/l10n/pt_BR.json
index e64c07ff8e0..51e6e9e6f0a 100644
--- a/apps/files_sharing/l10n/pt_BR.json
+++ b/apps/files_sharing/l10n/pt_BR.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "Compartilhamento de servidor para servidor não está habilitado no servidor",
"The mountpoint name contains invalid characters." : "O nome do ponto de montagem contém caracteres inválidos.",
+ "Not allowed to create a federated share with the same user server" : "Não permitido para criar um compartilhamento associado com o mesmo servidor do usuário",
"Invalid or untrusted SSL certificate" : "Certificado SSL inválido ou não confiável",
"Could not authenticate to remote share, password might be wrong" : "Não foi possível autenticação com o compartilhamento remoto, a senha deve estar errada",
"Storage not valid" : "Armazenamento não válido",
@@ -25,8 +26,8 @@
"Shared by" : "Compartilhado por",
"Sharing" : "Compartilhamento",
"A file or folder has been <strong>shared</strong>" : "Um arquivo ou pasta foi <strong>compartilhado</strong> ",
- "A file or folder was shared from <strong>another server</strong>" : "Um arquivo ou pasta foi compartilhada a partir de <strong>outro servidor</strong>",
- "A public shared file or folder was <strong>downloaded</strong>" : "Um arquivo ou pasta compartilhada publicamente foi <strong>baixado</strong>",
+ "A file or folder was shared from <strong>another server</strong>" : "Um arquivo ou pasta foi compartilhado a partir de <strong>outro servidor</strong>",
+ "A public shared file or folder was <strong>downloaded</strong>" : "Um arquivo ou pasta compartilhado publicamente foi <strong>baixado</strong>",
"You received a new remote share %2$s from %1$s" : "Você recebeu um novo conpartilhamento remoto %2$s de %1$s",
"You received a new remote share from %s" : "Você recebeu um novo compartilhamento remoto de %s",
"%1$s accepted remote share %2$s" : "%1$s aceitou o compartilhamento remoto %2$s",
@@ -53,14 +54,14 @@
"You received %2$s as a remote share from %1$s" : "Você recebeu %2$s como um compartilhamento remoto de %1$s",
"Accept" : "Aceitar",
"Decline" : "Rejeitar",
- "Share with me through my #ownCloud Federated Cloud ID, see %s" : "Compartilhe comigo através do meu #ownCloud Nuvem Federados ID, veja %s",
- "Share with me through my #ownCloud Federated Cloud ID" : "Compartilhe comigo através do meu #ownCloud Nuvem Federados ID",
+ "Share with me through my #ownCloud Federated Cloud ID, see %s" : "Compartilhe comigo através do meu #ownCloud Nuvem ID Associada, veja %s",
+ "Share with me through my #ownCloud Federated Cloud ID" : "Compartilhe comigo através do meu #ownCloud Nuvem ID Associada",
"This share is password-protected" : "Este compartilhamento esta protegido por senha",
"The password is wrong. Try again." : "Senha incorreta. Tente novamente.",
"Password" : "Senha",
"No entries found in this folder" : "Nenhuma entrada foi encontrada nesta pasta",
"Name" : "Nome",
- "Share time" : "Tempo de compartilhamento",
+ "Share time" : "Data compartilhado",
"Sorry, this link doesn’t seem to work anymore." : "Desculpe, este link parece não mais funcionar.",
"Reasons might be:" : "As razões podem ser:",
"the item was removed" : "o item foi removido",
@@ -71,12 +72,12 @@
"Download" : "Baixar",
"Download %s" : "Baixar %s",
"Direct link" : "Link direto",
- "Federated Cloud Sharing" : "Compartilhamento de Nuvem Conglomerada",
+ "Federated Cloud Sharing" : "Compartilhamento de Nuvem Associada",
"Open documentation" : "Abrir documentação",
"Allow users on this server to send shares to other servers" : "Permitir que os usuários deste servidor enviem compartilhamentos para outros servidores",
"Allow users on this server to receive shares from other servers" : "Permitir que os usuários nesse servidor recebam compartilhamentos de outros servidores",
- "Federated Cloud" : "Nuvem Conglomerada",
- "Your Federated Cloud ID:" : "Seu Federados Nuvem ID:",
+ "Federated Cloud" : "Nuvem Associada",
+ "Your Federated Cloud ID:" : "Sua ID na Nuvem Associada:",
"Share it:" : "Compartilhe:",
"Add to your website" : "Adicione ao seu website",
"Share with me via ownCloud" : "Compartilhe comigo via ownCloud",
diff --git a/apps/files_sharing/l10n/pt_PT.js b/apps/files_sharing/l10n/pt_PT.js
index c0a79ac58fa..afe04a57b90 100644
--- a/apps/files_sharing/l10n/pt_PT.js
+++ b/apps/files_sharing/l10n/pt_PT.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "A partilha entre servidores não se encontra disponível neste servidor",
"The mountpoint name contains invalid characters." : "O nome do ponto de montagem contém carateres inválidos.",
+ "Not allowed to create a federated share with the same user server" : "Não é possível criar uma partilha federada com o mesmo servidor de utilizador",
"Invalid or untrusted SSL certificate" : "Certificado SSL inválido ou não confiável",
"Could not authenticate to remote share, password might be wrong" : "Não foi possível autenticar para a partilha remota, a palavra-passe poderá estar errada",
"Storage not valid" : "Armazenamento inválido",
diff --git a/apps/files_sharing/l10n/pt_PT.json b/apps/files_sharing/l10n/pt_PT.json
index f57f939e5cb..190187b1500 100644
--- a/apps/files_sharing/l10n/pt_PT.json
+++ b/apps/files_sharing/l10n/pt_PT.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "A partilha entre servidores não se encontra disponível neste servidor",
"The mountpoint name contains invalid characters." : "O nome do ponto de montagem contém carateres inválidos.",
+ "Not allowed to create a federated share with the same user server" : "Não é possível criar uma partilha federada com o mesmo servidor de utilizador",
"Invalid or untrusted SSL certificate" : "Certificado SSL inválido ou não confiável",
"Could not authenticate to remote share, password might be wrong" : "Não foi possível autenticar para a partilha remota, a palavra-passe poderá estar errada",
"Storage not valid" : "Armazenamento inválido",
diff --git a/apps/files_sharing/l10n/ru.js b/apps/files_sharing/l10n/ru.js
index 1a84d10ecea..15b26160f6e 100644
--- a/apps/files_sharing/l10n/ru.js
+++ b/apps/files_sharing/l10n/ru.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "На данном сервере выключено межсерверное предоставление общего доступа",
"The mountpoint name contains invalid characters." : "Имя точки монтирования содержит недопустимые символы.",
+ "Not allowed to create a federated share with the same user server" : "Не допускается создание федеративного общего ресурса с тем-же сервером пользователя",
"Invalid or untrusted SSL certificate" : "Недействительный или недоверенный сертификат SSL",
"Could not authenticate to remote share, password might be wrong" : "Не удалось произвести аутентификацию для доступа к удалённому хранилищу, возможно неправильно указан пароль",
"Storage not valid" : "Хранилище недоступно",
diff --git a/apps/files_sharing/l10n/ru.json b/apps/files_sharing/l10n/ru.json
index 401896709d6..3b92d4cc4c3 100644
--- a/apps/files_sharing/l10n/ru.json
+++ b/apps/files_sharing/l10n/ru.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "На данном сервере выключено межсерверное предоставление общего доступа",
"The mountpoint name contains invalid characters." : "Имя точки монтирования содержит недопустимые символы.",
+ "Not allowed to create a federated share with the same user server" : "Не допускается создание федеративного общего ресурса с тем-же сервером пользователя",
"Invalid or untrusted SSL certificate" : "Недействительный или недоверенный сертификат SSL",
"Could not authenticate to remote share, password might be wrong" : "Не удалось произвести аутентификацию для доступа к удалённому хранилищу, возможно неправильно указан пароль",
"Storage not valid" : "Хранилище недоступно",
diff --git a/apps/files_sharing/l10n/sl.js b/apps/files_sharing/l10n/sl.js
index 3b6622aedf2..3624766ecee 100644
--- a/apps/files_sharing/l10n/sl.js
+++ b/apps/files_sharing/l10n/sl.js
@@ -21,6 +21,7 @@ OC.L10N.register(
"Remote share password" : "Geslo za mesto za oddaljeno souporabo",
"Cancel" : "Prekliči",
"Add remote share" : "Dodaj oddaljeno mesto za souporabo",
+ "You can upload into this folder" : "V to mapo je dovoljeno poslati datoteke",
"No ownCloud installation (7 or higher) found at {remote}" : "Na mestu {remote} ni nameščenega okolja ownCloud (različice 7 ali višje)",
"Invalid ownCloud url" : "Naveden je neveljaven naslov URL strežnika ownCloud",
"Shared by" : "V souporabi z",
@@ -40,6 +41,7 @@ OC.L10N.register(
"You shared %1$s via link" : "Omogočili ste souporabo %1$s preko povezave",
"Shares" : "Souporaba",
"Accept" : "Sprejmi",
+ "Decline" : "Zavrni",
"This share is password-protected" : "To mesto je zaščiteno z geslom.",
"The password is wrong. Try again." : "Geslo je napačno. Poskusite znova.",
"Password" : "Geslo",
@@ -60,6 +62,7 @@ OC.L10N.register(
"Open documentation" : "Odpri dokumentacijo",
"Allow users on this server to send shares to other servers" : "Dovoli uporabnikom tega strežnika pošiljanje map za souporabo na druge strežnike.",
"Allow users on this server to receive shares from other servers" : "Dovoli uporabnikom tega strežnika sprejemanje map za souporabo z drugih strežnikov.",
+ "Add to your website" : "Dodaj na spletišče",
"HTML Code:" : "Koda HTML:"
},
"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);");
diff --git a/apps/files_sharing/l10n/sl.json b/apps/files_sharing/l10n/sl.json
index 2d443de13d9..758097746bc 100644
--- a/apps/files_sharing/l10n/sl.json
+++ b/apps/files_sharing/l10n/sl.json
@@ -19,6 +19,7 @@
"Remote share password" : "Geslo za mesto za oddaljeno souporabo",
"Cancel" : "Prekliči",
"Add remote share" : "Dodaj oddaljeno mesto za souporabo",
+ "You can upload into this folder" : "V to mapo je dovoljeno poslati datoteke",
"No ownCloud installation (7 or higher) found at {remote}" : "Na mestu {remote} ni nameščenega okolja ownCloud (različice 7 ali višje)",
"Invalid ownCloud url" : "Naveden je neveljaven naslov URL strežnika ownCloud",
"Shared by" : "V souporabi z",
@@ -38,6 +39,7 @@
"You shared %1$s via link" : "Omogočili ste souporabo %1$s preko povezave",
"Shares" : "Souporaba",
"Accept" : "Sprejmi",
+ "Decline" : "Zavrni",
"This share is password-protected" : "To mesto je zaščiteno z geslom.",
"The password is wrong. Try again." : "Geslo je napačno. Poskusite znova.",
"Password" : "Geslo",
@@ -58,6 +60,7 @@
"Open documentation" : "Odpri dokumentacijo",
"Allow users on this server to send shares to other servers" : "Dovoli uporabnikom tega strežnika pošiljanje map za souporabo na druge strežnike.",
"Allow users on this server to receive shares from other servers" : "Dovoli uporabnikom tega strežnika sprejemanje map za souporabo z drugih strežnikov.",
+ "Add to your website" : "Dodaj na spletišče",
"HTML Code:" : "Koda HTML:"
},"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files_sharing/l10n/sq.js b/apps/files_sharing/l10n/sq.js
index 413214d58de..699578fb0fc 100644
--- a/apps/files_sharing/l10n/sq.js
+++ b/apps/files_sharing/l10n/sq.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "Ndarja mes shërbyesish s’është e aktivizuar në këtë shërbyes",
"The mountpoint name contains invalid characters." : "Emri i pikës së montimit përmban shenja të pavlefshme.",
+ "Not allowed to create a federated share with the same user server" : "Nuk i lejohet të krijojë një ndarje të federuar me të njëjtin shërbyes përdoruesi",
"Invalid or untrusted SSL certificate" : "Dëshmi SSL e pavlefshme ose e pabesuar",
"Could not authenticate to remote share, password might be wrong" : "S’bëri dot mirëfilltësimin te ndarja e largët, fjalëkalimi mund të jetë i gabuar",
"Storage not valid" : "Depozitë jo e vlefshme",
@@ -33,6 +34,7 @@ OC.L10N.register(
"You received a new remote share from %s" : "Morët një ndarje të largët nga %s",
"%1$s accepted remote share %2$s" : "%1$s pranoi ndarjen e largët %2$s",
"%1$s declined remote share %2$s" : "%1$s hodhi tej ndarjen e largët %2$s",
+ "%1$s unshared %2$s from you" : "%1$s shndau me ju %2$s",
"Public shared folder %1$s was downloaded" : "U shkarkua dosja e ndarë publikisht %1$s",
"Public shared file %1$s was downloaded" : "U shkarkua kartela e ndarë publikisht %1$s",
"You shared %1$s with %2$s" : "Ndatë %1$s me %2$s",
@@ -72,10 +74,12 @@ OC.L10N.register(
"Download" : "Shkarko",
"Download %s" : "Shkarko %s",
"Direct link" : "Lidhje e drejtpërdrejtë",
+ "Federated Cloud Sharing" : "Ndarje e Federuar Në Re",
"Open documentation" : "Hap dokumentimin",
"Allow users on this server to send shares to other servers" : "Lejoju përdoruesve në këtë shërbyes të dërgojnë ndarje në shërbyes të tjerë",
"Allow users on this server to receive shares from other servers" : "Lejoju përdoruesve në këtë shërbyes të marrin ndarje nga shërbyes të tjerë",
- "Your Federated Cloud ID:" : "ID-ja juaj Federated Cloud:",
+ "Federated Cloud" : "Re e Federuar",
+ "Your Federated Cloud ID:" : "ID-ja juaj për Re të Federuar:",
"Share it:" : "Ndajeni:",
"Add to your website" : "Shtojeni te sajti juaj",
"Share with me via ownCloud" : "Ndani me mua përmes ownCloud-it",
diff --git a/apps/files_sharing/l10n/sq.json b/apps/files_sharing/l10n/sq.json
index 8722966f5da..92c76b4c509 100644
--- a/apps/files_sharing/l10n/sq.json
+++ b/apps/files_sharing/l10n/sq.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "Ndarja mes shërbyesish s’është e aktivizuar në këtë shërbyes",
"The mountpoint name contains invalid characters." : "Emri i pikës së montimit përmban shenja të pavlefshme.",
+ "Not allowed to create a federated share with the same user server" : "Nuk i lejohet të krijojë një ndarje të federuar me të njëjtin shërbyes përdoruesi",
"Invalid or untrusted SSL certificate" : "Dëshmi SSL e pavlefshme ose e pabesuar",
"Could not authenticate to remote share, password might be wrong" : "S’bëri dot mirëfilltësimin te ndarja e largët, fjalëkalimi mund të jetë i gabuar",
"Storage not valid" : "Depozitë jo e vlefshme",
@@ -31,6 +32,7 @@
"You received a new remote share from %s" : "Morët një ndarje të largët nga %s",
"%1$s accepted remote share %2$s" : "%1$s pranoi ndarjen e largët %2$s",
"%1$s declined remote share %2$s" : "%1$s hodhi tej ndarjen e largët %2$s",
+ "%1$s unshared %2$s from you" : "%1$s shndau me ju %2$s",
"Public shared folder %1$s was downloaded" : "U shkarkua dosja e ndarë publikisht %1$s",
"Public shared file %1$s was downloaded" : "U shkarkua kartela e ndarë publikisht %1$s",
"You shared %1$s with %2$s" : "Ndatë %1$s me %2$s",
@@ -70,10 +72,12 @@
"Download" : "Shkarko",
"Download %s" : "Shkarko %s",
"Direct link" : "Lidhje e drejtpërdrejtë",
+ "Federated Cloud Sharing" : "Ndarje e Federuar Në Re",
"Open documentation" : "Hap dokumentimin",
"Allow users on this server to send shares to other servers" : "Lejoju përdoruesve në këtë shërbyes të dërgojnë ndarje në shërbyes të tjerë",
"Allow users on this server to receive shares from other servers" : "Lejoju përdoruesve në këtë shërbyes të marrin ndarje nga shërbyes të tjerë",
- "Your Federated Cloud ID:" : "ID-ja juaj Federated Cloud:",
+ "Federated Cloud" : "Re e Federuar",
+ "Your Federated Cloud ID:" : "ID-ja juaj për Re të Federuar:",
"Share it:" : "Ndajeni:",
"Add to your website" : "Shtojeni te sajti juaj",
"Share with me via ownCloud" : "Ndani me mua përmes ownCloud-it",
diff --git a/apps/files_sharing/l10n/th_TH.js b/apps/files_sharing/l10n/th_TH.js
index b1400469af8..b0022e9d959 100644
--- a/apps/files_sharing/l10n/th_TH.js
+++ b/apps/files_sharing/l10n/th_TH.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "เซิร์ฟเวอร์ไปยังแชร์เซิร์ฟเวอร์ไม่ได้เปิดใช้งานบนเซิร์ฟเวอร์นี้",
"The mountpoint name contains invalid characters." : "ชื่อจุดเชื่อมต่อมีตัวอักษรที่ไม่ถูกต้อง",
+ "Not allowed to create a federated share with the same user server" : "ไม่อนุญาตให้สร้างแชร์ในเครือกับเซิร์ฟเวอร์ที่มีผู้ใช้เดียวกัน",
"Invalid or untrusted SSL certificate" : "ใบรับรอง SSL ไม่ถูกต้องหรือไม่น่าเชื่อถือ",
"Could not authenticate to remote share, password might be wrong" : "ไม่สามารถรับรองความถูกต้องจากการแชร์ระยะไกลรหัสผ่านอาจจะผิด",
"Storage not valid" : "การจัดเก็บข้อมูลไม่ถูกต้อง",
diff --git a/apps/files_sharing/l10n/th_TH.json b/apps/files_sharing/l10n/th_TH.json
index a9ee8d6eb53..d973ad6ba19 100644
--- a/apps/files_sharing/l10n/th_TH.json
+++ b/apps/files_sharing/l10n/th_TH.json
@@ -1,6 +1,7 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "เซิร์ฟเวอร์ไปยังแชร์เซิร์ฟเวอร์ไม่ได้เปิดใช้งานบนเซิร์ฟเวอร์นี้",
"The mountpoint name contains invalid characters." : "ชื่อจุดเชื่อมต่อมีตัวอักษรที่ไม่ถูกต้อง",
+ "Not allowed to create a federated share with the same user server" : "ไม่อนุญาตให้สร้างแชร์ในเครือกับเซิร์ฟเวอร์ที่มีผู้ใช้เดียวกัน",
"Invalid or untrusted SSL certificate" : "ใบรับรอง SSL ไม่ถูกต้องหรือไม่น่าเชื่อถือ",
"Could not authenticate to remote share, password might be wrong" : "ไม่สามารถรับรองความถูกต้องจากการแชร์ระยะไกลรหัสผ่านอาจจะผิด",
"Storage not valid" : "การจัดเก็บข้อมูลไม่ถูกต้อง",
diff --git a/apps/files_sharing/l10n/zh_TW.js b/apps/files_sharing/l10n/zh_TW.js
index 58d0398a1d5..7416545bc4c 100644
--- a/apps/files_sharing/l10n/zh_TW.js
+++ b/apps/files_sharing/l10n/zh_TW.js
@@ -3,11 +3,12 @@ OC.L10N.register(
{
"Server to server sharing is not enabled on this server" : "伺服器對伺服器共享在這台伺服器上面並未啟用",
"The mountpoint name contains invalid characters." : "掛載的名稱含有不合法的字元",
- "Invalid or untrusted SSL certificate" : "無效或是不信任的SSL憑證",
+ "Not allowed to create a federated share with the same user server" : "不允許在同一個使用者伺服器建立聯盟式分享",
+ "Invalid or untrusted SSL certificate" : "無效或是不信任的 SSL憑證",
"Could not authenticate to remote share, password might be wrong" : "無法驗證遠端分享,可能是密碼錯誤",
"Storage not valid" : "儲存空間無法使用",
"Couldn't add remote share" : "無法加入遠端分享",
- "Shared with you" : "與你分享",
+ "Shared with you" : "與您分享",
"Shared with others" : "與其他人分享",
"Shared by link" : "由連結分享",
"Nothing shared with you yet" : "目前沒有任何與您分享的內容",
@@ -24,7 +25,7 @@ OC.L10N.register(
"You can upload into this folder" : "你可以上傳內容到此資料夾",
"No ownCloud installation (7 or higher) found at {remote}" : "沒有在 {remote} 找到 ownCloud (本版7 或 更新版)",
"Invalid ownCloud url" : "無效的 ownCloud URL",
- "Shared by" : "由...分享",
+ "Shared by" : "分享自",
"Sharing" : "分享",
"A file or folder has been <strong>shared</strong>" : "檔案或目錄已被 <strong>分享</strong>",
"A file or folder was shared from <strong>another server</strong>" : "檔案或目錄已被 <strong>其他伺服器</strong> 分享",
@@ -52,11 +53,11 @@ OC.L10N.register(
"Shared by %2$s" : "由 %2$s 分享",
"Shared via public link" : "透過公用連結分享",
"Shares" : "分享",
- "You received %2$s as a remote share from %1$s" : "您收到了來自%1$s的一個遠端分享 %2$s ",
+ "You received %2$s as a remote share from %1$s" : "您收到了來自 %1$s 的一個遠端分享 %2$s ",
"Accept" : "接受",
"Decline" : "拒絕",
- "Share with me through my #ownCloud Federated Cloud ID, see %s" : "可透過我的 #ownCloud 聯合 ID,與我分享,請看 %s",
- "Share with me through my #ownCloud Federated Cloud ID" : "可透過我的 #ownCloud 聯合 ID,與我分享",
+ "Share with me through my #ownCloud Federated Cloud ID, see %s" : "可透過我的 #ownCloud 聯盟雲端 ID,與我分享,請看 %s",
+ "Share with me through my #ownCloud Federated Cloud ID" : "可透過我的 #ownCloud 聯盟雲端 ID,與我分享",
"This share is password-protected" : "這個分享有密碼保護",
"The password is wrong. Try again." : "請檢查您的密碼並再試一次",
"Password" : "密碼",
@@ -78,10 +79,10 @@ OC.L10N.register(
"Allow users on this server to send shares to other servers" : "允許這台伺服器上的使用者發送分享給其他伺服器",
"Allow users on this server to receive shares from other servers" : "允許這台伺服器上的使用者發送接收來自其他伺服器的分享",
"Federated Cloud" : "聯盟式雲端",
- "Your Federated Cloud ID:" : "您的雲端聯盟ID:",
- "Share it:" : "分享它:",
+ "Your Federated Cloud ID:" : "您的雲端聯盟 ID:",
+ "Share it:" : "分享它:",
"Add to your website" : "新增至您的網站",
- "Share with me via ownCloud" : "透果ownCloud與我分享",
- "HTML Code:" : "HTML 代碼:"
+ "Share with me via ownCloud" : "透過 ownCloud 與我分享",
+ "HTML Code:" : "HTML Code:"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_sharing/l10n/zh_TW.json b/apps/files_sharing/l10n/zh_TW.json
index e73bbfa6574..0a2a18bc5f8 100644
--- a/apps/files_sharing/l10n/zh_TW.json
+++ b/apps/files_sharing/l10n/zh_TW.json
@@ -1,11 +1,12 @@
{ "translations": {
"Server to server sharing is not enabled on this server" : "伺服器對伺服器共享在這台伺服器上面並未啟用",
"The mountpoint name contains invalid characters." : "掛載的名稱含有不合法的字元",
- "Invalid or untrusted SSL certificate" : "無效或是不信任的SSL憑證",
+ "Not allowed to create a federated share with the same user server" : "不允許在同一個使用者伺服器建立聯盟式分享",
+ "Invalid or untrusted SSL certificate" : "無效或是不信任的 SSL憑證",
"Could not authenticate to remote share, password might be wrong" : "無法驗證遠端分享,可能是密碼錯誤",
"Storage not valid" : "儲存空間無法使用",
"Couldn't add remote share" : "無法加入遠端分享",
- "Shared with you" : "與你分享",
+ "Shared with you" : "與您分享",
"Shared with others" : "與其他人分享",
"Shared by link" : "由連結分享",
"Nothing shared with you yet" : "目前沒有任何與您分享的內容",
@@ -22,7 +23,7 @@
"You can upload into this folder" : "你可以上傳內容到此資料夾",
"No ownCloud installation (7 or higher) found at {remote}" : "沒有在 {remote} 找到 ownCloud (本版7 或 更新版)",
"Invalid ownCloud url" : "無效的 ownCloud URL",
- "Shared by" : "由...分享",
+ "Shared by" : "分享自",
"Sharing" : "分享",
"A file or folder has been <strong>shared</strong>" : "檔案或目錄已被 <strong>分享</strong>",
"A file or folder was shared from <strong>another server</strong>" : "檔案或目錄已被 <strong>其他伺服器</strong> 分享",
@@ -50,11 +51,11 @@
"Shared by %2$s" : "由 %2$s 分享",
"Shared via public link" : "透過公用連結分享",
"Shares" : "分享",
- "You received %2$s as a remote share from %1$s" : "您收到了來自%1$s的一個遠端分享 %2$s ",
+ "You received %2$s as a remote share from %1$s" : "您收到了來自 %1$s 的一個遠端分享 %2$s ",
"Accept" : "接受",
"Decline" : "拒絕",
- "Share with me through my #ownCloud Federated Cloud ID, see %s" : "可透過我的 #ownCloud 聯合 ID,與我分享,請看 %s",
- "Share with me through my #ownCloud Federated Cloud ID" : "可透過我的 #ownCloud 聯合 ID,與我分享",
+ "Share with me through my #ownCloud Federated Cloud ID, see %s" : "可透過我的 #ownCloud 聯盟雲端 ID,與我分享,請看 %s",
+ "Share with me through my #ownCloud Federated Cloud ID" : "可透過我的 #ownCloud 聯盟雲端 ID,與我分享",
"This share is password-protected" : "這個分享有密碼保護",
"The password is wrong. Try again." : "請檢查您的密碼並再試一次",
"Password" : "密碼",
@@ -76,10 +77,10 @@
"Allow users on this server to send shares to other servers" : "允許這台伺服器上的使用者發送分享給其他伺服器",
"Allow users on this server to receive shares from other servers" : "允許這台伺服器上的使用者發送接收來自其他伺服器的分享",
"Federated Cloud" : "聯盟式雲端",
- "Your Federated Cloud ID:" : "您的雲端聯盟ID:",
- "Share it:" : "分享它:",
+ "Your Federated Cloud ID:" : "您的雲端聯盟 ID:",
+ "Share it:" : "分享它:",
"Add to your website" : "新增至您的網站",
- "Share with me via ownCloud" : "透果ownCloud與我分享",
- "HTML Code:" : "HTML 代碼:"
+ "Share with me via ownCloud" : "透過 ownCloud 與我分享",
+ "HTML Code:" : "HTML Code:"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_sharing/lib/activity.php b/apps/files_sharing/lib/activity.php
index c5eb7d09ede..37a8113b916 100644
--- a/apps/files_sharing/lib/activity.php
+++ b/apps/files_sharing/lib/activity.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php
index 2e615e231f1..c44bebbceaf 100644
--- a/apps/files_sharing/lib/cache.php
+++ b/apps/files_sharing/lib/cache.php
@@ -7,13 +7,13 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,227 +32,75 @@
namespace OC\Files\Cache;
-use OC\User\NoUserException;
-use OCP\Share_Backend_Collection;
+use OC\Files\Cache\Wrapper\CacheJail;
+use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\Storage\IStorage;
/**
* Metadata cache for shared files
*
* don't use this class directly if you need to get metadata, use \OC\Files\Filesystem::getFileInfo instead
*/
-class Shared_Cache extends Cache {
-
- private $storage;
- private $files = array();
-
+class Shared_Cache extends CacheJail {
/**
- * @param \OC\Files\Storage\Shared $storage
+ * @var \OC\Files\Storage\Shared
*/
- public function __construct($storage) {
- parent::__construct($storage);
- $this->storage = $storage;
- }
+ private $storage;
/**
- * Get the source cache of a shared file or folder
- *
- * @param string $target Shared target file path
- * @return \OC\Files\Cache\Cache|false
+ * @var IStorage
*/
- private function getSourceCache($target) {
- if ($target === false || $target === $this->storage->getMountPoint()) {
- $target = '';
- }
- $source = \OC_Share_Backend_File::getSource($target, $this->storage->getShare());
- if (isset($source['path']) && isset($source['fileOwner'])) {
- try {
- \OC\Files\Filesystem::initMountPoints($source['fileOwner']);
- } catch(NoUserException $e) {
- \OC::$server->getLogger()->logException($e, ['app' => 'files_sharing']);
- return false;
- }
- $mounts = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
- if (is_array($mounts) and !empty($mounts)) {
- $fullPath = $mounts[0]->getMountPoint() . $source['path'];
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($fullPath);
- if ($storage) {
- $this->files[$target] = $internalPath;
- $cache = $storage->getCache();
- $this->storageId = $storage->getId();
- $this->numericId = $cache->getNumericStorageId();
- return $cache;
- }
- }
- }
- return false;
- }
-
- public function getNumericStorageId() {
- if (isset($this->numericId)) {
- return $this->numericId;
- } else {
- return false;
- }
- }
+ private $sourceStorage;
/**
- * get the stored metadata of a file or folder
- *
- * @param string|int $file
- * @return array|false
+ * @var ICacheEntry
*/
- public function get($file) {
- $mimetypeLoader = \OC::$server->getMimeTypeLoader();
- if (is_string($file)) {
- $cache = $this->getSourceCache($file);
- if ($cache) {
- $data = $cache->get($this->files[$file]);
- if ($data) {
- $data['displayname_owner'] = \OC_User::getDisplayName($this->storage->getSharedFrom());
- $data['path'] = $file;
- if ($file === '') {
- $data['is_share_mount_point'] = true;
- }
- $data['uid_owner'] = $this->storage->getOwner($file);
- if (isset($data['permissions'])) {
- $data['permissions'] &= $this->storage->getPermissions($file);
- } else {
- $data['permissions'] = $this->storage->getPermissions($file);
- }
- }
- return $data;
- }
- } else {
- $sourceId = $file;
- // if we are at the root of the mount point we want to return the
- // cache information for the source item
- if (!is_int($sourceId) || $sourceId === 0) {
- $sourceId = $this->storage->getSourceId();
- }
- $query = \OCP\DB::prepare(
- 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,'
- . ' `size`, `mtime`, `encrypted`, `storage_mtime`, `etag`, `permissions`'
- . ' FROM `*PREFIX*filecache` WHERE `fileid` = ?');
- $result = $query->execute(array($sourceId));
- $data = $result->fetchRow();
- $data['fileid'] = (int)$data['fileid'];
- $data['mtime'] = (int)$data['mtime'];
- $data['storage_mtime'] = (int)$data['storage_mtime'];
- $data['encrypted'] = (bool)$data['encrypted'];
- $data['mimetype'] = $mimetypeLoader->getMimetypeById($data['mimetype']);
- $data['mimepart'] = $mimetypeLoader->getMimetypeById($data['mimepart']);
- if ($data['storage_mtime'] === 0) {
- $data['storage_mtime'] = $data['mtime'];
- }
- $data['size'] = (int)$data['size'];
- $data['permissions'] = (int)$data['permissions'];
- if (!is_int($file) || $file === 0) {
- $data['path'] = '';
- $data['name'] = basename($this->storage->getMountPoint());
- $data['is_share_mount_point'] = true;
- }
- $data['permissions'] &= $this->storage->getPermissions('');
- return $data;
- }
- return false;
- }
+ private $sourceRootInfo;
/**
- * get the metadata of all files stored in $folder
- *
- * @param string $folderId
- * @return array|false
+ * @var \OCP\Files\Cache\ICache
*/
- public function getFolderContentsById($folderId) {
- $cache = $this->getSourceCache('');
- if ($cache) {
- $owner = $this->storage->getSharedFrom();
- $parentPath = $this->getPathById($folderId);
- if ($parentPath !== '') {
- $parentPath .= '/';
- }
- $sourceFolderContent = $cache->getFolderContentsById($folderId);
- foreach ($sourceFolderContent as &$c) {
- $c['path'] = ltrim($parentPath . $c['name'], '/');
- $c['uid_owner'] = $owner;
- $c['displayname_owner'] = \OC_User::getDisplayName($owner);
- $c['permissions'] = $c['permissions'] & $this->storage->getPermissions(false);
- }
-
- return $sourceFolderContent;
- }
-
- return false;
- }
+ private $sourceCache;
/**
- * store meta data for a file or folder
- *
- * @param string $file
- * @param array $data
- *
- * @return int|false file id
+ * @param \OC\Files\Storage\Shared $storage
+ * @param IStorage $sourceStorage
+ * @param ICacheEntry $sourceRootInfo
*/
- public function put($file, array $data) {
- $file = ($file === false) ? '' : $file;
- if ($cache = $this->getSourceCache($file)) {
- return $cache->put($this->files[$file], $data);
- }
- return false;
+ public function __construct($storage, IStorage $sourceStorage, ICacheEntry $sourceRootInfo) {
+ $this->storage = $storage;
+ $this->sourceStorage = $sourceStorage;
+ $this->sourceRootInfo = $sourceRootInfo;
+ $this->sourceCache = $sourceStorage->getCache();
+ parent::__construct(
+ $this->sourceCache,
+ $this->sourceRootInfo->getPath()
+ );
}
- /**
- * get the file id for a file
- *
- * @param string $file
- * @return int
- */
- public function getId($file) {
- if ($file === false) {
- return $this->storage->getSourceId();
- }
- $cache = $this->getSourceCache($file);
- if ($cache) {
- return $cache->getId($this->files[$file]);
+ public function getNumericStorageId() {
+ if (isset($this->numericId)) {
+ return $this->numericId;
+ } else {
+ return false;
}
- return -1;
}
- /**
- * check if a file is available in the cache
- *
- * @param string $file
- * @return bool
- */
- public function inCache($file) {
- if ($file == '') {
- return true;
+ protected function formatCacheEntry($entry) {
+ $path = $entry['path'];
+ $entry = parent::formatCacheEntry($entry);
+ $sharePermissions = $this->storage->getPermissions($path);
+ if (isset($entry['permissions'])) {
+ $entry['permissions'] &= $sharePermissions;
+ } else {
+ $entry['permissions'] = $sharePermissions;
}
- return parent::inCache($file);
- }
-
- /**
- * remove a file or folder from the cache
- *
- * @param string $file
- */
- public function remove($file) {
- $file = ($file === false) ? '' : $file;
- if ($cache = $this->getSourceCache($file)) {
- $cache->remove($this->files[$file]);
+ $entry['uid_owner'] = $this->storage->getOwner($path);
+ $entry['displayname_owner'] = \OC_User::getDisplayName($entry['uid_owner']);
+ if ($path === '') {
+ $entry['is_share_mount_point'] = true;
}
- }
-
- /**
- * Get the storage id and path needed for a move
- *
- * @param string $path
- * @return array [$storageId, $internalPath]
- */
- protected function getMoveInfo($path) {
- $cache = $this->getSourceCache($path);
- $file = \OC_Share_Backend_File::getSource($path, $this->storage->getShare());
- return [$cache->getNumericStorageId(), $file['path']];
+ return $entry;
}
/**
@@ -261,259 +109,4 @@ class Shared_Cache extends Cache {
public function clear() {
// Not a valid action for Shared Cache
}
-
- /**
- * @param string $file
- *
- * @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
- */
- public function getStatus($file) {
- if ($file == '') {
- return self::COMPLETE;
- }
- if ($cache = $this->getSourceCache($file)) {
- return $cache->getStatus($this->files[$file]);
- }
- return self::NOT_FOUND;
- }
-
- /**
- * search for files matching $pattern
- *
- * @param string $pattern
- * @return array of file data
- */
- public function search($pattern) {
-
- $pattern = trim($pattern, '%');
-
- $normalizedPattern = $this->normalize($pattern);
-
- $result = array();
- $exploreDirs = array('');
- while (count($exploreDirs) > 0) {
- $dir = array_pop($exploreDirs);
- $files = $this->getFolderContents($dir);
- // no results?
- if (!$files) {
- // maybe it's a single shared file
- $file = $this->get('');
- if ($normalizedPattern === '' || stristr($file['name'], $normalizedPattern) !== false) {
- $result[] = $file;
- }
- continue;
- }
- foreach ($files as $file) {
- if ($normalizedPattern === '' || stristr($file['name'], $normalizedPattern) !== false) {
- $result[] = $file;
- }
- if ($file['mimetype'] === 'httpd/unix-directory') {
- $exploreDirs[] = ltrim($dir . '/' . $file['name'], '/');
- }
- }
- }
- return $result;
-
- }
-
- /**
- * search for files by mimetype
- *
- * @param string $mimetype
- * @return array
- */
- public function searchByMime($mimetype) {
- $mimepart = null;
- if (strpos($mimetype, '/') === false) {
- $mimepart = $mimetype;
- $mimetype = null;
- }
-
- $result = array();
- $exploreDirs = array('');
- while (count($exploreDirs) > 0) {
- $dir = array_pop($exploreDirs);
- $files = $this->getFolderContents($dir);
- // no results?
- if (!$files) {
- // maybe it's a single shared file
- $file = $this->get('');
- if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) {
- $result[] = $file;
- }
- continue;
- }
- foreach ($files as $file) {
- if ($file['mimetype'] === 'httpd/unix-directory') {
- $exploreDirs[] = ltrim($dir . '/' . $file['name'], '/');
- } else if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) {
- $result[] = $file;
- }
- }
- }
- return $result;
- }
-
- /**
- * Checks whether the given file has the given tag.
- *
- * @param \OCP\ITags $tagger
- * @param array $fileData file data
- * @param string $tag tag to check for
- * @return boolean true if the given file has the expected tag,
- * false otherwise
- */
- private function hasTag($tagger, $fileData, $tag) {
- $tags = $tagger->getTagsForObjects(array((int)$fileData['fileid']));
- return (!empty($tags) && in_array($tag, current($tags)));
- }
-
- /**
- * search for files by tag
- *
- * @param string|int $tag tag to search for
- * @param string $userId owner of the tags
- * @return array file data
- */
- public function searchByTag($tag, $userId) {
- // TODO: inject this
- $tagger = \OC::$server->getTagManager()->load('files', null, null, $userId);
- $result = array();
- $exploreDirs = array('');
- // check if root is tagged
- $file = $this->get('');
- if ($this->hasTag($tagger, $file, $tag)) {
- $result[] = $file;
- }
- // FIXME: this is so wrong and unefficient, need to replace with actual DB queries
- while (count($exploreDirs) > 0) {
- $dir = array_pop($exploreDirs);
- $files = $this->getFolderContents($dir);
- if (!$files) {
- continue;
- }
- foreach ($files as $file) {
- if ($this->hasTag($tagger, $file, $tag)) {
- $result[] = $file;
- }
- if ($file['mimetype'] === 'httpd/unix-directory') {
- $exploreDirs[] = ltrim($dir . '/' . $file['name'], '/');
- }
- }
- }
- return $result;
- }
-
- /**
- * update the folder size and the size of all parent folders
- *
- * @param string|boolean $path
- * @param array $data (optional) meta data of the folder
- */
- public function correctFolderSize($path, $data = null) {
- $this->calculateFolderSize($path, $data);
- if ($path !== '') {
- $parent = dirname($path);
- if ($parent === '.' or $parent === '/') {
- $parent = '';
- }
- $this->correctFolderSize($parent);
- } else {
- // bubble up to source cache
- $sourceCache = $this->getSourceCache($path);
- if (isset($this->files[$path])) {
- $parent = dirname($this->files[$path]);
- if ($sourceCache) {
- $sourceCache->correctFolderSize($parent);
- }
- }
- }
- }
-
- /**
- * get the size of a folder and set it in the cache
- *
- * @param string $path
- * @param array $entry (optional) meta data of the folder
- * @return int
- */
- public function calculateFolderSize($path, $entry = null) {
- $path = ($path === false) ? '' : $path;
- if ($cache = $this->getSourceCache($path)) {
- return $cache->calculateFolderSize($this->files[$path]);
- }
- return 0;
- }
-
- /**
- * get all file ids on the files on the storage
- *
- * @return int[]
- */
- public function getAll() {
- $ids = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_ALL);
- $folderBackend = \OCP\Share::getBackend('folder');
- if ($folderBackend instanceof Share_Backend_Collection) {
- foreach ($ids as $file) {
- /** @var $folderBackend Share_Backend_Collection */
- $children = $folderBackend->getChildren($file);
- foreach ($children as $child) {
- $ids[] = (int)$child['source'];
- }
-
- }
- }
-
- return $ids;
- }
-
- /**
- * find a folder in the cache which has not been fully scanned
- *
- * If multiply incomplete folders are in the cache, the one with the highest id will be returned,
- * use the one with the highest id gives the best result with the background scanner, since that is most
- * likely the folder where we stopped scanning previously
- *
- * @return boolean the path of the folder or false when no folder matched
- */
- public function getIncomplete() {
- return false;
- }
-
- /**
- * get the path of a file on this storage relative to the mount point by it's id
- *
- * @param int $id
- * @param string $pathEnd (optional) used internally for recursive calls
- * @return string|null
- */
- public function getPathById($id, $pathEnd = '') {
- // direct shares are easy
- if ($id === $this->storage->getSourceId()) {
- return ltrim($pathEnd, '/');
- } else {
- // if the item is a direct share we try and get the path of the parent and append the name of the item to it
- list($parent, $name) = $this->getParentInfo($id);
- if ($parent > 0) {
- return $this->getPathById($parent, '/' . $name . $pathEnd);
- } else {
- return null;
- }
- }
- }
-
- /**
- * @param integer $id
- * @return array
- */
- private function getParentInfo($id) {
- $sql = 'SELECT `parent`, `name` FROM `*PREFIX*filecache` WHERE `fileid` = ?';
- $query = \OCP\DB::prepare($sql);
- $result = $query->execute(array($id));
- if ($row = $result->fetchRow()) {
- return array((int)$row['parent'], $row['name']);
- } else {
- return array(-1, '');
- }
- }
}
diff --git a/apps/files_sharing/lib/capabilities.php b/apps/files_sharing/lib/capabilities.php
index 220878ec2aa..913f248b174 100644
--- a/apps/files_sharing/lib/capabilities.php
+++ b/apps/files_sharing/lib/capabilities.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/controllers/externalsharescontroller.php b/apps/files_sharing/lib/controllers/externalsharescontroller.php
index edf065ab476..7ac2ef781a8 100644
--- a/apps/files_sharing/lib/controllers/externalsharescontroller.php
+++ b/apps/files_sharing/lib/controllers/externalsharescontroller.php
@@ -4,8 +4,9 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -45,7 +46,6 @@ class ExternalSharesController extends Controller {
/**
* @param string $appName
* @param IRequest $request
- * @param bool $incomingShareEnabled
* @param \OCA\Files_Sharing\External\Manager $externalManager
* @param IClientService $clientService
*/
@@ -84,7 +84,7 @@ class ExternalSharesController extends Controller {
* @NoAdminRequired
* @NoOutgoingFederatedSharingRequired
*
- * @param $id
+ * @param integer $id
* @return JSONResponse
*/
public function destroy($id) {
diff --git a/apps/files_sharing/lib/controllers/sharecontroller.php b/apps/files_sharing/lib/controllers/sharecontroller.php
index 4b446d79ada..bbe68096b52 100644
--- a/apps/files_sharing/lib/controllers/sharecontroller.php
+++ b/apps/files_sharing/lib/controllers/sharecontroller.php
@@ -6,10 +6,11 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -40,14 +41,18 @@ use OCP\IRequest;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\NotFoundResponse;
-use OC\URLGenerator;
-use OC\AppConfig;
+use OCP\IURLGenerator;
+use OCP\IConfig;
use OCP\ILogger;
+use OCP\IUserManager;
+use OCP\ISession;
+use OCP\IPreview;
use OCA\Files_Sharing\Helper;
-use OCP\User;
use OCP\Util;
use OCA\Files_Sharing\Activity;
use \OCP\Files\NotFoundException;
+use OCP\Files\IRootFolder;
+use OCP\Share\Exceptions\ShareNotFound;
/**
* Class ShareController
@@ -56,50 +61,60 @@ use \OCP\Files\NotFoundException;
*/
class ShareController extends Controller {
- /** @var \OC\User\Session */
- protected $userSession;
- /** @var \OC\AppConfig */
- protected $appConfig;
- /** @var \OCP\IConfig */
+ /** @var IConfig */
protected $config;
- /** @var \OC\URLGenerator */
+ /** @var IURLGenerator */
protected $urlGenerator;
- /** @var \OC\User\Manager */
+ /** @var IUserManager */
protected $userManager;
- /** @var \OCP\ILogger */
+ /** @var ILogger */
protected $logger;
/** @var OCP\Activity\IManager */
protected $activityManager;
+ /** @var OC\Share20\Manager */
+ protected $shareManager;
+ /** @var ISession */
+ protected $session;
+ /** @var IPreview */
+ protected $previewManager;
+ /** @var IRootFolder */
+ protected $rootFolder;
/**
* @param string $appName
* @param IRequest $request
- * @param OC\User\Session $userSession
- * @param AppConfig $appConfig
- * @param OCP\IConfig $config
- * @param URLGenerator $urlGenerator
- * @param OCP\IUserManager $userManager
+ * @param IConfig $config
+ * @param IURLGenerator $urlGenerator
+ * @param IUserManager $userManager
* @param ILogger $logger
* @param OCP\Activity\IManager $activityManager
+ * @param \OC\Share20\Manager $shareManager
+ * @param ISession $session
+ * @param IPreview $previewManager
+ * @param IRootFolder $rootFolder
*/
public function __construct($appName,
IRequest $request,
- OC\User\Session $userSession,
- AppConfig $appConfig,
- OCP\IConfig $config,
- URLGenerator $urlGenerator,
- OCP\IUserManager $userManager,
+ IConfig $config,
+ IURLGenerator $urlGenerator,
+ IUserManager $userManager,
ILogger $logger,
- OCP\Activity\IManager $activityManager) {
+ \OCP\Activity\IManager $activityManager,
+ \OC\Share20\Manager $shareManager,
+ ISession $session,
+ IPreview $previewManager,
+ IRootFolder $rootFolder) {
parent::__construct($appName, $request);
- $this->userSession = $userSession;
- $this->appConfig = $appConfig;
$this->config = $config;
$this->urlGenerator = $urlGenerator;
$this->userManager = $userManager;
$this->logger = $logger;
$this->activityManager = $activityManager;
+ $this->shareManager = $shareManager;
+ $this->session = $session;
+ $this->previewManager = $previewManager;
+ $this->rootFolder = $rootFolder;
}
/**
@@ -110,9 +125,9 @@ class ShareController extends Controller {
* @return TemplateResponse|RedirectResponse
*/
public function showAuthenticate($token) {
- $linkItem = Share::getShareByToken($token, false);
+ $share = $this->shareManager->getShareByToken($token);
- if(Helper::authenticate($linkItem)) {
+ if($this->linkShareAuth($share)) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
}
@@ -124,17 +139,20 @@ class ShareController extends Controller {
* @UseSession
*
* Authenticates against password-protected shares
- * @param $token
+ * @param string $token
* @param string $password
* @return RedirectResponse|TemplateResponse
*/
public function authenticate($token, $password = '') {
- $linkItem = Share::getShareByToken($token, false);
- if($linkItem === false) {
+
+ // Check whether share exists
+ try {
+ $share = $this->shareManager->getShareByToken($token);
+ } catch (ShareNotFound $e) {
return new NotFoundResponse();
}
- $authenticate = Helper::authenticate($linkItem, $password);
+ $authenticate = $this->linkShareAuth($share, $password);
if($authenticate === true) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
@@ -144,6 +162,34 @@ class ShareController extends Controller {
}
/**
+ * Authenticate a link item with the given password.
+ * Or use the session if no password is provided.
+ *
+ * This is a modified version of Helper::authenticate
+ * TODO: Try to merge back eventually with Helper::authenticate
+ *
+ * @param \OCP\Share\IShare $share
+ * @param string|null $password
+ * @return bool
+ */
+ private function linkShareAuth(\OCP\Share\IShare $share, $password = null) {
+ if ($password !== null) {
+ if ($this->shareManager->checkPassword($share, $password)) {
+ $this->session->set('public_link_authenticated', (string)$share->getId());
+ } else {
+ return false;
+ }
+ } else {
+ // not authenticated ?
+ if ( ! $this->session->exists('public_link_authenticated')
+ || $this->session->get('public_link_authenticated') !== (string)$share->getId()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* @PublicPage
* @NoCSRFRequired
*
@@ -156,53 +202,70 @@ class ShareController extends Controller {
\OC_User::setIncognitoMode(true);
// Check whether share exists
- $linkItem = Share::getShareByToken($token, false);
- if($linkItem === false) {
+ try {
+ $share = $this->shareManager->getShareByToken($token);
+ } catch (ShareNotFound $e) {
return new NotFoundResponse();
}
- $shareOwner = $linkItem['uid_owner'];
- $originalSharePath = $this->getPath($token);
-
// Share is password protected - check whether the user is permitted to access the share
- if (isset($linkItem['share_with']) && !Helper::authenticate($linkItem)) {
+ if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
array('token' => $token)));
}
- if (Filesystem::isReadable($originalSharePath . $path)) {
- $getPath = Filesystem::normalizePath($path);
- $originalSharePath .= $path;
- } else {
+ // We can't get the path of a file share
+ if ($share->getNode() instanceof \OCP\Files\File && $path !== '') {
throw new NotFoundException();
}
- $file = basename($originalSharePath);
+ $rootFolder = null;
+ if ($share->getNode() instanceof \OCP\Files\Folder) {
+ /** @var \OCP\Files\Folder $rootFolder */
+ $rootFolder = $share->getNode();
+
+ try {
+ $path = $rootFolder->get($path);
+ } catch (\OCP\Files\NotFoundException $e) {
+ throw new NotFoundException();
+ }
+ }
$shareTmpl = [];
- $shareTmpl['displayName'] = User::getDisplayName($shareOwner);
- $shareTmpl['filename'] = $file;
- $shareTmpl['directory_path'] = $linkItem['file_target'];
- $shareTmpl['mimetype'] = Filesystem::getMimeType($originalSharePath);
- $shareTmpl['previewSupported'] = \OC::$server->getPreviewManager()->isMimeSupported($shareTmpl['mimetype']);
- $shareTmpl['dirToken'] = $linkItem['token'];
+ $shareTmpl['displayName'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
+ $shareTmpl['owner'] = $share->getShareOwner();
+ $shareTmpl['filename'] = $share->getNode()->getName();
+ $shareTmpl['directory_path'] = $share->getTarget();
+ $shareTmpl['mimetype'] = $share->getNode()->getMimetype();
+ $shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($share->getNode()->getMimetype());
+ $shareTmpl['dirToken'] = $token;
$shareTmpl['sharingToken'] = $token;
$shareTmpl['server2serversharing'] = Helper::isOutgoingServer2serverShareEnabled();
- $shareTmpl['protected'] = isset($linkItem['share_with']) ? 'true' : 'false';
+ $shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false';
$shareTmpl['dir'] = '';
- $nonHumanFileSize = \OC\Files\Filesystem::filesize($originalSharePath);
- $shareTmpl['nonHumanFileSize'] = $nonHumanFileSize;
- $shareTmpl['fileSize'] = \OCP\Util::humanFileSize($nonHumanFileSize);
+ $shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize();
+ $shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize());
// Show file list
- if (Filesystem::is_dir($originalSharePath)) {
- $shareTmpl['dir'] = $getPath;
- $maxUploadFilesize = Util::maxUploadFilesize($originalSharePath);
- $freeSpace = Util::freeSpace($originalSharePath);
+ if ($share->getNode() instanceof \OCP\Files\Folder) {
+ $shareTmpl['dir'] = $rootFolder->getRelativePath($path->getPath());
+
+ /*
+ * The OC_Util methods require a view. This just uses the node API
+ */
+ $freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath());
+ if ($freeSpace !== \OCP\Files\FileInfo::SPACE_UNKNOWN) {
+ $freeSpace = max($freeSpace, 0);
+ } else {
+ $freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
+ }
+
$uploadLimit = Util::uploadLimit();
+ $maxUploadFilesize = min($freeSpace, $uploadLimit);
+
$folder = new Template('files', 'list', '');
- $folder->assign('dir', $getPath);
- $folder->assign('dirToken', $linkItem['token']);
+ $folder->assign('dir', $rootFolder->getRelativePath($path->getPath()));
+ $folder->assign('dirToken', $token);
$folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
$folder->assign('isPublic', true);
$folder->assign('publicUploadEnabled', 'no');
@@ -240,14 +303,12 @@ class ShareController extends Controller {
public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
\OC_User::setIncognitoMode(true);
- $linkItem = OCP\Share::getShareByToken($token, false);
+ $share = $this->shareManager->getShareByToken($token);
// Share is password protected - check whether the user is permitted to access the share
- if (isset($linkItem['share_with'])) {
- if(!Helper::authenticate($linkItem)) {
- return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
- array('token' => $token)));
- }
+ if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
+ return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
+ ['token' => $token]));
}
$files_list = null;
@@ -255,41 +316,86 @@ class ShareController extends Controller {
$files_list = json_decode($files);
// in case we get only a single file
if ($files_list === null) {
- $files_list = array($files);
+ $files_list = [$files];
}
}
- $originalSharePath = self::getPath($token);
-
- // Create the activities
- if (isset($originalSharePath) && Filesystem::isReadable($originalSharePath . $path)) {
- $originalSharePath = Filesystem::normalizePath($originalSharePath . $path);
- $isDir = \OC\Files\Filesystem::is_dir($originalSharePath);
+ $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
+ $originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
+
+ // Single file share
+ if ($share->getNode() instanceof \OCP\Files\File) {
+ // Single file download
+ $event = $this->activityManager->generateEvent();
+ $event->setApp('files_sharing')
+ ->setType(Activity::TYPE_PUBLIC_LINKS)
+ ->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED, [$userFolder->getRelativePath($share->getNode()->getPath())])
+ ->setAffectedUser($share->getShareOwner())
+ ->setObject('files', $share->getNode()->getId(), $userFolder->getRelativePath($share->getNode()->getPath()));
+ $this->activityManager->publish($event);
+ }
+ // Directory share
+ else {
+ /** @var \OCP\Files\Folder $node */
+ $node = $share->getNode();
+
+ // Try to get the path
+ if ($path !== '') {
+ try {
+ $node = $node->get($path);
+ } catch (NotFoundException $e) {
+ return new NotFoundResponse();
+ }
+ }
- $activities = [];
- if (!$isDir) {
- // Single file public share
- $activities[$originalSharePath] = Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
+ $originalSharePath = $userFolder->getRelativePath($node->getPath());
+
+ if ($node instanceof \OCP\Files\File) {
+ // Single file download
+ $event = $this->activityManager->generateEvent();
+ $event->setApp('files_sharing')
+ ->setType(Activity::TYPE_PUBLIC_LINKS)
+ ->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED, [$userFolder->getRelativePath($node->getPath())])
+ ->setAffectedUser($share->getShareOwner())
+ ->setObject('files', $node->getId(), $userFolder->getRelativePath($node->getPath()));
+ $this->activityManager->publish($event);
} else if (!empty($files_list)) {
- // Only some files are downloaded
+ /** @var \OCP\Files\Folder $node */
+
+ // Subset of files is downloaded
foreach ($files_list as $file) {
- $filePath = Filesystem::normalizePath($originalSharePath . '/' . $file);
- $isDir = \OC\Files\Filesystem::is_dir($filePath);
- $activities[$filePath] = ($isDir) ? Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED : Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
+ $subNode = $node->get($file);
+
+ $event = $this->activityManager->generateEvent();
+ $event->setApp('files_sharing')
+ ->setType(Activity::TYPE_PUBLIC_LINKS)
+ ->setAffectedUser($share->getShareOwner())
+ ->setObject('files', $subNode->getId(), $userFolder->getRelativePath($subNode->getPath()));
+
+ if ($subNode instanceof \OCP\Files\File) {
+ $event->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED, [$userFolder->getRelativePath($subNode->getPath())]);
+ } else {
+ $event->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED, [$userFolder->getRelativePath($subNode->getPath())]);
+ }
+
+ $this->activityManager->publish($event);
}
} else {
// The folder is downloaded
- $activities[$originalSharePath] = Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
- }
-
- foreach ($activities as $filePath => $subject) {
- $this->activityManager->publishActivity(
- 'files_sharing', $subject, array($filePath), '', array(),
- $filePath, '', $linkItem['uid_owner'], Activity::TYPE_PUBLIC_LINKS, Activity::PRIORITY_MEDIUM
- );
+ $event = $this->activityManager->generateEvent();
+ $event->setApp('files_sharing')
+ ->setType(Activity::TYPE_PUBLIC_LINKS)
+ ->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED, [$userFolder->getRelativePath($node->getPath())])
+ ->setAffectedUser($share->getShareOwner())
+ ->setObject('files', $node->getId(), $userFolder->getRelativePath($node->getPath()));
+ $this->activityManager->publish($event);
}
}
+ /* FIXME: We should do this all nicely in OCP */
+ OC_Util::tearDownFS();
+ OC_Util::setupFS($share->getShareOwner());
+
/**
* this sets a cookie to be able to recognize the start of the download
* the content must not be longer than 32 characters and must only contain
@@ -316,30 +422,4 @@ class ShareController extends Controller {
exit();
}
}
-
- /**
- * @param string $token
- * @return string Resolved file path of the token
- * @throws NotFoundException In case share could not get properly resolved
- */
- private function getPath($token) {
- $linkItem = Share::getShareByToken($token, false);
- if (is_array($linkItem) && isset($linkItem['uid_owner'])) {
- // seems to be a valid share
- $rootLinkItem = Share::resolveReShare($linkItem);
- if (isset($rootLinkItem['uid_owner'])) {
- if(!$this->userManager->userExists($rootLinkItem['uid_owner'])) {
- throw new NotFoundException('Owner of the share does not exist anymore');
- }
- OC_Util::tearDownFS();
- OC_Util::setupFS($rootLinkItem['uid_owner']);
- $path = Filesystem::getPath($linkItem['file_source']);
- if(Filesystem::isReadable($path)) {
- return $path;
- }
- }
- }
-
- throw new NotFoundException('No file found belonging to file.');
- }
}
diff --git a/apps/files_sharing/lib/deleteorphanedsharesjob.php b/apps/files_sharing/lib/deleteorphanedsharesjob.php
index 0654c82dd94..72bf6b222e7 100644
--- a/apps/files_sharing/lib/deleteorphanedsharesjob.php
+++ b/apps/files_sharing/lib/deleteorphanedsharesjob.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/exceptions/brokenpath.php b/apps/files_sharing/lib/exceptions/brokenpath.php
index 71fe93f8e92..4639d47c4a6 100644
--- a/apps/files_sharing/lib/exceptions/brokenpath.php
+++ b/apps/files_sharing/lib/exceptions/brokenpath.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/exceptions/s2sexception.php b/apps/files_sharing/lib/exceptions/s2sexception.php
index fe2659d36ff..1ed6a9e2179 100644
--- a/apps/files_sharing/lib/exceptions/s2sexception.php
+++ b/apps/files_sharing/lib/exceptions/s2sexception.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/expiresharesjob.php b/apps/files_sharing/lib/expiresharesjob.php
index bcd3fbe4605..479f407e68f 100644
--- a/apps/files_sharing/lib/expiresharesjob.php
+++ b/apps/files_sharing/lib/expiresharesjob.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/external/cache.php b/apps/files_sharing/lib/external/cache.php
index e99c00e884f..da9bf83cdfa 100644
--- a/apps/files_sharing/lib/external/cache.php
+++ b/apps/files_sharing/lib/external/cache.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php
index 93e2cdb540b..ea49348737f 100644
--- a/apps/files_sharing/lib/external/manager.php
+++ b/apps/files_sharing/lib/external/manager.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,7 +28,7 @@ namespace OCA\Files_Sharing\External;
use OC\Files\Filesystem;
use OCP\Files;
-use OC\Notification\IManager;
+use OCP\Notification\IManager;
class Manager {
const STORAGE = '\OCA\Files_Sharing\External\Storage';
@@ -192,6 +192,8 @@ class Manager {
$acceptShare->execute(array(1, $mountPoint, $hash, $id, $this->uid));
$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'accept');
+ \OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $share['remote']]);
+
//FIXME $this->scrapNotification($share['remote_id']);
return true;
}
diff --git a/apps/files_sharing/lib/external/mount.php b/apps/files_sharing/lib/external/mount.php
index 17923be8736..9cf66d3f8f0 100644
--- a/apps/files_sharing/lib/external/mount.php
+++ b/apps/files_sharing/lib/external/mount.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/external/mountprovider.php b/apps/files_sharing/lib/external/mountprovider.php
index 1739cec543f..0bef3539c42 100644
--- a/apps/files_sharing/lib/external/mountprovider.php
+++ b/apps/files_sharing/lib/external/mountprovider.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/external/scanner.php b/apps/files_sharing/lib/external/scanner.php
index 455225b2b79..3335fc4707c 100644
--- a/apps/files_sharing/lib/external/scanner.php
+++ b/apps/files_sharing/lib/external/scanner.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php
index 270d8b6d1b8..783eea43c62 100644
--- a/apps/files_sharing/lib/external/storage.php
+++ b/apps/files_sharing/lib/external/storage.php
@@ -6,7 +6,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -250,7 +250,7 @@ class Storage extends DAV implements ISharedStorage {
$response = $client->post($url, ['body' => ['password' => $password]]);
} catch (\GuzzleHttp\Exception\RequestException $e) {
if ($e->getCode() === 401 || $e->getCode() === 403) {
- throw new ForbiddenException();
+ throw new ForbiddenException();
}
// throw this to be on the safe side: the share will still be visible
// in the UI in case the failure is intermittent, and the user will
@@ -260,4 +260,17 @@ class Storage extends DAV implements ISharedStorage {
return json_decode($response->getBody(), true);
}
+
+ public function getOwner($path) {
+ list(, $remote) = explode('://', $this->remote, 2);
+ return $this->remoteUser . '@' . $remote;
+ }
+
+ public function isSharable($path) {
+ if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
+ return false;
+ }
+ return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
+ }
+
}
diff --git a/apps/files_sharing/lib/helper.php b/apps/files_sharing/lib/helper.php
index a804737c490..cffdc8887ec 100644
--- a/apps/files_sharing/lib/helper.php
+++ b/apps/files_sharing/lib/helper.php
@@ -10,7 +10,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,6 +28,7 @@
*/
namespace OCA\Files_Sharing;
+use OC\Files\Filesystem;
use OCP\Files\NotFoundException;
class Helper {
@@ -205,14 +206,7 @@ class Helper {
}
public static function getUidAndFilename($filename) {
- $uid = \OC\Files\Filesystem::getOwner($filename);
- \OC\Files\Filesystem::initMountPoints($uid);
- if ( $uid != \OCP\User::getUser() ) {
- $info = \OC\Files\Filesystem::getFileInfo($filename);
- $ownerView = new \OC\Files\View('/'.$uid.'/files');
- $filename = $ownerView->getPath($info['fileid']);
- }
- return array($uid, $filename);
+ return Filesystem::getView()->getUidAndFilename($filename);
}
/**
@@ -310,20 +304,4 @@ class Helper {
\OC::$server->getConfig()->setSystemValue('share_folder', $shareFolder);
}
- /**
- * remove protocol from URL
- *
- * @param string $url
- * @return string
- */
- public static function removeProtocolFromUrl($url) {
- if (strpos($url, 'https://') === 0) {
- return substr($url, strlen('https://'));
- } else if (strpos($url, 'http://') === 0) {
- return substr($url, strlen('http://'));
- }
-
- return $url;
- }
-
}
diff --git a/apps/files_sharing/lib/hooks.php b/apps/files_sharing/lib/hooks.php
index 079824f7fb0..166905b9aa4 100644
--- a/apps/files_sharing/lib/hooks.php
+++ b/apps/files_sharing/lib/hooks.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/isharedstorage.php b/apps/files_sharing/lib/isharedstorage.php
index cbbb40a2688..bb47b011f48 100644
--- a/apps/files_sharing/lib/isharedstorage.php
+++ b/apps/files_sharing/lib/isharedstorage.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/maintainer.php b/apps/files_sharing/lib/maintainer.php
index af8e1ac6668..a728f6bbb67 100644
--- a/apps/files_sharing/lib/maintainer.php
+++ b/apps/files_sharing/lib/maintainer.php
@@ -1,9 +1,9 @@
<?php
/**
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php b/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php
index 22b9d32a275..a4a968b37fa 100644
--- a/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php
+++ b/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php
@@ -5,7 +5,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,7 +27,6 @@ namespace OCA\Files_Sharing\Middleware;
use OCP\App\IAppManager;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\Middleware;
-use OCP\AppFramework\Http\TemplateResponse;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\AppFramework\Utility\IControllerMethodReflector;
diff --git a/apps/files_sharing/lib/migration.php b/apps/files_sharing/lib/migration.php
index f48467e1fad..90e0dead480 100644
--- a/apps/files_sharing/lib/migration.php
+++ b/apps/files_sharing/lib/migration.php
@@ -1,9 +1,8 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,22 +19,246 @@
*
*/
- namespace OCA\Files_Sharing;
+namespace OCA\Files_Sharing;
+use Doctrine\DBAL\Connection;
+use OCP\IDBConnection;
+use OC\Cache\CappedMemoryCache;
+
+/**
+ * Class Migration
+ *
+ * @package OCA\Files_Sharing
+ * @group DB
+ */
class Migration {
+ /** @var IDBConnection */
+ private $connection;
+
+ /** @var array with all shares we already saw */
+ private $shareCache;
+
+ /** @var string */
+ private $table = 'share';
+
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+
+ // We cache up to 10k share items (~20MB)
+ $this->shareCache = new CappedMemoryCache(10000);
+ }
+
+ /**
+ * move all re-shares to the owner in order to have a flat list of shares
+ * upgrade from oC 8.2 to 9.0 with the new sharing
+ */
+ public function removeReShares() {
+
+ while(true) {
+ $reShares = $this->getReShares(1000);
+
+ if (empty($reShares)) {
+ break;
+ }
+
+ // Update the cache
+ foreach($reShares as $reShare) {
+ $this->shareCache[$reShare['id']] = $reShare;
+ }
+
+ $owners = [];
+ foreach ($reShares as $share) {
+ $owners[$share['id']] = [
+ 'owner' => $this->findOwner($share),
+ 'initiator' => $share['uid_owner']
+ ];
+ }
+ $this->updateOwners($owners);
+
+ //Clear the cache of the shares we just updated so we have more room
+ foreach($owners as $id => $owner) {
+ unset($this->shareCache[$id]);
+ }
+ }
+ }
/**
- * set accepted to 1 for all external shares. At this point in time we only
- * have shares from the first version of server-to-server sharing so all should
- * be accepted
+ * update all owner information so that all shares have an owner
+ * and an initiator for the upgrade from oC 8.2 to 9.0 with the new sharing
*/
- public function addAcceptRow() {
- $statement = 'UPDATE `*PREFIX*share_external` SET `accepted` = 1';
- $connection = \OC::$server->getDatabaseConnection();
- $query = $connection->prepare($statement);
- $query->execute();
+ public function updateInitiatorInfo() {
+ while (true) {
+ $shares = $this->getMissingInitiator(1000);
+
+ if (empty($shares)) {
+ break;
+ }
+
+ $owners = [];
+ foreach ($shares as $share) {
+ $owners[$share['id']] = [
+ 'owner' => $share['uid_owner'],
+ 'initiator' => $share['uid_owner']
+ ];
+ }
+ $this->updateOwners($owners);
+ }
}
+ /**
+ * find the owner of a re-shared file/folder
+ *
+ * @param array $share
+ * @return array
+ */
+ private function findOwner($share) {
+ $currentShare = $share;
+ while(!is_null($currentShare['parent'])) {
+ if (isset($this->shareCache[$currentShare['parent']])) {
+ $currentShare = $this->shareCache[$currentShare['parent']];
+ } else {
+ $currentShare = $this->getShare((int)$currentShare['parent']);
+ $this->shareCache[$currentShare['id']] = $currentShare;
+ }
+ }
+
+ return $currentShare['uid_owner'];
+ }
+
+ /**
+ * Get $n re-shares from the database
+ *
+ * @param int $n The max number of shares to fetch
+ * @return array
+ */
+ private function getReShares($n = 1000) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select(['id', 'parent', 'uid_owner'])
+ ->from($this->table)
+ ->where($query->expr()->in(
+ 'share_type',
+ $query->createNamedParameter(
+ [
+ \OCP\Share::SHARE_TYPE_USER,
+ \OCP\Share::SHARE_TYPE_GROUP,
+ \OCP\Share::SHARE_TYPE_LINK
+ ],
+ Connection::PARAM_INT_ARRAY
+ )
+ ))
+ ->andWhere($query->expr()->in(
+ 'item_type',
+ $query->createNamedParameter(
+ ['file', 'folder'],
+ Connection::PARAM_STR_ARRAY
+ )
+ ))
+ ->andWhere($query->expr()->isNotNull('parent'))
+ ->orderBy('id', 'asc')
+ ->setMaxResults($n);
+ $result = $query->execute();
+ $shares = $result->fetchAll();
+ $result->closeCursor();
+
+ $ordered = [];
+ foreach ($shares as $share) {
+ $ordered[(int)$share['id']] = $share;
+ }
+
+ return $ordered;
+ }
+
+ /**
+ * Get $n re-shares from the database
+ *
+ * @param int $n The max number of shares to fetch
+ * @return array
+ */
+ private function getMissingInitiator($n = 1000) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select(['id', 'uid_owner'])
+ ->from($this->table)
+ ->where($query->expr()->in(
+ 'share_type',
+ $query->createNamedParameter(
+ [
+ \OCP\Share::SHARE_TYPE_USER,
+ \OCP\Share::SHARE_TYPE_GROUP,
+ \OCP\Share::SHARE_TYPE_LINK
+ ],
+ Connection::PARAM_INT_ARRAY
+ )
+ ))
+ ->andWhere($query->expr()->in(
+ 'item_type',
+ $query->createNamedParameter(
+ ['file', 'folder'],
+ Connection::PARAM_STR_ARRAY
+ )
+ ))
+ ->andWhere($query->expr()->isNull('uid_initiator'))
+ ->orderBy('id', 'asc')
+ ->setMaxResults($n);
+ $result = $query->execute();
+ $shares = $result->fetchAll();
+ $result->closeCursor();
+
+ $ordered = [];
+ foreach ($shares as $share) {
+ $ordered[(int)$share['id']] = $share;
+ }
+
+ return $ordered;
+ }
+
+ /**
+ * get a specific share
+ *
+ * @param int $id
+ * @return array
+ */
+ private function getShare($id) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select(['id', 'parent', 'uid_owner'])
+ ->from($this->table)
+ ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
+ $result = $query->execute();
+ $share = $result->fetchAll();
+ $result->closeCursor();
+
+ return $share[0];
+ }
+
+ /**
+ * update database with the new owners
+ *
+ * @param array $owners
+ * @throws \Exception
+ */
+ private function updateOwners($owners) {
+
+ $this->connection->beginTransaction();
+
+ try {
+
+ foreach ($owners as $id => $owner) {
+ $query = $this->connection->getQueryBuilder();
+ $query->update($this->table)
+ ->set('parent', $query->createNamedParameter(null))
+ ->set('uid_owner', $query->createNamedParameter($owner['owner']))
+ ->set('uid_initiator', $query->createNamedParameter($owner['initiator']))
+ ->where($query->expr()->eq('id', $query->createNamedParameter($id)))
+ ->execute();
+ }
+
+ $this->connection->commit();
+
+ } catch (\Exception $e) {
+ $this->connection->rollBack();
+ throw $e;
+ }
+
+ }
}
diff --git a/apps/files_sharing/lib/mountprovider.php b/apps/files_sharing/lib/mountprovider.php
index 458e7f2619b..4a60e44bb26 100644
--- a/apps/files_sharing/lib/mountprovider.php
+++ b/apps/files_sharing/lib/mountprovider.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,7 +24,6 @@ namespace OCA\Files_Sharing;
use OC\Files\Filesystem;
use OC\User\NoUserException;
-use OCA\Files_Sharing\Propagation\PropagationManager;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Storage\IStorageFactory;
use OCP\IConfig;
@@ -37,17 +36,10 @@ class MountProvider implements IMountProvider {
protected $config;
/**
- * @var \OCA\Files_Sharing\Propagation\PropagationManager
- */
- protected $propagationManager;
-
- /**
* @param \OCP\IConfig $config
- * @param \OCA\Files_Sharing\Propagation\PropagationManager $propagationManager
*/
- public function __construct(IConfig $config, PropagationManager $propagationManager) {
+ public function __construct(IConfig $config) {
$this->config = $config;
- $this->propagationManager = $propagationManager;
}
@@ -60,21 +52,15 @@ class MountProvider implements IMountProvider {
*/
public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
$shares = \OCP\Share::getItemsSharedWithUser('file', $user->getUID());
- $propagator = $this->propagationManager->getSharePropagator($user->getUID());
- $propagator->propagateDirtyMountPoints($shares);
$shares = array_filter($shares, function ($share) {
return $share['permissions'] > 0;
});
$shares = array_map(function ($share) use ($user, $storageFactory) {
- // for updating etags for the share owner when we make changes to this share.
- $ownerPropagator = $this->propagationManager->getChangePropagator($share['uid_owner']);
return new SharedMount(
'\OC\Files\Storage\Shared',
'/' . $user->getUID() . '/' . $share['file_target'],
array(
- 'propagationManager' => $this->propagationManager,
- 'propagator' => $ownerPropagator,
'share' => $share,
'user' => $user->getUID()
),
diff --git a/apps/files_sharing/lib/notifier.php b/apps/files_sharing/lib/notifier.php
index 02765fcfd1c..802f22e44c5 100644
--- a/apps/files_sharing/lib/notifier.php
+++ b/apps/files_sharing/lib/notifier.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,8 +22,8 @@
namespace OCA\Files_Sharing;
-use OC\Notification\INotification;
-use OC\Notification\INotifier;
+use OCP\Notification\INotification;
+use OCP\Notification\INotifier;
class Notifier implements INotifier {
/** @var \OCP\L10N\IFactory */
diff --git a/apps/files_sharing/lib/propagation/changewatcher.php b/apps/files_sharing/lib/propagation/changewatcher.php
deleted file mode 100644
index e61c161da19..00000000000
--- a/apps/files_sharing/lib/propagation/changewatcher.php
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-/**
- * @author Robin Appelman <icewind@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Sharing\Propagation;
-
-use OC\Files\Cache\ChangePropagator;
-use OC\Files\Filesystem;
-use OC\Files\View;
-use OCA\Files_Sharing\SharedMount;
-
-/**
- * Watch for changes made in a shared mount and propagate the changes to the share owner
- */
-class ChangeWatcher {
- /**
- * The user view for the logged in user
- *
- * @var \OC\Files\View
- */
- private $baseView;
-
- /**
- * @var RecipientPropagator
- */
- private $recipientPropagator;
-
- /**
- * @param \OC\Files\View $baseView the view for the logged in user
- * @param RecipientPropagator $recipientPropagator
- */
- public function __construct(View $baseView, RecipientPropagator $recipientPropagator) {
- $this->baseView = $baseView;
- $this->recipientPropagator = $recipientPropagator;
- }
-
-
- public function writeHook($params) {
- $path = $params['path'];
- $fullPath = $this->baseView->getAbsolutePath($path);
- $mount = $this->baseView->getMount($path);
- if ($mount instanceof SharedMount) {
- $this->propagateForOwner($mount->getShare(), $mount->getInternalPath($fullPath), $mount->getOwnerPropagator());
- }
- $info = $this->baseView->getFileInfo($path);
- if ($info) {
- // trigger propagation if the subject of the write hook is shared.
- // if a parent folder of $path is shared the propagation will be triggered from the change propagator hooks
- $this->recipientPropagator->propagateById($info->getId());
- }
- }
-
- public function renameHook($params) {
- $path1 = $params['oldpath'];
- $path2 = $params['newpath'];
- $fullPath1 = $this->baseView->getAbsolutePath($path1);
- $fullPath2 = $this->baseView->getAbsolutePath($path2);
- $mount1 = $this->baseView->getMount($path1);
- $mount2 = $this->baseView->getMount($path2);
- if ($mount1 instanceof SharedMount and $mount1->getInternalPath($fullPath1) !== '') {
- $this->propagateForOwner($mount1->getShare(), $mount1->getInternalPath($fullPath1), $mount1->getOwnerPropagator());
- }
- if ($mount1 !== $mount2 and $mount2 instanceof SharedMount and $mount2->getInternalPath($fullPath2) !== '') {
- $this->propagateForOwner($mount2->getShare(), $mount2->getInternalPath($fullPath2), $mount2->getOwnerPropagator());
- }
- }
-
- /**
- * @param array $share
- * @param string $internalPath
- * @param \OC\Files\Cache\ChangePropagator $propagator
- */
- private function propagateForOwner($share, $internalPath, ChangePropagator $propagator) {
- // note that we have already set up the filesystem for the owner when mounting the share
- $view = new View('/' . $share['uid_owner'] . '/files');
-
- $shareRootPath = $view->getPath($share['item_source']);
- if (!is_null($shareRootPath)) {
- $path = $shareRootPath . '/' . $internalPath;
- $path = Filesystem::normalizePath($path);
- $propagator->addChange($path);
- $propagator->propagateChanges();
- }
- }
-
- public function permissionsHook($params) {
- $share = $params['share'];
-
- if ($share['item_type'] === 'file' || $share['item_type'] === 'folder') {
- $this->recipientPropagator->markDirty($share, microtime(true));
- }
- }
-}
diff --git a/apps/files_sharing/lib/propagation/grouppropagationmanager.php b/apps/files_sharing/lib/propagation/grouppropagationmanager.php
deleted file mode 100644
index ba550dccec3..00000000000
--- a/apps/files_sharing/lib/propagation/grouppropagationmanager.php
+++ /dev/null
@@ -1,133 +0,0 @@
-<?php
-/**
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Sharing\Propagation;
-
-use OC\Files\Filesystem;
-use OC\Files\View;
-use OCP\IConfig;
-use OCP\IUserSession;
-use OCP\IGroup;
-use OCP\IUser;
-use OCP\IGroupManager;
-use OCA\Files_Sharing\Propagation\PropagationManager;
-
-/**
- * Propagate changes on group changes
- */
-class GroupPropagationManager {
- /**
- * @var \OCP\IUserSession
- */
- private $userSession;
-
- /**
- * @var \OCP\IGroupManager
- */
- private $groupManager;
-
- /**
- * @var PropagationManager
- */
- private $propagationManager;
-
- /**
- * Items shared with a given user.
- * Key is user id and value is an array of shares.
- *
- * @var array
- */
- private $userShares = [];
-
- public function __construct(IUserSession $userSession, IGroupManager $groupManager, PropagationManager $propagationManager) {
- $this->userSession = $userSession;
- $this->groupManager = $groupManager;
- $this->propagationManager = $propagationManager;
- }
-
- public function onPreProcessUser(IGroup $group, IUser $targetUser) {
- $this->userShares[$targetUser->getUID()] = $this->getUserShares($targetUser->getUID());
- }
-
- public function onPostAddUser(IGroup $group, IUser $targetUser) {
- $targetUserId = $targetUser->getUID();
- $sharesAfter = $this->getUserShares($targetUserId);
-
- $this->propagateSharesDiff($targetUserId, $sharesAfter, $this->userShares[$targetUserId]);
- unset($this->userShares[$targetUserId]);
- }
-
- public function onPostRemoveUser(IGroup $group, IUser $targetUser) {
- $targetUserId = $targetUser->getUID();
- $sharesAfter = $this->getUserShares($targetUserId);
-
- $this->propagateSharesDiff($targetUserId, $this->userShares[$targetUserId], $sharesAfter);
- unset($this->userShares[$targetUserId]);
- }
-
- private function getUserShares($targetUserId) {
- return \OCP\Share::getItemsSharedWithUser('file', $targetUserId);
- }
-
- /**
- * Propagate etag for the shares that are in $shares1 but not in $shares2.
- *
- * @param string $targetUserId user id for which to propagate shares
- * @param array $shares1
- * @param array $shares2
- */
- private function propagateSharesDiff($targetUserId, $shares1, $shares2) {
- $sharesToPropagate = array_udiff(
- $shares1,
- $shares2,
- function($share1, $share2) {
- return ($share2['id'] - $share1['id']);
- }
- );
-
- \OC\Files\Filesystem::initMountPoints($targetUserId);
- $this->propagationManager->propagateSharesToUser($sharesToPropagate, $targetUserId);
- }
-
- /**
- * To be called from setupFS trough a hook
- *
- * Sets up listening to changes made to shares owned by the current user
- */
- public function globalSetup() {
- $user = $this->userSession->getUser();
- if (!$user) {
- return;
- }
-
- $this->groupManager->listen('\OC\Group', 'preAddUser', [$this, 'onPreProcessUser']);
- $this->groupManager->listen('\OC\Group', 'postAddUser', [$this, 'onPostAddUser']);
- $this->groupManager->listen('\OC\Group', 'preRemoveUser', [$this, 'onPreProcessUser']);
- $this->groupManager->listen('\OC\Group', 'postRemoveUser', [$this, 'onPostRemoveUser']);
- }
-
- public function tearDown() {
- $this->groupManager->removeListener('\OC\Group', 'preAddUser', [$this, 'onPreProcessUser']);
- $this->groupManager->removeListener('\OC\Group', 'postAddUser', [$this, 'onPostAddUser']);
- $this->groupManager->removeListener('\OC\Group', 'preRemoveUser', [$this, 'onPreProcessUser']);
- $this->groupManager->removeListener('\OC\Group', 'postRemoveUser', [$this, 'onPostRemoveUser']);
- }
-}
diff --git a/apps/files_sharing/lib/propagation/propagationmanager.php b/apps/files_sharing/lib/propagation/propagationmanager.php
deleted file mode 100644
index aac9428240d..00000000000
--- a/apps/files_sharing/lib/propagation/propagationmanager.php
+++ /dev/null
@@ -1,144 +0,0 @@
-<?php
-/**
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Sharing\Propagation;
-
-use OC\Files\Filesystem;
-use OC\Files\View;
-use OCP\IConfig;
-use OCP\IUserSession;
-use OCP\Util;
-
-
-/**
- * Keep track of all change and share propagators by owner
- */
-class PropagationManager {
- /**
- * @var \OCP\IUserSession
- */
- private $userSession;
-
- /**
- * @var \OCP\IConfig
- */
- private $config;
-
- /**
- * Change propagators for share owner
- *
- * @var \OC\Files\Cache\ChangePropagator[]
- */
- private $changePropagators = [];
-
- /**
- * Recipient propagators
- *
- * @var \OCA\Files_Sharing\Propagation\RecipientPropagator[]
- */
- private $sharePropagators = [];
-
- public function __construct(IUserSession $userSession, IConfig $config) {
- $this->userSession = $userSession;
- $this->config = $config;
- }
-
- /**
- * @param string $user
- * @return \OC\Files\Cache\ChangePropagator
- */
- public function getChangePropagator($user) {
- $activeUser = $this->userSession->getUser();
-
- // for the local user we want to propagator from the active view, not any cached one
- if ($activeUser && $activeUser->getUID() === $user && Filesystem::getView() instanceof View) {
- // it's important that we take the existing propagator here to make sure we can listen to external changes
- $this->changePropagators[$user] = Filesystem::getView()->getUpdater()->getPropagator();
- }
- if (isset($this->changePropagators[$user])) {
- return $this->changePropagators[$user];
- }
- $view = new View('/' . $user . '/files');
- $this->changePropagators[$user] = $view->getUpdater()->getPropagator();
- return $this->changePropagators[$user];
- }
-
- /**
- * Propagates etag changes for the given shares to the given user
- *
- * @param array array of shares for which to trigger etag change
- * @param string $user
- */
- public function propagateSharesToUser($shares, $user) {
- $changePropagator = $this->getChangePropagator($user);
- foreach ($shares as $share) {
- $changePropagator->addChange($share['file_target']);
- }
- $time = microtime(true);
- $changePropagator->propagateChanges(floor($time));
- }
-
- /**
- * @param string $user
- * @return \OCA\Files_Sharing\Propagation\RecipientPropagator
- */
- public function getSharePropagator($user) {
- if (isset($this->sharePropagators[$user])) {
- return $this->sharePropagators[$user];
- }
- $this->sharePropagators[$user] = new RecipientPropagator($user, $this->getChangePropagator($user), $this->config, $this);
- return $this->sharePropagators[$user];
- }
-
- /**
- * Attach the recipient propagator for $user to the change propagator of a share owner to mark shares as dirty when the owner makes a change to a share
- *
- * @param string $shareOwner
- * @param string $user
- */
- public function listenToOwnerChanges($shareOwner, $user) {
- $sharePropagator = $this->getSharePropagator($user);
- $ownerPropagator = $this->getChangePropagator($shareOwner);
- $sharePropagator->attachToPropagator($ownerPropagator, $shareOwner);
- }
-
- /**
- * To be called from setupFS trough a hook
- *
- * Sets up listening to changes made to shares owned by the current user
- */
- public function globalSetup() {
- $user = $this->userSession->getUser();
- if (!$user) {
- return;
- }
- $recipientPropagator = $this->getSharePropagator($user->getUID());
- $watcher = new ChangeWatcher(Filesystem::getView(), $recipientPropagator);
-
- // for marking shares owned by the active user as dirty when a file inside them changes
- $this->listenToOwnerChanges($user->getUID(), $user->getUID());
- Util::connectHook('OC_Filesystem', 'post_write', $watcher, 'writeHook');
- Util::connectHook('OC_Filesystem', 'post_delete', $watcher, 'writeHook');
- Util::connectHook('OC_Filesystem', 'post_rename', $watcher, 'renameHook');
- Util::connectHook('OCP\Share', 'post_update_permissions', $watcher, 'permissionsHook');
- }
-}
diff --git a/apps/files_sharing/lib/propagation/recipientpropagator.php b/apps/files_sharing/lib/propagation/recipientpropagator.php
deleted file mode 100644
index 5eacf4c0f6e..00000000000
--- a/apps/files_sharing/lib/propagation/recipientpropagator.php
+++ /dev/null
@@ -1,164 +0,0 @@
-<?php
-/**
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Sharing\Propagation;
-
-use OC\Files\Cache\ChangePropagator;
-use OC\Files\View;
-use OC\Share\Share;
-use OCP\Files\NotFoundException;
-
-/**
- * Propagate etags for share recipients
- */
-class RecipientPropagator {
- /**
- * @var string
- */
- protected $userId;
-
- /**
- * @var \OC\Files\Cache\ChangePropagator
- */
- protected $changePropagator;
-
- /**
- * @var \OCP\IConfig
- */
- protected $config;
-
- /**
- * @var PropagationManager
- */
- private $manager;
-
- /**
- * @param string $userId current user, must match the propagator's
- * user
- * @param \OC\Files\Cache\ChangePropagator $changePropagator change propagator
- * initialized with a view for $user
- * @param \OCP\IConfig $config
- * @param PropagationManager $manager
- */
- public function __construct($userId, $changePropagator, $config, PropagationManager $manager) {
- $this->userId = $userId;
- $this->changePropagator = $changePropagator;
- $this->config = $config;
- $this->manager = $manager;
- }
-
- /**
- * Propagate the etag changes for all shares marked as dirty and mark the shares as clean
- *
- * @param array $shares the shares for the users
- * @param int $time
- */
- public function propagateDirtyMountPoints(array $shares, $time = null) {
- if ($time === null) {
- $time = microtime(true);
- }
- $dirtyShares = $this->getDirtyShares($shares);
- foreach ($dirtyShares as $share) {
- $this->changePropagator->addChange($share['file_target']);
- }
- if (count($dirtyShares)) {
- $this->config->setUserValue($this->userId, 'files_sharing', 'last_propagate', $time);
- $this->changePropagator->propagateChanges(floor($time));
- }
- }
-
- /**
- * Get all shares we need to update the etag for
- *
- * @param array $shares the shares for the users
- * @return string[]
- */
- protected function getDirtyShares($shares) {
- $dirty = [];
- $userTime = $this->config->getUserValue($this->userId, 'files_sharing', 'last_propagate', 0);
- foreach ($shares as $share) {
- $updateTime = $this->config->getAppValue('files_sharing', $share['id'], 0);
- if ($updateTime >= $userTime) {
- $dirty[] = $share;
- }
- }
- return $dirty;
- }
-
- /**
- * @param array $share
- * @param float $time
- */
- public function markDirty($share, $time = null) {
- if ($time === null) {
- $time = microtime(true);
- }
- $this->config->setAppValue('files_sharing', $share['id'], $time);
- }
-
- /**
- * Listen on the propagator for updates made to shares owned by a user
- *
- * @param \OC\Files\Cache\ChangePropagator $propagator
- * @param string $owner
- */
- public function attachToPropagator(ChangePropagator $propagator, $owner) {
- $propagator->listen('\OC\Files', 'propagate', function ($path, $entry) use ($owner) {
- $this->propagateById($entry['fileid']);
- });
- }
-
- protected $propagatingIds = [];
-
- /**
- * @param int $id
- */
- public function propagateById($id) {
- if (isset($this->propagatingIds[$id])) {
- return;
- }
- $this->propagatingIds[$id] = true;
- $shares = Share::getAllSharesForFileId($id);
- foreach ($shares as $share) {
- // propagate down the share tree
- $this->markDirty($share, microtime(true));
-
- // propagate up the share tree
- if ($share['share_with'] === $this->userId) {
- $user = $share['uid_owner'];
- $view = new View('/' . $user . '/files');
-
- try {
- $path = $view->getPath($share['file_source']);
- } catch (NotFoundException $e) {
- $path = null;
- }
-
- $watcher = new ChangeWatcher($view, $this->manager->getSharePropagator($user));
- $watcher->writeHook(['path' => $path]);
- }
- }
-
- unset($this->propagatingIds[$id]);
- }
-}
diff --git a/apps/files_sharing/lib/scanner.php b/apps/files_sharing/lib/scanner.php
index 23503bb56f2..e9cc40ae42c 100644
--- a/apps/files_sharing/lib/scanner.php
+++ b/apps/files_sharing/lib/scanner.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,10 +22,14 @@
namespace OC\Files\Cache;
+use OC\Files\ObjectStore\NoopScanner;
+use OC\Files\Storage\Shared;
+
/**
* Scanner for SharedStorage
*/
class SharedScanner extends Scanner {
+ private $sourceScanner;
/**
* Returns metadata from the shared storage, but
@@ -35,12 +39,35 @@ class SharedScanner extends Scanner {
*
* @return array an array of metadata of the file
*/
- public function getData($path){
+ public function getData($path) {
$data = parent::getData($path);
$sourcePath = $this->storage->getSourcePath($path);
list($sourceStorage, $internalPath) = \OC\Files\Filesystem::resolvePath($sourcePath);
$data['permissions'] = $sourceStorage->getPermissions($internalPath);
return $data;
}
+
+ private function getSourceScanner() {
+ if ($this->sourceScanner) {
+ return $this->sourceScanner;
+ }
+ if ($this->storage->instanceOfStorage('\OC\Files\Storage\Shared')) {
+ /** @var \OC\Files\Storage\Storage $storage */
+ list($storage) = $this->storage->resolvePath('');
+ $this->sourceScanner = $storage->getScanner();
+ return $this->sourceScanner;
+ } else {
+ return null;
+ }
+ }
+
+ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) {
+ $sourceScanner = $this->getSourceScanner();
+ if ($sourceScanner instanceof NoopScanner) {
+ return [];
+ } else {
+ return parent::scanFile($file, $reuseExisting, $parentId, $cacheData, $lock);
+ }
+ }
}
diff --git a/apps/files_sharing/lib/share/file.php b/apps/files_sharing/lib/share/file.php
index ffc417db2f4..113675508fb 100644
--- a/apps/files_sharing/lib/share/file.php
+++ b/apps/files_sharing/lib/share/file.php
@@ -11,7 +11,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/share/folder.php b/apps/files_sharing/lib/share/folder.php
index 5e7cd8099db..1004f049866 100644
--- a/apps/files_sharing/lib/share/folder.php
+++ b/apps/files_sharing/lib/share/folder.php
@@ -4,10 +4,10 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/lib/sharedmount.php b/apps/files_sharing/lib/sharedmount.php
index a1387957867..41194ec5862 100644
--- a/apps/files_sharing/lib/sharedmount.php
+++ b/apps/files_sharing/lib/sharedmount.php
@@ -5,8 +5,9 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -39,11 +40,6 @@ class SharedMount extends MountPoint implements MoveableMount {
protected $storage = null;
/**
- * @var \OC\Files\Cache\ChangePropagator
- */
- protected $ownerPropagator;
-
- /**
* @var \OC\Files\View
*/
private $recipientView;
@@ -53,9 +49,13 @@ class SharedMount extends MountPoint implements MoveableMount {
*/
private $user;
+ /**
+ * @param string $storage
+ * @param string $mountpoint
+ * @param array|null $arguments
+ * @param \OCP\Files\Storage\IStorageFactory $loader
+ */
public function __construct($storage, $mountpoint, $arguments = null, $loader = null) {
- // first update the mount point before creating the parent
- $this->ownerPropagator = $arguments['propagator'];
$this->user = $arguments['user'];
$this->recipientView = new View('/' . $this->user . '/files');
$newMountPoint = $this->verifyMountPoint($arguments['share']);
@@ -66,6 +66,9 @@ class SharedMount extends MountPoint implements MoveableMount {
/**
* check if the parent folder exists otherwise move the mount point up
+ *
+ * @param array $share
+ * @return string
*/
private function verifyMountPoint(&$share) {
@@ -128,6 +131,7 @@ class SharedMount extends MountPoint implements MoveableMount {
*
* @param string $path the absolute path
* @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
+ * @throws \OCA\Files_Sharing\Exceptions\BrokenPath
*/
protected function stripUserFilesPath($path) {
$trimmed = ltrim($path, '/');
@@ -190,7 +194,7 @@ class SharedMount extends MountPoint implements MoveableMount {
*/
public function removeMount() {
$mountManager = \OC\Files\Filesystem::getMountManager();
- /** @var \OC\Files\Storage\Shared */
+ /** @var $storage \OC\Files\Storage\Shared */
$storage = $this->getStorage();
$result = $storage->unshareStorage();
$mountManager->removeMount($this->mountPoint);
@@ -198,14 +202,12 @@ class SharedMount extends MountPoint implements MoveableMount {
return $result;
}
- public function getShare() {
- return $this->getStorage()->getShare();
- }
-
/**
- * @return \OC\Files\Cache\ChangePropagator
+ * @return array
*/
- public function getOwnerPropagator() {
- return $this->ownerPropagator;
+ public function getShare() {
+ /** @var $storage \OC\Files\Storage\Shared */
+ $storage = $this->getStorage();
+ return $storage->getShare();
}
}
diff --git a/apps/files_sharing/lib/sharedpropagator.php b/apps/files_sharing/lib/sharedpropagator.php
new file mode 100644
index 00000000000..29735934499
--- /dev/null
+++ b/apps/files_sharing/lib/sharedpropagator.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_Sharing;
+
+use OC\Files\Cache\Propagator;
+
+class SharedPropagator extends Propagator {
+ /**
+ * @var \OC\Files\Storage\Shared
+ */
+ protected $storage;
+
+ /**
+ * @param string $internalPath
+ * @param int $time
+ * @param int $sizeDifference
+ * @return \array[] all propagated entries
+ */
+ public function propagateChange($internalPath, $time, $sizeDifference = 0) {
+ $source = $this->storage->getSourcePath($internalPath);
+ /** @var \OC\Files\Storage\Storage $storage */
+ list($storage, $sourceInternalPath) = \OC\Files\Filesystem::resolvePath($source);
+ return $storage->getPropagator()->propagateChange($sourceInternalPath, $time, $sizeDifference);
+ }
+}
diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php
index 18e02844179..101503a03fb 100644
--- a/apps/files_sharing/lib/sharedstorage.php
+++ b/apps/files_sharing/lib/sharedstorage.php
@@ -6,12 +6,12 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author scambra <sergio@entrecables.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,8 +32,9 @@ namespace OC\Files\Storage;
use OC\Files\Filesystem;
use OCA\Files_Sharing\ISharedStorage;
-use OCA\Files_Sharing\Propagator;
-use OCA\Files_Sharing\SharedMount;
+use OCP\Constants;
+use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\Storage\IStorage;
use OCP\Lock\ILockingProvider;
/**
@@ -43,7 +44,6 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
private $share; // the shared resource
private $files = array();
- private static $isInitialized = array();
/**
* @var \OC\Files\View
@@ -51,21 +51,25 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
private $ownerView;
/**
- * @var \OCA\Files_Sharing\Propagation\PropagationManager
- */
- private $propagationManager;
-
- /**
* @var string
*/
private $user;
private $initialized = false;
+ /**
+ * @var ICacheEntry
+ */
+ private $sourceRootInfo;
+
+ /**
+ * @var IStorage
+ */
+ private $sourceStorage;
+
public function __construct($arguments) {
$this->share = $arguments['share'];
$this->ownerView = $arguments['ownerView'];
- $this->propagationManager = $arguments['propagationManager'];
$this->user = $arguments['user'];
}
@@ -75,9 +79,13 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
}
$this->initialized = true;
Filesystem::initMountPoints($this->share['uid_owner']);
+ $sourcePath = $this->ownerView->getPath($this->share['file_source']);
+ list($this->sourceStorage, $sourceInternalPath) = $this->ownerView->resolvePath($sourcePath);
+ $this->sourceRootInfo = $this->sourceStorage->getCache()->get($sourceInternalPath);
+ }
- // for updating our etags when changes are made to the share from the owners side (probably indirectly by us trough another share)
- $this->propagationManager->listenToOwnerChanges($this->share['uid_owner'], $this->user);
+ private function isValid() {
+ return ($this->sourceRootInfo->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
}
/**
@@ -130,6 +138,9 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
* @return string|false source file path or false if not found
*/
public function getSourcePath($target) {
+ if (!$this->isValid()){
+ return false;
+ }
$source = $this->getFile($target);
if ($source) {
if (!isset($source['fullPath'])) {
@@ -154,6 +165,9 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
* @return int CRUDS permissions granted
*/
public function getPermissions($target = '') {
+ if (!$this->isValid()) {
+ return 0;
+ }
$permissions = $this->share['permissions'];
// part files and the mount point always have delete permissions
if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
@@ -250,13 +264,14 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
}
public function isReadable($path) {
- $isReadable = false;
- if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- $isReadable = $storage->isReadable($internalPath);
+ if (!$this->isValid()) {
+ return false;
}
-
- return $isReadable && $this->file_exists($path);
+ if (!$this->file_exists($path)) {
+ return false;
+ }
+ list($storage, $internalPath) = $this->resolvePath($path);
+ return $storage->isReadable($internalPath);
}
public function isUpdatable($path) {
@@ -268,7 +283,7 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
}
public function isSharable($path) {
- if (\OCP\Util::isSharingDisabledForUser()) {
+ if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
return false;
}
return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
@@ -554,7 +569,7 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
if (!$storage) {
$storage = $this;
}
- return new \OC\Files\Cache\Shared_Cache($storage);
+ return new \OC\Files\Cache\Shared_Cache($storage, $this->sourceStorage, $this->sourceRootInfo);
}
public function getScanner($path = '', $storage = null) {
@@ -564,11 +579,11 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
return new \OC\Files\Cache\SharedScanner($storage);
}
- public function getWatcher($path = '', $storage = null) {
+ public function getPropagator($storage = null) {
if (!$storage) {
$storage = $this;
}
- return new \OC\Files\Cache\Shared_Watcher($storage);
+ return new \OCA\Files_Sharing\SharedPropagator($storage);
}
public function getOwner($path) {
@@ -613,7 +628,7 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
* @param string $path
* @return array
*/
- private function resolvePath($path) {
+ public function resolvePath($path) {
$source = $this->getSourcePath($path);
return \OC\Files\Filesystem::resolvePath($source);
}
@@ -703,4 +718,11 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
public function setAvailability($available) {
// shares do not participate in availability logic
}
+
+ public function isLocal() {
+ $this->init();
+ $ownerPath = $this->ownerView->getPath($this->share['item_source']);
+ list($targetStorage) = $this->ownerView->resolvePath($ownerPath);
+ return $targetStorage->isLocal();
+ }
}
diff --git a/apps/files_sharing/lib/updater.php b/apps/files_sharing/lib/updater.php
index 26044cc1c8e..9a1e554046b 100644
--- a/apps/files_sharing/lib/updater.php
+++ b/apps/files_sharing/lib/updater.php
@@ -8,7 +8,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -58,6 +58,47 @@ class Shared_Updater {
*/
static public function renameHook($params) {
self::renameChildren($params['oldpath'], $params['newpath']);
+ self::moveShareToShare($params['newpath']);
+ }
+
+ /**
+ * Fix for https://github.com/owncloud/core/issues/20769
+ *
+ * The owner is allowed to move their files (if they are shared) into a receiving folder
+ * In this case we need to update the parent of the moved share. Since they are
+ * effectively handing over ownership of the file the rest of the code needs to know
+ * they need to build up the reshare tree.
+ *
+ * @param string $path
+ */
+ static private function moveShareToShare($path) {
+ $userFolder = \OC::$server->getUserFolder();
+ $src = $userFolder->get($path);
+
+ $type = $src instanceof \OCP\Files\File ? 'file' : 'folder';
+ $shares = \OCP\Share::getItemShared($type, $src->getId());
+
+ // If the path we move is not a share we don't care
+ if (empty($shares)) {
+ return;
+ }
+
+ // Check if the destination is inside a share
+ $mountManager = \OC::$server->getMountManager();
+ $dstMount = $mountManager->find($src->getPath());
+ if (!($dstMount instanceof \OCA\Files_Sharing\SharedMount)) {
+ return;
+ }
+
+ $parenShare = $dstMount->getShare();
+
+ foreach ($shares as $share) {
+ $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ $qb->update('share')
+ ->set('parent', $qb->createNamedParameter($parenShare['id']))
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($share['id'])))
+ ->execute();
+ }
}
/**
diff --git a/apps/files_sharing/lib/watcher.php b/apps/files_sharing/lib/watcher.php
deleted file mode 100644
index 3af6f733b51..00000000000
--- a/apps/files_sharing/lib/watcher.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/**
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Michael Gapczynski <GapczynskiM@gmail.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OC\Files\Cache;
-
-/**
- * check the storage backends for updates and change the cache accordingly
- */
-class Shared_Watcher extends Watcher {
- /**
- * @var \OC\Files\Storage\Shared $storage
- */
- protected $storage;
-
- /**
- * Update the cache for changes to $path
- *
- * @param string $path
- * @param array $cachedData
- */
- public function update($path, $cachedData) {
- parent::update($path, $cachedData);
- // since parent::update() has already updated the size of the subdirs,
- // only apply the update to the owner's parent dirs
-
- // find last parent before reaching the shared storage root,
- // which is the actual shared dir from the owner
- $sepPos = strpos($path, '/');
- if ($sepPos > 0) {
- $baseDir = substr($path, 0, $sepPos);
- } else {
- $baseDir = $path;
- }
-
- // find the path relative to the data dir
- $file = $this->storage->getFile($baseDir);
- $view = new \OC\Files\View('/' . $file['fileOwner']);
-
- // find the owner's storage and path
- /** @var \OC\Files\Storage\Storage $storage */
- list($storage, $internalPath) = $view->resolvePath($file['path']);
-
- // update the parent dirs' sizes in the owner's cache
- $storage->getCache()->correctFolderSize(dirname($internalPath));
- }
-
- /**
- * remove deleted files in $path from the cache
- *
- * @param string $path
- */
- public function cleanFolder($path) {
- if ($path != '') {
- parent::cleanFolder($path);
- }
- }
-
-}
diff --git a/apps/files_sharing/list.php b/apps/files_sharing/list.php
index 2577ed91006..5d5d061187c 100644
--- a/apps/files_sharing/list.php
+++ b/apps/files_sharing/list.php
@@ -2,7 +2,7 @@
/**
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php
index 772419e64e4..0d67edcd362 100644
--- a/apps/files_sharing/public.php
+++ b/apps/files_sharing/public.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/settings-admin.php b/apps/files_sharing/settings-admin.php
index 9a89c45bfd7..b2a305ebcdb 100644
--- a/apps/files_sharing/settings-admin.php
+++ b/apps/files_sharing/settings-admin.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/settings-personal.php b/apps/files_sharing/settings-personal.php
index deaa7b92ac7..982a8b05c15 100644
--- a/apps/files_sharing/settings-personal.php
+++ b/apps/files_sharing/settings-personal.php
@@ -2,10 +2,9 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Jan-Christoph Borchardt <hey@jancborchardt.net>
- * @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,9 +31,7 @@ if (count($matches) > 0 && $matches[1] <= 9) {
$isIE8 = true;
}
-$uid = \OC::$server->getUserSession()->getUser()->getUID();
-$server = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
-$cloudID = $uid . '@' . rtrim(\OCA\Files_Sharing\Helper::removeProtocolFromUrl($server), '/');
+$cloudID = \OC::$server->getUserSession()->getUser()->getCloudId();
$url = 'https://owncloud.org/federation#' . $cloudID;
$ownCloudLogoPath = \OC::$server->getURLGenerator()->imagePath('core', 'logo-icon.svg');
diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php
index b5dd653d718..ae00b01dca2 100644
--- a/apps/files_sharing/templates/public.php
+++ b/apps/files_sharing/templates/public.php
@@ -26,7 +26,7 @@ $thumbSize = 1024;
?>
<?php if ($_['previewSupported']): /* This enables preview images for links (e.g. on Facebook, Google+, ...)*/?>
- <link rel="image_src" href="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => $thumbSize, 'y' => $thumbSize, 'file' => $_['directory_path'], 't' => $_['dirToken']))); ?>" />
+ <link rel="image_src" href="<?php p(\OC::$server->getURLGenerator()->linkToRoute( 'core_ajax_public_preview', array('x' => $thumbSize, 'y' => $thumbSize, 'file' => $_['directory_path'], 't' => $_['dirToken']))); ?>" />
<?php endif; ?>
<div id="notification-container">
@@ -41,7 +41,7 @@ $thumbSize = 1024;
<input type="hidden" name="filename" value="<?php p($_['filename']) ?>" id="filename">
<input type="hidden" name="mimetype" value="<?php p($_['mimetype']) ?>" id="mimetype">
<input type="hidden" name="previewSupported" value="<?php p($_['previewSupported'] ? 'true' : 'false'); ?>" id="previewSupported">
-<input type="hidden" name="mimetypeIcon" value="<?php p(OC_Helper::mimetypeIcon($_['mimetype'])); ?>" id="mimetypeIcon">
+<input type="hidden" name="mimetypeIcon" value="<?php p(\OC::$server->getMimeTypeDetector()->mimeTypeIcon($_['mimetype'])); ?>" id="mimetypeIcon">
<input type="hidden" name="filesize" value="<?php p($_['nonHumanFileSize']); ?>" id="filesize">
<input type="hidden" name="maxSizeAnimateGif" value="<?php p($_['maxSizeAnimateGif']); ?>" id="maxSizeAnimateGif">
@@ -72,7 +72,7 @@ $thumbSize = 1024;
if ($_['server2serversharing']) {
?>
<span id="save" data-protected="<?php p($_['protected']) ?>"
- data-owner="<?php p($_['displayName']) ?>" data-name="<?php p($_['filename']) ?>">
+ data-owner-display-name="<?php p($_['displayName']) ?>" data-owner="<?php p($_['owner']) ?>" data-name="<?php p($_['filename']) ?>">
<button id="save-button"><?php p($l->t('Add to your ownCloud')) ?></button>
<form class="save-form hidden" action="#">
<input type="text" id="remote_address" placeholder="example.com/owncloud"/>
@@ -81,7 +81,7 @@ $thumbSize = 1024;
</span>
<?php } ?>
<a href="<?php p($_['downloadURL']); ?>" id="download" class="button">
- <img class="svg" alt="" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"/>
+ <img class="svg" alt="" src="<?php print_unescaped(image_path("core", "actions/download.svg")); ?>"/>
<span id="download-text"><?php p($l->t('Download'))?></span>
</a>
</span>
@@ -105,7 +105,7 @@ $thumbSize = 1024;
<?php endif; ?>
<div class="directDownload">
<a href="<?php p($_['downloadURL']); ?>" id="downloadFile" class="button">
- <img class="svg" alt="" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"/>
+ <img class="svg" alt="" src="<?php print_unescaped(image_path("core", "actions/download.svg")); ?>"/>
<?php p($l->t('Download %s', array($_['filename'])))?> (<?php p($_['fileSize']) ?>)
</a>
</div>
diff --git a/apps/files_sharing/tests/activity.php b/apps/files_sharing/tests/activity.php
index f7f324cdfc3..40a1031f779 100644
--- a/apps/files_sharing/tests/activity.php
+++ b/apps/files_sharing/tests/activity.php
@@ -3,8 +3,9 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,10 +23,15 @@
*/
namespace OCA\Files_sharing\Tests;
-use OCA\Files_sharing\Tests\TestCase;
-
-class Activity extends \OCA\Files_Sharing\Tests\TestCase{
+/**
+ * Class Activity
+ *
+ * @group DB
+ *
+ * @package OCA\Files_sharing\Tests
+ */
+class Activity extends \OCA\Files_Sharing\Tests\TestCase {
/**
* @var \OCA\Files_Sharing\Activity
@@ -35,11 +41,13 @@ class Activity extends \OCA\Files_Sharing\Tests\TestCase{
protected function setUp() {
parent::setUp();
$this->activity = new \OCA\Files_Sharing\Activity(
- $this->getMock('\OC\L10N\Factory'),
- $this->getMockBuilder('\OCP\IURLGenerator')
+ $this->getMockBuilder('OCP\L10N\IFactory')
+ ->disableOriginalConstructor()
+ ->getMock(),
+ $this->getMockBuilder('OCP\IURLGenerator')
->disableOriginalConstructor()
->getMock(),
- $this->getMockBuilder('\OCP\Activity\IManager')
+ $this->getMockBuilder('OCP\Activity\IManager')
->disableOriginalConstructor()
->getMock()
);
diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php
index 760bc0591e5..49a08d3d0ce 100644
--- a/apps/files_sharing/tests/api.php
+++ b/apps/files_sharing/tests/api.php
@@ -4,12 +4,12 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,6 +31,8 @@ use OCA\Files_sharing\Tests\TestCase;
/**
* Class Test_Files_Sharing_Api
+ *
+ * @group DB
*/
class Test_Files_Sharing_Api extends TestCase {
diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php
index f74585eb47d..a93cd5f58ce 100644
--- a/apps/files_sharing/tests/api/share20ocstest.php
+++ b/apps/files_sharing/tests/api/share20ocstest.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,83 +21,98 @@
namespace OCA\Files_Sharing\Tests\API;
use OCA\Files_Sharing\API\Share20OCS;
+use OCP\IGroupManager;
+use OCP\IUserManager;
+use OCP\IRequest;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\Files\IRootFolder;
class Share20OCSTest extends \Test\TestCase {
- /** @var OC\Share20\Manager */
+ /** @var \OC\Share20\Manager | \PHPUnit_Framework_MockObject_MockObject */
private $shareManager;
- /** @var OCP\IGroupManager */
+ /** @var IGroupManager | \PHPUnit_Framework_MockObject_MockObject */
private $groupManager;
- /** @var OCP\IUserManager */
+ /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */
private $userManager;
- /** @var OCP\IRequest */
+ /** @var IRequest | \PHPUnit_Framework_MockObject_MockObject */
private $request;
- /** @var OCP\Files\Folder */
- private $userFolder;
+ /** @var IRootFolder | \PHPUnit_Framework_MockObject_MockObject */
+ private $rootFolder;
- /** @var OCP\IURLGenerator */
+ /** @var IURLGenerator */
private $urlGenerator;
- /** @var OCS */
+ /** @var IUser */
+ private $currentUser;
+
+ /** @var Share20OCS */
private $ocs;
protected function setUp() {
- $this->shareManager = $this->getMockBuilder('OC\Share20\Manager')
+ $this->shareManager = $this->getMockBuilder('OCP\Share\IManager')
->disableOriginalConstructor()
->getMock();
$this->groupManager = $this->getMock('OCP\IGroupManager');
$this->userManager = $this->getMock('OCP\IUserManager');
$this->request = $this->getMock('OCP\IRequest');
- $this->userFolder = $this->getMock('OCP\Files\Folder');
+ $this->rootFolder = $this->getMock('OCP\Files\IRootFolder');
$this->urlGenerator = $this->getMock('OCP\IURLGenerator');
+ $this->currentUser = $this->getMock('OCP\IUser');
+ $this->currentUser->method('getUID')->willReturn('currentUser');
- $this->ocs = new Share20OCS($this->shareManager,
- $this->groupManager,
- $this->userManager,
- $this->request,
- $this->userFolder,
- $this->urlGenerator);
+ $this->ocs = new Share20OCS(
+ $this->shareManager,
+ $this->groupManager,
+ $this->userManager,
+ $this->request,
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->currentUser
+ );
}
- public function testDeleteShareShareNotFound() {
- $this->shareManager
- ->expects($this->once())
- ->method('getShareById')
- ->with(42)
- ->will($this->throwException(new \OC\Share20\Exception\ShareNotFound()));
+ private function mockFormatShare() {
+ return $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS')
+ ->setConstructorArgs([
+ $this->shareManager,
+ $this->groupManager,
+ $this->userManager,
+ $this->request,
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->currentUser
+ ])->setMethods(['formatShare'])
+ ->getMock();
+ }
- $expected = new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
- $this->assertEquals($expected, $this->ocs->deleteShare(42));
+ private function newShare() {
+ return \OC::$server->getShareManager()->newShare();
}
- public function testDeleteShareCouldNotDelete() {
- $share = $this->getMock('OC\Share20\IShare');
+ public function testDeleteShareShareNotFound() {
$this->shareManager
->expects($this->once())
->method('getShareById')
- ->with(42)
- ->willReturn($share);
- $this->shareManager
- ->expects($this->once())
- ->method('deleteShare')
- ->with($share)
- ->will($this->throwException(new \OC\Share20\Exception\BackendError()));
+ ->with('ocinternal:42')
+ ->will($this->throwException(new \OCP\Share\Exceptions\ShareNotFound()));
-
- $expected = new \OC_OCS_Result(null, 404, 'could not delete share');
+ $expected = new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
$this->assertEquals($expected, $this->ocs->deleteShare(42));
}
public function testDeleteShare() {
- $share = $this->getMock('OC\Share20\IShare');
+ $share = $this->newShare();
+ $share->setSharedBy($this->currentUser->getUID());
$this->shareManager
->expects($this->once())
->method('getShareById')
- ->with(42)
+ ->with('ocinternal:42')
->willReturn($share);
$this->shareManager
->expects($this->once())
@@ -108,54 +123,63 @@ class Share20OCSTest extends \Test\TestCase {
$this->assertEquals($expected, $this->ocs->deleteShare(42));
}
+ /*
+ * FIXME: Enable once we have a federated Share Provider
+
public function testGetGetShareNotExists() {
$this->shareManager
->expects($this->once())
->method('getShareById')
- ->with(42)
+ ->with('ocinternal:42')
->will($this->throwException(new \OC\Share20\Exception\ShareNotFound()));
$expected = new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
$this->assertEquals($expected, $this->ocs->getShare(42));
}
+ */
- public function createShare($id, $shareType, $sharedWith, $sharedBy, $path, $permissions,
+ public function createShare($id, $shareType, $sharedWith, $sharedBy, $shareOwner, $path, $permissions,
$shareTime, $expiration, $parent, $target, $mail_send, $token=null,
$password=null) {
- $share = $this->getMock('OC\Share20\IShare');
+ $share = $this->getMock('\OCP\Share\IShare');
$share->method('getId')->willReturn($id);
$share->method('getShareType')->willReturn($shareType);
$share->method('getSharedWith')->willReturn($sharedWith);
$share->method('getSharedBy')->willReturn($sharedBy);
- $share->method('getPath')->willReturn($path);
+ $share->method('getShareOwner')->willReturn($shareOwner);
+ $share->method('getNode')->willReturn($path);
$share->method('getPermissions')->willReturn($permissions);
- $share->method('getShareTime')->willReturn($shareTime);
+ $time = new \DateTime();
+ $time->setTimestamp($shareTime);
+ $share->method('getShareTime')->willReturn($time);
$share->method('getExpirationDate')->willReturn($expiration);
- $share->method('getParent')->willReturn($parent);
$share->method('getTarget')->willReturn($target);
$share->method('getMailSend')->willReturn($mail_send);
$share->method('getToken')->willReturn($token);
$share->method('getPassword')->willReturn($password);
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER ||
+ $shareType === \OCP\Share::SHARE_TYPE_GROUP ||
+ $shareType === \OCP\Share::SHARE_TYPE_LINK) {
+ $share->method('getFullId')->willReturn('ocinternal:'.$id);
+ }
+
return $share;
}
public function dataGetShare() {
$data = [];
- $owner = $this->getMock('OCP\IUser');
- $owner->method('getUID')->willReturn('ownerId');
- $owner->method('getDisplayName')->willReturn('ownerDisplay');
-
- $user = $this->getMock('OCP\IUser');
- $user->method('getUID')->willReturn('userId');
- $user->method('getDisplayName')->willReturn('userDisplay');
-
- $group = $this->getMock('OCP\IGroup');
- $group->method('getGID')->willReturn('groupId');
+ $cache = $this->getMockBuilder('OC\Files\Cache\Cache')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $cache->method('getNumericStorageId')->willReturn(101);
- $storage = $this->getMock('OCP\Files\Storage');
+ $storage = $this->getMockBuilder('OC\Files\Storage\Storage')
+ ->disableOriginalConstructor()
+ ->getMock();
$storage->method('getId')->willReturn('STORAGE');
+ $storage->method('getCache')->willReturn($cache);
$parentFolder = $this->getMock('OCP\Files\Folder');
$parentFolder->method('getId')->willReturn(3);
@@ -173,24 +197,27 @@ class Share20OCSTest extends \Test\TestCase {
$folder->method('getParent')->willReturn($parentFolder);
// File shared with user
- $share = $this->createShare(100,
- \OCP\Share::SHARE_TYPE_USER,
- $user,
- $owner,
- $file,
- 4,
- 5,
- null,
- 6,
- 'target',
- 0);
+ $share = $this->createShare(
+ 100,
+ \OCP\Share::SHARE_TYPE_USER,
+ 'userId',
+ 'initiatorId',
+ 'ownerId',
+ $file,
+ 4,
+ 5,
+ null,
+ 6,
+ 'target',
+ 0
+ );
$expected = [
'id' => 100,
'share_type' => \OCP\Share::SHARE_TYPE_USER,
'share_with' => 'userId',
'share_with_displayname' => 'userDisplay',
- 'uid_owner' => 'ownerId',
- 'displayname_owner' => 'ownerDisplay',
+ 'uid_owner' => 'initiatorId',
+ 'displayname_owner' => 'initiatorDisplay',
'item_type' => 'file',
'item_source' => 1,
'file_source' => 1,
@@ -200,69 +227,38 @@ class Share20OCSTest extends \Test\TestCase {
'expiration' => null,
'permissions' => 4,
'stime' => 5,
- 'parent' => 6,
+ 'parent' => null,
'storage_id' => 'STORAGE',
'path' => 'file',
- 'storage' => null, // HACK around static function
+ 'storage' => 101,
'mail_send' => 0,
+ 'uid_file_owner' => 'ownerId',
+ 'displayname_file_owner' => 'ownerDisplay'
];
$data[] = [$share, $expected];
// Folder shared with group
- $share = $this->createShare(101,
- \OCP\Share::SHARE_TYPE_GROUP,
- $group,
- $owner,
- $folder,
- 4,
- 5,
- null,
- 6,
- 'target',
- 0);
+ $share = $this->createShare(
+ 101,
+ \OCP\Share::SHARE_TYPE_GROUP,
+ 'groupId',
+ 'initiatorId',
+ 'ownerId',
+ $folder,
+ 4,
+ 5,
+ null,
+ 6,
+ 'target',
+ 0
+ );
$expected = [
'id' => 101,
'share_type' => \OCP\Share::SHARE_TYPE_GROUP,
'share_with' => 'groupId',
'share_with_displayname' => 'groupId',
- 'uid_owner' => 'ownerId',
- 'displayname_owner' => 'ownerDisplay',
- 'item_type' => 'folder',
- 'item_source' => 2,
- 'file_source' => 2,
- 'file_target' => 'target',
- 'file_parent' => 3,
- 'token' => null,
- 'expiration' => null,
- 'permissions' => 4,
- 'stime' => 5,
- 'parent' => 6,
- 'storage_id' => 'STORAGE',
- 'path' => 'folder',
- 'storage' => null, // HACK around static function
- 'mail_send' => 0,
- ];
- $data[] = [$share, $expected];
-
- // Folder shared with remote
- $share = $this->createShare(101,
- \OCP\Share::SHARE_TYPE_REMOTE,
- 'user@remote.com',
- $owner,
- $folder,
- 4,
- 5,
- null,
- 6,
- 'target',
- 0);
- $expected = [
- 'id' => 101,
- 'share_type' => \OCP\Share::SHARE_TYPE_REMOTE,
- 'share_with' => 'user@remote.com',
- 'share_with_displayname' => 'user@remote.com',
- 'uid_owner' => 'ownerId',
- 'displayname_owner' => 'ownerDisplay',
+ 'uid_owner' => 'initiatorId',
+ 'displayname_owner' => 'initiatorDisplay',
'item_type' => 'folder',
'item_source' => 2,
'file_source' => 2,
@@ -272,36 +268,41 @@ class Share20OCSTest extends \Test\TestCase {
'expiration' => null,
'permissions' => 4,
'stime' => 5,
- 'parent' => 6,
+ 'parent' => null,
'storage_id' => 'STORAGE',
'path' => 'folder',
- 'storage' => null, // HACK around static function
+ 'storage' => 101,
'mail_send' => 0,
+ 'uid_file_owner' => 'ownerId',
+ 'displayname_file_owner' => 'ownerDisplay'
];
$data[] = [$share, $expected];
// File shared by link with Expire
$expire = \DateTime::createFromFormat('Y-m-d h:i:s', '2000-01-02 01:02:03');
- $share = $this->createShare(101,
- \OCP\Share::SHARE_TYPE_LINK,
- null,
- $owner,
- $folder,
- 4,
- 5,
- $expire,
- 6,
- 'target',
- 0,
- 'token',
- 'password');
+ $share = $this->createShare(
+ 101,
+ \OCP\Share::SHARE_TYPE_LINK,
+ null,
+ 'initiatorId',
+ 'ownerId',
+ $folder,
+ 4,
+ 5,
+ $expire,
+ 6,
+ 'target',
+ 0,
+ 'token',
+ 'password'
+ );
$expected = [
'id' => 101,
'share_type' => \OCP\Share::SHARE_TYPE_LINK,
'share_with' => 'password',
'share_with_displayname' => 'password',
- 'uid_owner' => 'ownerId',
- 'displayname_owner' => 'ownerDisplay',
+ 'uid_owner' => 'initiatorId',
+ 'displayname_owner' => 'initiatorDisplay',
'item_type' => 'folder',
'item_source' => 2,
'file_source' => 2,
@@ -311,12 +312,14 @@ class Share20OCSTest extends \Test\TestCase {
'expiration' => '2000-01-02 00:00:00',
'permissions' => 4,
'stime' => 5,
- 'parent' => 6,
+ 'parent' => null,
'storage_id' => 'STORAGE',
'path' => 'folder',
- 'storage' => null, // HACK around static function
+ 'storage' => 101,
'mail_send' => 0,
'url' => 'url',
+ 'uid_file_owner' => 'ownerId',
+ 'displayname_file_owner' => 'ownerDisplay'
];
$data[] = [$share, $expected];
@@ -326,21 +329,1029 @@ class Share20OCSTest extends \Test\TestCase {
/**
* @dataProvider dataGetShare
*/
- public function testGetShare(\OC\Share20\IShare $share, array $result) {
+ public function testGetShare(\OCP\Share\IShare $share, array $result) {
+ $ocs = $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS')
+ ->setConstructorArgs([
+ $this->shareManager,
+ $this->groupManager,
+ $this->userManager,
+ $this->request,
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->currentUser
+ ])->setMethods(['canAccessShare'])
+ ->getMock();
+
+ $ocs->method('canAccessShare')->willReturn(true);
+
$this->shareManager
->expects($this->once())
->method('getShareById')
- ->with($share->getId())
+ ->with($share->getFullId())
->willReturn($share);
- $this->userFolder
+ $userFolder = $this->getMock('OCP\Files\Folder');
+ $userFolder
->method('getRelativePath')
->will($this->returnArgument(0));
+ $this->rootFolder->method('getUserFolder')
+ ->with($share->getShareOwner())
+ ->willReturn($userFolder);
+
$this->urlGenerator
->method('linkToRouteAbsolute')
->willReturn('url');
+ $initiator = $this->getMock('OCP\IUser');
+ $initiator->method('getUID')->willReturn('initiatorId');
+ $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
+
+ $owner = $this->getMock('OCP\IUser');
+ $owner->method('getUID')->willReturn('ownerId');
+ $owner->method('getDisplayName')->willReturn('ownerDisplay');
+
+ $user = $this->getMock('OCP\IUser');
+ $user->method('getUID')->willReturn('userId');
+ $user->method('getDisplayName')->willReturn('userDisplay');
+
+ $group = $this->getMock('OCP\IGroup');
+ $group->method('getGID')->willReturn('groupId');
+
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['userId', $user],
+ ['initiatorId', $initiator],
+ ['ownerId', $owner],
+ ]));
+ $this->groupManager->method('get')->will($this->returnValueMap([
+ ['group', $group],
+ ]));
+
$expected = new \OC_OCS_Result($result);
- $this->assertEquals($expected->getData(), $this->ocs->getShare($share->getId())->getData()); }
+ $this->assertEquals($expected->getData(), $ocs->getShare($share->getId())->getData());
+ }
+
+ public function testCanAccessShare() {
+ $share = $this->getMock('OCP\Share\IShare');
+ $share->method('getShareOwner')->willReturn($this->currentUser->getUID());
+ $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
+
+ $share = $this->getMock('OCP\Share\IShare');
+ $share->method('getSharedBy')->willReturn($this->currentUser->getUID());
+ $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
+
+ $share = $this->getMock('OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER);
+ $share->method('getSharedWith')->willReturn($this->currentUser->getUID());
+ $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
+
+ $share = $this->getMock('OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER);
+ $share->method('getSharedWith')->willReturn($this->getMock('OCP\IUser'));
+ $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
+
+ $share = $this->getMock('OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_GROUP);
+ $share->method('getSharedWith')->willReturn('group');
+
+ $group = $this->getMock('OCP\IGroup');
+ $group->method('inGroup')->with($this->currentUser)->willReturn(true);
+ $group2 = $this->getMock('OCP\IGroup');
+ $group2->method('inGroup')->with($this->currentUser)->willReturn(false);
+
+
+ $this->groupManager->method('get')->will($this->returnValueMap([
+ ['group', $group],
+ ['group2', $group2],
+ ]));
+ $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
+
+ $share = $this->getMock('OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_GROUP);
+ $share->method('getSharedWith')->willReturn('group2');
+
+ $this->groupManager->method('get')->with('group2')->willReturn($group);
+ $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
+
+ $share = $this->getMock('OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_LINK);
+ $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
+ }
+
+ public function testCreateShareNoPath() {
+ $expected = new \OC_OCS_Result(null, 404, 'please specify a file or folder path');
+
+ $result = $this->ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareInvalidPath() {
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'invalid-path'],
+ ]));
+
+ $userFolder = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('currentUser')
+ ->willReturn($userFolder);
+
+ $userFolder->expects($this->once())
+ ->method('get')
+ ->with('invalid-path')
+ ->will($this->throwException(new \OCP\Files\NotFoundException()));
+
+ $expected = new \OC_OCS_Result(null, 404, 'wrong path, file/folder doesn\'t exist');
+
+ $result = $this->ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareInvalidPermissions() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $this->shareManager->method('newShare')->willReturn($share);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['permissions', null, 32],
+ ]));
+
+ $userFolder = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('currentUser')
+ ->willReturn($userFolder);
+
+ $path = $this->getMock('\OCP\Files\File');
+ $userFolder->expects($this->once())
+ ->method('get')
+ ->with('valid-path')
+ ->willReturn($path);
+
+ $expected = new \OC_OCS_Result(null, 404, 'invalid permissions');
+
+ $result = $this->ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareUserNoShareWith() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $this->shareManager->method('newShare')->willReturn($share);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['permissions', null, \OCP\Constants::PERMISSION_ALL],
+ ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER],
+ ]));
+
+ $userFolder = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('currentUser')
+ ->willReturn($userFolder);
+
+ $path = $this->getMock('\OCP\Files\File');
+ $userFolder->expects($this->once())
+ ->method('get')
+ ->with('valid-path')
+ ->willReturn($path);
+
+ $expected = new \OC_OCS_Result(null, 404, 'please specify a valid user');
+
+ $result = $this->ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareUserNoValidShareWith() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $this->shareManager->method('newShare')->willReturn($share);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['permissions', null, \OCP\Constants::PERMISSION_ALL],
+ ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER],
+ ['shareWith', $this->any(), 'invalidUser'],
+ ]));
+
+ $userFolder = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('currentUser')
+ ->willReturn($userFolder);
+
+ $path = $this->getMock('\OCP\Files\File');
+ $userFolder->expects($this->once())
+ ->method('get')
+ ->with('valid-path')
+ ->willReturn($path);
+
+ $expected = new \OC_OCS_Result(null, 404, 'please specify a valid user');
+
+ $result = $this->ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareUser() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $this->shareManager->method('newShare')->willReturn($share);
+ $this->shareManager->method('createShare')->will($this->returnArgument(0));
+
+ $ocs = $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS')
+ ->setConstructorArgs([
+ $this->shareManager,
+ $this->groupManager,
+ $this->userManager,
+ $this->request,
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->currentUser
+ ])->setMethods(['formatShare'])
+ ->getMock();
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['permissions', null, \OCP\Constants::PERMISSION_ALL],
+ ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER],
+ ['shareWith', null, 'validUser'],
+ ]));
+
+ $userFolder = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('currentUser')
+ ->willReturn($userFolder);
+
+ $path = $this->getMock('\OCP\Files\File');
+ $userFolder->expects($this->once())
+ ->method('get')
+ ->with('valid-path')
+ ->willReturn($path);
+
+ $user = $this->getMock('\OCP\IUser');
+ $this->userManager->method('userExists')->with('validUser')->willReturn(true);
+
+ $share->method('setPath')->with($path);
+ $share->method('setPermissions')
+ ->with(
+ \OCP\Constants::PERMISSION_ALL &
+ ~\OCP\Constants::PERMISSION_DELETE &
+ ~\OCP\Constants::PERMISSION_CREATE);
+ $share->method('setShareType')->with(\OCP\Share::SHARE_TYPE_USER);
+ $share->method('setSharedWith')->with('validUser');
+ $share->method('setSharedBy')->with('currentUser');
+
+ $expected = new \OC_OCS_Result();
+ $result = $ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareGroupNoValidShareWith() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $this->shareManager->method('newShare')->willReturn($share);
+ $this->shareManager->method('createShare')->will($this->returnArgument(0));
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['permissions', null, \OCP\Constants::PERMISSION_ALL],
+ ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_GROUP],
+ ['shareWith', $this->any(), 'invalidGroup'],
+ ]));
+
+ $userFolder = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('currentUser')
+ ->willReturn($userFolder);
+
+ $path = $this->getMock('\OCP\Files\File');
+ $userFolder->expects($this->once())
+ ->method('get')
+ ->with('valid-path')
+ ->willReturn($path);
+
+ $expected = new \OC_OCS_Result(null, 404, 'please specify a valid user');
+
+ $result = $this->ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareGroup() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $this->shareManager->method('newShare')->willReturn($share);
+ $this->shareManager->method('createShare')->will($this->returnArgument(0));
+
+ $ocs = $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS')
+ ->setConstructorArgs([
+ $this->shareManager,
+ $this->groupManager,
+ $this->userManager,
+ $this->request,
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->currentUser
+ ])->setMethods(['formatShare'])
+ ->getMock();
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['permissions', null, \OCP\Constants::PERMISSION_ALL],
+ ['shareType', '-1', \OCP\Share::SHARE_TYPE_GROUP],
+ ['shareWith', null, 'validGroup'],
+ ]));
+
+ $userFolder = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('currentUser')
+ ->willReturn($userFolder);
+
+ $path = $this->getMock('\OCP\Files\Folder');
+ $userFolder->expects($this->once())
+ ->method('get')
+ ->with('valid-path')
+ ->willReturn($path);
+
+ $group = $this->getMock('\OCP\IGroup');
+ $this->groupManager->method('groupExists')->with('validGroup')->willReturn(true);
+
+ $share->method('setPath')->with($path);
+ $share->method('setPermissions')->with(\OCP\Constants::PERMISSION_ALL);
+ $share->method('setShareType')->with(\OCP\Share::SHARE_TYPE_GROUP);
+ $share->method('setSharedWith')->with('validGroup');
+ $share->method('setSharedBy')->with('currentUser');
+
+ $expected = new \OC_OCS_Result();
+ $result = $ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareLinkNoLinksAllowed() {
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK],
+ ]));
+
+ $path = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf());
+ $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
+
+ $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare());
+
+ $expected = new \OC_OCS_Result(null, 404, 'public link sharing is disabled by the administrator');
+ $result = $this->ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareLinkNoPublicUpload() {
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK],
+ ['publicUpload', null, 'true'],
+ ]));
+
+ $path = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf());
+ $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
+
+ $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare());
+ $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
+
+ $expected = new \OC_OCS_Result(null, 403, 'public upload disabled by the administrator');
+ $result = $this->ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareLinkPublicUploadFile() {
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK],
+ ['publicUpload', null, 'true'],
+ ]));
+
+ $path = $this->getMock('\OCP\Files\File');
+ $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf());
+ $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
+
+ $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare());
+ $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $expected = new \OC_OCS_Result(null, 404, 'public upload is only possible for public shared folders');
+ $result = $this->ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareLinkPublicUploadFolder() {
+ $ocs = $this->mockFormatShare();
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK],
+ ['publicUpload', null, 'true'],
+ ['expireDate', '', ''],
+ ['password', '', ''],
+ ]));
+
+ $path = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf());
+ $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
+
+ $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare());
+ $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $this->shareManager->expects($this->once())->method('createShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) use ($path) {
+ return $share->getNode() === $path &&
+ $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
+ $share->getPermissions() === \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE &&
+ $share->getSharedBy() === 'currentUser' &&
+ $share->getPassword() === null &&
+ $share->getExpirationDate() === null;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareLinkPassword() {
+ $ocs = $this->mockFormatShare();
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK],
+ ['publicUpload', null, 'false'],
+ ['expireDate', '', ''],
+ ['password', '', 'password'],
+ ]));
+
+ $path = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf());
+ $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
+
+ $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare());
+ $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $this->shareManager->expects($this->once())->method('createShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) use ($path) {
+ return $share->getNode() === $path &&
+ $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
+ $share->getPermissions() === \OCP\Constants::PERMISSION_READ &&
+ $share->getSharedBy() === 'currentUser' &&
+ $share->getPassword() === 'password' &&
+ $share->getExpirationDate() === null;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareValidExpireDate() {
+ $ocs = $this->mockFormatShare();
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK],
+ ['publicUpload', null, 'false'],
+ ['expireDate', '', '2000-01-01'],
+ ['password', '', ''],
+ ]));
+
+ $path = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf());
+ $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
+
+ $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare());
+ $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $this->shareManager->expects($this->once())->method('createShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) use ($path) {
+ $date = new \DateTime('2000-01-01');
+ $date->setTime(0,0,0);
+
+ return $share->getNode() === $path &&
+ $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
+ $share->getPermissions() === \OCP\Constants::PERMISSION_READ &&
+ $share->getSharedBy() === 'currentUser' &&
+ $share->getPassword() === null &&
+ $share->getExpirationDate() == $date;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testCreateShareInvalidExpireDate() {
+ $ocs = $this->mockFormatShare();
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['path', null, 'valid-path'],
+ ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK],
+ ['publicUpload', null, 'false'],
+ ['expireDate', '', 'a1b2d3'],
+ ['password', '', ''],
+ ]));
+
+ $path = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf());
+ $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
+
+ $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare());
+ $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $expected = new \OC_OCS_Result(null, 404, 'Invalid Date. Format must be YYYY-MM-DD.');
+ $result = $ocs->createShare();
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateShareCantAccess() {
+ $share = \OC::$server->getShareManager()->newShare();
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+
+ $expected = new \OC_OCS_Result(null, 404, 'wrong share Id, share doesn\'t exist.');
+ $result = $this->ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateNoParametersLink() {
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK);
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+
+ $expected = new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given');
+ $result = $this->ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateNoParametersOther() {
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_GROUP);
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+
+ $expected = new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given');
+ $result = $this->ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkShareClear() {
+ $ocs = $this->mockFormatShare();
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setPassword('password')
+ ->setExpirationDate(new \DateTime())
+ ->setPermissions(\OCP\Constants::PERMISSION_ALL);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['publicUpload', null, 'false'],
+ ['expireDate', null, ''],
+ ['password', null, ''],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+
+ $this->shareManager->expects($this->once())->method('updateShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) {
+ return $share->getPermissions() === \OCP\Constants::PERMISSION_READ &&
+ $share->getPassword() === null &&
+ $share->getExpirationDate() === null;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkShareSet() {
+ $ocs = $this->mockFormatShare();
+
+ $folder = $this->getMock('\OCP\Files\Folder');
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setNode($folder);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['publicUpload', null, 'true'],
+ ['expireDate', null, '2000-01-01'],
+ ['password', null, 'password'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $this->shareManager->expects($this->once())->method('updateShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) {
+ $date = new \DateTime('2000-01-01');
+ $date->setTime(0,0,0);
+
+ return $share->getPermissions() === \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE && \OCP\Constants::PERMISSION_DELETE &&
+ $share->getPassword() === 'password' &&
+ $share->getExpirationDate() == $date;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkShareInvalidDate() {
+ $ocs = $this->mockFormatShare();
+
+ $folder = $this->getMock('\OCP\Files\Folder');
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setNode($folder);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['publicUpload', null, 'true'],
+ ['expireDate', null, '2000-01-a'],
+ ['password', null, 'password'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $expected = new \OC_OCS_Result(null, 400, 'Invalid date. Format must be YYYY-MM-DD');
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkSharePublicUploadNotAllowed() {
+ $ocs = $this->mockFormatShare();
+
+ $folder = $this->getMock('\OCP\Files\Folder');
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setNode($folder);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['publicUpload', null, 'true'],
+ ['expireDate', '', null],
+ ['password', '', 'password'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(false);
+
+ $expected = new \OC_OCS_Result(null, 403, 'public upload disabled by the administrator');
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkSharePublicUploadOnFile() {
+ $ocs = $this->mockFormatShare();
+
+ $file = $this->getMock('\OCP\Files\File');
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setNode($file);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['publicUpload', null, 'true'],
+ ['expireDate', '', ''],
+ ['password', '', 'password'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $expected = new \OC_OCS_Result(null, 400, 'public upload is only possible for public shared folders');
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkSharePasswordDoesNotChangeOther() {
+ $ocs = $this->mockFormatShare();
+
+ $date = new \DateTime('2000-01-01');
+ $date->setTime(0,0,0);
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setPassword('password')
+ ->setExpirationDate($date)
+ ->setPermissions(\OCP\Constants::PERMISSION_ALL);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['password', null, 'newpassword'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+
+ $this->shareManager->expects($this->once())->method('updateShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) use ($date) {
+ return $share->getPermissions() === \OCP\Constants::PERMISSION_ALL &&
+ $share->getPassword() === 'newpassword' &&
+ $share->getExpirationDate() === $date;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkShareExpireDateDoesNotChangeOther() {
+ $ocs = $this->mockFormatShare();
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setPassword('password')
+ ->setExpirationDate(new \DateTime())
+ ->setPermissions(\OCP\Constants::PERMISSION_ALL);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['expireDate', null, '2010-12-23'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+
+ $this->shareManager->expects($this->once())->method('updateShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) {
+ $date = new \DateTime('2010-12-23');
+ $date->setTime(0,0,0);
+
+ return $share->getPermissions() === \OCP\Constants::PERMISSION_ALL &&
+ $share->getPassword() === 'password' &&
+ $share->getExpirationDate() == $date;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkSharePublicUploadDoesNotChangeOther() {
+ $ocs = $this->mockFormatShare();
+
+ $date = new \DateTime('2000-01-01');
+
+ $folder = $this->getMock('\OCP\Files\Folder');
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setPassword('password')
+ ->setExpirationDate($date)
+ ->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setNode($folder);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['publicUpload', null, 'true'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $this->shareManager->expects($this->once())->method('updateShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) use ($date) {
+ return $share->getPermissions() === \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE &&
+ $share->getPassword() === 'password' &&
+ $share->getExpirationDate() === $date;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkSharePermissions() {
+ $ocs = $this->mockFormatShare();
+
+ $date = new \DateTime('2000-01-01');
+
+ $folder = $this->getMock('\OCP\Files\Folder');
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setPassword('password')
+ ->setExpirationDate($date)
+ ->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setNode($folder);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['permissions', null, '7'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $this->shareManager->expects($this->once())->method('updateShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) use ($date) {
+ return $share->getPermissions() === \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE &&
+ $share->getPassword() === 'password' &&
+ $share->getExpirationDate() === $date;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateLinkShareInvalidPermissions() {
+ $ocs = $this->mockFormatShare();
+
+ $date = new \DateTime('2000-01-01');
+
+ $folder = $this->getMock('\OCP\Files\Folder');
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setPassword('password')
+ ->setExpirationDate($date)
+ ->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setNode($folder);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['permissions', null, '31'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $expected = new \OC_OCS_Result(null, 400, 'can\'t change permission for public link share');
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
+
+ public function testUpdateOtherPermissions() {
+ $ocs = $this->mockFormatShare();
+
+ $file = $this->getMock('\OCP\Files\File');
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setSharedBy($this->currentUser->getUID())
+ ->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setNode($file);
+
+ $this->request
+ ->method('getParam')
+ ->will($this->returnValueMap([
+ ['permissions', null, '31'],
+ ]));
+
+ $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
+ $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
+
+ $this->shareManager->expects($this->once())->method('updateShare')->with(
+ $this->callback(function (\OCP\Share\IShare $share) {
+ return $share->getPermissions() === \OCP\Constants::PERMISSION_ALL;
+ })
+ )->will($this->returnArgument(0));
+
+ $expected = new \OC_OCS_Result(null);
+ $result = $ocs->updateShare(42);
+
+ $this->assertEquals($expected->getMeta(), $result->getMeta());
+ $this->assertEquals($expected->getData(), $result->getData());
+ }
}
diff --git a/apps/files_sharing/tests/api/shareestest.php b/apps/files_sharing/tests/api/shareestest.php
index 8a35350aeb5..4b8034a48b7 100644
--- a/apps/files_sharing/tests/api/shareestest.php
+++ b/apps/files_sharing/tests/api/shareestest.php
@@ -2,8 +2,10 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,6 +29,13 @@ use OCA\Files_sharing\Tests\TestCase;
use OCP\AppFramework\Http;
use OCP\Share;
+/**
+ * Class ShareesTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files_Sharing\Tests\API
+ */
class ShareesTest extends TestCase {
/** @var Sharees */
protected $sharees;
@@ -81,6 +90,11 @@ class ShareesTest extends TestCase {
);
}
+ /**
+ * @param string $uid
+ * @param string $displayName
+ * @return \OCP\IUser|\PHPUnit_Framework_MockObject_MockObject
+ */
protected function getUserMock($uid, $displayName) {
$user = $this->getMockBuilder('OCP\IUser')
->disableOriginalConstructor()
@@ -97,6 +111,10 @@ class ShareesTest extends TestCase {
return $user;
}
+ /**
+ * @param string $gid
+ * @return \OCP\IGroup|\PHPUnit_Framework_MockObject_MockObject
+ */
protected function getGroupMock($gid) {
$group = $this->getMockBuilder('OCP\IGroup')
->disableOriginalConstructor()
@@ -129,12 +147,20 @@ class ShareesTest extends TestCase {
],
[
'test', true, true, [], [],
+ [], [], true, $this->getUserMock('test', 'Test')
+ ],
+ [
+ 'test', true, false, [], [],
+ [], [], true, $this->getUserMock('test', 'Test')
+ ],
+ [
+ 'test', true, true, ['test-group'], [['test-group', 'test', 2, 0, []]],
[
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
], [], true, $this->getUserMock('test', 'Test')
],
[
- 'test', true, false, [], [],
+ 'test', true, false, ['test-group'], [['test-group', 'test', 2, 0, []]],
[
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
], [], true, $this->getUserMock('test', 'Test')
@@ -383,10 +409,20 @@ class ShareesTest extends TestCase {
->with($searchTerm, $this->invokePrivate($this->sharees, 'limit'), $this->invokePrivate($this->sharees, 'offset'))
->willReturn($userResponse);
} else {
- $this->groupManager->expects($this->once())
- ->method('getUserGroupIds')
- ->with($user)
- ->willReturn($groupResponse);
+ if ($singleUser !== false) {
+ $this->groupManager->expects($this->exactly(2))
+ ->method('getUserGroupIds')
+ ->withConsecutive(
+ $user,
+ $singleUser
+ )
+ ->willReturn($groupResponse);
+ } else {
+ $this->groupManager->expects($this->once())
+ ->method('getUserGroupIds')
+ ->with($user)
+ ->willReturn($groupResponse);
+ }
$this->groupManager->expects($this->exactly(sizeof($groupResponse)))
->method('displayNamesInGroup')
@@ -1009,6 +1045,10 @@ class ShareesTest extends TestCase {
[[], 'no', 'yes', true, '', null, $allTypes, 1, 200, false, true],
[[], 'no', 'no', true, '', null, $allTypes, 1, 200, false, false],
+ // Test keep case for search
+ [[
+ 'search' => 'foo@example.com/ownCloud',
+ ], '', 'yes', true, 'foo@example.com/ownCloud', null, $allTypes, 1, 200, false, true],
];
}
diff --git a/apps/files_sharing/tests/backend.php b/apps/files_sharing/tests/backend.php
index 1332342c44b..acb59855394 100644
--- a/apps/files_sharing/tests/backend.php
+++ b/apps/files_sharing/tests/backend.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,6 +27,8 @@ use OCA\Files_sharing\Tests\TestCase;
/**
* Class Test_Files_Sharing
+ *
+ * @group DB
*/
class Test_Files_Sharing_Backend extends TestCase {
@@ -56,8 +58,10 @@ class Test_Files_Sharing_Backend extends TestCase {
}
protected function tearDown() {
- $this->view->unlink($this->filename);
- $this->view->deleteAll($this->folder);
+ if ($this->view) {
+ $this->view->unlink($this->filename);
+ $this->view->deleteAll($this->folder);
+ }
parent::tearDown();
}
diff --git a/apps/files_sharing/tests/cache.php b/apps/files_sharing/tests/cache.php
index 7e7e5ee26d5..c137ba0728d 100644
--- a/apps/files_sharing/tests/cache.php
+++ b/apps/files_sharing/tests/cache.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -47,6 +47,12 @@ use OCA\Files_sharing\Tests\TestCase;
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
+
+/**
+ * Class Test_Files_Sharing_Cache
+ *
+ * @group DB
+ */
class Test_Files_Sharing_Cache extends TestCase {
/**
diff --git a/apps/files_sharing/tests/capabilities.php b/apps/files_sharing/tests/capabilities.php
index 8bebde9f2d1..7572f5c84aa 100644
--- a/apps/files_sharing/tests/capabilities.php
+++ b/apps/files_sharing/tests/capabilities.php
@@ -2,8 +2,9 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +27,8 @@ use OCA\Files_Sharing\Tests\TestCase;
/**
* Class FilesSharingCapabilitiesTest
+ *
+ * @group DB
*/
class FilesSharingCapabilitiesTest extends \Test\TestCase {
diff --git a/apps/files_sharing/tests/controller/externalsharecontroller.php b/apps/files_sharing/tests/controller/externalsharecontroller.php
index 4913c7308ba..ab5f1c153f3 100644
--- a/apps/files_sharing/tests/controller/externalsharecontroller.php
+++ b/apps/files_sharing/tests/controller/externalsharecontroller.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/tests/controller/sharecontroller.php b/apps/files_sharing/tests/controller/sharecontroller.php
index db5eb75d761..22e15972cd6 100644
--- a/apps/files_sharing/tests/controller/sharecontroller.php
+++ b/apps/files_sharing/tests/controller/sharecontroller.php
@@ -1,13 +1,16 @@
<?php
/**
+ * @author Björn Schießle <schiessle@owncloud.com>
* @author Georg Ehrke <georg@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Cloutier <vincent1cloutier@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,76 +30,86 @@
namespace OCA\Files_Sharing\Controllers;
use OC\Files\Filesystem;
-use OCA\Files_Sharing\AppInfo\Application;
+use OCP\Share\Exceptions\ShareNotFound;
use OCP\AppFramework\Http\NotFoundResponse;
-use OCP\AppFramework\IAppContainer;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse;
+use OCP\ISession;
+use OCP\IUserManager;
use OCP\Security\ISecureRandom;
-use OC\Files\View;
-use OCP\Share;
-use OC\URLGenerator;
+use OCP\IURLGenerator;
/**
+ * @group DB
+ *
* @package OCA\Files_Sharing\Controllers
*/
class ShareControllerTest extends \Test\TestCase {
- /** @var IAppContainer */
- private $container;
/** @var string */
private $user;
/** @var string */
- private $token;
- /** @var string */
private $oldUser;
+
+ /** @var string */
+ private $appName = 'files_sharing';
/** @var ShareController */
private $shareController;
- /** @var URLGenerator */
+ /** @var IURLGenerator | \PHPUnit_Framework_MockObject_MockObject */
private $urlGenerator;
+ /** @var ISession | \PHPUnit_Framework_MockObject_MockObject */
+ private $session;
+ /** @var \OCP\IPreview | \PHPUnit_Framework_MockObject_MockObject */
+ private $previewManager;
+ /** @var \OCP\IConfig | \PHPUnit_Framework_MockObject_MockObject */
+ private $config;
+ /** @var \OC\Share20\Manager | \PHPUnit_Framework_MockObject_MockObject */
+ private $shareManager;
+ /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */
+ private $userManager;
protected function setUp() {
- $app = new Application();
- $this->container = $app->getContainer();
- $this->container['Config'] = $this->getMockBuilder('\OCP\IConfig')
- ->disableOriginalConstructor()->getMock();
- $this->container['AppName'] = 'files_sharing';
- $this->container['UserSession'] = $this->getMockBuilder('\OC\User\Session')
- ->disableOriginalConstructor()->getMock();
- $this->container['URLGenerator'] = $this->getMockBuilder('\OC\URLGenerator')
- ->disableOriginalConstructor()->getMock();
- $this->container['UserManager'] = $this->getMockBuilder('\OCP\IUserManager')
- ->disableOriginalConstructor()->getMock();
- $this->urlGenerator = $this->container['URLGenerator'];
- $this->shareController = $this->container['ShareController'];
+ $this->appName = 'files_sharing';
+
+ $this->shareManager = $this->getMockBuilder('\OC\Share20\Manager')->disableOriginalConstructor()->getMock();
+ $this->urlGenerator = $this->getMock('\OCP\IURLGenerator');
+ $this->session = $this->getMock('\OCP\ISession');
+ $this->previewManager = $this->getMock('\OCP\IPreview');
+ $this->config = $this->getMock('\OCP\IConfig');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+
+ $this->shareController = new \OCA\Files_Sharing\Controllers\ShareController(
+ $this->appName,
+ $this->getMock('\OCP\IRequest'),
+ $this->config,
+ $this->urlGenerator,
+ $this->userManager,
+ $this->getMock('\OCP\ILogger'),
+ $this->getMock('\OCP\Activity\IManager'),
+ $this->shareManager,
+ $this->session,
+ $this->previewManager,
+ $this->getMock('\OCP\Files\IRootFolder')
+ );
+
// Store current user
$this->oldUser = \OC_User::getUser();
// Create a dummy user
- $this->user = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(12, ISecureRandom::CHAR_LOWER);
+ $this->user = \OC::$server->getSecureRandom()->generate(12, ISecureRandom::CHAR_LOWER);
- \OC_User::createUser($this->user, $this->user);
+ \OC::$server->getUserManager()->createUser($this->user, $this->user);
\OC_Util::tearDownFS();
$this->loginAsUser($this->user);
-
- // Create a dummy shared file
- $view = new View('/'. $this->user . '/files');
- $view->file_put_contents('file1.txt', 'I am such an awesome shared file!');
- $this->token = \OCP\Share::shareItem(
- Filesystem::getFileInfo('file1.txt')->getType(),
- Filesystem::getFileInfo('file1.txt')->getId(),
- \OCP\Share::SHARE_TYPE_LINK,
- 'IAmPasswordProtected!',
- 1
- );
}
protected function tearDown() {
\OC_Util::tearDownFS();
\OC_User::setUserId('');
Filesystem::tearDown();
- \OC_User::deleteUser($this->user);
+ $user = \OC::$server->getUserManager()->get($this->user);
+ if ($user !== null) { $user->delete(); }
\OC_User::setIncognitoMode(false);
\OC::$server->getSession()->set('public_link_authenticated', '');
@@ -106,71 +119,213 @@ class ShareControllerTest extends \Test\TestCase {
\OC_Util::setupFS($this->oldUser);
}
- public function testShowAuthenticate() {
- $linkItem = \OCP\Share::getShareByToken($this->token, false);
+ public function testShowAuthenticateNotAuthenticated() {
+ $share = \OC::$server->getShareManager()->newShare();
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
+ ->willReturn($share);
- // Test without being authenticated
- $response = $this->shareController->showAuthenticate($this->token);
- $expectedResponse = new TemplateResponse($this->container['AppName'], 'authenticate', array(), 'guest');
+ $response = $this->shareController->showAuthenticate('token');
+ $expectedResponse = new TemplateResponse($this->appName, 'authenticate', [], 'guest');
$this->assertEquals($expectedResponse, $response);
+ }
+
+ public function testShowAuthenticateAuthenticatedForDifferentShare() {
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setId(1);
- // Test with being authenticated for another file
- \OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']-1);
- $response = $this->shareController->showAuthenticate($this->token);
- $expectedResponse = new TemplateResponse($this->container['AppName'], 'authenticate', array(), 'guest');
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
+ ->willReturn($share);
+
+ $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
+ $this->session->method('get')->with('public_link_authenticated')->willReturn('2');
+
+ $response = $this->shareController->showAuthenticate('token');
+ $expectedResponse = new TemplateResponse($this->appName, 'authenticate', [], 'guest');
$this->assertEquals($expectedResponse, $response);
+ }
+
+ public function testShowAuthenticateCorrectShare() {
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setId(1);
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
+ ->willReturn($share);
+
+ $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
+ $this->session->method('get')->with('public_link_authenticated')->willReturn('1');
- // Test with being authenticated for the correct file
- \OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
- $response = $this->shareController->showAuthenticate($this->token);
- $expectedResponse = new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $this->token)));
+ $this->urlGenerator->expects($this->once())
+ ->method('linkToRoute')
+ ->with('files_sharing.sharecontroller.showShare', ['token' => 'token'])
+ ->willReturn('redirect');
+
+ $response = $this->shareController->showAuthenticate('token');
+ $expectedResponse = new RedirectResponse('redirect');
$this->assertEquals($expectedResponse, $response);
}
- public function testAuthenticate() {
- // Test without a not existing token
- $response = $this->shareController->authenticate('ThisTokenShouldHopefullyNeverExistSoThatTheUnitTestWillAlwaysPass :)');
+ public function testAutehnticateInvalidToken() {
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
+ ->will($this->throwException(new \OCP\Share\Exceptions\ShareNotFound()));
+
+ $response = $this->shareController->authenticate('token');
$expectedResponse = new NotFoundResponse();
$this->assertEquals($expectedResponse, $response);
+ }
- // Test with a valid password
- $response = $this->shareController->authenticate($this->token, 'IAmPasswordProtected!');
- $expectedResponse = new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $this->token)));
+ public function testAuthenticateValidPassword() {
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setId(42);
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
+ ->willReturn($share);
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('checkPassword')
+ ->with($share, 'validpassword')
+ ->willReturn(true);
+
+ $this->session
+ ->expects($this->once())
+ ->method('set')
+ ->with('public_link_authenticated', '42');
+
+ $this->urlGenerator->expects($this->once())
+ ->method('linkToRoute')
+ ->with('files_sharing.sharecontroller.showShare', ['token'=>'token'])
+ ->willReturn('redirect');
+
+ $response = $this->shareController->authenticate('token', 'validpassword');
+ $expectedResponse = new RedirectResponse('redirect');
$this->assertEquals($expectedResponse, $response);
+ }
- // Test with a invalid password
- $response = $this->shareController->authenticate($this->token, 'WrongPw!');
- $expectedResponse = new TemplateResponse($this->container['AppName'], 'authenticate', array('wrongpw' => true), 'guest');
+ public function testAuthenticateInvalidPassword() {
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setId(42);
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
+ ->willReturn($share);
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('checkPassword')
+ ->with($share, 'invalidpassword')
+ ->willReturn(false);
+
+ $this->session
+ ->expects($this->never())
+ ->method('set');
+
+ $response = $this->shareController->authenticate('token', 'invalidpassword');
+ $expectedResponse = new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest');
$this->assertEquals($expectedResponse, $response);
}
- public function testShowShare() {
- $this->container['UserManager']->expects($this->exactly(2))
- ->method('userExists')
- ->with($this->user)
- ->will($this->returnValue(true));
+ public function testShowShareInvalidToken() {
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('invalidtoken')
+ ->will($this->throwException(new ShareNotFound()));
// Test without a not existing token
- $response = $this->shareController->showShare('ThisTokenShouldHopefullyNeverExistSoThatTheUnitTestWillAlwaysPass :)');
+ $response = $this->shareController->showShare('invalidtoken');
$expectedResponse = new NotFoundResponse();
$this->assertEquals($expectedResponse, $response);
+ }
- // Test with a password protected share and no authentication
- $response = $this->shareController->showShare($this->token);
- $expectedResponse = new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate', array('token' => $this->token)));
+ public function testShowShareNotAuthenticated() {
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setPassword('password');
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('validtoken')
+ ->willReturn($share);
+
+ $this->urlGenerator->expects($this->once())
+ ->method('linkToRoute')
+ ->with('files_sharing.sharecontroller.authenticate', ['token' => 'validtoken'])
+ ->willReturn('redirect');
+
+ // Test without a not existing token
+ $response = $this->shareController->showShare('validtoken');
+ $expectedResponse = new RedirectResponse('redirect');
$this->assertEquals($expectedResponse, $response);
+ }
+
- // Test with password protected share and authentication
- $linkItem = Share::getShareByToken($this->token, false);
- \OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
- $response = $this->shareController->showShare($this->token);
+ public function testShowShare() {
+ $owner = $this->getMock('OCP\IUser');
+ $owner->method('getDisplayName')->willReturn('ownerDisplay');
+ $owner->method('getUID')->willReturn('ownerUID');
+
+ $file = $this->getMock('OCP\Files\File');
+ $file->method('getName')->willReturn('file1.txt');
+ $file->method('getMimetype')->willReturn('text/plain');
+ $file->method('getSize')->willReturn(33);
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setId(42);
+ $share->setPassword('password')
+ ->setShareOwner('ownerUID')
+ ->setNode($file)
+ ->setTarget('/file1.txt');
+
+ $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
+ $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
+
+ $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
+
+ $this->config->method('getSystemValue')
+ ->willReturnMap(
+ [
+ ['max_filesize_animated_gifs_public_sharing', 10, 10],
+ ['enable_previews', true, true],
+ ]
+ );
+ $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
+ $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
+ ->willReturn($share);
+
+ $this->userManager->method('get')->with('ownerUID')->willReturn($owner);
+
+ $response = $this->shareController->showShare('token');
$sharedTmplParams = array(
- 'displayName' => $this->user,
+ 'displayName' => 'ownerDisplay',
+ 'owner' => 'ownerUID',
'filename' => 'file1.txt',
'directory_path' => '/file1.txt',
'mimetype' => 'text/plain',
- 'dirToken' => $this->token,
- 'sharingToken' => $this->token,
+ 'dirToken' => 'token',
+ 'sharingToken' => 'token',
'server2serversharing' => true,
'protected' => 'true',
'dir' => '',
@@ -184,65 +339,31 @@ class ShareControllerTest extends \Test\TestCase {
$csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
$csp->addAllowedFrameDomain('\'self\'');
- $expectedResponse = new TemplateResponse($this->container['AppName'], 'public', $sharedTmplParams, 'base');
+ $expectedResponse = new TemplateResponse($this->appName, 'public', $sharedTmplParams, 'base');
$expectedResponse->setContentSecurityPolicy($csp);
$this->assertEquals($expectedResponse, $response);
}
public function testDownloadShare() {
- // Test with a password protected share and no authentication
- $response = $this->shareController->downloadShare($this->token);
- $expectedResponse = new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
- array('token' => $this->token)));
- $this->assertEquals($expectedResponse, $response);
- }
+ $share = $this->getMock('\OCP\Share\IShare');
+ $share->method('getPassword')->willReturn('password');
- /**
- * @expectedException \OCP\Files\NotFoundException
- */
- public function testShowShareWithDeletedFile() {
- $this->container['UserManager']->expects($this->once())
- ->method('userExists')
- ->with($this->user)
- ->will($this->returnValue(true));
-
- $view = new View('/'. $this->user . '/files');
- $view->unlink('file1.txt');
- $linkItem = Share::getShareByToken($this->token, false);
- \OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
- $this->shareController->showShare($this->token);
- }
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareByToken')
+ ->with('validtoken')
+ ->willReturn($share);
- /**
- * @expectedException \OCP\Files\NotFoundException
- */
- public function testDownloadShareWithDeletedFile() {
- $this->container['UserManager']->expects($this->once())
- ->method('userExists')
- ->with($this->user)
- ->will($this->returnValue(true));
-
- $view = new View('/'. $this->user . '/files');
- $view->unlink('file1.txt');
- $linkItem = Share::getShareByToken($this->token, false);
- \OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
- $this->shareController->downloadShare($this->token);
- }
+ $this->urlGenerator->expects($this->once())
+ ->method('linkToRoute')
+ ->with('files_sharing.sharecontroller.authenticate', ['token' => 'validtoken'])
+ ->willReturn('redirect');
- /**
- * @expectedException \Exception
- * @expectedExceptionMessage Owner of the share does not exist anymore
- */
- public function testShowShareWithNotExistingUser() {
- $this->container['UserManager']->expects($this->once())
- ->method('userExists')
- ->with($this->user)
- ->will($this->returnValue(false));
-
- $linkItem = Share::getShareByToken($this->token, false);
- \OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
- $this->shareController->showShare($this->token);
+ // Test with a password protected share and no authentication
+ $response = $this->shareController->downloadShare('validtoken');
+ $expectedResponse = new RedirectResponse('redirect');
+ $this->assertEquals($expectedResponse, $response);
}
}
diff --git a/apps/files_sharing/tests/deleteorphanedsharesjobtest.php b/apps/files_sharing/tests/deleteorphanedsharesjobtest.php
index 124cb83e6f0..353520bd604 100644
--- a/apps/files_sharing/tests/deleteorphanedsharesjobtest.php
+++ b/apps/files_sharing/tests/deleteorphanedsharesjobtest.php
@@ -1,8 +1,9 @@
<?php
/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +24,13 @@ namespace Test\BackgroundJob;
use OCA\Files_sharing\Lib\DeleteOrphanedSharesJob;
+/**
+ * Class DeleteOrphanedSharesJobTest
+ *
+ * @group DB
+ *
+ * @package Test\BackgroundJob
+ */
class DeleteOrphanedSharesJobTest extends \Test\TestCase {
/**
diff --git a/apps/files_sharing/tests/etagpropagation.php b/apps/files_sharing/tests/etagpropagation.php
index 1abf04df84f..55972dd9221 100644
--- a/apps/files_sharing/tests/etagpropagation.php
+++ b/apps/files_sharing/tests/etagpropagation.php
@@ -3,9 +3,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,31 +28,14 @@ namespace OCA\Files_sharing\Tests;
use OC\Files\Filesystem;
use OC\Files\View;
-class EtagPropagation extends TestCase {
- /**
- * @var \OC\Files\View
- */
- private $rootView;
- protected $fileIds = []; // [$user=>[$path=>$id]]
- protected $fileEtags = []; // [$id=>$etag]
-
- public static function setUpBeforeClass() {
- parent::setUpBeforeClass();
- \OCA\Files_Sharing\Helper::registerHooks();
- }
-
- protected function setUp() {
- parent::setUp();
- $this->setUpShares();
- }
-
- protected function tearDown() {
- \OC_Hook::clear('OC_Filesystem', 'post_write');
- \OC_Hook::clear('OC_Filesystem', 'post_delete');
- \OC_Hook::clear('OC_Filesystem', 'post_rename');
- \OC_Hook::clear('OCP\Share', 'post_update_permissions');
- parent::tearDown();
- }
+/**
+ * Class EtagPropagation
+ *
+ * @group DB
+ *
+ * @package OCA\Files_sharing\Tests
+ */
+class EtagPropagation extends PropagationTestCase {
/**
* "user1" is the admin who shares a folder "sub1/sub2/folder" with "user2" and "user3"
@@ -60,7 +44,7 @@ class EtagPropagation extends TestCase {
* "user2" reshares the subdir "sub1/sub2/folder/inside" with "user4"
* "user4" puts the received "inside" folder into "sub1/sub2/inside" (this is to check if it propagates across multiple subfolders)
*/
- private function setUpShares() {
+ protected function setUpShares() {
$this->fileIds[self::TEST_FILES_SHARING_API_USER1] = [];
$this->fileIds[self::TEST_FILES_SHARING_API_USER2] = [];
$this->fileIds[self::TEST_FILES_SHARING_API_USER3] = [];
@@ -129,58 +113,6 @@ class EtagPropagation extends TestCase {
}
}
- /**
- * @param string[] $users
- * @param string $subPath
- */
- private function assertEtagsChanged($users, $subPath = '') {
- $oldUser = \OC::$server->getUserSession()->getUser();
- foreach ($users as $user) {
- $this->loginAsUser($user);
- $id = $this->fileIds[$user][$subPath];
- $path = $this->rootView->getPath($id);
- $etag = $this->rootView->getFileInfo($path)->getEtag();
- $this->assertNotEquals($this->fileEtags[$id], $etag, 'Failed asserting that the etag for "' . $subPath . '" of user ' . $user . ' has changed');
- $this->fileEtags[$id] = $etag;
- }
- $this->loginAsUser($oldUser->getUID());
- }
-
- /**
- * @param string[] $users
- * @param string $subPath
- */
- private function assertEtagsNotChanged($users, $subPath = '') {
- $oldUser = \OC::$server->getUserSession()->getUser();
- foreach ($users as $user) {
- $this->loginAsUser($user);
- $id = $this->fileIds[$user][$subPath];
- $path = $this->rootView->getPath($id);
- $etag = $this->rootView->getFileInfo($path)->getEtag();
- $this->assertEquals($this->fileEtags[$id], $etag, 'Failed asserting that the etag for "' . $subPath . '" of user ' . $user . ' has not changed');
- $this->fileEtags[$id] = $etag;
- }
- $this->loginAsUser($oldUser->getUID());
- }
-
- /**
- * Assert that the etags for the root, /sub1 and /sub1/sub2 have changed
- *
- * @param string[] $users
- */
- private function assertEtagsForFoldersChanged($users) {
- $this->assertEtagsChanged($users);
-
- $this->assertEtagsChanged($users, 'sub1');
- $this->assertEtagsChanged($users, 'sub1/sub2');
- }
-
- private function assertAllUnchanged() {
- $users = [self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2,
- self::TEST_FILES_SHARING_API_USER3, self::TEST_FILES_SHARING_API_USER4];
- $this->assertEtagsNotChanged($users);
- }
-
public function testOwnerWritesToShare() {
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER1);
Filesystem::file_put_contents('/sub1/sub2/folder/asd.txt', 'bar');
@@ -193,7 +125,8 @@ class EtagPropagation extends TestCase {
public function testOwnerWritesToSingleFileShare() {
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER1);
- Filesystem::file_put_contents('/foo.txt', 'bar');
+ Filesystem::file_put_contents('/foo.txt', 'longer_bar');
+ Filesystem::touch('/foo.txt', time() - 1);
$this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER4, self::TEST_FILES_SHARING_API_USER3]);
$this->assertEtagsChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2]);
diff --git a/apps/files_sharing/tests/expiresharesjobtest.php b/apps/files_sharing/tests/expiresharesjobtest.php
index 63a2c46f647..bb4f756e6c7 100644
--- a/apps/files_sharing/tests/expiresharesjobtest.php
+++ b/apps/files_sharing/tests/expiresharesjobtest.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +24,13 @@ namespace OCA\Files_Sharing\Tests;
use OCA\Files_Sharing\ExpireSharesJob;
+/**
+ * Class ExpireSharesJobTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files_Sharing\Tests
+ */
class ExpireSharesJobTest extends \Test\TestCase {
/**
diff --git a/apps/files_sharing/tests/external/cache.php b/apps/files_sharing/tests/external/cache.php
index aa3839899ce..3e078bf3722 100644
--- a/apps/files_sharing/tests/external/cache.php
+++ b/apps/files_sharing/tests/external/cache.php
@@ -1,8 +1,9 @@
<?php
/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,24 +24,11 @@ namespace OCA\Files_sharing\Tests\External;
use OCA\Files_sharing\Tests\TestCase;
/**
- * ownCloud
+ * Class Cache
*
- * @author Vincent Petry
- * @copyright 2015 Vincent Petry <pvince81@owncloud.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ * @group DB
*
+ * @package OCA\Files_sharing\Tests\External
*/
class Cache extends TestCase {
@@ -87,7 +75,9 @@ class Cache extends TestCase {
}
protected function tearDown() {
- $this->cache->clear();
+ if ($this->cache) {
+ $this->cache->clear();
+ }
parent::tearDown();
}
diff --git a/apps/files_sharing/tests/external/managertest.php b/apps/files_sharing/tests/external/managertest.php
index 5b93b7494e9..f73fedaf05c 100644
--- a/apps/files_sharing/tests/external/managertest.php
+++ b/apps/files_sharing/tests/external/managertest.php
@@ -2,8 +2,9 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,6 +29,13 @@ use OCA\Files_Sharing\External\MountProvider;
use OCA\Files_Sharing\Tests\TestCase;
use Test\Traits\UserTrait;
+/**
+ * Class ManagerTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files_Sharing\Tests\External
+ */
class ManagerTest extends TestCase {
use UserTrait;
diff --git a/apps/files_sharing/tests/external/scannertest.php b/apps/files_sharing/tests/external/scannertest.php
index 43f33905608..f16e9952fce 100644
--- a/apps/files_sharing/tests/external/scannertest.php
+++ b/apps/files_sharing/tests/external/scannertest.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/tests/externalstorage.php b/apps/files_sharing/tests/externalstorage.php
index a549e093dc1..54cd7d1645c 100644
--- a/apps/files_sharing/tests/externalstorage.php
+++ b/apps/files_sharing/tests/externalstorage.php
@@ -3,9 +3,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,8 @@
/**
* Tests for the external Storage class for remote shares.
+ *
+ * @group DB
*/
class Test_Files_Sharing_External_Storage extends \Test\TestCase {
diff --git a/apps/files_sharing/tests/groupetagpropagation.php b/apps/files_sharing/tests/groupetagpropagation.php
new file mode 100644
index 00000000000..9f6b1e2f720
--- /dev/null
+++ b/apps/files_sharing/tests/groupetagpropagation.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_sharing\Tests;
+
+use OC\Files\Filesystem;
+use OC\Files\View;
+
+/**
+ * @group DB
+ *
+ * @package OCA\Files_sharing\Tests
+ */
+class GroupEtagPropagation extends PropagationTestCase {
+ /**
+ * "user1" creates /test, /test/sub and shares with group1
+ * "user2" (in group1) reshares /test with group2 and reshared /test/sub with group3
+ * "user3" (in group 2)
+ * "user4" (in group 3)
+ */
+ protected function setUpShares() {
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER1] = [];
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER2] = [];
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER3] = [];
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER4] = [];
+
+ $this->rootView = new View('');
+ $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1);
+ $view1 = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
+ $view1->mkdir('/test/sub');
+ $folderInfo = $view1->getFileInfo('/test');
+ \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_GROUP, 'group1', 31);
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER1][''] = $view1->getFileInfo('')->getId();
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER1]['test'] = $view1->getFileInfo('test')->getId();
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER1]['test/sub'] = $view1->getFileInfo('test/sub')->getId();
+
+ $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
+ $view2 = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
+ $folderInfo = $view2->getFileInfo('/test');
+ $subFolderInfo = $view2->getFileInfo('/test/sub');
+ \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_GROUP, 'group2', 31);
+ \OCP\Share::shareItem('folder', $subFolderInfo->getId(), \OCP\Share::SHARE_TYPE_GROUP, 'group3', 31);
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER2][''] = $view2->getFileInfo('')->getId();
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER2]['test'] = $view2->getFileInfo('test')->getId();
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER2]['test/sub'] = $view2->getFileInfo('test/sub')->getId();
+
+ $this->loginAsUser(self::TEST_FILES_SHARING_API_USER3);
+ $view3 = new View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files');
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER3][''] = $view3->getFileInfo('')->getId();
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER3]['test'] = $view3->getFileInfo('test')->getId();
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER3]['test/sub'] = $view3->getFileInfo('test/sub')->getId();
+
+ $this->loginAsUser(self::TEST_FILES_SHARING_API_USER4);
+ $view4 = new View('/' . self::TEST_FILES_SHARING_API_USER4 . '/files');
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER4][''] = $view4->getFileInfo('')->getId();
+ $this->fileIds[self::TEST_FILES_SHARING_API_USER4]['sub'] = $view4->getFileInfo('sub')->getId();
+
+ foreach ($this->fileIds as $user => $ids) {
+ $this->loginAsUser($user);
+ foreach ($ids as $id) {
+ $path = $this->rootView->getPath($id);
+ $this->fileEtags[$id] = $this->rootView->getFileInfo($path)->getEtag();
+ }
+ }
+ }
+
+ public function testGroupReShareRecipientWrites() {
+ $this->loginAsUser(self::TEST_FILES_SHARING_API_USER3);
+
+ Filesystem::file_put_contents('/test/sub/file.txt', 'asd');
+
+ $this->assertEtagsChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER3, self::TEST_FILES_SHARING_API_USER4]);
+
+ $this->assertAllUnchanged();
+ }
+
+ public function testGroupReShareSubFolderRecipientWrites() {
+ $this->loginAsUser(self::TEST_FILES_SHARING_API_USER4);
+
+ Filesystem::file_put_contents('/sub/file.txt', 'asd');
+
+ $this->assertEtagsChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER3, self::TEST_FILES_SHARING_API_USER4]);
+
+ $this->assertAllUnchanged();
+ }
+}
diff --git a/apps/files_sharing/tests/grouppropagationmanager.php b/apps/files_sharing/tests/grouppropagationmanager.php
deleted file mode 100644
index ea32ca4f7ec..00000000000
--- a/apps/files_sharing/tests/grouppropagationmanager.php
+++ /dev/null
@@ -1,173 +0,0 @@
-<?php
-/**
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_sharing\Tests;
-
-use OC\Files\View;
-use OCP\IGroupManager;
-use OCP\IGroup;
-use OCP\IUser;
-use OCP\Share;
-use OCA\Files_Sharing\Propagation\GroupPropagationManager;
-use OCA\Files_Sharing\Propagation\PropagationManager;
-
-class GroupPropagationManagerTest extends TestCase {
-
- /**
- * @var GroupPropagationManager
- */
- private $groupPropagationManager;
-
- /**
- * @var IGroupManager
- */
- private $groupManager;
-
- /**
- * @var PropagationManager
- */
- private $propagationManager;
-
- /**
- * @var IGroup
- */
- private $recipientGroup;
-
- /**
- * @var IUser
- */
- private $recipientUser;
-
- /**
- * @var array
- */
- private $fileInfo;
-
- protected function setUp() {
- parent::setUp();
-
- $user = $this->getMockBuilder('\OCP\IUser')
- ->disableOriginalConstructor()
- ->getMock();
- $user->method('getUID')->willReturn(self::TEST_FILES_SHARING_API_USER1);
- $userSession = $this->getMockBuilder('\OCP\IUserSession')
- ->disableOriginalConstructor()
- ->getMock();
- $userSession->method('getUser')->willReturn(selF::TEST_FILES_SHARING_API_USER1);
-
- $this->propagationManager = $this->getMockBuilder('OCA\Files_Sharing\Propagation\PropagationManager')
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->groupManager = \OC::$server->getGroupManager();
- $this->groupPropagationManager = new GroupPropagationManager(
- $userSession,
- $this->groupManager,
- $this->propagationManager
- );
- $this->groupPropagationManager->globalSetup();
-
- // since the sharing code is not mockable, we have to create a real folder
- $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1);
- $view1 = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
- $view1->mkdir('/folder');
-
- $this->fileInfo = $view1->getFileInfo('/folder');
-
- $this->recipientGroup = $this->groupManager->get(self::TEST_FILES_SHARING_API_GROUP1);
- $this->recipientUser = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER3);
-
- Share::shareItem(
- 'folder',
- $this->fileInfo['fileid'],
- Share::SHARE_TYPE_GROUP,
- $this->recipientGroup->getGID(),
- \OCP\Constants::PERMISSION_READ
- );
-
- $this->loginAsUser($this->recipientUser->getUID());
- }
-
- protected function tearDown() {
- $this->groupPropagationManager->tearDown();
- $this->recipientGroup->removeUser($this->recipientUser);
- parent::tearDown();
- }
-
- public function testPropagateWhenAddedToGroup() {
- $this->propagationManager->expects($this->once())
- ->method('propagateSharesToUser')
- ->with($this->callback(function($shares) {
- if (count($shares) !== 1) {
- return false;
- }
- $share = array_values($shares)[0];
- return $share['file_source'] === $this->fileInfo['fileid'] &&
- $share['share_with'] === $this->recipientGroup->getGID() &&
- $share['file_target'] === '/folder';
- }), $this->recipientUser->getUID());
-
- $this->recipientGroup->addUser($this->recipientUser);
- }
-
- public function testPropagateWhenRemovedFromGroup() {
- $this->recipientGroup->addUser($this->recipientUser);
-
- $this->propagationManager->expects($this->once())
- ->method('propagateSharesToUser')
- ->with($this->callback(function($shares) {
- if (count($shares) !== 1) {
- return false;
- }
- $share = array_values($shares)[0];
- return $share['file_source'] === $this->fileInfo['fileid'] &&
- $share['share_with'] === $this->recipientGroup->getGID() &&
- $share['file_target'] === '/folder';
- }), $this->recipientUser->getUID());
-
- $this->recipientGroup->removeUser($this->recipientUser);
- }
-
- public function testPropagateWhenRemovedFromGroupWithSubdirTarget() {
- $this->recipientGroup->addUser($this->recipientUser);
-
- // relogin to refresh mount points
- $this->loginAsUser($this->recipientUser->getUID());
- $recipientView = new View('/' . $this->recipientUser->getUID() . '/files');
-
- $this->assertTrue($recipientView->mkdir('sub'));
- $this->assertTrue($recipientView->rename('folder', 'sub/folder'));
-
- $this->propagationManager->expects($this->once())
- ->method('propagateSharesToUser')
- ->with($this->callback(function($shares) {
- if (count($shares) !== 1) {
- return false;
- }
- $share = array_values($shares)[0];
- return $share['file_source'] === $this->fileInfo['fileid'] &&
- $share['share_with'] === $this->recipientGroup->getGID() &&
- $share['file_target'] === '/sub/folder';
- }), $this->recipientUser->getUID());
-
- $this->recipientGroup->removeUser($this->recipientUser);
- }
-}
diff --git a/apps/files_sharing/tests/helper.php b/apps/files_sharing/tests/helper.php
index 34a1389db77..07f07f911cb 100644
--- a/apps/files_sharing/tests/helper.php
+++ b/apps/files_sharing/tests/helper.php
@@ -1,11 +1,10 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
- * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,26 +23,10 @@
use OCA\Files_sharing\Tests\TestCase;
/**
- * ownCloud
- *
- * @author Bjoern Schiessle
- * @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ * Class Test_Files_Sharing_Helper
*
+ * @group DB
*/
-
class Test_Files_Sharing_Helper extends TestCase {
/**
diff --git a/apps/files_sharing/tests/js/externalSpec.js b/apps/files_sharing/tests/js/externalSpec.js
index 255f0fc3a48..362df49252b 100644
--- a/apps/files_sharing/tests/js/externalSpec.js
+++ b/apps/files_sharing/tests/js/externalSpec.js
@@ -67,6 +67,7 @@ describe('OCA.Sharing external tests', function() {
remote: 'http://example.com/owncloud',
token: 'abcdefg',
owner: 'theowner',
+ ownerDisplayName: 'The Generous Owner',
name: 'the share name'
};
});
@@ -88,6 +89,7 @@ describe('OCA.Sharing external tests', function() {
remote: 'http://example.com/owncloud',
token: 'abcdefg',
owner: 'theowner',
+ ownerDisplayName: 'The Generous Owner',
name: 'the share name',
password: ''
});
@@ -104,6 +106,7 @@ describe('OCA.Sharing external tests', function() {
remote: 'http://example.com/owncloud',
token: 'abcdefg',
owner: 'theowner',
+ ownerDisplayName: 'The Generous Owner',
name: 'the share name',
password: 'thepassword'
});
@@ -148,6 +151,7 @@ describe('OCA.Sharing external tests', function() {
remote: 'http://example.com/owncloud',
token: 'abcdefg',
owner: 'theowner',
+ ownerDisplayName: 'The Generous Owner',
name: 'the share name'
};
});
diff --git a/apps/files_sharing/tests/js/publicAppSpec.js b/apps/files_sharing/tests/js/publicAppSpec.js
index d496b78acfa..8561836d77c 100644
--- a/apps/files_sharing/tests/js/publicAppSpec.js
+++ b/apps/files_sharing/tests/js/publicAppSpec.js
@@ -21,11 +21,13 @@
describe('OCA.Sharing.PublicApp tests', function() {
var App = OCA.Sharing.PublicApp;
+ var hostStub, protocolStub, webrootStub;
var $preview;
- var fileListIn;
- var fileListOut;
beforeEach(function() {
+ protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ hostStub = sinon.stub(OC, 'getHost').returns('example.com:9876');
+ webrootStub = sinon.stub(OC, 'getRootPath').returns('/owncloud');
$preview = $('<div id="preview"></div>');
$('#testArea').append($preview);
$preview.append(
@@ -35,6 +37,12 @@ describe('OCA.Sharing.PublicApp tests', function() {
);
});
+ afterEach(function() {
+ protocolStub.restore();
+ hostStub.restore();
+ webrootStub.restore();
+ });
+
describe('File list', function() {
// TODO: this should be moved to a separate file once the PublicFileList is extracted from public.js
beforeEach(function() {
@@ -78,6 +86,13 @@ describe('OCA.Sharing.PublicApp tests', function() {
App._initialized = false;
});
+ it('Uses public webdav endpoint', function() {
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('PROPFIND');
+ expect(fakeServer.requests[0].url).toEqual('https://example.com:9876/owncloud/public.php/webdav/subdir');
+ expect(fakeServer.requests[0].requestHeaders.Authorization).toEqual('Basic c2g0dG9rOm51bGw=');
+ });
+
describe('Download Url', function() {
var fileList;
@@ -87,12 +102,12 @@ describe('OCA.Sharing.PublicApp tests', function() {
it('returns correct download URL for single files', function() {
expect(fileList.getDownloadUrl('some file.txt'))
- .toEqual(OC.webroot + '/index.php/s/sh4tok/download?path=%2Fsubdir&files=some%20file.txt');
- expect(fileList.getDownloadUrl('some file.txt', '/anotherpath/abc'))
- .toEqual(OC.webroot + '/index.php/s/sh4tok/download?path=%2Fanotherpath%2Fabc&files=some%20file.txt');
+ .toEqual('https://sh4tok@example.com:9876/owncloud/public.php/webdav/subdir/some file.txt');
+ expect(fileList.getDownloadUrl('some file.txt', '/another path/abc'))
+ .toEqual('https://sh4tok@example.com:9876/owncloud/public.php/webdav/another path/abc/some file.txt');
fileList.changeDirectory('/');
expect(fileList.getDownloadUrl('some file.txt'))
- .toEqual(OC.webroot + '/index.php/s/sh4tok/download?path=%2F&files=some%20file.txt');
+ .toEqual('https://sh4tok@example.com:9876/owncloud/public.php/webdav/some file.txt');
});
it('returns correct download URL for multiple files', function() {
expect(fileList.getDownloadUrl(['a b c.txt', 'd e f.txt']))
diff --git a/apps/files_sharing/tests/js/sharedfilelistSpec.js b/apps/files_sharing/tests/js/sharedfilelistSpec.js
index b4b6ac4954a..0b0676a19e6 100644
--- a/apps/files_sharing/tests/js/sharedfilelistSpec.js
+++ b/apps/files_sharing/tests/js/sharedfilelistSpec.js
@@ -166,8 +166,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt'
+ '/remote.php/webdav/local%20path/local%20name.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
@@ -185,8 +184,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-id')).toEqual('8');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2F&files=b.txt'
+ '/remote.php/webdav/b.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('b.txt');
});
@@ -338,8 +336,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt'
+ '/remote.php/webdav/local%20path/local%20name.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
@@ -429,9 +426,8 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-owner')).not.toBeDefined();
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
- OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt');
+ OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
+ );
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
@@ -498,9 +494,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-owner')).not.toBeDefined();
expect($tr.attr('data-share-id')).toEqual('7,8,9');
expect($tr.find('a.name').attr('href')).toEqual(
- OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt'
+ OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
@@ -592,9 +586,8 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-owner')).not.toBeDefined();
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
- OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt');
+ OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
+ );
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
@@ -634,8 +627,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt');
+ '/remote.php/webdav/local%20path/local%20name.txt');
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
@@ -720,7 +712,7 @@ describe('OCA.Sharing.FileList tests', function() {
$tr = fileList.$el.find('tr:first');
expect(parseInt($tr.attr('data-share-permissions'), 10))
- .toEqual(OC.PERMISSION_ALL - OC.PERMISSION_SHARE - OC.PERMISSION_DELETE);
+ .toEqual(OC.PERMISSION_ALL - OC.PERMISSION_SHARE - OC.PERMISSION_DELETE - OC.PERMISSION_CREATE);
});
});
});
diff --git a/apps/files_sharing/tests/locking.php b/apps/files_sharing/tests/locking.php
index ae1fcf30a53..ef8b2bb1cd4 100644
--- a/apps/files_sharing/tests/locking.php
+++ b/apps/files_sharing/tests/locking.php
@@ -2,8 +2,9 @@
/**
* @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,9 +25,15 @@ namespace OCA\Files_sharing\Tests;
use OC\Files\Filesystem;
use OC\Files\View;
-use OC\Lock\MemcacheLockingProvider;
use OCP\Lock\ILockingProvider;
+/**
+ * Class Locking
+ *
+ * @group DB
+ *
+ * @package OCA\Files_sharing\Tests
+ */
class Locking extends TestCase {
/**
* @var \Test\Util\User\Dummy
diff --git a/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php b/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php
index 031f8c1b970..e80be772a92 100644
--- a/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php
+++ b/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php
@@ -5,7 +5,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_sharing/tests/migrationtest.php b/apps/files_sharing/tests/migrationtest.php
index 522181fbb23..e1c047e0342 100644
--- a/apps/files_sharing/tests/migrationtest.php
+++ b/apps/files_sharing/tests/migrationtest.php
@@ -2,8 +2,9 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,53 +25,284 @@
use OCA\Files_Sharing\Tests\TestCase;
use OCA\Files_Sharing\Migration;
+/**
+ * Class MigrationTest
+ *
+ * @group DB
+ */
class MigrationTest extends TestCase {
- /**
- * @var \OCP\IDBConnection
- */
+ /** @var \OCP\IDBConnection */
private $connection;
- function __construct() {
- parent::__construct();
+ /** @var Migration */
+ private $migration;
+
+ private $table = 'share';
+
+ public function setUp() {
+ parent::setUp();
$this->connection = \OC::$server->getDatabaseConnection();
+ $this->migration = new Migration($this->connection);
+
+ $this->cleanDB();
}
- function testAddAccept() {
+ public function tearDown() {
+ parent::tearDown();
+ $this->cleanDB();
+ }
- $query = $this->connection->prepare('
- INSERT INTO `*PREFIX*share_external`
- (`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `remote_id`, `accepted`)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- ');
+ private function cleanDB() {
+ $query = $this->connection->getQueryBuilder();
+ $query->delete($this->table)->execute();
+ }
- for ($i = 0; $i < 10; $i++) {
- $query->execute(array('remote', 'token', 'password', 'name', 'owner', 'user', 'mount point', $i, $i, 0));
- }
+ public function addDummyValues() {
+ $query = $this->connection->getQueryBuilder();
+ $query->insert($this->table)
+ ->values(
+ array(
+ 'share_type' => $query->createParameter('share_type'),
+ 'share_with' => $query->createParameter('share_with'),
+ 'uid_owner' => $query->createParameter('uid_owner'),
+ 'uid_initiator' => $query->createParameter('uid_initiator'),
+ 'parent' => $query->createParameter('parent'),
+ 'item_type' => $query->createParameter('item_type'),
+ 'item_source' => $query->createParameter('item_source'),
+ 'item_target' => $query->createParameter('item_target'),
+ 'file_source' => $query->createParameter('file_source'),
+ 'file_target' => $query->createParameter('file_target'),
+ 'permissions' => $query->createParameter('permissions'),
+ 'stime' => $query->createParameter('stime'),
+ )
+ );
+ // shared contact, shouldn't be modified
+ $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_CONTACT)
+ ->setParameter('share_with', 'user1')
+ ->setParameter('uid_owner', 'owner1')
+ ->setParameter('uid_initiator', '')
+ ->setParameter('parent', null)
+ ->setParameter('item_type', 'contact')
+ ->setParameter('item_source', '2')
+ ->setParameter('item_target', '/2')
+ ->setParameter('file_source', null)
+ ->setParameter('file_target', null)
+ ->setParameter('permissions', 31)
+ ->setParameter('stime', time());
+ $this->assertSame(1,
+ $query->execute()
+ );
+ // shared calendar, shouldn't be modified
+ $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER)
+ ->setParameter('share_with', 'user1')
+ ->setParameter('uid_owner', 'owner1')
+ ->setParameter('uid_initiator', '')
+ ->setParameter('parent', null)
+ ->setParameter('item_type', 'calendar')
+ ->setParameter('item_source', '2')
+ ->setParameter('item_target', '/2')
+ ->setParameter('file_source', null)
+ ->setParameter('file_target', null)
+ ->setParameter('permissions', 31)
+ ->setParameter('stime', time());
+ $this->assertSame(1,
+ $query->execute()
+ );
+ // single user share, shouldn't be modified
+ $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER)
+ ->setParameter('share_with', 'user1')
+ ->setParameter('uid_owner', 'owner1')
+ ->setParameter('uid_initiator', '')
+ ->setParameter('parent', null)
+ ->setParameter('item_type', 'file')
+ ->setParameter('item_source', '2')
+ ->setParameter('item_target', '/2')
+ ->setParameter('file_source', 2)
+ ->setParameter('file_target', '/foo')
+ ->setParameter('permissions', 31)
+ ->setParameter('stime', time());
+ $this->assertSame(1,
+ $query->execute()
+ );
+ // single group share, shouldn't be modified
+ $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_GROUP)
+ ->setParameter('share_with', 'group1')
+ ->setParameter('uid_owner', 'owner1')
+ ->setParameter('uid_initiator', '')
+ ->setParameter('parent', null)
+ ->setParameter('item_type', 'file')
+ ->setParameter('item_source', '2')
+ ->setParameter('item_target', '/2')
+ ->setParameter('file_source', 2)
+ ->setParameter('file_target', '/foo')
+ ->setParameter('permissions', 31)
+ ->setParameter('stime', time());
+ $this->assertSame(1,
+ $query->execute()
+ );
+ $parent = $query->getLastInsertId();
+ // unique target for group share, shouldn't be modified
+ $query->setParameter('share_type', 2)
+ ->setParameter('share_with', 'group1')
+ ->setParameter('uid_owner', 'owner1')
+ ->setParameter('uid_initiator', '')
+ ->setParameter('parent', $parent)
+ ->setParameter('item_type', 'file')
+ ->setParameter('item_source', '2')
+ ->setParameter('item_target', '/2')
+ ->setParameter('file_source', 2)
+ ->setParameter('file_target', '/foo renamed')
+ ->setParameter('permissions', 31)
+ ->setParameter('stime', time());
+ $this->assertSame(1,
+ $query->execute()
+ );
+ // first user share, shouldn't be modified
+ $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER)
+ ->setParameter('share_with', 'user1')
+ ->setParameter('uid_owner', 'owner2')
+ ->setParameter('uid_initiator', '')
+ ->setParameter('parent', null)
+ ->setParameter('item_type', 'file')
+ ->setParameter('item_source', '2')
+ ->setParameter('item_target', '/2')
+ ->setParameter('file_source', 2)
+ ->setParameter('file_target', '/foobar')
+ ->setParameter('permissions', 31)
+ ->setParameter('stime', time());
+ $this->assertSame(1,
+ $query->execute()
+ );
+ $parent = $query->getLastInsertId();
+ // first re-share, should be attached to the first user share after migration
+ $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER)
+ ->setParameter('share_with', 'user2')
+ ->setParameter('uid_owner', 'user1')
+ ->setParameter('uid_initiator', '')
+ ->setParameter('parent', $parent)
+ ->setParameter('item_type', 'file')
+ ->setParameter('item_source', '2')
+ ->setParameter('item_target', '/2')
+ ->setParameter('file_source', 2)
+ ->setParameter('file_target', '/foobar')
+ ->setParameter('permissions', 31)
+ ->setParameter('stime', time());
+ $this->assertSame(1,
+ $query->execute()
+ );
+ $parent = $query->getLastInsertId();
+ // second re-share, should be attached to the first user share after migration
+ $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER)
+ ->setParameter('share_with', 'user3')
+ ->setParameter('uid_owner', 'user2')
+ ->setParameter('uid_initiator', '')
+ ->setParameter('parent', $parent)
+ ->setParameter('item_type', 'file')
+ ->setParameter('item_source', '2')
+ ->setParameter('item_target', '/2')
+ ->setParameter('file_source', 2)
+ ->setParameter('file_target', '/foobar')
+ ->setParameter('permissions', 31)
+ ->setParameter('stime', time());
+ $this->assertSame(1,
+ $query->execute()
+ );
+ }
- $query = $this->connection->prepare('SELECT `id` FROM `*PREFIX*share_external`');
- $query->execute();
- $dummyEntries = $query->fetchAll();
+ public function testRemoveReShares() {
+ $this->addDummyValues();
+ $this->migration->removeReShares();
+ $this->verifyResult();
+ }
- $this->assertSame(10, count($dummyEntries));
+ public function verifyResult() {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')->from($this->table)->orderBy('id');
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(8, count($result));
- $m = new Migration();
- $m->addAcceptRow();
+ // shares which shouldn't be modified
+ for ($i = 0; $i < 4; $i++) {
+ $this->assertSame('owner1', $result[$i]['uid_owner']);
+ $this->assertEmpty($result[$i]['uid_initiator']);
+ $this->assertNull($result[$i]['parent']);
+ }
+ // group share with unique target
+ $this->assertSame('owner1', $result[4]['uid_owner']);
+ $this->assertEmpty($result[4]['uid_initiator']);
+ $this->assertNotEmpty($result[4]['parent']);
+ // initial user share which was re-shared
+ $this->assertSame('owner2', $result[5]['uid_owner']);
+ $this->assertEmpty($result[5]['uid_initiator']);
+ $this->assertNull($result[5]['parent']);
+ // flatted re-shares
+ for($i = 6; $i < 8; $i++) {
+ $this->assertSame('owner2', $result[$i]['uid_owner']);
+ $user = 'user' . ($i - 5);
+ $this->assertSame($user, $result[$i]['uid_initiator']);
+ $this->assertNull($result[$i]['parent']);
+ }
+ }
- // verify result
- $query = $this->connection->prepare('SELECT `accepted` FROM `*PREFIX*share_external`');
- $query->execute();
- $results = $query->fetchAll();
- $this->assertSame(10, count($results));
+ public function test1001DeepReshares() {
+ $parent = null;
+ for ($i = 0; $i < 1001; $i++) {
+ $query = $this->connection->getQueryBuilder();
+ $query->insert($this->table)
+ ->values(
+ [
+ 'share_type' => $query->createParameter('share_type'),
+ 'share_with' => $query->createParameter('share_with'),
+ 'uid_owner' => $query->createParameter('uid_owner'),
+ 'uid_initiator' => $query->createParameter('uid_initiator'),
+ 'parent' => $query->createParameter('parent'),
+ 'item_type' => $query->createParameter('item_type'),
+ 'item_source' => $query->createParameter('item_source'),
+ 'item_target' => $query->createParameter('item_target'),
+ 'file_source' => $query->createParameter('file_source'),
+ 'file_target' => $query->createParameter('file_target'),
+ 'permissions' => $query->createParameter('permissions'),
+ 'stime' => $query->createParameter('stime'),
+ ]
+ )
+ ->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER)
+ ->setParameter('share_with', 'user'.($i+1))
+ ->setParameter('uid_owner', 'user'.($i))
+ ->setParameter('uid_initiator', null)
+ ->setParameter('parent', $parent)
+ ->setParameter('item_type', 'file')
+ ->setParameter('item_source', '2')
+ ->setParameter('item_target', '/2')
+ ->setParameter('file_source', 2)
+ ->setParameter('file_target', '/foobar')
+ ->setParameter('permissions', 31)
+ ->setParameter('stime', time());
- foreach ($results as $r) {
- $this->assertSame(1, (int) $r['accepted']);
+ $this->assertSame(1, $query->execute());
+ $parent = $query->getLastInsertId();
}
- // cleanup
- $cleanup = $this->connection->prepare('DELETE FROM `*PREFIX*share_external`');
- $cleanup->execute();
- }
+ $this->migration->removeReShares();
+ $this->migration->updateInitiatorInfo();
+ $qb = $this->connection->getQueryBuilder();
+
+ $stmt = $qb->select('id', 'share_with', 'uid_owner', 'uid_initiator', 'parent')
+ ->from('share')
+ ->orderBy('id', 'asc')
+ ->execute();
+
+ $i = 0;
+ while($share = $stmt->fetch()) {
+ $this->assertEquals('user'.($i+1), $share['share_with']);
+ $this->assertEquals('user' . ($i), $share['uid_initiator']);
+ $this->assertEquals('user0', $share['uid_owner']);
+ $this->assertEquals(null, $share['parent']);
+ $i++;
+ }
+ $stmt->closeCursor();
+ $this->assertEquals(1001, $i);
+ }
}
diff --git a/apps/files_sharing/tests/permissions.php b/apps/files_sharing/tests/permissions.php
index 80e727b7178..43a57266851 100644
--- a/apps/files_sharing/tests/permissions.php
+++ b/apps/files_sharing/tests/permissions.php
@@ -6,7 +6,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,7 +26,11 @@ use OC\Files\Cache\Cache;
use OC\Files\Storage\Storage;
use OC\Files\View;
-
+/**
+ * Class Test_Files_Sharing_Permissions
+ *
+ * @group DB
+ */
class Test_Files_Sharing_Permissions extends OCA\Files_sharing\Tests\TestCase {
/**
diff --git a/apps/files_sharing/tests/propagationtestcase.php b/apps/files_sharing/tests/propagationtestcase.php
new file mode 100644
index 00000000000..159a7b859aa
--- /dev/null
+++ b/apps/files_sharing/tests/propagationtestcase.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_sharing\Tests;
+
+abstract class PropagationTestCase extends TestCase {
+ /**
+ * @var \OC\Files\View
+ */
+ protected $rootView;
+ protected $fileIds = []; // [$user=>[$path=>$id]]
+ protected $fileEtags = []; // [$id=>$etag]
+
+ public static function setUpBeforeClass() {
+ parent::setUpBeforeClass();
+ \OCA\Files_Sharing\Helper::registerHooks();
+ }
+
+ protected function setUp() {
+ parent::setUp();
+ $this->setUpShares();
+ }
+
+ protected function tearDown() {
+ \OC_Hook::clear('OC_Filesystem', 'post_write');
+ \OC_Hook::clear('OC_Filesystem', 'post_delete');
+ \OC_Hook::clear('OC_Filesystem', 'post_rename');
+ \OC_Hook::clear('OCP\Share', 'post_update_permissions');
+ parent::tearDown();
+ }
+
+ abstract protected function setUpShares();
+
+ /**
+ * @param string[] $users
+ * @param string $subPath
+ */
+ protected function assertEtagsChanged($users, $subPath = '') {
+ $oldUser = \OC::$server->getUserSession()->getUser();
+ foreach ($users as $user) {
+ $this->loginAsUser($user);
+ $id = $this->fileIds[$user][$subPath];
+ $path = $this->rootView->getPath($id);
+ $etag = $this->rootView->getFileInfo($path)->getEtag();
+ $this->assertNotEquals($this->fileEtags[$id], $etag, 'Failed asserting that the etag for "' . $subPath . '" of user ' . $user . ' has changed');
+ $this->fileEtags[$id] = $etag;
+ }
+ $this->loginAsUser($oldUser->getUID());
+ }
+
+ /**
+ * @param string[] $users
+ * @param string $subPath
+ */
+ protected function assertEtagsNotChanged($users, $subPath = '') {
+ $oldUser = \OC::$server->getUserSession()->getUser();
+ foreach ($users as $user) {
+ $this->loginAsUser($user);
+ $id = $this->fileIds[$user][$subPath];
+ $path = $this->rootView->getPath($id);
+ $etag = $this->rootView->getFileInfo($path)->getEtag();
+ $this->assertEquals($this->fileEtags[$id], $etag, 'Failed asserting that the etag for "' . $subPath . '" of user ' . $user . ' has not changed');
+ $this->fileEtags[$id] = $etag;
+ }
+ $this->loginAsUser($oldUser->getUID());
+ }
+
+ /**
+ * Assert that the etags for the root, /sub1 and /sub1/sub2 have changed
+ *
+ * @param string[] $users
+ */
+ protected function assertEtagsForFoldersChanged($users) {
+ $this->assertEtagsChanged($users);
+
+ $this->assertEtagsChanged($users, 'sub1');
+ $this->assertEtagsChanged($users, 'sub1/sub2');
+ }
+
+ protected function assertAllUnchanged() {
+ $users = [self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2,
+ self::TEST_FILES_SHARING_API_USER3, self::TEST_FILES_SHARING_API_USER4];
+ $this->assertEtagsNotChanged($users);
+ }
+}
diff --git a/apps/files_sharing/tests/server2server.php b/apps/files_sharing/tests/server2server.php
index 300c637c777..a282f92ecb9 100644
--- a/apps/files_sharing/tests/server2server.php
+++ b/apps/files_sharing/tests/server2server.php
@@ -4,8 +4,9 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +27,8 @@ use OCA\Files_Sharing\Tests\TestCase;
/**
* Class Test_Files_Sharing_Api
+ *
+ * @group DB
*/
class Test_Files_Sharing_S2S_OCS_API extends TestCase {
diff --git a/apps/files_sharing/tests/share.php b/apps/files_sharing/tests/share.php
index 896191dfe51..6b8c685cc10 100644
--- a/apps/files_sharing/tests/share.php
+++ b/apps/files_sharing/tests/share.php
@@ -3,10 +3,12 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,6 +29,8 @@ use OCA\Files\Share;
/**
* Class Test_Files_Sharing
+ *
+ * @group DB
*/
class Test_Files_Sharing extends OCA\Files_sharing\Tests\TestCase {
@@ -218,6 +222,10 @@ class Test_Files_Sharing extends OCA\Files_sharing\Tests\TestCase {
}
+ /**
+ * @param OC\Files\FileInfo[] $content
+ * @param string[] $expected
+ */
public function verifyDirContent($content, $expected) {
foreach ($content as $c) {
if (!in_array($c['name'], $expected)) {
diff --git a/apps/files_sharing/tests/sharedmount.php b/apps/files_sharing/tests/sharedmount.php
index 94c0ad448bc..e01deeb60f4 100644
--- a/apps/files_sharing/tests/sharedmount.php
+++ b/apps/files_sharing/tests/sharedmount.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,6 +27,8 @@
/**
* Class Test_Files_Sharing_Api
+ *
+ * @group DB
*/
class Test_Files_Sharing_Mount extends OCA\Files_sharing\Tests\TestCase {
@@ -46,8 +48,10 @@ class Test_Files_Sharing_Mount extends OCA\Files_sharing\Tests\TestCase {
}
protected function tearDown() {
- $this->view->unlink($this->folder);
- $this->view->unlink($this->filename);
+ if ($this->view) {
+ $this->view->unlink($this->folder);
+ $this->view->unlink($this->filename);
+ }
parent::tearDown();
}
@@ -235,6 +239,220 @@ class Test_Files_Sharing_Mount extends OCA\Files_sharing\Tests\TestCase {
);
}
+ function dataPermissionMovedGroupShare() {
+ $data = [];
+
+ $powerset = function($permissions) {
+ $results = [\OCP\Constants::PERMISSION_READ];
+
+ foreach ($permissions as $permission) {
+ foreach ($results as $combination) {
+ $results[] = $permission | $combination;
+ }
+ }
+ return $results;
+ };
+
+ //Generate file permissions
+ $permissions = [
+ \OCP\Constants::PERMISSION_UPDATE,
+ \OCP\Constants::PERMISSION_CREATE,
+ \OCP\Constants::PERMISSION_SHARE,
+ ];
+
+ $allPermissions = $powerset($permissions);
+
+ foreach ($allPermissions as $before) {
+ foreach ($allPermissions as $after) {
+ if ($before === $after) { continue; }
+
+ $data[] = [
+ 'file',
+ $before,
+ $after,
+ ];
+ }
+ }
+
+ //Generate folder permissions
+ $permissions = [
+ \OCP\Constants::PERMISSION_UPDATE,
+ \OCP\Constants::PERMISSION_CREATE,
+ \OCP\Constants::PERMISSION_SHARE,
+ \OCP\Constants::PERMISSION_DELETE,
+ ];
+
+ $allPermissions = $powerset($permissions);
+
+ foreach ($allPermissions as $before) {
+ foreach ($allPermissions as $after) {
+ if ($before === $after) { continue; }
+
+ $data[] = [
+ 'folder',
+ $before,
+ $after,
+ ];
+ }
+ }
+
+ return $data;
+ }
+
+
+
+ /**
+ * moved mountpoints of a group share should keep the same permission as their parent group share.
+ * See #15253
+ *
+ * @dataProvider dataPermissionMovedGroupShare
+ */
+ function testPermissionMovedGroupShare($type, $beforePerm, $afterPerm) {
+
+ if ($type === 'file') {
+ $path = $this->filename;
+ } else if ($type === 'folder') {
+ $path = $this->folder;
+ }
+
+ \OC_Group::createGroup('testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+
+ // Share item with group
+ $fileinfo = $this->view->getFileInfo($path);
+ $this->assertTrue(
+ \OCP\Share::shareItem($type, $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", $beforePerm)
+ );
+
+ // Login as user 2 and verify the item exists
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($path));
+ $result = \OCP\Share::getItemSharedWithBySource($type, $fileinfo['fileid']);
+ $this->assertNotEmpty($result);
+ $this->assertEquals($beforePerm, $result['permissions']);
+
+ // Now move the item forcing a new entry in the share table
+ \OC\Files\Filesystem::rename($path, "newPath");
+ $this->assertTrue(\OC\Files\Filesystem::file_exists('newPath'));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($path));
+
+ // Login as user 1 again and change permissions
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ $this->assertTrue(
+ \OCP\Share::setPermissions($type, $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", $afterPerm)
+ );
+
+ // Login as user 3 and verify that the permissions are changed
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+ $result = \OCP\Share::getItemSharedWithBySource($type, $fileinfo['fileid']);
+ $this->assertNotEmpty($result);
+ $this->assertEquals($afterPerm, $result['permissions']);
+ $groupShareId = $result['id'];
+
+ // Login as user 2 and verify that the permissions are changed
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $result = \OCP\Share::getItemSharedWithBySource($type, $fileinfo['fileid']);
+ $this->assertNotEmpty($result);
+ $this->assertEquals($afterPerm, $result['permissions']);
+ $this->assertNotEquals($groupShareId, $result['id']);
+
+ // Also verify in the DB
+ $statement = "SELECT `permissions` FROM `*PREFIX*share` WHERE `id`=?";
+ $query = \OCP\DB::prepare($statement);
+ $result = $query->execute([$result['id']]);
+ $shares = $result->fetchAll();
+ $this->assertCount(1, $shares);
+ $this->assertEquals($afterPerm, $shares[0]['permissions']);
+
+ //cleanup
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ \OCP\Share::unshare($type, $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+ }
+
+ /**
+ * If the permissions on a group share are upgraded be sure to still respect
+ * removed shares by a member of that group
+ */
+ function testPermissionUpgradeOnUserDeletedGroupShare() {
+ \OC_Group::createGroup('testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+
+ $connection = \OC::$server->getDatabaseConnection();
+
+ // Share item with group
+ $fileinfo = $this->view->getFileInfo($this->folder);
+ $this->assertTrue(
+ \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", \OCP\Constants::PERMISSION_READ)
+ );
+
+ // Login as user 2 and verify the item exists
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->folder));
+ $result = \OCP\Share::getItemSharedWithBySource('folder', $fileinfo['fileid']);
+ $this->assertNotEmpty($result);
+ $this->assertEquals(\OCP\Constants::PERMISSION_READ, $result['permissions']);
+
+ // Delete the share
+ $this->assertTrue(\OC\Files\Filesystem::rmdir($this->folder));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($this->folder));
+
+ // Verify we do not get a share
+ $result = \OCP\Share::getItemSharedWithBySource('folder', $fileinfo['fileid']);
+ $this->assertEmpty($result);
+
+ // Verify that the permission is correct in the DB
+ $qb = $connection->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('file_source', $qb->createParameter('fileSource')))
+ ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('shareType')))
+ ->setParameter(':fileSource', $fileinfo['fileid'])
+ ->setParameter(':shareType', 2);
+ $res = $qb->execute()->fetchAll();
+
+ $this->assertCount(1, $res);
+ $this->assertEquals(0, $res[0]['permissions']);
+
+ // Login as user 1 again and change permissions
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ $this->assertTrue(
+ \OCP\Share::setPermissions('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", \OCP\Constants::PERMISSION_ALL)
+ );
+
+ // Login as user 2 and verify
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($this->folder));
+ $result = \OCP\Share::getItemSharedWithBySource('folder', $fileinfo['fileid']);
+ $this->assertEmpty($result);
+
+ $connection = \OC::$server->getDatabaseConnection();
+ $qb = $connection->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('file_source', $qb->createParameter('fileSource')))
+ ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('shareType')))
+ ->setParameter(':fileSource', $fileinfo['fileid'])
+ ->setParameter(':shareType', 2);
+ $res = $qb->execute()->fetchAll();
+
+ $this->assertCount(1, $res);
+ $this->assertEquals(0, $res[0]['permissions']);
+
+ //cleanup
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+ }
+
}
class DummyTestClassSharedMount extends \OCA\Files_Sharing\SharedMount {
diff --git a/apps/files_sharing/tests/sharedstorage.php b/apps/files_sharing/tests/sharedstorage.php
index 3361d2cbd12..63f4334103f 100644
--- a/apps/files_sharing/tests/sharedstorage.php
+++ b/apps/files_sharing/tests/sharedstorage.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,6 +28,8 @@ use OCA\Files\Share;
/**
* Class Test_Files_Sharing_Api
+ *
+ * @group DB
*/
class Test_Files_Sharing_Storage extends OCA\Files_sharing\Tests\TestCase {
diff --git a/apps/files_sharing/tests/sizepropagation.php b/apps/files_sharing/tests/sizepropagation.php
index 1d09f69449f..7b7884f3f96 100644
--- a/apps/files_sharing/tests/sizepropagation.php
+++ b/apps/files_sharing/tests/sizepropagation.php
@@ -2,8 +2,9 @@
/**
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,13 @@ namespace OCA\Files_sharing\Tests;
use OC\Files\View;
+/**
+ * Class SizePropagation
+ *
+ * @group DB
+ *
+ * @package OCA\Files_sharing\Tests
+ */
class SizePropagation extends TestCase {
public function testSizePropagationWhenOwnerChangesFile() {
diff --git a/apps/files_sharing/tests/testcase.php b/apps/files_sharing/tests/testcase.php
index c91734a5b03..ce0a8beeec8 100644
--- a/apps/files_sharing/tests/testcase.php
+++ b/apps/files_sharing/tests/testcase.php
@@ -6,11 +6,12 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -36,6 +37,8 @@ use OCA\Files_Sharing\Appinfo\Application;
/**
* Class Test_Files_Sharing_Base
*
+ * @group DB
+ *
* Base class for sharing tests.
*/
abstract class TestCase extends \Test\TestCase {
@@ -61,7 +64,6 @@ abstract class TestCase extends \Test\TestCase {
$application = new Application();
$application->registerMountProviders();
- $application->setupPropagation();
// reset backend
\OC_User::clearBackends();
@@ -83,9 +85,15 @@ abstract class TestCase extends \Test\TestCase {
$groupBackend = new \OC_Group_Dummy();
$groupBackend->createGroup(self::TEST_FILES_SHARING_API_GROUP1);
$groupBackend->createGroup('group');
+ $groupBackend->createGroup('group1');
+ $groupBackend->createGroup('group2');
+ $groupBackend->createGroup('group3');
$groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER1, 'group');
$groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER2, 'group');
$groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER3, 'group');
+ $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER2, 'group1');
+ $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER3, 'group2');
+ $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER4, 'group3');
$groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_GROUP1);
\OC_Group::useBackend($groupBackend);
@@ -110,9 +118,12 @@ abstract class TestCase extends \Test\TestCase {
public static function tearDownAfterClass() {
// cleanup users
- \OC_User::deleteUser(self::TEST_FILES_SHARING_API_USER1);
- \OC_User::deleteUser(self::TEST_FILES_SHARING_API_USER2);
- \OC_User::deleteUser(self::TEST_FILES_SHARING_API_USER3);
+ $user = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER1);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER2);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER3);
+ if ($user !== null) { $user->delete(); }
// delete group
\OC_Group::deleteGroup(self::TEST_FILES_SHARING_API_GROUP1);
@@ -142,7 +153,7 @@ abstract class TestCase extends \Test\TestCase {
}
if ($create) {
- \OC_User::createUser($user, $password);
+ \OC::$server->getUserManager()->createUser($user, $password);
\OC_Group::createGroup('group');
\OC_Group::addToGroup($user, 'group');
}
@@ -163,9 +174,9 @@ abstract class TestCase extends \Test\TestCase {
*/
protected static function resetStorage() {
$storage = new \ReflectionClass('\OC\Files\Storage\Shared');
- $isInitialized = $storage->getProperty('isInitialized');
+ $isInitialized = $storage->getProperty('initialized');
$isInitialized->setAccessible(true);
- $isInitialized->setValue(array());
+ $isInitialized->setValue($storage, false);
$isInitialized->setAccessible(false);
}
diff --git a/apps/files_sharing/tests/unsharechildren.php b/apps/files_sharing/tests/unsharechildren.php
index c57070ba641..1968007be4e 100644
--- a/apps/files_sharing/tests/unsharechildren.php
+++ b/apps/files_sharing/tests/unsharechildren.php
@@ -4,8 +4,9 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +27,13 @@ namespace OCA\Files_sharing\Tests;
use OCA\Files\Share;
+/**
+ * Class UnshareChildren
+ *
+ * @group DB
+ *
+ * @package OCA\Files_sharing\Tests
+ */
class UnshareChildren extends TestCase {
protected $subsubfolder;
diff --git a/apps/files_sharing/tests/updater.php b/apps/files_sharing/tests/updater.php
index 63ab452a5e1..dd1f83c99a8 100644
--- a/apps/files_sharing/tests/updater.php
+++ b/apps/files_sharing/tests/updater.php
@@ -3,9 +3,10 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +26,8 @@
/**
* Class Test_Files_Sharing_Updater
+ *
+ * @group DB
*/
class Test_Files_Sharing_Updater extends OCA\Files_Sharing\Tests\TestCase {
@@ -49,8 +52,10 @@ class Test_Files_Sharing_Updater extends OCA\Files_Sharing\Tests\TestCase {
}
protected function tearDown() {
- $this->view->unlink($this->filename);
- $this->view->deleteAll($this->folder);
+ if ($this->view) {
+ $this->view->unlink($this->filename);
+ $this->view->deleteAll($this->folder);
+ }
parent::tearDown();
}
diff --git a/apps/files_sharing/tests/watcher.php b/apps/files_sharing/tests/watcher.php
index 5e96a3fe68e..247fb59f351 100644
--- a/apps/files_sharing/tests/watcher.php
+++ b/apps/files_sharing/tests/watcher.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +25,11 @@
*
*/
+/**
+ * Class Test_Files_Sharing_Watcher
+ *
+ * @group DB
+ */
class Test_Files_Sharing_Watcher extends OCA\Files_sharing\Tests\TestCase {
/**
@@ -83,13 +88,15 @@ class Test_Files_Sharing_Watcher extends OCA\Files_sharing\Tests\TestCase {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
- $fileinfo = $this->view->getFileInfo('container/shareddir');
- \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
- self::TEST_FILES_SHARING_API_USER2);
+ if ($this->view) {
+ $fileinfo = $this->view->getFileInfo('container/shareddir');
+ \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+ self::TEST_FILES_SHARING_API_USER2);
- $this->view->deleteAll('container');
+ $this->view->deleteAll('container');
- $this->ownerCache->clear();
+ $this->ownerCache->clear();
+ }
parent::tearDown();
}
diff --git a/apps/files_trashbin/ajax/delete.php b/apps/files_trashbin/ajax/delete.php
index 40d1811717c..a4f97a03486 100644
--- a/apps/files_trashbin/ajax/delete.php
+++ b/apps/files_trashbin/ajax/delete.php
@@ -7,7 +7,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/ajax/isEmpty.php b/apps/files_trashbin/ajax/isEmpty.php
index a8122b94733..f8a7cf03a8b 100644
--- a/apps/files_trashbin/ajax/isEmpty.php
+++ b/apps/files_trashbin/ajax/isEmpty.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/ajax/list.php b/apps/files_trashbin/ajax/list.php
index 46168f7865e..45cc1254e59 100644
--- a/apps/files_trashbin/ajax/list.php
+++ b/apps/files_trashbin/ajax/list.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/ajax/preview.php b/apps/files_trashbin/ajax/preview.php
index 49d6d93f574..86c5ea2dbe5 100644
--- a/apps/files_trashbin/ajax/preview.php
+++ b/apps/files_trashbin/ajax/preview.php
@@ -3,10 +3,11 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Georg Ehrke <georg@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -62,7 +63,7 @@ try{
$fileName = substr($fileName, 0, $i);
}
}
- $mimetype = \OC_Helper::getFileNameMimeType($fileName);
+ $mimetype = \OC::$server->getMimeTypeDetector()->detectPath($fileName);
}
$preview->setMimetype($mimetype);
$preview->setMaxX($maxX);
diff --git a/apps/files_trashbin/ajax/undelete.php b/apps/files_trashbin/ajax/undelete.php
index f0e5ce6d889..97d8425f0f5 100644
--- a/apps/files_trashbin/ajax/undelete.php
+++ b/apps/files_trashbin/ajax/undelete.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/appinfo/app.php b/apps/files_trashbin/appinfo/app.php
index 7d99270557f..3f86dd5b17e 100644
--- a/apps/files_trashbin/appinfo/app.php
+++ b/apps/files_trashbin/appinfo/app.php
@@ -7,7 +7,7 @@
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/appinfo/application.php b/apps/files_trashbin/appinfo/application.php
index 59553abfb14..841c9d90f1b 100644
--- a/apps/files_trashbin/appinfo/application.php
+++ b/apps/files_trashbin/appinfo/application.php
@@ -3,7 +3,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/appinfo/info.xml b/apps/files_trashbin/appinfo/info.xml
index c4bade081b3..8fcb9956c7d 100644
--- a/apps/files_trashbin/appinfo/info.xml
+++ b/apps/files_trashbin/appinfo/info.xml
@@ -9,14 +9,13 @@ To prevent a user from running out of disk space, the ownCloud Deleted files app
</description>
<licence>AGPL</licence>
<author>Bjoern Schiessle</author>
- <shipped>true</shipped>
<default_enable/>
<version>0.8.0</version>
<types>
<filesystem/>
</types>
<dependencies>
- <owncloud min-version="9.0" />
+ <owncloud min-version="9.0" max-version="9.0" />
</dependencies>
<documentation>
<user>user-trashbin</user>
diff --git a/apps/files_trashbin/appinfo/install.php b/apps/files_trashbin/appinfo/install.php
index dc4c2847c22..51b0bdf43c3 100644
--- a/apps/files_trashbin/appinfo/install.php
+++ b/apps/files_trashbin/appinfo/install.php
@@ -2,7 +2,7 @@
/**
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/appinfo/register_command.php b/apps/files_trashbin/appinfo/register_command.php
index ae4196dd506..08c98741156 100644
--- a/apps/files_trashbin/appinfo/register_command.php
+++ b/apps/files_trashbin/appinfo/register_command.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/appinfo/routes.php b/apps/files_trashbin/appinfo/routes.php
index f3b97d8687c..717820adf49 100644
--- a/apps/files_trashbin/appinfo/routes.php
+++ b/apps/files_trashbin/appinfo/routes.php
@@ -4,7 +4,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/appinfo/update.php b/apps/files_trashbin/appinfo/update.php
index bd2ee6bb390..f0c95baeb71 100644
--- a/apps/files_trashbin/appinfo/update.php
+++ b/apps/files_trashbin/appinfo/update.php
@@ -1,11 +1,9 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,12 +23,6 @@
$config = \OC::$server->getConfig();
$installedVersion = $config->getAppValue('files_trashbin', 'installed_version');
-if (version_compare($installedVersion, '0.6', '<')) {
- //size of the trash bin could be incorrect, remove it for all users to
- //enforce a recalculation during next usage.
- \OC_DB::dropTable('files_trashsize');
-}
-
if (version_compare($installedVersion, '0.6.4', '<')) {
$isExpirationEnabled = $config->getSystemValue('trashbin_auto_expire', true);
$oldObligation = $config->getSystemValue('trashbin_retention_obligation', null);
diff --git a/apps/files_trashbin/command/cleanup.php b/apps/files_trashbin/command/cleanup.php
index 8af5dee4fcb..cffe7f7d1dd 100644
--- a/apps/files_trashbin/command/cleanup.php
+++ b/apps/files_trashbin/command/cleanup.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/command/expire.php b/apps/files_trashbin/command/expire.php
index f34c63b718b..9e0f58e12ce 100644
--- a/apps/files_trashbin/command/expire.php
+++ b/apps/files_trashbin/command/expire.php
@@ -1,11 +1,12 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -37,17 +38,10 @@ class Expire implements ICommand {
private $user;
/**
- * @var int
- */
- private $trashBinSize;
-
- /**
* @param string $user
- * @param int $trashBinSize
*/
- function __construct($user, $trashBinSize) {
+ function __construct($user) {
$this->user = $user;
- $this->trashBinSize = $trashBinSize;
}
public function handle() {
@@ -59,7 +53,7 @@ class Expire implements ICommand {
\OC_Util::tearDownFS();
\OC_Util::setupFS($this->user);
- Trashbin::expire($this->trashBinSize, $this->user);
+ Trashbin::expire($this->user);
\OC_Util::tearDownFS();
}
}
diff --git a/apps/files_trashbin/js/app.js b/apps/files_trashbin/js/app.js
index 1f46f568bf2..600a8ce2b03 100644
--- a/apps/files_trashbin/js/app.js
+++ b/apps/files_trashbin/js/app.js
@@ -38,10 +38,7 @@ OCA.Trashbin.App = {
var fileActions = new OCA.Files.FileActions();
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
var dir = context.fileList.getCurrentDirectory();
- if (dir !== '/') {
- dir = dir + '/';
- }
- context.fileList.changeDirectory(dir + filename);
+ context.fileList.changeDirectory(OC.joinPaths(dir, filename));
});
fileActions.setDefault('dir', 'Open');
diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js
index 6b624e333a0..5812aff82f7 100644
--- a/apps/files_trashbin/js/filelist.js
+++ b/apps/files_trashbin/js/filelist.js
@@ -283,7 +283,77 @@
isSelectedDeletable: function() {
return true;
- }
+ },
+
+ /**
+ * Reloads the file list using ajax call
+ *
+ * @return ajax call object
+ */
+ reload: function() {
+ this._selectedFiles = {};
+ this._selectionSummary.clear();
+ this.$el.find('.select-all').prop('checked', false);
+ this.showMask();
+ if (this._reloadCall) {
+ this._reloadCall.abort();
+ }
+ this._reloadCall = $.ajax({
+ url: this.getAjaxUrl('list'),
+ data: {
+ dir : this.getCurrentDirectory(),
+ sort: this._sort,
+ sortdirection: this._sortDirection
+ }
+ });
+ var callBack = this.reloadCallback.bind(this);
+ return this._reloadCall.then(callBack, callBack);
+ },
+ reloadCallback: function(result) {
+ delete this._reloadCall;
+ this.hideMask();
+
+ if (!result || result.status === 'error') {
+ // if the error is not related to folder we're trying to load, reload the page to handle logout etc
+ if (result.data.error === 'authentication_error' ||
+ result.data.error === 'token_expired' ||
+ result.data.error === 'application_not_enabled'
+ ) {
+ OC.redirect(OC.generateUrl('apps/files'));
+ }
+ OC.Notification.show(result.data.message);
+ return false;
+ }
+
+ // Firewall Blocked request?
+ if (result.status === 403) {
+ // Go home
+ this.changeDirectory('/');
+ OC.Notification.show(t('files', 'This operation is forbidden'));
+ return false;
+ }
+
+ // Did share service die or something else fail?
+ if (result.status === 500) {
+ // Go home
+ this.changeDirectory('/');
+ OC.Notification.show(t('files', 'This directory is unavailable, please check the logs or contact the administrator'));
+ return false;
+ }
+
+ if (result.status === 404) {
+ // go back home
+ this.changeDirectory('/');
+ return false;
+ }
+ // aborted ?
+ if (result.status === 0){
+ return true;
+ }
+
+ this.setFiles(result.data.files);
+ return true;
+ },
});
diff --git a/apps/files_trashbin/l10n/ar.js b/apps/files_trashbin/l10n/ar.js
index 964d547c42a..8b78e9e017a 100644
--- a/apps/files_trashbin/l10n/ar.js
+++ b/apps/files_trashbin/l10n/ar.js
@@ -8,6 +8,7 @@ OC.L10N.register(
"Delete" : "إلغاء",
"Delete permanently" : "حذف بشكل دائم",
"Error" : "خطأ",
+ "This operation is forbidden" : "هذة العملية ممنوعة ",
"restored" : "تمت الاستعادة",
"No entries found in this folder" : "لا يوجد مدخلات في هذا المجلد ",
"Select all" : "تحديد الكل ",
diff --git a/apps/files_trashbin/l10n/ar.json b/apps/files_trashbin/l10n/ar.json
index cb73176fda1..ac3552d79af 100644
--- a/apps/files_trashbin/l10n/ar.json
+++ b/apps/files_trashbin/l10n/ar.json
@@ -6,6 +6,7 @@
"Delete" : "إلغاء",
"Delete permanently" : "حذف بشكل دائم",
"Error" : "خطأ",
+ "This operation is forbidden" : "هذة العملية ممنوعة ",
"restored" : "تمت الاستعادة",
"No entries found in this folder" : "لا يوجد مدخلات في هذا المجلد ",
"Select all" : "تحديد الكل ",
diff --git a/apps/files_trashbin/l10n/ast.js b/apps/files_trashbin/l10n/ast.js
index b467f8b51a1..f59457ad6d1 100644
--- a/apps/files_trashbin/l10n/ast.js
+++ b/apps/files_trashbin/l10n/ast.js
@@ -8,6 +8,8 @@ OC.L10N.register(
"Delete" : "Desaniciar",
"Delete permanently" : "Desaniciar dafechu",
"Error" : "Fallu",
+ "This operation is forbidden" : "La operación ta prohibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Esti direutoriu nun ta disponible, por favor verifica'l rexistru o contacta l'alministrador",
"restored" : "recuperóse",
"No deleted files" : "Ensin ficheros desaniciaos",
"You will be able to recover deleted files from here" : "Dende equí podrás recureperar los ficheros desaniciaos",
diff --git a/apps/files_trashbin/l10n/ast.json b/apps/files_trashbin/l10n/ast.json
index b568456279b..65380e118d6 100644
--- a/apps/files_trashbin/l10n/ast.json
+++ b/apps/files_trashbin/l10n/ast.json
@@ -6,6 +6,8 @@
"Delete" : "Desaniciar",
"Delete permanently" : "Desaniciar dafechu",
"Error" : "Fallu",
+ "This operation is forbidden" : "La operación ta prohibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Esti direutoriu nun ta disponible, por favor verifica'l rexistru o contacta l'alministrador",
"restored" : "recuperóse",
"No deleted files" : "Ensin ficheros desaniciaos",
"You will be able to recover deleted files from here" : "Dende equí podrás recureperar los ficheros desaniciaos",
diff --git a/apps/files_trashbin/l10n/az.js b/apps/files_trashbin/l10n/az.js
index a6b149dcbdb..7b3ab2ef04a 100644
--- a/apps/files_trashbin/l10n/az.js
+++ b/apps/files_trashbin/l10n/az.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Geri qaytarila bilmədi %s",
"Deleted files" : "Silinmiş fayllar",
"Restore" : "Geri qaytar",
+ "Delete" : "Sil",
"Delete permanently" : "Həmişəlik sil",
"Error" : "Səhv",
+ "This operation is forbidden" : "Bu əməliyyat qadağandır",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Bu qovluq tapılmir. Xahiş olunur jurnalları yoxlayın ya da inzibatçı ilə əlaqə saxlayın",
"restored" : "geriqaytarılıb",
"No deleted files" : "Silinmiş fayllar mövcud deyil",
"You will be able to recover deleted files from here" : "Siz silinmiş faylları burdan bərpa edə bilərsiniz",
"No entries found in this folder" : "Bu qovluqda heç bir verilən tapılmadı",
"Select all" : "Hamısıı seç",
"Name" : "Ad",
- "Deleted" : "Silinib",
- "Delete" : "Sil"
+ "Deleted" : "Silinib"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/az.json b/apps/files_trashbin/l10n/az.json
index 45d74ddbc9c..f9d23ea362a 100644
--- a/apps/files_trashbin/l10n/az.json
+++ b/apps/files_trashbin/l10n/az.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Geri qaytarila bilmədi %s",
"Deleted files" : "Silinmiş fayllar",
"Restore" : "Geri qaytar",
+ "Delete" : "Sil",
"Delete permanently" : "Həmişəlik sil",
"Error" : "Səhv",
+ "This operation is forbidden" : "Bu əməliyyat qadağandır",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Bu qovluq tapılmir. Xahiş olunur jurnalları yoxlayın ya da inzibatçı ilə əlaqə saxlayın",
"restored" : "geriqaytarılıb",
"No deleted files" : "Silinmiş fayllar mövcud deyil",
"You will be able to recover deleted files from here" : "Siz silinmiş faylları burdan bərpa edə bilərsiniz",
"No entries found in this folder" : "Bu qovluqda heç bir verilən tapılmadı",
"Select all" : "Hamısıı seç",
"Name" : "Ad",
- "Deleted" : "Silinib",
- "Delete" : "Sil"
+ "Deleted" : "Silinib"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/bg_BG.js b/apps/files_trashbin/l10n/bg_BG.js
index 9db73c98a6d..767f529a9a1 100644
--- a/apps/files_trashbin/l10n/bg_BG.js
+++ b/apps/files_trashbin/l10n/bg_BG.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "Неуспешно възтановяване на %s.",
"Deleted files" : "Изтрити файлове",
"Restore" : "Възстановяви",
+ "Delete" : "Изтрий",
"Delete permanently" : "Изтрий завинаги",
"Error" : "Грешка",
"restored" : "възстановено",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "Няма намерени записи в тази папка",
"Select all" : "Избери всички",
"Name" : "Име",
- "Deleted" : "Изтрито",
- "Delete" : "Изтрий"
+ "Deleted" : "Изтрито"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/bg_BG.json b/apps/files_trashbin/l10n/bg_BG.json
index 3f3b3e8b835..824d1e44254 100644
--- a/apps/files_trashbin/l10n/bg_BG.json
+++ b/apps/files_trashbin/l10n/bg_BG.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "Неуспешно възтановяване на %s.",
"Deleted files" : "Изтрити файлове",
"Restore" : "Възстановяви",
+ "Delete" : "Изтрий",
"Delete permanently" : "Изтрий завинаги",
"Error" : "Грешка",
"restored" : "възстановено",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "Няма намерени записи в тази папка",
"Select all" : "Избери всички",
"Name" : "Име",
- "Deleted" : "Изтрито",
- "Delete" : "Изтрий"
+ "Deleted" : "Изтрито"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/bn_BD.js b/apps/files_trashbin/l10n/bn_BD.js
index 6f6626b71cc..12537a14afb 100644
--- a/apps/files_trashbin/l10n/bn_BD.js
+++ b/apps/files_trashbin/l10n/bn_BD.js
@@ -5,10 +5,10 @@ OC.L10N.register(
"Couldn't restore %s" : "%s ফেরত আনা গেলনা",
"Deleted files" : "মুছে ফেলা ফাইলসমূহ",
"Restore" : "ফিরিয়ে দাও",
+ "Delete" : "মুছে",
"Error" : "সমস্যা",
"restored" : "পূণঃসংরক্ষিত",
"Name" : "নাম",
- "Deleted" : "মুছে ফেলা",
- "Delete" : "মুছে"
+ "Deleted" : "মুছে ফেলা"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/bn_BD.json b/apps/files_trashbin/l10n/bn_BD.json
index affc277fcda..3630d490455 100644
--- a/apps/files_trashbin/l10n/bn_BD.json
+++ b/apps/files_trashbin/l10n/bn_BD.json
@@ -3,10 +3,10 @@
"Couldn't restore %s" : "%s ফেরত আনা গেলনা",
"Deleted files" : "মুছে ফেলা ফাইলসমূহ",
"Restore" : "ফিরিয়ে দাও",
+ "Delete" : "মুছে",
"Error" : "সমস্যা",
"restored" : "পূণঃসংরক্ষিত",
"Name" : "নাম",
- "Deleted" : "মুছে ফেলা",
- "Delete" : "মুছে"
+ "Deleted" : "মুছে ফেলা"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/bn_IN.js b/apps/files_trashbin/l10n/bn_IN.js
index 5943177a923..7c3bb37553a 100644
--- a/apps/files_trashbin/l10n/bn_IN.js
+++ b/apps/files_trashbin/l10n/bn_IN.js
@@ -5,11 +5,11 @@ OC.L10N.register(
"Couldn't restore %s" : "%s পুনরুদ্ধার করা যায়নি",
"Deleted files" : "ফাইলস মুছে ফেলা হয়েছে",
"Restore" : "পুনরুদ্ধার",
+ "Delete" : "মুছে ফেলা",
"Delete permanently" : "স্থায়ীভাবে মুছে দিন",
"Error" : "ভুল",
"restored" : "পুনরুদ্ধার করা হয়েছে",
"Name" : "নাম",
- "Deleted" : "মুছে ফেলা হয়েছে",
- "Delete" : "মুছে ফেলা"
+ "Deleted" : "মুছে ফেলা হয়েছে"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/bn_IN.json b/apps/files_trashbin/l10n/bn_IN.json
index 45a24ee7675..b7ae21692bf 100644
--- a/apps/files_trashbin/l10n/bn_IN.json
+++ b/apps/files_trashbin/l10n/bn_IN.json
@@ -3,11 +3,11 @@
"Couldn't restore %s" : "%s পুনরুদ্ধার করা যায়নি",
"Deleted files" : "ফাইলস মুছে ফেলা হয়েছে",
"Restore" : "পুনরুদ্ধার",
+ "Delete" : "মুছে ফেলা",
"Delete permanently" : "স্থায়ীভাবে মুছে দিন",
"Error" : "ভুল",
"restored" : "পুনরুদ্ধার করা হয়েছে",
"Name" : "নাম",
- "Deleted" : "মুছে ফেলা হয়েছে",
- "Delete" : "মুছে ফেলা"
+ "Deleted" : "মুছে ফেলা হয়েছে"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/bs.js b/apps/files_trashbin/l10n/bs.js
index 0378a76f855..c02d88b07e4 100644
--- a/apps/files_trashbin/l10n/bs.js
+++ b/apps/files_trashbin/l10n/bs.js
@@ -2,9 +2,9 @@ OC.L10N.register(
"files_trashbin",
{
"Restore" : "Obnovi",
+ "Delete" : "Izbriši",
"Error" : "Greška",
"Select all" : "Označi sve",
- "Name" : "Ime",
- "Delete" : "Izbriši"
+ "Name" : "Ime"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_trashbin/l10n/bs.json b/apps/files_trashbin/l10n/bs.json
index 6f222ca37af..00f1105abc6 100644
--- a/apps/files_trashbin/l10n/bs.json
+++ b/apps/files_trashbin/l10n/bs.json
@@ -1,8 +1,8 @@
{ "translations": {
"Restore" : "Obnovi",
+ "Delete" : "Izbriši",
"Error" : "Greška",
"Select all" : "Označi sve",
- "Name" : "Ime",
- "Delete" : "Izbriši"
+ "Name" : "Ime"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ca.js b/apps/files_trashbin/l10n/ca.js
index 356e525b73c..d5f19e466c1 100644
--- a/apps/files_trashbin/l10n/ca.js
+++ b/apps/files_trashbin/l10n/ca.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "No s'ha pogut restaurar %s",
"Deleted files" : "Fitxers esborrats",
"Restore" : "Recupera",
+ "Delete" : "Esborra",
"Delete permanently" : "Esborra permanentment",
"Error" : "Error",
"restored" : "restaurat",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "No hi ha entrades en aquesta carpeta",
"Select all" : "Seleccionar tot",
"Name" : "Nom",
- "Deleted" : "Eliminat",
- "Delete" : "Esborra"
+ "Deleted" : "Eliminat"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/ca.json b/apps/files_trashbin/l10n/ca.json
index dfdec62d7d1..520ef5f2f74 100644
--- a/apps/files_trashbin/l10n/ca.json
+++ b/apps/files_trashbin/l10n/ca.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "No s'ha pogut restaurar %s",
"Deleted files" : "Fitxers esborrats",
"Restore" : "Recupera",
+ "Delete" : "Esborra",
"Delete permanently" : "Esborra permanentment",
"Error" : "Error",
"restored" : "restaurat",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "No hi ha entrades en aquesta carpeta",
"Select all" : "Seleccionar tot",
"Name" : "Nom",
- "Deleted" : "Eliminat",
- "Delete" : "Esborra"
+ "Deleted" : "Eliminat"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/cs_CZ.js b/apps/files_trashbin/l10n/cs_CZ.js
index 4d0f9b7018d..22c33690420 100644
--- a/apps/files_trashbin/l10n/cs_CZ.js
+++ b/apps/files_trashbin/l10n/cs_CZ.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Nelze obnovit %s",
"Deleted files" : "Odstraněné soubory",
"Restore" : "Obnovit",
+ "Delete" : "Smazat",
"Delete permanently" : "Trvale odstranit",
"Error" : "Chyba",
+ "This operation is forbidden" : "Tato operace je zakázána",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Tento adresář není dostupný, zkontrolujte prosím logy nebo kontaktujte svého správce systému",
"restored" : "obnoveno",
"No deleted files" : "Žádné smazané soubory",
"You will be able to recover deleted files from here" : "Odtud budete moci obnovovat odstraněné soubory",
"No entries found in this folder" : "V této složce nebylo nic nalezeno",
"Select all" : "Vybrat vše",
"Name" : "Název",
- "Deleted" : "Smazáno",
- "Delete" : "Smazat"
+ "Deleted" : "Smazáno"
},
"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;");
diff --git a/apps/files_trashbin/l10n/cs_CZ.json b/apps/files_trashbin/l10n/cs_CZ.json
index cffa7b663fa..a4a13942fd1 100644
--- a/apps/files_trashbin/l10n/cs_CZ.json
+++ b/apps/files_trashbin/l10n/cs_CZ.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Nelze obnovit %s",
"Deleted files" : "Odstraněné soubory",
"Restore" : "Obnovit",
+ "Delete" : "Smazat",
"Delete permanently" : "Trvale odstranit",
"Error" : "Chyba",
+ "This operation is forbidden" : "Tato operace je zakázána",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Tento adresář není dostupný, zkontrolujte prosím logy nebo kontaktujte svého správce systému",
"restored" : "obnoveno",
"No deleted files" : "Žádné smazané soubory",
"You will be able to recover deleted files from here" : "Odtud budete moci obnovovat odstraněné soubory",
"No entries found in this folder" : "V této složce nebylo nic nalezeno",
"Select all" : "Vybrat vše",
"Name" : "Název",
- "Deleted" : "Smazáno",
- "Delete" : "Smazat"
+ "Deleted" : "Smazáno"
},"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/cy_GB.js b/apps/files_trashbin/l10n/cy_GB.js
index cd20621625f..e689aa9b52c 100644
--- a/apps/files_trashbin/l10n/cy_GB.js
+++ b/apps/files_trashbin/l10n/cy_GB.js
@@ -5,10 +5,10 @@ OC.L10N.register(
"Couldn't restore %s" : "Methwyd adfer %s",
"Deleted files" : "Ffeiliau ddilewyd",
"Restore" : "Adfer",
+ "Delete" : "Dileu",
"Delete permanently" : "Dileu'n barhaol",
"Error" : "Gwall",
"Name" : "Enw",
- "Deleted" : "Wedi dileu",
- "Delete" : "Dileu"
+ "Deleted" : "Wedi dileu"
},
"nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;");
diff --git a/apps/files_trashbin/l10n/cy_GB.json b/apps/files_trashbin/l10n/cy_GB.json
index 0f21da0c56d..c42ce3d10ea 100644
--- a/apps/files_trashbin/l10n/cy_GB.json
+++ b/apps/files_trashbin/l10n/cy_GB.json
@@ -3,10 +3,10 @@
"Couldn't restore %s" : "Methwyd adfer %s",
"Deleted files" : "Ffeiliau ddilewyd",
"Restore" : "Adfer",
+ "Delete" : "Dileu",
"Delete permanently" : "Dileu'n barhaol",
"Error" : "Gwall",
"Name" : "Enw",
- "Deleted" : "Wedi dileu",
- "Delete" : "Dileu"
+ "Deleted" : "Wedi dileu"
},"pluralForm" :"nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/da.js b/apps/files_trashbin/l10n/da.js
index dbcd566a9d2..6dcbd7040d1 100644
--- a/apps/files_trashbin/l10n/da.js
+++ b/apps/files_trashbin/l10n/da.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Kunne ikke gendanne %s",
"Deleted files" : "Slettede filer",
"Restore" : "Gendan",
+ "Delete" : "Slet",
"Delete permanently" : "Slet permanent",
"Error" : "Fejl",
+ "This operation is forbidden" : "Denne operation er forbudt",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Denne mappe er utilgængelig, tjek venligst loggene eller kontakt administratoren",
"restored" : "Gendannet",
"No deleted files" : "Ingen slettede filer",
"You will be able to recover deleted files from here" : "Du vil kunne gendanne slettede filer herfra",
"No entries found in this folder" : "Der blev ikke fundet poster i denne mappe",
"Select all" : "Vælg alle",
"Name" : "Navn",
- "Deleted" : "Slettet",
- "Delete" : "Slet"
+ "Deleted" : "Slettet"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/da.json b/apps/files_trashbin/l10n/da.json
index 0f660d2e44d..456b1ab73b2 100644
--- a/apps/files_trashbin/l10n/da.json
+++ b/apps/files_trashbin/l10n/da.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Kunne ikke gendanne %s",
"Deleted files" : "Slettede filer",
"Restore" : "Gendan",
+ "Delete" : "Slet",
"Delete permanently" : "Slet permanent",
"Error" : "Fejl",
+ "This operation is forbidden" : "Denne operation er forbudt",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Denne mappe er utilgængelig, tjek venligst loggene eller kontakt administratoren",
"restored" : "Gendannet",
"No deleted files" : "Ingen slettede filer",
"You will be able to recover deleted files from here" : "Du vil kunne gendanne slettede filer herfra",
"No entries found in this folder" : "Der blev ikke fundet poster i denne mappe",
"Select all" : "Vælg alle",
"Name" : "Navn",
- "Deleted" : "Slettet",
- "Delete" : "Slet"
+ "Deleted" : "Slettet"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/de.js b/apps/files_trashbin/l10n/de.js
index 96addde03b2..500205227c8 100644
--- a/apps/files_trashbin/l10n/de.js
+++ b/apps/files_trashbin/l10n/de.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Konnte %s nicht wiederherstellen",
"Deleted files" : "Gelöschte Dateien",
"Restore" : "Wiederherstellen",
+ "Delete" : "Löschen",
"Delete permanently" : "Endgültig löschen",
"Error" : "Fehler",
+ "This operation is forbidden" : "Diese Operation ist nicht erlaubt",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Dieses Verzeichnis ist nicht verfügbar, bitte überprüfe die Logdateien oder kontaktiere den Administrator",
"restored" : "Wiederhergestellt",
"No deleted files" : "Keine gelöschten Dateien",
"You will be able to recover deleted files from here" : "Du kannst hier gelöschte Dateien wiederherstellen",
"No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden",
"Select all" : "Alle auswählen",
"Name" : "Name",
- "Deleted" : "gelöscht",
- "Delete" : "Löschen"
+ "Deleted" : "gelöscht"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/de.json b/apps/files_trashbin/l10n/de.json
index d7b9b07b87e..baa976b6ff3 100644
--- a/apps/files_trashbin/l10n/de.json
+++ b/apps/files_trashbin/l10n/de.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Konnte %s nicht wiederherstellen",
"Deleted files" : "Gelöschte Dateien",
"Restore" : "Wiederherstellen",
+ "Delete" : "Löschen",
"Delete permanently" : "Endgültig löschen",
"Error" : "Fehler",
+ "This operation is forbidden" : "Diese Operation ist nicht erlaubt",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Dieses Verzeichnis ist nicht verfügbar, bitte überprüfe die Logdateien oder kontaktiere den Administrator",
"restored" : "Wiederhergestellt",
"No deleted files" : "Keine gelöschten Dateien",
"You will be able to recover deleted files from here" : "Du kannst hier gelöschte Dateien wiederherstellen",
"No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden",
"Select all" : "Alle auswählen",
"Name" : "Name",
- "Deleted" : "gelöscht",
- "Delete" : "Löschen"
+ "Deleted" : "gelöscht"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/de_AT.js b/apps/files_trashbin/l10n/de_AT.js
index db1e7544a5b..5d1a6cec445 100644
--- a/apps/files_trashbin/l10n/de_AT.js
+++ b/apps/files_trashbin/l10n/de_AT.js
@@ -1,7 +1,7 @@
OC.L10N.register(
"files_trashbin",
{
- "Error" : "Fehler",
- "Delete" : "Löschen"
+ "Delete" : "Löschen",
+ "Error" : "Fehler"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/de_AT.json b/apps/files_trashbin/l10n/de_AT.json
index a854415701f..5452cc8972a 100644
--- a/apps/files_trashbin/l10n/de_AT.json
+++ b/apps/files_trashbin/l10n/de_AT.json
@@ -1,5 +1,5 @@
{ "translations": {
- "Error" : "Fehler",
- "Delete" : "Löschen"
+ "Delete" : "Löschen",
+ "Error" : "Fehler"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/de_DE.js b/apps/files_trashbin/l10n/de_DE.js
index c25166efc80..84a2c382efa 100644
--- a/apps/files_trashbin/l10n/de_DE.js
+++ b/apps/files_trashbin/l10n/de_DE.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Konnte %s nicht wiederherstellen",
"Deleted files" : "Gelöschte Dateien",
"Restore" : "Wiederherstellen",
+ "Delete" : "Löschen",
"Delete permanently" : "Endgültig löschen",
"Error" : "Fehler",
+ "This operation is forbidden" : "Diese Operation ist nicht erlaubt",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Dieses Verzeichnis ist nicht verfügbar, bitte überprüfen Sie die Logdateien oder kontaktieren Sie den Administrator",
"restored" : "Wiederhergestellt",
"No deleted files" : "Keine gelöschten Dateien",
"You will be able to recover deleted files from here" : "Sie können hier gelöschte Dateien wiederherstellen",
"No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden",
"Select all" : "Alle auswählen",
"Name" : "Name",
- "Deleted" : "Gelöscht",
- "Delete" : "Löschen"
+ "Deleted" : "Gelöscht"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/de_DE.json b/apps/files_trashbin/l10n/de_DE.json
index 9f4a895fa16..966461efee3 100644
--- a/apps/files_trashbin/l10n/de_DE.json
+++ b/apps/files_trashbin/l10n/de_DE.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Konnte %s nicht wiederherstellen",
"Deleted files" : "Gelöschte Dateien",
"Restore" : "Wiederherstellen",
+ "Delete" : "Löschen",
"Delete permanently" : "Endgültig löschen",
"Error" : "Fehler",
+ "This operation is forbidden" : "Diese Operation ist nicht erlaubt",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Dieses Verzeichnis ist nicht verfügbar, bitte überprüfen Sie die Logdateien oder kontaktieren Sie den Administrator",
"restored" : "Wiederhergestellt",
"No deleted files" : "Keine gelöschten Dateien",
"You will be able to recover deleted files from here" : "Sie können hier gelöschte Dateien wiederherstellen",
"No entries found in this folder" : "Keine Einträge in diesem Ordner gefunden",
"Select all" : "Alle auswählen",
"Name" : "Name",
- "Deleted" : "Gelöscht",
- "Delete" : "Löschen"
+ "Deleted" : "Gelöscht"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/el.js b/apps/files_trashbin/l10n/el.js
index 8abbdb85b48..d63dc09c745 100644
--- a/apps/files_trashbin/l10n/el.js
+++ b/apps/files_trashbin/l10n/el.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Αδυναμία επαναφοράς %s",
"Deleted files" : "Διεγραμμένα αρχεία",
"Restore" : "Επαναφορά",
+ "Delete" : "Διαγραφή",
"Delete permanently" : "Μόνιμη διαγραφή",
"Error" : "Σφάλμα",
+ "This operation is forbidden" : "Αυτή η ενέργεια δεν επιτρέπεται",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Ο κατάλογος δεν είναι διαθέσιμος, παρακαλώ ελέγξτε τα αρχεία καταγραφής ή επικοινωνήστε με το διαχειριστή",
"restored" : "επαναφέρθηκαν",
"No deleted files" : "Κανένα διαγεγραμμένο αρχείο",
"You will be able to recover deleted files from here" : "Θα έχετε την δυνατότητα επαναφοράς διαγεγραμμένων αρχείων από εδώ",
"No entries found in this folder" : "Δεν βρέθηκαν καταχωρήσεις σε αυτόν το φάκελο",
"Select all" : "Επιλογή όλων",
"Name" : "Όνομα",
- "Deleted" : "Διαγραμμένα",
- "Delete" : "Διαγραφή"
+ "Deleted" : "Διαγραμμένα"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/el.json b/apps/files_trashbin/l10n/el.json
index eb52020a3e1..5d0ad857d35 100644
--- a/apps/files_trashbin/l10n/el.json
+++ b/apps/files_trashbin/l10n/el.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Αδυναμία επαναφοράς %s",
"Deleted files" : "Διεγραμμένα αρχεία",
"Restore" : "Επαναφορά",
+ "Delete" : "Διαγραφή",
"Delete permanently" : "Μόνιμη διαγραφή",
"Error" : "Σφάλμα",
+ "This operation is forbidden" : "Αυτή η ενέργεια δεν επιτρέπεται",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Ο κατάλογος δεν είναι διαθέσιμος, παρακαλώ ελέγξτε τα αρχεία καταγραφής ή επικοινωνήστε με το διαχειριστή",
"restored" : "επαναφέρθηκαν",
"No deleted files" : "Κανένα διαγεγραμμένο αρχείο",
"You will be able to recover deleted files from here" : "Θα έχετε την δυνατότητα επαναφοράς διαγεγραμμένων αρχείων από εδώ",
"No entries found in this folder" : "Δεν βρέθηκαν καταχωρήσεις σε αυτόν το φάκελο",
"Select all" : "Επιλογή όλων",
"Name" : "Όνομα",
- "Deleted" : "Διαγραμμένα",
- "Delete" : "Διαγραφή"
+ "Deleted" : "Διαγραμμένα"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/en_GB.js b/apps/files_trashbin/l10n/en_GB.js
index e2ff4ac73fb..e3f3b78af57 100644
--- a/apps/files_trashbin/l10n/en_GB.js
+++ b/apps/files_trashbin/l10n/en_GB.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "Couldn't restore %s",
"Deleted files" : "Deleted files",
"Restore" : "Restore",
+ "Delete" : "Delete",
"Delete permanently" : "Delete permanently",
"Error" : "Error",
"restored" : "restored",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "No entries found in this folder",
"Select all" : "Select all",
"Name" : "Name",
- "Deleted" : "Deleted",
- "Delete" : "Delete"
+ "Deleted" : "Deleted"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/en_GB.json b/apps/files_trashbin/l10n/en_GB.json
index 078bca97a49..9c533523889 100644
--- a/apps/files_trashbin/l10n/en_GB.json
+++ b/apps/files_trashbin/l10n/en_GB.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "Couldn't restore %s",
"Deleted files" : "Deleted files",
"Restore" : "Restore",
+ "Delete" : "Delete",
"Delete permanently" : "Delete permanently",
"Error" : "Error",
"restored" : "restored",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "No entries found in this folder",
"Select all" : "Select all",
"Name" : "Name",
- "Deleted" : "Deleted",
- "Delete" : "Delete"
+ "Deleted" : "Deleted"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/eo.js b/apps/files_trashbin/l10n/eo.js
index 95edf8d3eb0..b4ab12d4bdd 100644
--- a/apps/files_trashbin/l10n/eo.js
+++ b/apps/files_trashbin/l10n/eo.js
@@ -5,12 +5,12 @@ OC.L10N.register(
"Couldn't restore %s" : "Ne povis restaŭriĝi %s",
"Deleted files" : "Forigitaj dosieroj",
"Restore" : "Restaŭri",
+ "Delete" : "Forigi",
"Delete permanently" : "Forigi por ĉiam",
"Error" : "Eraro",
"restored" : "restaŭrita",
"Select all" : "Elekti ĉion",
"Name" : "Nomo",
- "Deleted" : "Forigita",
- "Delete" : "Forigi"
+ "Deleted" : "Forigita"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/eo.json b/apps/files_trashbin/l10n/eo.json
index 7fd1d85ff7a..87a9b7d479b 100644
--- a/apps/files_trashbin/l10n/eo.json
+++ b/apps/files_trashbin/l10n/eo.json
@@ -3,12 +3,12 @@
"Couldn't restore %s" : "Ne povis restaŭriĝi %s",
"Deleted files" : "Forigitaj dosieroj",
"Restore" : "Restaŭri",
+ "Delete" : "Forigi",
"Delete permanently" : "Forigi por ĉiam",
"Error" : "Eraro",
"restored" : "restaŭrita",
"Select all" : "Elekti ĉion",
"Name" : "Nomo",
- "Deleted" : "Forigita",
- "Delete" : "Forigi"
+ "Deleted" : "Forigita"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/es.js b/apps/files_trashbin/l10n/es.js
index b7f1a52327a..7cc67ce1945 100644
--- a/apps/files_trashbin/l10n/es.js
+++ b/apps/files_trashbin/l10n/es.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "No se puede restaurar %s",
"Deleted files" : "Archivos eliminados",
"Restore" : "Recuperar",
+ "Delete" : "Eliminar",
"Delete permanently" : "Eliminar permanentemente",
"Error" : "Error",
+ "This operation is forbidden" : "Esta operación está prohibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Esta carpeta no está disponible, por favor verifique los registros o contáctese con el administrador",
"restored" : "recuperado",
"No deleted files" : "No hay ningún archivo eliminado",
"You will be able to recover deleted files from here" : "Desde aquí se podrán recuperar archivos eliminados",
"No entries found in this folder" : "No hay entradas en esta carpeta",
"Select all" : "Seleccionar todo",
"Name" : "Nombre",
- "Deleted" : "Eliminado",
- "Delete" : "Eliminar"
+ "Deleted" : "Eliminado"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/es.json b/apps/files_trashbin/l10n/es.json
index c55ae652d55..05f3dfa20b8 100644
--- a/apps/files_trashbin/l10n/es.json
+++ b/apps/files_trashbin/l10n/es.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "No se puede restaurar %s",
"Deleted files" : "Archivos eliminados",
"Restore" : "Recuperar",
+ "Delete" : "Eliminar",
"Delete permanently" : "Eliminar permanentemente",
"Error" : "Error",
+ "This operation is forbidden" : "Esta operación está prohibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Esta carpeta no está disponible, por favor verifique los registros o contáctese con el administrador",
"restored" : "recuperado",
"No deleted files" : "No hay ningún archivo eliminado",
"You will be able to recover deleted files from here" : "Desde aquí se podrán recuperar archivos eliminados",
"No entries found in this folder" : "No hay entradas en esta carpeta",
"Select all" : "Seleccionar todo",
"Name" : "Nombre",
- "Deleted" : "Eliminado",
- "Delete" : "Eliminar"
+ "Deleted" : "Eliminado"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/es_AR.js b/apps/files_trashbin/l10n/es_AR.js
index b9566c17f1f..e916fc98f04 100644
--- a/apps/files_trashbin/l10n/es_AR.js
+++ b/apps/files_trashbin/l10n/es_AR.js
@@ -5,11 +5,11 @@ OC.L10N.register(
"Couldn't restore %s" : "No se pudo restaurar %s",
"Deleted files" : "Archivos borrados",
"Restore" : "Recuperar",
+ "Delete" : "Borrar",
"Delete permanently" : "Borrar permanentemente",
"Error" : "Error",
"restored" : "recuperado",
"Name" : "Nombre",
- "Deleted" : "Borrado",
- "Delete" : "Borrar"
+ "Deleted" : "Borrado"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/es_AR.json b/apps/files_trashbin/l10n/es_AR.json
index c3de7177ef6..41ad13d0ba2 100644
--- a/apps/files_trashbin/l10n/es_AR.json
+++ b/apps/files_trashbin/l10n/es_AR.json
@@ -3,11 +3,11 @@
"Couldn't restore %s" : "No se pudo restaurar %s",
"Deleted files" : "Archivos borrados",
"Restore" : "Recuperar",
+ "Delete" : "Borrar",
"Delete permanently" : "Borrar permanentemente",
"Error" : "Error",
"restored" : "recuperado",
"Name" : "Nombre",
- "Deleted" : "Borrado",
- "Delete" : "Borrar"
+ "Deleted" : "Borrado"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/es_MX.js b/apps/files_trashbin/l10n/es_MX.js
index 0a53f9cffdf..109427e9d80 100644
--- a/apps/files_trashbin/l10n/es_MX.js
+++ b/apps/files_trashbin/l10n/es_MX.js
@@ -5,11 +5,11 @@ OC.L10N.register(
"Couldn't restore %s" : "No se puede restaurar %s",
"Deleted files" : "Archivos eliminados",
"Restore" : "Recuperar",
+ "Delete" : "Eliminar",
"Delete permanently" : "Eliminar permanentemente",
"Error" : "Error",
"restored" : "recuperado",
"Name" : "Nombre",
- "Deleted" : "Eliminado",
- "Delete" : "Eliminar"
+ "Deleted" : "Eliminado"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/es_MX.json b/apps/files_trashbin/l10n/es_MX.json
index 56dce90e07d..a1bbba28cde 100644
--- a/apps/files_trashbin/l10n/es_MX.json
+++ b/apps/files_trashbin/l10n/es_MX.json
@@ -3,11 +3,11 @@
"Couldn't restore %s" : "No se puede restaurar %s",
"Deleted files" : "Archivos eliminados",
"Restore" : "Recuperar",
+ "Delete" : "Eliminar",
"Delete permanently" : "Eliminar permanentemente",
"Error" : "Error",
"restored" : "recuperado",
"Name" : "Nombre",
- "Deleted" : "Eliminado",
- "Delete" : "Eliminar"
+ "Deleted" : "Eliminado"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/et_EE.js b/apps/files_trashbin/l10n/et_EE.js
index 9298fdd5b18..3f928dede8d 100644
--- a/apps/files_trashbin/l10n/et_EE.js
+++ b/apps/files_trashbin/l10n/et_EE.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "%s ei saa taastada",
"Deleted files" : "Kustutatud failid",
"Restore" : "Taasta",
+ "Delete" : "Kustuta",
"Delete permanently" : "Kustuta jäädavalt",
"Error" : "Viga",
+ "This operation is forbidden" : "See toiming on keelatud",
+ "This directory is unavailable, please check the logs or contact the administrator" : "See kaust pole saadaval. Palun kontrolli logifaile või võta ühendust administraatoriga",
"restored" : "taastatud",
"No deleted files" : "Kustutatud faile pole",
"You will be able to recover deleted files from here" : "Sa saad siit kustutatud faile taastada",
"No entries found in this folder" : "Selles kaustas ei leitud kirjeid",
"Select all" : "Vali kõik",
"Name" : "Nimi",
- "Deleted" : "Kustutatud",
- "Delete" : "Kustuta"
+ "Deleted" : "Kustutatud"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/et_EE.json b/apps/files_trashbin/l10n/et_EE.json
index 734c8f6f2ec..468a3bcb385 100644
--- a/apps/files_trashbin/l10n/et_EE.json
+++ b/apps/files_trashbin/l10n/et_EE.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "%s ei saa taastada",
"Deleted files" : "Kustutatud failid",
"Restore" : "Taasta",
+ "Delete" : "Kustuta",
"Delete permanently" : "Kustuta jäädavalt",
"Error" : "Viga",
+ "This operation is forbidden" : "See toiming on keelatud",
+ "This directory is unavailable, please check the logs or contact the administrator" : "See kaust pole saadaval. Palun kontrolli logifaile või võta ühendust administraatoriga",
"restored" : "taastatud",
"No deleted files" : "Kustutatud faile pole",
"You will be able to recover deleted files from here" : "Sa saad siit kustutatud faile taastada",
"No entries found in this folder" : "Selles kaustas ei leitud kirjeid",
"Select all" : "Vali kõik",
"Name" : "Nimi",
- "Deleted" : "Kustutatud",
- "Delete" : "Kustuta"
+ "Deleted" : "Kustutatud"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/eu.js b/apps/files_trashbin/l10n/eu.js
index 568fda14450..5db27f0a9c6 100644
--- a/apps/files_trashbin/l10n/eu.js
+++ b/apps/files_trashbin/l10n/eu.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "Ezin izan da %s berreskuratu",
"Deleted files" : "Ezabatutako fitxategiak",
"Restore" : "Berrezarri",
+ "Delete" : "Ezabatu",
"Delete permanently" : "Ezabatu betirako",
"Error" : "Errorea",
"restored" : "Berrezarrita",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "Ez da sarrerarik aurkitu karpeta honetan",
"Select all" : "Hautatu dena",
"Name" : "Izena",
- "Deleted" : "Ezabatuta",
- "Delete" : "Ezabatu"
+ "Deleted" : "Ezabatuta"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/eu.json b/apps/files_trashbin/l10n/eu.json
index 890ff07a468..07591e6b5d6 100644
--- a/apps/files_trashbin/l10n/eu.json
+++ b/apps/files_trashbin/l10n/eu.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "Ezin izan da %s berreskuratu",
"Deleted files" : "Ezabatutako fitxategiak",
"Restore" : "Berrezarri",
+ "Delete" : "Ezabatu",
"Delete permanently" : "Ezabatu betirako",
"Error" : "Errorea",
"restored" : "Berrezarrita",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "Ez da sarrerarik aurkitu karpeta honetan",
"Select all" : "Hautatu dena",
"Name" : "Izena",
- "Deleted" : "Ezabatuta",
- "Delete" : "Ezabatu"
+ "Deleted" : "Ezabatuta"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/fa.js b/apps/files_trashbin/l10n/fa.js
index 28aa38a96a6..281851c65a0 100644
--- a/apps/files_trashbin/l10n/fa.js
+++ b/apps/files_trashbin/l10n/fa.js
@@ -8,6 +8,8 @@ OC.L10N.register(
"Delete" : "حذف",
"Delete permanently" : "حذف قطعی",
"Error" : "خطا",
+ "This operation is forbidden" : "این عملیات غیرمجاز است",
+ "This directory is unavailable, please check the logs or contact the administrator" : "پوشه‌ در دسترس نیست، لطفا لاگ‌ها را بررسی کنید یا به مدیر سیستم اطلاع دهید",
"restored" : "بازیابی شد",
"No entries found in this folder" : "هیچ ورودی‌ای در این پوشه وجود ندارد",
"Select all" : "انتخاب همه",
diff --git a/apps/files_trashbin/l10n/fa.json b/apps/files_trashbin/l10n/fa.json
index d8641316f44..08bee906d38 100644
--- a/apps/files_trashbin/l10n/fa.json
+++ b/apps/files_trashbin/l10n/fa.json
@@ -6,6 +6,8 @@
"Delete" : "حذف",
"Delete permanently" : "حذف قطعی",
"Error" : "خطا",
+ "This operation is forbidden" : "این عملیات غیرمجاز است",
+ "This directory is unavailable, please check the logs or contact the administrator" : "پوشه‌ در دسترس نیست، لطفا لاگ‌ها را بررسی کنید یا به مدیر سیستم اطلاع دهید",
"restored" : "بازیابی شد",
"No entries found in this folder" : "هیچ ورودی‌ای در این پوشه وجود ندارد",
"Select all" : "انتخاب همه",
diff --git a/apps/files_trashbin/l10n/fi_FI.js b/apps/files_trashbin/l10n/fi_FI.js
index be3fbad301f..a8758c77050 100644
--- a/apps/files_trashbin/l10n/fi_FI.js
+++ b/apps/files_trashbin/l10n/fi_FI.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Kohteen %s palautus epäonnistui",
"Deleted files" : "Poistetut tiedostot",
"Restore" : "Palauta",
+ "Delete" : "Poista",
"Delete permanently" : "Poista pysyvästi",
"Error" : "Virhe",
+ "This operation is forbidden" : "Tämä toiminto on kielletty",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Hakemisto ei ole käytettävissä. Tarkista lokit tai ole yhteydessä ylläpitoon.",
"restored" : "palautettu",
"No deleted files" : "Ei poistettuja tiedostoja",
"You will be able to recover deleted files from here" : "Voit palauttaa poistettuja tiedostoja tätä kautta",
"No entries found in this folder" : "Ei kohteita tässä kansiossa",
"Select all" : "Valitse kaikki",
"Name" : "Nimi",
- "Deleted" : "Poistettu",
- "Delete" : "Poista"
+ "Deleted" : "Poistettu"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/fi_FI.json b/apps/files_trashbin/l10n/fi_FI.json
index 3e22acdf2c9..c4ead30d036 100644
--- a/apps/files_trashbin/l10n/fi_FI.json
+++ b/apps/files_trashbin/l10n/fi_FI.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Kohteen %s palautus epäonnistui",
"Deleted files" : "Poistetut tiedostot",
"Restore" : "Palauta",
+ "Delete" : "Poista",
"Delete permanently" : "Poista pysyvästi",
"Error" : "Virhe",
+ "This operation is forbidden" : "Tämä toiminto on kielletty",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Hakemisto ei ole käytettävissä. Tarkista lokit tai ole yhteydessä ylläpitoon.",
"restored" : "palautettu",
"No deleted files" : "Ei poistettuja tiedostoja",
"You will be able to recover deleted files from here" : "Voit palauttaa poistettuja tiedostoja tätä kautta",
"No entries found in this folder" : "Ei kohteita tässä kansiossa",
"Select all" : "Valitse kaikki",
"Name" : "Nimi",
- "Deleted" : "Poistettu",
- "Delete" : "Poista"
+ "Deleted" : "Poistettu"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/fr.js b/apps/files_trashbin/l10n/fr.js
index 573977570a7..402644ecdb2 100644
--- a/apps/files_trashbin/l10n/fr.js
+++ b/apps/files_trashbin/l10n/fr.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Impossible de restaurer %s",
"Deleted files" : "Fichiers supprimés",
"Restore" : "Restaurer",
+ "Delete" : "Supprimer",
"Delete permanently" : "Supprimer de façon définitive",
"Error" : "Erreur",
+ "This operation is forbidden" : "Cette opération est interdite",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Ce répertoire n'est pas disponible. Consultez les logs ou contactez votre administrateur",
"restored" : "restauré",
"No deleted files" : "Aucun fichier supprimé",
"You will be able to recover deleted files from here" : "Vous pourrez restaurer vos fichiers supprimés ici",
"No entries found in this folder" : "Aucune entrée trouvée dans ce dossier",
"Select all" : "Tout sélectionner",
"Name" : "Nom",
- "Deleted" : "Effacé",
- "Delete" : "Supprimer"
+ "Deleted" : "Effacé"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files_trashbin/l10n/fr.json b/apps/files_trashbin/l10n/fr.json
index f4525b9d079..029c6bab0b5 100644
--- a/apps/files_trashbin/l10n/fr.json
+++ b/apps/files_trashbin/l10n/fr.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Impossible de restaurer %s",
"Deleted files" : "Fichiers supprimés",
"Restore" : "Restaurer",
+ "Delete" : "Supprimer",
"Delete permanently" : "Supprimer de façon définitive",
"Error" : "Erreur",
+ "This operation is forbidden" : "Cette opération est interdite",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Ce répertoire n'est pas disponible. Consultez les logs ou contactez votre administrateur",
"restored" : "restauré",
"No deleted files" : "Aucun fichier supprimé",
"You will be able to recover deleted files from here" : "Vous pourrez restaurer vos fichiers supprimés ici",
"No entries found in this folder" : "Aucune entrée trouvée dans ce dossier",
"Select all" : "Tout sélectionner",
"Name" : "Nom",
- "Deleted" : "Effacé",
- "Delete" : "Supprimer"
+ "Deleted" : "Effacé"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/gl.js b/apps/files_trashbin/l10n/gl.js
index a6ea37031a0..52ce23875a0 100644
--- a/apps/files_trashbin/l10n/gl.js
+++ b/apps/files_trashbin/l10n/gl.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Non foi posíbel restaurar %s",
"Deleted files" : "Ficheiros eliminados",
"Restore" : "Restabelecer",
+ "Delete" : "Eliminar",
"Delete permanently" : "Eliminar permanentemente",
"Error" : "Erro",
+ "This operation is forbidden" : "Esta operación está prohibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Este directorio non está dispoñíbel, comprobe os rexistros ou póñase en contacto co administrador",
"restored" : "restaurado",
"No deleted files" : "Non hai ficheiros eliminados",
"You will be able to recover deleted files from here" : "Poderá recuperar ficheiros borrados de aquí",
"No entries found in this folder" : "Non se atoparon entradas neste cartafol",
"Select all" : "Seleccionar todo",
"Name" : "Nome",
- "Deleted" : "Eliminado",
- "Delete" : "Eliminar"
+ "Deleted" : "Eliminado"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/gl.json b/apps/files_trashbin/l10n/gl.json
index da3aa55fa3f..89df0d2813f 100644
--- a/apps/files_trashbin/l10n/gl.json
+++ b/apps/files_trashbin/l10n/gl.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Non foi posíbel restaurar %s",
"Deleted files" : "Ficheiros eliminados",
"Restore" : "Restabelecer",
+ "Delete" : "Eliminar",
"Delete permanently" : "Eliminar permanentemente",
"Error" : "Erro",
+ "This operation is forbidden" : "Esta operación está prohibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Este directorio non está dispoñíbel, comprobe os rexistros ou póñase en contacto co administrador",
"restored" : "restaurado",
"No deleted files" : "Non hai ficheiros eliminados",
"You will be able to recover deleted files from here" : "Poderá recuperar ficheiros borrados de aquí",
"No entries found in this folder" : "Non se atoparon entradas neste cartafol",
"Select all" : "Seleccionar todo",
"Name" : "Nome",
- "Deleted" : "Eliminado",
- "Delete" : "Eliminar"
+ "Deleted" : "Eliminado"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/he.js b/apps/files_trashbin/l10n/he.js
index 95e5f391151..e2104b9b570 100644
--- a/apps/files_trashbin/l10n/he.js
+++ b/apps/files_trashbin/l10n/he.js
@@ -5,11 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "לא ניתן לשחזר את %s",
"Deleted files" : "קבצים שנמחקו",
"Restore" : "שחזור",
+ "Delete" : "מחיקה",
"Delete permanently" : "מחיקה לצמיתות",
"Error" : "שגיאה",
+ "This operation is forbidden" : "פעולה זו אסורה",
+ "This directory is unavailable, please check the logs or contact the administrator" : "תיקייה זו לא קיימת, יש לבדוק את הלוגים או ליצור קשר עם המנהל",
"restored" : "שוחזר",
+ "No deleted files" : "אין קבצים שנמחקו",
+ "You will be able to recover deleted files from here" : "ניתן לבטל מחיקת קבצים מכאן",
+ "No entries found in this folder" : "לא נמצאו כניסות לתיקייה זו",
+ "Select all" : "לבחור הכול",
"Name" : "שם",
- "Deleted" : "נמחק",
- "Delete" : "מחיקה"
+ "Deleted" : "נמחק"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/he.json b/apps/files_trashbin/l10n/he.json
index 68f38e819ff..c76079b0d34 100644
--- a/apps/files_trashbin/l10n/he.json
+++ b/apps/files_trashbin/l10n/he.json
@@ -3,11 +3,17 @@
"Couldn't restore %s" : "לא ניתן לשחזר את %s",
"Deleted files" : "קבצים שנמחקו",
"Restore" : "שחזור",
+ "Delete" : "מחיקה",
"Delete permanently" : "מחיקה לצמיתות",
"Error" : "שגיאה",
+ "This operation is forbidden" : "פעולה זו אסורה",
+ "This directory is unavailable, please check the logs or contact the administrator" : "תיקייה זו לא קיימת, יש לבדוק את הלוגים או ליצור קשר עם המנהל",
"restored" : "שוחזר",
+ "No deleted files" : "אין קבצים שנמחקו",
+ "You will be able to recover deleted files from here" : "ניתן לבטל מחיקת קבצים מכאן",
+ "No entries found in this folder" : "לא נמצאו כניסות לתיקייה זו",
+ "Select all" : "לבחור הכול",
"Name" : "שם",
- "Deleted" : "נמחק",
- "Delete" : "מחיקה"
+ "Deleted" : "נמחק"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/hr.js b/apps/files_trashbin/l10n/hr.js
index 89db9a16b98..476b0938c77 100644
--- a/apps/files_trashbin/l10n/hr.js
+++ b/apps/files_trashbin/l10n/hr.js
@@ -5,13 +5,13 @@ OC.L10N.register(
"Couldn't restore %s" : "Nije moguće obnoviti %s",
"Deleted files" : "Izbrisane datoteke",
"Restore" : "Obnovite",
+ "Delete" : "Izbrišite",
"Delete permanently" : "Trajno izbrišite",
"Error" : "Pogreška",
"restored" : "Obnovljeno",
"No entries found in this folder" : "Zapis nije pronadjen u ovom direktorijumu ",
"Select all" : "Selektiraj sve",
"Name" : "Naziv",
- "Deleted" : "Izbrisano",
- "Delete" : "Izbrišite"
+ "Deleted" : "Izbrisano"
},
"nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;");
diff --git a/apps/files_trashbin/l10n/hr.json b/apps/files_trashbin/l10n/hr.json
index d74addf2ca7..877d486fb80 100644
--- a/apps/files_trashbin/l10n/hr.json
+++ b/apps/files_trashbin/l10n/hr.json
@@ -3,13 +3,13 @@
"Couldn't restore %s" : "Nije moguće obnoviti %s",
"Deleted files" : "Izbrisane datoteke",
"Restore" : "Obnovite",
+ "Delete" : "Izbrišite",
"Delete permanently" : "Trajno izbrišite",
"Error" : "Pogreška",
"restored" : "Obnovljeno",
"No entries found in this folder" : "Zapis nije pronadjen u ovom direktorijumu ",
"Select all" : "Selektiraj sve",
"Name" : "Naziv",
- "Deleted" : "Izbrisano",
- "Delete" : "Izbrišite"
+ "Deleted" : "Izbrisano"
},"pluralForm" :"nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/hu_HU.js b/apps/files_trashbin/l10n/hu_HU.js
index 0df2816a312..5fac34bbb2d 100644
--- a/apps/files_trashbin/l10n/hu_HU.js
+++ b/apps/files_trashbin/l10n/hu_HU.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Nem sikerült %s visszaállítása",
"Deleted files" : "Törölt fájlok",
"Restore" : "Visszaállítás",
+ "Delete" : "Törlés",
"Delete permanently" : "Végleges törlés",
"Error" : "Hiba",
+ "This operation is forbidden" : "Tiltott művelet",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Ez a könyvtár nem elérhető, kérem nézze meg a naplófájlokat vagy keresse az adminisztrátort",
"restored" : "visszaállítva",
"No deleted files" : "Nincs törölt fájl",
"You will be able to recover deleted files from here" : "Innen vissza tudja állítani a törölt fáljait.",
"No entries found in this folder" : "Nincsenek bejegyzések ebben a könyvtárban",
"Select all" : "Összes kijelölése",
"Name" : "Név",
- "Deleted" : "Törölve",
- "Delete" : "Törlés"
+ "Deleted" : "Törölve"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/hu_HU.json b/apps/files_trashbin/l10n/hu_HU.json
index 331cd210721..866c885a5d8 100644
--- a/apps/files_trashbin/l10n/hu_HU.json
+++ b/apps/files_trashbin/l10n/hu_HU.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Nem sikerült %s visszaállítása",
"Deleted files" : "Törölt fájlok",
"Restore" : "Visszaállítás",
+ "Delete" : "Törlés",
"Delete permanently" : "Végleges törlés",
"Error" : "Hiba",
+ "This operation is forbidden" : "Tiltott művelet",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Ez a könyvtár nem elérhető, kérem nézze meg a naplófájlokat vagy keresse az adminisztrátort",
"restored" : "visszaállítva",
"No deleted files" : "Nincs törölt fájl",
"You will be able to recover deleted files from here" : "Innen vissza tudja állítani a törölt fáljait.",
"No entries found in this folder" : "Nincsenek bejegyzések ebben a könyvtárban",
"Select all" : "Összes kijelölése",
"Name" : "Név",
- "Deleted" : "Törölve",
- "Delete" : "Törlés"
+ "Deleted" : "Törölve"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/hy.js b/apps/files_trashbin/l10n/hy.js
index 3cc05b39236..39e49b47ae1 100644
--- a/apps/files_trashbin/l10n/hy.js
+++ b/apps/files_trashbin/l10n/hy.js
@@ -5,8 +5,10 @@ OC.L10N.register(
"Restore" : "Վերականգնել",
"Delete" : "Ջնջել",
"Delete permanently" : "Ջնջել ընդմիշտ",
+ "Error" : "Սխալ",
"No deleted files" : "Ջնջված ֆայլեր չկան",
"Select all" : "Նշել բոլորը",
- "Name" : "Անուն"
+ "Name" : "Անուն",
+ "Deleted" : "Ջնջված"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/hy.json b/apps/files_trashbin/l10n/hy.json
index 994d6afaa58..4bd34056b3f 100644
--- a/apps/files_trashbin/l10n/hy.json
+++ b/apps/files_trashbin/l10n/hy.json
@@ -3,8 +3,10 @@
"Restore" : "Վերականգնել",
"Delete" : "Ջնջել",
"Delete permanently" : "Ջնջել ընդմիշտ",
+ "Error" : "Սխալ",
"No deleted files" : "Ջնջված ֆայլեր չկան",
"Select all" : "Նշել բոլորը",
- "Name" : "Անուն"
+ "Name" : "Անուն",
+ "Deleted" : "Ջնջված"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ia.js b/apps/files_trashbin/l10n/ia.js
index 1ae952f8c9b..04e773a81bc 100644
--- a/apps/files_trashbin/l10n/ia.js
+++ b/apps/files_trashbin/l10n/ia.js
@@ -1,8 +1,8 @@
OC.L10N.register(
"files_trashbin",
{
+ "Delete" : "Deler",
"Error" : "Error",
- "Name" : "Nomine",
- "Delete" : "Deler"
+ "Name" : "Nomine"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/ia.json b/apps/files_trashbin/l10n/ia.json
index 909e6dfe769..fa4d526c849 100644
--- a/apps/files_trashbin/l10n/ia.json
+++ b/apps/files_trashbin/l10n/ia.json
@@ -1,6 +1,6 @@
{ "translations": {
+ "Delete" : "Deler",
"Error" : "Error",
- "Name" : "Nomine",
- "Delete" : "Deler"
+ "Name" : "Nomine"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/id.js b/apps/files_trashbin/l10n/id.js
index 53827980ea9..499e1211e59 100644
--- a/apps/files_trashbin/l10n/id.js
+++ b/apps/files_trashbin/l10n/id.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Tidak dapat memulihkan %s",
"Deleted files" : "Berkas yang dihapus",
"Restore" : "Pulihkan",
+ "Delete" : "Hapus",
"Delete permanently" : "Hapus secara permanen",
"Error" : "Galat",
+ "This operation is forbidden" : "Operasi ini dilarang",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Direktori ini tidak tersedia, silakan periksa log atau hubungi kontak",
"restored" : "dipulihkan",
"No deleted files" : "Tidak ada berkas yang dihapus",
"You will be able to recover deleted files from here" : "Anda dapat memulihkan berkas yang dihapus dari sini",
"No entries found in this folder" : "Tidak ada entri yang ditemukan dalam folder ini",
"Select all" : "Pilih Semua",
"Name" : "Nama",
- "Deleted" : "Dihapus",
- "Delete" : "Hapus"
+ "Deleted" : "Dihapus"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/id.json b/apps/files_trashbin/l10n/id.json
index d0d107a9571..491aad79f16 100644
--- a/apps/files_trashbin/l10n/id.json
+++ b/apps/files_trashbin/l10n/id.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Tidak dapat memulihkan %s",
"Deleted files" : "Berkas yang dihapus",
"Restore" : "Pulihkan",
+ "Delete" : "Hapus",
"Delete permanently" : "Hapus secara permanen",
"Error" : "Galat",
+ "This operation is forbidden" : "Operasi ini dilarang",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Direktori ini tidak tersedia, silakan periksa log atau hubungi kontak",
"restored" : "dipulihkan",
"No deleted files" : "Tidak ada berkas yang dihapus",
"You will be able to recover deleted files from here" : "Anda dapat memulihkan berkas yang dihapus dari sini",
"No entries found in this folder" : "Tidak ada entri yang ditemukan dalam folder ini",
"Select all" : "Pilih Semua",
"Name" : "Nama",
- "Deleted" : "Dihapus",
- "Delete" : "Hapus"
+ "Deleted" : "Dihapus"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/is.js b/apps/files_trashbin/l10n/is.js
index 38858a5a944..6c9250c21b6 100644
--- a/apps/files_trashbin/l10n/is.js
+++ b/apps/files_trashbin/l10n/is.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "Gat ekki endurheimt %s",
"Deleted files" : "eyddar skrár",
"Restore" : "Endurheimta",
+ "Delete" : "Eyða",
"Delete permanently" : "Eyða varanlega",
"Error" : "Villa",
"restored" : "endurheimt",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "Engar skrár fundust í þessari möppu",
"Select all" : "Velja allt",
"Name" : "Nafn",
- "Deleted" : "Eytt",
- "Delete" : "Eyða"
+ "Deleted" : "Eytt"
},
"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);");
diff --git a/apps/files_trashbin/l10n/is.json b/apps/files_trashbin/l10n/is.json
index ea2257a68ad..04d746c488d 100644
--- a/apps/files_trashbin/l10n/is.json
+++ b/apps/files_trashbin/l10n/is.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "Gat ekki endurheimt %s",
"Deleted files" : "eyddar skrár",
"Restore" : "Endurheimta",
+ "Delete" : "Eyða",
"Delete permanently" : "Eyða varanlega",
"Error" : "Villa",
"restored" : "endurheimt",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "Engar skrár fundust í þessari möppu",
"Select all" : "Velja allt",
"Name" : "Nafn",
- "Deleted" : "Eytt",
- "Delete" : "Eyða"
+ "Deleted" : "Eytt"
},"pluralForm" :"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/it.js b/apps/files_trashbin/l10n/it.js
index 01840a9907c..2f98cd25e07 100644
--- a/apps/files_trashbin/l10n/it.js
+++ b/apps/files_trashbin/l10n/it.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Impossibile ripristinare %s",
"Deleted files" : "File eliminati",
"Restore" : "Ripristina",
+ "Delete" : "Elimina",
"Delete permanently" : "Elimina definitivamente",
"Error" : "Errore",
+ "This operation is forbidden" : "Questa operazione è vietata",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Questa cartella non è disponibile, controlla i log o contatta l'amministratore",
"restored" : "ripristinati",
"No deleted files" : "Nessun file eliminato",
"You will be able to recover deleted files from here" : "Potrai ripristinare i file eliminati da qui",
"No entries found in this folder" : "Nessuna voce trovata in questa cartella",
"Select all" : "Seleziona tutto",
"Name" : "Nome",
- "Deleted" : "Eliminati",
- "Delete" : "Elimina"
+ "Deleted" : "Eliminati"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/it.json b/apps/files_trashbin/l10n/it.json
index 89ee8efad16..3164a763c18 100644
--- a/apps/files_trashbin/l10n/it.json
+++ b/apps/files_trashbin/l10n/it.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Impossibile ripristinare %s",
"Deleted files" : "File eliminati",
"Restore" : "Ripristina",
+ "Delete" : "Elimina",
"Delete permanently" : "Elimina definitivamente",
"Error" : "Errore",
+ "This operation is forbidden" : "Questa operazione è vietata",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Questa cartella non è disponibile, controlla i log o contatta l'amministratore",
"restored" : "ripristinati",
"No deleted files" : "Nessun file eliminato",
"You will be able to recover deleted files from here" : "Potrai ripristinare i file eliminati da qui",
"No entries found in this folder" : "Nessuna voce trovata in questa cartella",
"Select all" : "Seleziona tutto",
"Name" : "Nome",
- "Deleted" : "Eliminati",
- "Delete" : "Elimina"
+ "Deleted" : "Eliminati"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ja.js b/apps/files_trashbin/l10n/ja.js
index 6fdb9f3738e..880f391fbc9 100644
--- a/apps/files_trashbin/l10n/ja.js
+++ b/apps/files_trashbin/l10n/ja.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "%s を復元できませんでした",
"Deleted files" : "ゴミ箱",
"Restore" : "復元",
+ "Delete" : "削除",
"Delete permanently" : "完全に削除する",
"Error" : "エラー",
+ "This operation is forbidden" : "この操作は禁止されています",
+ "This directory is unavailable, please check the logs or contact the administrator" : "このディレクトリは利用できません。ログを確認するか管理者に問い合わせてください。",
"restored" : "復元済",
"No deleted files" : "削除されたファイルはありません",
"You will be able to recover deleted files from here" : "ここから削除されたファイルを元に戻すことができます。",
"No entries found in this folder" : "このフォルダーにはエントリーがありません",
"Select all" : "すべて選択",
"Name" : "名前",
- "Deleted" : "削除日時",
- "Delete" : "削除"
+ "Deleted" : "削除日時"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/ja.json b/apps/files_trashbin/l10n/ja.json
index 1d07e8dd960..14172a324f2 100644
--- a/apps/files_trashbin/l10n/ja.json
+++ b/apps/files_trashbin/l10n/ja.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "%s を復元できませんでした",
"Deleted files" : "ゴミ箱",
"Restore" : "復元",
+ "Delete" : "削除",
"Delete permanently" : "完全に削除する",
"Error" : "エラー",
+ "This operation is forbidden" : "この操作は禁止されています",
+ "This directory is unavailable, please check the logs or contact the administrator" : "このディレクトリは利用できません。ログを確認するか管理者に問い合わせてください。",
"restored" : "復元済",
"No deleted files" : "削除されたファイルはありません",
"You will be able to recover deleted files from here" : "ここから削除されたファイルを元に戻すことができます。",
"No entries found in this folder" : "このフォルダーにはエントリーがありません",
"Select all" : "すべて選択",
"Name" : "名前",
- "Deleted" : "削除日時",
- "Delete" : "削除"
+ "Deleted" : "削除日時"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ka_GE.js b/apps/files_trashbin/l10n/ka_GE.js
index cd578d4117a..71f465fe5b1 100644
--- a/apps/files_trashbin/l10n/ka_GE.js
+++ b/apps/files_trashbin/l10n/ka_GE.js
@@ -5,10 +5,10 @@ OC.L10N.register(
"Couldn't restore %s" : "%s–ის აღდგენა ვერ მოხერხდა",
"Deleted files" : "წაშლილი ფაილები",
"Restore" : "აღდგენა",
+ "Delete" : "წაშლა",
"Delete permanently" : "სრულად წაშლა",
"Error" : "შეცდომა",
"Name" : "სახელი",
- "Deleted" : "წაშლილი",
- "Delete" : "წაშლა"
+ "Deleted" : "წაშლილი"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/ka_GE.json b/apps/files_trashbin/l10n/ka_GE.json
index 11fc08b1255..e1721d96f29 100644
--- a/apps/files_trashbin/l10n/ka_GE.json
+++ b/apps/files_trashbin/l10n/ka_GE.json
@@ -3,10 +3,10 @@
"Couldn't restore %s" : "%s–ის აღდგენა ვერ მოხერხდა",
"Deleted files" : "წაშლილი ფაილები",
"Restore" : "აღდგენა",
+ "Delete" : "წაშლა",
"Delete permanently" : "სრულად წაშლა",
"Error" : "შეცდომა",
"Name" : "სახელი",
- "Deleted" : "წაშლილი",
- "Delete" : "წაშლა"
+ "Deleted" : "წაშლილი"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/km.js b/apps/files_trashbin/l10n/km.js
index fafbff1e665..b568abde589 100644
--- a/apps/files_trashbin/l10n/km.js
+++ b/apps/files_trashbin/l10n/km.js
@@ -5,11 +5,11 @@ OC.L10N.register(
"Couldn't restore %s" : "មិន​អាច​ស្ដារ %s ឡើង​វិញ​បាន​ទេ",
"Deleted files" : "ឯកសារ​ដែល​បាន​លុប",
"Restore" : "ស្ដារ​មក​វិញ",
+ "Delete" : "លុប",
"Delete permanently" : "លុប​ជា​អចិន្ត្រៃយ៍",
"Error" : "កំហុស",
"restored" : "បាន​ស្ដារ​វិញ",
"Name" : "ឈ្មោះ",
- "Deleted" : "បាន​លុប",
- "Delete" : "លុប"
+ "Deleted" : "បាន​លុប"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/km.json b/apps/files_trashbin/l10n/km.json
index 0b291a61eb2..14481c4f2e7 100644
--- a/apps/files_trashbin/l10n/km.json
+++ b/apps/files_trashbin/l10n/km.json
@@ -3,11 +3,11 @@
"Couldn't restore %s" : "មិន​អាច​ស្ដារ %s ឡើង​វិញ​បាន​ទេ",
"Deleted files" : "ឯកសារ​ដែល​បាន​លុប",
"Restore" : "ស្ដារ​មក​វិញ",
+ "Delete" : "លុប",
"Delete permanently" : "លុប​ជា​អចិន្ត្រៃយ៍",
"Error" : "កំហុស",
"restored" : "បាន​ស្ដារ​វិញ",
"Name" : "ឈ្មោះ",
- "Deleted" : "បាន​លុប",
- "Delete" : "លុប"
+ "Deleted" : "បាន​លុប"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/kn.js b/apps/files_trashbin/l10n/kn.js
index 4e918b5f06f..c9e17d94c58 100644
--- a/apps/files_trashbin/l10n/kn.js
+++ b/apps/files_trashbin/l10n/kn.js
@@ -2,9 +2,9 @@ OC.L10N.register(
"files_trashbin",
{
"Restore" : "ಮರುಸ್ಥಾಪಿಸು",
+ "Delete" : "ಅಳಿಸಿ",
"Error" : "ತಪ್ಪಾಗಿದೆ",
"Select all" : "ಎಲ್ಲಾ ಆಯ್ಕೆ ಮಾಡಿ",
- "Name" : "ಹೆಸರು",
- "Delete" : "ಅಳಿಸಿ"
+ "Name" : "ಹೆಸರು"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/kn.json b/apps/files_trashbin/l10n/kn.json
index 174306ce04a..3bd9118dfce 100644
--- a/apps/files_trashbin/l10n/kn.json
+++ b/apps/files_trashbin/l10n/kn.json
@@ -1,8 +1,8 @@
{ "translations": {
"Restore" : "ಮರುಸ್ಥಾಪಿಸು",
+ "Delete" : "ಅಳಿಸಿ",
"Error" : "ತಪ್ಪಾಗಿದೆ",
"Select all" : "ಎಲ್ಲಾ ಆಯ್ಕೆ ಮಾಡಿ",
- "Name" : "ಹೆಸರು",
- "Delete" : "ಅಳಿಸಿ"
+ "Name" : "ಹೆಸರು"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ko.js b/apps/files_trashbin/l10n/ko.js
index d93dca056bb..36cb40288a3 100644
--- a/apps/files_trashbin/l10n/ko.js
+++ b/apps/files_trashbin/l10n/ko.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "%s을(를) 복원할 수 없습니다",
"Deleted files" : "삭제된 파일",
"Restore" : "복원",
+ "Delete" : "삭제",
"Delete permanently" : "영구히 삭제",
"Error" : "오류",
+ "This operation is forbidden" : "이 작업이 금지됨",
+ "This directory is unavailable, please check the logs or contact the administrator" : "디렉터리를 사용할 수 없습니다. 로그를 확인하거나 관리자에게 연락하십시오",
"restored" : "복원됨",
"No deleted files" : "삭제된 파일 없음",
"You will be able to recover deleted files from here" : "삭제된 파일을 여기에서 복구할 수 있습니다",
"No entries found in this folder" : "이 폴더에 항목 없음",
"Select all" : "모두 선택",
"Name" : "이름",
- "Deleted" : "삭제됨",
- "Delete" : "삭제"
+ "Deleted" : "삭제됨"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/ko.json b/apps/files_trashbin/l10n/ko.json
index 25d1c888550..e95101dfce5 100644
--- a/apps/files_trashbin/l10n/ko.json
+++ b/apps/files_trashbin/l10n/ko.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "%s을(를) 복원할 수 없습니다",
"Deleted files" : "삭제된 파일",
"Restore" : "복원",
+ "Delete" : "삭제",
"Delete permanently" : "영구히 삭제",
"Error" : "오류",
+ "This operation is forbidden" : "이 작업이 금지됨",
+ "This directory is unavailable, please check the logs or contact the administrator" : "디렉터리를 사용할 수 없습니다. 로그를 확인하거나 관리자에게 연락하십시오",
"restored" : "복원됨",
"No deleted files" : "삭제된 파일 없음",
"You will be able to recover deleted files from here" : "삭제된 파일을 여기에서 복구할 수 있습니다",
"No entries found in this folder" : "이 폴더에 항목 없음",
"Select all" : "모두 선택",
"Name" : "이름",
- "Deleted" : "삭제됨",
- "Delete" : "삭제"
+ "Deleted" : "삭제됨"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/lb.js b/apps/files_trashbin/l10n/lb.js
index c83d9a3a28b..9b2aad6d8b0 100644
--- a/apps/files_trashbin/l10n/lb.js
+++ b/apps/files_trashbin/l10n/lb.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "Konnt %s net erëmhierstellen",
"Deleted files" : "Geläscht Fichieren",
"Restore" : "Erëmhierstellen",
+ "Delete" : "Läschen",
"Delete permanently" : "Permanent läschen",
"Error" : "Fehler",
"restored" : "erëmhiergestallt",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "Keng Elementer an dësem Dossier fonnt",
"Select all" : "All auswielen",
"Name" : "Numm",
- "Deleted" : "Geläscht",
- "Delete" : "Läschen"
+ "Deleted" : "Geläscht"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/lb.json b/apps/files_trashbin/l10n/lb.json
index ca13342cb3b..f9c13ce017f 100644
--- a/apps/files_trashbin/l10n/lb.json
+++ b/apps/files_trashbin/l10n/lb.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "Konnt %s net erëmhierstellen",
"Deleted files" : "Geläscht Fichieren",
"Restore" : "Erëmhierstellen",
+ "Delete" : "Läschen",
"Delete permanently" : "Permanent läschen",
"Error" : "Fehler",
"restored" : "erëmhiergestallt",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "Keng Elementer an dësem Dossier fonnt",
"Select all" : "All auswielen",
"Name" : "Numm",
- "Deleted" : "Geläscht",
- "Delete" : "Läschen"
+ "Deleted" : "Geläscht"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/lt_LT.js b/apps/files_trashbin/l10n/lt_LT.js
index afe317ca20a..1548afcc2ee 100644
--- a/apps/files_trashbin/l10n/lt_LT.js
+++ b/apps/files_trashbin/l10n/lt_LT.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Nepavyko atkurti %s",
"Deleted files" : "Ištrinti failai",
"Restore" : "Atstatyti",
+ "Delete" : "Ištrinti",
"Delete permanently" : "Ištrinti negrįžtamai",
"Error" : "Klaida",
+ "This operation is forbidden" : "Ši operacija yra uždrausta",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Katalogas nepasiekiamas, prašome peržiūrėti žurnalo įrašus arba susisiekti su administratoriumi",
"restored" : "atstatyta",
"No deleted files" : "Nėra ištrintų failų",
"You will be able to recover deleted files from here" : "Jūs galėsite atkurti ištrintus failus iš čia",
"No entries found in this folder" : "Nerasta įrašų šiame aplanke",
"Select all" : "Pažymėti viską",
"Name" : "Pavadinimas",
- "Deleted" : "Ištrinti",
- "Delete" : "Ištrinti"
+ "Deleted" : "Ištrinti"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_trashbin/l10n/lt_LT.json b/apps/files_trashbin/l10n/lt_LT.json
index bf2cb31b588..51fab92428f 100644
--- a/apps/files_trashbin/l10n/lt_LT.json
+++ b/apps/files_trashbin/l10n/lt_LT.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Nepavyko atkurti %s",
"Deleted files" : "Ištrinti failai",
"Restore" : "Atstatyti",
+ "Delete" : "Ištrinti",
"Delete permanently" : "Ištrinti negrįžtamai",
"Error" : "Klaida",
+ "This operation is forbidden" : "Ši operacija yra uždrausta",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Katalogas nepasiekiamas, prašome peržiūrėti žurnalo įrašus arba susisiekti su administratoriumi",
"restored" : "atstatyta",
"No deleted files" : "Nėra ištrintų failų",
"You will be able to recover deleted files from here" : "Jūs galėsite atkurti ištrintus failus iš čia",
"No entries found in this folder" : "Nerasta įrašų šiame aplanke",
"Select all" : "Pažymėti viską",
"Name" : "Pavadinimas",
- "Deleted" : "Ištrinti",
- "Delete" : "Ištrinti"
+ "Deleted" : "Ištrinti"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/lv.js b/apps/files_trashbin/l10n/lv.js
index 813ddd314e1..5629ba6af06 100644
--- a/apps/files_trashbin/l10n/lv.js
+++ b/apps/files_trashbin/l10n/lv.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "Nevarēja atjaunot %s",
"Deleted files" : "Dzēstās datnes",
"Restore" : "Atjaunot",
+ "Delete" : "Dzēst",
"Delete permanently" : "Dzēst pavisam",
"Error" : "Kļūda",
"restored" : "atjaunots",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "Šajā mapē nekas nav atrasts",
"Select all" : "Atzīmēt visu",
"Name" : "Nosaukums",
- "Deleted" : "Dzēsts",
- "Delete" : "Dzēst"
+ "Deleted" : "Dzēsts"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);");
diff --git a/apps/files_trashbin/l10n/lv.json b/apps/files_trashbin/l10n/lv.json
index 9c0ad01ce9a..4cf941bd21e 100644
--- a/apps/files_trashbin/l10n/lv.json
+++ b/apps/files_trashbin/l10n/lv.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "Nevarēja atjaunot %s",
"Deleted files" : "Dzēstās datnes",
"Restore" : "Atjaunot",
+ "Delete" : "Dzēst",
"Delete permanently" : "Dzēst pavisam",
"Error" : "Kļūda",
"restored" : "atjaunots",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "Šajā mapē nekas nav atrasts",
"Select all" : "Atzīmēt visu",
"Name" : "Nosaukums",
- "Deleted" : "Dzēsts",
- "Delete" : "Dzēst"
+ "Deleted" : "Dzēsts"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/mk.js b/apps/files_trashbin/l10n/mk.js
index f5286eac043..4e6e5da77df 100644
--- a/apps/files_trashbin/l10n/mk.js
+++ b/apps/files_trashbin/l10n/mk.js
@@ -5,11 +5,14 @@ OC.L10N.register(
"Couldn't restore %s" : "Не можеше да се поврати %s",
"Deleted files" : "Избришани датотеки",
"Restore" : "Поврати",
+ "Delete" : "Избриши",
"Delete permanently" : "Трајно избришани",
"Error" : "Грешка",
+ "This operation is forbidden" : "Операцијата не е дозволена",
"restored" : "повратени",
+ "No entries found in this folder" : "Нема ништо во оваа папка",
+ "Select all" : "Избери се",
"Name" : "Име",
- "Deleted" : "Избришан",
- "Delete" : "Избриши"
+ "Deleted" : "Избришан"
},
"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;");
diff --git a/apps/files_trashbin/l10n/mk.json b/apps/files_trashbin/l10n/mk.json
index 119a6c4f954..1e1a8aff42a 100644
--- a/apps/files_trashbin/l10n/mk.json
+++ b/apps/files_trashbin/l10n/mk.json
@@ -3,11 +3,14 @@
"Couldn't restore %s" : "Не можеше да се поврати %s",
"Deleted files" : "Избришани датотеки",
"Restore" : "Поврати",
+ "Delete" : "Избриши",
"Delete permanently" : "Трајно избришани",
"Error" : "Грешка",
+ "This operation is forbidden" : "Операцијата не е дозволена",
"restored" : "повратени",
+ "No entries found in this folder" : "Нема ништо во оваа папка",
+ "Select all" : "Избери се",
"Name" : "Име",
- "Deleted" : "Избришан",
- "Delete" : "Избриши"
+ "Deleted" : "Избришан"
},"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ms_MY.js b/apps/files_trashbin/l10n/ms_MY.js
index 1441ab03bf9..22680ff254d 100644
--- a/apps/files_trashbin/l10n/ms_MY.js
+++ b/apps/files_trashbin/l10n/ms_MY.js
@@ -5,10 +5,10 @@ OC.L10N.register(
"Couldn't restore %s" : "Tidak dapat memulihkan %s",
"Deleted files" : "Fail dipadam",
"Restore" : "Pulihkan",
+ "Delete" : "Padam",
"Error" : "Ralat",
"restored" : "dipulihkan",
"Name" : "Nama",
- "Deleted" : "Dipadam",
- "Delete" : "Padam"
+ "Deleted" : "Dipadam"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/ms_MY.json b/apps/files_trashbin/l10n/ms_MY.json
index a2b674d23d5..340b46e78a1 100644
--- a/apps/files_trashbin/l10n/ms_MY.json
+++ b/apps/files_trashbin/l10n/ms_MY.json
@@ -3,10 +3,10 @@
"Couldn't restore %s" : "Tidak dapat memulihkan %s",
"Deleted files" : "Fail dipadam",
"Restore" : "Pulihkan",
+ "Delete" : "Padam",
"Error" : "Ralat",
"restored" : "dipulihkan",
"Name" : "Nama",
- "Deleted" : "Dipadam",
- "Delete" : "Padam"
+ "Deleted" : "Dipadam"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/nb_NO.js b/apps/files_trashbin/l10n/nb_NO.js
index 2c1fd5396ef..644ad102ae4 100644
--- a/apps/files_trashbin/l10n/nb_NO.js
+++ b/apps/files_trashbin/l10n/nb_NO.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Kunne ikke gjenopprette %s",
"Deleted files" : "Slettede filer",
"Restore" : "Gjenopprett",
+ "Delete" : "Slett",
"Delete permanently" : "Slett permanent",
"Error" : "Feil",
+ "This operation is forbidden" : "Operasjonen er forbudt",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Denne mappen er utilgjengelig. Sjekk loggene eller kontakt administrator",
"restored" : "gjenopprettet",
"No deleted files" : "Ingen slettede filer",
"You will be able to recover deleted files from here" : "Du vil kunne gjenopprette slettede filer herfra",
"No entries found in this folder" : "Ingen oppføringer funnet i denne mappen",
"Select all" : "Velg alle",
"Name" : "Navn",
- "Deleted" : "Slettet",
- "Delete" : "Slett"
+ "Deleted" : "Slettet"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/nb_NO.json b/apps/files_trashbin/l10n/nb_NO.json
index 44e6161fe18..442221a2c8c 100644
--- a/apps/files_trashbin/l10n/nb_NO.json
+++ b/apps/files_trashbin/l10n/nb_NO.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Kunne ikke gjenopprette %s",
"Deleted files" : "Slettede filer",
"Restore" : "Gjenopprett",
+ "Delete" : "Slett",
"Delete permanently" : "Slett permanent",
"Error" : "Feil",
+ "This operation is forbidden" : "Operasjonen er forbudt",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Denne mappen er utilgjengelig. Sjekk loggene eller kontakt administrator",
"restored" : "gjenopprettet",
"No deleted files" : "Ingen slettede filer",
"You will be able to recover deleted files from here" : "Du vil kunne gjenopprette slettede filer herfra",
"No entries found in this folder" : "Ingen oppføringer funnet i denne mappen",
"Select all" : "Velg alle",
"Name" : "Navn",
- "Deleted" : "Slettet",
- "Delete" : "Slett"
+ "Deleted" : "Slettet"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/nds.js b/apps/files_trashbin/l10n/nds.js
index b2dd9ff4ca6..8212e5210a9 100644
--- a/apps/files_trashbin/l10n/nds.js
+++ b/apps/files_trashbin/l10n/nds.js
@@ -2,6 +2,7 @@ OC.L10N.register(
"files_trashbin",
{
"Delete" : "Löschen",
+ "Error" : "Fehler",
"Name" : "Name"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/nds.json b/apps/files_trashbin/l10n/nds.json
index 45b0caa74ac..d15a7c583ac 100644
--- a/apps/files_trashbin/l10n/nds.json
+++ b/apps/files_trashbin/l10n/nds.json
@@ -1,5 +1,6 @@
{ "translations": {
"Delete" : "Löschen",
+ "Error" : "Fehler",
"Name" : "Name"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/nl.js b/apps/files_trashbin/l10n/nl.js
index 4b9227b563f..1b536860ce6 100644
--- a/apps/files_trashbin/l10n/nl.js
+++ b/apps/files_trashbin/l10n/nl.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Kon %s niet herstellen",
"Deleted files" : "Verwijderde bestanden",
"Restore" : "Herstellen",
+ "Delete" : "Verwijder",
"Delete permanently" : "Definitief verwijderen",
"Error" : "Fout",
+ "This operation is forbidden" : "Deze taak is verboden",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Deze map is niet beschikbaar. Verifieer de logs of neem contact op met de beheerder",
"restored" : "hersteld",
"No deleted files" : "Geen verwijderde bestanden",
"You will be able to recover deleted files from here" : "U kunt verwijderde bestanden hier vandaan weer terugzetten",
"No entries found in this folder" : "Niets gevonden in deze map",
"Select all" : "Alles selecteren",
"Name" : "Naam",
- "Deleted" : "Verwijderd",
- "Delete" : "Verwijder"
+ "Deleted" : "Verwijderd"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/nl.json b/apps/files_trashbin/l10n/nl.json
index 7e78dde9baa..a80e1d8e1a9 100644
--- a/apps/files_trashbin/l10n/nl.json
+++ b/apps/files_trashbin/l10n/nl.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Kon %s niet herstellen",
"Deleted files" : "Verwijderde bestanden",
"Restore" : "Herstellen",
+ "Delete" : "Verwijder",
"Delete permanently" : "Definitief verwijderen",
"Error" : "Fout",
+ "This operation is forbidden" : "Deze taak is verboden",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Deze map is niet beschikbaar. Verifieer de logs of neem contact op met de beheerder",
"restored" : "hersteld",
"No deleted files" : "Geen verwijderde bestanden",
"You will be able to recover deleted files from here" : "U kunt verwijderde bestanden hier vandaan weer terugzetten",
"No entries found in this folder" : "Niets gevonden in deze map",
"Select all" : "Alles selecteren",
"Name" : "Naam",
- "Deleted" : "Verwijderd",
- "Delete" : "Verwijder"
+ "Deleted" : "Verwijderd"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/nn_NO.js b/apps/files_trashbin/l10n/nn_NO.js
index fc4a6a5cc37..c97071b9c66 100644
--- a/apps/files_trashbin/l10n/nn_NO.js
+++ b/apps/files_trashbin/l10n/nn_NO.js
@@ -5,11 +5,11 @@ OC.L10N.register(
"Couldn't restore %s" : "Klarte ikkje gjenoppretta %s",
"Deleted files" : "Sletta filer",
"Restore" : "Gjenopprett",
+ "Delete" : "Slett",
"Delete permanently" : "Slett for godt",
"Error" : "Feil",
"restored" : "gjenoppretta",
"Name" : "Namn",
- "Deleted" : "Sletta",
- "Delete" : "Slett"
+ "Deleted" : "Sletta"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/nn_NO.json b/apps/files_trashbin/l10n/nn_NO.json
index f8cf76ca3f4..acecd932b77 100644
--- a/apps/files_trashbin/l10n/nn_NO.json
+++ b/apps/files_trashbin/l10n/nn_NO.json
@@ -3,11 +3,11 @@
"Couldn't restore %s" : "Klarte ikkje gjenoppretta %s",
"Deleted files" : "Sletta filer",
"Restore" : "Gjenopprett",
+ "Delete" : "Slett",
"Delete permanently" : "Slett for godt",
"Error" : "Feil",
"restored" : "gjenoppretta",
"Name" : "Namn",
- "Deleted" : "Sletta",
- "Delete" : "Slett"
+ "Deleted" : "Sletta"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/oc.js b/apps/files_trashbin/l10n/oc.js
index 390ccaea050..762d7a9b424 100644
--- a/apps/files_trashbin/l10n/oc.js
+++ b/apps/files_trashbin/l10n/oc.js
@@ -8,6 +8,8 @@ OC.L10N.register(
"Delete" : "Suprimir",
"Delete permanently" : "Suprimir de faiçon definitiva",
"Error" : "Error",
+ "This operation is forbidden" : "L'operacion es interdicha",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Aqueste repertòri es pas disponible. Consultatz los logs o contactatz vòstre administrator",
"restored" : "restablit",
"No deleted files" : "Cap de fichièr pas suprimit",
"You will be able to recover deleted files from here" : "Poiretz restablir vòstres fichièrs suprimits aicí",
diff --git a/apps/files_trashbin/l10n/oc.json b/apps/files_trashbin/l10n/oc.json
index e2add0b3cdb..a48b12e0c6e 100644
--- a/apps/files_trashbin/l10n/oc.json
+++ b/apps/files_trashbin/l10n/oc.json
@@ -6,6 +6,8 @@
"Delete" : "Suprimir",
"Delete permanently" : "Suprimir de faiçon definitiva",
"Error" : "Error",
+ "This operation is forbidden" : "L'operacion es interdicha",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Aqueste repertòri es pas disponible. Consultatz los logs o contactatz vòstre administrator",
"restored" : "restablit",
"No deleted files" : "Cap de fichièr pas suprimit",
"You will be able to recover deleted files from here" : "Poiretz restablir vòstres fichièrs suprimits aicí",
diff --git a/apps/files_trashbin/l10n/pa.js b/apps/files_trashbin/l10n/pa.js
index 301d8f08c15..7c2bd3674dd 100644
--- a/apps/files_trashbin/l10n/pa.js
+++ b/apps/files_trashbin/l10n/pa.js
@@ -1,7 +1,7 @@
OC.L10N.register(
"files_trashbin",
{
- "Error" : "ਗਲਤੀ",
- "Delete" : "ਹਟਾਓ"
+ "Delete" : "ਹਟਾਓ",
+ "Error" : "ਗਲਤੀ"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/pa.json b/apps/files_trashbin/l10n/pa.json
index 6ad75a4c997..aa150965640 100644
--- a/apps/files_trashbin/l10n/pa.json
+++ b/apps/files_trashbin/l10n/pa.json
@@ -1,5 +1,5 @@
{ "translations": {
- "Error" : "ਗਲਤੀ",
- "Delete" : "ਹਟਾਓ"
+ "Delete" : "ਹਟਾਓ",
+ "Error" : "ਗਲਤੀ"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/pl.js b/apps/files_trashbin/l10n/pl.js
index ba0a2e93bd3..0c11dab91d4 100644
--- a/apps/files_trashbin/l10n/pl.js
+++ b/apps/files_trashbin/l10n/pl.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "Nie można przywrócić %s",
"Deleted files" : "Usunięte pliki",
"Restore" : "Przywróć",
+ "Delete" : "Usuń",
"Delete permanently" : "Trwale usuń",
"Error" : "Błąd",
"restored" : "przywrócony",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "Brak wpisów w tym folderze",
"Select all" : "Wybierz wszystko",
"Name" : "Nazwa",
- "Deleted" : "Usunięte",
- "Delete" : "Usuń"
+ "Deleted" : "Usunięte"
},
"nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_trashbin/l10n/pl.json b/apps/files_trashbin/l10n/pl.json
index 4fa8debaf29..8b56be020fb 100644
--- a/apps/files_trashbin/l10n/pl.json
+++ b/apps/files_trashbin/l10n/pl.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "Nie można przywrócić %s",
"Deleted files" : "Usunięte pliki",
"Restore" : "Przywróć",
+ "Delete" : "Usuń",
"Delete permanently" : "Trwale usuń",
"Error" : "Błąd",
"restored" : "przywrócony",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "Brak wpisów w tym folderze",
"Select all" : "Wybierz wszystko",
"Name" : "Nazwa",
- "Deleted" : "Usunięte",
- "Delete" : "Usuń"
+ "Deleted" : "Usunięte"
},"pluralForm" :"nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/pt_BR.js b/apps/files_trashbin/l10n/pt_BR.js
index 737a522eea1..806200ea651 100644
--- a/apps/files_trashbin/l10n/pt_BR.js
+++ b/apps/files_trashbin/l10n/pt_BR.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Não foi possível restaurar %s",
"Deleted files" : "Arquivos apagados",
"Restore" : "Restaurar",
+ "Delete" : "Excluir",
"Delete permanently" : "Excluir permanentemente",
"Error" : "Erro",
+ "This operation is forbidden" : "Esta operação é proibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Este diretório não está disponível, por favor, verifique os logs ou entre em contato com o administrador",
"restored" : "restaurado",
- "No deleted files" : "Aquivos não removidos",
- "You will be able to recover deleted files from here" : "Você pode recuperar arquivos removidos daqui",
+ "No deleted files" : "Nenhum arquivo excluído",
+ "You will be able to recover deleted files from here" : "Neste local, você será capaz de recuperar arquivos excluídos",
"No entries found in this folder" : "Nenhuma entrada foi encontrada nesta pasta",
"Select all" : "Selecionar tudo",
"Name" : "Nome",
- "Deleted" : "Excluído",
- "Delete" : "Excluir"
+ "Deleted" : "Excluído"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files_trashbin/l10n/pt_BR.json b/apps/files_trashbin/l10n/pt_BR.json
index 25ee0439d67..177a377bdfd 100644
--- a/apps/files_trashbin/l10n/pt_BR.json
+++ b/apps/files_trashbin/l10n/pt_BR.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Não foi possível restaurar %s",
"Deleted files" : "Arquivos apagados",
"Restore" : "Restaurar",
+ "Delete" : "Excluir",
"Delete permanently" : "Excluir permanentemente",
"Error" : "Erro",
+ "This operation is forbidden" : "Esta operação é proibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Este diretório não está disponível, por favor, verifique os logs ou entre em contato com o administrador",
"restored" : "restaurado",
- "No deleted files" : "Aquivos não removidos",
- "You will be able to recover deleted files from here" : "Você pode recuperar arquivos removidos daqui",
+ "No deleted files" : "Nenhum arquivo excluído",
+ "You will be able to recover deleted files from here" : "Neste local, você será capaz de recuperar arquivos excluídos",
"No entries found in this folder" : "Nenhuma entrada foi encontrada nesta pasta",
"Select all" : "Selecionar tudo",
"Name" : "Nome",
- "Deleted" : "Excluído",
- "Delete" : "Excluir"
+ "Deleted" : "Excluído"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/pt_PT.js b/apps/files_trashbin/l10n/pt_PT.js
index 8124af21751..8bcc248d948 100644
--- a/apps/files_trashbin/l10n/pt_PT.js
+++ b/apps/files_trashbin/l10n/pt_PT.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Não foi possível restaurar %s",
"Deleted files" : "Ficheiros eliminados",
"Restore" : "Restaurar",
+ "Delete" : "Eliminar",
"Delete permanently" : "Eliminar permanentemente",
"Error" : "Erro",
+ "This operation is forbidden" : "Esta operação é proibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Esta diretoria está indisponível, por favor, verifique os registos ou contacte o administrador",
"restored" : "Restaurado",
"No deleted files" : "Sem ficheiros eliminados",
"You will be able to recover deleted files from here" : "Poderá recuperar ficheiros apagados aqui",
"No entries found in this folder" : "Não foram encontradas entradas nesta pasta",
"Select all" : "Seleccionar todos",
"Name" : "Nome",
- "Deleted" : "Eliminado",
- "Delete" : "Eliminar"
+ "Deleted" : "Eliminado"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/pt_PT.json b/apps/files_trashbin/l10n/pt_PT.json
index f1fb924af59..e8bed1ea891 100644
--- a/apps/files_trashbin/l10n/pt_PT.json
+++ b/apps/files_trashbin/l10n/pt_PT.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Não foi possível restaurar %s",
"Deleted files" : "Ficheiros eliminados",
"Restore" : "Restaurar",
+ "Delete" : "Eliminar",
"Delete permanently" : "Eliminar permanentemente",
"Error" : "Erro",
+ "This operation is forbidden" : "Esta operação é proibida",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Esta diretoria está indisponível, por favor, verifique os registos ou contacte o administrador",
"restored" : "Restaurado",
"No deleted files" : "Sem ficheiros eliminados",
"You will be able to recover deleted files from here" : "Poderá recuperar ficheiros apagados aqui",
"No entries found in this folder" : "Não foram encontradas entradas nesta pasta",
"Select all" : "Seleccionar todos",
"Name" : "Nome",
- "Deleted" : "Eliminado",
- "Delete" : "Eliminar"
+ "Deleted" : "Eliminado"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ro.js b/apps/files_trashbin/l10n/ro.js
index 89fb577014e..1c0df1c5157 100644
--- a/apps/files_trashbin/l10n/ro.js
+++ b/apps/files_trashbin/l10n/ro.js
@@ -5,13 +5,13 @@ OC.L10N.register(
"Couldn't restore %s" : "Nu se poate recupera %s",
"Deleted files" : "Sterge fisierele",
"Restore" : "Restabilire",
+ "Delete" : "Șterge",
"Delete permanently" : "Șterge permanent",
"Error" : "Eroare",
"restored" : "restaurat",
"No deleted files" : "Nu sunt fișiere șterse",
"Select all" : "Selectează tot",
"Name" : "Nume",
- "Deleted" : "A fost șters.",
- "Delete" : "Șterge"
+ "Deleted" : "A fost șters."
},
"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));");
diff --git a/apps/files_trashbin/l10n/ro.json b/apps/files_trashbin/l10n/ro.json
index 6a68abae7fa..d7f01caca38 100644
--- a/apps/files_trashbin/l10n/ro.json
+++ b/apps/files_trashbin/l10n/ro.json
@@ -3,13 +3,13 @@
"Couldn't restore %s" : "Nu se poate recupera %s",
"Deleted files" : "Sterge fisierele",
"Restore" : "Restabilire",
+ "Delete" : "Șterge",
"Delete permanently" : "Șterge permanent",
"Error" : "Eroare",
"restored" : "restaurat",
"No deleted files" : "Nu sunt fișiere șterse",
"Select all" : "Selectează tot",
"Name" : "Nume",
- "Deleted" : "A fost șters.",
- "Delete" : "Șterge"
+ "Deleted" : "A fost șters."
},"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ru.js b/apps/files_trashbin/l10n/ru.js
index b51486b6eb0..337d0b0a575 100644
--- a/apps/files_trashbin/l10n/ru.js
+++ b/apps/files_trashbin/l10n/ru.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "%s не может быть восстановлен",
"Deleted files" : "Удалённые файлы",
"Restore" : "Восстановить",
+ "Delete" : "Удалить",
"Delete permanently" : "Удалить окончательно",
"Error" : "Ошибка",
+ "This operation is forbidden" : "Операция запрещена",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Директория недоступна, пожалуйста проверьте журнал сообщений или свяжитесь с администратором",
"restored" : "восстановлен",
"No deleted files" : "Нет удалённых файлов",
"You will be able to recover deleted files from here" : "Здесь вы сможете восстановить удалённые файлы",
"No entries found in this folder" : "Нет элементов в этом каталоге",
"Select all" : "Выделить все",
"Name" : "Имя",
- "Deleted" : "Удалён",
- "Delete" : "Удалить"
+ "Deleted" : "Удалён"
},
"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/apps/files_trashbin/l10n/ru.json b/apps/files_trashbin/l10n/ru.json
index 9fecb3a9641..2ab8d48476d 100644
--- a/apps/files_trashbin/l10n/ru.json
+++ b/apps/files_trashbin/l10n/ru.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "%s не может быть восстановлен",
"Deleted files" : "Удалённые файлы",
"Restore" : "Восстановить",
+ "Delete" : "Удалить",
"Delete permanently" : "Удалить окончательно",
"Error" : "Ошибка",
+ "This operation is forbidden" : "Операция запрещена",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Директория недоступна, пожалуйста проверьте журнал сообщений или свяжитесь с администратором",
"restored" : "восстановлен",
"No deleted files" : "Нет удалённых файлов",
"You will be able to recover deleted files from here" : "Здесь вы сможете восстановить удалённые файлы",
"No entries found in this folder" : "Нет элементов в этом каталоге",
"Select all" : "Выделить все",
"Name" : "Имя",
- "Deleted" : "Удалён",
- "Delete" : "Удалить"
+ "Deleted" : "Удалён"
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/si_LK.js b/apps/files_trashbin/l10n/si_LK.js
index 2f8a62ccab8..84d0f86a7f6 100644
--- a/apps/files_trashbin/l10n/si_LK.js
+++ b/apps/files_trashbin/l10n/si_LK.js
@@ -1,8 +1,8 @@
OC.L10N.register(
"files_trashbin",
{
+ "Delete" : "මකා දමන්න",
"Error" : "දෝෂයක්",
- "Name" : "නම",
- "Delete" : "මකා දමන්න"
+ "Name" : "නම"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/si_LK.json b/apps/files_trashbin/l10n/si_LK.json
index c46fb9adcbc..467fc3e058c 100644
--- a/apps/files_trashbin/l10n/si_LK.json
+++ b/apps/files_trashbin/l10n/si_LK.json
@@ -1,6 +1,6 @@
{ "translations": {
+ "Delete" : "මකා දමන්න",
"Error" : "දෝෂයක්",
- "Name" : "නම",
- "Delete" : "මකා දමන්න"
+ "Name" : "නම"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/sk_SK.js b/apps/files_trashbin/l10n/sk_SK.js
index 483691acf99..b4168ec5440 100644
--- a/apps/files_trashbin/l10n/sk_SK.js
+++ b/apps/files_trashbin/l10n/sk_SK.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Nemožno obnoviť %s",
"Deleted files" : "Zmazané súbory",
"Restore" : "Obnoviť",
+ "Delete" : "Zmazať",
"Delete permanently" : "Zmazať natrvalo",
"Error" : "Chyba",
+ "This operation is forbidden" : "Táto operácia je zakázaná",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Priečinok je nedostupný, skontrolujte prosím logy, alebo kontaktujte správcu",
"restored" : "obnovené",
"No deleted files" : "Žiadne zmazané súbory",
"You will be able to recover deleted files from here" : "Tu budete mať možnosť obnoviť zmazané súbory",
"No entries found in this folder" : "V tomto priečinku nebolo nič nájdené",
"Select all" : "Vybrať všetko",
"Name" : "Názov",
- "Deleted" : "Zmazané",
- "Delete" : "Zmazať"
+ "Deleted" : "Zmazané"
},
"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;");
diff --git a/apps/files_trashbin/l10n/sk_SK.json b/apps/files_trashbin/l10n/sk_SK.json
index 90b91cd92be..b02227c7064 100644
--- a/apps/files_trashbin/l10n/sk_SK.json
+++ b/apps/files_trashbin/l10n/sk_SK.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Nemožno obnoviť %s",
"Deleted files" : "Zmazané súbory",
"Restore" : "Obnoviť",
+ "Delete" : "Zmazať",
"Delete permanently" : "Zmazať natrvalo",
"Error" : "Chyba",
+ "This operation is forbidden" : "Táto operácia je zakázaná",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Priečinok je nedostupný, skontrolujte prosím logy, alebo kontaktujte správcu",
"restored" : "obnovené",
"No deleted files" : "Žiadne zmazané súbory",
"You will be able to recover deleted files from here" : "Tu budete mať možnosť obnoviť zmazané súbory",
"No entries found in this folder" : "V tomto priečinku nebolo nič nájdené",
"Select all" : "Vybrať všetko",
"Name" : "Názov",
- "Deleted" : "Zmazané",
- "Delete" : "Zmazať"
+ "Deleted" : "Zmazané"
},"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/sl.js b/apps/files_trashbin/l10n/sl.js
index 4287b3d860c..21482af3e12 100644
--- a/apps/files_trashbin/l10n/sl.js
+++ b/apps/files_trashbin/l10n/sl.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Ni mogoče obnoviti %s",
"Deleted files" : "Izbrisane datoteke",
"Restore" : "Obnovi",
+ "Delete" : "Izbriši",
"Delete permanently" : "Izbriši dokončno",
"Error" : "Napaka",
+ "This operation is forbidden" : "To dejanje ni dovoljeno!",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Mapa ni na voljo. Preverite dnevnik in stopite v stik s skrbnikom sistema.",
"restored" : "obnovljeno",
"No deleted files" : "Ni izbrisanih datotek",
"You will be able to recover deleted files from here" : "Izbrisane datoteke je mogoče povrniti na tem mestu",
"No entries found in this folder" : "V tej mapi ni najdenih predmetov.",
"Select all" : "izberi vse",
"Name" : "Ime",
- "Deleted" : "Izbrisano",
- "Delete" : "Izbriši"
+ "Deleted" : "Izbrisano"
},
"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);");
diff --git a/apps/files_trashbin/l10n/sl.json b/apps/files_trashbin/l10n/sl.json
index 0e996a2495b..4eee41e0c82 100644
--- a/apps/files_trashbin/l10n/sl.json
+++ b/apps/files_trashbin/l10n/sl.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Ni mogoče obnoviti %s",
"Deleted files" : "Izbrisane datoteke",
"Restore" : "Obnovi",
+ "Delete" : "Izbriši",
"Delete permanently" : "Izbriši dokončno",
"Error" : "Napaka",
+ "This operation is forbidden" : "To dejanje ni dovoljeno!",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Mapa ni na voljo. Preverite dnevnik in stopite v stik s skrbnikom sistema.",
"restored" : "obnovljeno",
"No deleted files" : "Ni izbrisanih datotek",
"You will be able to recover deleted files from here" : "Izbrisane datoteke je mogoče povrniti na tem mestu",
"No entries found in this folder" : "V tej mapi ni najdenih predmetov.",
"Select all" : "izberi vse",
"Name" : "Ime",
- "Deleted" : "Izbrisano",
- "Delete" : "Izbriši"
+ "Deleted" : "Izbrisano"
},"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/sq.js b/apps/files_trashbin/l10n/sq.js
index 3a1d0fed3bb..45348ca24b3 100644
--- a/apps/files_trashbin/l10n/sq.js
+++ b/apps/files_trashbin/l10n/sq.js
@@ -8,6 +8,8 @@ OC.L10N.register(
"Delete" : "Fshije",
"Delete permanently" : "Fshije përgjithmonë",
"Error" : "Gabim",
+ "This operation is forbidden" : "Ky veprim është i ndaluar",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Kjo drejtori nuk kapet, ju lutemi, kontrolloni regjistrat ose lidhuni me përgjegjësin",
"restored" : "u rikthye",
"No deleted files" : "Pa kartela të fshira",
"You will be able to recover deleted files from here" : "Që këtu do të jeni në gjendje të rimerrni kartela të fshira",
diff --git a/apps/files_trashbin/l10n/sq.json b/apps/files_trashbin/l10n/sq.json
index 4f2c429cb75..a28078058c9 100644
--- a/apps/files_trashbin/l10n/sq.json
+++ b/apps/files_trashbin/l10n/sq.json
@@ -6,6 +6,8 @@
"Delete" : "Fshije",
"Delete permanently" : "Fshije përgjithmonë",
"Error" : "Gabim",
+ "This operation is forbidden" : "Ky veprim është i ndaluar",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Kjo drejtori nuk kapet, ju lutemi, kontrolloni regjistrat ose lidhuni me përgjegjësin",
"restored" : "u rikthye",
"No deleted files" : "Pa kartela të fshira",
"You will be able to recover deleted files from here" : "Që këtu do të jeni në gjendje të rimerrni kartela të fshira",
diff --git a/apps/files_trashbin/l10n/sr.js b/apps/files_trashbin/l10n/sr.js
index e9a4f79f94e..dc3c8b46bc7 100644
--- a/apps/files_trashbin/l10n/sr.js
+++ b/apps/files_trashbin/l10n/sr.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "Не могу да вратим %s",
"Deleted files" : "Обрисани фајлови",
"Restore" : "Врати",
+ "Delete" : "Обриши",
"Delete permanently" : "Обриши заувек",
"Error" : "Грешка",
+ "This operation is forbidden" : "Ова радња је забрањена",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Овај директоријум није доступан, проверите записе или контактирајте администратора",
"restored" : "враћено",
"No deleted files" : "Нема обрисаних фајлова",
"You will be able to recover deleted files from here" : "Одавде ћете моћи да повратите обрисане фајлове",
"No entries found in this folder" : "Нема ничега у овој фасцикли",
"Select all" : "Означи све",
"Name" : "Назив",
- "Deleted" : "Обрисано",
- "Delete" : "Обриши"
+ "Deleted" : "Обрисано"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_trashbin/l10n/sr.json b/apps/files_trashbin/l10n/sr.json
index e572b6a3e85..c57bbdb83d4 100644
--- a/apps/files_trashbin/l10n/sr.json
+++ b/apps/files_trashbin/l10n/sr.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "Не могу да вратим %s",
"Deleted files" : "Обрисани фајлови",
"Restore" : "Врати",
+ "Delete" : "Обриши",
"Delete permanently" : "Обриши заувек",
"Error" : "Грешка",
+ "This operation is forbidden" : "Ова радња је забрањена",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Овај директоријум није доступан, проверите записе или контактирајте администратора",
"restored" : "враћено",
"No deleted files" : "Нема обрисаних фајлова",
"You will be able to recover deleted files from here" : "Одавде ћете моћи да повратите обрисане фајлове",
"No entries found in this folder" : "Нема ничега у овој фасцикли",
"Select all" : "Означи све",
"Name" : "Назив",
- "Deleted" : "Обрисано",
- "Delete" : "Обриши"
+ "Deleted" : "Обрисано"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/sr@latin.js b/apps/files_trashbin/l10n/sr@latin.js
index 24b57789fdb..e6eb817ccf3 100644
--- a/apps/files_trashbin/l10n/sr@latin.js
+++ b/apps/files_trashbin/l10n/sr@latin.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "Ne mogu da vratim %s",
"Deleted files" : "Obrisani fajlovi",
"Restore" : "Vrati",
+ "Delete" : "Obriši",
"Delete permanently" : "Obriši zauvek",
"Error" : "Greška",
"restored" : "vraćeno",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "Nema ničega u ovoj fascikli",
"Select all" : "Označi sve",
"Name" : "Naziv",
- "Deleted" : "Obrisano",
- "Delete" : "Obriši"
+ "Deleted" : "Obrisano"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_trashbin/l10n/sr@latin.json b/apps/files_trashbin/l10n/sr@latin.json
index 9351affd2a9..462e2f21e2a 100644
--- a/apps/files_trashbin/l10n/sr@latin.json
+++ b/apps/files_trashbin/l10n/sr@latin.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "Ne mogu da vratim %s",
"Deleted files" : "Obrisani fajlovi",
"Restore" : "Vrati",
+ "Delete" : "Obriši",
"Delete permanently" : "Obriši zauvek",
"Error" : "Greška",
"restored" : "vraćeno",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "Nema ničega u ovoj fascikli",
"Select all" : "Označi sve",
"Name" : "Naziv",
- "Deleted" : "Obrisano",
- "Delete" : "Obriši"
+ "Deleted" : "Obrisano"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/sv.js b/apps/files_trashbin/l10n/sv.js
index d21f1418073..923d9cdd7db 100644
--- a/apps/files_trashbin/l10n/sv.js
+++ b/apps/files_trashbin/l10n/sv.js
@@ -8,6 +8,8 @@ OC.L10N.register(
"Delete" : "Radera",
"Delete permanently" : "Radera permanent",
"Error" : "Fel",
+ "This operation is forbidden" : "Denna operation är förbjuden",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Denna katalog är inte tillgänglig, kontrollera loggarna eller kontakta administratören",
"restored" : "återställd",
"No deleted files" : "Inga borttagna filer",
"You will be able to recover deleted files from here" : "Du kommer kunna återfå raderade filer härifrån",
diff --git a/apps/files_trashbin/l10n/sv.json b/apps/files_trashbin/l10n/sv.json
index 0b9052ea713..f9ae83cabd2 100644
--- a/apps/files_trashbin/l10n/sv.json
+++ b/apps/files_trashbin/l10n/sv.json
@@ -6,6 +6,8 @@
"Delete" : "Radera",
"Delete permanently" : "Radera permanent",
"Error" : "Fel",
+ "This operation is forbidden" : "Denna operation är förbjuden",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Denna katalog är inte tillgänglig, kontrollera loggarna eller kontakta administratören",
"restored" : "återställd",
"No deleted files" : "Inga borttagna filer",
"You will be able to recover deleted files from here" : "Du kommer kunna återfå raderade filer härifrån",
diff --git a/apps/files_trashbin/l10n/ta_LK.js b/apps/files_trashbin/l10n/ta_LK.js
index cd53239625e..c5514d9d218 100644
--- a/apps/files_trashbin/l10n/ta_LK.js
+++ b/apps/files_trashbin/l10n/ta_LK.js
@@ -1,8 +1,8 @@
OC.L10N.register(
"files_trashbin",
{
+ "Delete" : "நீக்குக",
"Error" : "வழு",
- "Name" : "பெயர்",
- "Delete" : "நீக்குக"
+ "Name" : "பெயர்"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/ta_LK.json b/apps/files_trashbin/l10n/ta_LK.json
index ade1c7f13e0..c46481e9da9 100644
--- a/apps/files_trashbin/l10n/ta_LK.json
+++ b/apps/files_trashbin/l10n/ta_LK.json
@@ -1,6 +1,6 @@
{ "translations": {
+ "Delete" : "நீக்குக",
"Error" : "வழு",
- "Name" : "பெயர்",
- "Delete" : "நீக்குக"
+ "Name" : "பெயர்"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/te.js b/apps/files_trashbin/l10n/te.js
index e851ec86421..d9972912e61 100644
--- a/apps/files_trashbin/l10n/te.js
+++ b/apps/files_trashbin/l10n/te.js
@@ -1,9 +1,9 @@
OC.L10N.register(
"files_trashbin",
{
+ "Delete" : "తొలగించు",
"Delete permanently" : "శాశ్వతంగా తొలగించు",
"Error" : "పొరపాటు",
- "Name" : "పేరు",
- "Delete" : "తొలగించు"
+ "Name" : "పేరు"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/te.json b/apps/files_trashbin/l10n/te.json
index 4df06631a0c..0e6c6557355 100644
--- a/apps/files_trashbin/l10n/te.json
+++ b/apps/files_trashbin/l10n/te.json
@@ -1,7 +1,7 @@
{ "translations": {
+ "Delete" : "తొలగించు",
"Delete permanently" : "శాశ్వతంగా తొలగించు",
"Error" : "పొరపాటు",
- "Name" : "పేరు",
- "Delete" : "తొలగించు"
+ "Name" : "పేరు"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/th_TH.js b/apps/files_trashbin/l10n/th_TH.js
index e294f592e84..487b457deb3 100644
--- a/apps/files_trashbin/l10n/th_TH.js
+++ b/apps/files_trashbin/l10n/th_TH.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "ไม่สามารถกู้คืน %s",
"Deleted files" : "ไฟล์ที่ถูกลบ",
"Restore" : "คืนค่า",
+ "Delete" : "ลบ",
"Delete permanently" : "ลบแบบถาวร",
"Error" : "ข้อผิดพลาด",
+ "This operation is forbidden" : "การดำเนินการนี้ถูกห้าม",
+ "This directory is unavailable, please check the logs or contact the administrator" : "ไม่สามารถใช้งานไดเรกทอรีนี้โปรดตรวจสอบบันทึกหรือติดต่อผู้ดูแลระบบ",
"restored" : "การเรียกคืน",
"No deleted files" : "ไม่มีไฟล์ที่ถูกลบ",
"You will be able to recover deleted files from here" : "คุณจะสามารถกู้คืนไฟล์ที่ถูกลบจากที่นี่",
"No entries found in this folder" : "ไม่พบรายการในโฟลเดอร์นี้",
"Select all" : "เลือกทั้งหมด",
"Name" : "ชื่อ",
- "Deleted" : "ลบแล้ว",
- "Delete" : "ลบ"
+ "Deleted" : "ลบแล้ว"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/th_TH.json b/apps/files_trashbin/l10n/th_TH.json
index 7dc7546f55b..db4bd2de209 100644
--- a/apps/files_trashbin/l10n/th_TH.json
+++ b/apps/files_trashbin/l10n/th_TH.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "ไม่สามารถกู้คืน %s",
"Deleted files" : "ไฟล์ที่ถูกลบ",
"Restore" : "คืนค่า",
+ "Delete" : "ลบ",
"Delete permanently" : "ลบแบบถาวร",
"Error" : "ข้อผิดพลาด",
+ "This operation is forbidden" : "การดำเนินการนี้ถูกห้าม",
+ "This directory is unavailable, please check the logs or contact the administrator" : "ไม่สามารถใช้งานไดเรกทอรีนี้โปรดตรวจสอบบันทึกหรือติดต่อผู้ดูแลระบบ",
"restored" : "การเรียกคืน",
"No deleted files" : "ไม่มีไฟล์ที่ถูกลบ",
"You will be able to recover deleted files from here" : "คุณจะสามารถกู้คืนไฟล์ที่ถูกลบจากที่นี่",
"No entries found in this folder" : "ไม่พบรายการในโฟลเดอร์นี้",
"Select all" : "เลือกทั้งหมด",
"Name" : "ชื่อ",
- "Deleted" : "ลบแล้ว",
- "Delete" : "ลบ"
+ "Deleted" : "ลบแล้ว"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/tr.js b/apps/files_trashbin/l10n/tr.js
index c6c73929555..e3f55f29aae 100644
--- a/apps/files_trashbin/l10n/tr.js
+++ b/apps/files_trashbin/l10n/tr.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "%s geri yüklenemedi",
"Deleted files" : "Silinmiş dosyalar",
"Restore" : "Geri yükle",
+ "Delete" : "Sil",
"Delete permanently" : "Kalıcı olarak sil",
"Error" : "Hata",
+ "This operation is forbidden" : "Bu işlem yasak",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Bu dizine yazılamıyor, lütfen günlüğü kontrol edin veya yönetici ile iletişime geçin",
"restored" : "geri yüklendi",
"No deleted files" : "Silinen dosya yok",
"You will be able to recover deleted files from here" : "Silinen dosyalarınızı buradan kurtarabileceksiniz",
"No entries found in this folder" : "Bu klasörde hiçbir girdi bulunamadı",
"Select all" : "Tümünü seç",
"Name" : "İsim",
- "Deleted" : "Silinme",
- "Delete" : "Sil"
+ "Deleted" : "Silinme"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files_trashbin/l10n/tr.json b/apps/files_trashbin/l10n/tr.json
index 64f14af6674..d0f21497b5a 100644
--- a/apps/files_trashbin/l10n/tr.json
+++ b/apps/files_trashbin/l10n/tr.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "%s geri yüklenemedi",
"Deleted files" : "Silinmiş dosyalar",
"Restore" : "Geri yükle",
+ "Delete" : "Sil",
"Delete permanently" : "Kalıcı olarak sil",
"Error" : "Hata",
+ "This operation is forbidden" : "Bu işlem yasak",
+ "This directory is unavailable, please check the logs or contact the administrator" : "Bu dizine yazılamıyor, lütfen günlüğü kontrol edin veya yönetici ile iletişime geçin",
"restored" : "geri yüklendi",
"No deleted files" : "Silinen dosya yok",
"You will be able to recover deleted files from here" : "Silinen dosyalarınızı buradan kurtarabileceksiniz",
"No entries found in this folder" : "Bu klasörde hiçbir girdi bulunamadı",
"Select all" : "Tümünü seç",
"Name" : "İsim",
- "Deleted" : "Silinme",
- "Delete" : "Sil"
+ "Deleted" : "Silinme"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ug.js b/apps/files_trashbin/l10n/ug.js
index 329a04416c2..244c0d92c17 100644
--- a/apps/files_trashbin/l10n/ug.js
+++ b/apps/files_trashbin/l10n/ug.js
@@ -2,10 +2,10 @@ OC.L10N.register(
"files_trashbin",
{
"Deleted files" : "ئۆچۈرۈلگەن ھۆججەتلەر",
+ "Delete" : "ئۆچۈر",
"Delete permanently" : "مەڭگۈلۈك ئۆچۈر",
"Error" : "خاتالىق",
"Name" : "ئاتى",
- "Deleted" : "ئۆچۈرۈلدى",
- "Delete" : "ئۆچۈر"
+ "Deleted" : "ئۆچۈرۈلدى"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/ug.json b/apps/files_trashbin/l10n/ug.json
index 60a915b2ee5..3c11d802b5f 100644
--- a/apps/files_trashbin/l10n/ug.json
+++ b/apps/files_trashbin/l10n/ug.json
@@ -1,9 +1,9 @@
{ "translations": {
"Deleted files" : "ئۆچۈرۈلگەن ھۆججەتلەر",
+ "Delete" : "ئۆچۈر",
"Delete permanently" : "مەڭگۈلۈك ئۆچۈر",
"Error" : "خاتالىق",
"Name" : "ئاتى",
- "Deleted" : "ئۆچۈرۈلدى",
- "Delete" : "ئۆچۈر"
+ "Deleted" : "ئۆچۈرۈلدى"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/uk.js b/apps/files_trashbin/l10n/uk.js
index 656a6f7b50b..eb3aca343d7 100644
--- a/apps/files_trashbin/l10n/uk.js
+++ b/apps/files_trashbin/l10n/uk.js
@@ -5,15 +5,16 @@ OC.L10N.register(
"Couldn't restore %s" : "Неможливо відновити %s",
"Deleted files" : "Видалені файли",
"Restore" : "Відновити",
+ "Delete" : "Видалити",
"Delete permanently" : "Видалити назавжди",
"Error" : "Помилка",
+ "This operation is forbidden" : "Ця операція заборонена",
"restored" : "відновлено",
"No deleted files" : "Немає видалених файлів",
"You will be able to recover deleted files from here" : "Ви зможете відновлювати видалені файли звідси",
"No entries found in this folder" : "Записів не знайдено в цій папці",
"Select all" : "Вибрати всі",
"Name" : "Ім'я",
- "Deleted" : "Видалено",
- "Delete" : "Видалити"
+ "Deleted" : "Видалено"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files_trashbin/l10n/uk.json b/apps/files_trashbin/l10n/uk.json
index bfd6860252e..47c17cd1d65 100644
--- a/apps/files_trashbin/l10n/uk.json
+++ b/apps/files_trashbin/l10n/uk.json
@@ -3,15 +3,16 @@
"Couldn't restore %s" : "Неможливо відновити %s",
"Deleted files" : "Видалені файли",
"Restore" : "Відновити",
+ "Delete" : "Видалити",
"Delete permanently" : "Видалити назавжди",
"Error" : "Помилка",
+ "This operation is forbidden" : "Ця операція заборонена",
"restored" : "відновлено",
"No deleted files" : "Немає видалених файлів",
"You will be able to recover deleted files from here" : "Ви зможете відновлювати видалені файли звідси",
"No entries found in this folder" : "Записів не знайдено в цій папці",
"Select all" : "Вибрати всі",
"Name" : "Ім'я",
- "Deleted" : "Видалено",
- "Delete" : "Видалити"
+ "Deleted" : "Видалено"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ur_PK.js b/apps/files_trashbin/l10n/ur_PK.js
index 2dbe75b304e..eaa9dca8e34 100644
--- a/apps/files_trashbin/l10n/ur_PK.js
+++ b/apps/files_trashbin/l10n/ur_PK.js
@@ -5,10 +5,10 @@ OC.L10N.register(
"Couldn't restore %s" : "بحال نہيں کيا جا سکتا %s",
"Deleted files" : "حذف شدہ فائليں",
"Restore" : "بحال",
+ "Delete" : "حذف کریں",
"Error" : "ایرر",
"restored" : "بحال شدہ",
"Name" : "اسم",
- "Deleted" : "حذف شدہ ",
- "Delete" : "حذف کریں"
+ "Deleted" : "حذف شدہ "
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/ur_PK.json b/apps/files_trashbin/l10n/ur_PK.json
index d7ec3662998..fd88573d62a 100644
--- a/apps/files_trashbin/l10n/ur_PK.json
+++ b/apps/files_trashbin/l10n/ur_PK.json
@@ -3,10 +3,10 @@
"Couldn't restore %s" : "بحال نہيں کيا جا سکتا %s",
"Deleted files" : "حذف شدہ فائليں",
"Restore" : "بحال",
+ "Delete" : "حذف کریں",
"Error" : "ایرر",
"restored" : "بحال شدہ",
"Name" : "اسم",
- "Deleted" : "حذف شدہ ",
- "Delete" : "حذف کریں"
+ "Deleted" : "حذف شدہ "
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/vi.js b/apps/files_trashbin/l10n/vi.js
index c0ff36d90c3..660c8cf321b 100644
--- a/apps/files_trashbin/l10n/vi.js
+++ b/apps/files_trashbin/l10n/vi.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "Không thể khôi phục %s",
"Deleted files" : "File đã bị xóa",
"Restore" : "Khôi phục",
+ "Delete" : "Xóa",
"Delete permanently" : "Xóa vĩnh vễn",
"Error" : "Lỗi",
"restored" : "khôi phục",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "Chưa có mục nào trong thư mục",
"Select all" : "Chọn tất cả",
"Name" : "Tên",
- "Deleted" : "Đã xóa",
- "Delete" : "Xóa"
+ "Deleted" : "Đã xóa"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/vi.json b/apps/files_trashbin/l10n/vi.json
index a8b2c4a055e..ed25e642538 100644
--- a/apps/files_trashbin/l10n/vi.json
+++ b/apps/files_trashbin/l10n/vi.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "Không thể khôi phục %s",
"Deleted files" : "File đã bị xóa",
"Restore" : "Khôi phục",
+ "Delete" : "Xóa",
"Delete permanently" : "Xóa vĩnh vễn",
"Error" : "Lỗi",
"restored" : "khôi phục",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "Chưa có mục nào trong thư mục",
"Select all" : "Chọn tất cả",
"Name" : "Tên",
- "Deleted" : "Đã xóa",
- "Delete" : "Xóa"
+ "Deleted" : "Đã xóa"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/zh_CN.js b/apps/files_trashbin/l10n/zh_CN.js
index 0ef17e35d62..be1eeab9348 100644
--- a/apps/files_trashbin/l10n/zh_CN.js
+++ b/apps/files_trashbin/l10n/zh_CN.js
@@ -5,15 +5,17 @@ OC.L10N.register(
"Couldn't restore %s" : "无法恢复%s",
"Deleted files" : "已删除文件",
"Restore" : "恢复",
+ "Delete" : "删除",
"Delete permanently" : "永久删除",
"Error" : "错误",
+ "This operation is forbidden" : "操作被禁止",
+ "This directory is unavailable, please check the logs or contact the administrator" : "此目录不可用,请检查日志或联系管理员",
"restored" : "已恢复",
"No deleted files" : "无已删除文件",
"You will be able to recover deleted files from here" : "你可以在此处恢复已删除的文件",
"No entries found in this folder" : "此文件夹中无项目",
"Select all" : "全部选择",
"Name" : "名称",
- "Deleted" : "已删除",
- "Delete" : "删除"
+ "Deleted" : "已删除"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/zh_CN.json b/apps/files_trashbin/l10n/zh_CN.json
index 0349f643555..5d458254b87 100644
--- a/apps/files_trashbin/l10n/zh_CN.json
+++ b/apps/files_trashbin/l10n/zh_CN.json
@@ -3,15 +3,17 @@
"Couldn't restore %s" : "无法恢复%s",
"Deleted files" : "已删除文件",
"Restore" : "恢复",
+ "Delete" : "删除",
"Delete permanently" : "永久删除",
"Error" : "错误",
+ "This operation is forbidden" : "操作被禁止",
+ "This directory is unavailable, please check the logs or contact the administrator" : "此目录不可用,请检查日志或联系管理员",
"restored" : "已恢复",
"No deleted files" : "无已删除文件",
"You will be able to recover deleted files from here" : "你可以在此处恢复已删除的文件",
"No entries found in this folder" : "此文件夹中无项目",
"Select all" : "全部选择",
"Name" : "名称",
- "Deleted" : "已删除",
- "Delete" : "删除"
+ "Deleted" : "已删除"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/zh_HK.js b/apps/files_trashbin/l10n/zh_HK.js
index 78811bbdd2c..8c3f5bda38a 100644
--- a/apps/files_trashbin/l10n/zh_HK.js
+++ b/apps/files_trashbin/l10n/zh_HK.js
@@ -1,8 +1,8 @@
OC.L10N.register(
"files_trashbin",
{
+ "Delete" : "刪除",
"Error" : "錯誤",
- "Name" : "名稱",
- "Delete" : "刪除"
+ "Name" : "名稱"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_trashbin/l10n/zh_HK.json b/apps/files_trashbin/l10n/zh_HK.json
index eaa123c49f4..559081426a0 100644
--- a/apps/files_trashbin/l10n/zh_HK.json
+++ b/apps/files_trashbin/l10n/zh_HK.json
@@ -1,6 +1,6 @@
{ "translations": {
+ "Delete" : "刪除",
"Error" : "錯誤",
- "Name" : "名稱",
- "Delete" : "刪除"
+ "Name" : "名稱"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/zh_TW.js b/apps/files_trashbin/l10n/zh_TW.js
index e0ad6dbd723..76273723073 100644
--- a/apps/files_trashbin/l10n/zh_TW.js
+++ b/apps/files_trashbin/l10n/zh_TW.js
@@ -8,6 +8,8 @@ OC.L10N.register(
"Delete" : "刪除",
"Delete permanently" : "永久刪除",
"Error" : "錯誤",
+ "This operation is forbidden" : "此動作被禁止",
+ "This directory is unavailable, please check the logs or contact the administrator" : "這個目錄無法存取,請檢查伺服器記錄檔或聯絡管理員",
"restored" : "已還原",
"No deleted files" : "沒有已刪除的檔案",
"You will be able to recover deleted files from here" : "您可以從這裡還原已刪除的檔案",
diff --git a/apps/files_trashbin/l10n/zh_TW.json b/apps/files_trashbin/l10n/zh_TW.json
index 6a313220b58..18a8bb872f8 100644
--- a/apps/files_trashbin/l10n/zh_TW.json
+++ b/apps/files_trashbin/l10n/zh_TW.json
@@ -6,6 +6,8 @@
"Delete" : "刪除",
"Delete permanently" : "永久刪除",
"Error" : "錯誤",
+ "This operation is forbidden" : "此動作被禁止",
+ "This directory is unavailable, please check the logs or contact the administrator" : "這個目錄無法存取,請檢查伺服器記錄檔或聯絡管理員",
"restored" : "已還原",
"No deleted files" : "沒有已刪除的檔案",
"You will be able to recover deleted files from here" : "您可以從這裡還原已刪除的檔案",
diff --git a/apps/files_trashbin/lib/backgroundjob/expiretrash.php b/apps/files_trashbin/lib/backgroundjob/expiretrash.php
index 079fdd29912..7f4f4823918 100644
--- a/apps/files_trashbin/lib/backgroundjob/expiretrash.php
+++ b/apps/files_trashbin/lib/backgroundjob/expiretrash.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/lib/capabilities.php b/apps/files_trashbin/lib/capabilities.php
index d903066e676..43daa8cfa47 100644
--- a/apps/files_trashbin/lib/capabilities.php
+++ b/apps/files_trashbin/lib/capabilities.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/lib/exceptions/copyrecursiveexception.php b/apps/files_trashbin/lib/exceptions/copyrecursiveexception.php
index 0edf9d35118..8ebc8dfbfe1 100644
--- a/apps/files_trashbin/lib/exceptions/copyrecursiveexception.php
+++ b/apps/files_trashbin/lib/exceptions/copyrecursiveexception.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/lib/expiration.php b/apps/files_trashbin/lib/expiration.php
index 1c08e2869f6..e5a37b88b49 100644
--- a/apps/files_trashbin/lib/expiration.php
+++ b/apps/files_trashbin/lib/expiration.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/lib/helper.php b/apps/files_trashbin/lib/helper.php
index d14e97285c5..f56bbb12a91 100644
--- a/apps/files_trashbin/lib/helper.php
+++ b/apps/files_trashbin/lib/helper.php
@@ -3,12 +3,12 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,6 +27,7 @@
namespace OCA\Files_Trashbin;
use OC\Files\FileInfo;
+use OCP\Constants;
class Helper
{
@@ -87,10 +88,12 @@ class Helper
$i = array(
'name' => $id,
'mtime' => $timestamp,
- 'mimetype' => $view->is_dir($dir . '/' . $entryName) ? 'httpd/unix-directory' : \OC_Helper::getFileNameMimeType($id),
+ 'mimetype' => $view->is_dir($dir . '/' . $entryName) ? 'httpd/unix-directory' : \OC::$server->getMimeTypeDetector()->detectPath($id),
'type' => $view->is_dir($dir . '/' . $entryName) ? 'dir' : 'file',
'directory' => ($dir === '/') ? '' : $dir,
'size' => $size,
+ 'etag' => '',
+ 'permissions' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE
);
if ($originalPath) {
$i['extraData'] = $originalPath.'/'.$id;
diff --git a/apps/files_trashbin/lib/hooks.php b/apps/files_trashbin/lib/hooks.php
index 57fc8d7a8d3..0a018f4f0f8 100644
--- a/apps/files_trashbin/lib/hooks.php
+++ b/apps/files_trashbin/lib/hooks.php
@@ -2,9 +2,9 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/lib/storage.php b/apps/files_trashbin/lib/storage.php
index 0e42df1e967..c4c523810ac 100644
--- a/apps/files_trashbin/lib/storage.php
+++ b/apps/files_trashbin/lib/storage.php
@@ -5,7 +5,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +26,7 @@ namespace OCA\Files_Trashbin;
use OC\Files\Filesystem;
use OC\Files\Storage\Wrapper\Wrapper;
+use OC\Files\View;
use OCP\IUserManager;
class Storage extends Wrapper {
@@ -151,8 +152,8 @@ class Storage extends Wrapper {
$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
$result = true;
- if (!isset($this->deletedFiles[$normalized])) {
- $view = Filesystem::getView();
+ $view = Filesystem::getView();
+ if (!isset($this->deletedFiles[$normalized]) && $view instanceof View) {
$this->deletedFiles[$normalized] = $normalized;
if ($filesPath = $view->getRelativePath($normalized)) {
$filesPath = trim($filesPath, '/');
diff --git a/apps/files_trashbin/lib/trashbin.php b/apps/files_trashbin/lib/trashbin.php
index 8f0fe745a45..ca3a8b178a2 100644
--- a/apps/files_trashbin/lib/trashbin.php
+++ b/apps/files_trashbin/lib/trashbin.php
@@ -11,14 +11,15 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Qingping Hou <dave2008713@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Sjors van der Pluijm <sjors@desjors.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -62,7 +63,11 @@ class Trashbin {
* @param array $params
*/
public static function ensureFileScannedHook($params) {
- self::getUidAndFilename($params['path']);
+ try {
+ self::getUidAndFilename($params['path']);
+ } catch (NotFoundException $e) {
+ // nothing to scan for non existing files
+ }
}
/**
@@ -71,18 +76,7 @@ class Trashbin {
* @throws \OC\User\NoUserException
*/
public static function getUidAndFilename($filename) {
- $uid = \OC\Files\Filesystem::getOwner($filename);
- \OC\Files\Filesystem::initMountPoints($uid);
- if ($uid != \OCP\User::getUser()) {
- $info = \OC\Files\Filesystem::getFileInfo($filename);
- $ownerView = new \OC\Files\View('/' . $uid . '/files');
- try {
- $filename = $ownerView->getPath($info['fileid']);
- } catch (NotFoundException $e) {
- $filename = null;
- }
- }
- return [$uid, $filename];
+ return Filesystem::getView()->getUidAndFilename($filename);
}
/**
@@ -147,7 +141,7 @@ class Trashbin {
*
* @param string $sourcePath
* @param string $owner
- * @param $targetPath
+ * @param string $targetPath
* @param $user
* @param integer $timestamp
*/
@@ -186,7 +180,6 @@ class Trashbin {
// get the user for which the filesystem is setup
$root = Filesystem::getRoot();
list(, $user) = explode('/', $root);
- $size = 0;
list($owner, $ownerPath) = self::getUidAndFilename($file_path);
$ownerView = new \OC\Files\View('/' . $owner);
@@ -207,8 +200,6 @@ class Trashbin {
$location = $path_parts['dirname'];
$timestamp = time();
- $userTrashSize = self::getTrashbinSize($user);
-
// disable proxy to prevent recursive calls
$trashPath = '/files_trashbin/files/' . $filename . '.d' . $timestamp;
@@ -217,13 +208,13 @@ class Trashbin {
/** @var \OC\Files\Storage\Storage $sourceStorage */
list($sourceStorage, $sourceInternalPath) = $ownerView->resolvePath('/files/' . $ownerPath);
try {
- $sizeOfAddedFiles = $sourceStorage->filesize($sourceInternalPath);
+ $moveSuccessful = true;
if ($trashStorage->file_exists($trashInternalPath)) {
$trashStorage->unlink($trashInternalPath);
}
$trashStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath);
} catch (\OCA\Files_Trashbin\Exceptions\CopyRecursiveException $e) {
- $sizeOfAddedFiles = false;
+ $moveSuccessful = false;
if ($trashStorage->file_exists($trashInternalPath)) {
$trashStorage->unlink($trashInternalPath);
}
@@ -235,10 +226,9 @@ class Trashbin {
return false;
}
- $ownerView->getUpdater()->rename('/files/' . $ownerPath, $trashPath);
+ $trashStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath);
- if ($sizeOfAddedFiles !== false) {
- $size = $sizeOfAddedFiles;
+ if ($moveSuccessful) {
$query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?)");
$result = $query->execute(array($filename, $timestamp, $location, $owner));
if (!$result) {
@@ -247,7 +237,7 @@ class Trashbin {
\OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_moveToTrash', array('filePath' => \OC\Files\Filesystem::normalizePath($file_path),
'trashPath' => \OC\Files\Filesystem::normalizePath($filename . '.d' . $timestamp)));
- $size += self::retainVersions($filename, $owner, $ownerPath, $timestamp);
+ self::retainVersions($filename, $owner, $ownerPath, $timestamp);
// if owner !== user we need to also add a copy to the owners trash
if ($user !== $owner) {
@@ -255,17 +245,14 @@ class Trashbin {
}
}
- $userTrashSize += $size;
- self::scheduleExpire($userTrashSize, $user);
+ self::scheduleExpire($user);
// if owner !== user we also need to update the owners trash size
if ($owner !== $user) {
- $ownerTrashSize = self::getTrashbinSize($owner);
- $ownerTrashSize += $size;
- self::scheduleExpire($ownerTrashSize, $owner);
+ self::scheduleExpire($owner);
}
- return ($sizeOfAddedFiles === false) ? false : true;
+ return $moveSuccessful;
}
/**
@@ -275,18 +262,14 @@ class Trashbin {
* @param string $owner owner user id
* @param string $ownerPath path relative to the owner's home storage
* @param integer $timestamp when the file was deleted
- *
- * @return int size of stored versions
*/
private static function retainVersions($filename, $owner, $ownerPath, $timestamp) {
- $size = 0;
if (\OCP\App::isEnabled('files_versions') && !empty($ownerPath)) {
$user = \OCP\User::getUser();
$rootView = new \OC\Files\View('/');
if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
- $size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath));
if ($owner !== $user) {
self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
}
@@ -294,7 +277,6 @@ class Trashbin {
} else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
foreach ($versions as $v) {
- $size += $rootView->filesize($owner . '/files_versions/' . $v['path'] . '.v' . $v['version']);
if ($owner !== $user) {
self::copy($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $owner . '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp);
}
@@ -302,8 +284,6 @@ class Trashbin {
}
}
}
-
- return $size;
}
/**
@@ -323,7 +303,7 @@ class Trashbin {
$result = $targetStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
if ($result) {
- $view->getUpdater()->rename($source, $target);
+ $targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
}
return $result;
}
@@ -345,7 +325,7 @@ class Trashbin {
$result = $targetStorage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
if ($result) {
- $view->getUpdater()->update($target);
+ $targetStorage->getUpdater()->update($targetInternalPath);
}
return $result;
}
@@ -424,7 +404,7 @@ class Trashbin {
* @param string $uniqueFilename new file name to restore the file without overwriting existing files
* @param string $location location if file
* @param int $timestamp deletion time
- * @return bool
+ * @return false|null
*/
private static function restoreVersions(\OC\Files\View $view, $file, $filename, $uniqueFilename, $location, $timestamp) {
@@ -514,9 +494,10 @@ class Trashbin {
/**
* @param \OC\Files\View $view
- * @param $file
- * @param $filename
- * @param $timestamp
+ * @param string $file
+ * @param string $filename
+ * @param integer|null $timestamp
+ * @param string $user
* @return int
*/
private static function deleteVersions(\OC\Files\View $view, $file, $filename, $timestamp, $user) {
@@ -628,41 +609,39 @@ class Trashbin {
$freeSpace = self::calculateFreeSpace($size, $user);
if ($freeSpace < 0) {
- self::scheduleExpire($size, $user);
+ self::scheduleExpire($user);
}
}
/**
* clean up the trash bin
*
- * @param int $trashBinSize current size of the trash bin
* @param string $user
*/
- public static function expire($trashBinSize, $user) {
+ public static function expire($user) {
+ $trashBinSize = self::getTrashbinSize($user);
$availableSpace = self::calculateFreeSpace($trashBinSize, $user);
- $size = 0;
$dirContent = Helper::getTrashFiles('/', $user, 'mtime');
// delete all files older then $retention_obligation
list($delSize, $count) = self::deleteExpiredFiles($dirContent, $user);
- $size += $delSize;
- $availableSpace += $size;
+ $availableSpace += $delSize;
// delete files from trash until we meet the trash bin size limit again
- $size += self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace);
+ self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace);
}
- /**@param int $trashBinSize current size of the trash bin
+ /**
* @param string $user
*/
- private static function scheduleExpire($trashBinSize, $user) {
+ private static function scheduleExpire($user) {
// let the admin disable auto expire
$application = new Application();
$expiration = $application->getContainer()->query('Expiration');
if ($expiration->isEnabled()) {
- \OC::$server->getCommandBus()->push(new Expire($user, $trashBinSize));
+ \OC::$server->getCommandBus()->push(new Expire($user));
}
}
@@ -700,7 +679,7 @@ class Trashbin {
*
* @param array $files list of files sorted by mtime
* @param string $user
- * @return array size of deleted files and number of deleted files
+ * @return integer[] size of deleted files and number of deleted files
*/
public static function deleteExpiredFiles($files, $user) {
$application = new Application();
diff --git a/apps/files_trashbin/list.php b/apps/files_trashbin/list.php
index 890f03aa09a..caf3296eb94 100644
--- a/apps/files_trashbin/list.php
+++ b/apps/files_trashbin/list.php
@@ -4,7 +4,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php
index b5c1c622156..a7c1df93af2 100644
--- a/apps/files_trashbin/templates/index.php
+++ b/apps/files_trashbin/templates/index.php
@@ -31,7 +31,7 @@
<span id="selectedActionsList" class='selectedActions'>
<a href="" class="undelete">
<img class="svg" alt=""
- src="<?php print_unescaped(OCP\image_path("core", "actions/history.svg")); ?>" />
+ src="<?php print_unescaped(image_path("core", "actions/history.svg")); ?>" />
<?php p($l->t('Restore'))?>
</a>
</span>
@@ -43,7 +43,7 @@
<a href="" class="delete-selected">
<?php p($l->t('Delete'))?>
<img class="svg" alt=""
- src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
+ src="<?php print_unescaped(image_path("core", "actions/delete.svg")); ?>" />
</a>
</span>
</th>
diff --git a/apps/files_trashbin/tests/backgroundjob/expiretrash.php b/apps/files_trashbin/tests/backgroundjob/expiretrash.php
index ad7b0fbca28..79fc91884fc 100644
--- a/apps/files_trashbin/tests/backgroundjob/expiretrash.php
+++ b/apps/files_trashbin/tests/backgroundjob/expiretrash.php
@@ -2,7 +2,7 @@
/**
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/tests/command/cleanuptest.php b/apps/files_trashbin/tests/command/cleanuptest.php
index e928f55eb8b..d71c4ecd85d 100644
--- a/apps/files_trashbin/tests/command/cleanuptest.php
+++ b/apps/files_trashbin/tests/command/cleanuptest.php
@@ -2,8 +2,9 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,6 +30,13 @@ use Test\TestCase;
use OC\User\Manager;
use OCP\Files\IRootFolder;
+/**
+ * Class CleanUpTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files_Trashbin\Tests\Command
+ */
class CleanUpTest extends TestCase {
/** @var CleanUp */
diff --git a/apps/files_trashbin/tests/command/expiretest.php b/apps/files_trashbin/tests/command/expiretest.php
index a6a8a6d53a8..e481e29330f 100644
--- a/apps/files_trashbin/tests/command/expiretest.php
+++ b/apps/files_trashbin/tests/command/expiretest.php
@@ -1,8 +1,10 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,9 +26,16 @@ namespace OCA\Files_Trashbin\Tests\Command;
use OCA\Files_Trashbin\Command\Expire;
use Test\TestCase;
+/**
+ * Class ExpireTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files_Trashbin\Tests\Command
+ */
class ExpireTest extends TestCase {
public function testExpireNonExistingUser() {
- $command = new Expire('test', 0);
+ $command = new Expire('test');
$command->handle();
$this->assertTrue(true);
diff --git a/apps/files_trashbin/tests/expiration.php b/apps/files_trashbin/tests/expiration.php
index c142133ceb7..420d255947e 100644
--- a/apps/files_trashbin/tests/expiration.php
+++ b/apps/files_trashbin/tests/expiration.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_trashbin/tests/storage.php b/apps/files_trashbin/tests/storage.php
index 44b680f265c..958c5f79a98 100644
--- a/apps/files_trashbin/tests/storage.php
+++ b/apps/files_trashbin/tests/storage.php
@@ -3,9 +3,11 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,6 +29,13 @@ namespace OCA\Files_trashbin\Tests\Storage;
use OC\Files\Storage\Temporary;
use OC\Files\Filesystem;
+/**
+ * Class Storage
+ *
+ * @group DB
+ *
+ * @package OCA\Files_trashbin\Tests\Storage
+ */
class Storage extends \Test\TestCase {
/**
* @var string
@@ -68,7 +77,8 @@ class Storage extends \Test\TestCase {
protected function tearDown() {
\OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin');
$this->logout();
- \OC_User::deleteUser($this->user);
+ $user = \OC::$server->getUserManager()->get($this->user);
+ if ($user !== null) { $user->delete(); }
\OC_Hook::clear();
parent::tearDown();
}
@@ -524,4 +534,17 @@ class Storage extends \Test\TestCase {
['/schiesbn/', '/test.txt', false, false],
];
}
+
+ /**
+ * Test that deleting a file doesn't error when nobody is logged in
+ */
+ public function testSingleStorageDeleteFileLoggedOut() {
+ $this->logout();
+
+ if (!$this->userView->file_exists('test.txt')) {
+ $this->markTestSkipped('Skipping since the current home storage backend requires the user to logged in');
+ } else {
+ $this->userView->unlink('test.txt');
+ }
+ }
}
diff --git a/apps/files_trashbin/tests/trashbin.php b/apps/files_trashbin/tests/trashbin.php
index e28b854ca1f..7844e95084a 100644
--- a/apps/files_trashbin/tests/trashbin.php
+++ b/apps/files_trashbin/tests/trashbin.php
@@ -5,10 +5,12 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Victor Dubiniuk <dubiniuk@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,6 +31,8 @@ use OCA\Files_Trashbin;
/**
* Class Test_Encryption
+ *
+ * @group DB
*/
class Test_Trashbin extends \Test\TestCase {
@@ -65,14 +69,14 @@ class Test_Trashbin extends \Test\TestCase {
\OC::registerShareHooks();
$application = new \OCA\Files_Sharing\AppInfo\Application();
$application->registerMountProviders();
- $application->setupPropagation();
//disable encryption
\OC_App::disable('encryption');
+ $config = \OC::$server->getConfig();
//configure trashbin
- self::$rememberRetentionObligation = \OC_Config::getValue('trashbin_retention_obligation', Files_Trashbin\Expiration::DEFAULT_RETENTION_OBLIGATION);
- \OC_Config::setValue('trashbin_retention_obligation', 'auto, 2');
+ self::$rememberRetentionObligation = $config->getSystemValue('trashbin_retention_obligation', Files_Trashbin\Expiration::DEFAULT_RETENTION_OBLIGATION);
+ $config->setSystemValue('trashbin_retention_obligation', 'auto, 2');
// register hooks
Files_Trashbin\Trashbin::registerHooks();
@@ -86,9 +90,10 @@ class Test_Trashbin extends \Test\TestCase {
public static function tearDownAfterClass() {
// cleanup test user
- \OC_User::deleteUser(self::TEST_TRASHBIN_USER1);
+ $user = \OC::$server->getUserManager()->get(self::TEST_TRASHBIN_USER1);
+ if ($user !== null) { $user->delete(); }
- \OC_Config::setValue('trashbin_retention_obligation', self::$rememberRetentionObligation);
+ \OC::$server->getConfig()->setSystemValue('trashbin_retention_obligation', self::$rememberRetentionObligation);
\OC_Hook::clear();
@@ -246,8 +251,8 @@ class Test_Trashbin extends \Test\TestCase {
/**
* verify that the array contains the expected results
- * @param array $result
- * @param array $expected
+ * @param OCP\Files\FileInfo[] $result
+ * @param string[] $expected
*/
private function verifyArray($result, $expected) {
$this->assertSame(count($expected), count($result));
@@ -266,6 +271,11 @@ class Test_Trashbin extends \Test\TestCase {
}
}
+ /**
+ * @param OCP\Files\FileInfo[] $files
+ * @param string $trashRoot
+ * @param integer $expireDate
+ */
private function manipulateDeleteTime($files, $trashRoot, $expireDate) {
$counter = 0;
foreach ($files as &$file) {
@@ -625,12 +635,11 @@ class Test_Trashbin extends \Test\TestCase {
/**
* @param string $user
* @param bool $create
- * @param bool $password
*/
public static function loginHelper($user, $create = false) {
if ($create) {
try {
- \OC_User::createUser($user, $user);
+ \OC::$server->getUserManager()->createUser($user, $user);
} catch(\Exception $e) { // catch username is already being used from previous aborted runs
}
@@ -648,11 +657,20 @@ class Test_Trashbin extends \Test\TestCase {
// just a dummy class to make protected methods available for testing
class TrashbinForTesting extends Files_Trashbin\Trashbin {
+
+ /**
+ * @param OCP\Files\FileInfo[] $files
+ * @param integer $limit
+ */
public function dummyDeleteExpiredFiles($files, $limit) {
// dummy value for $retention_obligation because it is not needed here
return parent::deleteExpiredFiles($files, \Test_Trashbin::TEST_TRASHBIN_USER1, $limit, 0);
}
+ /**
+ * @param OCP\Files\FileInfo[] $files
+ * @param integer $availableSpace
+ */
public function dummyDeleteFiles($files, $availableSpace) {
return parent::deleteFiles($files, \Test_Trashbin::TEST_TRASHBIN_USER1, $availableSpace);
}
diff --git a/apps/files_versions/ajax/getVersions.php b/apps/files_versions/ajax/getVersions.php
index d50545f7c69..1953a55d13d 100644
--- a/apps/files_versions/ajax/getVersions.php
+++ b/apps/files_versions/ajax/getVersions.php
@@ -7,7 +7,7 @@
* @author Sam Tuke <mail@samtuke.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/ajax/preview.php b/apps/files_versions/ajax/preview.php
index 0da518f3eaa..c0a9828b1f0 100644
--- a/apps/files_versions/ajax/preview.php
+++ b/apps/files_versions/ajax/preview.php
@@ -1,11 +1,12 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -48,7 +49,7 @@ if($maxX === 0 || $maxY === 0) {
try {
list($user, $file) = \OCA\Files_Versions\Storage::getUidAndFilename($file);
$preview = new \OC\Preview($user, 'files_versions', $file.'.v'.$version);
- $mimetype = \OC_Helper::getFileNameMimeType($file);
+ $mimetype = \OC::$server->getMimeTypeDetector()->detectPath($file);
$preview->setMimetype($mimetype);
$preview->setMaxX($maxX);
$preview->setMaxY($maxY);
diff --git a/apps/files_versions/ajax/rollbackVersion.php b/apps/files_versions/ajax/rollbackVersion.php
index e75df28dbcd..7700c03a144 100644
--- a/apps/files_versions/ajax/rollbackVersion.php
+++ b/apps/files_versions/ajax/rollbackVersion.php
@@ -9,7 +9,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/appinfo/app.php b/apps/files_versions/appinfo/app.php
index 89990fdf0d8..b653d0d345b 100644
--- a/apps/files_versions/appinfo/app.php
+++ b/apps/files_versions/appinfo/app.php
@@ -4,7 +4,7 @@
* @author Frank Karlitschek <frank@owncloud.org>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/appinfo/application.php b/apps/files_versions/appinfo/application.php
index ba0a2ae74cb..b32cf54729d 100644
--- a/apps/files_versions/appinfo/application.php
+++ b/apps/files_versions/appinfo/application.php
@@ -3,7 +3,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/appinfo/info.xml b/apps/files_versions/appinfo/info.xml
index 8fe6372279a..0098ea9e20f 100644
--- a/apps/files_versions/appinfo/info.xml
+++ b/apps/files_versions/appinfo/info.xml
@@ -4,7 +4,6 @@
<name>Versions</name>
<licence>AGPL</licence>
<author>Frank Karlitschek, Bjoern Schiessle</author>
- <shipped>true</shipped>
<description>
This application enables ownCloud to automatically maintain older versions of files that are changed. When enabled, a hidden versions folder is provisioned in every user’s directory and is used to store old file versions. A user can revert to an older version through the web interface at any time, with the replaced file becoming a version. ownCloud then automatically manages the versions folder to ensure the user doesn’t run out of Quota because of versions.
In addition to the expiry of versions, ownCloud’s versions app makes certain never to use more than 50% of the user’s currently available free space. If stored versions exceed this limit, ownCloud will delete the oldest versions first until it meets this limit. More information is available in the Versions documentation.
@@ -15,7 +14,7 @@ In addition to the expiry of versions, ownCloud’s versions app makes certain n
<filesystem/>
</types>
<dependencies>
- <owncloud min-version="9.0" />
+ <owncloud min-version="9.0" max-version="9.0" />
</dependencies>
<documentation>
<user>user-versions</user>
diff --git a/apps/files_versions/appinfo/install.php b/apps/files_versions/appinfo/install.php
index d72ba2f56e5..81ff6337aa0 100644
--- a/apps/files_versions/appinfo/install.php
+++ b/apps/files_versions/appinfo/install.php
@@ -2,7 +2,7 @@
/**
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/appinfo/register_command.php b/apps/files_versions/appinfo/register_command.php
index 49efdbe6190..ee0e860dfba 100644
--- a/apps/files_versions/appinfo/register_command.php
+++ b/apps/files_versions/appinfo/register_command.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/appinfo/routes.php b/apps/files_versions/appinfo/routes.php
index b2ed477de68..4db52cb3870 100644
--- a/apps/files_versions/appinfo/routes.php
+++ b/apps/files_versions/appinfo/routes.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/appinfo/update.php b/apps/files_versions/appinfo/update.php
index ef6772f3079..09ac6ce8a2f 100644
--- a/apps/files_versions/appinfo/update.php
+++ b/apps/files_versions/appinfo/update.php
@@ -1,10 +1,8 @@
<?php
/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,11 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-$installedVersion=OCP\Config::getAppValue('files_versions', 'installed_version');
-// move versions to new directory
-if (version_compare($installedVersion, '1.0.4', '<')) {
- \OC_DB::dropTable("files_versions");
-}
// Cron job for deleting expired trash items
\OC::$server->getJobList()->add('OCA\Files_Versions\BackgroundJob\ExpireVersions');
diff --git a/apps/files_versions/command/cleanup.php b/apps/files_versions/command/cleanup.php
index bed6dd01773..1abf62763b1 100644
--- a/apps/files_versions/command/cleanup.php
+++ b/apps/files_versions/command/cleanup.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/command/expire.php b/apps/files_versions/command/expire.php
index 5db33f38772..b1f72980633 100644
--- a/apps/files_versions/command/expire.php
+++ b/apps/files_versions/command/expire.php
@@ -1,9 +1,10 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,16 +36,6 @@ class Expire implements ICommand {
private $fileName;
/**
- * @var int|null
- */
- private $versionsSize;
-
- /**
- * @var int
- */
- private $neededSpace = 0;
-
- /**
* @var string
*/
private $user;
@@ -52,14 +43,10 @@ class Expire implements ICommand {
/**
* @param string $user
* @param string $fileName
- * @param int|null $versionsSize
- * @param int $neededSpace
*/
- function __construct($user, $fileName, $versionsSize = null, $neededSpace = 0) {
+ function __construct($user, $fileName) {
$this->user = $user;
$this->fileName = $fileName;
- $this->versionsSize = $versionsSize;
- $this->neededSpace = $neededSpace;
}
@@ -71,7 +58,7 @@ class Expire implements ICommand {
}
\OC_Util::setupFS($this->user);
- Storage::expire($this->fileName, $this->versionsSize, $this->neededSpace);
+ Storage::expire($this->fileName);
\OC_Util::tearDownFS();
}
}
diff --git a/apps/files_versions/download.php b/apps/files_versions/download.php
index 22a218f472a..b3742d79de1 100644
--- a/apps/files_versions/download.php
+++ b/apps/files_versions/download.php
@@ -4,9 +4,10 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,7 +36,7 @@ $versionName = '/'.$uid.'/files_versions/'.$filename.'.v'.$revision;
$view = new OC\Files\View('/');
-$ftype = \OC_Helper::getSecureMimeType($view->getMimeType('/'.$uid.'/files/'.$filename));
+$ftype = \OC::$server->getMimeTypeDetector()->getSecureMimeType($view->getMimeType('/'.$uid.'/files/'.$filename));
header('Content-Type:'.$ftype);
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
diff --git a/apps/files_versions/l10n/he.js b/apps/files_versions/l10n/he.js
index ecb859bb7f8..c240aff76a9 100644
--- a/apps/files_versions/l10n/he.js
+++ b/apps/files_versions/l10n/he.js
@@ -3,6 +3,9 @@ OC.L10N.register(
{
"Could not revert: %s" : "לא ניתן להחזיר: %s",
"Versions" : "גרסאות",
- "Restore" : "שחזור"
+ "Failed to revert {file} to revision {timestamp}." : "נכשל אחזור {file} לגרסה {timestamp}.",
+ "Restore" : "שחזור",
+ "No other versions available" : "אין גרסאות אחרות זמינות",
+ "More versions..." : "גרסאות נוספות..."
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_versions/l10n/he.json b/apps/files_versions/l10n/he.json
index 6cedccc663c..11bd3077abf 100644
--- a/apps/files_versions/l10n/he.json
+++ b/apps/files_versions/l10n/he.json
@@ -1,6 +1,9 @@
{ "translations": {
"Could not revert: %s" : "לא ניתן להחזיר: %s",
"Versions" : "גרסאות",
- "Restore" : "שחזור"
+ "Failed to revert {file} to revision {timestamp}." : "נכשל אחזור {file} לגרסה {timestamp}.",
+ "Restore" : "שחזור",
+ "No other versions available" : "אין גרסאות אחרות זמינות",
+ "More versions..." : "גרסאות נוספות..."
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_versions/l10n/hy.js b/apps/files_versions/l10n/hy.js
index 3924810e149..d48487a9a84 100644
--- a/apps/files_versions/l10n/hy.js
+++ b/apps/files_versions/l10n/hy.js
@@ -2,6 +2,7 @@ OC.L10N.register(
"files_versions",
{
"Versions" : "Տարբերակներ",
- "Restore" : "Վերականգնել"
+ "Restore" : "Վերականգնել",
+ "No other versions available" : "Այլ տարբերակներ չկան"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_versions/l10n/hy.json b/apps/files_versions/l10n/hy.json
index 7f61c267c7c..579b9240310 100644
--- a/apps/files_versions/l10n/hy.json
+++ b/apps/files_versions/l10n/hy.json
@@ -1,5 +1,6 @@
{ "translations": {
"Versions" : "Տարբերակներ",
- "Restore" : "Վերականգնել"
+ "Restore" : "Վերականգնել",
+ "No other versions available" : "Այլ տարբերակներ չկան"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_versions/lib/backgroundjob/expireversions.php b/apps/files_versions/lib/backgroundjob/expireversions.php
index afdd5eed57a..5d8eef4e351 100644
--- a/apps/files_versions/lib/backgroundjob/expireversions.php
+++ b/apps/files_versions/lib/backgroundjob/expireversions.php
@@ -2,7 +2,7 @@
/**
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/lib/capabilities.php b/apps/files_versions/lib/capabilities.php
index ba4de906c70..441b2adfba3 100644
--- a/apps/files_versions/lib/capabilities.php
+++ b/apps/files_versions/lib/capabilities.php
@@ -5,7 +5,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/lib/expiration.php b/apps/files_versions/lib/expiration.php
index 4b3cecc1202..ffc7640e7f9 100644
--- a/apps/files_versions/lib/expiration.php
+++ b/apps/files_versions/lib/expiration.php
@@ -2,7 +2,7 @@
/**
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/lib/hooks.php b/apps/files_versions/lib/hooks.php
index f9d9eddf5e2..beaf81c7471 100644
--- a/apps/files_versions/lib/hooks.php
+++ b/apps/files_versions/lib/hooks.php
@@ -5,11 +5,11 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Sam Tuke <mail@samtuke.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/lib/storage.php b/apps/files_versions/lib/storage.php
index 6737bf20f90..35b3110928b 100644
--- a/apps/files_versions/lib/storage.php
+++ b/apps/files_versions/lib/storage.php
@@ -10,13 +10,13 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -41,10 +41,10 @@
namespace OCA\Files_Versions;
+use OC\Files\Filesystem;
use OCA\Files_Versions\AppInfo\Application;
use OCA\Files_Versions\Command\Expire;
use OCP\Lock\ILockingProvider;
-use OCP\Files\NotFoundException;
class Storage {
@@ -81,18 +81,7 @@ class Storage {
* @throws \OC\User\NoUserException
*/
public static function getUidAndFilename($filename) {
- $uid = \OC\Files\Filesystem::getOwner($filename);
- \OC\Files\Filesystem::initMountPoints($uid);
- if ( $uid != \OCP\User::getUser() ) {
- $info = \OC\Files\Filesystem::getFileInfo($filename);
- $ownerView = new \OC\Files\View('/'.$uid.'/files');
- try {
- $filename = $ownerView->getPath($info['fileid']);
- } catch (NotFoundException $e) {
- $filename = null;
- }
- }
- return [$uid, $filename];
+ return Filesystem::getView()->getUidAndFilename($filename);
}
/**
@@ -145,7 +134,12 @@ class Storage {
// to get the right target
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if ($ext === 'part') {
- $filename = substr($filename, 0, strlen($filename)-5);
+ $filename = substr($filename, 0, strlen($filename) - 5);
+ }
+
+ // we only handle existing files
+ if (! Filesystem::file_exists($filename) || Filesystem::is_dir($filename)) {
+ return false;
}
list($uid, $filename) = self::getUidAndFilename($filename);
@@ -153,29 +147,15 @@ class Storage {
$files_view = new \OC\Files\View('/'.$uid .'/files');
$users_view = new \OC\Files\View('/'.$uid);
- // check if filename is a directory
- if($files_view->is_dir($filename)) {
- return false;
- }
-
- // we should have a source file to work with, and the file shouldn't
- // be empty
- $fileExists = $files_view->file_exists($filename);
- if (!($fileExists && $files_view->filesize($filename) > 0)) {
+ // no use making versions for empty files
+ if ($files_view->filesize($filename) === 0) {
return false;
}
// create all parent folders
self::createMissingDirectories($filename, $users_view);
- $versionsSize = self::getVersionsSize($uid);
-
- // assumption: we need filesize($filename) for the new version +
- // some more free space for the modified file which might be
- // 1.5 times as large as the current version -> 2.5
- $neededSpace = $files_view->filesize($filename) * 2.5;
-
- self::scheduleExpire($uid, $filename, $versionsSize, $neededSpace);
+ self::scheduleExpire($uid, $filename);
// store a new version of a file
$mtime = $users_view->filemtime('files/' . $filename);
@@ -634,14 +614,12 @@ class Storage {
*
* @param string $uid owner of the file
* @param string $fileName file/folder for which to schedule expiration
- * @param int|null $versionsSize current versions size
- * @param int $neededSpace requested versions size
*/
- private static function scheduleExpire($uid, $fileName, $versionsSize = null, $neededSpace = 0) {
+ private static function scheduleExpire($uid, $fileName) {
// let the admin disable auto expire
$expiration = self::getExpiration();
if ($expiration->isEnabled()) {
- $command = new Expire($uid, $fileName, $versionsSize, $neededSpace);
+ $command = new Expire($uid, $fileName);
\OC::$server->getCommandBus()->push($command);
}
}
@@ -649,16 +627,19 @@ class Storage {
/**
* Expire versions which exceed the quota
*
- * @param $filename
- * @param int|null $versionsSize
- * @param int $offset
+ * @param string $filename
* @return bool|int|null
*/
- public static function expire($filename, $versionsSize = null, $offset = 0) {
+ public static function expire($filename) {
$config = \OC::$server->getConfig();
$expiration = self::getExpiration();
if($config->getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' && $expiration->isEnabled()) {
+
+ if (!Filesystem::file_exists($filename)) {
+ return false;
+ }
+
list($uid, $filename) = self::getUidAndFilename($filename);
if (empty($filename)) {
// file maybe renamed or deleted
@@ -680,9 +661,7 @@ class Storage {
}
// make sure that we have the current size of the version history
- if ( $versionsSize === null ) {
- $versionsSize = self::getVersionsSize($uid);
- }
+ $versionsSize = self::getVersionsSize($uid);
// calculate available space for version history
// subtract size of files and current versions size from quota
@@ -692,12 +671,12 @@ class Storage {
$rootInfo = $files_view->getFileInfo('/', false);
$free = $quota - $rootInfo['size']; // remaining free space for user
if ($free > 0) {
- $availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - ($versionsSize + $offset); // how much space can be used for versions
+ $availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $versionsSize; // how much space can be used for versions
} else {
- $availableSpace = $free - $versionsSize - $offset;
+ $availableSpace = $free - $versionsSize;
}
} else {
- $availableSpace = $quota - $offset;
+ $availableSpace = $quota;
}
} else {
$availableSpace = PHP_INT_MAX;
diff --git a/apps/files_versions/tests/command/cleanuptest.php b/apps/files_versions/tests/command/cleanuptest.php
index bfde25d75ce..af217b18893 100644
--- a/apps/files_versions/tests/command/cleanuptest.php
+++ b/apps/files_versions/tests/command/cleanuptest.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,6 +29,13 @@ use Test\TestCase;
use OC\User\Manager;
use OCP\Files\IRootFolder;
+/**
+ * Class CleanupTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files_Versions\Tests\Command
+ */
class CleanupTest extends TestCase {
/** @var CleanUp */
diff --git a/apps/files_versions/tests/command/expiretest.php b/apps/files_versions/tests/command/expiretest.php
index eccc1f4c2ad..f89ece82515 100644
--- a/apps/files_versions/tests/command/expiretest.php
+++ b/apps/files_versions/tests/command/expiretest.php
@@ -2,8 +2,9 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +26,13 @@ namespace OCA\Files_Versions\Tests\Command;
use OCA\Files_Versions\Command\Expire;
use Test\TestCase;
+/**
+ * Class ExpireTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files_Versions\Tests\Command
+ */
class ExpireTest extends TestCase {
public function testExpireNonExistingUser() {
$command = new Expire($this->getUniqueID('test'), '');
diff --git a/apps/files_versions/tests/expirationtest.php b/apps/files_versions/tests/expirationtest.php
index 1081e412ce9..2dfff19f230 100644
--- a/apps/files_versions/tests/expirationtest.php
+++ b/apps/files_versions/tests/expirationtest.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/files_versions/tests/versions.php b/apps/files_versions/tests/versions.php
index b9bc0932a84..b85877cebd3 100644
--- a/apps/files_versions/tests/versions.php
+++ b/apps/files_versions/tests/versions.php
@@ -7,10 +7,11 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -34,6 +35,8 @@ use OC\Files\Storage\Temporary;
/**
* Class Test_Files_versions
* this class provide basic files versions test
+ *
+ * @group DB
*/
class Test_Files_Versioning extends \Test\TestCase {
@@ -51,7 +54,6 @@ class Test_Files_Versioning extends \Test\TestCase {
$application = new \OCA\Files_Sharing\AppInfo\Application();
$application->registerMountProviders();
- $application->setupPropagation();
// create test user
self::loginHelper(self::TEST_VERSIONS_USER2, true);
@@ -60,8 +62,10 @@ class Test_Files_Versioning extends \Test\TestCase {
public static function tearDownAfterClass() {
// cleanup test user
- \OC_User::deleteUser(self::TEST_VERSIONS_USER);
- \OC_User::deleteUser(self::TEST_VERSIONS_USER2);
+ $user = \OC::$server->getUserManager()->get(self::TEST_VERSIONS_USER);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get(self::TEST_VERSIONS_USER2);
+ if ($user !== null) { $user->delete(); }
parent::tearDownAfterClass();
}
@@ -82,10 +86,12 @@ class Test_Files_Versioning extends \Test\TestCase {
}
protected function tearDown() {
- $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files/');
- $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files/');
- $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/');
- $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/');
+ if ($this->rootView) {
+ $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files/');
+ $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files/');
+ $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/');
+ $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/');
+ }
\OC_Hook::clear();
@@ -796,9 +802,9 @@ class Test_Files_Versioning extends \Test\TestCase {
}
$storage = new \ReflectionClass('\OC\Files\Storage\Shared');
- $isInitialized = $storage->getProperty('isInitialized');
+ $isInitialized = $storage->getProperty('initialized');
$isInitialized->setAccessible(true);
- $isInitialized->setValue(array());
+ $isInitialized->setValue($storage, false);
$isInitialized->setAccessible(false);
\OC_Util::tearDownFS();
diff --git a/apps/provisioning_api/appinfo/info.xml b/apps/provisioning_api/appinfo/info.xml
index a77b1f67e21..e75f032008c 100644
--- a/apps/provisioning_api/appinfo/info.xml
+++ b/apps/provisioning_api/appinfo/info.xml
@@ -13,17 +13,15 @@
</description>
<licence>AGPL</licence>
<author>Tom Needham</author>
- <shipped>true</shipped>
<default_enable/>
<documentation>
<admin>admin-provisioning-api</admin>
</documentation>
- <version>0.4.0</version>
+ <version>0.4.1</version>
<types>
- <!-- this is used to disable the feature of enabling an app for specific groups only because this would break this app -->
- <filesystem/>
+ <prevent_group_restriction/>
</types>
<dependencies>
- <owncloud min-version="9.0" />
+ <owncloud min-version="9.0" max-version="9.0" />
</dependencies>
</info>
diff --git a/apps/provisioning_api/appinfo/routes.php b/apps/provisioning_api/appinfo/routes.php
index 22a923f5c20..08411856e7e 100644
--- a/apps/provisioning_api/appinfo/routes.php
+++ b/apps/provisioning_api/appinfo/routes.php
@@ -7,7 +7,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -62,7 +62,8 @@ API::register('get', '/cloud/groups/{groupid}/subadmins', [$groups, 'getSubAdmin
// Apps
$apps = new \OCA\Provisioning_API\Apps(
- \OC::$server->getAppManager()
+ \OC::$server->getAppManager(),
+ \OC::$server->getOcsClient()
);
API::register('get', '/cloud/apps', [$apps, 'getApps'], 'provisioning_api', API::ADMIN_AUTH);
API::register('get', '/cloud/apps/{appid}', [$apps, 'getAppInfo'], 'provisioning_api', API::ADMIN_AUTH);
diff --git a/apps/provisioning_api/lib/apps.php b/apps/provisioning_api/lib/apps.php
index e0fa63cca34..f0079b8a8f3 100644
--- a/apps/provisioning_api/lib/apps.php
+++ b/apps/provisioning_api/lib/apps.php
@@ -6,7 +6,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,19 +25,23 @@
namespace OCA\Provisioning_API;
+use OC\OCSClient;
use \OC_OCS_Result;
use \OC_App;
class Apps {
-
/** @var \OCP\App\IAppManager */
private $appManager;
+ /** @var OCSClient */
+ private $ocsClient;
/**
* @param \OCP\App\IAppManager $appManager
*/
- public function __construct(\OCP\App\IAppManager $appManager) {
+ public function __construct(\OCP\App\IAppManager $appManager,
+ OCSClient $ocsClient) {
$this->appManager = $appManager;
+ $this->ocsClient = $ocsClient;
}
/**
@@ -45,7 +49,7 @@ class Apps {
* @return OC_OCS_Result
*/
public function getApps($parameters) {
- $apps = OC_App::listAllApps();
+ $apps = OC_App::listAllApps(false, true, $this->ocsClient);
$list = [];
foreach($apps as $app) {
$list[] = $app['id'];
diff --git a/apps/provisioning_api/lib/groups.php b/apps/provisioning_api/lib/groups.php
index 7c35caca5fd..6784894dbc9 100644
--- a/apps/provisioning_api/lib/groups.php
+++ b/apps/provisioning_api/lib/groups.php
@@ -6,7 +6,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -130,8 +130,8 @@ class Groups{
public function addGroup($parameters) {
// Validate name
$groupId = $this->request->getParam('groupid', '');
- if( preg_match( '/[^a-zA-Z0-9 _\.@\-]/', $groupId ) || empty($groupId)){
- \OCP\Util::writeLog('provisioning_api', 'Attempt made to create group using invalid characters.', \OCP\Util::ERROR);
+ if(empty($groupId)){
+ \OCP\Util::writeLog('provisioning_api', 'Group name not supplied', \OCP\Util::ERROR);
return new OC_OCS_Result(null, 101, 'Invalid group name');
}
// Check if it exists
@@ -176,14 +176,8 @@ class Groups{
foreach ($subadmins as $user) {
$uids[] = $user->getUID();
}
- $subadmins = $uids;
- // Go
- if(!$subadmins) {
- return new OC_OCS_Result(null, 102, 'Unknown error occured');
- } else {
- return new OC_OCS_Result($subadmins);
- }
+ return new OC_OCS_Result($uids);
}
}
diff --git a/apps/provisioning_api/lib/users.php b/apps/provisioning_api/lib/users.php
index a2568425d0f..efb10a50865 100644
--- a/apps/provisioning_api/lib/users.php
+++ b/apps/provisioning_api/lib/users.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -199,7 +199,7 @@ class Users {
// Find the data
$data['quota'] = $this->fillStorageInfo($userId);
- $data['email'] = $this->config->getUserValue($userId, 'settings', 'email');
+ $data['email'] = $targetUserObject->getEMailAddress();
$data['displayname'] = $targetUserObject->getDisplayName();
return new OC_OCS_Result($data);
@@ -285,7 +285,7 @@ class Users {
break;
case 'email':
if(filter_var($parameters['_put']['value'], FILTER_VALIDATE_EMAIL)) {
- $this->config->setUserValue($targetUserId, 'settings', 'email', $parameters['_put']['value']);
+ $targetUser->setEMailAddress($parameters['_put']['value']);
} else {
return new OC_OCS_Result(null, 102);
}
diff --git a/apps/provisioning_api/tests/appstest.php b/apps/provisioning_api/tests/appstest.php
index 2e1a86025c2..260bb4d527e 100644
--- a/apps/provisioning_api/tests/appstest.php
+++ b/apps/provisioning_api/tests/appstest.php
@@ -1,11 +1,13 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,35 +25,57 @@
*/
namespace OCA\Provisioning_API\Tests;
+use OC\OCSClient;
+use OCA\Provisioning_API\Apps;
+use OCP\API;
+use OCP\App\IAppManager;
+use OCP\IUserSession;
+/**
+ * Class AppsTest
+ *
+ * @group DB
+ *
+ * @package OCA\Provisioning_API\Tests
+ */
class AppsTest extends TestCase {
-
+ /** @var IAppManager */
+ private $appManager;
+ /** @var Apps */
+ private $api;
+ /** @var IUserSession */
+ private $userSession;
+ /** @var OCSClient */
+ private $ocsClient;
+
public function setup() {
parent::setup();
$this->appManager = \OC::$server->getAppManager();
$this->groupManager = \OC::$server->getGroupManager();
$this->userSession = \OC::$server->getUserSession();
- $this->api = new \OCA\Provisioning_API\Apps($this->appManager);
+ $this->ocsClient = $this->getMockBuilder('\OC\OCSClient')
+ ->disableOriginalConstructor()->getMock();
+ $this->api = new Apps($this->appManager, $this->ocsClient);
}
public function testGetAppInfo() {
$result = $this->api->getAppInfo(['appid' => 'provisioning_api']);
$this->assertInstanceOf('OC_OCS_Result', $result);
$this->assertTrue($result->succeeded());
-
}
public function testGetAppInfoOnBadAppID() {
-
$result = $this->api->getAppInfo(['appid' => 'not_provisioning_api']);
$this->assertInstanceOf('OC_OCS_Result', $result);
$this->assertFalse($result->succeeded());
- $this->assertEquals(\OCP\API::RESPOND_NOT_FOUND, $result->getStatusCode());
-
+ $this->assertEquals(API::RESPOND_NOT_FOUND, $result->getStatusCode());
}
public function testGetApps() {
-
+ $this->ocsClient
+ ->expects($this->any())
+ ->method($this->anything())
+ ->will($this->returnValue(null));
$user = $this->generateUsers();
$this->groupManager->get('admin')->addUser($user);
$this->userSession->setUser($user);
@@ -60,27 +84,27 @@ class AppsTest extends TestCase {
$this->assertTrue($result->succeeded());
$data = $result->getData();
- $this->assertEquals(count(\OC_App::listAllApps()), count($data['apps']));
-
+ $this->assertEquals(count(\OC_App::listAllApps(false, true, $this->ocsClient)), count($data['apps']));
}
public function testGetAppsEnabled() {
-
$_GET['filter'] = 'enabled';
$result = $this->api->getApps(['filter' => 'enabled']);
$this->assertTrue($result->succeeded());
$data = $result->getData();
$this->assertEquals(count(\OC_App::getEnabledApps()), count($data['apps']));
-
}
public function testGetAppsDisabled() {
-
+ $this->ocsClient
+ ->expects($this->any())
+ ->method($this->anything())
+ ->will($this->returnValue(null));
$_GET['filter'] = 'disabled';
$result = $this->api->getApps(['filter' => 'disabled']);
$this->assertTrue($result->succeeded());
$data = $result->getData();
- $apps = \OC_App::listAllApps();
+ $apps = \OC_App::listAllApps(false, true, $this->ocsClient);
$list = array();
foreach($apps as $app) {
$list[] = $app['id'];
diff --git a/apps/provisioning_api/tests/groupstest.php b/apps/provisioning_api/tests/groupstest.php
index 7d4beb6a368..a9c011d18ff 100644
--- a/apps/provisioning_api/tests/groupstest.php
+++ b/apps/provisioning_api/tests/groupstest.php
@@ -4,9 +4,10 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,13 +31,13 @@ use OCP\IUserSession;
use OCP\IRequest;
class GroupsTest extends \Test\TestCase {
- /** @var IGroupManager */
+ /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */
protected $groupManager;
- /** @var IUserSession */
+ /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */
protected $userSession;
- /** @var IRequest */
+ /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */
protected $request;
- /** @var \OC\SubAdmin */
+ /** @var \OC\SubAdmin|\PHPUnit_Framework_MockObject_MockObject */
protected $subAdminManager;
/** @var \OCA\Provisioning_API\Groups */
protected $api;
@@ -58,6 +59,10 @@ class GroupsTest extends \Test\TestCase {
);
}
+ /**
+ * @param string $gid
+ * @return \OCP\IGroup|\PHPUnit_Framework_MockObject_MockObject
+ */
private function createGroup($gid) {
$group = $this->getMock('OCP\IGroup');
$group
@@ -66,6 +71,10 @@ class GroupsTest extends \Test\TestCase {
return $group;
}
+ /**
+ * @param string $uid
+ * @return \OCP\IUser|\PHPUnit_Framework_MockObject_MockObject
+ */
private function createUser($uid) {
$user = $this->getMock('OCP\IUser');
$user
@@ -308,9 +317,8 @@ class GroupsTest extends \Test\TestCase {
]);
$this->assertInstanceOf('OC_OCS_Result', $result);
- $this->assertFalse($result->succeeded());
- $this->assertEquals(102, $result->getStatusCode());
- $this->assertEquals('Unknown error occured', $result->getMeta()['message']);
+ $this->assertTrue($result->succeeded());
+ $this->assertEquals([], $result->getData());
}
public function testAddGroupEmptyGroup() {
@@ -366,6 +374,27 @@ class GroupsTest extends \Test\TestCase {
$this->assertTrue($result->succeeded());
}
+ public function testAddGroupWithSpecialChar() {
+ $this->request
+ ->method('getParam')
+ ->with('groupid')
+ ->willReturn('Iñtërnâtiônàlizætiøn');
+
+ $this->groupManager
+ ->method('groupExists')
+ ->with('Iñtërnâtiônàlizætiøn')
+ ->willReturn(false);
+
+ $this->groupManager
+ ->expects($this->once())
+ ->method('createGroup')
+ ->with('Iñtërnâtiônàlizætiøn');
+
+ $result = $this->api->addGroup([]);
+ $this->assertInstanceOf('OC_OCS_Result', $result);
+ $this->assertTrue($result->succeeded());
+ }
+
public function testDeleteGroupNonExisting() {
$result = $this->api->deleteGroup([
'groupid' => 'NonExistingGroup'
diff --git a/apps/provisioning_api/tests/testcase.php b/apps/provisioning_api/tests/testcase.php
index 113bc512243..743c1c9c44b 100644
--- a/apps/provisioning_api/tests/testcase.php
+++ b/apps/provisioning_api/tests/testcase.php
@@ -3,8 +3,9 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,10 +24,13 @@
namespace OCA\Provisioning_API\Tests;
+use OCP\IUser;
use OCP\IUserManager;
use OCP\IGroupManager;
abstract class TestCase extends \Test\TestCase {
+
+ /** @var IUser[] */
protected $users = array();
/** @var IUserManager */
@@ -46,7 +50,7 @@ abstract class TestCase extends \Test\TestCase {
/**
* Generates a temp user
* @param int $num number of users to generate
- * @return IUser[]|Iuser
+ * @return IUser[]|IUser
*/
protected function generateUsers($num = 1) {
$users = array();
diff --git a/apps/provisioning_api/tests/userstest.php b/apps/provisioning_api/tests/userstest.php
index 63180eb3472..3ce13181b8d 100644
--- a/apps/provisioning_api/tests/userstest.php
+++ b/apps/provisioning_api/tests/userstest.php
@@ -2,12 +2,13 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author michag86 <micha_g@arcor.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,26 +28,27 @@
namespace OCA\Provisioning_API\Tests;
use OCA\Provisioning_API\Users;
+use OCP\API;
use OCP\IUserManager;
use OCP\IConfig;
-use OCP\IGroupManager;
use OCP\IUserSession;
+use PHPUnit_Framework_MockObject_MockObject;
use Test\TestCase as OriginalTest;
use OCP\ILogger;
class UsersTest extends OriginalTest {
- /** @var IUserManager */
+ /** @var IUserManager | PHPUnit_Framework_MockObject_MockObject */
protected $userManager;
- /** @var IConfig */
+ /** @var IConfig | PHPUnit_Framework_MockObject_MockObject */
protected $config;
- /** @var \OC\Group\Manager */
+ /** @var \OC\Group\Manager | PHPUnit_Framework_MockObject_MockObject */
protected $groupManager;
- /** @var IUserSession */
+ /** @var IUserSession | PHPUnit_Framework_MockObject_MockObject */
protected $userSession;
- /** @var ILogger */
+ /** @var ILogger | PHPUnit_Framework_MockObject_MockObject */
protected $logger;
- /** @var Users */
+ /** @var Users | PHPUnit_Framework_MockObject_MockObject */
protected $api;
protected function tearDown() {
@@ -83,7 +85,7 @@ class UsersTest extends OriginalTest {
->method('getUser')
->will($this->returnValue(null));
- $expected = new \OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED);
+ $expected = new \OC_OCS_Result(null, API::RESPOND_UNAUTHORISED);
$this->assertEquals($expected, $this->api->getUsers());
}
@@ -203,7 +205,7 @@ class UsersTest extends OriginalTest {
->method('getSubAdmin')
->will($this->returnValue($subAdminManager));
- $expected = new \OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED);
+ $expected = new \OC_OCS_Result(null, API::RESPOND_UNAUTHORISED);
$this->assertEquals($expected, $this->api->getUsers());
}
@@ -464,7 +466,7 @@ class UsersTest extends OriginalTest {
->with()
->willReturn($subAdminManager);
- $expected = new \OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED);
+ $expected = new \OC_OCS_Result(null, API::RESPOND_UNAUTHORISED);
$this->assertEquals($expected, $this->api->addUser());
}
@@ -653,7 +655,7 @@ class UsersTest extends OriginalTest {
->method('getUser')
->will($this->returnValue(null));
- $expected = new \OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED);
+ $expected = new \OC_OCS_Result(null, API::RESPOND_UNAUTHORISED);
$this->assertEquals($expected, $this->api->getUser(['userid' => 'UserToGet']));
}
@@ -669,7 +671,7 @@ class UsersTest extends OriginalTest {
->with('UserToGet')
->will($this->returnValue(null));
- $expected = new \OC_OCS_Result(null, \OCP\API::RESPOND_NOT_FOUND, 'The requested user could not be found');
+ $expected = new \OC_OCS_Result(null, API::RESPOND_NOT_FOUND, 'The requested user could not be found');
$this->assertEquals($expected, $this->api->getUser(['userid' => 'UserToGet']));
}
@@ -680,6 +682,9 @@ class UsersTest extends OriginalTest {
->method('getUID')
->will($this->returnValue('admin'));
$targetUser = $this->getMock('\OCP\IUser');
+ $targetUser->expects($this->once())
+ ->method('getEMailAddress')
+ ->willReturn('demo@owncloud.org');
$this->userSession
->expects($this->once())
->method('getUser')
@@ -704,11 +709,6 @@ class UsersTest extends OriginalTest {
->method('fillStorageInfo')
->with('UserToGet')
->will($this->returnValue(['DummyValue']));
- $this->config
- ->expects($this->at(1))
- ->method('getUserValue')
- ->with('UserToGet', 'settings', 'email')
- ->will($this->returnValue('demo@owncloud.org'));
$targetUser
->expects($this->once())
->method('getDisplayName')
@@ -732,6 +732,10 @@ class UsersTest extends OriginalTest {
->method('getUID')
->will($this->returnValue('subadmin'));
$targetUser = $this->getMock('\OCP\IUser');
+ $targetUser
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->willReturn('demo@owncloud.org');
$this->userSession
->expects($this->once())
->method('getUser')
@@ -768,11 +772,6 @@ class UsersTest extends OriginalTest {
->method('fillStorageInfo')
->with('UserToGet')
->will($this->returnValue(['DummyValue']));
- $this->config
- ->expects($this->at(1))
- ->method('getUserValue')
- ->with('UserToGet', 'settings', 'email')
- ->will($this->returnValue('demo@owncloud.org'));
$targetUser
->expects($this->once())
->method('getDisplayName')
@@ -823,7 +822,7 @@ class UsersTest extends OriginalTest {
->method('getSubAdmin')
->will($this->returnValue($subAdminManager));
- $expected = new \OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED);
+ $expected = new \OC_OCS_Result(null, API::RESPOND_UNAUTHORISED);
$this->assertEquals($expected, $this->api->getUser(['userid' => 'UserToGet']));
}
@@ -865,15 +864,14 @@ class UsersTest extends OriginalTest {
->method('fillStorageInfo')
->with('subadmin')
->will($this->returnValue(['DummyValue']));
- $this->config
- ->expects($this->once())
- ->method('getUserValue')
- ->with('subadmin', 'settings', 'email')
- ->will($this->returnValue('subadmin@owncloud.org'));
$targetUser
->expects($this->once())
->method('getDisplayName')
->will($this->returnValue('Subadmin User'));
+ $targetUser
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('subadmin@owncloud.org'));
$expected = new \OC_OCS_Result([
'quota' => ['DummyValue'],
@@ -889,7 +887,7 @@ class UsersTest extends OriginalTest {
->method('getUser')
->will($this->returnValue(null));
- $expected = new \OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED);
+ $expected = new \OC_OCS_Result(null, API::RESPOND_UNAUTHORISED);
$this->assertEquals($expected, $this->api->editUser(['userid' => 'UserToEdit']));
}
@@ -934,10 +932,10 @@ class UsersTest extends OriginalTest {
->method('get')
->with('UserToEdit')
->will($this->returnValue($targetUser));
- $this->config
+ $targetUser
->expects($this->once())
- ->method('setUserValue')
- ->with('UserToEdit', 'settings', 'email', 'demo@owncloud.org');
+ ->method('setEMailAddress')
+ ->with('demo@owncloud.org');
$expected = new \OC_OCS_Result(null, 100);
$this->assertEquals($expected, $this->api->editUser(['userid' => 'UserToEdit', '_put' => ['key' => 'email', 'value' => 'demo@owncloud.org']]));
diff --git a/apps/systemtags/activity/extension.php b/apps/systemtags/activity/extension.php
new file mode 100644
index 00000000000..4a974611509
--- /dev/null
+++ b/apps/systemtags/activity/extension.php
@@ -0,0 +1,300 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\SystemTags\Activity;
+
+use OCP\Activity\IExtension;
+use OCP\Activity\IManager;
+use OCP\IL10N;
+use OCP\L10N\IFactory;
+
+/**
+ * Class Extension
+ *
+ * @package OCA\SystemTags\Activity
+ */
+class Extension implements IExtension {
+ const APP_NAME = 'systemtags';
+
+ const CREATE_TAG = 'create_tag';
+ const UPDATE_TAG = 'update_tag';
+ const DELETE_TAG = 'delete_tag';
+
+ const ASSIGN_TAG = 'assign_tag';
+ const UNASSIGN_TAG = 'unassign_tag';
+
+ /** @var IFactory */
+ protected $languageFactory;
+
+ /** @var IManager */
+ protected $activityManager;
+
+ /**
+ * @param IFactory $languageFactory
+ * @param IManager $activityManager
+ */
+ public function __construct(IFactory $languageFactory, IManager $activityManager) {
+ $this->languageFactory = $languageFactory;
+ $this->activityManager = $activityManager;
+ }
+
+ protected function getL10N($languageCode = null) {
+ return $this->languageFactory->get(self::APP_NAME, $languageCode);
+ }
+
+ /**
+ * The extension can return an array of additional notification types.
+ * If no additional types are to be added false is to be returned
+ *
+ * @param string $languageCode
+ * @return array|false
+ */
+ public function getNotificationTypes($languageCode) {
+ $l = $this->getL10N($languageCode);
+
+ return array(
+ self::APP_NAME => (string) $l->t('<strong>System tags</strong> for a file have been modified'),
+ );
+ }
+
+ /**
+ * For a given method additional types to be displayed in the settings can be returned.
+ * In case no additional types are to be added false is to be returned.
+ *
+ * @param string $method
+ * @return array|false
+ */
+ public function getDefaultTypes($method) {
+ return $method === self::METHOD_STREAM ? [self::APP_NAME] : false;
+ }
+
+ /**
+ * A string naming the css class for the icon to be used can be returned.
+ * If no icon is known for the given type false is to be returned.
+ *
+ * @param string $type
+ * @return string|false
+ */
+ public function getTypeIcon($type) {
+ switch ($type) {
+ case self::APP_NAME:
+ return false;
+ }
+
+ return false;
+ }
+
+ /**
+ * The extension can translate a given message to the requested languages.
+ * If no translation is available false is to be returned.
+ *
+ * @param string $app
+ * @param string $text
+ * @param array $params
+ * @param boolean $stripPath
+ * @param boolean $highlightParams
+ * @param string $languageCode
+ * @return string|false
+ */
+ public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) {
+ if ($app !== self::APP_NAME) {
+ return false;
+ }
+
+ $l = $this->getL10N($languageCode);
+
+ if ($this->activityManager->isFormattingFilteredObject()) {
+ $translation = $this->translateShort($text, $l, $params);
+ if ($translation !== false) {
+ return $translation;
+ }
+ }
+
+ return $this->translateLong($text, $l, $params);
+ }
+
+ /**
+ * @param string $text
+ * @param IL10N $l
+ * @param array $params
+ * @return bool|string
+ */
+ protected function translateShort($text, IL10N $l, array $params) {
+
+ switch ($text) {
+ case self::ASSIGN_TAG:
+ $params[2] = $this->convertParameterToTag($params[2], $l);
+ return (string) $l->t('%1$s assigned system tag %3$s', $params);
+ case self::UNASSIGN_TAG:
+ $params[2] = $this->convertParameterToTag($params[2], $l);
+ return (string) $l->t('%1$s unassigned system tag %3$s', $params);
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $text
+ * @param IL10N $l
+ * @param array $params
+ * @return bool|string
+ */
+ protected function translateLong($text, IL10N $l, array $params) {
+
+ switch ($text) {
+ case self::CREATE_TAG:
+ $params[1] = $this->convertParameterToTag($params[1], $l);
+ return (string) $l->t('%1$s created system tag %2$s', $params);
+ case self::DELETE_TAG:
+ $params[1] = $this->convertParameterToTag($params[1], $l);
+ return (string) $l->t('%1$s deleted system tag %2$s', $params);
+ case self::UPDATE_TAG:
+ $params[1] = $this->convertParameterToTag($params[1], $l);
+ $params[2] = $this->convertParameterToTag($params[2], $l);
+ return (string) $l->t('%1$s updated system tag %3$s to %2$s', $params);
+ case self::ASSIGN_TAG:
+ $params[2] = $this->convertParameterToTag($params[2], $l);
+ return (string) $l->t('%1$s assigned system tag %3$s to %2$s', $params);
+ case self::UNASSIGN_TAG:
+ $params[2] = $this->convertParameterToTag($params[2], $l);
+ return (string) $l->t('%1$s unassigned system tag %3$s from %2$s', $params);
+ }
+
+ return false;
+ }
+
+ /**
+ * The extension can define the type of parameters for translation
+ *
+ * Currently known types are:
+ * * file => will strip away the path of the file and add a tooltip with it
+ * * username => will add the avatar of the user
+ *
+ * @param string $app
+ * @param string $text
+ * @return array|false
+ */
+ public function getSpecialParameterList($app, $text) {
+ if ($app === self::APP_NAME) {
+ switch ($text) {
+ case self::CREATE_TAG:
+ case self::DELETE_TAG:
+ return array(
+ 0 => 'username',
+ //1 => 'systemtag description',
+ );
+ case self::UPDATE_TAG:
+ return array(
+ 0 => 'username',
+ //1 => 'systemtag description',
+ //2 => 'systemtag description',
+ );
+
+ case self::ASSIGN_TAG:
+ case self::UNASSIGN_TAG:
+ return array(
+ 0 => 'username',
+ 1 => 'file',
+ //2 => 'systemtag description',
+ );
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * The extension can define the parameter grouping by returning the index as integer.
+ * In case no grouping is required false is to be returned.
+ *
+ * @param array $activity
+ * @return integer|false
+ */
+ public function getGroupParameter($activity) {
+ return false;
+ }
+
+ /**
+ * The extension can define additional navigation entries. The array returned has to contain two keys 'top'
+ * and 'apps' which hold arrays with the relevant entries.
+ * If no further entries are to be added false is no be returned.
+ *
+ * @return array|false
+ */
+ public function getNavigation() {
+ return false;
+ }
+
+ /**
+ * The extension can check if a custom filter (given by a query string like filter=abc) is valid or not.
+ *
+ * @param string $filterValue
+ * @return boolean
+ */
+ public function isFilterValid($filterValue) {
+ return false;
+ }
+
+ /**
+ * The extension can filter the types based on the filter if required.
+ * In case no filter is to be applied false is to be returned unchanged.
+ *
+ * @param array $types
+ * @param string $filter
+ * @return array|false
+ */
+ public function filterNotificationTypes($types, $filter) {
+ return false;
+ }
+
+ /**
+ * For a given filter the extension can specify the sql query conditions including parameters for that query.
+ * In case the extension does not know the filter false is to be returned.
+ * The query condition and the parameters are to be returned as array with two elements.
+ * E.g. return array('`app` = ? and `message` like ?', array('mail', 'ownCloud%'));
+ *
+ * @param string $filter
+ * @return array|false
+ */
+ public function getQueryForFilter($filter) {
+ return false;
+ }
+
+ /**
+ * @param string $parameter
+ * @param IL10N $l
+ * @return string
+ */
+ protected function convertParameterToTag($parameter, IL10N $l) {
+ if (preg_match('/^\<parameter\>\{\{\{(.*)\|\|\|(.*)\}\}\}\<\/parameter\>$/', $parameter, $matches)) {
+ switch ($matches[2]) {
+ case 'assignable':
+ return '<parameter>' . $matches[1] . '</parameter>';
+ case 'not-assignable':
+ return '<parameter>' . $l->t('%s (not-assignable)', $matches[1]) . '</parameter>';
+ case 'invisible':
+ return '<parameter>' . $l->t('%s (invisible)', $matches[1]) . '</parameter>';
+ }
+ }
+
+ return $parameter;
+ }
+}
diff --git a/apps/systemtags/activity/listener.php b/apps/systemtags/activity/listener.php
new file mode 100644
index 00000000000..9b6597119c6
--- /dev/null
+++ b/apps/systemtags/activity/listener.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\SystemTags\Activity;
+
+use OCP\Activity\IManager;
+use OCP\App\IAppManager;
+use OCP\Files\Config\IMountProviderCollection;
+use OCP\Files\IRootFolder;
+use OCP\Files\Node;
+use OCP\IGroup;
+use OCP\IGroupManager;
+use OCP\IUser;
+use OCP\IUserSession;
+use OCP\Share;
+use OCP\SystemTag\ISystemTag;
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ManagerEvent;
+use OCP\SystemTag\MapperEvent;
+use OCP\SystemTag\TagNotFoundException;
+
+class Listener {
+ /** @var IGroupManager */
+ protected $groupManager;
+ /** @var IManager */
+ protected $activityManager;
+ /** @var IUserSession */
+ protected $session;
+ /** @var \OCP\SystemTag\ISystemTagManager */
+ protected $tagManager;
+ /** @var \OCP\App\IAppManager */
+ protected $appManager;
+ /** @var \OCP\Files\Config\IMountProviderCollection */
+ protected $mountCollection;
+ /** @var \OCP\Files\IRootFolder */
+ protected $rootFolder;
+
+ /**
+ * Listener constructor.
+ *
+ * @param IGroupManager $groupManager
+ * @param IManager $activityManager
+ * @param IUserSession $session
+ * @param ISystemTagManager $tagManager
+ * @param IAppManager $appManager
+ * @param IMountProviderCollection $mountCollection
+ * @param IRootFolder $rootFolder
+ */
+ public function __construct(IGroupManager $groupManager,
+ IManager $activityManager,
+ IUserSession $session,
+ ISystemTagManager $tagManager,
+ IAppManager $appManager,
+ IMountProviderCollection $mountCollection,
+ IRootFolder $rootFolder) {
+ $this->groupManager = $groupManager;
+ $this->activityManager = $activityManager;
+ $this->session = $session;
+ $this->tagManager = $tagManager;
+ $this->appManager = $appManager;
+ $this->mountCollection = $mountCollection;
+ $this->rootFolder = $rootFolder;
+ }
+
+ /**
+ * @param ManagerEvent $event
+ */
+ public function event(ManagerEvent $event) {
+ $actor = $this->session->getUser();
+ if ($actor instanceof IUser) {
+ $actor = $actor->getUID();
+ } else {
+ $actor = '';
+ }
+
+ $activity = $this->activityManager->generateEvent();
+ $activity->setApp(Extension::APP_NAME)
+ ->setType(Extension::APP_NAME)
+ ->setAuthor($actor);
+ if ($event->getEvent() === ManagerEvent::EVENT_CREATE) {
+ $activity->setSubject(Extension::CREATE_TAG, [
+ $actor,
+ $this->prepareTagAsParameter($event->getTag()),
+ ]);
+ } else if ($event->getEvent() === ManagerEvent::EVENT_UPDATE) {
+ $activity->setSubject(Extension::UPDATE_TAG, [
+ $actor,
+ $this->prepareTagAsParameter($event->getTag()),
+ $this->prepareTagAsParameter($event->getTagBefore()),
+ ]);
+ } else if ($event->getEvent() === ManagerEvent::EVENT_DELETE) {
+ $activity->setSubject(Extension::DELETE_TAG, [
+ $actor,
+ $this->prepareTagAsParameter($event->getTag()),
+ ]);
+ } else {
+ return;
+ }
+
+ $group = $this->groupManager->get('admin');
+ if ($group instanceof IGroup) {
+ foreach ($group->getUsers() as $user) {
+ $activity->setAffectedUser($user->getUID());
+ $this->activityManager->publish($activity);
+ }
+ }
+ }
+
+ /**
+ * @param MapperEvent $event
+ */
+ public function mapperEvent(MapperEvent $event) {
+ $tagIds = $event->getTags();
+ if ($event->getObjectType() !== 'files' ||empty($tagIds)
+ || !in_array($event->getEvent(), [MapperEvent::EVENT_ASSIGN, MapperEvent::EVENT_UNASSIGN])
+ || !$this->appManager->isInstalled('activity')) {
+ // System tags not for files, no tags, not (un-)assigning or no activity-app enabled (save the energy)
+ return;
+ }
+
+ try {
+ $tags = $this->tagManager->getTagsByIds($tagIds);
+ } catch (TagNotFoundException $e) {
+ // User assigned/unassigned a non-existing tag, ignore...
+ return;
+ }
+
+ if (empty($tags)) {
+ return;
+ }
+
+ // Get all mount point owners
+ $cache = $this->mountCollection->getMountCache();
+ $mounts = $cache->getMountsForFileId($event->getObjectId());
+ if (empty($mounts)) {
+ return;
+ }
+
+ $users = [];
+ foreach ($mounts as $mount) {
+ $owner = $mount->getUser()->getUID();
+ $ownerFolder = $this->rootFolder->getUserFolder($owner);
+ $nodes = $ownerFolder->getById($event->getObjectId());
+ if (!empty($nodes)) {
+ /** @var Node $node */
+ $node = array_shift($nodes);
+ $path = $node->getPath();
+ if (strpos($path, '/' . $owner . '/files/') === 0) {
+ $path = substr($path, strlen('/' . $owner . '/files'));
+ }
+ // Get all users that have access to the mount point
+ $users = array_merge($users, Share::getUsersSharingFile($path, $owner, true, true));
+ }
+ }
+
+ $actor = $this->session->getUser();
+ if ($actor instanceof IUser) {
+ $actor = $actor->getUID();
+ } else {
+ $actor = '';
+ }
+
+ $activity = $this->activityManager->generateEvent();
+ $activity->setApp(Extension::APP_NAME)
+ ->setType(Extension::APP_NAME)
+ ->setAuthor($actor)
+ ->setObject($event->getObjectType(), $event->getObjectId());
+
+ foreach ($users as $user => $path) {
+ $activity->setAffectedUser($user);
+
+ foreach ($tags as $tag) {
+ if ($event->getEvent() === MapperEvent::EVENT_ASSIGN) {
+ $activity->setSubject(Extension::ASSIGN_TAG, [
+ $actor,
+ $path,
+ $this->prepareTagAsParameter($tag),
+ ]);
+ } else if ($event->getEvent() === MapperEvent::EVENT_UNASSIGN) {
+ $activity->setSubject(Extension::UNASSIGN_TAG, [
+ $actor,
+ $path,
+ $this->prepareTagAsParameter($tag),
+ ]);
+ }
+
+ $this->activityManager->publish($activity);
+ }
+ }
+ }
+
+ /**
+ * @param ISystemTag $tag
+ * @return string
+ */
+ protected function prepareTagAsParameter(ISystemTag $tag) {
+ if (!$tag->isUserVisible()) {
+ return '{{{' . $tag->getName() . '|||invisible}}}';
+ } else if (!$tag->isUserAssignable()) {
+ return '{{{' . $tag->getName() . '|||not-assignable}}}';
+ } else {
+ return '{{{' . $tag->getName() . '|||assignable}}}';
+ }
+ }
+}
diff --git a/apps/systemtags/appinfo/app.php b/apps/systemtags/appinfo/app.php
new file mode 100644
index 00000000000..0bb57e1227b
--- /dev/null
+++ b/apps/systemtags/appinfo/app.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+use OCA\SystemTags\Activity\Extension;
+use OCA\SystemTags\Activity\Listener;
+use OCP\SystemTag\ManagerEvent;
+use OCP\SystemTag\MapperEvent;
+
+$eventDispatcher = \OC::$server->getEventDispatcher();
+$eventDispatcher->addListener(
+ 'OCA\Files::loadAdditionalScripts',
+ function() {
+ // FIXME: no public API for these ?
+ \OC_Util::addVendorScript('select2/select2');
+ \OC_Util::addVendorStyle('select2/select2');
+ \OCP\Util::addScript('select2-toggleselect');
+ \OCP\Util::addScript('oc-backbone-webdav');
+ \OCP\Util::addScript('systemtags/systemtags');
+ \OCP\Util::addScript('systemtags/systemtagmodel');
+ \OCP\Util::addScript('systemtags/systemtagsmappingcollection');
+ \OCP\Util::addScript('systemtags/systemtagscollection');
+ \OCP\Util::addScript('systemtags/systemtagsinputfield');
+ \OCP\Util::addScript('systemtags', 'app');
+ \OCP\Util::addScript('systemtags', 'filesplugin');
+ \OCP\Util::addScript('systemtags', 'systemtagsinfoview');
+ \OCP\Util::addStyle('systemtags');
+ }
+);
+
+$activityManager = \OC::$server->getActivityManager();
+$activityManager->registerExtension(function() {
+ $application = new \OCP\AppFramework\App('systemtags');
+ /** @var \OCA\SystemTags\Activity\Extension $extension */
+ $extension = $application->getContainer()->query('OCA\SystemTags\Activity\Extension');
+ return $extension;
+});
+
+$managerListener = function(ManagerEvent $event) use ($activityManager) {
+ $application = new \OCP\AppFramework\App('systemtags');
+ /** @var \OCA\SystemTags\Activity\Listener $listener */
+ $listener = $application->getContainer()->query('OCA\SystemTags\Activity\Listener');
+ $listener->event($event);
+};
+
+$eventDispatcher->addListener(ManagerEvent::EVENT_CREATE, $managerListener);
+$eventDispatcher->addListener(ManagerEvent::EVENT_DELETE, $managerListener);
+$eventDispatcher->addListener(ManagerEvent::EVENT_UPDATE, $managerListener);
+
+$mapperListener = function(MapperEvent $event) use ($activityManager) {
+ $application = new \OCP\AppFramework\App('systemtags');
+ /** @var \OCA\SystemTags\Activity\Listener $listener */
+ $listener = $application->getContainer()->query('OCA\SystemTags\Activity\Listener');
+ $listener->mapperEvent($event);
+};
+
+$eventDispatcher->addListener(MapperEvent::EVENT_ASSIGN, $mapperListener);
+$eventDispatcher->addListener(MapperEvent::EVENT_UNASSIGN, $mapperListener);
diff --git a/apps/systemtags/appinfo/info.xml b/apps/systemtags/appinfo/info.xml
new file mode 100644
index 00000000000..d0b4c1fce00
--- /dev/null
+++ b/apps/systemtags/appinfo/info.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<info>
+ <id>systemtags</id>
+ <name>System tags</name>
+ <description>System-wide tags user interface</description>
+ <licence>AGPL</licence>
+ <author>Vincent Petry</author>
+ <default_enable/>
+ <version>0.2</version>
+ <dependencies>
+ <owncloud min-version="9.0" max-version="9.0" />
+ </dependencies>
+ <types>
+ <logging/>
+ </types>
+</info>
diff --git a/apps/systemtags/js/app.js b/apps/systemtags/js/app.js
new file mode 100644
index 00000000000..f55aa5c9a6e
--- /dev/null
+++ b/apps/systemtags/js/app.js
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function() {
+ if (!OCA.SystemTags) {
+ /**
+ * @namespace
+ */
+ OCA.SystemTags = {};
+ }
+
+})();
+
diff --git a/apps/systemtags/js/filesplugin.js b/apps/systemtags/js/filesplugin.js
new file mode 100644
index 00000000000..471440c2e09
--- /dev/null
+++ b/apps/systemtags/js/filesplugin.js
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function() {
+ OCA.SystemTags = _.extend({}, OCA.SystemTags);
+ if (!OCA.SystemTags) {
+ /**
+ * @namespace
+ */
+ OCA.SystemTags = {};
+ }
+
+ /**
+ * @namespace
+ */
+ OCA.SystemTags.FilesPlugin = {
+ allowedLists: [
+ 'files',
+ 'favorites'
+ ],
+
+ attach: function(fileList) {
+ if (this.allowedLists.indexOf(fileList.id) < 0) {
+ return;
+ }
+
+ fileList.registerDetailView(new OCA.SystemTags.SystemTagsInfoView());
+ }
+ };
+
+})();
+
+OC.Plugins.register('OCA.Files.FileList', OCA.SystemTags.FilesPlugin);
+
diff --git a/apps/systemtags/js/systemtagsinfoview.js b/apps/systemtags/js/systemtagsinfoview.js
new file mode 100644
index 00000000000..2e808f9a84f
--- /dev/null
+++ b/apps/systemtags/js/systemtagsinfoview.js
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OCA) {
+
+ function modelToSelection(model) {
+ var data = model.toJSON();
+ if (!OC.isUserAdmin() && !data.userAssignable) {
+ data.locked = true;
+ }
+ return data;
+ }
+
+ /**
+ * @class OCA.SystemTags.SystemTagsInfoView
+ * @classdesc
+ *
+ * Displays a file's system tags
+ *
+ */
+ var SystemTagsInfoView = OCA.Files.DetailFileInfoView.extend(
+ /** @lends OCA.SystemTags.SystemTagsInfoView.prototype */ {
+
+ _rendered: false,
+
+ className: 'systemTagsInfoView hidden',
+
+ /**
+ * @type OC.SystemTags.SystemTagsInputField
+ */
+ _inputView: null,
+
+ initialize: function(options) {
+ var self = this;
+ options = options || {};
+
+ this._inputView = new OC.SystemTags.SystemTagsInputField({
+ multiple: true,
+ allowActions: true,
+ allowCreate: true,
+ isAdmin: OC.isUserAdmin(),
+ initSelection: function(element, callback) {
+ callback(self.selectedTagsCollection.map(modelToSelection));
+ }
+ });
+
+ this.selectedTagsCollection = new OC.SystemTags.SystemTagsMappingCollection([], {objectType: 'files'});
+
+ this._inputView.collection.on('change:name', this._onTagRenamedGlobally, this);
+ this._inputView.collection.on('remove', this._onTagDeletedGlobally, this);
+
+ this._inputView.on('select', this._onSelectTag, this);
+ this._inputView.on('deselect', this._onDeselectTag, this);
+ },
+
+ /**
+ * Event handler whenever a tag was selected
+ */
+ _onSelectTag: function(tag) {
+ // create a mapping entry for this tag
+ this.selectedTagsCollection.create(tag.toJSON());
+ },
+
+ /**
+ * Event handler whenever a tag gets deselected.
+ * Removes the selected tag from the mapping collection.
+ *
+ * @param {string} tagId tag id
+ */
+ _onDeselectTag: function(tagId) {
+ this.selectedTagsCollection.get(tagId).destroy();
+ },
+
+ /**
+ * Event handler whenever a tag was renamed globally.
+ *
+ * This will automatically adjust the tag mapping collection to
+ * container the new name.
+ *
+ * @param {OC.Backbone.Model} changedTag tag model that has changed
+ */
+ _onTagRenamedGlobally: function(changedTag) {
+ // also rename it in the selection, if applicable
+ var selectedTagMapping = this.selectedTagsCollection.get(changedTag.id);
+ if (selectedTagMapping) {
+ selectedTagMapping.set(changedTag.toJSON());
+ }
+ },
+
+ /**
+ * Event handler whenever a tag was deleted globally.
+ *
+ * This will automatically adjust the tag mapping collection to
+ * container the new name.
+ *
+ * @param {OC.Backbone.Model} changedTag tag model that has changed
+ */
+ _onTagDeletedGlobally: function(tagId) {
+ // also rename it in the selection, if applicable
+ this.selectedTagsCollection.remove(tagId);
+ },
+
+ setFileInfo: function(fileInfo) {
+ var self = this;
+ if (!this._rendered) {
+ this.render();
+ }
+
+ if (fileInfo) {
+ this.selectedTagsCollection.setObjectId(fileInfo.id);
+ this.selectedTagsCollection.fetch({
+ success: function(collection) {
+ collection.fetched = true;
+ self._inputView.setData(collection.map(modelToSelection));
+ self.$el.removeClass('hidden');
+ }
+ });
+ }
+ this.$el.addClass('hidden');
+ },
+
+ /**
+ * Renders this details view
+ */
+ render: function() {
+ this.$el.append(this._inputView.$el);
+ this._inputView.render();
+ },
+
+ remove: function() {
+ this._inputView.remove();
+ }
+ });
+
+ OCA.SystemTags.SystemTagsInfoView = SystemTagsInfoView;
+
+})(OCA);
+
diff --git a/apps/systemtags/tests/js/systemtagsinfoviewSpec.js b/apps/systemtags/tests/js/systemtagsinfoviewSpec.js
new file mode 100644
index 00000000000..0fb4e7b22c2
--- /dev/null
+++ b/apps/systemtags/tests/js/systemtagsinfoviewSpec.js
@@ -0,0 +1,176 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2016 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+describe('OCA.SystemTags.SystemTagsInfoView tests', function() {
+ var isAdminStub;
+ var view;
+
+ beforeEach(function() {
+ view = new OCA.SystemTags.SystemTagsInfoView();
+ $('#testArea').append(view.$el);
+ isAdminStub = sinon.stub(OC, 'isUserAdmin').returns(true);
+ });
+ afterEach(function() {
+ isAdminStub.restore();
+ view.remove();
+ view = undefined;
+ });
+ describe('rendering', function() {
+ it('renders input field view', function() {
+ view.render();
+ expect(view.$el.find('input[name=tags]').length).toEqual(1);
+ });
+ it('fetches selected tags then renders when setting file info', function() {
+ var fetchStub = sinon.stub(OC.SystemTags.SystemTagsMappingCollection.prototype, 'fetch');
+ var setDataStub = sinon.stub(OC.SystemTags.SystemTagsInputField.prototype, 'setData');
+
+ expect(view.$el.hasClass('hidden')).toEqual(true);
+
+ view.setFileInfo({id: '123'});
+ expect(view.$el.find('input[name=tags]').length).toEqual(1);
+
+ expect(fetchStub.calledOnce).toEqual(true);
+ expect(view.selectedTagsCollection.url())
+ .toEqual(OC.linkToRemote('dav') + '/systemtags-relations/files/123');
+
+ view.selectedTagsCollection.add([
+ {id: '1', name: 'test1'},
+ {id: '3', name: 'test3'}
+ ]);
+
+ fetchStub.yieldTo('success', view.selectedTagsCollection);
+ expect(setDataStub.calledOnce).toEqual(true);
+ expect(setDataStub.getCall(0).args[0]).toEqual([{
+ id: '1', name: 'test1', userVisible: true, userAssignable: true
+ }, {
+ id: '3', name: 'test3', userVisible: true, userAssignable: true
+ }]);
+
+ expect(view.$el.hasClass('hidden')).toEqual(false);
+
+ fetchStub.restore();
+ setDataStub.restore();
+ });
+ it('overrides initSelection to use the local collection', function() {
+ var inputViewSpy = sinon.spy(OC.SystemTags, 'SystemTagsInputField');
+ var element = $('<input type="hidden" val="1,3"/>');
+ view.remove();
+ view = new OCA.SystemTags.SystemTagsInfoView();
+ view.selectedTagsCollection.add([
+ {id: '1', name: 'test1'},
+ {id: '3', name: 'test3', userVisible: false, userAssignable: false}
+ ]);
+
+ var callback = sinon.stub();
+ inputViewSpy.getCall(0).args[0].initSelection(element, callback);
+
+ expect(callback.calledOnce).toEqual(true);
+ expect(callback.getCall(0).args[0]).toEqual([{
+ id: '1', name: 'test1', userVisible: true, userAssignable: true
+ }, {
+ id: '3', name: 'test3', userVisible: false, userAssignable: false
+ }]);
+
+ inputViewSpy.restore();
+ });
+ it('sets locked flag on non-assignable tags when user is not an admin', function() {
+ isAdminStub.returns(false);
+
+ var inputViewSpy = sinon.spy(OC.SystemTags, 'SystemTagsInputField');
+ var element = $('<input type="hidden" val="1,3"/>');
+ view.remove();
+ view = new OCA.SystemTags.SystemTagsInfoView();
+ view.selectedTagsCollection.add([
+ {id: '1', name: 'test1'},
+ {id: '3', name: 'test3', userAssignable: false}
+ ]);
+
+ var callback = sinon.stub();
+ inputViewSpy.getCall(0).args[0].initSelection(element, callback);
+
+ expect(callback.calledOnce).toEqual(true);
+ expect(callback.getCall(0).args[0]).toEqual([{
+ id: '1', name: 'test1', userVisible: true, userAssignable: true
+ }, {
+ id: '3', name: 'test3', userVisible: true, userAssignable: false, locked: true
+ }]);
+
+ inputViewSpy.restore();
+ });
+ });
+ describe('events', function() {
+ var allTagsCollection;
+ beforeEach(function() {
+ allTagsCollection = view._inputView.collection;
+
+ allTagsCollection.add([
+ {id: '1', name: 'test1'},
+ {id: '2', name: 'test2'},
+ {id: '3', name: 'test3'}
+ ]);
+
+ view.selectedTagsCollection.add([
+ {id: '1', name: 'test1'},
+ {id: '3', name: 'test3'}
+ ]);
+ view.render();
+ });
+
+ it('renames model in selection collection on rename', function() {
+ allTagsCollection.get('3').set('name', 'test3_renamed');
+
+ expect(view.selectedTagsCollection.get('3').get('name')).toEqual('test3_renamed');
+ });
+
+ it('adds tag to selection collection when selected by input', function() {
+ var createStub = sinon.stub(OC.SystemTags.SystemTagsMappingCollection.prototype, 'create');
+ view._inputView.trigger('select', allTagsCollection.get('2'));
+
+ expect(createStub.calledOnce).toEqual(true);
+ expect(createStub.getCall(0).args[0]).toEqual({
+ id: '2',
+ name: 'test2',
+ userVisible: true,
+ userAssignable: true
+ });
+
+ createStub.restore();
+ });
+ it('removes tag from selection collection when deselected by input', function() {
+ var destroyStub = sinon.stub(OC.SystemTags.SystemTagModel.prototype, 'destroy');
+ view._inputView.trigger('deselect', '3');
+
+ expect(destroyStub.calledOnce).toEqual(true);
+ expect(destroyStub.calledOn(view.selectedTagsCollection.get('3'))).toEqual(true);
+
+ destroyStub.restore();
+ });
+
+ it('removes tag from selection whenever the tag was deleted globally', function() {
+ expect(view.selectedTagsCollection.get('3')).not.toBeFalsy();
+
+ allTagsCollection.remove('3');
+
+ expect(view.selectedTagsCollection.get('3')).toBeFalsy();
+
+ });
+ });
+});
diff --git a/apps/testing/appinfo/info.xml b/apps/testing/appinfo/info.xml
new file mode 100644
index 00000000000..cfbe75ddadc
--- /dev/null
+++ b/apps/testing/appinfo/info.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<info>
+ <id>testing</id>
+ <name>QA testing</name>
+ <description>This app is only for testing! It is dangerous to have it enabled in a live instance</description>
+ <licence>AGPL</licence>
+ <author>Joas Schilling</author>
+ <version>0.1.0</version>
+ <dependencies>
+ <owncloud min-version="9.0" max-version="9.0" />
+ </dependencies>
+</info>
diff --git a/apps/testing/appinfo/routes.php b/apps/testing/appinfo/routes.php
new file mode 100644
index 00000000000..b6f20d04ef2
--- /dev/null
+++ b/apps/testing/appinfo/routes.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Testing\AppInfo;
+
+use OCA\Testing\Config;
+use OCP\API;
+
+$config = new Config(
+ \OC::$server->getConfig(),
+ \OC::$server->getRequest()
+);
+
+API::register(
+ 'post',
+ '/apps/testing/api/v1/app/{appid}/{configkey}',
+ [$config, 'setAppValue'],
+ 'testing',
+ API::ADMIN_AUTH
+);
+
+API::register(
+ 'delete',
+ '/apps/testing/api/v1/app/{appid}/{configkey}',
+ [$config, 'deleteAppValue'],
+ 'testing',
+ API::ADMIN_AUTH
+);
diff --git a/apps/testing/config.php b/apps/testing/config.php
new file mode 100644
index 00000000000..068cb28e04b
--- /dev/null
+++ b/apps/testing/config.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Testing;
+
+use OCP\IConfig;
+use OCP\IRequest;
+
+class Config {
+
+ /** @var IConfig */
+ private $config;
+
+ /** @var IRequest */
+ private $request;
+
+ /**
+ * @param IConfig $config
+ * @param IRequest $request
+ */
+ public function __construct(IConfig $config, IRequest $request) {
+ $this->config = $config;
+ $this->request = $request;
+ }
+
+ /**
+ * @param array $parameters
+ * @return \OC_OCS_Result
+ */
+ public function setAppValue($parameters) {
+ $app = $parameters['appid'];
+ $configKey = $parameters['configkey'];
+
+ $value = $this->request->getParam('value');
+ $this->config->setAppValue($app, $configKey, $value);
+
+ return new \OC_OCS_Result();
+ }
+
+ /**
+ * @param array $parameters
+ * @return \OC_OCS_Result
+ */
+ public function deleteAppValue($parameters) {
+ $app = $parameters['appid'];
+ $configKey = $parameters['configkey'];
+
+ $this->config->deleteAppValue($app, $configKey);
+
+ return new \OC_OCS_Result();
+ }
+}
diff --git a/apps/testing/img/app.svg b/apps/testing/img/app.svg
new file mode 100644
index 00000000000..b6ae35211a3
--- /dev/null
+++ b/apps/testing/img/app.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.0" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m13.733 0.00064c-0.52991 0-0.93331 0.40337-0.93331 0.93333v2.6666c-1.182 0.3034-2.243 0.7934-3.2668 1.4001l-1.9334-1.9334c-0.3747-0.3747-0.9586-0.3747-1.3333 0l-3.1999 3.2c-0.37473 0.37474-0.37473 0.95859 0 1.3333l1.9334 1.9335c-0.6067 1.0239-1.0967 2.0849-1.4001 3.2669h-2.6666c-0.52994 0-0.9333 0.403-0.9333 0.933v4.5333c2e-8 0.52996 0.40336 0.93333 0.93331 0.93333h2.6666c0.30335 1.1817 0.79332 2.2426 1.4 3.2666l-1.9334 1.9349c-0.37473 0.37474-0.37473 0.95859 0 1.3333l3.1999 3.2c0.37473 0.37474 0.95857 0.37474 1.3333 0l1.9334-1.9349c1.024 0.608 2.0849 1.0965 3.2665 1.3995v2.6667c0 0.53 0.403 0.933 0.933 0.933h4.5332c0.52991 0 0.93331-0.4032 0.93331-0.9344v-2.6667c1.1816-0.30336 2.2425-0.79335 3.2665-1.4l1.9333 1.9333c0.37473 0.37474 0.95857 0.37474 1.3333 0l3.1999-3.2c0.37473-0.37474 0.37473-0.95859 0-1.3333l-1.9327-1.9328c0.60798-1.024 1.0965-2.0845 1.3994-3.2661h2.6666c0.532 0 0.935-0.403 0.935-0.933v-4.534c0-0.53-0.403-0.933-0.934-0.933h-2.667c-0.303-1.182-0.791-2.243-1.399-3.2666l1.932-1.9334c0.37473-0.37474 0.37473-0.95859 0-1.3333l-3.2-3.2c-0.37473-0.37474-0.95857-0.37474-1.3333 0l-1.9327 1.9334c-1.024-0.6067-2.084-1.0967-3.266-1.4001v-2.6667c0-0.52993-0.403-0.9333-0.933-0.9333zm2.2666 8.8689c3.9361 0 7.1309 3.1947 7.1309 7.1311 0 3.9362-3.1946 7.1311-7.1309 7.1311-3.9361 0-7.1309-3.1955-7.1309-7.1317s3.1948-7.1311 7.1309-7.1311z" display="block" fill="#fff"/>
+</svg>
diff --git a/apps/user_ldap/ajax/clearMappings.php b/apps/user_ldap/ajax/clearMappings.php
index bbc379a775f..8f9cf981e57 100644
--- a/apps/user_ldap/ajax/clearMappings.php
+++ b/apps/user_ldap/ajax/clearMappings.php
@@ -5,7 +5,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/ajax/deleteConfiguration.php b/apps/user_ldap/ajax/deleteConfiguration.php
index c629c79d61f..780a4bc35d0 100644
--- a/apps/user_ldap/ajax/deleteConfiguration.php
+++ b/apps/user_ldap/ajax/deleteConfiguration.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/ajax/getConfiguration.php b/apps/user_ldap/ajax/getConfiguration.php
index 91a5a868536..795261bc91d 100644
--- a/apps/user_ldap/ajax/getConfiguration.php
+++ b/apps/user_ldap/ajax/getConfiguration.php
@@ -5,7 +5,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/ajax/getNewServerConfigPrefix.php b/apps/user_ldap/ajax/getNewServerConfigPrefix.php
index 41a061e6c50..df85d99f2c7 100644
--- a/apps/user_ldap/ajax/getNewServerConfigPrefix.php
+++ b/apps/user_ldap/ajax/getNewServerConfigPrefix.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/ajax/setConfiguration.php b/apps/user_ldap/ajax/setConfiguration.php
index 3b0ba1b7754..a2e73783e00 100644
--- a/apps/user_ldap/ajax/setConfiguration.php
+++ b/apps/user_ldap/ajax/setConfiguration.php
@@ -6,7 +6,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/ajax/testConfiguration.php b/apps/user_ldap/ajax/testConfiguration.php
index f5fd5f23b87..e9f5167bfe7 100644
--- a/apps/user_ldap/ajax/testConfiguration.php
+++ b/apps/user_ldap/ajax/testConfiguration.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -49,7 +49,7 @@ try {
* pass (like e.g. expected syntax error).
*/
try {
- $ldapWrapper->read($connection->getConnectionResource(), 'neverwhere', 'objectClass=*', array('dn'));
+ $ldapWrapper->read($connection->getConnectionResource(), '', 'objectClass=*', array('dn'));
} catch (\Exception $e) {
if($e->getCode() === 1) {
OCP\JSON::error(array('message' => $l->t('The configuration is invalid: anonymous bind is not allowed.')));
diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php
index 267b9568a28..666af85e56e 100644
--- a/apps/user_ldap/ajax/wizard.php
+++ b/apps/user_ldap/ajax/wizard.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -54,7 +54,8 @@ $userManager = new \OCA\user_ldap\lib\user\Manager(
new \OCA\user_ldap\lib\LogWrapper(),
\OC::$server->getAvatarManager(),
new \OCP\Image(),
- \OC::$server->getDatabaseConnection());
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getUserManager());
$access = new \OCA\user_ldap\lib\Access($con, $ldapWrapper, $userManager);
diff --git a/apps/user_ldap/appinfo/app.php b/apps/user_ldap/appinfo/app.php
index 60c2accdccb..dab47ee6e6f 100644
--- a/apps/user_ldap/appinfo/app.php
+++ b/apps/user_ldap/appinfo/app.php
@@ -7,7 +7,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -37,7 +37,8 @@ if(count($configPrefixes) === 1) {
new OCA\user_ldap\lib\LogWrapper(),
\OC::$server->getAvatarManager(),
new \OCP\Image(),
- $dbc
+ $dbc,
+ \OC::$server->getUserManager()
);
$connector = new OCA\user_ldap\lib\Connection($ldapWrapper, $configPrefixes[0]);
$ldapAccess = new OCA\user_ldap\lib\Access($connector, $ldapWrapper, $userManager);
diff --git a/apps/user_ldap/appinfo/info.xml b/apps/user_ldap/appinfo/info.xml
index 7dbce1da5fa..864eaebe4d0 100644
--- a/apps/user_ldap/appinfo/info.xml
+++ b/apps/user_ldap/appinfo/info.xml
@@ -9,7 +9,6 @@ A user logs into ownCloud with their LDAP or AD credentials, and is granted acce
</description>
<licence>AGPL</licence>
<author>Dominik Schmidt and Arthur Schiwon</author>
- <shipped>true</shipped>
<version>0.8.0</version>
<types>
<authentication/>
@@ -19,6 +18,6 @@ A user logs into ownCloud with their LDAP or AD credentials, and is granted acce
</documentation>
<dependencies>
<lib>ldap</lib>
- <owncloud min-version="9.0" />
+ <owncloud min-version="9.0" max-version="9.0" />
</dependencies>
</info>
diff --git a/apps/user_ldap/appinfo/install.php b/apps/user_ldap/appinfo/install.php
index 844c724ac25..49c8f808ef3 100644
--- a/apps/user_ldap/appinfo/install.php
+++ b/apps/user_ldap/appinfo/install.php
@@ -4,7 +4,7 @@
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/appinfo/register_command.php b/apps/user_ldap/appinfo/register_command.php
index a13eeb6cdc3..f356f635023 100644
--- a/apps/user_ldap/appinfo/register_command.php
+++ b/apps/user_ldap/appinfo/register_command.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/appinfo/routes.php b/apps/user_ldap/appinfo/routes.php
index f8640ba00ca..9308df6dc1a 100644
--- a/apps/user_ldap/appinfo/routes.php
+++ b/apps/user_ldap/appinfo/routes.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/appinfo/update.php b/apps/user_ldap/appinfo/update.php
index 7d358e5b268..82f3e86bd33 100644
--- a/apps/user_ldap/appinfo/update.php
+++ b/apps/user_ldap/appinfo/update.php
@@ -1,10 +1,9 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Lennart Rosam <hello@takuto.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,21 +20,5 @@
*
*/
-$installedVersion = \OC::$server->getConfig()->getAppValue('user_ldap', 'installed_version');
-
-if (version_compare($installedVersion, '0.6.1', '<')) {
- \OC::$server->getConfig()->setAppValue('user_ldap', 'enforce_home_folder_naming_rule', false);
-}
-
-if(version_compare($installedVersion, '0.6.2', '<')) {
- // Remove LDAP case insensitive setting from DB as it is no longer beeing used.
- $helper = new \OCA\user_ldap\lib\Helper();
- $prefixes = $helper->getServerConfigurationPrefixes();
-
- foreach($prefixes as $prefix) {
- \OC::$server->getConfig()->deleteAppValue('user_ldap', $prefix . "ldap_nocase");
- }
-}
-
OCP\Backgroundjob::registerJob('OCA\user_ldap\lib\Jobs');
OCP\Backgroundjob::registerJob('\OCA\User_LDAP\Jobs\CleanUp');
diff --git a/apps/user_ldap/command/checkuser.php b/apps/user_ldap/command/checkuser.php
index 574b59699ad..eb1a7e494d5 100644
--- a/apps/user_ldap/command/checkuser.php
+++ b/apps/user_ldap/command/checkuser.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/command/createemptyconfig.php b/apps/user_ldap/command/createemptyconfig.php
index 7f452626859..f1c94704415 100644
--- a/apps/user_ldap/command/createemptyconfig.php
+++ b/apps/user_ldap/command/createemptyconfig.php
@@ -4,7 +4,7 @@
* @author Martin Konrad <konrad@frib.msu.edu>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/command/deleteconfig.php b/apps/user_ldap/command/deleteconfig.php
index 4479fe6bda1..4dfef9c18da 100644
--- a/apps/user_ldap/command/deleteconfig.php
+++ b/apps/user_ldap/command/deleteconfig.php
@@ -4,7 +4,7 @@
* @author Martin Konrad <info@martin-konrad.net>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/command/search.php b/apps/user_ldap/command/search.php
index 7bb315a5fb8..8d43d15649a 100644
--- a/apps/user_ldap/command/search.php
+++ b/apps/user_ldap/command/search.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/command/setconfig.php b/apps/user_ldap/command/setconfig.php
index 53de5317207..575d429241b 100644
--- a/apps/user_ldap/command/setconfig.php
+++ b/apps/user_ldap/command/setconfig.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/command/showconfig.php b/apps/user_ldap/command/showconfig.php
index b076ecccdfb..164cdada100 100644
--- a/apps/user_ldap/command/showconfig.php
+++ b/apps/user_ldap/command/showconfig.php
@@ -4,7 +4,7 @@
* @author Laurens Post <Crote@users.noreply.github.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/command/showremnants.php b/apps/user_ldap/command/showremnants.php
index 72217c50972..83bb5eaefd3 100644
--- a/apps/user_ldap/command/showremnants.php
+++ b/apps/user_ldap/command/showremnants.php
@@ -2,8 +2,9 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author scolebrook <scolebrook@mac.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,7 @@ namespace OCA\user_ldap\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use OCA\user_ldap\lib\user\DeletedUsersIndex;
@@ -50,7 +52,7 @@ class ShowRemnants extends Command {
$this
->setName('ldap:show-remnants')
->setDescription('shows which users are not available on LDAP anymore, but have remnants in ownCloud.')
- ;
+ ->addOption('json', null, InputOption::VALUE_NONE, 'return JSON array instead of pretty table.');
}
/**
@@ -70,18 +72,21 @@ class ShowRemnants extends Command {
$hAS = $user->getHasActiveShares() ? 'Y' : 'N';
$lastLogin = ($user->getLastLogin() > 0) ?
$this->dateFormatter->formatDate($user->getLastLogin()) : '-';
- $rows[] = array(
- $user->getOCName(),
- $user->getDisplayName(),
- $user->getUid(),
- $user->getDN(),
- $lastLogin,
- $user->getHomePath(),
- $hAS
+ $rows[] = array('ocName' => $user->getOCName(),
+ 'displayName' => $user->getDisplayName(),
+ 'uid' => $user->getUid(),
+ 'dn' => $user->getDN(),
+ 'lastLogin' => $lastLogin,
+ 'homePath' => $user->getHomePath(),
+ 'sharer' => $hAS
);
}
- $table->setRows($rows);
- $table->render($output);
+ if ($input->getOption('json')) {
+ $output->writeln(json_encode($rows));
+ } else {
+ $table->setRows($rows);
+ $table->render($output);
+ }
}
}
diff --git a/apps/user_ldap/command/testconfig.php b/apps/user_ldap/command/testconfig.php
index 8c8d73cade8..62d40265777 100644
--- a/apps/user_ldap/command/testconfig.php
+++ b/apps/user_ldap/command/testconfig.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php
index 7c06e24293e..05ab9ddfaae 100644
--- a/apps/user_ldap/group_ldap.php
+++ b/apps/user_ldap/group_ldap.php
@@ -9,11 +9,12 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Nicolas Grekas <nicolas.grekas@gmail.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
+ * @author Richard Bentley <rbentley@e2advance.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -148,6 +149,46 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
/**
* @param string $dnGroup
+ * @return array
+ *
+ * For a group that has user membership defined by an LDAP search url attribute returns the users
+ * that match the search url otherwise returns an empty array.
+ */
+ public function getDynamicGroupMembers($dnGroup) {
+ $dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
+
+ if (empty($dynamicGroupMemberURL)) {
+ return array();
+ }
+
+ $dynamicMembers = array();
+ $memberURLs = $this->access->readAttribute(
+ $dnGroup,
+ $dynamicGroupMemberURL,
+ $this->access->connection->ldapGroupFilter
+ );
+ if ($memberURLs !== false) {
+ // this group has the 'memberURL' attribute so this is a dynamic group
+ // example 1: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(o=HeadOffice)
+ // example 2: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(&(o=HeadOffice)(uidNumber>=500))
+ $pos = strpos($memberURLs[0], '(');
+ if ($pos !== false) {
+ $memberUrlFilter = substr($memberURLs[0], $pos);
+ $foundMembers = $this->access->searchUsers($memberUrlFilter,'dn');
+ $dynamicMembers = array();
+ foreach($foundMembers as $value) {
+ $dynamicMembers[$value['dn'][0]] = 1;
+ }
+ } else {
+ \OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
+ 'of group ' . $dnGroup, \OCP\Util::DEBUG);
+ }
+ }
+ return $dynamicMembers;
+ }
+
+ /**
+ * @param string $dnGroup
* @param array|null &$seen
* @return array|mixed|null
*/
@@ -180,6 +221,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
}
}
+
+ $allMembers = array_merge($allMembers, $this->getDynamicGroupMembers($dnGroup));
+
$this->access->connection->writeToCache($cacheKey, $allMembers);
return $allMembers;
}
@@ -387,6 +431,8 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
*
* This function fetches all groups a user belongs to. It does not check
* if the user exists at all.
+ *
+ * This function includes groups based on dynamic group membership.
*/
public function getUserGroups($uid) {
if(!$this->enabled) {
@@ -405,6 +451,41 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
$groups = [];
$primaryGroup = $this->getUserPrimaryGroup($userDN);
+ $dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
+
+ if (!empty($dynamicGroupMemberURL)) {
+ // look through dynamic groups to add them to the result array if needed
+ $groupsToMatch = $this->access->fetchListOfGroups(
+ $this->access->connection->ldapGroupFilter,array('dn',$dynamicGroupMemberURL));
+ foreach($groupsToMatch as $dynamicGroup) {
+ if (!array_key_exists($dynamicGroupMemberURL, $dynamicGroup)) {
+ continue;
+ }
+ $pos = strpos($dynamicGroup[$dynamicGroupMemberURL][0], '(');
+ if ($pos !== false) {
+ $memberUrlFilter = substr($dynamicGroup[$dynamicGroupMemberURL][0],$pos);
+ // apply filter via ldap search to see if this user is in this
+ // dynamic group
+ $userMatch = $this->access->readAttribute(
+ $uid,
+ $this->access->connection->ldapUserDisplayName,
+ $memberUrlFilter
+ );
+ if ($userMatch !== false) {
+ // match found so this user is in this group
+ $pos = strpos($dynamicGroup['dn'][0], ',');
+ if ($pos !== false) {
+ $membershipGroup = substr($dynamicGroup['dn'][0],3,$pos-3);
+ $groups[] = $membershipGroup;
+ }
+ }
+ } else {
+ \OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
+ 'of group ' . print_r($dynamicGroup, true), \OCP\Util::DEBUG);
+ }
+ }
+ }
+
// if possible, read out membership via memberOf. It's far faster than
// performing a search, which still is a fallback later.
if(intval($this->access->connection->hasMemberOfFilterSupport) === 1
diff --git a/apps/user_ldap/group_proxy.php b/apps/user_ldap/group_proxy.php
index b30563941bd..7d496a129a1 100644
--- a/apps/user_ldap/group_proxy.php
+++ b/apps/user_ldap/group_proxy.php
@@ -3,9 +3,9 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js
index 7367bfe87ae..9e898ba2fc8 100644
--- a/apps/user_ldap/js/wizard/wizardTabAdvanced.js
+++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js
@@ -79,6 +79,10 @@ OCA = OCA || {};
$element: $('#ldap_group_member_assoc_attribute'),
setMethod: 'setGroupMemberAssociationAttribute'
},
+ ldap_dynamic_group_member_url: {
+ $element: $('#ldap_dynamic_group_member_url'),
+ setMethod: 'setDynamicGroupMemberURL'
+ },
ldap_nested_groups: {
$element: $('#ldap_nested_groups'),
setMethod: 'setUseNestedGroups'
@@ -245,6 +249,15 @@ OCA = OCA || {};
},
/**
+ * sets the dynamic group member url attribute
+ *
+ * @param {string} attribute
+ */
+ setDynamicGroupMemberURL: function(attribute) {
+ this.setElementValue(this.managedItems.ldap_dynamic_group_member_url.$element, attribute);
+ },
+
+ /**
* enabled or disables the use of nested groups (groups in groups in
* groups…)
*
diff --git a/apps/user_ldap/js/wizard/wizardTabGeneric.js b/apps/user_ldap/js/wizard/wizardTabGeneric.js
index 60e7cd2ad9e..8940a8468a0 100644
--- a/apps/user_ldap/js/wizard/wizardTabGeneric.js
+++ b/apps/user_ldap/js/wizard/wizardTabGeneric.js
@@ -198,9 +198,13 @@ OCA = OCA || {};
return;
}
- // deal with text area
+ // special cases: deal with text area and multiselect
if ($element.is('textarea') && $.isArray(value)) {
value = value.join("\n");
+ } else if($element.hasClass(this.multiSelectPluginClass)) {
+ if(!_.isArray(value)) {
+ value = value.split("\n");
+ }
}
if ($element.is('span')) {
diff --git a/apps/user_ldap/l10n/de_DE.js b/apps/user_ldap/l10n/de_DE.js
index 4ef7b94c361..b72b41ea293 100644
--- a/apps/user_ldap/l10n/de_DE.js
+++ b/apps/user_ldap/l10n/de_DE.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "Die Base DN konnte nicht erkannt werden, bitte geben Sie sie manuell ein.",
"{nthServer}. Server" : "{nthServer}. - Server",
"No object found in the given Base DN. Please revise." : "Keine Objekte in der angegebenen Base DN gefunden, bitte überprüfen.",
+ "More than 1,000 directory entries available." : "Es sind mehr als 1.000 Verzeichniseinträge verfügbar.",
" entries available within the provided Base DN" : "Einträge in der angegebenen Base DN verfügbar",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Es ist ein Fehler aufgetreten. Bitte überprüfen Sie die Base DN wie auch die Verbindungseinstellungen und Anmeldeinformationen.",
"Do you really want to delete the current Server Configuration?" : "Soll die aktuelle Serverkonfiguration wirklich gelöscht werden?",
diff --git a/apps/user_ldap/l10n/de_DE.json b/apps/user_ldap/l10n/de_DE.json
index c90e39c996b..58ccaa400c9 100644
--- a/apps/user_ldap/l10n/de_DE.json
+++ b/apps/user_ldap/l10n/de_DE.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "Die Base DN konnte nicht erkannt werden, bitte geben Sie sie manuell ein.",
"{nthServer}. Server" : "{nthServer}. - Server",
"No object found in the given Base DN. Please revise." : "Keine Objekte in der angegebenen Base DN gefunden, bitte überprüfen.",
+ "More than 1,000 directory entries available." : "Es sind mehr als 1.000 Verzeichniseinträge verfügbar.",
" entries available within the provided Base DN" : "Einträge in der angegebenen Base DN verfügbar",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Es ist ein Fehler aufgetreten. Bitte überprüfen Sie die Base DN wie auch die Verbindungseinstellungen und Anmeldeinformationen.",
"Do you really want to delete the current Server Configuration?" : "Soll die aktuelle Serverkonfiguration wirklich gelöscht werden?",
diff --git a/apps/user_ldap/l10n/es.js b/apps/user_ldap/l10n/es.js
index bfe48c28f99..e457978bcd7 100644
--- a/apps/user_ldap/l10n/es.js
+++ b/apps/user_ldap/l10n/es.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "No se pudo detectar Base DN, por favor ingrésela manualmente.",
"{nthServer}. Server" : "{nthServer}. servidor",
"No object found in the given Base DN. Please revise." : "No se encuentra ningún objeto en la Base DN dada. Por favor revisar.",
+ "More than 1,000 directory entries available." : "Más de 1.000 entradas de directorios disponibles.",
" entries available within the provided Base DN" : "entradas disponibles dentro de la BaseDN provista",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Un error ocurrió. Por favor revise la Base DN, también como la configuración de la conexión y credenciales.",
"Do you really want to delete the current Server Configuration?" : "¿Realmente desea eliminar la configuración actual del servidor?",
diff --git a/apps/user_ldap/l10n/es.json b/apps/user_ldap/l10n/es.json
index c8d64f6b9d6..ebce66270f1 100644
--- a/apps/user_ldap/l10n/es.json
+++ b/apps/user_ldap/l10n/es.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "No se pudo detectar Base DN, por favor ingrésela manualmente.",
"{nthServer}. Server" : "{nthServer}. servidor",
"No object found in the given Base DN. Please revise." : "No se encuentra ningún objeto en la Base DN dada. Por favor revisar.",
+ "More than 1,000 directory entries available." : "Más de 1.000 entradas de directorios disponibles.",
" entries available within the provided Base DN" : "entradas disponibles dentro de la BaseDN provista",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Un error ocurrió. Por favor revise la Base DN, también como la configuración de la conexión y credenciales.",
"Do you really want to delete the current Server Configuration?" : "¿Realmente desea eliminar la configuración actual del servidor?",
diff --git a/apps/user_ldap/l10n/et_EE.js b/apps/user_ldap/l10n/et_EE.js
index aa0727c9bc1..649950716b6 100644
--- a/apps/user_ldap/l10n/et_EE.js
+++ b/apps/user_ldap/l10n/et_EE.js
@@ -18,18 +18,22 @@ OC.L10N.register(
"Select groups" : "Vali grupid",
"Select object classes" : "Vali objekti klassid",
"Please check the credentials, they seem to be wrong." : "Palu nkontrolli kasutajaandmeid, need näivad olevat valed.",
+ "Could not detect Base DN, please enter it manually." : "BaasDN-i tuvastamine ebaõnnestus. Palun sisesta see käsitsi.",
"{nthServer}. Server" : "{nthServer}. Server",
"Do you really want to delete the current Server Configuration?" : "Oled kindel, et tahad kustutada praegust serveri seadistust?",
"Confirm Deletion" : "Kinnita kustutamine",
+ "Error while clearing the mappings." : "Tõrgeseose eemaldamisel.",
"Mode switch" : "Režiimi lüliti",
"Select attributes" : "Vali atribuudid",
"User found and settings verified." : "Kasutaja leiti ja seaded on kontrollitud.",
+ "Please provide a login name to test against" : "Palun sisesta kasutajanimi, mida testida",
"_%s group found_::_%s groups found_" : ["%s grupp leitud","%s gruppi leitud"],
"_%s user found_::_%s users found_" : ["%s kasutaja leitud","%s kasutajat leitud"],
"Could not find the desired feature" : "Ei suuda leida soovitud funktsioonaalsust",
"Invalid Host" : "Vigane server",
"Server" : "Server",
"Users" : "Kasutajad",
+ "Login Attributes" : "Sisselogimise andmed",
"Groups" : "Grupid",
"Test Configuration" : "Testi seadistust",
"Help" : "Abiinfo",
@@ -43,6 +47,8 @@ OC.L10N.register(
"LDAP Filter:" : "LDAP filter:",
"The filter specifies which LDAP groups shall have access to the %s instance." : "Filter määrab millised LDAP grupid saavad ligipääsu sellele %s instantsile.",
"Verify settings and count groups" : "Kontrolli seadeid ja loe grupid üle",
+ "LDAP / AD Username:" : "LDAP / AD kasutajanimi:",
+ "LDAP / AD Email Address:" : "LDAP / AD e-posti aadress:",
"Other Attributes:" : "Muud atribuudid:",
"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "Määrab sisselogimisel kasutatava filtri. %%uid asendab sisselogimistegevuses kasutajanime. Näide: \"uid=%%uid\"",
"Test Loginname" : "Testi kasutajanime",
diff --git a/apps/user_ldap/l10n/et_EE.json b/apps/user_ldap/l10n/et_EE.json
index 5d8fbe2f81b..04b22459b18 100644
--- a/apps/user_ldap/l10n/et_EE.json
+++ b/apps/user_ldap/l10n/et_EE.json
@@ -16,18 +16,22 @@
"Select groups" : "Vali grupid",
"Select object classes" : "Vali objekti klassid",
"Please check the credentials, they seem to be wrong." : "Palu nkontrolli kasutajaandmeid, need näivad olevat valed.",
+ "Could not detect Base DN, please enter it manually." : "BaasDN-i tuvastamine ebaõnnestus. Palun sisesta see käsitsi.",
"{nthServer}. Server" : "{nthServer}. Server",
"Do you really want to delete the current Server Configuration?" : "Oled kindel, et tahad kustutada praegust serveri seadistust?",
"Confirm Deletion" : "Kinnita kustutamine",
+ "Error while clearing the mappings." : "Tõrgeseose eemaldamisel.",
"Mode switch" : "Režiimi lüliti",
"Select attributes" : "Vali atribuudid",
"User found and settings verified." : "Kasutaja leiti ja seaded on kontrollitud.",
+ "Please provide a login name to test against" : "Palun sisesta kasutajanimi, mida testida",
"_%s group found_::_%s groups found_" : ["%s grupp leitud","%s gruppi leitud"],
"_%s user found_::_%s users found_" : ["%s kasutaja leitud","%s kasutajat leitud"],
"Could not find the desired feature" : "Ei suuda leida soovitud funktsioonaalsust",
"Invalid Host" : "Vigane server",
"Server" : "Server",
"Users" : "Kasutajad",
+ "Login Attributes" : "Sisselogimise andmed",
"Groups" : "Grupid",
"Test Configuration" : "Testi seadistust",
"Help" : "Abiinfo",
@@ -41,6 +45,8 @@
"LDAP Filter:" : "LDAP filter:",
"The filter specifies which LDAP groups shall have access to the %s instance." : "Filter määrab millised LDAP grupid saavad ligipääsu sellele %s instantsile.",
"Verify settings and count groups" : "Kontrolli seadeid ja loe grupid üle",
+ "LDAP / AD Username:" : "LDAP / AD kasutajanimi:",
+ "LDAP / AD Email Address:" : "LDAP / AD e-posti aadress:",
"Other Attributes:" : "Muud atribuudid:",
"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "Määrab sisselogimisel kasutatava filtri. %%uid asendab sisselogimistegevuses kasutajanime. Näide: \"uid=%%uid\"",
"Test Loginname" : "Testi kasutajanime",
diff --git a/apps/user_ldap/l10n/eu.js b/apps/user_ldap/l10n/eu.js
index 44ce45a1b96..410b626745c 100644
--- a/apps/user_ldap/l10n/eu.js
+++ b/apps/user_ldap/l10n/eu.js
@@ -10,15 +10,22 @@ OC.L10N.register(
"No configuration specified" : "Ez da konfiguraziorik zehaztu",
"No data specified" : "Ez da daturik zehaztu",
" Could not set configuration %s" : "Ezin izan da %s konfigurazioa ezarri",
+ "Action does not exist" : "Ekintza ez da existitzen",
+ "The Base DN appears to be wrong" : "Oinarrizko DN gaizki dagoela dirudi",
"Configuration incorrect" : "Konfigurazioa ez dago ongi",
"Configuration incomplete" : "Konfigurazioa osatu gabe dago",
"Configuration OK" : "Konfigurazioa ongi dago",
"Select groups" : "Hautatu taldeak",
"Select object classes" : "Hautatu objektu klaseak",
"{nthServer}. Server" : "{nthServer}. Zerbitzaria",
+ "More than 1,000 directory entries available." : "1.000 baino direktorio sarrera gehiago daude.",
+ " entries available within the provided Base DN" : "sarrera eskuragarri emandako Oinarrizko DNarekin",
"Do you really want to delete the current Server Configuration?" : "Ziur zaude Zerbitzariaren Konfigurazioa ezabatu nahi duzula?",
"Confirm Deletion" : "Baieztatu Ezabatzea",
"Select attributes" : "Hautatu atributuak",
+ "User found and settings verified." : "Erabiltzailea aurkituta eta ezarpenak egiaztatutak.",
+ "Please provide a login name to test against" : "Mesedez saioa hasteko izen bat eman frogatu ahal izateko",
+ "The group box was disabled, because the LDAP / AD server does not support memberOf." : "Taldeen sarrera desgaitu da, LDAP / AD zerbitzariak ez duelako memberOf onartzen.",
"_%s group found_::_%s groups found_" : ["Talde %s aurkitu da","%s talde aurkitu dira"],
"_%s user found_::_%s users found_" : ["Erabiltzaile %s aurkitu da","%s erabiltzaile aurkitu dira"],
"Could not detect user display name attribute. Please specify it yourself in advanced ldap settings." : "Ezin izan da erabiltzailearen bistaratze izenaren atributua antzeman. Mesedez zehaztu ldap ezarpen aurreratuetan.",
@@ -26,27 +33,47 @@ OC.L10N.register(
"Invalid Host" : "Baliogabeko hostalaria",
"Server" : "Zerbitzaria",
"Users" : "Erabiltzaileak",
+ "Login Attributes" : "Saioa hasteko atributuak",
"Groups" : "Taldeak",
"Test Configuration" : "Egiaztatu Konfigurazioa",
"Help" : "Laguntza",
"Groups meeting these criteria are available in %s:" : "Baldintza horiek betetzen dituzten taldeak bertan eskuragarri %s:",
+ "Only these object classes:" : "Bakarrik objektu klase hauetakoak:",
+ "Only from these groups:" : "Bakarrik talde hauetakoak:",
+ "Search groups" : "Bilatu taldeak",
+ "Available groups" : "Eskuragarri dauden taldeak",
+ "Selected groups" : "Hautatuko taldeak",
+ "Edit LDAP Query" : "Editatu LDAP kontsulta",
+ "LDAP Filter:" : "LDAP Iragazkia:",
"The filter specifies which LDAP groups shall have access to the %s instance." : "Iragazkiak zehazten du ze LDAP taldek izango duten sarrera %s instantziara:",
+ "Verify settings and count groups" : "Egiaztatu ezarpetak eta zenbatu taldeak",
+ "LDAP / AD Username:" : "LDAP / AD Erabiltzaile izena:",
+ "LDAP / AD Email Address:" : "LDAP / AD E-posta Helbidea:",
"Other Attributes:" : "Bestelako atributuak:",
"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "Definitu aplikatu beharreko iragazkia sartzen saiatzean. %%uid erabiltzailearen izena ordezten du sartzeko ekintzan. Adibidez: \"uid=%%uid\"",
+ "Test Loginname" : "Egiaztatu Saioa hasteko izena",
+ "Verify settings" : "Egiaztatu ezarpenak",
"1. Server" : "1. Zerbitzaria",
"%s. Server:" : "%s. Zerbitzaria:",
+ "Add a new and blank configuration" : "Gehitu konfigurazio berri eta huts bat",
+ "Copy current configuration into new directory binding" : "Kopiatu uneko konfigurazioa direktorio lotura berrian",
+ "Delete the current configuration" : "Ezabatu uneko konfigurazioa",
"Host" : "Hostalaria",
"You can omit the protocol, except you require SSL. Then start with ldaps://" : "Protokoloa ez da beharrezkoa, SSL behar baldin ez baduzu. Honela bada hasi ldaps://",
"Port" : "Portua",
+ "Detect Port" : "Antzeman Ataka",
"User DN" : "Erabiltzaile DN",
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "Lotura egingo den bezero erabiltzailearen DNa, adb. uid=agent,dc=example,dc=com. Sarrera anonimoak gaitzeko utzi DN eta Pasahitza hutsik.",
"Password" : "Pasahitza",
"For anonymous access, leave DN and Password empty." : "Sarrera anonimoak gaitzeko utzi DN eta Pasahitza hutsik.",
"One Base DN per line" : "DN Oinarri bat lerroko",
"You can specify Base DN for users and groups in the Advanced tab" : "Erabiltzaile eta taldeentzako Oinarrizko DN zehaztu dezakezu Aurreratu fitxan",
+ "Detect Base DN" : "Anteman Oinarrizko DN",
+ "Test Base DN" : "Egiaztatu Oinarrizko DN",
"Manually enter LDAP filters (recommended for large directories)" : "Eskuz sartu LDAP iragazkiak (direktorio handietarako gomendatuta)",
"Limit %s access to users meeting these criteria:" : "Mugatu %s sarbidea baldintza horiek betetzen dituzten erabiltzaileei.",
"The filter specifies which LDAP users shall have access to the %s instance." : "Iragazkiak zehazten du ze LDAP erabiltzailek izango duten sarrera %s instantziara:",
+ "Verify settings and count users" : "Egiaztatu ezarpetak eta zenbatu erabiltzaileak",
"Saving" : "Gordetzen",
"Back" : "Atzera",
"Continue" : "Jarraitu",
diff --git a/apps/user_ldap/l10n/eu.json b/apps/user_ldap/l10n/eu.json
index 64539c16e11..f0599392c50 100644
--- a/apps/user_ldap/l10n/eu.json
+++ b/apps/user_ldap/l10n/eu.json
@@ -8,15 +8,22 @@
"No configuration specified" : "Ez da konfiguraziorik zehaztu",
"No data specified" : "Ez da daturik zehaztu",
" Could not set configuration %s" : "Ezin izan da %s konfigurazioa ezarri",
+ "Action does not exist" : "Ekintza ez da existitzen",
+ "The Base DN appears to be wrong" : "Oinarrizko DN gaizki dagoela dirudi",
"Configuration incorrect" : "Konfigurazioa ez dago ongi",
"Configuration incomplete" : "Konfigurazioa osatu gabe dago",
"Configuration OK" : "Konfigurazioa ongi dago",
"Select groups" : "Hautatu taldeak",
"Select object classes" : "Hautatu objektu klaseak",
"{nthServer}. Server" : "{nthServer}. Zerbitzaria",
+ "More than 1,000 directory entries available." : "1.000 baino direktorio sarrera gehiago daude.",
+ " entries available within the provided Base DN" : "sarrera eskuragarri emandako Oinarrizko DNarekin",
"Do you really want to delete the current Server Configuration?" : "Ziur zaude Zerbitzariaren Konfigurazioa ezabatu nahi duzula?",
"Confirm Deletion" : "Baieztatu Ezabatzea",
"Select attributes" : "Hautatu atributuak",
+ "User found and settings verified." : "Erabiltzailea aurkituta eta ezarpenak egiaztatutak.",
+ "Please provide a login name to test against" : "Mesedez saioa hasteko izen bat eman frogatu ahal izateko",
+ "The group box was disabled, because the LDAP / AD server does not support memberOf." : "Taldeen sarrera desgaitu da, LDAP / AD zerbitzariak ez duelako memberOf onartzen.",
"_%s group found_::_%s groups found_" : ["Talde %s aurkitu da","%s talde aurkitu dira"],
"_%s user found_::_%s users found_" : ["Erabiltzaile %s aurkitu da","%s erabiltzaile aurkitu dira"],
"Could not detect user display name attribute. Please specify it yourself in advanced ldap settings." : "Ezin izan da erabiltzailearen bistaratze izenaren atributua antzeman. Mesedez zehaztu ldap ezarpen aurreratuetan.",
@@ -24,27 +31,47 @@
"Invalid Host" : "Baliogabeko hostalaria",
"Server" : "Zerbitzaria",
"Users" : "Erabiltzaileak",
+ "Login Attributes" : "Saioa hasteko atributuak",
"Groups" : "Taldeak",
"Test Configuration" : "Egiaztatu Konfigurazioa",
"Help" : "Laguntza",
"Groups meeting these criteria are available in %s:" : "Baldintza horiek betetzen dituzten taldeak bertan eskuragarri %s:",
+ "Only these object classes:" : "Bakarrik objektu klase hauetakoak:",
+ "Only from these groups:" : "Bakarrik talde hauetakoak:",
+ "Search groups" : "Bilatu taldeak",
+ "Available groups" : "Eskuragarri dauden taldeak",
+ "Selected groups" : "Hautatuko taldeak",
+ "Edit LDAP Query" : "Editatu LDAP kontsulta",
+ "LDAP Filter:" : "LDAP Iragazkia:",
"The filter specifies which LDAP groups shall have access to the %s instance." : "Iragazkiak zehazten du ze LDAP taldek izango duten sarrera %s instantziara:",
+ "Verify settings and count groups" : "Egiaztatu ezarpetak eta zenbatu taldeak",
+ "LDAP / AD Username:" : "LDAP / AD Erabiltzaile izena:",
+ "LDAP / AD Email Address:" : "LDAP / AD E-posta Helbidea:",
"Other Attributes:" : "Bestelako atributuak:",
"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "Definitu aplikatu beharreko iragazkia sartzen saiatzean. %%uid erabiltzailearen izena ordezten du sartzeko ekintzan. Adibidez: \"uid=%%uid\"",
+ "Test Loginname" : "Egiaztatu Saioa hasteko izena",
+ "Verify settings" : "Egiaztatu ezarpenak",
"1. Server" : "1. Zerbitzaria",
"%s. Server:" : "%s. Zerbitzaria:",
+ "Add a new and blank configuration" : "Gehitu konfigurazio berri eta huts bat",
+ "Copy current configuration into new directory binding" : "Kopiatu uneko konfigurazioa direktorio lotura berrian",
+ "Delete the current configuration" : "Ezabatu uneko konfigurazioa",
"Host" : "Hostalaria",
"You can omit the protocol, except you require SSL. Then start with ldaps://" : "Protokoloa ez da beharrezkoa, SSL behar baldin ez baduzu. Honela bada hasi ldaps://",
"Port" : "Portua",
+ "Detect Port" : "Antzeman Ataka",
"User DN" : "Erabiltzaile DN",
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "Lotura egingo den bezero erabiltzailearen DNa, adb. uid=agent,dc=example,dc=com. Sarrera anonimoak gaitzeko utzi DN eta Pasahitza hutsik.",
"Password" : "Pasahitza",
"For anonymous access, leave DN and Password empty." : "Sarrera anonimoak gaitzeko utzi DN eta Pasahitza hutsik.",
"One Base DN per line" : "DN Oinarri bat lerroko",
"You can specify Base DN for users and groups in the Advanced tab" : "Erabiltzaile eta taldeentzako Oinarrizko DN zehaztu dezakezu Aurreratu fitxan",
+ "Detect Base DN" : "Anteman Oinarrizko DN",
+ "Test Base DN" : "Egiaztatu Oinarrizko DN",
"Manually enter LDAP filters (recommended for large directories)" : "Eskuz sartu LDAP iragazkiak (direktorio handietarako gomendatuta)",
"Limit %s access to users meeting these criteria:" : "Mugatu %s sarbidea baldintza horiek betetzen dituzten erabiltzaileei.",
"The filter specifies which LDAP users shall have access to the %s instance." : "Iragazkiak zehazten du ze LDAP erabiltzailek izango duten sarrera %s instantziara:",
+ "Verify settings and count users" : "Egiaztatu ezarpetak eta zenbatu erabiltzaileak",
"Saving" : "Gordetzen",
"Back" : "Atzera",
"Continue" : "Jarraitu",
diff --git a/apps/user_ldap/l10n/fi_FI.js b/apps/user_ldap/l10n/fi_FI.js
index 96ed6a00c7d..e10a9f17559 100644
--- a/apps/user_ldap/l10n/fi_FI.js
+++ b/apps/user_ldap/l10n/fi_FI.js
@@ -3,14 +3,21 @@ OC.L10N.register(
{
"Failed to delete the server configuration" : "Palvelinmäärityksen poistaminen epäonnistui",
"The configuration is valid and the connection could be established!" : "Määritys on kelvollinen ja yhteys kyettiin muodostamaan!",
+ "The configuration is invalid. Please have a look at the logs for further details." : "Määritykset ovat väärin. Tarkista loki saadaksesi lisätietoja.",
"No action specified" : "Toimintoa ei määritetty",
"Action does not exist" : "Toimintoa ei ole olemassa.",
"Configuration incorrect" : "Määritykset väärin",
"Configuration incomplete" : "Määritykset puutteelliset",
"Configuration OK" : "Määritykset OK",
"Select groups" : "Valitse ryhmät",
+ "Please check the credentials, they seem to be wrong." : "Tarkista kirjautumistiedot, ne vaikuttavat olevan väärin.",
+ "Please specify the port, it could not be auto-detected." : "Määritä portti, sitä ei kyetty havaitsemaan automaattisesti.",
+ "More than 1,000 directory entries available." : "Yli 1000 hakemistotietuetta saatavilla.",
"Do you really want to delete the current Server Configuration?" : "Haluatko varmasti poistaa nykyisen palvelinmäärityksen?",
"Confirm Deletion" : "Vahvista poisto",
+ "User found and settings verified." : "Käyttäjä löytyi ja asetukset vahvistettiin.",
+ "An unspecified error occurred. Please check the settings and the log." : "Tapahtui määrittämätön virhe. Tarkista asetukset ja loki.",
+ "A connection error to LDAP / AD occurred, please check host, port and credentials." : "Yhteysvirhe LDAP:iin/AD:hen, tarkista palvelimen osoite, portti ja kirjautumistiedot.",
"_%s group found_::_%s groups found_" : ["%s ryhmä löytynyt","%s ryhmää löytynyt"],
"_%s user found_::_%s users found_" : ["%s käyttäjä löytynyt","%s käyttäjää löytynyt"],
"Server" : "Palvelin",
@@ -21,12 +28,17 @@ OC.L10N.register(
"Search groups" : "Etsi ryhmiä",
"Available groups" : "Käytettävissä olevat ryhmät",
"Selected groups" : "Valitut ryhmät",
+ "Edit LDAP Query" : "Muokkaa LDAP-kyselyä",
"LDAP Filter:" : "LDAP-suodatin:",
+ "Verify settings and count groups" : "Vahvista asetukset ja laske ryhmät",
"LDAP / AD Username:" : "LDAP-/AD-käyttäjätunnus:",
"LDAP / AD Email Address:" : "LDAP-/AD-sähköpostiosoite:",
+ "Test Loginname" : "Testaa kirjautumisnimi",
"Verify settings" : "Vahvista asetukset",
"1. Server" : "1. Palvelin",
"%s. Server:" : "%s. Palvelin:",
+ "Add a new and blank configuration" : "Lisää uusi, tyhjä määritys",
+ "Delete the current configuration" : "Poista nykyinen määritys",
"Host" : "Isäntä",
"You can omit the protocol, except you require SSL. Then start with ldaps://" : "Voit jättää protokollan määrittämättä, paitsi kun vaadit SSL:ää. Aloita silloin ldaps://",
"Port" : "Portti",
@@ -36,6 +48,8 @@ OC.L10N.register(
"Password" : "Salasana",
"For anonymous access, leave DN and Password empty." : "Jos haluat mahdollistaa anonyymin pääsyn, jätä DN ja Salasana tyhjäksi ",
"You can specify Base DN for users and groups in the Advanced tab" : "Voit määrittää käyttäjien ja ryhmien oletus DN:n (distinguished name) 'tarkemmat asetukset'-välilehdeltä ",
+ "Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "Välttää automaattisia LDAP-pyyntöjä. Sopiva suurille instansseille, mutta vaatii LDAP-tietoutta.",
+ "Manually enter LDAP filters (recommended for large directories)" : "Syötä LDAP-suodattimet manuaalisesti (suositeltu suurille hakemistoille)",
"Verify settings and count users" : "Vahvista asetukset ja laske käyttäjät",
"Saving" : "Tallennetaan",
"Back" : "Takaisin",
diff --git a/apps/user_ldap/l10n/fi_FI.json b/apps/user_ldap/l10n/fi_FI.json
index e34fefaf93d..8abef4f8585 100644
--- a/apps/user_ldap/l10n/fi_FI.json
+++ b/apps/user_ldap/l10n/fi_FI.json
@@ -1,14 +1,21 @@
{ "translations": {
"Failed to delete the server configuration" : "Palvelinmäärityksen poistaminen epäonnistui",
"The configuration is valid and the connection could be established!" : "Määritys on kelvollinen ja yhteys kyettiin muodostamaan!",
+ "The configuration is invalid. Please have a look at the logs for further details." : "Määritykset ovat väärin. Tarkista loki saadaksesi lisätietoja.",
"No action specified" : "Toimintoa ei määritetty",
"Action does not exist" : "Toimintoa ei ole olemassa.",
"Configuration incorrect" : "Määritykset väärin",
"Configuration incomplete" : "Määritykset puutteelliset",
"Configuration OK" : "Määritykset OK",
"Select groups" : "Valitse ryhmät",
+ "Please check the credentials, they seem to be wrong." : "Tarkista kirjautumistiedot, ne vaikuttavat olevan väärin.",
+ "Please specify the port, it could not be auto-detected." : "Määritä portti, sitä ei kyetty havaitsemaan automaattisesti.",
+ "More than 1,000 directory entries available." : "Yli 1000 hakemistotietuetta saatavilla.",
"Do you really want to delete the current Server Configuration?" : "Haluatko varmasti poistaa nykyisen palvelinmäärityksen?",
"Confirm Deletion" : "Vahvista poisto",
+ "User found and settings verified." : "Käyttäjä löytyi ja asetukset vahvistettiin.",
+ "An unspecified error occurred. Please check the settings and the log." : "Tapahtui määrittämätön virhe. Tarkista asetukset ja loki.",
+ "A connection error to LDAP / AD occurred, please check host, port and credentials." : "Yhteysvirhe LDAP:iin/AD:hen, tarkista palvelimen osoite, portti ja kirjautumistiedot.",
"_%s group found_::_%s groups found_" : ["%s ryhmä löytynyt","%s ryhmää löytynyt"],
"_%s user found_::_%s users found_" : ["%s käyttäjä löytynyt","%s käyttäjää löytynyt"],
"Server" : "Palvelin",
@@ -19,12 +26,17 @@
"Search groups" : "Etsi ryhmiä",
"Available groups" : "Käytettävissä olevat ryhmät",
"Selected groups" : "Valitut ryhmät",
+ "Edit LDAP Query" : "Muokkaa LDAP-kyselyä",
"LDAP Filter:" : "LDAP-suodatin:",
+ "Verify settings and count groups" : "Vahvista asetukset ja laske ryhmät",
"LDAP / AD Username:" : "LDAP-/AD-käyttäjätunnus:",
"LDAP / AD Email Address:" : "LDAP-/AD-sähköpostiosoite:",
+ "Test Loginname" : "Testaa kirjautumisnimi",
"Verify settings" : "Vahvista asetukset",
"1. Server" : "1. Palvelin",
"%s. Server:" : "%s. Palvelin:",
+ "Add a new and blank configuration" : "Lisää uusi, tyhjä määritys",
+ "Delete the current configuration" : "Poista nykyinen määritys",
"Host" : "Isäntä",
"You can omit the protocol, except you require SSL. Then start with ldaps://" : "Voit jättää protokollan määrittämättä, paitsi kun vaadit SSL:ää. Aloita silloin ldaps://",
"Port" : "Portti",
@@ -34,6 +46,8 @@
"Password" : "Salasana",
"For anonymous access, leave DN and Password empty." : "Jos haluat mahdollistaa anonyymin pääsyn, jätä DN ja Salasana tyhjäksi ",
"You can specify Base DN for users and groups in the Advanced tab" : "Voit määrittää käyttäjien ja ryhmien oletus DN:n (distinguished name) 'tarkemmat asetukset'-välilehdeltä ",
+ "Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "Välttää automaattisia LDAP-pyyntöjä. Sopiva suurille instansseille, mutta vaatii LDAP-tietoutta.",
+ "Manually enter LDAP filters (recommended for large directories)" : "Syötä LDAP-suodattimet manuaalisesti (suositeltu suurille hakemistoille)",
"Verify settings and count users" : "Vahvista asetukset ja laske käyttäjät",
"Saving" : "Tallennetaan",
"Back" : "Takaisin",
diff --git a/apps/user_ldap/l10n/he.js b/apps/user_ldap/l10n/he.js
index 1baa1d43a66..56be7447e72 100644
--- a/apps/user_ldap/l10n/he.js
+++ b/apps/user_ldap/l10n/he.js
@@ -1,19 +1,119 @@
OC.L10N.register(
"user_ldap",
{
- "Do you really want to delete the current Server Configuration?" : "האם אכן למחוק את הגדרות השרת הנוכחיות?",
+ "Failed to clear the mappings." : "כשל בניקוי המיפויים.",
+ "Failed to delete the server configuration" : "כשל במחיקת הגדרות השרת",
+ "The configuration is invalid: anonymous bind is not allowed." : "התצורה אינה חוקית: חיבור אנונימי אסור",
+ "The configuration is valid and the connection could be established!" : "התצורה תקפה וניתן לבצע חיבור!",
+ "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "התצורה תקפה, אך הקישור נכשל. יש לבדוק את הגדרות השרת והחיבור.",
+ "The configuration is invalid. Please have a look at the logs for further details." : "התצורה אינה חוקית. יש לבדוק את הלוגים לפרטים נוספים.",
+ "No action specified" : "לא צויינה פעולה",
+ "No configuration specified" : "לא הוגדרה תצורה",
+ "No data specified" : "לא הוגדר מידע",
+ " Could not set configuration %s" : " לא ניתן היה לקבוע הגדרות %s",
+ "Action does not exist" : "פעולה לא קיימת",
+ "The Base DN appears to be wrong" : "בסיס DN נראה כשגוי",
+ "Configuration incorrect" : "הגדרה שגויה",
+ "Configuration incomplete" : "הגדרה לא מלאה",
+ "Configuration OK" : "הגדרה בסדר",
+ "Select groups" : "בחירת קבוצות",
+ "Select object classes" : "בחירת מחלקות עצמים",
+ "Please check the credentials, they seem to be wrong." : "יש לבדוק את פרטי הכניסה, נראה שהם שגויים",
+ "Please specify the port, it could not be auto-detected." : "יש לספק את שער הכניסה - פורט, לא ניתן היה לאתרו בצורה אוטומטית",
+ "Base DN could not be auto-detected, please revise credentials, host and port." : "לא ניתן היה לאתר באופן אוטומטי את בסיס DN, יש להחליף את פרטי הכניסה, פרטי שרת ושער גישה - פורט.",
+ "Could not detect Base DN, please enter it manually." : "לא ניתן היה לאתר את בסיס DN, יש להכניסו באופן ידני.",
+ "{nthServer}. Server" : "{nthServer}. שרת",
+ "No object found in the given Base DN. Please revise." : "לא אותר אוביקט בבסיס DN שסופק. יש להחליף.",
+ "More than 1,000 directory entries available." : "קיימים יותר מ- 1,000 רשומות ספריה.",
+ " entries available within the provided Base DN" : " קיימות רשומות מתוך בסיס ה- DN שסופק",
+ "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "אירעה שגיאה. יש לבדוק את בסיס ה- DN, כמו גם את הגדרות החיבור ופרטי הכניסה.",
+ "Do you really want to delete the current Server Configuration?" : "האם אכן למחוק את הגדרות השרת הנוכחיות?האם באמת ברצונך למחוק את הגדרות השרת הנוכחיות?",
"Confirm Deletion" : "אישור המחיקה",
+ "Mappings cleared successfully!" : "מיפויים נוקו בהצלחה!",
+ "Error while clearing the mappings." : "שגיאה בזמן ניקוי המיפויים.",
+ "Anonymous bind is not allowed. Please provide a User DN and Password." : "קישור אננונימי אינו מותר. יש לספק שם משתמש DN וסיסמא.",
+ "LDAP Operations error. Anonymous bind might not be allowed." : "שגיאת פעילויות LDAP. יתכן שקישור אנונימי אינו מותר.",
+ "Saving failed. Please make sure the database is in Operation. Reload before continuing." : "שמירה נכשלה. יש לבדוק אם מסד הנתונים פעיל. יש לטעון מחדש לפני המשך.",
+ "Switching the mode will enable automatic LDAP queries. Depending on your LDAP size they may take a while. Do you still want to switch the mode?" : "שינוי המצב יאפשר שאילתות LDAP אוטמטיות. בהתאם לגודל ה- LDAP שלך ייתכן והפעולה תיקח זמן רב. האם ברצונך לשנות את המצב?",
+ "Mode switch" : "שינוי מצב",
+ "Select attributes" : "בחירת מאפיינים",
+ "User not found. Please check your login attributes and username. Effective filter (to copy-and-paste for command line validation): <br/>" : "משתמש לא אותר. יש לבדוק את מאפייני ההתחברות ושם המשתמש. מסנן אפקטיבי (העתקה והדבקה לאימות שורת פקודה):<br/>",
+ "User found and settings verified." : "משתמש אותר והגדרות אומתו.",
+ "Settings verified, but one user found. Only the first will be able to login. Consider a more narrow filter." : "הגדרות אומתו, אך רק משתמש אחד אותר. רק הראשון יוכל להתחבר. יש לבחון שימוש בסינון צר יותר.",
+ "An unspecified error occurred. Please check the settings and the log." : "אירעה שגיאה לא מזוהה. יש לבדוק את ההגדרות ואת הלוג.",
+ "The search filter is invalid, probably due to syntax issues like uneven number of opened and closed brackets. Please revise." : "סינון החיפוש אינו חוקי. ככל הנראה בשל שיאה תחבירית כגון מספר לא שווה של פתח-סוגריים וסגור-סוגריים. יש לתקן.",
+ "A connection error to LDAP / AD occurred, please check host, port and credentials." : "אירעה שגיאת חיבור ל- LDAP / AD, יש לבדוק את השרת, שער החיבור - פורט ופרטי הכניסה. ",
+ "The %uid placeholder is missing. It will be replaced with the login name when querying LDAP / AD." : "שומר המקום %uid חסר. הוא יוחלף עם שם המשתמש בזמן שאילתת LDAP / AD.",
+ "Please provide a login name to test against" : "יש לספק שם משתמש לבדיקה מולו",
+ "The group box was disabled, because the LDAP / AD server does not support memberOf." : "שדה הקבוצה נוטרל, כיוון ששרת ה- LDAP / AD לא תומך ב- memberOf.",
+ "_%s group found_::_%s groups found_" : ["אותרה %s קבוצה","אותרו %s קבוצות"],
+ "_%s user found_::_%s users found_" : ["אותר %s משתמש","אותרו %s משתמשים"],
+ "Could not detect user display name attribute. Please specify it yourself in advanced ldap settings." : "לא אותר מאפיין שם תצוגה למשתמש. יש לספק אותו בעצמך בהגדרות ldap מתקדמות.",
+ "Could not find the desired feature" : "לא אותרה התכונה הרצויה",
+ "Invalid Host" : "מארח לא חוקי",
+ "Server" : "שרת",
"Users" : "משתמשים",
+ "Login Attributes" : "פרטי כניסה",
"Groups" : "קבוצות",
+ "Test Configuration" : "בדיקת הגדרות",
"Help" : "עזרה",
+ "Groups meeting these criteria are available in %s:" : "קבוצות העומדות בקריטריון זה זמינות ב- %s:",
+ "Only these object classes:" : "מחלקות עצמים אלו בלבד:",
+ "Only from these groups:" : "רק מקבוצות אלו:",
+ "Search groups" : "חיפוש בקבוצות",
+ "Available groups" : "קבוצות זמינות",
+ "Selected groups" : "קבוצות נבחרות",
+ "Edit LDAP Query" : "עריכת שאילתת LDAP",
+ "LDAP Filter:" : "מסנן LDAP:",
+ "The filter specifies which LDAP groups shall have access to the %s instance." : "המסנן הקובע לאיזו קבוצת LDAP תהיה יכולת כניסה למקרה %s.",
+ "Verify settings and count groups" : "מאמת הגדרות וסופר קבוצות",
+ "When logging in, %s will find the user based on the following attributes:" : "כאשר מתחברים, %s יחפש את המשתמש על פי המאפיינים הבאים:",
+ "LDAP / AD Username:" : "שם משתמש LDAP / AD:",
+ "Allows login against the LDAP / AD username, which is either uid or samaccountname and will be detected." : "מאפשר התחברות אל מול שם משתמש LDAP / AD, שהוא רק uid או samaccountname ויזוהה.",
+ "LDAP / AD Email Address:" : "כתובת דואר אלקטרוני LDAP / AD:",
+ "Allows login against an email attribute. Mail and mailPrimaryAddress will be allowed." : "מאפשר התחברות אל מול מאפיין דואר אלקטרוני. Mail וכן mailPrimaryAddress יהיו מותרים לשימוש.",
+ "Other Attributes:" : "מאפיינים נוספים:",
+ "Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "מגדיר את הסינון הפעיל, כשיש ניסיון התחברות. %%uid מחליף את שם המשתמש בפעולת ההתחברות. לדוגמא: \"uid=%%uid\"",
+ "Test Loginname" : "בדיקת שם התחברות",
+ "Verify settings" : "מאמת הגדרות",
+ "1. Server" : "1. שרת",
+ "%s. Server:" : "%s. שרת:",
+ "Add a new and blank configuration" : "הוספת תצורה חדשה וריקה",
+ "Copy current configuration into new directory binding" : "מעתיק תצורה נוכחית אל תוך תיקייה חדשה",
+ "Delete the current configuration" : "מחיקת תצורה נוכחית",
"Host" : "מארח",
+ "You can omit the protocol, except you require SSL. Then start with ldaps://" : "ניתן להשמיט את הפרוטוקול, אך SSL מחייב. לפיכך יש להתחיל עם ldaps://",
"Port" : "פורט",
+ "Detect Port" : "מחיקת שער - פורט",
"User DN" : "DN משתמש",
+ "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "ה- DN של משתמש הלקוח שבו החיבור יעשה, למשל uid=agent,dc=example,dc=com. לחיבור אנונימי, יש להשאיר את ה- DN והסיסמא ריקים.",
"Password" : "סיסמא",
"For anonymous access, leave DN and Password empty." : "לגישה אנונימית, השאר את הDM והסיסמא ריקים.",
+ "One Base DN per line" : "DN בסיסי אחד לשורה",
+ "You can specify Base DN for users and groups in the Advanced tab" : "ניתן לציין DN בסיסי למשתמשים ולקבוצות בלשונית מתקדם",
+ "Detect Base DN" : "גילוי DN בסיסי",
+ "Test Base DN" : "בדיקת DN בסיסי",
+ "Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "נמנע מבקשות אוטומטיות של LDAP. מועדף עבור התקנות גדולות, אבל מחייב ידע מסויים של LDAP.",
+ "Manually enter LDAP filters (recommended for large directories)" : "הכנסת מסנני LDAP ידנית (מומלץ עבוק תיקיות גדולות)",
+ "Limit %s access to users meeting these criteria:" : "מגביל כניסות %s למשתמשים אשר עומדים בתנאים אלו:",
+ "Verify settings and count users" : "מאמת הגדרות וסופר משתמשים",
+ "Saving" : "שמירה",
"Back" : "אחורה",
+ "Continue" : "המשך",
+ "LDAP" : "LDAP",
+ "Expert" : "מומחה",
"Advanced" : "מתקדם",
+ "Connection Settings" : "הגדרות התחברות",
+ "Configuration Active" : "תצורה פעילה",
+ "When unchecked, this configuration will be skipped." : "כאשר לא מסומן, נדלג על תצורה זו.",
+ "Backup (Replica) Host" : "גיבוי (העתק) שרת",
+ "Backup (Replica) Port" : "גיבוי (העתק) שער - פורט",
+ "Disable Main Server" : "ניטרול שרת עיקרי",
+ "Only connect to the replica server." : "חיבור רק להעתק שרת.",
+ "Turn off SSL certificate validation." : "כיבוי אימות אישורי אבטחה SSL.",
"in seconds. A change empties the cache." : "בשניות. שינוי מרוקן את המטמון.",
+ "Directory Settings" : "הגדרות תיקייה",
+ "Base User Tree" : "עץ משתמש בסיסי",
"in bytes" : "בבתים"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/user_ldap/l10n/he.json b/apps/user_ldap/l10n/he.json
index 77ef6d25887..ca2ba2f91a6 100644
--- a/apps/user_ldap/l10n/he.json
+++ b/apps/user_ldap/l10n/he.json
@@ -1,17 +1,117 @@
{ "translations": {
- "Do you really want to delete the current Server Configuration?" : "האם אכן למחוק את הגדרות השרת הנוכחיות?",
+ "Failed to clear the mappings." : "כשל בניקוי המיפויים.",
+ "Failed to delete the server configuration" : "כשל במחיקת הגדרות השרת",
+ "The configuration is invalid: anonymous bind is not allowed." : "התצורה אינה חוקית: חיבור אנונימי אסור",
+ "The configuration is valid and the connection could be established!" : "התצורה תקפה וניתן לבצע חיבור!",
+ "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "התצורה תקפה, אך הקישור נכשל. יש לבדוק את הגדרות השרת והחיבור.",
+ "The configuration is invalid. Please have a look at the logs for further details." : "התצורה אינה חוקית. יש לבדוק את הלוגים לפרטים נוספים.",
+ "No action specified" : "לא צויינה פעולה",
+ "No configuration specified" : "לא הוגדרה תצורה",
+ "No data specified" : "לא הוגדר מידע",
+ " Could not set configuration %s" : " לא ניתן היה לקבוע הגדרות %s",
+ "Action does not exist" : "פעולה לא קיימת",
+ "The Base DN appears to be wrong" : "בסיס DN נראה כשגוי",
+ "Configuration incorrect" : "הגדרה שגויה",
+ "Configuration incomplete" : "הגדרה לא מלאה",
+ "Configuration OK" : "הגדרה בסדר",
+ "Select groups" : "בחירת קבוצות",
+ "Select object classes" : "בחירת מחלקות עצמים",
+ "Please check the credentials, they seem to be wrong." : "יש לבדוק את פרטי הכניסה, נראה שהם שגויים",
+ "Please specify the port, it could not be auto-detected." : "יש לספק את שער הכניסה - פורט, לא ניתן היה לאתרו בצורה אוטומטית",
+ "Base DN could not be auto-detected, please revise credentials, host and port." : "לא ניתן היה לאתר באופן אוטומטי את בסיס DN, יש להחליף את פרטי הכניסה, פרטי שרת ושער גישה - פורט.",
+ "Could not detect Base DN, please enter it manually." : "לא ניתן היה לאתר את בסיס DN, יש להכניסו באופן ידני.",
+ "{nthServer}. Server" : "{nthServer}. שרת",
+ "No object found in the given Base DN. Please revise." : "לא אותר אוביקט בבסיס DN שסופק. יש להחליף.",
+ "More than 1,000 directory entries available." : "קיימים יותר מ- 1,000 רשומות ספריה.",
+ " entries available within the provided Base DN" : " קיימות רשומות מתוך בסיס ה- DN שסופק",
+ "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "אירעה שגיאה. יש לבדוק את בסיס ה- DN, כמו גם את הגדרות החיבור ופרטי הכניסה.",
+ "Do you really want to delete the current Server Configuration?" : "האם אכן למחוק את הגדרות השרת הנוכחיות?האם באמת ברצונך למחוק את הגדרות השרת הנוכחיות?",
"Confirm Deletion" : "אישור המחיקה",
+ "Mappings cleared successfully!" : "מיפויים נוקו בהצלחה!",
+ "Error while clearing the mappings." : "שגיאה בזמן ניקוי המיפויים.",
+ "Anonymous bind is not allowed. Please provide a User DN and Password." : "קישור אננונימי אינו מותר. יש לספק שם משתמש DN וסיסמא.",
+ "LDAP Operations error. Anonymous bind might not be allowed." : "שגיאת פעילויות LDAP. יתכן שקישור אנונימי אינו מותר.",
+ "Saving failed. Please make sure the database is in Operation. Reload before continuing." : "שמירה נכשלה. יש לבדוק אם מסד הנתונים פעיל. יש לטעון מחדש לפני המשך.",
+ "Switching the mode will enable automatic LDAP queries. Depending on your LDAP size they may take a while. Do you still want to switch the mode?" : "שינוי המצב יאפשר שאילתות LDAP אוטמטיות. בהתאם לגודל ה- LDAP שלך ייתכן והפעולה תיקח זמן רב. האם ברצונך לשנות את המצב?",
+ "Mode switch" : "שינוי מצב",
+ "Select attributes" : "בחירת מאפיינים",
+ "User not found. Please check your login attributes and username. Effective filter (to copy-and-paste for command line validation): <br/>" : "משתמש לא אותר. יש לבדוק את מאפייני ההתחברות ושם המשתמש. מסנן אפקטיבי (העתקה והדבקה לאימות שורת פקודה):<br/>",
+ "User found and settings verified." : "משתמש אותר והגדרות אומתו.",
+ "Settings verified, but one user found. Only the first will be able to login. Consider a more narrow filter." : "הגדרות אומתו, אך רק משתמש אחד אותר. רק הראשון יוכל להתחבר. יש לבחון שימוש בסינון צר יותר.",
+ "An unspecified error occurred. Please check the settings and the log." : "אירעה שגיאה לא מזוהה. יש לבדוק את ההגדרות ואת הלוג.",
+ "The search filter is invalid, probably due to syntax issues like uneven number of opened and closed brackets. Please revise." : "סינון החיפוש אינו חוקי. ככל הנראה בשל שיאה תחבירית כגון מספר לא שווה של פתח-סוגריים וסגור-סוגריים. יש לתקן.",
+ "A connection error to LDAP / AD occurred, please check host, port and credentials." : "אירעה שגיאת חיבור ל- LDAP / AD, יש לבדוק את השרת, שער החיבור - פורט ופרטי הכניסה. ",
+ "The %uid placeholder is missing. It will be replaced with the login name when querying LDAP / AD." : "שומר המקום %uid חסר. הוא יוחלף עם שם המשתמש בזמן שאילתת LDAP / AD.",
+ "Please provide a login name to test against" : "יש לספק שם משתמש לבדיקה מולו",
+ "The group box was disabled, because the LDAP / AD server does not support memberOf." : "שדה הקבוצה נוטרל, כיוון ששרת ה- LDAP / AD לא תומך ב- memberOf.",
+ "_%s group found_::_%s groups found_" : ["אותרה %s קבוצה","אותרו %s קבוצות"],
+ "_%s user found_::_%s users found_" : ["אותר %s משתמש","אותרו %s משתמשים"],
+ "Could not detect user display name attribute. Please specify it yourself in advanced ldap settings." : "לא אותר מאפיין שם תצוגה למשתמש. יש לספק אותו בעצמך בהגדרות ldap מתקדמות.",
+ "Could not find the desired feature" : "לא אותרה התכונה הרצויה",
+ "Invalid Host" : "מארח לא חוקי",
+ "Server" : "שרת",
"Users" : "משתמשים",
+ "Login Attributes" : "פרטי כניסה",
"Groups" : "קבוצות",
+ "Test Configuration" : "בדיקת הגדרות",
"Help" : "עזרה",
+ "Groups meeting these criteria are available in %s:" : "קבוצות העומדות בקריטריון זה זמינות ב- %s:",
+ "Only these object classes:" : "מחלקות עצמים אלו בלבד:",
+ "Only from these groups:" : "רק מקבוצות אלו:",
+ "Search groups" : "חיפוש בקבוצות",
+ "Available groups" : "קבוצות זמינות",
+ "Selected groups" : "קבוצות נבחרות",
+ "Edit LDAP Query" : "עריכת שאילתת LDAP",
+ "LDAP Filter:" : "מסנן LDAP:",
+ "The filter specifies which LDAP groups shall have access to the %s instance." : "המסנן הקובע לאיזו קבוצת LDAP תהיה יכולת כניסה למקרה %s.",
+ "Verify settings and count groups" : "מאמת הגדרות וסופר קבוצות",
+ "When logging in, %s will find the user based on the following attributes:" : "כאשר מתחברים, %s יחפש את המשתמש על פי המאפיינים הבאים:",
+ "LDAP / AD Username:" : "שם משתמש LDAP / AD:",
+ "Allows login against the LDAP / AD username, which is either uid or samaccountname and will be detected." : "מאפשר התחברות אל מול שם משתמש LDAP / AD, שהוא רק uid או samaccountname ויזוהה.",
+ "LDAP / AD Email Address:" : "כתובת דואר אלקטרוני LDAP / AD:",
+ "Allows login against an email attribute. Mail and mailPrimaryAddress will be allowed." : "מאפשר התחברות אל מול מאפיין דואר אלקטרוני. Mail וכן mailPrimaryAddress יהיו מותרים לשימוש.",
+ "Other Attributes:" : "מאפיינים נוספים:",
+ "Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "מגדיר את הסינון הפעיל, כשיש ניסיון התחברות. %%uid מחליף את שם המשתמש בפעולת ההתחברות. לדוגמא: \"uid=%%uid\"",
+ "Test Loginname" : "בדיקת שם התחברות",
+ "Verify settings" : "מאמת הגדרות",
+ "1. Server" : "1. שרת",
+ "%s. Server:" : "%s. שרת:",
+ "Add a new and blank configuration" : "הוספת תצורה חדשה וריקה",
+ "Copy current configuration into new directory binding" : "מעתיק תצורה נוכחית אל תוך תיקייה חדשה",
+ "Delete the current configuration" : "מחיקת תצורה נוכחית",
"Host" : "מארח",
+ "You can omit the protocol, except you require SSL. Then start with ldaps://" : "ניתן להשמיט את הפרוטוקול, אך SSL מחייב. לפיכך יש להתחיל עם ldaps://",
"Port" : "פורט",
+ "Detect Port" : "מחיקת שער - פורט",
"User DN" : "DN משתמש",
+ "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "ה- DN של משתמש הלקוח שבו החיבור יעשה, למשל uid=agent,dc=example,dc=com. לחיבור אנונימי, יש להשאיר את ה- DN והסיסמא ריקים.",
"Password" : "סיסמא",
"For anonymous access, leave DN and Password empty." : "לגישה אנונימית, השאר את הDM והסיסמא ריקים.",
+ "One Base DN per line" : "DN בסיסי אחד לשורה",
+ "You can specify Base DN for users and groups in the Advanced tab" : "ניתן לציין DN בסיסי למשתמשים ולקבוצות בלשונית מתקדם",
+ "Detect Base DN" : "גילוי DN בסיסי",
+ "Test Base DN" : "בדיקת DN בסיסי",
+ "Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "נמנע מבקשות אוטומטיות של LDAP. מועדף עבור התקנות גדולות, אבל מחייב ידע מסויים של LDAP.",
+ "Manually enter LDAP filters (recommended for large directories)" : "הכנסת מסנני LDAP ידנית (מומלץ עבוק תיקיות גדולות)",
+ "Limit %s access to users meeting these criteria:" : "מגביל כניסות %s למשתמשים אשר עומדים בתנאים אלו:",
+ "Verify settings and count users" : "מאמת הגדרות וסופר משתמשים",
+ "Saving" : "שמירה",
"Back" : "אחורה",
+ "Continue" : "המשך",
+ "LDAP" : "LDAP",
+ "Expert" : "מומחה",
"Advanced" : "מתקדם",
+ "Connection Settings" : "הגדרות התחברות",
+ "Configuration Active" : "תצורה פעילה",
+ "When unchecked, this configuration will be skipped." : "כאשר לא מסומן, נדלג על תצורה זו.",
+ "Backup (Replica) Host" : "גיבוי (העתק) שרת",
+ "Backup (Replica) Port" : "גיבוי (העתק) שער - פורט",
+ "Disable Main Server" : "ניטרול שרת עיקרי",
+ "Only connect to the replica server." : "חיבור רק להעתק שרת.",
+ "Turn off SSL certificate validation." : "כיבוי אימות אישורי אבטחה SSL.",
"in seconds. A change empties the cache." : "בשניות. שינוי מרוקן את המטמון.",
+ "Directory Settings" : "הגדרות תיקייה",
+ "Base User Tree" : "עץ משתמש בסיסי",
"in bytes" : "בבתים"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/user_ldap/l10n/ko.js b/apps/user_ldap/l10n/ko.js
index c08dd0e2a93..0ed95377acb 100644
--- a/apps/user_ldap/l10n/ko.js
+++ b/apps/user_ldap/l10n/ko.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "기본 DN을 자동으로 감지할 수 없습니다. 직접 입력하십시오.",
"{nthServer}. Server" : "{nthServer}. 서버",
"No object found in the given Base DN. Please revise." : "입력한 기본 DN에서 객체를 찾을 수 없습니다. 다시 입력하십시오.",
+ "More than 1,000 directory entries available." : "디렉터리 항목이 1,000개 이상 존재합니다.",
" entries available within the provided Base DN" : "개(지정한 DN의 기본 항목 수)",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "오류가 발생했습니다. 기본 DN, 연결 설정, 인증 정보를 확인하십시오.",
"Do you really want to delete the current Server Configuration?" : "현재 서버 설정을 지우시겠습니까?",
diff --git a/apps/user_ldap/l10n/ko.json b/apps/user_ldap/l10n/ko.json
index 59037ab0a2b..3fccad0577c 100644
--- a/apps/user_ldap/l10n/ko.json
+++ b/apps/user_ldap/l10n/ko.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "기본 DN을 자동으로 감지할 수 없습니다. 직접 입력하십시오.",
"{nthServer}. Server" : "{nthServer}. 서버",
"No object found in the given Base DN. Please revise." : "입력한 기본 DN에서 객체를 찾을 수 없습니다. 다시 입력하십시오.",
+ "More than 1,000 directory entries available." : "디렉터리 항목이 1,000개 이상 존재합니다.",
" entries available within the provided Base DN" : "개(지정한 DN의 기본 항목 수)",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "오류가 발생했습니다. 기본 DN, 연결 설정, 인증 정보를 확인하십시오.",
"Do you really want to delete the current Server Configuration?" : "현재 서버 설정을 지우시겠습니까?",
diff --git a/apps/user_ldap/l10n/lt_LT.js b/apps/user_ldap/l10n/lt_LT.js
index e9429c0de2a..c263e952206 100644
--- a/apps/user_ldap/l10n/lt_LT.js
+++ b/apps/user_ldap/l10n/lt_LT.js
@@ -4,9 +4,15 @@ OC.L10N.register(
"Failed to clear the mappings." : "Nepavyko išvalyti sąsajų.",
"Failed to delete the server configuration" : "Nepavyko pašalinti serverio konfigūracijos",
"The configuration is valid and the connection could be established!" : "Konfigūracija yra tinkama bei prisijungta sėkmingai!",
+ "The configuration is invalid. Please have a look at the logs for further details." : "Neteisinga konfigūracija. Daugiau informacijos rasite žurnaluose.",
+ "No action specified" : "Nepasirinktas veiksmas",
+ "No data specified" : "Nepateikta duomenų",
"Select groups" : "Pasirinkti grupes",
"Do you really want to delete the current Server Configuration?" : "Ar tikrai norite ištrinti dabartinę serverio konfigūraciją?",
"Confirm Deletion" : "Patvirtinkite trynimą",
+ "Select attributes" : "Pasirink atributus",
+ "_%s group found_::_%s groups found_" : ["Rasta %s grupė","Rastos %s grupės","Rastos %s grupės"],
+ "_%s user found_::_%s users found_" : ["Rastas %s vartotojas","Rasti %s vartotojai","Rasti %s vartotojai"],
"Server" : "Serveris",
"Users" : "Vartotojai",
"Groups" : "Grupės",
diff --git a/apps/user_ldap/l10n/lt_LT.json b/apps/user_ldap/l10n/lt_LT.json
index 19ca042b62f..64e2bae4670 100644
--- a/apps/user_ldap/l10n/lt_LT.json
+++ b/apps/user_ldap/l10n/lt_LT.json
@@ -2,9 +2,15 @@
"Failed to clear the mappings." : "Nepavyko išvalyti sąsajų.",
"Failed to delete the server configuration" : "Nepavyko pašalinti serverio konfigūracijos",
"The configuration is valid and the connection could be established!" : "Konfigūracija yra tinkama bei prisijungta sėkmingai!",
+ "The configuration is invalid. Please have a look at the logs for further details." : "Neteisinga konfigūracija. Daugiau informacijos rasite žurnaluose.",
+ "No action specified" : "Nepasirinktas veiksmas",
+ "No data specified" : "Nepateikta duomenų",
"Select groups" : "Pasirinkti grupes",
"Do you really want to delete the current Server Configuration?" : "Ar tikrai norite ištrinti dabartinę serverio konfigūraciją?",
"Confirm Deletion" : "Patvirtinkite trynimą",
+ "Select attributes" : "Pasirink atributus",
+ "_%s group found_::_%s groups found_" : ["Rasta %s grupė","Rastos %s grupės","Rastos %s grupės"],
+ "_%s user found_::_%s users found_" : ["Rastas %s vartotojas","Rasti %s vartotojai","Rasti %s vartotojai"],
"Server" : "Serveris",
"Users" : "Vartotojai",
"Groups" : "Grupės",
diff --git a/apps/user_ldap/l10n/mk.js b/apps/user_ldap/l10n/mk.js
index 560aa4b6b8c..1165678b925 100644
--- a/apps/user_ldap/l10n/mk.js
+++ b/apps/user_ldap/l10n/mk.js
@@ -1,6 +1,7 @@
OC.L10N.register(
"user_ldap",
{
+ "Select groups" : "Одбери групи",
"Confirm Deletion" : "Потврдете го бришењето",
"Users" : "Корисници",
"Groups" : "Групи",
diff --git a/apps/user_ldap/l10n/mk.json b/apps/user_ldap/l10n/mk.json
index 85fab2fb2d1..3bd03720893 100644
--- a/apps/user_ldap/l10n/mk.json
+++ b/apps/user_ldap/l10n/mk.json
@@ -1,4 +1,5 @@
{ "translations": {
+ "Select groups" : "Одбери групи",
"Confirm Deletion" : "Потврдете го бришењето",
"Users" : "Корисници",
"Groups" : "Групи",
diff --git a/apps/user_ldap/l10n/nb_NO.js b/apps/user_ldap/l10n/nb_NO.js
index 8770dfa0841..62fadd9365e 100644
--- a/apps/user_ldap/l10n/nb_NO.js
+++ b/apps/user_ldap/l10n/nb_NO.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "Klarte ikke å påvise basis-DN. Det må skrives inn manuelt.",
"{nthServer}. Server" : "{nthServer}. server",
"No object found in the given Base DN. Please revise." : "Intet objekt funnet i angitt basis-DN. Revider oppsettet.",
+ "More than 1,000 directory entries available." : "Mer enn 1.000 katalogoppføringer tilgjengelig.",
" entries available within the provided Base DN" : "oppføringer tilgjengelig innenfor angitt basis-DN",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Det oppstod en feil. Sjekk basis-DN, tilkoblingsoppsett og påloggingsdetaljer.",
"Do you really want to delete the current Server Configuration?" : "Er du sikker på at du vil slette aktiv tjener-konfigurasjon?",
diff --git a/apps/user_ldap/l10n/nb_NO.json b/apps/user_ldap/l10n/nb_NO.json
index 9cc0e4964dd..ee049b8a50f 100644
--- a/apps/user_ldap/l10n/nb_NO.json
+++ b/apps/user_ldap/l10n/nb_NO.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "Klarte ikke å påvise basis-DN. Det må skrives inn manuelt.",
"{nthServer}. Server" : "{nthServer}. server",
"No object found in the given Base DN. Please revise." : "Intet objekt funnet i angitt basis-DN. Revider oppsettet.",
+ "More than 1,000 directory entries available." : "Mer enn 1.000 katalogoppføringer tilgjengelig.",
" entries available within the provided Base DN" : "oppføringer tilgjengelig innenfor angitt basis-DN",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Det oppstod en feil. Sjekk basis-DN, tilkoblingsoppsett og påloggingsdetaljer.",
"Do you really want to delete the current Server Configuration?" : "Er du sikker på at du vil slette aktiv tjener-konfigurasjon?",
diff --git a/apps/user_ldap/l10n/oc.js b/apps/user_ldap/l10n/oc.js
index 97ad04c7ec4..77cb592e402 100644
--- a/apps/user_ldap/l10n/oc.js
+++ b/apps/user_ldap/l10n/oc.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "Impossible de detectar lo DN de basa, especificatz-lo manualament",
"{nthServer}. Server" : "{nthServer}. Servidor",
"No object found in the given Base DN. Please revise." : "Cap d'objècte pas trobat dins lo DN de basa especificat. Verificatz-lo.",
+ "More than 1,000 directory entries available." : "I a mai de 1000 entradas de repertòri disponiblas.",
" entries available within the provided Base DN" : "entradas disponiblas dins lo DN de basa especificat",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Una error s'es produsida. Verificatz lo DN de basa, e tanben los paramètres de connexion e las informacions d'identificacion.",
"Do you really want to delete the current Server Configuration?" : "Sètz segur que volètz escafar la configuracion servidor actuala ?",
diff --git a/apps/user_ldap/l10n/oc.json b/apps/user_ldap/l10n/oc.json
index 8db8ef6297f..aa8d2b41861 100644
--- a/apps/user_ldap/l10n/oc.json
+++ b/apps/user_ldap/l10n/oc.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "Impossible de detectar lo DN de basa, especificatz-lo manualament",
"{nthServer}. Server" : "{nthServer}. Servidor",
"No object found in the given Base DN. Please revise." : "Cap d'objècte pas trobat dins lo DN de basa especificat. Verificatz-lo.",
+ "More than 1,000 directory entries available." : "I a mai de 1000 entradas de repertòri disponiblas.",
" entries available within the provided Base DN" : "entradas disponiblas dins lo DN de basa especificat",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Una error s'es produsida. Verificatz lo DN de basa, e tanben los paramètres de connexion e las informacions d'identificacion.",
"Do you really want to delete the current Server Configuration?" : "Sètz segur que volètz escafar la configuracion servidor actuala ?",
diff --git a/apps/user_ldap/l10n/pt_PT.js b/apps/user_ldap/l10n/pt_PT.js
index 3863326e6c3..d6bd1d9d515 100644
--- a/apps/user_ldap/l10n/pt_PT.js
+++ b/apps/user_ldap/l10n/pt_PT.js
@@ -5,8 +5,8 @@ OC.L10N.register(
"Failed to delete the server configuration" : "Erro ao eliminar a configuração do servidor",
"The configuration is invalid: anonymous bind is not allowed." : "A configuração é inválida: ligação anónima não é permitida.",
"The configuration is valid and the connection could be established!" : "A configuração está correcta e foi possível estabelecer a ligação!",
- "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "A configuração está correcta, mas não foi possível estabelecer o \"laço\", por favor, verifique as configurações do servidor e as credenciais.",
- "The configuration is invalid. Please have a look at the logs for further details." : "A configuração é inválida. Por favor, veja o log do ownCloud para mais detalhes.",
+ "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "A configuração está correcta, mas não foi possível estabelecer a conexão. Por favor, verifique as configurações do servidor e as credenciais.",
+ "The configuration is invalid. Please have a look at the logs for further details." : "A configuração é inválida. Por favor, veja o registo (log) do ownCloud para mais detalhes.",
"No action specified" : "Nenhuma acção especificada",
"No configuration specified" : "Nenhuma configuração especificada",
"No data specified" : "Nenhuma data especificada",
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "Não foi possível detetar o ND de base, por favor introduza-o manualmente.",
"{nthServer}. Server" : "{nthServer}. Servidor",
"No object found in the given Base DN. Please revise." : "Nenhum objecto encontrado na Base DN fornecida. Por favor verifique.",
+ "More than 1,000 directory entries available." : "Mais de 1,000 entradas de diretório disponíveis.",
" entries available within the provided Base DN" : "entradas disponíveis no ND de base fornecido",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Ocorreu um erro. Por favor verifique o ND de base, bem como as definições de ligação e as credenciais.",
"Do you really want to delete the current Server Configuration?" : "Deseja realmente apagar as configurações de servidor actuais?",
@@ -36,9 +37,15 @@ OC.L10N.register(
"Switching the mode will enable automatic LDAP queries. Depending on your LDAP size they may take a while. Do you still want to switch the mode?" : "Trocando o modo vai permitir a busca automática no LDAP. Dependendo do tamanho do seu LDAP poderá demorar um pouco. Ainda pretende trocar o modo?",
"Mode switch" : "Trocar de modo",
"Select attributes" : "Selecionar atributos",
+ "User not found. Please check your login attributes and username. Effective filter (to copy-and-paste for command line validation): <br/>" : "O utilizador não foi encontrado. Por favor, verifique nome de utilizador e os atributos de permissão. Filtro eficaz (para copiar/colar na linha de comando de validação): <br/>",
"User found and settings verified." : "Utilizador encontrado e as definilções verificadas",
+ "Settings verified, but one user found. Only the first will be able to login. Consider a more narrow filter." : "Definições verificadas, com problemas. Somente o primeiro utilizador encontrado poderá entrar no sistema. Considere criar um filtro mais expecífico.",
"An unspecified error occurred. Please check the settings and the log." : "ocorreu um erro não especificado. Por favor, verifique as configurações e o registo.",
+ "The search filter is invalid, probably due to syntax issues like uneven number of opened and closed brackets. Please revise." : "O filtro de procura é inválido, provavelmente devido a problemas de sintaxe. Verifique se existem números ímpares de parêntisis abertos e/ou fechados. Por favor reveja.",
+ "A connection error to LDAP / AD occurred, please check host, port and credentials." : "Ocorreu um erro de conexão ao servidor LDAP / AD. Por favor, reveja as definições de endereço, porto e credenciais.",
+ "The %uid placeholder is missing. It will be replaced with the login name when querying LDAP / AD." : "O campo %uid está em falta. Este será substituído pelo utilizador do ownCloud quando for efectuado o pedido ao LDAP / AD.",
"Please provide a login name to test against" : "Por favor, indique um nome de sessão para testar",
+ "The group box was disabled, because the LDAP / AD server does not support memberOf." : "Uma vez que o servidor LDAP / AD não suporta a propriedade \"memberOf\" (grupos) a caixa de grupos foi desactivada.",
"_%s group found_::_%s groups found_" : ["%s grupo encontrado","%s grupos encontrados"],
"_%s user found_::_%s users found_" : ["%s utilizador encontrado","%s utilizadores encontrados"],
"Could not detect user display name attribute. Please specify it yourself in advanced ldap settings." : "Não foi possível detetar o atributo do nome do utilizador. Por favor especifique-o nas configurações ldap avançadas.",
@@ -56,16 +63,23 @@ OC.L10N.register(
"Search groups" : "Procurar grupos",
"Available groups" : "Grupos disponiveis",
"Selected groups" : "Grupos seleccionados",
+ "Edit LDAP Query" : "Modificar pedido LDAP",
"LDAP Filter:" : "Filtro LDAP:",
"The filter specifies which LDAP groups shall have access to the %s instance." : "O filtro especifica quais grupos LDAP devem ter acesso à instância %s.",
+ "Verify settings and count groups" : "Verificar condições e contar grupos",
+ "When logging in, %s will find the user based on the following attributes:" : "Quando entrar no sistema, %s irá encontrar o utilizador baseando-se nos seguintes atributos:",
"LDAP / AD Username:" : "Nome de Utilizador LDAP / AD:",
+ "Allows login against the LDAP / AD username, which is either uid or samaccountname and will be detected." : "Permitir entrar no sistema com verificação LDAP / AD, do qual o utilizador poderá ser detectado a partir do \"uid\" ou \"samaccountname\".",
"LDAP / AD Email Address:" : "Endereço de Correio Eletrónico LDPA / AD",
+ "Allows login against an email attribute. Mail and mailPrimaryAddress will be allowed." : "Permtir entrar no sistema a partir do atributo \"email\". Neste caso os campos \"Mail\" e \"mailPrimaryAddress\" serão utilizados para verificação.",
"Other Attributes:" : "Outros Atributos:",
"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "Define o filtro a aplicar, quando se tenta uma sessão. %%uid substitui o nome de utilizador na ação de início de sessão. Exemplo: \"uid=%%uid\"",
+ "Test Loginname" : "Testar nome de login",
"Verify settings" : "Verificar definições",
"1. Server" : "1. Servidor",
"%s. Server:" : "%s. Servvidor",
"Add a new and blank configuration" : "Adicione uma nova configuração em branco",
+ "Copy current configuration into new directory binding" : "Copiar a configuração actual para um novo registo de conexão",
"Delete the current configuration" : "Apagar a configuração actual",
"Host" : "Anfitrião",
"You can omit the protocol, except you require SSL. Then start with ldaps://" : "Pode omitir o protocolo, excepto se necessitar de SSL. Neste caso, comece com ldaps://",
@@ -75,13 +89,14 @@ OC.L10N.register(
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "O DN to cliente ",
"Password" : "Password",
"For anonymous access, leave DN and Password empty." : "Para acesso anónimo, deixe DN e a Palavra-passe vazios.",
- "One Base DN per line" : "Uma base DN por linho",
+ "One Base DN per line" : "Uma base DN por linha",
"You can specify Base DN for users and groups in the Advanced tab" : "Pode especificar o ND Base para utilizadores e grupos no separador Avançado",
"Detect Base DN" : "Detectar Base DN",
"Test Base DN" : "Testar Base DN",
"Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "Evita pedidos LDAP automáticos. Melhor para grandes configurações, mas requer conhecimentos LDAP.",
"Manually enter LDAP filters (recommended for large directories)" : "Introduzir filtros LDAP manualmente (recomendado para directórios grandes)",
"Limit %s access to users meeting these criteria:" : "Limitar o acesso a %s de utilizadores com estes critérios:",
+ "The most common object classes for users are organizationalPerson, person, user, and inetOrgPerson. If you are not sure which object class to select, please consult your directory admin." : "Os objectos mais comuns para utilizadores são <em>organizationalPerson, person, user, and inetOrgPerson</em>. Se não tem a certeza de que classe de objecto deverá seleccionar, por favor, contacte o administrador do Directório.",
"The filter specifies which LDAP users shall have access to the %s instance." : "O filtro especifica quais utilizadores do LDAP devem ter acesso à instância %s.",
"Verify settings and count users" : "Verificar definições e contar utilizadores",
"Saving" : "Guardando",
diff --git a/apps/user_ldap/l10n/pt_PT.json b/apps/user_ldap/l10n/pt_PT.json
index 729674e0b2c..8073db3efa6 100644
--- a/apps/user_ldap/l10n/pt_PT.json
+++ b/apps/user_ldap/l10n/pt_PT.json
@@ -3,8 +3,8 @@
"Failed to delete the server configuration" : "Erro ao eliminar a configuração do servidor",
"The configuration is invalid: anonymous bind is not allowed." : "A configuração é inválida: ligação anónima não é permitida.",
"The configuration is valid and the connection could be established!" : "A configuração está correcta e foi possível estabelecer a ligação!",
- "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "A configuração está correcta, mas não foi possível estabelecer o \"laço\", por favor, verifique as configurações do servidor e as credenciais.",
- "The configuration is invalid. Please have a look at the logs for further details." : "A configuração é inválida. Por favor, veja o log do ownCloud para mais detalhes.",
+ "The configuration is valid, but the Bind failed. Please check the server settings and credentials." : "A configuração está correcta, mas não foi possível estabelecer a conexão. Por favor, verifique as configurações do servidor e as credenciais.",
+ "The configuration is invalid. Please have a look at the logs for further details." : "A configuração é inválida. Por favor, veja o registo (log) do ownCloud para mais detalhes.",
"No action specified" : "Nenhuma acção especificada",
"No configuration specified" : "Nenhuma configuração especificada",
"No data specified" : "Nenhuma data especificada",
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "Não foi possível detetar o ND de base, por favor introduza-o manualmente.",
"{nthServer}. Server" : "{nthServer}. Servidor",
"No object found in the given Base DN. Please revise." : "Nenhum objecto encontrado na Base DN fornecida. Por favor verifique.",
+ "More than 1,000 directory entries available." : "Mais de 1,000 entradas de diretório disponíveis.",
" entries available within the provided Base DN" : "entradas disponíveis no ND de base fornecido",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Ocorreu um erro. Por favor verifique o ND de base, bem como as definições de ligação e as credenciais.",
"Do you really want to delete the current Server Configuration?" : "Deseja realmente apagar as configurações de servidor actuais?",
@@ -34,9 +35,15 @@
"Switching the mode will enable automatic LDAP queries. Depending on your LDAP size they may take a while. Do you still want to switch the mode?" : "Trocando o modo vai permitir a busca automática no LDAP. Dependendo do tamanho do seu LDAP poderá demorar um pouco. Ainda pretende trocar o modo?",
"Mode switch" : "Trocar de modo",
"Select attributes" : "Selecionar atributos",
+ "User not found. Please check your login attributes and username. Effective filter (to copy-and-paste for command line validation): <br/>" : "O utilizador não foi encontrado. Por favor, verifique nome de utilizador e os atributos de permissão. Filtro eficaz (para copiar/colar na linha de comando de validação): <br/>",
"User found and settings verified." : "Utilizador encontrado e as definilções verificadas",
+ "Settings verified, but one user found. Only the first will be able to login. Consider a more narrow filter." : "Definições verificadas, com problemas. Somente o primeiro utilizador encontrado poderá entrar no sistema. Considere criar um filtro mais expecífico.",
"An unspecified error occurred. Please check the settings and the log." : "ocorreu um erro não especificado. Por favor, verifique as configurações e o registo.",
+ "The search filter is invalid, probably due to syntax issues like uneven number of opened and closed brackets. Please revise." : "O filtro de procura é inválido, provavelmente devido a problemas de sintaxe. Verifique se existem números ímpares de parêntisis abertos e/ou fechados. Por favor reveja.",
+ "A connection error to LDAP / AD occurred, please check host, port and credentials." : "Ocorreu um erro de conexão ao servidor LDAP / AD. Por favor, reveja as definições de endereço, porto e credenciais.",
+ "The %uid placeholder is missing. It will be replaced with the login name when querying LDAP / AD." : "O campo %uid está em falta. Este será substituído pelo utilizador do ownCloud quando for efectuado o pedido ao LDAP / AD.",
"Please provide a login name to test against" : "Por favor, indique um nome de sessão para testar",
+ "The group box was disabled, because the LDAP / AD server does not support memberOf." : "Uma vez que o servidor LDAP / AD não suporta a propriedade \"memberOf\" (grupos) a caixa de grupos foi desactivada.",
"_%s group found_::_%s groups found_" : ["%s grupo encontrado","%s grupos encontrados"],
"_%s user found_::_%s users found_" : ["%s utilizador encontrado","%s utilizadores encontrados"],
"Could not detect user display name attribute. Please specify it yourself in advanced ldap settings." : "Não foi possível detetar o atributo do nome do utilizador. Por favor especifique-o nas configurações ldap avançadas.",
@@ -54,16 +61,23 @@
"Search groups" : "Procurar grupos",
"Available groups" : "Grupos disponiveis",
"Selected groups" : "Grupos seleccionados",
+ "Edit LDAP Query" : "Modificar pedido LDAP",
"LDAP Filter:" : "Filtro LDAP:",
"The filter specifies which LDAP groups shall have access to the %s instance." : "O filtro especifica quais grupos LDAP devem ter acesso à instância %s.",
+ "Verify settings and count groups" : "Verificar condições e contar grupos",
+ "When logging in, %s will find the user based on the following attributes:" : "Quando entrar no sistema, %s irá encontrar o utilizador baseando-se nos seguintes atributos:",
"LDAP / AD Username:" : "Nome de Utilizador LDAP / AD:",
+ "Allows login against the LDAP / AD username, which is either uid or samaccountname and will be detected." : "Permitir entrar no sistema com verificação LDAP / AD, do qual o utilizador poderá ser detectado a partir do \"uid\" ou \"samaccountname\".",
"LDAP / AD Email Address:" : "Endereço de Correio Eletrónico LDPA / AD",
+ "Allows login against an email attribute. Mail and mailPrimaryAddress will be allowed." : "Permtir entrar no sistema a partir do atributo \"email\". Neste caso os campos \"Mail\" e \"mailPrimaryAddress\" serão utilizados para verificação.",
"Other Attributes:" : "Outros Atributos:",
"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "Define o filtro a aplicar, quando se tenta uma sessão. %%uid substitui o nome de utilizador na ação de início de sessão. Exemplo: \"uid=%%uid\"",
+ "Test Loginname" : "Testar nome de login",
"Verify settings" : "Verificar definições",
"1. Server" : "1. Servidor",
"%s. Server:" : "%s. Servvidor",
"Add a new and blank configuration" : "Adicione uma nova configuração em branco",
+ "Copy current configuration into new directory binding" : "Copiar a configuração actual para um novo registo de conexão",
"Delete the current configuration" : "Apagar a configuração actual",
"Host" : "Anfitrião",
"You can omit the protocol, except you require SSL. Then start with ldaps://" : "Pode omitir o protocolo, excepto se necessitar de SSL. Neste caso, comece com ldaps://",
@@ -73,13 +87,14 @@
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "O DN to cliente ",
"Password" : "Password",
"For anonymous access, leave DN and Password empty." : "Para acesso anónimo, deixe DN e a Palavra-passe vazios.",
- "One Base DN per line" : "Uma base DN por linho",
+ "One Base DN per line" : "Uma base DN por linha",
"You can specify Base DN for users and groups in the Advanced tab" : "Pode especificar o ND Base para utilizadores e grupos no separador Avançado",
"Detect Base DN" : "Detectar Base DN",
"Test Base DN" : "Testar Base DN",
"Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "Evita pedidos LDAP automáticos. Melhor para grandes configurações, mas requer conhecimentos LDAP.",
"Manually enter LDAP filters (recommended for large directories)" : "Introduzir filtros LDAP manualmente (recomendado para directórios grandes)",
"Limit %s access to users meeting these criteria:" : "Limitar o acesso a %s de utilizadores com estes critérios:",
+ "The most common object classes for users are organizationalPerson, person, user, and inetOrgPerson. If you are not sure which object class to select, please consult your directory admin." : "Os objectos mais comuns para utilizadores são <em>organizationalPerson, person, user, and inetOrgPerson</em>. Se não tem a certeza de que classe de objecto deverá seleccionar, por favor, contacte o administrador do Directório.",
"The filter specifies which LDAP users shall have access to the %s instance." : "O filtro especifica quais utilizadores do LDAP devem ter acesso à instância %s.",
"Verify settings and count users" : "Verificar definições e contar utilizadores",
"Saving" : "Guardando",
diff --git a/apps/user_ldap/l10n/ru.js b/apps/user_ldap/l10n/ru.js
index 40705449edf..08069e28fd9 100644
--- a/apps/user_ldap/l10n/ru.js
+++ b/apps/user_ldap/l10n/ru.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "Не возможно обнаружить Base DN, пожалуйста задайте в ручную.",
"{nthServer}. Server" : "Сервер {nthServer}.",
"No object found in the given Base DN. Please revise." : "Не найдено объектов в Base DN. Пожалуйста перепроверьте.",
+ "More than 1,000 directory entries available." : "В каталоге доступно более 1,000 записей.",
" entries available within the provided Base DN" : "элементы доступные в Базе",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Произошла ошибка. Пожалуйста проверьте базу поиска DN, а также настройки подключения и учетные данные.",
"Do you really want to delete the current Server Configuration?" : "Вы действительно хотите удалить существующую конфигурацию сервера?",
diff --git a/apps/user_ldap/l10n/ru.json b/apps/user_ldap/l10n/ru.json
index 4a6f9ea52d0..126e78593d1 100644
--- a/apps/user_ldap/l10n/ru.json
+++ b/apps/user_ldap/l10n/ru.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "Не возможно обнаружить Base DN, пожалуйста задайте в ручную.",
"{nthServer}. Server" : "Сервер {nthServer}.",
"No object found in the given Base DN. Please revise." : "Не найдено объектов в Base DN. Пожалуйста перепроверьте.",
+ "More than 1,000 directory entries available." : "В каталоге доступно более 1,000 записей.",
" entries available within the provided Base DN" : "элементы доступные в Базе",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Произошла ошибка. Пожалуйста проверьте базу поиска DN, а также настройки подключения и учетные данные.",
"Do you really want to delete the current Server Configuration?" : "Вы действительно хотите удалить существующую конфигурацию сервера?",
diff --git a/apps/user_ldap/l10n/sl.js b/apps/user_ldap/l10n/sl.js
index d3712c273f0..8444f09fed2 100644
--- a/apps/user_ldap/l10n/sl.js
+++ b/apps/user_ldap/l10n/sl.js
@@ -21,7 +21,7 @@ OC.L10N.register(
"Confirm Deletion" : "Potrdi brisanje",
"Mode switch" : "Preklop načina",
"Select attributes" : "Izbor atributov",
- "User found and settings verified." : "Uporabnik najden in nastavitve preverjene.",
+ "User found and settings verified." : "Uporabnik je najden in nastavitve so overjene.",
"_%s group found_::_%s groups found_" : ["%s najdena skupina","%s najdeni skupini","%s najdene skupine","%s najdenih skupin"],
"_%s user found_::_%s users found_" : ["%s najden uporabnik","%s najdena uporabnika","%s najdeni uporabniki","%s najdenih uporabnikov"],
"Could not detect user display name attribute. Please specify it yourself in advanced ldap settings." : "Ni mogoče prebrati atributa prikaznega imena. Določiti ga je treba ročno med nastavitvami LDAP.",
@@ -34,11 +34,12 @@ OC.L10N.register(
"Test Configuration" : "Preizkusne nastavitve",
"Help" : "Pomoč",
"Groups meeting these criteria are available in %s:" : "Skupine, ki so skladne s kriterijem, so na voljo v %s:",
- "Only these object classes:" : "Samo tej razredi objektov:",
- "Only from these groups:" : "Samo te skupine:",
- "Search groups" : "Skupine za iskanje",
- "Available groups" : "Razpoložljive skupine",
+ "Only these object classes:" : "Le ti razredi predmetov:",
+ "Only from these groups:" : "Le od skupin:",
+ "Search groups" : "Iskanje skupin",
+ "Available groups" : "Skupine na voljo",
"Selected groups" : "Izbrane skupine",
+ "Edit LDAP Query" : "Uredi poizvedbo LDAP",
"LDAP Filter:" : "Filter LDAP:",
"The filter specifies which LDAP groups shall have access to the %s instance." : "Filter določa, katere skupine LDAP bodo imele dostop do %s.",
"Other Attributes:" : "Drugi atributi:",
diff --git a/apps/user_ldap/l10n/sl.json b/apps/user_ldap/l10n/sl.json
index 14e73e628a0..8dbb7111a32 100644
--- a/apps/user_ldap/l10n/sl.json
+++ b/apps/user_ldap/l10n/sl.json
@@ -19,7 +19,7 @@
"Confirm Deletion" : "Potrdi brisanje",
"Mode switch" : "Preklop načina",
"Select attributes" : "Izbor atributov",
- "User found and settings verified." : "Uporabnik najden in nastavitve preverjene.",
+ "User found and settings verified." : "Uporabnik je najden in nastavitve so overjene.",
"_%s group found_::_%s groups found_" : ["%s najdena skupina","%s najdeni skupini","%s najdene skupine","%s najdenih skupin"],
"_%s user found_::_%s users found_" : ["%s najden uporabnik","%s najdena uporabnika","%s najdeni uporabniki","%s najdenih uporabnikov"],
"Could not detect user display name attribute. Please specify it yourself in advanced ldap settings." : "Ni mogoče prebrati atributa prikaznega imena. Določiti ga je treba ročno med nastavitvami LDAP.",
@@ -32,11 +32,12 @@
"Test Configuration" : "Preizkusne nastavitve",
"Help" : "Pomoč",
"Groups meeting these criteria are available in %s:" : "Skupine, ki so skladne s kriterijem, so na voljo v %s:",
- "Only these object classes:" : "Samo tej razredi objektov:",
- "Only from these groups:" : "Samo te skupine:",
- "Search groups" : "Skupine za iskanje",
- "Available groups" : "Razpoložljive skupine",
+ "Only these object classes:" : "Le ti razredi predmetov:",
+ "Only from these groups:" : "Le od skupin:",
+ "Search groups" : "Iskanje skupin",
+ "Available groups" : "Skupine na voljo",
"Selected groups" : "Izbrane skupine",
+ "Edit LDAP Query" : "Uredi poizvedbo LDAP",
"LDAP Filter:" : "Filter LDAP:",
"The filter specifies which LDAP groups shall have access to the %s instance." : "Filter določa, katere skupine LDAP bodo imele dostop do %s.",
"Other Attributes:" : "Drugi atributi:",
diff --git a/apps/user_ldap/l10n/sq.js b/apps/user_ldap/l10n/sq.js
index 4f0d1d3697c..aaebf07862d 100644
--- a/apps/user_ldap/l10n/sq.js
+++ b/apps/user_ldap/l10n/sq.js
@@ -81,7 +81,7 @@ OC.L10N.register(
"Add a new and blank configuration" : "Shtoni një formësim të ri të zbrazët",
"Copy current configuration into new directory binding" : "Kopjojeni formësimin e tanishëm te një lidhmë e re drejtorie",
"Delete the current configuration" : "Fshije formësimin e tanishëm",
- "Host" : "Pritësi",
+ "Host" : "Strehë",
"You can omit the protocol, except you require SSL. Then start with ldaps://" : "Protokollin mund ta lini pa vënë, hiq rastin kur ju duhet SSL. Në atë rast filloni me ldaps://",
"Port" : "Portë",
"Detect Port" : "Zbulo Portë",
@@ -96,7 +96,7 @@ OC.L10N.register(
"Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "Shmang kërkesa LDAP automatike. Më e përshtatshme për instalime më të mëdha, por lyp ca dije rreth LDAP-it.",
"Manually enter LDAP filters (recommended for large directories)" : "Jepni filtra LDAP dorazi (e këshilluar për drejtori të mëdha)",
"Limit %s access to users meeting these criteria:" : "Kufizo hyrje %s vetëm për përdorues që plotësojnë këtë kusht:",
- "The most common object classes for users are organizationalPerson, person, user, and inetOrgPerson. If you are not sure which object class to select, please consult your directory admin." : "Klasat më të rëndomta objektesht për përdoruesit janë organizationalPerson, person, user, dhe inetOrgPerson. Nëse s’jeni i sigurt cilën klasë objekti të përzgjidhniI, ju lutemi, lidhuni me përgjegjësin e drejtorisë suaj.",
+ "The most common object classes for users are organizationalPerson, person, user, and inetOrgPerson. If you are not sure which object class to select, please consult your directory admin." : "Klasat më të rëndomta objektesh për përdoruesit janë organizationalPerson, person, user, dhe inetOrgPerson. Nëse s’jeni i sigurt cilën klasë objekti të përzgjidhni, ju lutemi, lidhuni me përgjegjësin e drejtorisë suaj.",
"The filter specifies which LDAP users shall have access to the %s instance." : "Filtri përcakton se cilët përdorues LDAP do të kenë hyrje te instanca %s.",
"Verify settings and count users" : "Verifiko rregullimet dhe numëro përdoruesit",
"Saving" : "Po ruhet",
@@ -122,16 +122,16 @@ OC.L10N.register(
"Directory Settings" : "Rregullime Drejtorie",
"User Display Name Field" : "Fushë Emri Përdoruesi Në Ekran",
"The LDAP attribute to use to generate the user's display name." : "Atribut LDAP që përdoret për të prodhuar emër ekrani për përdoruesin.",
- "Base User Tree" : "Struktura bazë e përdoruesit",
+ "Base User Tree" : "Strukturë Bazë Përdoruesi",
"One User Base DN per line" : "Një DN Bazë Përdoruesi për rresht",
- "User Search Attributes" : "Atributet e kërkimit të përdoruesëve",
+ "User Search Attributes" : "Atribute Kërkimesh Nga Përdoruesi",
"Optional; one attribute per line" : "Opsionale; një atribut për rresht",
"Group Display Name Field" : "Fushë Emri Grupi Në Ekran",
"The LDAP attribute to use to generate the groups's display name." : "Atribut LDAP që përdoret për të prodhuar emër ekrani për grupin.",
- "Base Group Tree" : "Struktura bazë e grupit",
+ "Base Group Tree" : "Strukturë Bazë Grupi",
"One Group Base DN per line" : "Një DN Bazë Grupi për rresht",
"Group Search Attributes" : "Atribute Kërkimi Grupi",
- "Group-Member association" : "Pjestar Grup-Përdorues ",
+ "Group-Member association" : "Përshoqërim Grup-Përdorues",
"Nested Groups" : "Grupe Brenda Njëri-Tjetrit",
"When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" : "Kur aktivizohet, grupet që përmbajnë grupe mbulohen. (Funksionon vetëm nëse atributi për anëtar grupi përmban DN-ra.)",
"Special Attributes" : "Atribute Speciale",
diff --git a/apps/user_ldap/l10n/sq.json b/apps/user_ldap/l10n/sq.json
index 6045b61f57d..335a42630b5 100644
--- a/apps/user_ldap/l10n/sq.json
+++ b/apps/user_ldap/l10n/sq.json
@@ -79,7 +79,7 @@
"Add a new and blank configuration" : "Shtoni një formësim të ri të zbrazët",
"Copy current configuration into new directory binding" : "Kopjojeni formësimin e tanishëm te një lidhmë e re drejtorie",
"Delete the current configuration" : "Fshije formësimin e tanishëm",
- "Host" : "Pritësi",
+ "Host" : "Strehë",
"You can omit the protocol, except you require SSL. Then start with ldaps://" : "Protokollin mund ta lini pa vënë, hiq rastin kur ju duhet SSL. Në atë rast filloni me ldaps://",
"Port" : "Portë",
"Detect Port" : "Zbulo Portë",
@@ -94,7 +94,7 @@
"Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge." : "Shmang kërkesa LDAP automatike. Më e përshtatshme për instalime më të mëdha, por lyp ca dije rreth LDAP-it.",
"Manually enter LDAP filters (recommended for large directories)" : "Jepni filtra LDAP dorazi (e këshilluar për drejtori të mëdha)",
"Limit %s access to users meeting these criteria:" : "Kufizo hyrje %s vetëm për përdorues që plotësojnë këtë kusht:",
- "The most common object classes for users are organizationalPerson, person, user, and inetOrgPerson. If you are not sure which object class to select, please consult your directory admin." : "Klasat më të rëndomta objektesht për përdoruesit janë organizationalPerson, person, user, dhe inetOrgPerson. Nëse s’jeni i sigurt cilën klasë objekti të përzgjidhniI, ju lutemi, lidhuni me përgjegjësin e drejtorisë suaj.",
+ "The most common object classes for users are organizationalPerson, person, user, and inetOrgPerson. If you are not sure which object class to select, please consult your directory admin." : "Klasat më të rëndomta objektesh për përdoruesit janë organizationalPerson, person, user, dhe inetOrgPerson. Nëse s’jeni i sigurt cilën klasë objekti të përzgjidhni, ju lutemi, lidhuni me përgjegjësin e drejtorisë suaj.",
"The filter specifies which LDAP users shall have access to the %s instance." : "Filtri përcakton se cilët përdorues LDAP do të kenë hyrje te instanca %s.",
"Verify settings and count users" : "Verifiko rregullimet dhe numëro përdoruesit",
"Saving" : "Po ruhet",
@@ -120,16 +120,16 @@
"Directory Settings" : "Rregullime Drejtorie",
"User Display Name Field" : "Fushë Emri Përdoruesi Në Ekran",
"The LDAP attribute to use to generate the user's display name." : "Atribut LDAP që përdoret për të prodhuar emër ekrani për përdoruesin.",
- "Base User Tree" : "Struktura bazë e përdoruesit",
+ "Base User Tree" : "Strukturë Bazë Përdoruesi",
"One User Base DN per line" : "Një DN Bazë Përdoruesi për rresht",
- "User Search Attributes" : "Atributet e kërkimit të përdoruesëve",
+ "User Search Attributes" : "Atribute Kërkimesh Nga Përdoruesi",
"Optional; one attribute per line" : "Opsionale; një atribut për rresht",
"Group Display Name Field" : "Fushë Emri Grupi Në Ekran",
"The LDAP attribute to use to generate the groups's display name." : "Atribut LDAP që përdoret për të prodhuar emër ekrani për grupin.",
- "Base Group Tree" : "Struktura bazë e grupit",
+ "Base Group Tree" : "Strukturë Bazë Grupi",
"One Group Base DN per line" : "Një DN Bazë Grupi për rresht",
"Group Search Attributes" : "Atribute Kërkimi Grupi",
- "Group-Member association" : "Pjestar Grup-Përdorues ",
+ "Group-Member association" : "Përshoqërim Grup-Përdorues",
"Nested Groups" : "Grupe Brenda Njëri-Tjetrit",
"When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" : "Kur aktivizohet, grupet që përmbajnë grupe mbulohen. (Funksionon vetëm nëse atributi për anëtar grupi përmban DN-ra.)",
"Special Attributes" : "Atribute Speciale",
diff --git a/apps/user_ldap/l10n/sr.js b/apps/user_ldap/l10n/sr.js
index 1ccfefcb7a8..eb3ee924b7a 100644
--- a/apps/user_ldap/l10n/sr.js
+++ b/apps/user_ldap/l10n/sr.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "Не могу да откријем базни ДН. Унесите га ручно.",
"{nthServer}. Server" : "{nthServer}. Сервер",
"No object found in the given Base DN. Please revise." : "Нема објекта за дати базни ДН. Проверите.",
+ "More than 1,000 directory entries available." : "Више од 1000 уноса је доступно.",
" entries available within the provided Base DN" : "уноса доступно за дати базни ДН",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Грешка. Проверите базни ДН као и поставке везе и акредитиве.",
"Do you really want to delete the current Server Configuration?" : "Да ли стварно желите да обришете тренутну конфигурацију сервера?",
diff --git a/apps/user_ldap/l10n/sr.json b/apps/user_ldap/l10n/sr.json
index 658edafc77b..233df2f4e34 100644
--- a/apps/user_ldap/l10n/sr.json
+++ b/apps/user_ldap/l10n/sr.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "Не могу да откријем базни ДН. Унесите га ручно.",
"{nthServer}. Server" : "{nthServer}. Сервер",
"No object found in the given Base DN. Please revise." : "Нема објекта за дати базни ДН. Проверите.",
+ "More than 1,000 directory entries available." : "Више од 1000 уноса је доступно.",
" entries available within the provided Base DN" : "уноса доступно за дати базни ДН",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Грешка. Проверите базни ДН као и поставке везе и акредитиве.",
"Do you really want to delete the current Server Configuration?" : "Да ли стварно желите да обришете тренутну конфигурацију сервера?",
diff --git a/apps/user_ldap/l10n/th_TH.js b/apps/user_ldap/l10n/th_TH.js
index c848d137464..8b155dcfe23 100644
--- a/apps/user_ldap/l10n/th_TH.js
+++ b/apps/user_ldap/l10n/th_TH.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "ไม่สามารถตรวจสอบ Base DN โปรดเลือกด้วยตนเอง",
"{nthServer}. Server" : "เซิร์ฟเวอร์ {nthServer}",
"No object found in the given Base DN. Please revise." : "ไม่พบวัตถุที่กำหนดใน Base DN กรุณาแก้ไข",
+ "More than 1,000 directory entries available." : "ไดเรกทอรีมีอยู่มากกว่า 1,000 รายการ",
" entries available within the provided Base DN" : "รายการที่มีอยู่ใน Base DN",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "เกิดข้อผิดพลาด กรุณาตรวจสอบ Base DN เช่นเดียวกับการตั้งค่าการเชื่อมต่อและข้อมูลที่สำคัญ",
"Do you really want to delete the current Server Configuration?" : "คุณแน่ใจแล้วหรือว่าต้องการลบการกำหนดค่าเซิร์ฟเวอร์ปัจจุบันทิ้งไป?",
diff --git a/apps/user_ldap/l10n/th_TH.json b/apps/user_ldap/l10n/th_TH.json
index 6afa6f2bbc4..9787ba10037 100644
--- a/apps/user_ldap/l10n/th_TH.json
+++ b/apps/user_ldap/l10n/th_TH.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "ไม่สามารถตรวจสอบ Base DN โปรดเลือกด้วยตนเอง",
"{nthServer}. Server" : "เซิร์ฟเวอร์ {nthServer}",
"No object found in the given Base DN. Please revise." : "ไม่พบวัตถุที่กำหนดใน Base DN กรุณาแก้ไข",
+ "More than 1,000 directory entries available." : "ไดเรกทอรีมีอยู่มากกว่า 1,000 รายการ",
" entries available within the provided Base DN" : "รายการที่มีอยู่ใน Base DN",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "เกิดข้อผิดพลาด กรุณาตรวจสอบ Base DN เช่นเดียวกับการตั้งค่าการเชื่อมต่อและข้อมูลที่สำคัญ",
"Do you really want to delete the current Server Configuration?" : "คุณแน่ใจแล้วหรือว่าต้องการลบการกำหนดค่าเซิร์ฟเวอร์ปัจจุบันทิ้งไป?",
diff --git a/apps/user_ldap/l10n/tr.js b/apps/user_ldap/l10n/tr.js
index cbe95a194c5..48677918ed8 100644
--- a/apps/user_ldap/l10n/tr.js
+++ b/apps/user_ldap/l10n/tr.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "Base DN tespit edilemedi, lütfen elle girin.",
"{nthServer}. Server" : "{nthServer}. Sunucu",
"No object found in the given Base DN. Please revise." : "Girilen Base DN içerisinde nesne bulunamadı. Lütfen gözden geçirin.",
+ "More than 1,000 directory entries available." : "1000'den fazla dizin şu an müsait durumdadır.",
" entries available within the provided Base DN" : " girdi sağlanan Base DN içerisinde mevcut",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Bir hata oluştu. Lütfen Base DN ile birlikte bağlantı ayarlarını ve kimlik bilgilerini denetleyin.",
"Do you really want to delete the current Server Configuration?" : "Şu anki sunucu yapılandırmasını silmek istediğinizden emin misiniz?",
diff --git a/apps/user_ldap/l10n/tr.json b/apps/user_ldap/l10n/tr.json
index 2bd0bd59907..912f4385cf3 100644
--- a/apps/user_ldap/l10n/tr.json
+++ b/apps/user_ldap/l10n/tr.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "Base DN tespit edilemedi, lütfen elle girin.",
"{nthServer}. Server" : "{nthServer}. Sunucu",
"No object found in the given Base DN. Please revise." : "Girilen Base DN içerisinde nesne bulunamadı. Lütfen gözden geçirin.",
+ "More than 1,000 directory entries available." : "1000'den fazla dizin şu an müsait durumdadır.",
" entries available within the provided Base DN" : " girdi sağlanan Base DN içerisinde mevcut",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Bir hata oluştu. Lütfen Base DN ile birlikte bağlantı ayarlarını ve kimlik bilgilerini denetleyin.",
"Do you really want to delete the current Server Configuration?" : "Şu anki sunucu yapılandırmasını silmek istediğinizden emin misiniz?",
diff --git a/apps/user_ldap/l10n/zh_TW.js b/apps/user_ldap/l10n/zh_TW.js
index 244206927ba..77bd5ab1258 100644
--- a/apps/user_ldap/l10n/zh_TW.js
+++ b/apps/user_ldap/l10n/zh_TW.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "無法偵測到Base DN,請手動輸入",
"{nthServer}. Server" : "{nthServer}. 伺服器",
"No object found in the given Base DN. Please revise." : "在Base DN中找不到物件,請重新修改",
+ "More than 1,000 directory entries available." : "目前有超過 1,000 個資料夾項目是可以使用的",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "產生錯誤,請檢查Base DN,以及連線設定和驗證",
"Do you really want to delete the current Server Configuration?" : "您真的要刪除現在的伺服器設定嗎?",
"Confirm Deletion" : "確認刪除",
diff --git a/apps/user_ldap/l10n/zh_TW.json b/apps/user_ldap/l10n/zh_TW.json
index 35b5b5bad27..abbd1d65071 100644
--- a/apps/user_ldap/l10n/zh_TW.json
+++ b/apps/user_ldap/l10n/zh_TW.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "無法偵測到Base DN,請手動輸入",
"{nthServer}. Server" : "{nthServer}. 伺服器",
"No object found in the given Base DN. Please revise." : "在Base DN中找不到物件,請重新修改",
+ "More than 1,000 directory entries available." : "目前有超過 1,000 個資料夾項目是可以使用的",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "產生錯誤,請檢查Base DN,以及連線設定和驗證",
"Do you really want to delete the current Server Configuration?" : "您真的要刪除現在的伺服器設定嗎?",
"Confirm Deletion" : "確認刪除",
diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php
index 7be91186c16..82cd342ae2f 100644
--- a/apps/user_ldap/lib/access.php
+++ b/apps/user_ldap/lib/access.php
@@ -11,12 +11,15 @@
* @author Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Lyonel Vincent <lyonel@ezix.org>
+ * @author Mario Kolling <mario.kolling@serpro.gov.br>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Nicolas Grekas <nicolas.grekas@gmail.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Ralph Krimmel <rkrimme1@gwdg.de>
+ * @author Renaud Fortier <Renaud.Fortier@fsaa.ulaval.ca>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -177,7 +180,7 @@ class Access extends LDAPUtility implements user\IUserTools {
//in case an error occurs , e.g. object does not exist
return false;
}
- if (empty($attr)) {
+ if (empty($attr) && ($filter === 'objectclass=*' || $this->ldap->countEntries($cr, $rr) === 1)) {
\OCP\Util::writeLog('user_ldap', 'readAttribute: '.$dn.' found', \OCP\Util::DEBUG);
return array();
}
@@ -706,8 +709,16 @@ class Access extends LDAPUtility implements user\IUserTools {
* @param array $ldapRecords
*/
public function batchApplyUserAttributes(array $ldapRecords){
+ $displayNameAttribute = strtolower($this->connection->ldapUserDisplayName);
foreach($ldapRecords as $userRecord) {
+ if(!isset($userRecord[$displayNameAttribute])) {
+ // displayName is obligatory
+ continue;
+ }
$ocName = $this->dn2ocname($userRecord['dn'][0]);
+ if($ocName === false) {
+ continue;
+ }
$this->cacheUserExists($ocName);
$user = $this->userManager->get($ocName);
if($user instanceof OfflineUser) {
@@ -864,14 +875,13 @@ class Access extends LDAPUtility implements user\IUserTools {
* @param bool $pagedSearchOK whether a paged search has been executed
* @param bool $skipHandling required for paged search when cookies to
* prior results need to be gained
- * @return array|false array with the search result as first value and pagedSearchOK as
- * second | false if not successful
+ * @return bool cookie validity, true if we have more pages, false otherwise.
*/
private function processPagedSearchStatus($sr, $filter, $base, $iFoundItems, $limit, $offset, $pagedSearchOK, $skipHandling) {
+ $cookie = null;
if($pagedSearchOK) {
$cr = $this->connection->getConnectionResource();
foreach($sr as $key => $res) {
- $cookie = null;
if($this->ldap->controlPagedResultResponse($cr, $res, $cookie)) {
$this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie);
}
@@ -892,6 +902,12 @@ class Access extends LDAPUtility implements user\IUserTools {
\OCP\Util::writeLog('user_ldap', 'Paged search was not available', \OCP\Util::INFO);
}
}
+ /* ++ Fixing RHDS searches with pages with zero results ++
+ * Return cookie status. If we don't have more pages, with RHDS
+ * cookie is null, with openldap cookie is an empty string and
+ * to 386ds '0' is a valid cookie. Even if $iFoundItems == 0
+ */
+ return !empty($cookie) || $cookie === '0';
}
/**
@@ -920,7 +936,6 @@ class Access extends LDAPUtility implements user\IUserTools {
$this->connection->getConnectionResource();
do {
- $continue = false;
$search = $this->executeSearch($filter, $base, $attr,
$limitPerPage, $offset);
if($search === false) {
@@ -928,12 +943,20 @@ class Access extends LDAPUtility implements user\IUserTools {
}
list($sr, $pagedSearchOK) = $search;
- $count = $this->countEntriesInSearchResults($sr, $limitPerPage, $continue);
+ /* ++ Fixing RHDS searches with pages with zero results ++
+ * countEntriesInSearchResults() method signature changed
+ * by removing $limit and &$hasHitLimit parameters
+ */
+ $count = $this->countEntriesInSearchResults($sr);
$counter += $count;
- $this->processPagedSearchStatus($sr, $filter, $base, $count, $limitPerPage,
+ $hasMorePages = $this->processPagedSearchStatus($sr, $filter, $base, $count, $limitPerPage,
$offset, $pagedSearchOK, $skipHandling);
$offset += $limitPerPage;
+ /* ++ Fixing RHDS searches with pages with zero results ++
+ * Continue now depends on $hasMorePages value
+ */
+ $continue = $pagedSearchOK && $hasMorePages;
} while($continue && (is_null($limit) || $limit <= 0 || $limit > $counter));
return $counter;
@@ -941,20 +964,15 @@ class Access extends LDAPUtility implements user\IUserTools {
/**
* @param array $searchResults
- * @param int $limit
- * @param bool $hasHitLimit
* @return int
*/
- private function countEntriesInSearchResults($searchResults, $limit, &$hasHitLimit) {
+ private function countEntriesInSearchResults($searchResults) {
$cr = $this->connection->getConnectionResource();
$counter = 0;
foreach($searchResults as $res) {
$count = intval($this->ldap->countEntries($cr, $res));
$counter += $count;
- if($count > 0 && $count === $limit) {
- $hasHitLimit = true;
- }
}
return $counter;
@@ -975,38 +993,53 @@ class Access extends LDAPUtility implements user\IUserTools {
//otherwise search will fail
$limit = null;
}
- $search = $this->executeSearch($filter, $base, $attr, $limit, $offset);
- if($search === false) {
- return array();
- }
- list($sr, $pagedSearchOK) = $search;
- $cr = $this->connection->getConnectionResource();
- if($skipHandling) {
- //i.e. result do not need to be fetched, we just need the cookie
- //thus pass 1 or any other value as $iFoundItems because it is not
- //used
- $this->processPagedSearchStatus($sr, $filter, $base, 1, $limit,
- $offset, $pagedSearchOK,
- $skipHandling);
- return array();
- }
+ /* ++ Fixing RHDS searches with pages with zero results ++
+ * As we can have pages with zero results and/or pages with less
+ * than $limit results but with a still valid server 'cookie',
+ * loops through until we get $continue equals true and
+ * $findings['count'] < $limit
+ */
+ $findings = array();
+ $savedoffset = $offset;
+ do {
+ $continue = false;
+ $search = $this->executeSearch($filter, $base, $attr, $limit, $offset);
+ if($search === false) {
+ return array();
+ }
+ list($sr, $pagedSearchOK) = $search;
+ $cr = $this->connection->getConnectionResource();
- // Do the server-side sorting
- foreach(array_reverse($attr) as $sortAttr){
- foreach($sr as $searchResource) {
- $this->ldap->sort($cr, $searchResource, $sortAttr);
+ if($skipHandling) {
+ //i.e. result do not need to be fetched, we just need the cookie
+ //thus pass 1 or any other value as $iFoundItems because it is not
+ //used
+ $this->processPagedSearchStatus($sr, $filter, $base, 1, $limit,
+ $offset, $pagedSearchOK,
+ $skipHandling);
+ return array();
}
- }
- $findings = array();
- foreach($sr as $res) {
- $findings = array_merge($findings, $this->ldap->getEntries($cr , $res ));
- }
+ // Do the server-side sorting
+ foreach(array_reverse($attr) as $sortAttr){
+ foreach($sr as $searchResource) {
+ $this->ldap->sort($cr, $searchResource, $sortAttr);
+ }
+ }
+
+
+ foreach($sr as $res) {
+ $findings = array_merge($findings, $this->ldap->getEntries($cr , $res ));
+ }
- $this->processPagedSearchStatus($sr, $filter, $base, $findings['count'],
- $limit, $offset, $pagedSearchOK,
+ $continue = $this->processPagedSearchStatus($sr, $filter, $base, $findings['count'],
+ $limit, $offset, $pagedSearchOK,
$skipHandling);
+ $offset += $limit;
+ } while ($continue && $pagedSearchOK && $findings['count'] < $limit);
+ // reseting offset
+ $offset = $savedoffset;
// if we're here, probably no connection resource is returned.
// to make ownCloud behave nicely, we simply give back an empty array.
@@ -1171,7 +1204,7 @@ class Access extends LDAPUtility implements user\IUserTools {
$searchWords = explode(' ', trim($search));
$wordFilters = array();
foreach($searchWords as $word) {
- $word .= '*';
+ $word = $this->prepareSearchTerm($word);
//every word needs to appear at least once
$wordMatchOneAttrFilters = array();
foreach($searchAttributes as $attr) {
@@ -1204,7 +1237,8 @@ class Access extends LDAPUtility implements user\IUserTools {
);
}
}
- $search = empty($search) ? '*' : $search.'*';
+
+ $search = $this->prepareSearchTerm($search);
if(!is_array($searchAttributes) || count($searchAttributes) === 0) {
if(empty($fallbackAttribute)) {
return '';
@@ -1222,6 +1256,22 @@ class Access extends LDAPUtility implements user\IUserTools {
}
/**
+ * returns the search term depending on whether we are allowed
+ * list users found by ldap with the current input appended by
+ * a *
+ * @return string
+ */
+ private function prepareSearchTerm($term) {
+ $config = \OC::$server->getConfig();
+
+ $allowEnum = $config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes');
+
+ $result = empty($term) ? '*' :
+ $allowEnum !== 'no' ? $term . '*' : $term;
+ return $result;
+ }
+
+ /**
* returns the filter used for counting users
* @return string
*/
@@ -1255,6 +1305,54 @@ class Access extends LDAPUtility implements user\IUserTools {
}
/**
+ * reverse lookup of a DN given a known UUID
+ *
+ * @param string $uuid
+ * @return string
+ * @throws \Exception
+ */
+ public function getUserDnByUuid($uuid) {
+ $uuidOverride = $this->connection->ldapExpertUUIDUserAttr;
+ $filter = $this->connection->ldapUserFilter;
+ $base = $this->connection->ldapBaseUsers;
+
+ if($this->connection->ldapUuidUserAttribute === 'auto' && empty($uuidOverride)) {
+ // Sacrebleu! The UUID attribute is unknown :( We need first an
+ // existing DN to be able to reliably detect it.
+ $result = $this->search($filter, $base, ['dn'], 1);
+ if(!isset($result[0]) || !isset($result[0]['dn'])) {
+ throw new \Exception('Cannot determine UUID attribute');
+ }
+ $dn = $result[0]['dn'][0];
+ if(!$this->detectUuidAttribute($dn, true)) {
+ throw new \Exception('Cannot determine UUID attribute');
+ }
+ } else {
+ // The UUID attribute is either known or an override is given.
+ // By calling this method we ensure that $this->connection->$uuidAttr
+ // is definitely set
+ if(!$this->detectUuidAttribute('', true)) {
+ throw new \Exception('Cannot determine UUID attribute');
+ }
+ }
+
+ $uuidAttr = $this->connection->ldapUuidUserAttribute;
+ if($uuidAttr === 'guid' || $uuidAttr === 'objectguid') {
+ $uuid = $this->formatGuid2ForFilterUser($uuid);
+ }
+
+ $filter = $uuidAttr . '=' . $uuid;
+ $result = $this->searchUsers($filter, ['dn'], 2);
+ if(is_array($result) && isset($result[0]) && isset($result[0]['dn']) && count($result) === 1) {
+ // we put the count into account to make sure that this is
+ // really unique
+ return $result[0]['dn'][0];
+ }
+
+ throw new \Exception('Cannot determine UUID attribute');
+ }
+
+ /**
* auto-detects the directory's UUID attribute
* @param string $dn a known DN used to check against
* @param bool $isUser
@@ -1357,6 +1455,53 @@ class Access extends LDAPUtility implements user\IUserTools {
}
/**
+ * the first three blocks of the string-converted GUID happen to be in
+ * reverse order. In order to use it in a filter, this needs to be
+ * corrected. Furthermore the dashes need to be replaced and \\ preprended
+ * to every two hax figures.
+ *
+ * If an invalid string is passed, it will be returned without change.
+ *
+ * @param string $guid
+ * @return string
+ */
+ public function formatGuid2ForFilterUser($guid) {
+ if(!is_string($guid)) {
+ throw new \InvalidArgumentException('String expected');
+ }
+ $blocks = explode('-', $guid);
+ if(count($blocks) !== 5) {
+ /*
+ * Why not throw an Exception instead? This method is a utility
+ * called only when trying to figure out whether a "missing" known
+ * LDAP user was or was not renamed on the LDAP server. And this
+ * even on the use case that a reverse lookup is needed (UUID known,
+ * not DN), i.e. when finding users (search dialog, users page,
+ * login, …) this will not be fired. This occurs only if shares from
+ * a users are supposed to be mounted who cannot be found. Throwing
+ * an exception here would kill the experience for a valid, acting
+ * user. Instead we write a log message.
+ */
+ \OC::$server->getLogger()->info(
+ 'Passed string does not resemble a valid GUID. Known UUID ' .
+ '({uuid}) probably does not match UUID configuration.',
+ [ 'app' => 'user_ldap', 'uuid' => $guid ]
+ );
+ return $guid;
+ }
+ for($i=0; $i < 3; $i++) {
+ $pairs = str_split($blocks[$i], 2);
+ $pairs = array_reverse($pairs);
+ $blocks[$i] = implode('', $pairs);
+ }
+ for($i=0; $i < 5; $i++) {
+ $pairs = str_split($blocks[$i], 2);
+ $blocks[$i] = '\\' . implode('\\', $pairs);
+ }
+ return implode('', $blocks);
+ }
+
+ /**
* gets a SID of the domain of the given dn
* @param string $dn
* @return string|bool
@@ -1594,7 +1739,13 @@ class Access extends LDAPUtility implements user\IUserTools {
}
}
- } else if($this->connection->hasPagedResultSupport && $limit === 0) {
+ /* ++ Fixing RHDS searches with pages with zero results ++
+ * We coudn't get paged searches working with our RHDS for login ($limit = 0),
+ * due to pages with zero results.
+ * So we added "&& !empty($this->lastCookie)" to this test to ignore pagination
+ * if we don't have a previous paged search.
+ */
+ } else if($this->connection->hasPagedResultSupport && $limit === 0 && !empty($this->lastCookie)) {
// a search without limit was requested. However, if we do use
// Paged Search once, we always must do it. This requires us to
// initialize it with the configured page size.
diff --git a/apps/user_ldap/lib/backendutility.php b/apps/user_ldap/lib/backendutility.php
index b0fee7cd25e..87c1649cada 100644
--- a/apps/user_ldap/lib/backendutility.php
+++ b/apps/user_ldap/lib/backendutility.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php
index e1ca624af95..11090f1301b 100644
--- a/apps/user_ldap/lib/configuration.php
+++ b/apps/user_ldap/lib/configuration.php
@@ -6,9 +6,10 @@
* @author Lennart Rosam <hello@takuto.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Richard Bentley <rbentley@e2advance.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -83,6 +84,7 @@ class Configuration {
'lastJpegPhotoLookup' => null,
'ldapNestedGroups' => false,
'ldapPagingSize' => null,
+ 'ldapDynamicGroupMemberURL' => null,
);
/**
@@ -281,7 +283,6 @@ class Configuration {
*
* @param string $varName name of config-key
* @param array|string $value to set
- * @param boolean $trim Trim value? (default: false)
*/
protected function setMultiLine($varName, $value) {
if(empty($value)) {
@@ -440,6 +441,7 @@ class Configuration {
'ldap_nested_groups' => 0,
'ldap_paging_size' => 500,
'ldap_experienced_admin' => 0,
+ 'ldap_dynamic_group_member_url' => '',
);
}
@@ -493,7 +495,8 @@ class Configuration {
'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup',
'ldap_nested_groups' => 'ldapNestedGroups',
'ldap_paging_size' => 'ldapPagingSize',
- 'ldap_experienced_admin' => 'ldapExperiencedAdmin'
+ 'ldap_experienced_admin' => 'ldapExperiencedAdmin',
+ 'ldap_dynamic_group_member_url' => 'ldapDynamicGroupMemberURL',
);
return $array;
}
diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php
index 3f3953bb28b..addd7d0b51d 100644
--- a/apps/user_ldap/lib/connection.php
+++ b/apps/user_ldap/lib/connection.php
@@ -7,10 +7,10 @@
* @author Lyonel Vincent <lyonel@ezix.org>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -206,7 +206,7 @@ class Connection extends LDAPUtility {
}
$key = $this->getCacheKey($key);
- return json_decode(base64_decode($this->cache->get($key)));
+ return json_decode(base64_decode($this->cache->get($key)), true);
}
/**
@@ -570,15 +570,12 @@ class Connection extends LDAPUtility {
* @param string $host
* @param string $port
* @return false|void
+ * @throws \OC\ServerNotAvailableException
*/
private function doConnect($host, $port) {
if(empty($host)) {
return false;
}
- if(strpos($host, '://') !== false) {
- //ldap_connect ignores port parameter when URLs are passed
- $host .= ':' . $port;
- }
$this->ldapConnectionRes = $this->ldap->connect($host, $port);
if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
@@ -586,6 +583,8 @@ class Connection extends LDAPUtility {
$this->ldap->startTls($this->ldapConnectionRes);
}
}
+ } else {
+ throw new \OC\ServerNotAvailableException('Could not set required LDAP Protocol version.');
}
}
diff --git a/apps/user_ldap/lib/filesystemhelper.php b/apps/user_ldap/lib/filesystemhelper.php
index ee8c26d2f59..03f4c4274f4 100644
--- a/apps/user_ldap/lib/filesystemhelper.php
+++ b/apps/user_ldap/lib/filesystemhelper.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/helper.php b/apps/user_ldap/lib/helper.php
index f05a4afad2c..bfff6baf0d3 100644
--- a/apps/user_ldap/lib/helper.php
+++ b/apps/user_ldap/lib/helper.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -62,7 +62,7 @@ class Helper {
';
if($activeConfigurations) {
- if (\OC_Config::getValue( 'dbtype', 'sqlite' ) === 'oci') {
+ if (\OC::$server->getConfig()->getSystemValue( 'dbtype', 'sqlite' ) === 'oci') {
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
$sql .= ' AND to_char(`configvalue`)=\'1\'';
} else {
diff --git a/apps/user_ldap/lib/ildapwrapper.php b/apps/user_ldap/lib/ildapwrapper.php
index dceb038ba3d..44ec08f59fd 100644
--- a/apps/user_ldap/lib/ildapwrapper.php
+++ b/apps/user_ldap/lib/ildapwrapper.php
@@ -4,9 +4,9 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/jobs.php b/apps/user_ldap/lib/jobs.php
index 5c8d631de3e..47e28470188 100644
--- a/apps/user_ldap/lib/jobs.php
+++ b/apps/user_ldap/lib/jobs.php
@@ -6,9 +6,9 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -175,7 +175,8 @@ class Jobs extends \OC\BackgroundJob\TimedJob {
new LogWrapper(),
\OC::$server->getAvatarManager(),
new \OCP\Image(),
- $dbc);
+ $dbc,
+ \OC::$server->getUserManager());
$connector = new Connection($ldapWrapper, $configPrefixes[0]);
$ldapAccess = new Access($connector, $ldapWrapper, $userManager);
$groupMapper = new GroupMapping($dbc);
diff --git a/apps/user_ldap/lib/jobs/cleanup.php b/apps/user_ldap/lib/jobs/cleanup.php
index da2c332cf0e..c9f5f2021eb 100644
--- a/apps/user_ldap/lib/jobs/cleanup.php
+++ b/apps/user_ldap/lib/jobs/cleanup.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/ldap.php b/apps/user_ldap/lib/ldap.php
index 4d45db2e155..ad8c338b587 100644
--- a/apps/user_ldap/lib/ldap.php
+++ b/apps/user_ldap/lib/ldap.php
@@ -5,9 +5,9 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -48,7 +48,14 @@ class LDAP implements ILDAPWrapper {
* @return mixed
*/
public function connect($host, $port) {
- return $this->invokeLDAPMethod('connect', $host, $port);
+ if(strpos($host, '://') === false) {
+ $host = 'ldap://' . $host;
+ }
+ if(strpos($host, ':', strpos($host, '://') + 1) === false) {
+ //ldap_connect ignores port parameter when URLs are passed
+ $host .= ':' . $port;
+ }
+ return $this->invokeLDAPMethod('connect', $host);
}
/**
diff --git a/apps/user_ldap/lib/ldaputility.php b/apps/user_ldap/lib/ldaputility.php
index 01aabdaa1b0..e80fc12e087 100644
--- a/apps/user_ldap/lib/ldaputility.php
+++ b/apps/user_ldap/lib/ldaputility.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/logwrapper.php b/apps/user_ldap/lib/logwrapper.php
index 7080366c675..41ae4fc3426 100644
--- a/apps/user_ldap/lib/logwrapper.php
+++ b/apps/user_ldap/lib/logwrapper.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/mapping/abstractmapping.php b/apps/user_ldap/lib/mapping/abstractmapping.php
index f0f0f6df75e..1c896a9bbf4 100644
--- a/apps/user_ldap/lib/mapping/abstractmapping.php
+++ b/apps/user_ldap/lib/mapping/abstractmapping.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -158,7 +158,7 @@ abstract class AbstractMapping {
}
/**
- * Gets the name based on the provided LDAP DN.
+ * Gets the name based on the provided LDAP UUID.
* @param string $uuid
* @return string|false
*/
@@ -167,6 +167,16 @@ abstract class AbstractMapping {
}
/**
+ * Gets the UUID based on the provided LDAP DN
+ * @param string $dn
+ * @return false|string
+ * @throws \Exception
+ */
+ public function getUUIDByDN($dn) {
+ return $this->getXbyY('directory_uuid', 'ldap_dn', $dn);
+ }
+
+ /**
* gets a piece of the mapping list
* @param int $offset
* @param int $limit
diff --git a/apps/user_ldap/lib/mapping/groupmapping.php b/apps/user_ldap/lib/mapping/groupmapping.php
index 105155e72cc..49bb41b8c76 100644
--- a/apps/user_ldap/lib/mapping/groupmapping.php
+++ b/apps/user_ldap/lib/mapping/groupmapping.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/mapping/usermapping.php b/apps/user_ldap/lib/mapping/usermapping.php
index d83c6160527..b39f738ea8c 100644
--- a/apps/user_ldap/lib/mapping/usermapping.php
+++ b/apps/user_ldap/lib/mapping/usermapping.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/proxy.php b/apps/user_ldap/lib/proxy.php
index 2a423cb0e4b..082ba9a93d0 100644
--- a/apps/user_ldap/lib/proxy.php
+++ b/apps/user_ldap/lib/proxy.php
@@ -6,10 +6,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -61,6 +61,7 @@ abstract class Proxy {
static $userMap;
static $groupMap;
static $db;
+ static $userManager;
if(is_null($fs)) {
$ocConfig = \OC::$server->getConfig();
$fs = new FilesystemHelper();
@@ -69,9 +70,10 @@ abstract class Proxy {
$db = \OC::$server->getDatabaseConnection();
$userMap = new UserMapping($db);
$groupMap = new GroupMapping($db);
+ $userManager = \OC::$server->getUserManager();
}
$userManager =
- new user\Manager($ocConfig, $fs, $log, $avatarM, new \OCP\Image(), $db);
+ new user\Manager($ocConfig, $fs, $log, $avatarM, new \OCP\Image(), $db, $userManager);
$connector = new Connection($this->ldap, $configPrefix);
$access = new Access($connector, $this->ldap, $userManager);
$access->setUserMapper($userMap);
diff --git a/apps/user_ldap/lib/user/deletedusersindex.php b/apps/user_ldap/lib/user/deletedusersindex.php
index 6b58595cce6..48daeb9b8bc 100644
--- a/apps/user_ldap/lib/user/deletedusersindex.php
+++ b/apps/user_ldap/lib/user/deletedusersindex.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/user/iusertools.php b/apps/user_ldap/lib/user/iusertools.php
index afd01856048..b0eb9e1ffb3 100644
--- a/apps/user_ldap/lib/user/iusertools.php
+++ b/apps/user_ldap/lib/user/iusertools.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/user/manager.php b/apps/user_ldap/lib/user/manager.php
index 4a687c0832a..cfa333b06d4 100644
--- a/apps/user_ldap/lib/user/manager.php
+++ b/apps/user_ldap/lib/user/manager.php
@@ -5,7 +5,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,6 +29,11 @@ use OCA\user_ldap\lib\user\User;
use OCA\user_ldap\lib\LogWrapper;
use OCA\user_ldap\lib\FilesystemHelper;
use OCA\user_ldap\lib\user\OfflineUser;
+use OCP\IAvatarManager;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\Image;
+use OCP\IUserManager;
/**
* Manager
@@ -40,10 +45,10 @@ class Manager {
/** @var IUserTools */
protected $access;
- /** @var \OCP\IConfig */
+ /** @var IConfig */
protected $ocConfig;
- /** @var \OCP\IDBConnection */
+ /** @var IDBConnection */
protected $db;
/** @var FilesystemHelper */
@@ -52,7 +57,7 @@ class Manager {
/** @var LogWrapper */
protected $ocLog;
- /** @var \OCP\Image */
+ /** @var Image */
protected $image;
/** @param \OCP\IAvatarManager */
@@ -69,18 +74,19 @@ class Manager {
);
/**
- * @param \OCP\IConfig $ocConfig
+ * @param IConfig $ocConfig
* @param \OCA\user_ldap\lib\FilesystemHelper $ocFilesystem object that
* gives access to necessary functions from the OC filesystem
* @param \OCA\user_ldap\lib\LogWrapper $ocLog
- * @param \OCP\IAvatarManager $avatarManager
- * @param \OCP\Image $image an empty image instance
- * @param \OCP\IDBConnection $db
+ * @param IAvatarManager $avatarManager
+ * @param Image $image an empty image instance
+ * @param IDBConnection $db
* @throws \Exception when the methods mentioned above do not exist
*/
- public function __construct(\OCP\IConfig $ocConfig,
- FilesystemHelper $ocFilesystem, LogWrapper $ocLog,
- \OCP\IAvatarManager $avatarManager, \OCP\Image $image, \OCP\IDBConnection $db) {
+ public function __construct(IConfig $ocConfig,
+ FilesystemHelper $ocFilesystem, LogWrapper $ocLog,
+ IAvatarManager $avatarManager, Image $image,
+ IDBConnection $db, IUserManager $userManager) {
$this->ocConfig = $ocConfig;
$this->ocFilesystem = $ocFilesystem;
@@ -88,6 +94,7 @@ class Manager {
$this->avatarManager = $avatarManager;
$this->image = $image;
$this->db = $db;
+ $this->userManager = $userManager;
}
/**
@@ -110,7 +117,7 @@ class Manager {
$this->checkAccess();
$user = new User($uid, $dn, $this->access, $this->ocConfig,
$this->ocFilesystem, clone $this->image, $this->ocLog,
- $this->avatarManager);
+ $this->avatarManager, $this->userManager);
$this->users['byDN'][$dn] = $user;
$this->users['byUid'][$uid] = $user;
return $user;
diff --git a/apps/user_ldap/lib/user/offlineuser.php b/apps/user_ldap/lib/user/offlineuser.php
index 3456a27b412..aee1a137a96 100644
--- a/apps/user_ldap/lib/user/offlineuser.php
+++ b/apps/user_ldap/lib/user/offlineuser.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/lib/user/user.php b/apps/user_ldap/lib/user/user.php
index 0dc3c8c0c26..13f88aa6507 100644
--- a/apps/user_ldap/lib/user/user.php
+++ b/apps/user_ldap/lib/user/user.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,6 +27,9 @@ use OCA\user_ldap\lib\user\IUserTools;
use OCA\user_ldap\lib\Connection;
use OCA\user_ldap\lib\FilesystemHelper;
use OCA\user_ldap\lib\LogWrapper;
+use OCP\IAvatarManager;
+use OCP\IConfig;
+use OCP\IUserManager;
/**
* User
@@ -43,7 +46,7 @@ class User {
*/
protected $connection;
/**
- * @var \OCP\IConfig
+ * @var IConfig
*/
protected $config;
/**
@@ -59,10 +62,13 @@ class User {
*/
protected $log;
/**
- * @var \OCP\IAvatarManager
+ * @var IAvatarManager
*/
protected $avatarManager;
-
+ /**
+ * @var IUserManager
+ */
+ protected $userManager;
/**
* @var string
*/
@@ -92,15 +98,16 @@ class User {
* @param string $dn the LDAP DN
* @param IUserTools $access an instance that implements IUserTools for
* LDAP interaction
- * @param \OCP\IConfig $config
+ * @param IConfig $config
* @param FilesystemHelper $fs
* @param \OCP\Image $image any empty instance
* @param LogWrapper $log
- * @param \OCP\IAvatarManager $avatarManager
+ * @param IAvatarManager $avatarManager
+ * @param IUserManager $userManager
*/
public function __construct($username, $dn, IUserTools $access,
- \OCP\IConfig $config, FilesystemHelper $fs, \OCP\Image $image,
- LogWrapper $log, \OCP\IAvatarManager $avatarManager) {
+ IConfig $config, FilesystemHelper $fs, \OCP\Image $image,
+ LogWrapper $log, IAvatarManager $avatarManager, IUserManager $userManager) {
$this->access = $access;
$this->connection = $access->getConnection();
@@ -111,6 +118,7 @@ class User {
$this->image = $image;
$this->log = $log;
$this->avatarManager = $avatarManager;
+ $this->userManager = $userManager;
}
/**
@@ -400,8 +408,8 @@ class User {
}
}
if(!is_null($email)) {
- $this->config->setUserValue(
- $this->uid, 'settings', 'email', $email);
+ $user = $this->userManager->get($this->uid);
+ $user->setEMailAddress($email);
}
}
@@ -474,8 +482,8 @@ class User {
$this->fs->setup($this->uid);
}
- $avatar = $this->avatarManager->getAvatar($this->uid);
try {
+ $avatar = $this->avatarManager->getAvatar($this->uid);
$avatar->set($this->image);
} catch (\Exception $e) {
\OC::$server->getLogger()->notice(
diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php
index e53ff35cfd6..4a12d411ec1 100644
--- a/apps/user_ldap/lib/wizard.php
+++ b/apps/user_ldap/lib/wizard.php
@@ -9,11 +9,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Nicolas Grekas <nicolas.grekas@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -1035,13 +1035,6 @@ class Wizard extends LDAPUtility {
if(!$hostInfo) {
throw new \Exception($this->l->t('Invalid Host'));
}
- if(isset($hostInfo['scheme'])) {
- if(isset($hostInfo['port'])) {
- //problem
- } else {
- $host .= ':' . $port;
- }
- }
\OCP\Util::writeLog('user_ldap', 'Wiz: Attempting to connect ', \OCP\Util::DEBUG);
$cr = $this->ldap->connect($host, $port);
if(!is_resource($cr)) {
@@ -1291,12 +1284,10 @@ class Wizard extends LDAPUtility {
return $this->cr;
}
- $host = $this->configuration->ldapHost;
- if(strpos($host, '://') !== false) {
- //ldap_connect ignores port parameter when URLs are passed
- $host .= ':' . $this->configuration->ldapPort;
- }
- $cr = $this->ldap->connect($host, $this->configuration->ldapPort);
+ $cr = $this->ldap->connect(
+ $this->configuration->ldapHost,
+ $this->configuration->ldapPort
+ );
$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
diff --git a/apps/user_ldap/lib/wizardresult.php b/apps/user_ldap/lib/wizardresult.php
index 09ee43b716e..54f01cf59b8 100644
--- a/apps/user_ldap/lib/wizardresult.php
+++ b/apps/user_ldap/lib/wizardresult.php
@@ -4,9 +4,9 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/settings.php b/apps/user_ldap/settings.php
index fb54276b463..9d54684685a 100644
--- a/apps/user_ldap/settings.php
+++ b/apps/user_ldap/settings.php
@@ -6,10 +6,10 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Volkan Gezer <volkangezer@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php
index 88900e22bf7..1c0c9a8acb7 100644
--- a/apps/user_ldap/templates/settings.php
+++ b/apps/user_ldap/templates/settings.php
@@ -90,6 +90,7 @@ style('user_ldap', 'settings');
<p><label for="ldap_base_groups"><?php p($l->t('Base Group Tree'));?></label><textarea id="ldap_base_groups" name="ldap_base_groups" placeholder="<?php p($l->t('One Group Base DN per line'));?>" data-default="<?php p($_['ldap_base_groups_default']); ?>" title="<?php p($l->t('Base Group Tree'));?>"></textarea></p>
<p><label for="ldap_attributes_for_group_search"><?php p($l->t('Group Search Attributes'));?></label><textarea id="ldap_attributes_for_group_search" name="ldap_attributes_for_group_search" placeholder="<?php p($l->t('Optional; one attribute per line'));?>" data-default="<?php p($_['ldap_attributes_for_group_search_default']); ?>" title="<?php p($l->t('Group Search Attributes'));?>"></textarea></p>
<p><label for="ldap_group_member_assoc_attribute"><?php p($l->t('Group-Member association'));?></label><select id="ldap_group_member_assoc_attribute" name="ldap_group_member_assoc_attribute" data-default="<?php p($_['ldap_group_member_assoc_attribute_default']); ?>" ><option value="uniqueMember"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'uniqueMember')) p(' selected'); ?>>uniqueMember</option><option value="memberUid"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'memberUid')) p(' selected'); ?>>memberUid</option><option value="member"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'member')) p(' selected'); ?>>member (AD)</option></select></p>
+ <p><label for="ldap_dynamic_group_member_url"><?php p($l->t('Dynamic Group Member URL'));?></label><input type="text" id="ldap_dynamic_group_member_url" name="ldap_dynamic_group_member_url" title="<?php p($l->t('The LDAP attribute that on group objects contains an LDAP search URL that determines what objects belong to the group. (An empty setting disables dynamic group membership functionality.)'));?>" data-default="<?php p($_['ldap_dynamic_group_member_url_default']); ?>" /></p>
<p><label for="ldap_nested_groups"><?php p($l->t('Nested Groups'));?></label><input type="checkbox" id="ldap_nested_groups" name="ldap_nested_groups" value="1" data-default="<?php p($_['ldap_nested_groups_default']); ?>" title="<?php p($l->t('When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)'));?>" /></p>
<p><label for="ldap_paging_size"><?php p($l->t('Paging chunksize'));?></label><input type="number" id="ldap_paging_size" name="ldap_paging_size" title="<?php p($l->t('Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)'));?>" data-default="<?php p($_['ldap_paging_size_default']); ?>" /></p>
</div>
diff --git a/apps/user_ldap/tests/access.php b/apps/user_ldap/tests/access.php
index 25e871d9b3d..6d35adf1694 100644
--- a/apps/user_ldap/tests/access.php
+++ b/apps/user_ldap/tests/access.php
@@ -4,8 +4,9 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,6 +29,13 @@ use \OCA\user_ldap\lib\Access;
use \OCA\user_ldap\lib\Connection;
use \OCA\user_ldap\lib\ILDAPWrapper;
+/**
+ * Class Test_Access
+ *
+ * @group DB
+ *
+ * @package OCA\user_ldap\tests
+ */
class Test_Access extends \Test\TestCase {
private function getConnectorAndLdapMock() {
static $conMethods;
@@ -50,7 +58,8 @@ class Test_Access extends \Test\TestCase {
$this->getMock('\OCA\user_ldap\lib\LogWrapper'),
$this->getMock('\OCP\IAvatarManager'),
$this->getMock('\OCP\Image'),
- $this->getMock('\OCP\IDBConnection')));
+ $this->getMock('\OCP\IDBConnection'),
+ $this->getMock('\OCP\IUserManager')));
return array($lw, $connector, $um);
}
diff --git a/apps/user_ldap/tests/configuration.php b/apps/user_ldap/tests/configuration.php
index efe4d7eec83..3b87223b75b 100644
--- a/apps/user_ldap/tests/configuration.php
+++ b/apps/user_ldap/tests/configuration.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/connection.php b/apps/user_ldap/tests/connection.php
index b0b4b78ce4d..ecee25583ab 100644
--- a/apps/user_ldap/tests/connection.php
+++ b/apps/user_ldap/tests/connection.php
@@ -3,8 +3,9 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +24,13 @@
namespace OCA\user_ldap\tests;
+/**
+ * Class Test_Connection
+ *
+ * @group DB
+ *
+ * @package OCA\user_ldap\tests
+ */
class Test_Connection extends \Test\TestCase {
public function testOriginalAgentUnchangedOnClone() {
@@ -52,4 +60,4 @@ class Test_Connection extends \Test\TestCase {
$this->assertSame($agentPawd, $agent['ldapAgentPassword']);
}
-} \ No newline at end of file
+}
diff --git a/apps/user_ldap/tests/group_ldap.php b/apps/user_ldap/tests/group_ldap.php
index 6a6d5bc7ca1..667a1c3acb2 100644
--- a/apps/user_ldap/tests/group_ldap.php
+++ b/apps/user_ldap/tests/group_ldap.php
@@ -5,8 +5,9 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,6 +31,13 @@ use \OCA\user_ldap\lib\Access;
use \OCA\user_ldap\lib\Connection;
use \OCA\user_ldap\lib\ILDAPWrapper;
+/**
+ * Class Test_Group_Ldap
+ *
+ * @group DB
+ *
+ * @package OCA\user_ldap\tests
+ */
class Test_Group_Ldap extends \Test\TestCase {
private function getAccessMock() {
static $conMethods;
@@ -59,10 +67,13 @@ class Test_Group_Ldap extends \Test\TestCase {
private function enableGroups($access) {
$access->connection->expects($this->any())
- ->method('__get')
- ->will($this->returnCallback(function() {
- return 1;
- }));
+ ->method('__get')
+ ->will($this->returnCallback(function($name) {
+ if($name === 'ldapDynamicGroupMemberURL') {
+ return '';
+ }
+ return 1;
+ }));
}
public function testCountEmptySearchString() {
@@ -422,6 +433,8 @@ class Test_Group_Ldap extends \Test\TestCase {
->will($this->returnCallback(function($name) {
if($name === 'useMemberOfToDetectMembership') {
return 0;
+ } else if($name === 'ldapDynamicGroupMemberURL') {
+ return '';
}
return 1;
}));
diff --git a/apps/user_ldap/tests/integration/abstractintegrationtest.php b/apps/user_ldap/tests/integration/abstractintegrationtest.php
index f0f5e2de0a4..10ce7378830 100644
--- a/apps/user_ldap/tests/integration/abstractintegrationtest.php
+++ b/apps/user_ldap/tests/integration/abstractintegrationtest.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/exceptionOnLostConnection.php b/apps/user_ldap/tests/integration/exceptionOnLostConnection.php
index a55d4822689..4813bd9ff5e 100644
--- a/apps/user_ldap/tests/integration/exceptionOnLostConnection.php
+++ b/apps/user_ldap/tests/integration/exceptionOnLostConnection.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/fakemanager.php b/apps/user_ldap/tests/integration/fakemanager.php
index f47668aa15b..7d6ea0f3c13 100644
--- a/apps/user_ldap/tests/integration/fakemanager.php
+++ b/apps/user_ldap/tests/integration/fakemanager.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/lib/IntegrationTestAccessGroupsMatchFilter.php b/apps/user_ldap/tests/integration/lib/IntegrationTestAccessGroupsMatchFilter.php
index 17d046187e8..af553c01728 100644
--- a/apps/user_ldap/tests/integration/lib/IntegrationTestAccessGroupsMatchFilter.php
+++ b/apps/user_ldap/tests/integration/lib/IntegrationTestAccessGroupsMatchFilter.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/lib/integrationtestbackupserver.php b/apps/user_ldap/tests/integration/lib/integrationtestbackupserver.php
index 95cb4b8f270..4faf173af11 100644
--- a/apps/user_ldap/tests/integration/lib/integrationtestbackupserver.php
+++ b/apps/user_ldap/tests/integration/lib/integrationtestbackupserver.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/lib/integrationtestbatchapplyuserattributes.php b/apps/user_ldap/tests/integration/lib/integrationtestbatchapplyuserattributes.php
new file mode 100644
index 00000000000..f83b0efd0cc
--- /dev/null
+++ b/apps/user_ldap/tests/integration/lib/integrationtestbatchapplyuserattributes.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\user_ldap\tests\integration\lib;
+
+use OCA\User_LDAP\Mapping\UserMapping;
+use OCA\user_ldap\tests\integration\AbstractIntegrationTest;
+
+require_once __DIR__ . '/../../../../../lib/base.php';
+
+class IntegrationTestBatchApplyUserAttributes extends AbstractIntegrationTest {
+ /**
+ * prepares the LDAP environment and sets up a test configuration for
+ * the LDAP backend.
+ */
+ public function init() {
+ require(__DIR__ . '/../setup-scripts/createExplicitUsers.php');
+ require(__DIR__ . '/../setup-scripts/createUsersWithoutDisplayName.php');
+ parent::init();
+
+ $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection());
+ $this->mapping->clear();
+ $this->access->setUserMapper($this->mapping);
+ }
+
+ /**
+ * sets up the LDAP configuration to be used for the test
+ */
+ protected function initConnection() {
+ parent::initConnection();
+ $this->connection->setConfiguration([
+ 'ldapUserDisplayName' => 'displayname',
+ ]);
+ }
+
+ /**
+ * indirectly tests whether batchApplyUserAttributes does it job properly,
+ * when a user without display name is included in the result set from LDAP.
+ *
+ * @return bool
+ */
+ protected function case1() {
+ $result = $this->access->fetchListOfUsers('objectclass=person', 'dn');
+ // on the original issue, PHP would emit a fatal error
+ // – cannot catch it here, but will render the test as unsuccessful
+ return is_array($result) && !empty($result);
+ }
+
+}
+
+require_once(__DIR__ . '/../setup-scripts/config.php');
+$test = new IntegrationTestBatchApplyUserAttributes($host, $port, $adn, $apwd, $bdn);
+$test->init();
+$test->run();
diff --git a/apps/user_ldap/tests/integration/lib/integrationtestconnect.php b/apps/user_ldap/tests/integration/lib/integrationtestconnect.php
new file mode 100644
index 00000000000..ad4d0a3da7e
--- /dev/null
+++ b/apps/user_ldap/tests/integration/lib/integrationtestconnect.php
@@ -0,0 +1,166 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\user_ldap\tests\integration\lib;
+
+use OCA\user_ldap\lib\user\Manager as LDAPUserManager;
+use OCA\user_ldap\tests\integration\AbstractIntegrationTest;
+use OCA\User_LDAP\Mapping\UserMapping;
+use OCA\user_ldap\USER_LDAP;
+
+require_once __DIR__ . '/../../../../../lib/base.php';
+
+class IntegrationConnect extends AbstractIntegrationTest {
+ /** @var UserMapping */
+ protected $mapping;
+
+ /** @var USER_LDAP */
+ protected $backend;
+
+ /** @var string */
+ protected $host;
+
+ /** @var int */
+ protected $port;
+
+ public function __construct($host, $port, $bind, $pwd, $base) {
+ // make sure host is a simple host name
+ if(strpos($host, '://') !== false) {
+ $host = substr_replace($host, '', 0, strpos($host, '://') + 3);
+ }
+ if(strpos($host, ':') !== false) {
+ $host = substr_replace($host, '', strpos($host, ':'));
+ }
+ $this->host = $host;
+ $this->port = $port;
+ parent::__construct($host, $port, $bind, $pwd, $base);
+ }
+
+ /**
+ * test that a faulty host will does not connect successfully
+ *
+ * @return bool
+ */
+ protected function case1() {
+ // reset possible LDAP connection
+ $this->initConnection();
+ $this->connection->setConfiguration([
+ 'ldapHost' => 'qwertz.uiop',
+ ]);
+ try {
+ $this->connection->getConnectionResource();
+ } catch (\OC\ServerNotAvailableException $e) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * tests that a connect succeeds when only a hostname is provided
+ *
+ * @return bool
+ */
+ protected function case2() {
+ // reset possible LDAP connection
+ $this->initConnection();
+ $this->connection->setConfiguration([
+ 'ldapHost' => $this->host,
+ ]);
+ try {
+ $this->connection->getConnectionResource();
+ } catch (\OC\ServerNotAvailableException $e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * tests that a connect succeeds when an LDAP URL is provided
+ *
+ * @return bool
+ */
+ protected function case3() {
+ // reset possible LDAP connection
+ $this->initConnection();
+ $this->connection->setConfiguration([
+ 'ldapHost' => 'ldap://' . $this->host,
+ ]);
+ try {
+ $this->connection->getConnectionResource();
+ } catch (\OC\ServerNotAvailableException $e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * tests that a connect succeeds when an LDAP URL with port is provided
+ *
+ * @return bool
+ */
+ protected function case4() {
+ // reset possible LDAP connection
+ $this->initConnection();
+ $this->connection->setConfiguration([
+ 'ldapHost' => 'ldap://' . $this->host . ':' . $this->port,
+ ]);
+ try {
+ $this->connection->getConnectionResource();
+ } catch (\OC\ServerNotAvailableException $e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * tests that a connect succeeds when a hostname with port is provided
+ *
+ * @return bool
+ */
+ protected function case5() {
+ // reset possible LDAP connection
+ $this->initConnection();
+ $this->connection->setConfiguration([
+ 'ldapHost' => $this->host . ':' . $this->port,
+ ]);
+ try {
+ $this->connection->getConnectionResource();
+ } catch (\OC\ServerNotAvailableException $e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * repeat case1, only to make sure that not a connection was reused by
+ * accident.
+ *
+ * @return bool
+ */
+ protected function case6() {
+ return $this->case1();
+ }
+}
+
+require_once(__DIR__ . '/../setup-scripts/config.php');
+$test = new IntegrationConnect($host, $port, $adn, $apwd, $bdn);
+$test->init();
+$test->run();
diff --git a/apps/user_ldap/tests/integration/lib/integrationtestcountusersbyloginname.php b/apps/user_ldap/tests/integration/lib/integrationtestcountusersbyloginname.php
index 6e3908c558b..861638e25bd 100644
--- a/apps/user_ldap/tests/integration/lib/integrationtestcountusersbyloginname.php
+++ b/apps/user_ldap/tests/integration/lib/integrationtestcountusersbyloginname.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/lib/integrationtestfetchusersbyloginname.php b/apps/user_ldap/tests/integration/lib/integrationtestfetchusersbyloginname.php
index 403c3a0c73c..fb2cb45e9e7 100644
--- a/apps/user_ldap/tests/integration/lib/integrationtestfetchusersbyloginname.php
+++ b/apps/user_ldap/tests/integration/lib/integrationtestfetchusersbyloginname.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/lib/integrationtestpaging.php b/apps/user_ldap/tests/integration/lib/integrationtestpaging.php
index f8d008d065f..94f7d7fd0f5 100644
--- a/apps/user_ldap/tests/integration/lib/integrationtestpaging.php
+++ b/apps/user_ldap/tests/integration/lib/integrationtestpaging.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/lib/integrationtestuserhome.php b/apps/user_ldap/tests/integration/lib/integrationtestuserhome.php
index ef000286109..8d36e1f2dfe 100644
--- a/apps/user_ldap/tests/integration/lib/integrationtestuserhome.php
+++ b/apps/user_ldap/tests/integration/lib/integrationtestuserhome.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/lib/user/IntegrationTestUserAvatar.php b/apps/user_ldap/tests/integration/lib/user/IntegrationTestUserAvatar.php
index 6bb8afc01a2..4db3ca48768 100644
--- a/apps/user_ldap/tests/integration/lib/user/IntegrationTestUserAvatar.php
+++ b/apps/user_ldap/tests/integration/lib/user/IntegrationTestUserAvatar.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -123,7 +123,8 @@ class IntegrationTestUserAvatar extends AbstractIntegrationTest {
new \OCA\user_ldap\lib\LogWrapper(),
\OC::$server->getAvatarManager(),
new \OCP\Image(),
- \OC::$server->getDatabaseConnection()
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getUserManager()
);
}
diff --git a/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroups.php b/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroups.php
index 8ac35a54528..57a304be057 100644
--- a/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroups.php
+++ b/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroups.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroupsDifferentOU.php b/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroupsDifferentOU.php
index e22b72c452c..62480c5160c 100644
--- a/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroupsDifferentOU.php
+++ b/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroupsDifferentOU.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/setup-scripts/createExplicitUsers.php b/apps/user_ldap/tests/integration/setup-scripts/createExplicitUsers.php
index 3e9cb674254..e580dece40c 100644
--- a/apps/user_ldap/tests/integration/setup-scripts/createExplicitUsers.php
+++ b/apps/user_ldap/tests/integration/setup-scripts/createExplicitUsers.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/integration/setup-scripts/createUsersWithoutDisplayName.php b/apps/user_ldap/tests/integration/setup-scripts/createUsersWithoutDisplayName.php
new file mode 100644
index 00000000000..7f474aaa0e8
--- /dev/null
+++ b/apps/user_ldap/tests/integration/setup-scripts/createUsersWithoutDisplayName.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+if(php_sapi_name() !== 'cli') {
+ print('Only via CLI, please.');
+ exit(1);
+}
+
+include __DIR__ . '/config.php';
+
+$cr = ldap_connect($host, $port);
+ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
+$ok = ldap_bind($cr, $adn, $apwd);
+
+if (!$ok) {
+ die(ldap_error($cr));
+}
+
+$ouName = 'Users';
+$ouDN = 'ou=' . $ouName . ',' . $bdn;
+
+$users = ['robot'];
+
+foreach ($users as $uid) {
+ $newDN = 'uid=' . $uid . ',' . $ouDN;
+ $fn = ucfirst($uid);
+ $sn = ucfirst(str_shuffle($uid)); // not so explicit but it's OK.
+
+ $entry = [];
+ $entry['cn'] = ucfirst($uid);
+ $entry['objectclass'][] = 'inetOrgPerson';
+ $entry['objectclass'][] = 'person';
+ $entry['sn'] = $sn;
+ $entry['userPassword'] = $uid;
+
+ $ok = ldap_add($cr, $newDN, $entry);
+ if ($ok) {
+ echo('created user ' . ': ' . $entry['cn'] . PHP_EOL);
+ } else {
+ die(ldap_error($cr));
+ }
+}
diff --git a/apps/user_ldap/tests/jobs/cleanup.php b/apps/user_ldap/tests/jobs/cleanup.php
index aad8fbd20ad..4c6893b19cf 100644
--- a/apps/user_ldap/tests/jobs/cleanup.php
+++ b/apps/user_ldap/tests/jobs/cleanup.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/mapping/abstractmappingtest.php b/apps/user_ldap/tests/mapping/abstractmappingtest.php
index dc9304fe325..c6427be516b 100644
--- a/apps/user_ldap/tests/mapping/abstractmappingtest.php
+++ b/apps/user_ldap/tests/mapping/abstractmappingtest.php
@@ -3,7 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/apps/user_ldap/tests/mapping/groupmapping.php b/apps/user_ldap/tests/mapping/groupmapping.php
index e8fe655630d..e25fae9329f 100644
--- a/apps/user_ldap/tests/mapping/groupmapping.php
+++ b/apps/user_ldap/tests/mapping/groupmapping.php
@@ -2,8 +2,9 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,13 @@ namespace OCA\user_ldap\tests\mapping;
use OCA\User_LDAP\Mapping\GroupMapping;
+/**
+ * Class Test_GroupMapping
+ *
+ * @group DB
+ *
+ * @package OCA\user_ldap\tests\mapping
+ */
class Test_GroupMapping extends AbstractMappingTest {
public function getMapper(\OCP\IDBConnection $dbMock) {
return new GroupMapping($dbMock);
diff --git a/apps/user_ldap/tests/mapping/usermapping.php b/apps/user_ldap/tests/mapping/usermapping.php
index fa9311b405a..6138740b81a 100644
--- a/apps/user_ldap/tests/mapping/usermapping.php
+++ b/apps/user_ldap/tests/mapping/usermapping.php
@@ -2,8 +2,9 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,13 @@ namespace OCA\user_ldap\tests\mapping;
use OCA\User_LDAP\Mapping\UserMapping;
+/**
+ * Class Test_UserMapping
+ *
+ * @group DB
+ *
+ * @package OCA\user_ldap\tests\mapping
+ */
class Test_UserMapping extends AbstractMappingTest {
public function getMapper(\OCP\IDBConnection $dbMock) {
return new UserMapping($dbMock);
diff --git a/apps/user_ldap/tests/user/manager.php b/apps/user_ldap/tests/user/manager.php
index 98e48638d8b..c4af1009df8 100644
--- a/apps/user_ldap/tests/user/manager.php
+++ b/apps/user_ldap/tests/user/manager.php
@@ -4,8 +4,9 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Philippe Jung <phil.jung@free.fr>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +27,13 @@ namespace OCA\user_ldap\tests;
use OCA\user_ldap\lib\user\Manager;
+/**
+ * Class Test_User_Manager
+ *
+ * @group DB
+ *
+ * @package OCA\user_ldap\tests
+ */
class Test_User_Manager extends \Test\TestCase {
private function getTestInstances() {
@@ -36,6 +44,7 @@ class Test_User_Manager extends \Test\TestCase {
$avaMgr = $this->getMock('\OCP\IAvatarManager');
$image = $this->getMock('\OCP\Image');
$dbc = $this->getMock('\OCP\IDBConnection');
+ $userMgr = $this->getMock('\OCP\IUserManager');
$connection = new \OCA\user_ldap\lib\Connection(
$lw = $this->getMock('\OCA\user_ldap\lib\ILDAPWrapper'),
@@ -47,11 +56,11 @@ class Test_User_Manager extends \Test\TestCase {
->method('getConnection')
->will($this->returnValue($connection));
- return array($access, $config, $filesys, $image, $log, $avaMgr, $dbc);
+ return array($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr);
}
public function testGetByDNExisting() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
$inputDN = 'cn=foo,dc=foobar,dc=bar';
@@ -70,7 +79,7 @@ class Test_User_Manager extends \Test\TestCase {
$access->expects($this->never())
->method('username2dn');
- $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
+ $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
@@ -82,7 +91,7 @@ class Test_User_Manager extends \Test\TestCase {
}
public function testGetByEDirectoryDN() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
$inputDN = 'uid=foo,o=foobar,c=bar';
@@ -101,7 +110,7 @@ class Test_User_Manager extends \Test\TestCase {
$access->expects($this->never())
->method('username2dn');
- $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
+ $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
@@ -109,7 +118,7 @@ class Test_User_Manager extends \Test\TestCase {
}
public function testGetByExoticDN() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
$inputDN = 'ab=cde,f=ghei,mno=pq';
@@ -128,7 +137,7 @@ class Test_User_Manager extends \Test\TestCase {
$access->expects($this->never())
->method('username2dn');
- $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
+ $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
@@ -136,7 +145,7 @@ class Test_User_Manager extends \Test\TestCase {
}
public function testGetByDNNotExisting() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
$inputDN = 'cn=gone,dc=foobar,dc=bar';
@@ -156,7 +165,7 @@ class Test_User_Manager extends \Test\TestCase {
->with($this->equalTo($inputDN))
->will($this->returnValue(false));
- $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
+ $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
@@ -164,7 +173,7 @@ class Test_User_Manager extends \Test\TestCase {
}
public function testGetByUidExisting() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
$dn = 'cn=foo,dc=foobar,dc=bar';
@@ -183,7 +192,7 @@ class Test_User_Manager extends \Test\TestCase {
->with($this->equalTo($uid))
->will($this->returnValue(false));
- $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
+ $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr);
$manager->setLdapAccess($access);
$user = $manager->get($uid);
@@ -195,7 +204,7 @@ class Test_User_Manager extends \Test\TestCase {
}
public function testGetByUidNotExisting() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
$dn = 'cn=foo,dc=foobar,dc=bar';
@@ -209,7 +218,7 @@ class Test_User_Manager extends \Test\TestCase {
->with($this->equalTo($uid))
->will($this->returnValue(false));
- $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
+ $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr);
$manager->setLdapAccess($access);
$user = $manager->get($uid);
@@ -217,10 +226,10 @@ class Test_User_Manager extends \Test\TestCase {
}
public function testGetAttributesAll() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
- $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
+ $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr);
$manager->setLdapAccess($access);
$connection = $access->getConnection();
@@ -235,10 +244,10 @@ class Test_User_Manager extends \Test\TestCase {
}
public function testGetAttributesMinimal() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
- $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
+ $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr);
$manager->setLdapAccess($access);
$attributes = $manager->getAttributes(true);
diff --git a/apps/user_ldap/tests/user/user.php b/apps/user_ldap/tests/user/user.php
index 19581d835d1..6fa7f3b6b27 100644
--- a/apps/user_ldap/tests/user/user.php
+++ b/apps/user_ldap/tests/user/user.php
@@ -3,8 +3,9 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,7 +25,15 @@
namespace OCA\user_ldap\tests;
use OCA\user_ldap\lib\user\User;
+use OCP\IUserManager;
+/**
+ * Class Test_User_User
+ *
+ * @group DB
+ *
+ * @package OCA\user_ldap\tests
+ */
class Test_User_User extends \Test\TestCase {
private function getTestInstances() {
@@ -35,11 +44,12 @@ class Test_User_User extends \Test\TestCase {
$avaMgr = $this->getMock('\OCP\IAvatarManager');
$image = $this->getMock('\OCP\Image');
$dbc = $this->getMock('\OCP\IDBConnection');
+ $userMgr = $this->getMock('\OCP\IUserManager');
- return array($access, $config, $filesys, $image, $log, $avaMgr, $dbc);
+ return array($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr);
}
- private function getAdvancedMocks($cfMock, $fsMock, $logMock, $avaMgr, $dbc) {
+ private function getAdvancedMocks($cfMock, $fsMock, $logMock, $avaMgr, $dbc, $userMgr = null) {
static $conMethods;
static $accMethods;
static $umMethods;
@@ -53,8 +63,11 @@ class Test_User_User extends \Test\TestCase {
}
$lw = $this->getMock('\OCA\user_ldap\lib\ILDAPWrapper');
$im = $this->getMock('\OCP\Image');
+ if (is_null($userMgr)) {
+ $userMgr = $this->getMock('\OCP\IUserManager');
+ }
$um = $this->getMock('\OCA\user_ldap\lib\user\Manager',
- $umMethods, array($cfMock, $fsMock, $logMock, $avaMgr, $im, $dbc));
+ $umMethods, array($cfMock, $fsMock, $logMock, $avaMgr, $im, $dbc, $userMgr));
$connector = $this->getMock('\OCA\user_ldap\lib\Connection',
$conMethods, array($lw, null, null));
$access = $this->getMock('\OCA\user_ldap\lib\Access',
@@ -64,25 +77,25 @@ class Test_User_User extends \Test\TestCase {
}
public function testGetDNandUsername() {
- list($access, $config, $filesys, $image, $log, $avaMgr) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $db, $userMgr) =
$this->getTestInstances();
$uid = 'alice';
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$this->assertSame($dn, $user->getDN());
$this->assertSame($uid, $user->getUsername());
}
public function testUpdateEmailProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
- $this->getAdvancedMocks($config, $filesys, $log, $avaMgr, $dbc);
+ $this->getAdvancedMocks($config, $filesys, $log, $avaMgr, $dbc, $userMgr);
$connection->expects($this->once())
->method('__get')
@@ -95,24 +108,27 @@ class Test_User_User extends \Test\TestCase {
$this->equalTo('email'))
->will($this->returnValue(array('alice@foo.bar')));
- $config->expects($this->once())
- ->method('setUserValue')
- ->with($this->equalTo('alice'), $this->equalTo('settings'),
- $this->equalTo('email'),
- $this->equalTo('alice@foo.bar'))
- ->will($this->returnValue(true));
-
$uid = 'alice';
$dn = 'uid=alice,dc=foo,dc=bar';
+ $uuser = $this->getMockBuilder('\OCP\IUser')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $uuser->expects($this->once())
+ ->method('setEMailAddress')
+ ->with('alice@foo.bar');
+ /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject $userMgr */
+ $userMgr->expects($this->any())
+ ->method('get')
+ ->willReturn($uuser);
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateEmail();
}
public function testUpdateEmailNotProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -136,13 +152,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateEmail();
}
public function testUpdateEmailNotConfigured() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -163,13 +179,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateEmail();
}
public function testUpdateQuotaAllProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -206,13 +222,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateQuota();
}
public function testUpdateQuotaDefaultProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -249,13 +265,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateQuota();
}
public function testUpdateQuotaIndividualProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -292,13 +308,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateQuota();
}
public function testUpdateQuotaNoneProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -330,13 +346,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateQuota();
}
public function testUpdateQuotaNoneConfigured() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -365,13 +381,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateQuota();
}
public function testUpdateQuotaFromValue() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -404,14 +420,14 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateQuota($readQuota);
}
//the testUpdateAvatar series also implicitely tests getAvatarImage
public function testUpdateAvatarJpegPhotoProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -454,13 +470,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateAvatar();
}
public function testUpdateAvatarThumbnailPhotoProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -512,13 +528,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateAvatar();
}
public function testUpdateAvatarNotProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -558,13 +574,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->updateAvatar();
}
public function testUpdateBeforeFirstLogin() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -594,13 +610,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->update();
}
public function testUpdateAfterFirstLogin() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -634,13 +650,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->update();
}
public function testUpdateNoRefresh() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -670,13 +686,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->update();
}
public function testMarkLogin() {
- list($access, $config, $filesys, $image, $log, $avaMgr) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $db, $userMgr) =
$this->getTestInstances();
$config->expects($this->once())
@@ -691,13 +707,13 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->markLogin();
}
public function testGetAvatarImageProvided() {
- list($access, $config, $filesys, $image, $log, $avaMgr) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $db, $userMgr) =
$this->getTestInstances();
$access->expects($this->once())
@@ -710,7 +726,7 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$photo = $user->getAvatarImage();
$this->assertSame('this is a photo', $photo);
@@ -720,7 +736,7 @@ class Test_User_User extends \Test\TestCase {
}
public function testProcessAttributes() {
- list(, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -740,7 +756,7 @@ class Test_User_User extends \Test\TestCase {
);
$userMock = $this->getMockBuilder('OCA\user_ldap\lib\user\User')
- ->setConstructorArgs(array($uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr))
+ ->setConstructorArgs(array($uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr))
->setMethods($requiredMethods)
->getMock();
@@ -787,7 +803,7 @@ class Test_User_User extends \Test\TestCase {
* @dataProvider emptyHomeFolderAttributeValueProvider
*/
public function testGetHomePathNotConfigured($attributeValue) {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -808,14 +824,14 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$path = $user->getHomePath();
$this->assertSame($path, false);
}
public function testGetHomePathConfiguredNotAvailableAllowed() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
@@ -839,7 +855,7 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$path = $user->getHomePath();
@@ -850,11 +866,11 @@ class Test_User_User extends \Test\TestCase {
* @expectedException \Exception
*/
public function testGetHomePathConfiguredNotAvailableNotAllowed() {
- list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
+ list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr) =
$this->getTestInstances();
list($access, $connection) =
- $this->getAdvancedMocks($config, $filesys, $log, $avaMgr, $dbc);
+ $this->getAdvancedMocks($config, $filesys, $log, $avaMgr, $dbc, $userMgr);
$connection->expects($this->any())
->method('__get')
@@ -874,7 +890,7 @@ class Test_User_User extends \Test\TestCase {
$dn = 'uid=alice,dc=foo,dc=bar';
$user = new User(
- $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr);
+ $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr);
$user->getHomePath();
}
diff --git a/apps/user_ldap/tests/user_ldap.php b/apps/user_ldap/tests/user_ldap.php
index 0f70c43fc11..0ae18a2aa96 100644
--- a/apps/user_ldap/tests/user_ldap.php
+++ b/apps/user_ldap/tests/user_ldap.php
@@ -5,9 +5,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,6 +32,13 @@ use \OCA\user_ldap\lib\Access;
use \OCA\user_ldap\lib\Connection;
use \OCA\user_ldap\lib\ILDAPWrapper;
+/**
+ * Class Test_User_Ldap_Direct
+ *
+ * @group DB
+ *
+ * @package OCA\user_ldap\tests
+ */
class Test_User_Ldap_Direct extends \Test\TestCase {
protected $backend;
protected $access;
@@ -63,14 +71,27 @@ class Test_User_Ldap_Direct extends \Test\TestCase {
array($lw, null, null));
$this->configMock = $this->getMock('\OCP\IConfig');
- $um = new \OCA\user_ldap\lib\user\Manager(
+
+ $offlineUser = $this->getMockBuilder('\OCA\user_ldap\lib\user\OfflineUser')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $um = $this->getMockBuilder('\OCA\user_ldap\lib\user\Manager')
+ ->setMethods(['getDeletedUser'])
+ ->setConstructorArgs([
$this->configMock,
$this->getMock('\OCA\user_ldap\lib\FilesystemHelper'),
$this->getMock('\OCA\user_ldap\lib\LogWrapper'),
$this->getMock('\OCP\IAvatarManager'),
$this->getMock('\OCP\Image'),
- $this->getMock('\OCP\IDBConnection')
- );
+ $this->getMock('\OCP\IDBConnection'),
+ $this->getMock('\OCP\IUserManager')
+ ])
+ ->getMock();
+
+ $um->expects($this->any())
+ ->method('getDeletedUser')
+ ->will($this->returnValue($offlineUser));
$access = $this->getMock('\OCA\user_ldap\lib\Access',
$accMethods,
@@ -294,7 +315,7 @@ class Test_User_Ldap_Direct extends \Test\TestCase {
$access->expects($this->any())
->method('combineFilterWithAnd')
->will($this->returnCallback(function($param) {
- return $param[1];
+ return $param[2];
}));
$access->expects($this->any())
@@ -654,6 +675,44 @@ class Test_User_Ldap_Direct extends \Test\TestCase {
$this->assertFalse($result);
}
+ /**
+ * @expectedException \OC\User\NoUserException
+ */
+ public function testGetHomeDeletedUser() {
+ $access = $this->getAccessMock();
+ $backend = new UserLDAP($access, $this->getMock('\OCP\IConfig'));
+ $this->prepareMockForUserExists($access);
+
+ $access->connection->expects($this->any())
+ ->method('__get')
+ ->will($this->returnCallback(function($name) {
+ if($name === 'homeFolderNamingRule') {
+ return 'attr:testAttribute';
+ }
+ return null;
+ }));
+
+ $access->expects($this->any())
+ ->method('readAttribute')
+ ->will($this->returnValue([]));
+
+ $userMapper = $this->getMockBuilder('\OCA\User_LDAP\Mapping\UserMapping')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $access->expects($this->any())
+ ->method('getUserMapper')
+ ->will($this->returnValue($userMapper));
+
+ $this->configMock->expects($this->any())
+ ->method('getUserValue')
+ ->will($this->returnValue(true));
+
+ //no path at all – triggers OC default behaviour
+ $result = $backend->getHome('newyorker');
+ $this->assertFalse($result);
+ }
+
private function prepareAccessForGetDisplayName(&$access) {
$access->connection->expects($this->any())
->method('__get')
@@ -679,6 +738,14 @@ class Test_User_Ldap_Direct extends \Test\TestCase {
return false;
}
}));
+
+ $userMapper = $this->getMockBuilder('\OCA\User_LDAP\Mapping\UserMapping')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $access->expects($this->any())
+ ->method('getUserMapper')
+ ->will($this->returnValue($userMapper));
}
public function testGetDisplayName() {
diff --git a/apps/user_ldap/tests/wizard.php b/apps/user_ldap/tests/wizard.php
index 7b046187831..33fb2712e23 100644
--- a/apps/user_ldap/tests/wizard.php
+++ b/apps/user_ldap/tests/wizard.php
@@ -3,9 +3,10 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Viktor Szépe <viktor@szepe.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,6 +32,13 @@ use \OCA\user_ldap\lib\Wizard;
// use \OCA\user_ldap\lib\Configuration;
// use \OCA\user_ldap\lib\ILDAPWrapper;
+/**
+ * Class Test_Wizard
+ *
+ * @group DB
+ *
+ * @package OCA\user_ldap\tests
+ */
class Test_Wizard extends \Test\TestCase {
protected function setUp() {
parent::setUp();
diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php
index fc8ce361637..65a4bbdda77 100644
--- a/apps/user_ldap/user_ldap.php
+++ b/apps/user_ldap/user_ldap.php
@@ -6,12 +6,13 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Renaud Fortier <Renaud.Fortier@fsaa.ulaval.ca>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,6 +31,7 @@
namespace OCA\user_ldap;
+use OC\User\NoUserException;
use OCA\user_ldap\lib\BackendUtility;
use OCA\user_ldap\lib\Access;
use OCA\user_ldap\lib\user\OfflineUser;
@@ -117,6 +119,7 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
try {
$ldapRecord = $this->getLDAPUserByLoginName($uid);
} catch(\Exception $e) {
+ \OC::$server->getLogger()->logException($e, ['app' => 'user_ldap']);
return false;
}
$dn = $ldapRecord['dn'][0];
@@ -149,8 +152,8 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
* Get a list of all users
*
* @param string $search
- * @param null|int $limit
- * @param null|int $offset
+ * @param integer $limit
+ * @param integer $offset
* @return string[] an array of all uids
*/
public function getUsers($search = '', $limit = 10, $offset = 0) {
@@ -170,6 +173,7 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
$filter = $this->access->combineFilterWithAnd(array(
$this->access->connection->ldapUserFilter,
+ $this->access->connection->ldapUserDisplayName . '=*',
$this->access->getFilterPartForUserSearch($search)
));
@@ -190,26 +194,44 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
/**
* checks whether a user is still available on LDAP
+ *
* @param string|\OCA\User_LDAP\lib\user\User $user either the ownCloud user
* name or an instance of that user
* @return bool
+ * @throws \Exception
+ * @throws \OC\ServerNotAvailableException
*/
public function userExistsOnLDAP($user) {
if(is_string($user)) {
$user = $this->access->userManager->get($user);
}
- if(!$user instanceof User) {
+ if(is_null($user)) {
return false;
}
$dn = $user->getDN();
//check if user really still exists by reading its entry
- if(!is_array($this->access->readAttribute($dn, ''))) {
+ if(!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) {
$lcr = $this->access->connection->getConnectionResource();
if(is_null($lcr)) {
throw new \Exception('No LDAP Connection to server ' . $this->access->connection->ldapHost);
}
- return false;
+
+ try {
+ $uuid = $this->access->getUserMapper()->getUUIDByDN($dn);
+ if(!$uuid) {
+ return false;
+ }
+ $newDn = $this->access->getUserDnByUuid($uuid);
+ $this->access->getUserMapper()->setDNbyUUID($newDn, $uuid);
+ return true;
+ } catch (\Exception $e) {
+ return false;
+ }
+ }
+
+ if($user instanceof OfflineUser) {
+ $user->unmark();
}
return true;
@@ -274,10 +296,13 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
/**
- * get the user's home directory
- * @param string $uid the username
- * @return string|bool
- */
+ * get the user's home directory
+ *
+ * @param string $uid the username
+ * @return bool|string
+ * @throws NoUserException
+ * @throws \Exception
+ */
public function getHome($uid) {
if(isset($this->homesToKill[$uid]) && !empty($this->homesToKill[$uid])) {
//a deleted user who needs some clean up
@@ -295,6 +320,15 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
$user = $this->access->userManager->get($uid);
+ if(is_null($user) || ($user instanceof OfflineUser && !$this->userExistsOnLDAP($user->getOCName()))) {
+ throw new NoUserException($uid . ' is not a valid user anymore');
+ }
+ if($user instanceof OfflineUser) {
+ // apparently this user survived the userExistsOnLDAP check,
+ // we request the user instance again in order to retrieve a User
+ // instance instead
+ $user = $this->access->userManager->get($uid);
+ }
$path = $user->getHomePath();
$this->access->cacheUserHome($uid, $path);
diff --git a/apps/user_ldap/user_proxy.php b/apps/user_ldap/user_proxy.php
index 2582355e4a3..9ea0b6dd235 100644
--- a/apps/user_ldap/user_proxy.php
+++ b/apps/user_ldap/user_proxy.php
@@ -4,10 +4,10 @@
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/autotest-external.sh b/autotest-external.sh
index b738669b48c..6128f68136f 100755
--- a/autotest-external.sh
+++ b/autotest-external.sh
@@ -175,57 +175,63 @@ EOF
fi
if [ -n "$2" -a "$2" == "common-tests" ]; then
- return;
+ return;
fi
- FILES_EXTERNAL_BACKEND_PATH=../apps/files_external/tests/backends
- FILES_EXTERNAL_BACKEND_ENV_PATH=../apps/files_external/tests/env
+ FILES_EXTERNAL_BACKEND_PATH=../apps/files_external/tests/backends
+ FILES_EXTERNAL_BACKEND_ENV_PATH=../apps/files_external/tests/env
for startFile in `ls -1 $FILES_EXTERNAL_BACKEND_ENV_PATH | grep start`; do
- name=`echo $startFile | sed 's/start-//' | sed 's/\.sh//'`
-
- if [ -n "$2" -a "$2" != "$name" ]; then
- echo "skip: $startFile"
- continue;
- fi
-
- echo "start: $startFile"
- echo "name: $name"
-
- # execute start file
- ./$FILES_EXTERNAL_BACKEND_ENV_PATH/$startFile
-
- # getting backend to test from filename
- # it's the part between the dots startSomething.TestToRun.sh
- testToRun=`echo $startFile | cut -d '-' -f 2`
-
- # run the specific test
- if [ -z "$NOCOVERAGE" ]; then
- rm -rf "coverage-external-html-$1-$name"
- mkdir "coverage-external-html-$1-$name"
- "$PHPUNIT" --configuration phpunit-autotest-external.xml --log-junit "autotest-external-results-$1-$name.xml" --coverage-clover "autotest-external-clover-$1-$name.xml" --coverage-html "coverage-external-html-$1-$name" "$FILES_EXTERNAL_BACKEND_PATH/$testToRun.php"
- RESULT=$?
- else
- echo "No coverage"
- "$PHPUNIT" --configuration phpunit-autotest-external.xml --log-junit "autotest-external-results-$1-$name.xml" "$FILES_EXTERNAL_BACKEND_PATH/$testToRun.php"
- RESULT=$?
- fi
-
- # calculate stop file
- stopFile=`echo "$startFile" | sed 's/start/stop/'`
- echo "stop: $stopFile"
- if [ -f $FILES_EXTERNAL_BACKEND_ENV_PATH/$stopFile ]; then
- # execute stop file if existant
- ./$FILES_EXTERNAL_BACKEND_ENV_PATH/$stopFile
- fi
+ name=`echo $startFile | sed 's/start-//' | sed 's/\.sh//'`
+
+ if [ -n "$2" -a "$2" != "$name" ]; then
+ echo "skip: $startFile"
+ continue;
+ fi
+
+ echo "start: $startFile"
+ echo "name: $name"
+
+ # execute start file
+ ./$FILES_EXTERNAL_BACKEND_ENV_PATH/$startFile
+ if [ $? -eq 0 ]; then
+ # getting backend to test from filename
+ # it's the part between the dots startSomething.TestToRun.sh
+ testToRun=`echo $startFile | cut -d '-' -f 2`
+
+ # run the specific test
+ if [ -z "$NOCOVERAGE" ]; then
+ rm -rf "coverage-external-html-$1-$name"
+ mkdir "coverage-external-html-$1-$name"
+ "$PHPUNIT" --configuration phpunit-autotest-external.xml --log-junit "autotest-external-results-$1-$name.xml" --coverage-clover "autotest-external-clover-$1-$name.xml" --coverage-html "coverage-external-html-$1-$name" "$FILES_EXTERNAL_BACKEND_PATH/$testToRun.php"
+ RESULT=$?
+ else
+ echo "No coverage"
+ "$PHPUNIT" --configuration phpunit-autotest-external.xml --log-junit "autotest-external-results-$1-$name.xml" "$FILES_EXTERNAL_BACKEND_PATH/$testToRun.php"
+ RESULT=$?
+ fi
+ else
+ DOEXIT=1
+ fi
+
+ # calculate stop file
+ stopFile=`echo "$startFile" | sed 's/start/stop/'`
+ echo "stop: $stopFile"
+ if [ -f $FILES_EXTERNAL_BACKEND_ENV_PATH/$stopFile ]; then
+ # execute stop file if existant
+ ./$FILES_EXTERNAL_BACKEND_ENV_PATH/$stopFile
+ fi
+ if [ "$DOEXIT" ]; then
+ echo "Error during start file execution ... terminating"
+ exit $DOEXIT
+ fi
done;
}
#
# start test execution
#
-if [ -z "$1" ]
- then
+if [ -z "$1" ]; then
# run all known database configs
for DBCONFIG in $DBCONFIGS; do
execute_tests $DBCONFIG "$2"
diff --git a/autotest.sh b/autotest.sh
index f0efc45ccca..5196d5c31d5 100755
--- a/autotest.sh
+++ b/autotest.sh
@@ -260,14 +260,23 @@ function execute_tests {
if [[ "$_XDEBUG_CONFIG" ]]; then
export XDEBUG_CONFIG=$_XDEBUG_CONFIG
fi
+ GROUP=''
+ if [ "$TEST_SELECTION" == "DB" ]; then
+ GROUP='--group DB'
+ fi
+ if [ "$TEST_SELECTION" == "NODB" ]; then
+ GROUP='--exclude-group DB'
+ fi
+
+ COVER=''
if [ -z "$NOCOVERAGE" ]; then
- "${PHPUNIT[@]}" --configuration phpunit-autotest.xml --log-junit "autotest-results-$DB.xml" --coverage-clover "autotest-clover-$DB.xml" --coverage-html "coverage-html-$DB" "$2" "$3"
- RESULT=$?
+ COVER="--coverage-clover autotest-clover-$DB.xml --coverage-html coverage-html-$DB"
else
echo "No coverage"
- "${PHPUNIT[@]}" --configuration phpunit-autotest.xml --log-junit "autotest-results-$DB.xml" "$2" "$3"
- RESULT=$?
fi
+ echo "${PHPUNIT[@]}" --configuration phpunit-autotest.xml $GROUP $COVER --log-junit "autotest-results-$DB.xml" "$2" "$3"
+ "${PHPUNIT[@]}" --configuration phpunit-autotest.xml $GROUP $COVER --log-junit "autotest-results-$DB.xml" "$2" "$3"
+ RESULT=$?
if [ "$PRIMARY_STORAGE_CONFIG" == "swift" ] ; then
cd ..
diff --git a/bower.json b/bower.json
index e8bb9a35f32..ae9575249c9 100644
--- a/bower.json
+++ b/bower.json
@@ -26,7 +26,10 @@
"snapjs": "~2.0.0-rc1",
"strengthify": "0.4.2",
"underscore": "~1.8.0",
- "bootstrap": "~3.3.5",
- "backbone": "~1.2.1"
+ "bootstrap": "~3.3.6",
+ "backbone": "~1.2.3",
+ "davclient.js": "https://github.com/evert/davclient.js.git",
+ "es6-promise": "https://github.com/jakearchibald/es6-promise.git#~2.3.0",
+ "base64": "~0.3.0"
}
}
diff --git a/build/integration/capabilities_features/capabilities.feature b/build/integration/capabilities_features/capabilities.feature
new file mode 100644
index 00000000000..3c1eb025ec7
--- /dev/null
+++ b/build/integration/capabilities_features/capabilities.feature
@@ -0,0 +1,217 @@
+Feature: capabilities
+ Background:
+ Given using api version "1"
+
+ Scenario: getting capabilities with admin user
+ Given As an "admin"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | 1 |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Changing public upload
+ Given As an "admin"
+ And parameter "shareapi_allow_public_upload" of app "core" is set to "no"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | EMPTY |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Disabling share api
+ Given As an "admin"
+ And parameter "shareapi_enabled" of app "core" is set to "no"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | EMPTY |
+ | files_sharing | public@@@enabled | EMPTY |
+ | files_sharing | public@@@upload | EMPTY |
+ | files_sharing | resharing | EMPTY |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Disabling public links
+ Given As an "admin"
+ And parameter "shareapi_allow_links" of app "core" is set to "no"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | EMPTY |
+ | files_sharing | public@@@upload | EMPTY |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Changing resharing
+ Given As an "admin"
+ And parameter "shareapi_allow_resharing" of app "core" is set to "no"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | 1 |
+ | files_sharing | resharing | EMPTY |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Changing federation outgoing
+ Given As an "admin"
+ And parameter "outgoing_server2server_share_enabled" of app "files_sharing" is set to "no"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | 1 |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | EMPTY |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Changing federation incoming
+ Given As an "admin"
+ And parameter "incoming_server2server_share_enabled" of app "files_sharing" is set to "no"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | 1 |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | EMPTY |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Changing password enforce
+ Given As an "admin"
+ And parameter "shareapi_enforce_links_password" of app "core" is set to "yes"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | 1 |
+ | files_sharing | public@@@password@@@enforced | 1 |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Changing public notifications
+ Given As an "admin"
+ And parameter "shareapi_allow_public_notification" of app "core" is set to "yes"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | 1 |
+ | files_sharing | public@@@send_mail | 1 |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Changing expire date
+ Given As an "admin"
+ And parameter "shareapi_default_expire_date" of app "core" is set to "yes"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | 1 |
+ | files_sharing | public@@@expire_date@@@enabled | 1 |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Changing expire date enforcing
+ Given As an "admin"
+ And parameter "shareapi_default_expire_date" of app "core" is set to "yes"
+ And parameter "shareapi_enforce_expire_date" of app "core" is set to "yes"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | 1 |
+ | files_sharing | public@@@expire_date@@@enabled | 1 |
+ | files_sharing | public@@@expire_date@@@enforced | 1 |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
diff --git a/build/integration/composer.json b/build/integration/composer.json
index 2f0f8a815ce..a9516391a41 100644
--- a/build/integration/composer.json
+++ b/build/integration/composer.json
@@ -3,6 +3,7 @@
"phpunit/phpunit": "~4.6",
"behat/behat": "^3.0",
"guzzlehttp/guzzle": "~5.0",
- "jarnaiz/behat-junit-formatter": "^1.3"
+ "jarnaiz/behat-junit-formatter": "^1.3",
+ "sabre/dav": "3.0.x-dev"
}
}
diff --git a/build/integration/config/behat.yml b/build/integration/config/behat.yml
index c9d6754a0fa..42f5f88ac8a 100644
--- a/build/integration/config/behat.yml
+++ b/build/integration/config/behat.yml
@@ -12,6 +12,28 @@ default:
- admin
- admin
regular_user_password: 123456
+ federation:
+ paths:
+ - %paths.base%/../federation_features
+ contexts:
+ - FederationContext:
+ baseUrl: http://localhost:8080/ocs/
+ admin:
+ - admin
+ - admin
+ regular_user_password: 123456
+ capabilities:
+ paths:
+ - %paths.base%/../capabilities_features
+ contexts:
+ - CapabilitiesContext:
+ baseUrl: http://localhost:8080/ocs/
+ admin:
+ - admin
+ - admin
+ regular_user_password: 123456
+
+
extensions:
jarnaiz\JUnitFormatter\JUnitFormatterExtension:
diff --git a/build/integration/data/textfile.txt b/build/integration/data/textfile.txt
new file mode 100644
index 00000000000..efffdeff159
--- /dev/null
+++ b/build/integration/data/textfile.txt
@@ -0,0 +1,3 @@
+This is a testfile.
+
+Cheers. \ No newline at end of file
diff --git a/build/integration/features/bootstrap/BasicStructure.php b/build/integration/features/bootstrap/BasicStructure.php
new file mode 100644
index 00000000000..bf3b1d50814
--- /dev/null
+++ b/build/integration/features/bootstrap/BasicStructure.php
@@ -0,0 +1,188 @@
+<?php
+
+use Behat\Behat\Context\Context;
+use Behat\Behat\Context\SnippetAcceptingContext;
+use GuzzleHttp\Client;
+use GuzzleHttp\Message\ResponseInterface;
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+trait BasicStructure{
+ /** @var string */
+ private $currentUser = '';
+
+ /** @var string */
+ private $currentServer = '';
+
+ /** @var string */
+ private $baseUrl = '';
+
+ /** @var ResponseInterface */
+ private $response = null;
+
+ public function __construct($baseUrl, $admin, $regular_user_password) {
+
+ // Initialize your context here
+ $this->baseUrl = $baseUrl;
+ $this->adminUser = $admin;
+ $this->regularUser = $regular_user_password;
+ $this->localBaseUrl = substr($this->baseUrl, 0, -4);
+ $this->remoteBaseUrl = substr($this->baseUrl, 0, -4);
+ $this->currentServer = 'LOCAL';
+
+ // in case of ci deployment we take the server url from the environment
+ $testServerUrl = getenv('TEST_SERVER_URL');
+ if ($testServerUrl !== false) {
+ $this->baseUrl = $testServerUrl;
+ $this->localBaseUrl = $testServerUrl;
+ }
+
+ // federated server url from the environment
+ $testRemoteServerUrl = getenv('TEST_SERVER_FED_URL');
+ if ($testRemoteServerUrl !== false) {
+ $this->remoteBaseUrl = $testRemoteServerUrl;
+ }
+ }
+
+ /**
+ * @Given /^As an "([^"]*)"$/
+ */
+ public function asAn($user) {
+ $this->currentUser = $user;
+ }
+
+ /**
+ * @Given /^Using server "([^"]*)"$/
+ */
+ public function usingServer($server) {
+ if ($server === 'LOCAL'){
+ $this->baseUrl = $this->localBaseUrl;
+ $this->currentServer = 'LOCAL';
+ } elseif ($server === 'REMOTE'){
+ $this->baseUrl = $this->remoteBaseUrl;
+ $this->currentServer = 'REMOTE';
+ } else{
+ PHPUnit_Framework_Assert::fail("Server can only be LOCAL or REMOTE");
+ }
+ }
+
+ /**
+ * @When /^sending "([^"]*)" to "([^"]*)"$/
+ */
+ public function sendingTo($verb, $url) {
+ $this->sendingToWith($verb, $url, null);
+ }
+
+ /**
+ * Parses the xml answer to get ocs response which doesn't match with
+ * http one in v1 of the api.
+ * @param ResponseInterface $response
+ * @return string
+ */
+ public function getOCSResponse($response) {
+ return $response->xml()->meta[0]->statuscode;
+ }
+
+ /**
+ * This function is needed to use a vertical fashion in the gherkin tables.
+ */
+ public function simplifyArray($arrayOfArrays){
+ $a = array_map(function($subArray) { return $subArray[0]; }, $arrayOfArrays);
+ return $a;
+ }
+
+ /**
+ * @When /^sending "([^"]*)" to "([^"]*)" with$/
+ * @param \Behat\Gherkin\Node\TableNode|null $formData
+ */
+ public function sendingToWith($verb, $url, $body) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php" . $url;
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$this->currentUser, $this->regularUser];
+ }
+ if ($body instanceof \Behat\Gherkin\Node\TableNode) {
+ $fd = $body->getRowsHash();
+ $options['body'] = $fd;
+ }
+
+ try {
+ $this->response = $client->send($client->createRequest($verb, $fullUrl, $options));
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $this->response = $ex->getResponse();
+ }
+ }
+
+ public function isExpectedUrl($possibleUrl, $finalPart){
+ $baseUrlChopped = substr($this->baseUrl, 0, -4);
+ $endCharacter = strlen($baseUrlChopped) + strlen($finalPart);
+ return (substr($possibleUrl,0,$endCharacter) == "$baseUrlChopped" . "$finalPart");
+ }
+
+ /**
+ * @Then /^the OCS status code should be "([^"]*)"$/
+ */
+ public function theOCSStatusCodeShouldBe($statusCode) {
+ PHPUnit_Framework_Assert::assertEquals($statusCode, $this->getOCSResponse($this->response));
+ }
+
+ /**
+ * @Then /^the HTTP status code should be "([^"]*)"$/
+ */
+ public function theHTTPStatusCodeShouldBe($statusCode) {
+ PHPUnit_Framework_Assert::assertEquals($statusCode, $this->response->getStatusCode());
+ }
+
+ public static function removeFile($path, $filename){
+ if (file_exists("$path" . "$filename")) {
+ unlink("$path" . "$filename");
+ }
+ }
+
+ /**
+ * @BeforeSuite
+ */
+ public static function addFilesToSkeleton(){
+ for ($i=0; $i<5; $i++){
+ file_put_contents("../../core/skeleton/" . "textfile" . "$i" . ".txt", "ownCloud test text file\n");
+ }
+ if (!file_exists("../../core/skeleton/FOLDER")) {
+ mkdir("../../core/skeleton/FOLDER", 0777, true);
+ }
+ if (!file_exists("../../core/skeleton/PARENT")) {
+ mkdir("../../core/skeleton/PARENT", 0777, true);
+ }
+ file_put_contents("../../core/skeleton/PARENT/" . "parent.txt", "ownCloud test text file\n");
+ if (!file_exists("../../core/skeleton/PARENT/CHILD")) {
+ mkdir("../../core/skeleton/PARENT/CHILD", 0777, true);
+ }
+ file_put_contents("../../core/skeleton/PARENT/CHILD/" . "child.txt", "ownCloud test text file\n");
+
+ }
+
+ /**
+ * @AfterSuite
+ */
+ public static function removeFilesFromSkeleton(){
+ for ($i=0; $i<5; $i++){
+ self::removeFile("../../core/skeleton/", "textfile" . "$i" . ".txt");
+ }
+ if (is_dir("../../core/skeleton/FOLDER")) {
+ rmdir("../../core/skeleton/FOLDER");
+ }
+ self::removeFile("../../core/skeleton/PARENT/CHILD/", "child.txt");
+ if (is_dir("../../core/skeleton/PARENT/CHILD")) {
+ rmdir("../../core/skeleton/PARENT/CHILD");
+ }
+ self::removeFile("../../core/skeleton/PARENT/", "parent.txt");
+ if (is_dir("../../core/skeleton/PARENT")) {
+ rmdir("../../core/skeleton/PARENT");
+ }
+
+
+ }
+}
+
diff --git a/build/integration/features/bootstrap/CapabilitiesContext.php b/build/integration/features/bootstrap/CapabilitiesContext.php
new file mode 100644
index 00000000000..d30984f0db7
--- /dev/null
+++ b/build/integration/features/bootstrap/CapabilitiesContext.php
@@ -0,0 +1,134 @@
+<?php
+
+use Behat\Behat\Context\Context;
+use Behat\Behat\Context\SnippetAcceptingContext;
+use Behat\Behat\Hook\Scope\AfterScenarioScope;
+use Behat\Behat\Hook\Scope\BeforeScenarioScope;
+use GuzzleHttp\Client;
+use GuzzleHttp\Message\ResponseInterface;
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+/**
+ * Capabilities context.
+ */
+class CapabilitiesContext implements Context, SnippetAcceptingContext {
+
+ use BasicStructure;
+ use Provisioning;
+ use Sharing;
+
+ /**
+ * @Given /^parameter "([^"]*)" of app "([^"]*)" is set to "([^"]*)"$/
+ */
+ public function serverParameterIsSetTo($parameter, $app, $value){
+ $user = $this->currentUser;
+ $this->currentUser = 'admin';
+
+ $this->modifyServerConfig($app, $parameter, $value);
+
+ $this->currentUser = $user;
+ }
+
+ /**
+ * @Then /^fields of capabilities match with$/
+ * @param \Behat\Gherkin\Node\TableNode|null $formData
+ */
+ public function checkCapabilitiesResponse(\Behat\Gherkin\Node\TableNode $formData){
+ $capabilitiesXML = $this->response->xml()->data->capabilities;
+
+ foreach ($formData->getHash() as $row) {
+ $path_to_element = explode('@@@', $row['path_to_element']);
+ $answeredValue = $capabilitiesXML->$row['capability'];
+ for ($i = 0; $i < count($path_to_element); $i++){
+ $answeredValue = $answeredValue->$path_to_element[$i];
+ }
+ $answeredValue = (string)$answeredValue;
+ PHPUnit_Framework_Assert::assertEquals(
+ $row['value']==="EMPTY" ? '' : $row['value'],
+ $answeredValue,
+ "Failed field " . $row['capability'] . " " . $row['path_to_element']
+ );
+
+ }
+ }
+
+ protected function resetAppConfigs() {
+ $this->modifyServerConfig('core', 'shareapi_enabled', 'yes');
+ $this->modifyServerConfig('core', 'shareapi_allow_links', 'yes');
+ $this->modifyServerConfig('core', 'shareapi_allow_public_upload', 'yes');
+ $this->modifyServerConfig('core', 'shareapi_allow_resharing', 'yes');
+ $this->modifyServerConfig('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
+ $this->modifyServerConfig('files_sharing', 'incoming_server2server_share_enabled', 'yes');
+ $this->modifyServerConfig('core', 'shareapi_enforce_links_password', 'no');
+ $this->modifyServerConfig('core', 'shareapi_allow_public_notification', 'no');
+ $this->modifyServerConfig('core', 'shareapi_default_expire_date', 'no');
+ $this->modifyServerConfig('core', 'shareapi_enforce_expire_date', 'no');
+ }
+
+ /**
+ * @BeforeScenario
+ *
+ * Enable the testing app before the first scenario of the feature and
+ * reset the configs before each scenario
+ * @param BeforeScenarioScope $event
+ */
+ public function prepareParameters(BeforeScenarioScope $event){
+ $user = $this->currentUser;
+ $this->currentUser = 'admin';
+
+ $scenarios = $event->getFeature()->getScenarios();
+ if ($event->getScenario() === reset($scenarios)) {
+ $this->setStatusTestingApp(true);
+ }
+
+ $this->resetAppConfigs();
+
+ $this->currentUser = $user;
+ }
+
+ /**
+ * @AfterScenario
+ *
+ * Reset the values after the last scenario of the feature and disable the testing app
+ * @param AfterScenarioScope $event
+ */
+ public function undoChangingParameters(AfterScenarioScope $event) {
+ $scenarios = $event->getFeature()->getScenarios();
+ if ($event->getScenario() === end($scenarios)) {
+ $user = $this->currentUser;
+ $this->currentUser = 'admin';
+
+ $this->resetAppConfigs();
+
+ $this->setStatusTestingApp(false);
+ $this->currentUser = $user;
+ }
+ }
+
+ /**
+ * @param string $app
+ * @param string $parameter
+ * @param string $value
+ */
+ protected function modifyServerConfig($app, $parameter, $value) {
+ $body = new \Behat\Gherkin\Node\TableNode([['value', $value]]);
+ $this->sendingToWith('post', "/apps/testing/api/v1/app/{$app}/{$parameter}", $body);
+ $this->theHTTPStatusCodeShouldBe('200');
+ $this->theOCSStatusCodeShouldBe('100');
+ }
+
+ protected function setStatusTestingApp($enabled) {
+ $this->sendingTo(($enabled ? 'post' : 'delete'), '/cloud/apps/testing');
+ $this->theHTTPStatusCodeShouldBe('200');
+ $this->theOCSStatusCodeShouldBe('100');
+
+ $this->sendingTo('get', '/cloud/apps?filter=enabled');
+ $this->theHTTPStatusCodeShouldBe('200');
+ if ($enabled) {
+ PHPUnit_Framework_Assert::assertContains('testing', $this->response->getBody()->getContents());
+ } else {
+ PHPUnit_Framework_Assert::assertNotContains('testing', $this->response->getBody()->getContents());
+ }
+ }
+}
diff --git a/build/integration/features/bootstrap/FeatureContext.php b/build/integration/features/bootstrap/FeatureContext.php
index 46c86f1300b..78ff4e7833d 100644
--- a/build/integration/features/bootstrap/FeatureContext.php
+++ b/build/integration/features/bootstrap/FeatureContext.php
@@ -7,924 +7,13 @@ use GuzzleHttp\Message\ResponseInterface;
require __DIR__ . '/../../vendor/autoload.php';
+
/**
* Features context.
*/
class FeatureContext implements Context, SnippetAcceptingContext {
-
- /** @var string */
- private $baseUrl = '';
-
- /** @var ResponseInterface */
- private $response = null;
-
- /** @var string */
- private $currentUser = '';
-
- /** @var int */
- private $apiVersion = 1;
-
- /** @var int */
- private $sharingApiVersion = 1;
-
- /** @var SimpleXMLElement */
- private $lastShareData = null;
-
- /** @var array */
- private $createdUsers = [];
-
- /** @var array */
- private $createdGroups = [];
-
- public function __construct($baseUrl, $admin, $regular_user_password) {
-
- // Initialize your context here
- $this->baseUrl = $baseUrl;
- $this->adminUser = $admin;
- $this->regularUser = $regular_user_password;
-
- // in case of ci deployment we take the server url from the environment
- $testServerUrl = getenv('TEST_SERVER_URL');
- if ($testServerUrl !== false) {
- $this->baseUrl = $testServerUrl;
- }
- }
-
- /**
- * @When /^sending "([^"]*)" to "([^"]*)"$/
- */
- public function sendingTo($verb, $url) {
- $this->sendingToWith($verb, $url, null);
- }
-
- /**
- * Parses the xml answer to get ocs response which doesn't match with
- * http one in v1 of the api.
- */
- public function getOCSResponse($response) {
- return $response->xml()->meta[0]->statuscode;
- }
-
- /**
- * Parses the xml answer to get the array of users returned.
- */
- public function getArrayOfUsersResponded($resp) {
- $listCheckedElements = $resp->xml()->data[0]->users[0]->element;
- $extractedElementsArray = json_decode(json_encode($listCheckedElements), 1);
- return $extractedElementsArray;
- }
-
- /**
- * Parses the xml answer to get the array of groups returned.
- */
- public function getArrayOfGroupsResponded($resp) {
- $listCheckedElements = $resp->xml()->data[0]->groups[0]->element;
- $extractedElementsArray = json_decode(json_encode($listCheckedElements), 1);
- return $extractedElementsArray;
- }
-
- /**
- * Parses the xml answer to get the array of subadmins returned.
- */
- public function getArrayOfSubadminsResponded($resp) {
- $listCheckedElements = $resp->xml()->data[0]->element;
- $extractedElementsArray = json_decode(json_encode($listCheckedElements), 1);
- return $extractedElementsArray;
- }
-
- /**
- * Parses the xml answer to get the array of apps returned.
- */
- public function getArrayOfAppsResponded($resp) {
- $listCheckedElements = $resp->xml()->data[0]->apps[0]->element;
- $extractedElementsArray = json_decode(json_encode($listCheckedElements), 1);
- return $extractedElementsArray;
- }
-
- /**
- * This function is needed to use a vertical fashion in the gherkin tables.
- */
- public function simplifyArray($arrayOfArrays){
- $a = array_map(function($subArray) { return $subArray[0]; }, $arrayOfArrays);
- return $a;
- }
-
- /**
- * @Then /^users returned are$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
- */
- public function theUsersShouldBe($usersList) {
- if ($usersList instanceof \Behat\Gherkin\Node\TableNode) {
- $users = $usersList->getRows();
- $usersSimplified = $this->simplifyArray($users);
- $respondedArray = $this->getArrayOfUsersResponded($this->response);
- PHPUnit_Framework_Assert::assertEquals($usersSimplified, $respondedArray, "", 0.0, 10, true);
- }
-
- }
-
- /**
- * @Then /^groups returned are$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
- */
- public function theGroupsShouldBe($groupsList) {
- if ($groupsList instanceof \Behat\Gherkin\Node\TableNode) {
- $groups = $groupsList->getRows();
- $groupsSimplified = $this->simplifyArray($groups);
- $respondedArray = $this->getArrayOfGroupsResponded($this->response);
- PHPUnit_Framework_Assert::assertEquals($groupsSimplified, $respondedArray, "", 0.0, 10, true);
- }
-
- }
-
- /**
- * @Then /^subadmin groups returned are$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
- */
- public function theSubadminGroupsShouldBe($groupsList) {
- if ($groupsList instanceof \Behat\Gherkin\Node\TableNode) {
- $groups = $groupsList->getRows();
- $groupsSimplified = $this->simplifyArray($groups);
- $respondedArray = $this->getArrayOfSubadminsResponded($this->response);
- PHPUnit_Framework_Assert::assertEquals($groupsSimplified, $respondedArray, "", 0.0, 10, true);
- }
-
- }
-
- /**
- * @Then /^subadmin users returned are$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
- */
- public function theSubadminUsersShouldBe($groupsList) {
- $this->theSubadminGroupsShouldBe($groupsList);
- }
-
- /**
- * @Then /^apps returned are$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
- */
- public function theAppsShouldBe($appList) {
- if ($appList instanceof \Behat\Gherkin\Node\TableNode) {
- $apps = $appList->getRows();
- $appsSimplified = $this->simplifyArray($apps);
- $respondedArray = $this->getArrayOfAppsResponded($this->response);
- PHPUnit_Framework_Assert::assertEquals($appsSimplified, $respondedArray, "", 0.0, 10, true);
- }
-
- }
-
- /**
- * @Then /^the OCS status code should be "([^"]*)"$/
- */
- public function theOCSStatusCodeShouldBe($statusCode) {
- PHPUnit_Framework_Assert::assertEquals($statusCode, $this->getOCSResponse($this->response));
- }
-
- /**
- * @Then /^the HTTP status code should be "([^"]*)"$/
- */
- public function theHTTPStatusCodeShouldBe($statusCode) {
- PHPUnit_Framework_Assert::assertEquals($statusCode, $this->response->getStatusCode());
- }
-
- /**
- * @Given /^As an "([^"]*)"$/
- */
- public function asAn($user) {
- $this->currentUser = $user;
- }
-
- /**
- * @Given /^using api version "([^"]*)"$/
- */
- public function usingApiVersion($version) {
- $this->apiVersion = $version;
- }
-
- /**
- * @Given /^user "([^"]*)" exists$/
- */
- public function assureUserExists($user) {
- try {
- $this->userExists($user);
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $previous_user = $this->currentUser;
- $this->currentUser = "admin";
- $this->creatingTheUser($user);
- $this->currentUser = $previous_user;
- }
- $this->userExists($user);
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
-
- }
-
- public function userExists($user){
- $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user";
- $client = new Client();
- $options = [];
- $options['auth'] = $this->adminUser;
-
- $this->response = $client->get($fullUrl, $options);
- }
-
- /**
- * @Given /^user "([^"]*)" belongs to group "([^"]*)"$/
- */
- public function userBelongsToGroup($user, $group) {
- $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $this->response = $client->get($fullUrl, $options);
- $groups = array($group);
- $respondedArray = $this->getArrayOfGroupsResponded($this->response);
- PHPUnit_Framework_Assert::assertEquals($groups, $respondedArray, "", 0.0, 10, true);
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
- }
-
- /**
- * @Given /^user "([^"]*)" does not belong to group "([^"]*)"$/
- */
- public function userDoesNotBelongToGroup($user, $group) {
- $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $this->response = $client->get($fullUrl, $options);
- $groups = array($group);
- $respondedArray = $this->getArrayOfGroupsResponded($this->response);
- PHPUnit_Framework_Assert::assertNotEquals($groups, $respondedArray, "", 0.0, 10, true);
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
- }
-
-
- /**
- * @Given /^user "([^"]*)" is subadmin of group "([^"]*)"$/
- */
- public function userIsSubadminOfGroup($user, $group) {
- $fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group/subadmins";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $this->response = $client->get($fullUrl, $options);
- $subadmins = array($user);
- $respondedArray = $this->getArrayOfSubadminsResponded($this->response);
- sort($respondedArray);
- PHPUnit_Framework_Assert::assertContains($user, $respondedArray);
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
- }
-
- /**
- * @Given /^user "([^"]*)" is not a subadmin of group "([^"]*)"$/
- */
- public function userIsNotSubadminOfGroup($user, $group) {
- $fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group/subadmins";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $this->response = $client->get($fullUrl, $options);
- $subadmins = array($user);
- $respondedArray = $this->getArrayOfSubadminsResponded($this->response);
- sort($respondedArray);
- PHPUnit_Framework_Assert::assertNotContains($user, $respondedArray);
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
- }
-
- /**
- * @Given /^user "([^"]*)" does not exist$/
- */
- public function userDoesNotExist($user) {
- try {
- $this->userExists($user);
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $this->response = $ex->getResponse();
- PHPUnit_Framework_Assert::assertEquals(404, $ex->getResponse()->getStatusCode());
- return;
- }
- $previous_user = $this->currentUser;
- $this->currentUser = "admin";
- $this->deletingTheUser($user);
- $this->currentUser = $previous_user;
- try {
- $this->userExists($user);
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $this->response = $ex->getResponse();
- PHPUnit_Framework_Assert::assertEquals(404, $ex->getResponse()->getStatusCode());
- }
- }
-
- /**
- * @Given /^app "([^"]*)" is disabled$/
- */
- public function appIsDisabled($app) {
- $fullUrl = $this->baseUrl . "v2.php/cloud/apps?filter=disabled";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $this->response = $client->get($fullUrl, $options);
- $respondedArray = $this->getArrayOfAppsResponded($this->response);
- PHPUnit_Framework_Assert::assertContains($app, $respondedArray);
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
- }
-
- /**
- * @Given /^app "([^"]*)" is enabled$/
- */
- public function appIsEnabled($app) {
- $fullUrl = $this->baseUrl . "v2.php/cloud/apps?filter=enabled";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $this->response = $client->get($fullUrl, $options);
- $respondedArray = $this->getArrayOfAppsResponded($this->response);
- PHPUnit_Framework_Assert::assertContains($app, $respondedArray);
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
- }
-
- public function createUser($user) {
- $previous_user = $this->currentUser;
- $this->currentUser = "admin";
- $this->creatingTheUser($user);
- $this->userExists($user);
- $this->currentUser = $previous_user;
- }
-
- public function deleteUser($user) {
- $previous_user = $this->currentUser;
- $this->currentUser = "admin";
- $this->deletingTheUser($user);
- $this->userDoesNotExist($user);
- $this->currentUser = $previous_user;
- }
-
- public function createGroup($group) {
- $previous_user = $this->currentUser;
- $this->currentUser = "admin";
- $this->creatingTheGroup($group);
- $this->groupExists($group);
- $this->currentUser = $previous_user;
- }
-
- public function deleteGroup($group) {
- $previous_user = $this->currentUser;
- $this->currentUser = "admin";
- $this->deletingTheGroup($group);
- $this->groupDoesNotExist($group);
- $this->currentUser = $previous_user;
- }
-
- public function creatingTheUser($user) {
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $options['body'] = [
- 'userid' => $user,
- 'password' => '123456'
- ];
-
- $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
- $this->createdUsers[$user] = $user;
- }
-
- /**
- * @When /^creating the group "([^"]*)"$/
- */
- public function creatingTheGroup($group) {
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/groups";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $options['body'] = [
- 'groupid' => $group,
- ];
-
- $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
- $this->createdGroups[$group] = $group;
- }
-
- /**
- * @When /^Deleting the user "([^"]*)"$/
- */
- public function deletingTheUser($user) {
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $this->response = $client->send($client->createRequest("DELETE", $fullUrl, $options));
- }
-
- /**
- * @When /^Deleting the group "([^"]*)"$/
- */
- public function deletingTheGroup($group) {
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/groups/$group";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $this->response = $client->send($client->createRequest("DELETE", $fullUrl, $options));
- }
-
- /**
- * @Given /^Add user "([^"]*)" to the group "([^"]*)"$/
- */
- public function addUserToGroup($user, $group) {
- $this->userExists($user);
- $this->groupExists($group);
- $this->addingUserToGroup($user, $group);
-
- }
-
- /**
- * @When /^User "([^"]*)" is added to the group "([^"]*)"$/
- */
- public function addingUserToGroup($user, $group) {
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user/groups";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- }
-
- $options['body'] = [
- 'groupid' => $group,
- ];
-
- $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
- }
-
-
- public function groupExists($group) {
- $fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group";
- $client = new Client();
- $options = [];
- $options['auth'] = $this->adminUser;
-
- $this->response = $client->get($fullUrl, $options);
- }
-
- /**
- * @Given /^group "([^"]*)" exists$/
- */
- public function assureGroupExists($group) {
- try {
- $this->groupExists($group);
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $previous_user = $this->currentUser;
- $this->currentUser = "admin";
- $this->creatingTheGroup($group);
- $this->currentUser = $previous_user;
- }
- $this->groupExists($group);
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
- }
-
- /**
- * @Given /^group "([^"]*)" does not exist$/
- */
- public function groupDoesNotExist($group) {
- try {
- $this->groupExists($group);
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $this->response = $ex->getResponse();
- PHPUnit_Framework_Assert::assertEquals(404, $ex->getResponse()->getStatusCode());
- return;
- }
- $previous_user = $this->currentUser;
- $this->currentUser = "admin";
- $this->deletingTheGroup($group);
- $this->currentUser = $previous_user;
- try {
- $this->groupExists($group);
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $this->response = $ex->getResponse();
- PHPUnit_Framework_Assert::assertEquals(404, $ex->getResponse()->getStatusCode());
- }
- }
-
- /**
- * @When /^sending "([^"]*)" to "([^"]*)" with$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
- */
- public function sendingToWith($verb, $url, $body) {
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php" . $url;
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- } else {
- $options['auth'] = [$this->currentUser, $this->regularUser];
- }
- if ($body instanceof \Behat\Gherkin\Node\TableNode) {
- $fd = $body->getRowsHash();
- $options['body'] = $fd;
- }
-
- try {
- $this->response = $client->send($client->createRequest($verb, $fullUrl, $options));
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $this->response = $ex->getResponse();
- }
- }
-
- /**
- * @When /^creating a public share with$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
- */
- public function createPublicShare($body) {
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v1/shares";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- } else {
- $options['auth'] = [$this->currentUser, $this->regularUser];
- }
-
- if ($body instanceof \Behat\Gherkin\Node\TableNode) {
- $fd = $body->getRowsHash();
- if (array_key_exists('expireDate', $fd)){
- $dateModification = $fd['expireDate'];
- $fd['expireDate'] = date('Y-m-d', strtotime($dateModification));
- }
- $options['body'] = $fd;
- }
-
- try {
- $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $this->response = $ex->getResponse();
- }
-
- $this->lastShareData = $this->response->xml();
- }
-
- /**
- * @Then /^Public shared file "([^"]*)" can be downloaded$/
- */
- public function checkPublicSharedFile($filename) {
- $client = new Client();
- $options = [];
- if (count($this->lastShareData->data->element) > 0){
- $url = $this->lastShareData->data[0]->url;
- }
- else{
- $url = $this->lastShareData->data->url;
- }
- $fullUrl = $url . "/download";
- $options['save_to'] = "./$filename";
- $this->response = $client->get($fullUrl, $options);
- $finfo = new finfo;
- $fileinfo = $finfo->file("./$filename", FILEINFO_MIME_TYPE);
- PHPUnit_Framework_Assert::assertEquals($fileinfo, "text/plain");
- if (file_exists("./$filename")) {
- unlink("./$filename");
- }
- }
-
- /**
- * @Then /^Public shared file "([^"]*)" with password "([^"]*)" can be downloaded$/
- */
- public function checkPublicSharedFileWithPassword($filename, $password) {
- $client = new Client();
- $options = [];
- if (count($this->lastShareData->data->element) > 0){
- $token = $this->lastShareData->data[0]->token;
- }
- else{
- $token = $this->lastShareData->data->token;
- }
-
- $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/webdav";
- $options['auth'] = [$token, $password];
- $options['save_to'] = "./$filename";
- $this->response = $client->get($fullUrl, $options);
- $finfo = new finfo;
- $fileinfo = $finfo->file("./$filename", FILEINFO_MIME_TYPE);
- PHPUnit_Framework_Assert::assertEquals($fileinfo, "text/plain");
- if (file_exists("./$filename")) {
- unlink("./$filename");
- }
- }
-
- /**
- * @When /^Adding expiration date to last share$/
- */
- public function addingExpirationDate() {
- $share_id = $this->lastShareData->data[0]->id;
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- } else {
- $options['auth'] = [$this->currentUser, $this->regularUser];
- }
- $date = date('Y-m-d', strtotime("+3 days"));
- $options['body'] = ['expireDate' => $date];
- $this->response = $client->send($client->createRequest("PUT", $fullUrl, $options));
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
- }
-
- /**
- * @When /^Updating last share with$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
- */
- public function updatingLastShare($body) {
- $share_id = $this->lastShareData->data[0]->id;
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
- $client = new Client();
- $options = [];
- if ($this->currentUser === 'admin') {
- $options['auth'] = $this->adminUser;
- } else {
- $options['auth'] = [$this->currentUser, $this->regularUser];
- }
-
- if ($body instanceof \Behat\Gherkin\Node\TableNode) {
- $fd = $body->getRowsHash();
- if (array_key_exists('expireDate', $fd)){
- $dateModification = $fd['expireDate'];
- $fd['expireDate'] = date('Y-m-d', strtotime($dateModification));
- }
- $options['body'] = $fd;
- }
-
- try {
- $this->response = $client->send($client->createRequest("PUT", $fullUrl, $options));
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $this->response = $ex->getResponse();
- }
-
- PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
- }
-
-
- public function createShare($user,
- $path = null,
- $shareType = null,
- $shareWith = null,
- $publicUpload = null,
- $password = null,
- $permissions = null){
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares";
- $client = new Client();
- $options = [];
-
- if ($user === 'admin') {
- $options['auth'] = $this->adminUser;
- } else {
- $options['auth'] = [$user, $this->regularUser];
- }
- $fd = [];
- if (!is_null($path)){
- $fd['path'] = $path;
- }
- if (!is_null($shareType)){
- $fd['shareType'] = $shareType;
- }
- if (!is_null($shareWith)){
- $fd['shareWith'] = $shareWith;
- }
- if (!is_null($publicUpload)){
- $fd['publicUpload'] = $publicUpload;
- }
- if (!is_null($password)){
- $fd['password'] = $password;
- }
- if (!is_null($permissions)){
- $fd['permissions'] = $permissions;
- }
-
- $options['body'] = $fd;
-
- try {
- $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
- $this->lastShareData = $this->response->xml();
- } catch (\GuzzleHttp\Exception\ClientException $ex) {
- $this->response = $ex->getResponse();
- }
-
- }
-
- public function isExpectedUrl($possibleUrl, $finalPart){
- $baseUrlChopped = substr($this->baseUrl, 0, -4);
- $endCharacter = strlen($baseUrlChopped) + strlen($finalPart);
- return (substr($possibleUrl,0,$endCharacter) == "$baseUrlChopped" . "$finalPart");
- }
-
- public function isFieldInResponse($field, $contentExpected){
- $data = $this->response->xml()->data[0];
- if ((string)$field == 'expiration'){
- $contentExpected = date('Y-m-d', strtotime($contentExpected)) . " 00:00:00";
- }
- if (count($data->element) > 0){
- foreach($data as $element) {
- if ($contentExpected == "A_TOKEN"){
- return (strlen((string)$element->$field) == 15);
- }
- elseif ($contentExpected == "A_NUMBER"){
- return is_numeric((string)$element->$field);
- }
- elseif($contentExpected == "AN_URL"){
- return $this->isExpectedUrl((string)$element->$field, "index.php/s/");
- }
- elseif ($element->$field == $contentExpected){
- return True;
- }
- }
-
- return False;
- } else {
- if ($contentExpected == "A_TOKEN"){
- return (strlen((string)$data->$field) == 15);
- }
- elseif ($contentExpected == "A_NUMBER"){
- return is_numeric((string)$data->$field);
- }
- elseif($contentExpected == "AN_URL"){
- return $this->isExpectedUrl((string)$data->$field, "index.php/s/");
- }
- elseif ($data->$field == $contentExpected){
- return True;
- }
- return False;
- }
- }
-
- /**
- * @Then /^File "([^"]*)" should be included in the response$/
- */
- public function checkSharedFileInResponse($filename){
- PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse('file_target', "/$filename"));
- }
-
- /**
- * @Then /^File "([^"]*)" should not be included in the response$/
- */
- public function checkSharedFileNotInResponse($filename){
- PHPUnit_Framework_Assert::assertEquals(False, $this->isFieldInResponse('file_target', "/$filename"));
- }
-
- /**
- * @Then /^User "([^"]*)" should be included in the response$/
- */
- public function checkSharedUserInResponse($user){
- PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse('share_with', "$user"));
- }
-
- /**
- * @Then /^User "([^"]*)" should not be included in the response$/
- */
- public function checkSharedUserNotInResponse($user){
- PHPUnit_Framework_Assert::assertEquals(False, $this->isFieldInResponse('share_with', "$user"));
- }
-
- public function isUserInSharedData($user){
- $data = $this->response->xml()->data[0];
- foreach($data as $element) {
- if ($element->share_with == $user){
- return True;
- }
- }
- return False;
- }
-
- /**
- * @Given /^file "([^"]*)" from user "([^"]*)" is shared with user "([^"]*)"$/
- */
- public function assureFileIsShared($filepath, $user1, $user2){
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares" . "?path=$filepath";
- $client = new Client();
- $options = [];
- if ($user1 === 'admin') {
- $options['auth'] = $this->adminUser;
- } else {
- $options['auth'] = [$user1, $this->regularUser];
- }
- $this->response = $client->get($fullUrl, $options);
- if ($this->isUserInSharedData($user2)){
- return;
- } else {
- $this->createShare($user1, $filepath, 0, $user2, null, null, null);
- }
- $this->response = $client->get($fullUrl, $options);
- PHPUnit_Framework_Assert::assertEquals(True, $this->isUserInSharedData($user2));
- }
-
- /**
- * @When /^Deleting last share$/
- */
- public function deletingLastShare(){
- $share_id = $this->lastShareData->data[0]->id;
- $url = "/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
- $this->sendingToWith("DELETE", $url, null);
- }
-
- /**
- * @When /^Getting info of last share$/
- */
- public function gettingInfoOfLastShare(){
- $share_id = $this->lastShareData->data[0]->id;
- $url = "/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
- $this->sendingToWith("GET", $url, null);
- }
-
- /**
- * @Then /^Share fields of last share match with$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
- */
- public function checkShareFields($body){
- if ($body instanceof \Behat\Gherkin\Node\TableNode) {
- $fd = $body->getRowsHash();
-
- foreach($fd as $field => $value) {
- PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse($field, $value));
- }
- }
- }
-
- public static function removeFile($path, $filename){
- if (file_exists("$path" . "$filename")) {
- unlink("$path" . "$filename");
- }
- }
-
- /**
- * @BeforeSuite
- */
- public static function addFilesToSkeleton(){
- for ($i=0; $i<5; $i++){
- file_put_contents("../../core/skeleton/" . "textfile" . "$i" . ".txt", "ownCloud test text file\n");
- }
- if (!file_exists("../../core/skeleton/FOLDER")) {
- mkdir("../../core/skeleton/FOLDER", 0777, true);
- }
-
- }
-
- /**
- * @AfterSuite
- */
- public static function removeFilesFromSkeleton(){
- for ($i=0; $i<5; $i++){
- self::removeFile("../../core/skeleton/", "textfile" . "$i" . ".txt");
- }
- if (!is_dir("../../core/skeleton/FOLDER")) {
- rmdir("../../core/skeleton/FOLDER");
- }
- }
-
- /**
- * @BeforeScenario
- * @AfterScenario
- */
- public function cleanupUsers()
- {
- foreach($this->createdUsers as $user) {
- $this->deleteUser($user);
- }
- }
-
-
- /**
- * @BeforeScenario
- * @AfterScenario
- */
- public function cleanupGroups()
- {
- foreach($this->createdGroups as $group) {
- $this->deleteGroup($group);
- }
- }
+ use BasicStructure;
+ use Provisioning;
+ use Sharing;
+ use WebDav;
}
diff --git a/build/integration/features/bootstrap/FederationContext.php b/build/integration/features/bootstrap/FederationContext.php
new file mode 100644
index 00000000000..279b5206dee
--- /dev/null
+++ b/build/integration/features/bootstrap/FederationContext.php
@@ -0,0 +1,27 @@
+<?php
+
+use Behat\Behat\Context\Context;
+use Behat\Behat\Context\SnippetAcceptingContext;
+use GuzzleHttp\Client;
+use GuzzleHttp\Message\ResponseInterface;
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+/**
+ * Federation context.
+ */
+class FederationContext implements Context, SnippetAcceptingContext {
+
+ use BasicStructure;
+ use Provisioning;
+ use Sharing;
+
+ /**
+ * @When /^User "([^"]*)" from server "([^"]*)" shares "([^"]*)" with user "([^"]*)" from server "([^"]*)"$/
+ */
+ public function federateSharing($userLocal, $serverLocal, $pathLocal, $userRemote, $serverRemote){
+ $shareWith = "$userRemote@" . substr($this->remoteBaseUrl, 0, -4);
+ $this->createShare($userLocal, $pathLocal, 6, $shareWith, null, null, null);
+ }
+
+}
diff --git a/build/integration/features/bootstrap/Provisioning.php b/build/integration/features/bootstrap/Provisioning.php
new file mode 100644
index 00000000000..65a6611b06c
--- /dev/null
+++ b/build/integration/features/bootstrap/Provisioning.php
@@ -0,0 +1,568 @@
+<?php
+
+use Behat\Behat\Context\Context;
+use Behat\Behat\Context\SnippetAcceptingContext;
+use GuzzleHttp\Client;
+use GuzzleHttp\Message\ResponseInterface;
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+trait Provisioning {
+
+ /** @var int */
+ private $apiVersion = 1;
+
+ /** @var array */
+ private $createdUsers = [];
+
+ /** @var array */
+ private $createdRemoteUsers = [];
+
+ /** @var array */
+ private $createdRemoteGroups = [];
+
+ /** @var array */
+ private $createdGroups = [];
+
+ /**
+ * @Given /^using api version "([^"]*)"$/
+ */
+ public function usingApiVersion($version) {
+ $this->apiVersion = $version;
+ }
+
+ /**
+ * @Given /^user "([^"]*)" exists$/
+ */
+ public function assureUserExists($user) {
+ try {
+ $this->userExists($user);
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+ $this->creatingTheUser($user);
+ $this->currentUser = $previous_user;
+ }
+ $this->userExists($user);
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+
+ }
+
+ /**
+ * @Given /^user "([^"]*)" does not exist$/
+ */
+ public function userDoesNotExist($user) {
+ try {
+ $this->userExists($user);
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $this->response = $ex->getResponse();
+ PHPUnit_Framework_Assert::assertEquals(404, $ex->getResponse()->getStatusCode());
+ return;
+ }
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+ $this->deletingTheUser($user);
+ $this->currentUser = $previous_user;
+ try {
+ $this->userExists($user);
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $this->response = $ex->getResponse();
+ PHPUnit_Framework_Assert::assertEquals(404, $ex->getResponse()->getStatusCode());
+ }
+ }
+
+ public function creatingTheUser($user) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $options['body'] = [
+ 'userid' => $user,
+ 'password' => '123456'
+ ];
+
+ $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
+ if ($this->currentServer === 'LOCAL'){
+ $this->createdUsers[$user] = $user;
+ } elseif ($this->currentServer === 'REMOTE') {
+ $this->createdRemoteUsers[$user] = $user;
+ }
+
+ //Quick hack to login once with the current user
+ $options2 = [
+ 'auth' => [$user, '123456'],
+ ];
+ $url = $fullUrl.'/'.$user;
+ $client->send($client->createRequest('GET', $url, $options2));
+ }
+
+ public function createUser($user) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+ $this->creatingTheUser($user);
+ $this->userExists($user);
+ $this->currentUser = $previous_user;
+ }
+
+ public function deleteUser($user) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+ $this->deletingTheUser($user);
+ $this->userDoesNotExist($user);
+ $this->currentUser = $previous_user;
+ }
+
+ public function createGroup($group) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+ $this->creatingTheGroup($group);
+ $this->groupExists($group);
+ $this->currentUser = $previous_user;
+ }
+
+ public function deleteGroup($group) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+ $this->deletingTheGroup($group);
+ $this->groupDoesNotExist($group);
+ $this->currentUser = $previous_user;
+ }
+
+ public function userExists($user){
+ $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user";
+ $client = new Client();
+ $options = [];
+ $options['auth'] = $this->adminUser;
+
+ $this->response = $client->get($fullUrl, $options);
+ }
+
+ /**
+ * @Then /^check that user "([^"]*)" belongs to group "([^"]*)"$/
+ */
+ public function checkThatUserBelongsToGroup($user, $group) {
+ $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->get($fullUrl, $options);
+ $respondedArray = $this->getArrayOfGroupsResponded($this->response);
+ sort($respondedArray);
+ PHPUnit_Framework_Assert::assertContains($group, $respondedArray);
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ public function userBelongsToGroup($user, $group) {
+ $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->get($fullUrl, $options);
+ $groups = array($group);
+ $respondedArray = $this->getArrayOfGroupsResponded($this->response);
+
+ if (array_key_exists($group, $respondedArray)) {
+ return True;
+ } else{
+ return False;
+ }
+ }
+
+ /**
+ * @Given /^user "([^"]*)" belongs to group "([^"]*)"$/
+ */
+ public function assureUserBelongsToGroup($user, $group){
+ if (!$this->userBelongsToGroup($user, $group)){
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+ $this->addingUserToGroup($user, $group);
+ $this->currentUser = $previous_user;
+ }
+ $this->checkThatUserBelongsToGroup($user, $group);
+
+ }
+
+ /**
+ * @Given /^user "([^"]*)" does not belong to group "([^"]*)"$/
+ */
+ public function userDoesNotBelongToGroup($user, $group) {
+ $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->get($fullUrl, $options);
+ $groups = array($group);
+ $respondedArray = $this->getArrayOfGroupsResponded($this->response);
+ PHPUnit_Framework_Assert::assertNotEquals($groups, $respondedArray, "", 0.0, 10, true);
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ /**
+ * @When /^creating the group "([^"]*)"$/
+ */
+ public function creatingTheGroup($group) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/groups";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $options['body'] = [
+ 'groupid' => $group,
+ ];
+
+ $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
+ if ($this->currentServer === 'LOCAL'){
+ $this->createdGroups[$group] = $group;
+ } elseif ($this->currentServer === 'REMOTE') {
+ $this->createdRemoteGroups[$group] = $group;
+ }
+ }
+
+ /**
+ * @When /^Deleting the user "([^"]*)"$/
+ */
+ public function deletingTheUser($user) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->send($client->createRequest("DELETE", $fullUrl, $options));
+ }
+
+ /**
+ * @When /^Deleting the group "([^"]*)"$/
+ */
+ public function deletingTheGroup($group) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/groups/$group";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->send($client->createRequest("DELETE", $fullUrl, $options));
+ }
+
+ /**
+ * @Given /^Add user "([^"]*)" to the group "([^"]*)"$/
+ */
+ public function addUserToGroup($user, $group) {
+ $this->userExists($user);
+ $this->groupExists($group);
+ $this->addingUserToGroup($user, $group);
+
+ }
+
+ /**
+ * @When /^User "([^"]*)" is added to the group "([^"]*)"$/
+ */
+ public function addingUserToGroup($user, $group) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user/groups";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $options['body'] = [
+ 'groupid' => $group,
+ ];
+
+ $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
+ }
+
+
+ public function groupExists($group) {
+ $fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group";
+ $client = new Client();
+ $options = [];
+ $options['auth'] = $this->adminUser;
+
+ $this->response = $client->get($fullUrl, $options);
+ }
+
+ /**
+ * @Given /^group "([^"]*)" exists$/
+ */
+ public function assureGroupExists($group) {
+ try {
+ $this->groupExists($group);
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+ $this->creatingTheGroup($group);
+ $this->currentUser = $previous_user;
+ }
+ $this->groupExists($group);
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ /**
+ * @Given /^group "([^"]*)" does not exist$/
+ */
+ public function groupDoesNotExist($group) {
+ try {
+ $this->groupExists($group);
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $this->response = $ex->getResponse();
+ PHPUnit_Framework_Assert::assertEquals(404, $ex->getResponse()->getStatusCode());
+ return;
+ }
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+ $this->deletingTheGroup($group);
+ $this->currentUser = $previous_user;
+ try {
+ $this->groupExists($group);
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $this->response = $ex->getResponse();
+ PHPUnit_Framework_Assert::assertEquals(404, $ex->getResponse()->getStatusCode());
+ }
+ }
+
+ /**
+ * @Given /^user "([^"]*)" is subadmin of group "([^"]*)"$/
+ */
+ public function userIsSubadminOfGroup($user, $group) {
+ $fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group/subadmins";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->get($fullUrl, $options);
+ $respondedArray = $this->getArrayOfSubadminsResponded($this->response);
+ sort($respondedArray);
+ PHPUnit_Framework_Assert::assertContains($user, $respondedArray);
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ /**
+ * @Given /^user "([^"]*)" is not a subadmin of group "([^"]*)"$/
+ */
+ public function userIsNotSubadminOfGroup($user, $group) {
+ $fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group/subadmins";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->get($fullUrl, $options);
+ $respondedArray = $this->getArrayOfSubadminsResponded($this->response);
+ sort($respondedArray);
+ PHPUnit_Framework_Assert::assertNotContains($user, $respondedArray);
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ /**
+ * @Then /^users returned are$/
+ * @param \Behat\Gherkin\Node\TableNode|null $usersList
+ */
+ public function theUsersShouldBe($usersList) {
+ if ($usersList instanceof \Behat\Gherkin\Node\TableNode) {
+ $users = $usersList->getRows();
+ $usersSimplified = $this->simplifyArray($users);
+ $respondedArray = $this->getArrayOfUsersResponded($this->response);
+ PHPUnit_Framework_Assert::assertEquals($usersSimplified, $respondedArray, "", 0.0, 10, true);
+ }
+
+ }
+
+ /**
+ * @Then /^groups returned are$/
+ * @param \Behat\Gherkin\Node\TableNode|null $groupsList
+ */
+ public function theGroupsShouldBe($groupsList) {
+ if ($groupsList instanceof \Behat\Gherkin\Node\TableNode) {
+ $groups = $groupsList->getRows();
+ $groupsSimplified = $this->simplifyArray($groups);
+ $respondedArray = $this->getArrayOfGroupsResponded($this->response);
+ PHPUnit_Framework_Assert::assertEquals($groupsSimplified, $respondedArray, "", 0.0, 10, true);
+ }
+
+ }
+
+ /**
+ * @Then /^subadmin groups returned are$/
+ * @param \Behat\Gherkin\Node\TableNode|null $groupsList
+ */
+ public function theSubadminGroupsShouldBe($groupsList) {
+ if ($groupsList instanceof \Behat\Gherkin\Node\TableNode) {
+ $groups = $groupsList->getRows();
+ $groupsSimplified = $this->simplifyArray($groups);
+ $respondedArray = $this->getArrayOfSubadminsResponded($this->response);
+ PHPUnit_Framework_Assert::assertEquals($groupsSimplified, $respondedArray, "", 0.0, 10, true);
+ }
+
+ }
+
+ /**
+ * @Then /^apps returned are$/
+ * @param \Behat\Gherkin\Node\TableNode|null $appList
+ */
+ public function theAppsShouldBe($appList) {
+ if ($appList instanceof \Behat\Gherkin\Node\TableNode) {
+ $apps = $appList->getRows();
+ $appsSimplified = $this->simplifyArray($apps);
+ $respondedArray = $this->getArrayOfAppsResponded($this->response);
+ PHPUnit_Framework_Assert::assertEquals($appsSimplified, $respondedArray, "", 0.0, 10, true);
+ }
+
+ }
+
+ /**
+ * @Then /^subadmin users returned are$/
+ * @param \Behat\Gherkin\Node\TableNode|null $groupsList
+ */
+ public function theSubadminUsersShouldBe($groupsList) {
+ $this->theSubadminGroupsShouldBe($groupsList);
+ }
+
+ /**
+ * Parses the xml answer to get the array of users returned.
+ * @param ResponseInterface $resp
+ * @return array
+ */
+ public function getArrayOfUsersResponded($resp) {
+ $listCheckedElements = $resp->xml()->data[0]->users[0]->element;
+ $extractedElementsArray = json_decode(json_encode($listCheckedElements), 1);
+ return $extractedElementsArray;
+ }
+
+ /**
+ * Parses the xml answer to get the array of groups returned.
+ * @param ResponseInterface $resp
+ * @return array
+ */
+ public function getArrayOfGroupsResponded($resp) {
+ $listCheckedElements = $resp->xml()->data[0]->groups[0]->element;
+ $extractedElementsArray = json_decode(json_encode($listCheckedElements), 1);
+ return $extractedElementsArray;
+ }
+
+ /**
+ * Parses the xml answer to get the array of apps returned.
+ * @param ResponseInterface $resp
+ * @return array
+ */
+ public function getArrayOfAppsResponded($resp) {
+ $listCheckedElements = $resp->xml()->data[0]->apps[0]->element;
+ $extractedElementsArray = json_decode(json_encode($listCheckedElements), 1);
+ return $extractedElementsArray;
+ }
+
+ /**
+ * Parses the xml answer to get the array of subadmins returned.
+ * @param ResponseInterface $resp
+ * @return array
+ */
+ public function getArrayOfSubadminsResponded($resp) {
+ $listCheckedElements = $resp->xml()->data[0]->element;
+ $extractedElementsArray = json_decode(json_encode($listCheckedElements), 1);
+ return $extractedElementsArray;
+ }
+
+
+ /**
+ * @Given /^app "([^"]*)" is disabled$/
+ */
+ public function appIsDisabled($app) {
+ $fullUrl = $this->baseUrl . "v2.php/cloud/apps?filter=disabled";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->get($fullUrl, $options);
+ $respondedArray = $this->getArrayOfAppsResponded($this->response);
+ PHPUnit_Framework_Assert::assertContains($app, $respondedArray);
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ /**
+ * @Given /^app "([^"]*)" is enabled$/
+ */
+ public function appIsEnabled($app) {
+ $fullUrl = $this->baseUrl . "v2.php/cloud/apps?filter=enabled";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->get($fullUrl, $options);
+ $respondedArray = $this->getArrayOfAppsResponded($this->response);
+ PHPUnit_Framework_Assert::assertContains($app, $respondedArray);
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ /**
+ * @Given user :user has a quota of :quota
+ */
+ public function userHasAQuotaOf($user, $quota)
+ {
+ $body = new \Behat\Gherkin\Node\TableNode([
+ 0 => ['key', 'quota'],
+ 1 => ['value', $quota],
+ ]);
+
+ // method used from BasicStructure trait
+ $this->sendingToWith("PUT", "/cloud/users/" . $user, $body);
+ }
+
+ /**
+ * @BeforeScenario
+ * @AfterScenario
+ */
+ public function cleanupUsers()
+ {
+ $previousServer = $this->currentServer;
+ $this->usingServer('LOCAL');
+ foreach($this->createdUsers as $user) {
+ $this->deleteUser($user);
+ }
+ $this->usingServer('REMOTE');
+ foreach($this->createdRemoteUsers as $remoteUser) {
+ $this->deleteUser($remoteUser);
+ }
+ $this->usingServer($previousServer);
+ }
+
+ /**
+ * @BeforeScenario
+ * @AfterScenario
+ */
+ public function cleanupGroups()
+ {
+ $previousServer = $this->currentServer;
+ $this->usingServer('LOCAL');
+ foreach($this->createdGroups as $group) {
+ $this->deleteGroup($group);
+ }
+ $this->usingServer('REMOTE');
+ foreach($this->createdRemoteGroups as $remoteGroup) {
+ $this->deleteUser($remoteGroup);
+ }
+ $this->usingServer($previousServer);
+ }
+}
diff --git a/build/integration/features/bootstrap/Sharing.php b/build/integration/features/bootstrap/Sharing.php
new file mode 100644
index 00000000000..5103b4af508
--- /dev/null
+++ b/build/integration/features/bootstrap/Sharing.php
@@ -0,0 +1,374 @@
+<?php
+
+use Behat\Behat\Context\Context;
+use Behat\Behat\Context\SnippetAcceptingContext;
+use GuzzleHttp\Client;
+use GuzzleHttp\Message\ResponseInterface;
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+
+
+trait Sharing{
+
+ /** @var int */
+ private $sharingApiVersion = 1;
+
+ /** @var SimpleXMLElement */
+ private $lastShareData = null;
+
+ /**
+ * @When /^creating a share with$/
+ * @param \Behat\Gherkin\Node\TableNode|null $formData
+ */
+ public function creatingShare($body) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v1/shares";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$this->currentUser, $this->regularUser];
+ }
+
+ if ($body instanceof \Behat\Gherkin\Node\TableNode) {
+ $fd = $body->getRowsHash();
+ if (array_key_exists('expireDate', $fd)){
+ $dateModification = $fd['expireDate'];
+ $fd['expireDate'] = date('Y-m-d', strtotime($dateModification));
+ }
+ $options['body'] = $fd;
+ }
+
+ try {
+ $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $this->response = $ex->getResponse();
+ }
+
+ $this->lastShareData = $this->response->xml();
+ }
+
+ /**
+ * @Then /^Public shared file "([^"]*)" can be downloaded$/
+ */
+ public function checkPublicSharedFile($filename) {
+ $client = new Client();
+ $options = [];
+ if (count($this->lastShareData->data->element) > 0){
+ $url = $this->lastShareData->data[0]->url;
+ }
+ else{
+ $url = $this->lastShareData->data->url;
+ }
+ $fullUrl = $url . "/download";
+ $options['save_to'] = "./$filename";
+ $this->response = $client->get($fullUrl, $options);
+ $finfo = new finfo;
+ $fileinfo = $finfo->file("./$filename", FILEINFO_MIME_TYPE);
+ PHPUnit_Framework_Assert::assertEquals($fileinfo, "text/plain");
+ if (file_exists("./$filename")) {
+ unlink("./$filename");
+ }
+ }
+
+ /**
+ * @Then /^Public shared file "([^"]*)" with password "([^"]*)" can be downloaded$/
+ */
+ public function checkPublicSharedFileWithPassword($filename, $password) {
+ $client = new Client();
+ $options = [];
+ if (count($this->lastShareData->data->element) > 0){
+ $token = $this->lastShareData->data[0]->token;
+ }
+ else{
+ $token = $this->lastShareData->data->token;
+ }
+
+ $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/webdav";
+ $options['auth'] = [$token, $password];
+ $options['save_to'] = "./$filename";
+ $this->response = $client->get($fullUrl, $options);
+ $finfo = new finfo;
+ $fileinfo = $finfo->file("./$filename", FILEINFO_MIME_TYPE);
+ PHPUnit_Framework_Assert::assertEquals($fileinfo, "text/plain");
+ if (file_exists("./$filename")) {
+ unlink("./$filename");
+ }
+ }
+
+ /**
+ * @When /^Adding expiration date to last share$/
+ */
+ public function addingExpirationDate() {
+ $share_id = $this->lastShareData->data[0]->id;
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$this->currentUser, $this->regularUser];
+ }
+ $date = date('Y-m-d', strtotime("+3 days"));
+ $options['body'] = ['expireDate' => $date];
+ $this->response = $client->send($client->createRequest("PUT", $fullUrl, $options));
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ /**
+ * @When /^Updating last share with$/
+ * @param \Behat\Gherkin\Node\TableNode|null $body
+ */
+ public function updatingLastShare($body) {
+ $share_id = $this->lastShareData->data[0]->id;
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$this->currentUser, $this->regularUser];
+ }
+
+ if ($body instanceof \Behat\Gherkin\Node\TableNode) {
+ $fd = $body->getRowsHash();
+ if (array_key_exists('expireDate', $fd)){
+ $dateModification = $fd['expireDate'];
+ $fd['expireDate'] = date('Y-m-d', strtotime($dateModification));
+ }
+ $options['body'] = $fd;
+ }
+
+ try {
+ $this->response = $client->send($client->createRequest("PUT", $fullUrl, $options));
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $this->response = $ex->getResponse();
+ }
+
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ public function createShare($user,
+ $path = null,
+ $shareType = null,
+ $shareWith = null,
+ $publicUpload = null,
+ $password = null,
+ $permissions = null){
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares";
+ $client = new Client();
+ $options = [];
+
+ if ($user === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$user, $this->regularUser];
+ }
+ $fd = [];
+ if (!is_null($path)){
+ $fd['path'] = $path;
+ }
+ if (!is_null($shareType)){
+ $fd['shareType'] = $shareType;
+ }
+ if (!is_null($shareWith)){
+ $fd['shareWith'] = $shareWith;
+ }
+ if (!is_null($publicUpload)){
+ $fd['publicUpload'] = $publicUpload;
+ }
+ if (!is_null($password)){
+ $fd['password'] = $password;
+ }
+ if (!is_null($permissions)){
+ $fd['permissions'] = $permissions;
+ }
+
+ $options['body'] = $fd;
+
+ try {
+ $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
+ $this->lastShareData = $this->response->xml();
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $this->response = $ex->getResponse();
+ }
+ }
+
+ public function isFieldInResponse($field, $contentExpected){
+ $data = $this->response->xml()->data[0];
+ if ((string)$field == 'expiration'){
+ $contentExpected = date('Y-m-d', strtotime($contentExpected)) . " 00:00:00";
+ }
+ if (count($data->element) > 0){
+ foreach($data as $element) {
+ if ($contentExpected == "A_TOKEN"){
+ return (strlen((string)$element->$field) == 15);
+ }
+ elseif ($contentExpected == "A_NUMBER"){
+ return is_numeric((string)$element->$field);
+ }
+ elseif($contentExpected == "AN_URL"){
+ return $this->isExpectedUrl((string)$element->$field, "index.php/s/");
+ }
+ elseif ((string)$element->$field == $contentExpected){
+ return True;
+ }
+ }
+
+ return False;
+ } else {
+ if ($contentExpected == "A_TOKEN"){
+ return (strlen((string)$data->$field) == 15);
+ }
+ elseif ($contentExpected == "A_NUMBER"){
+ return is_numeric((string)$data->$field);
+ }
+ elseif($contentExpected == "AN_URL"){
+ return $this->isExpectedUrl((string)$data->$field, "index.php/s/");
+ }
+ elseif ($data->$field == $contentExpected){
+ return True;
+ }
+ return False;
+ }
+ }
+
+ /**
+ * @Then /^File "([^"]*)" should be included in the response$/
+ */
+ public function checkSharedFileInResponse($filename){
+ PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse('file_target', "/$filename"));
+ }
+
+ /**
+ * @Then /^File "([^"]*)" should not be included in the response$/
+ */
+ public function checkSharedFileNotInResponse($filename){
+ PHPUnit_Framework_Assert::assertEquals(False, $this->isFieldInResponse('file_target', "/$filename"));
+ }
+
+ /**
+ * @Then /^User "([^"]*)" should be included in the response$/
+ */
+ public function checkSharedUserInResponse($user){
+ PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse('share_with', "$user"));
+ }
+
+ /**
+ * @Then /^User "([^"]*)" should not be included in the response$/
+ */
+ public function checkSharedUserNotInResponse($user){
+ PHPUnit_Framework_Assert::assertEquals(False, $this->isFieldInResponse('share_with', "$user"));
+ }
+
+ public function isUserOrGroupInSharedData($userOrGroup){
+ $data = $this->response->xml()->data[0];
+ foreach($data as $element) {
+ if ($element->share_with == $userOrGroup){
+ return True;
+ }
+ }
+ return False;
+ }
+
+ /**
+ * @Given /^file "([^"]*)" of user "([^"]*)" is shared with user "([^"]*)"$/
+ */
+ public function assureFileIsShared($filepath, $user1, $user2){
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares" . "?path=$filepath";
+ $client = new Client();
+ $options = [];
+ if ($user1 === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$user1, $this->regularUser];
+ }
+ $this->response = $client->get($fullUrl, $options);
+ if ($this->isUserOrGroupInSharedData($user2)){
+ return;
+ } else {
+ $this->createShare($user1, $filepath, 0, $user2, null, null, null);
+ }
+ $this->response = $client->get($fullUrl, $options);
+ PHPUnit_Framework_Assert::assertEquals(True, $this->isUserOrGroupInSharedData($user2));
+ }
+
+ /**
+ * @Given /^file "([^"]*)" of user "([^"]*)" is shared with group "([^"]*)"$/
+ */
+ public function assureFileIsSharedWithGroup($filepath, $user, $group){
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares" . "?path=$filepath";
+ $client = new Client();
+ $options = [];
+ if ($user === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$user, $this->regularUser];
+ }
+ $this->response = $client->get($fullUrl, $options);
+ if ($this->isUserOrGroupInSharedData($group)){
+ return;
+ } else {
+ $this->createShare($user, $filepath, 1, $group, null, null, null);
+ }
+ $this->response = $client->get($fullUrl, $options);
+ PHPUnit_Framework_Assert::assertEquals(True, $this->isUserOrGroupInSharedData($group));
+ }
+
+ /**
+ * @When /^Deleting last share$/
+ */
+ public function deletingLastShare(){
+ $share_id = $this->lastShareData->data[0]->id;
+ $url = "/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
+ $this->sendingToWith("DELETE", $url, null);
+ }
+
+ /**
+ * @When /^Getting info of last share$/
+ */
+ public function gettingInfoOfLastShare(){
+ $share_id = $this->lastShareData->data[0]->id;
+ $url = "/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
+ $this->sendingToWith("GET", $url, null);
+ }
+
+ /**
+ * @Then /^last share_id is included in the answer$/
+ */
+ public function checkingLastShareIDIsIncluded(){
+ $share_id = $this->lastShareData->data[0]->id;
+ if (!$this->isFieldInResponse('id', $share_id)){
+ PHPUnit_Framework_Assert::fail("Share id $share_id not found in response");
+ }
+ }
+
+ /**
+ * @Then /^last share_id is not included in the answer$/
+ */
+ public function checkingLastShareIDIsNotIncluded(){
+ $share_id = $this->lastShareData->data[0]->id;
+ if ($this->isFieldInResponse('id', $share_id)){
+ PHPUnit_Framework_Assert::fail("Share id $share_id has been found in response");
+ }
+ }
+
+ /**
+ * @Then /^Share fields of last share match with$/
+ * @param \Behat\Gherkin\Node\TableNode|null $formData
+ */
+ public function checkShareFields($body){
+ if ($body instanceof \Behat\Gherkin\Node\TableNode) {
+ $fd = $body->getRowsHash();
+
+ foreach($fd as $field => $value) {
+ if (!$this->isFieldInResponse($field, $value)){
+ PHPUnit_Framework_Assert::fail("$field" . " doesn't have value " . "$value");
+ }
+ }
+ }
+ }
+
+}
+
diff --git a/build/integration/features/bootstrap/WebDav.php b/build/integration/features/bootstrap/WebDav.php
new file mode 100644
index 00000000000..49cd565cf26
--- /dev/null
+++ b/build/integration/features/bootstrap/WebDav.php
@@ -0,0 +1,178 @@
+<?php
+
+use Behat\Behat\Context\Context;
+use Behat\Behat\Context\SnippetAcceptingContext;
+use GuzzleHttp\Client as GClient;
+use GuzzleHttp\Message\ResponseInterface;
+use Sabre\DAV\Client as SClient;
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+
+trait WebDav{
+
+ /** @var string*/
+ private $davPath = "remote.php/webdav";
+
+ /**
+ * @Given /^using dav path "([^"]*)"$/
+ */
+ public function usingDavPath($davPath) {
+ $this->davPath = $davPath;
+ }
+
+ public function makeDavRequest($user, $method, $path, $headers, $body = null){
+ $fullUrl = substr($this->baseUrl, 0, -4) . $this->davPath . "$path";
+ $client = new GClient();
+ $options = [];
+ if ($user === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$user, $this->regularUser];
+ }
+ $request = $client->createRequest($method, $fullUrl, $options);
+ if (!is_null($headers)){
+ foreach ($headers as $key => $value) {
+ $request->addHeader($key, $value);
+ }
+ }
+
+ if (!is_null($body)) {
+ $request->setBody($body);
+ }
+
+ return $client->send($request);
+ }
+
+ /**
+ * @Given /^User "([^"]*)" moved file "([^"]*)" to "([^"]*)"$/
+ */
+ public function userMovedFile($user, $fileSource, $fileDestination){
+ $fullUrl = substr($this->baseUrl, 0, -4) . $this->davPath;
+ $headers['Destination'] = $fullUrl . $fileDestination;
+ $this->response = $this->makeDavRequest($user, "MOVE", $fileSource, $headers);
+ PHPUnit_Framework_Assert::assertEquals(201, $this->response->getStatusCode());
+ }
+
+ /**
+ * @When /^User "([^"]*)" moves file "([^"]*)" to "([^"]*)"$/
+ */
+ public function userMovesFile($user, $fileSource, $fileDestination){
+ $fullUrl = substr($this->baseUrl, 0, -4) . $this->davPath;
+ $headers['Destination'] = $fullUrl . $fileDestination;
+ $this->response = $this->makeDavRequest($user, "MOVE", $fileSource, $headers);
+ }
+
+ /**
+ * @When /^Downloading file "([^"]*)" with range "([^"]*)"$/
+ */
+ public function downloadFileWithRange($fileSource, $range){
+ $fullUrl = substr($this->baseUrl, 0, -4) . $this->davPath;
+ $headers['Range'] = $range;
+ $this->response = $this->makeDavRequest($this->currentUser, "GET", $fileSource, $headers);
+ }
+
+ /**
+ * @When /^Downloading last public shared file with range "([^"]*)"$/
+ */
+ public function downloadPublicFileWithRange($range){
+ $token = $this->lastShareData->data->token;
+ $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/webdav";
+ $headers['Range'] = $range;
+
+ $client = new GClient();
+ $options = [];
+ $options['auth'] = [$token, ""];
+
+ $request = $client->createRequest("GET", $fullUrl, $options);
+ $request->addHeader('Range', $range);
+
+ $this->response = $client->send($request);
+ }
+
+ /**
+ * @Then /^Downloaded content should be "([^"]*)"$/
+ */
+ public function downloadedContentShouldBe($content){
+ PHPUnit_Framework_Assert::assertEquals($content, (string)$this->response->getBody());
+ }
+
+ /**
+ * @Then /^Downloaded content when downloading file "([^"]*)" with range "([^"]*)" should be "([^"]*)"$/
+ */
+ public function downloadedContentWhenDownloadindShouldBe($fileSource, $range, $content){
+ $this->downloadFileWithRange($fileSource, $range);
+ $this->downloadedContentShouldBe($content);
+ }
+
+
+ /*Returns the elements of a propfind, $folderDepth requires 1 to see elements without children*/
+ public function listFolder($user, $path, $folderDepth){
+ $fullUrl = substr($this->baseUrl, 0, -4);
+
+ $settings = array(
+ 'baseUri' => $fullUrl,
+ 'userName' => $user,
+ );
+
+ if ($user === 'admin') {
+ $settings['password'] = $this->adminUser[1];
+ } else {
+ $settings['password'] = $this->regularUser;
+ }
+
+ $client = new SClient($settings);
+
+ $response = $client->propfind($this->davPath . "/", array(
+ '{DAV:}getetag'
+ ), $folderDepth);
+
+ return $response;
+ }
+
+ /**
+ * @Then /^user "([^"]*)" should see following elements$/
+ * @param \Behat\Gherkin\Node\TableNode|null $expectedElements
+ */
+ public function checkElementList($user, $expectedElements){
+ $elementList = $this->listFolder($user, '/', 3);
+ if ($expectedElements instanceof \Behat\Gherkin\Node\TableNode) {
+ $elementRows = $expectedElements->getRows();
+ $elementsSimplified = $this->simplifyArray($elementRows);
+ foreach($elementsSimplified as $expectedElement) {
+ $webdavPath = "/" . $this->davPath . $expectedElement;
+ if (!array_key_exists($webdavPath,$elementList)){
+ PHPUnit_Framework_Assert::fail("$webdavPath" . " is not in propfind answer");
+ }
+ }
+ }
+ }
+
+ /**
+ * @When User :user uploads file :source to :destination
+ */
+ public function userUploadsAFileTo($user, $source, $destination)
+ {
+ $file = \GuzzleHttp\Stream\Stream::factory(fopen($source, 'r'));
+ try {
+ $this->response = $this->makeDavRequest($user, "PUT", $destination, [], $file);
+ } catch (\GuzzleHttp\Exception\ServerException $e) {
+ // 4xx and 5xx responses cause an exception
+ $this->response = $e->getResponse();
+ }
+ }
+
+ /**
+ * @Given User :user created a folder :destination
+ */
+ public function userCreatedAFolder($user, $destination){
+ try {
+ $this->response = $this->makeDavRequest($user, "MKCOL", $destination, []);
+ } catch (\GuzzleHttp\Exception\ServerException $e) {
+ // 4xx and 5xx responses cause an exception
+ $this->response = $e->getResponse();
+ }
+ }
+
+}
+
diff --git a/build/integration/features/provisioning-v1.feature b/build/integration/features/provisioning-v1.feature
index 2a3e8e07fc4..3b8633b872a 100644
--- a/build/integration/features/provisioning-v1.feature
+++ b/build/integration/features/provisioning-v1.feature
@@ -70,6 +70,16 @@ Feature: provisioning
And the HTTP status code should be "200"
And group "new-group" exists
+ Scenario: Create a group with special characters
+ Given As an "admin"
+ And group "España" does not exist
+ When sending "POST" to "/cloud/groups" with
+ | groupid | España |
+ | password | 123456 |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And group "España" exists
+
Scenario: adding user to a group without sending the group
Given As an "admin"
And user "brand-new-user" exists
@@ -134,6 +144,7 @@ Feature: provisioning
And group "admin" exists
When sending "GET" to "/cloud/groups"
Then groups returned are
+ | España |
| admin |
| new-group |
@@ -257,18 +268,28 @@ Feature: provisioning
And the HTTP status code should be "200"
And group "new-group" does not exist
+ Scenario: Delete a group with special characters
+ Given As an "admin"
+ And group "España" exists
+ When sending "DELETE" to "/cloud/groups/España"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And group "España" does not exist
+
Scenario: get enabled apps
Given As an "admin"
When sending "GET" to "/cloud/apps?filter=enabled"
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And apps returned are
- | files |
+ | comments |
| dav |
+ | files |
| files_sharing |
| files_trashbin |
| files_versions |
| provisioning_api |
+ | systemtags |
Scenario: get app info
Given As an "admin"
@@ -291,8 +312,3 @@ Feature: provisioning
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And app "files_external" is disabled
-
-
-
-
-
diff --git a/build/integration/features/sharing-v1.feature b/build/integration/features/sharing-v1.feature
index 07c05af2f54..1a1a5c1981a 100644
--- a/build/integration/features/sharing-v1.feature
+++ b/build/integration/features/sharing-v1.feature
@@ -1,6 +1,7 @@
Feature: sharing
Background:
Given using api version "1"
+ Given using dav path "remote.php/webdav"
Scenario: Creating a new share with user
Given user "user0" exists
@@ -28,7 +29,7 @@ Feature: sharing
Scenario: Creating a new public share
Given user "user0" exists
And As an "user0"
- When creating a public share with
+ When creating a share with
| path | welcome.txt |
| shareType | 3 |
Then the OCS status code should be "100"
@@ -38,7 +39,7 @@ Feature: sharing
Scenario: Creating a new public share with password
Given user "user0" exists
And As an "user0"
- When creating a public share with
+ When creating a share with
| path | welcome.txt |
| shareType | 3 |
| password | publicpw |
@@ -49,7 +50,7 @@ Feature: sharing
Scenario: Creating a new public share of a folder
Given user "user0" exists
And As an "user0"
- When creating a public share with
+ When creating a share with
| path | FOLDER |
| shareType | 3 |
| password | publicpw |
@@ -68,7 +69,7 @@ Feature: sharing
Scenario: Creating a new public share with password and adding an expiration date
Given user "user0" exists
And As an "user0"
- When creating a public share with
+ When creating a share with
| path | welcome.txt |
| shareType | 3 |
| password | publicpw |
@@ -81,7 +82,7 @@ Feature: sharing
Scenario: Creating a new public share, updating its expiration date and getting its info
Given user "user0" exists
And As an "user0"
- When creating a public share with
+ When creating a share with
| path | FOLDER |
| shareType | 3 |
And Updating last share with
@@ -111,7 +112,7 @@ Feature: sharing
Scenario: Creating a new public share, updating its password and getting its info
Given user "user0" exists
And As an "user0"
- When creating a public share with
+ When creating a share with
| path | FOLDER |
| shareType | 3 |
And Updating last share with
@@ -140,7 +141,7 @@ Feature: sharing
Scenario: Creating a new public share, updating its permissions and getting its info
Given user "user0" exists
And As an "user0"
- When creating a public share with
+ When creating a share with
| path | FOLDER |
| shareType | 3 |
And Updating last share with
@@ -169,7 +170,7 @@ Feature: sharing
Scenario: Creating a new public share, updating publicUpload option and getting its info
Given user "user0" exists
And As an "user0"
- When creating a public share with
+ When creating a share with
| path | FOLDER |
| shareType | 3 |
And Updating last share with
@@ -198,17 +199,17 @@ Feature: sharing
Scenario: getting all shares of a user using that user
Given user "user0" exists
And user "user1" exists
- And file "textfile0.txt" from user "user0" is shared with user "user1"
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
And As an "user0"
When sending "GET" to "/apps/files_sharing/api/v1/shares"
Then the OCS status code should be "100"
And the HTTP status code should be "200"
- And File "textfile0.txt" should be included in the response
+ And File "textfile0 (2).txt" should be included in the response
Scenario: getting all shares of a user using another user
Given user "user0" exists
And user "user1" exists
- And file "textfile0.txt" from user "user0" is shared with user "user1"
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
And As an "admin"
When sending "GET" to "/apps/files_sharing/api/v1/shares"
Then the OCS status code should be "100"
@@ -220,8 +221,8 @@ Feature: sharing
And user "user1" exists
And user "user2" exists
And user "user3" exists
- And file "textfile0.txt" from user "user0" is shared with user "user1"
- And file "textfile0.txt" from user "user0" is shared with user "user2"
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
+ And file "textfile0.txt" of user "user0" is shared with user "user2"
And As an "user0"
When sending "GET" to "/apps/files_sharing/api/v1/shares?path=textfile0.txt"
Then the OCS status code should be "100"
@@ -235,8 +236,8 @@ Feature: sharing
And user "user1" exists
And user "user2" exists
And user "user3" exists
- And file "textfile0.txt" from user "user0" is shared with user "user1"
- And file "textfile0.txt" from user "user1" is shared with user "user2"
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
+ And file "textfile0 (2).txt" of user "user1" is shared with user "user2"
And As an "user0"
When sending "GET" to "/apps/files_sharing/api/v1/shares?reshares=true&path=textfile0.txt"
Then the OCS status code should be "100"
@@ -248,7 +249,7 @@ Feature: sharing
Scenario: getting share info of a share
Given user "user0" exists
And user "user1" exists
- And file "textfile0.txt" from user "user0" is shared with user "user1"
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
And As an "user0"
When Getting info of last share
Then the OCS status code should be "100"
@@ -260,9 +261,9 @@ Feature: sharing
| share_type | 0 |
| share_with | user1 |
| file_source | A_NUMBER |
- | file_target | /textfile0.txt |
+ | file_target | /textfile0 (2).txt |
| path | /textfile0.txt |
- | permissions | 23 |
+ | permissions | 19 |
| stime | A_NUMBER |
| storage | A_NUMBER |
| mail_send | 0 |
@@ -272,22 +273,225 @@ Feature: sharing
| share_with_displayname | user1 |
| displayname_owner | user0 |
- Scenario: delete a share
+ Scenario: keep group permissions in sync
+ Given As an "admin"
Given user "user0" exists
And user "user1" exists
- And file "textfile0.txt" from user "user0" is shared with user "user1"
+ And group "group1" exists
+ And user "user1" belongs to group "group1"
+ And file "textfile0.txt" of user "user0" is shared with group "group1"
+ And User "user1" moved file "/textfile0.txt" to "/FOLDER/textfile0.txt"
And As an "user0"
- When Deleting last share
+ When Updating last share with
+ | permissions | 1 |
+ And Getting info of last share
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And Share fields of last share match with
+ | id | A_NUMBER |
+ | item_type | file |
+ | item_source | A_NUMBER |
+ | share_type | 1 |
+ | file_source | A_NUMBER |
+ | file_target | /textfile0.txt |
+ | permissions | 1 |
+ | stime | A_NUMBER |
+ | storage | A_NUMBER |
+ | mail_send | 0 |
+ | uid_owner | user0 |
+ | storage_id | home::user0 |
+ | file_parent | A_NUMBER |
+ | displayname_owner | user0 |
+
+ Scenario: Sharee can see the share
+ Given user "user0" exists
+ And user "user1" exists
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
+ And As an "user1"
+ When sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=true"
Then the OCS status code should be "100"
And the HTTP status code should be "200"
+ And last share_id is included in the answer
+ Scenario: Sharee can see the filtered share
+ Given user "user0" exists
+ And user "user1" exists
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
+ And file "textfile1.txt" of user "user0" is shared with user "user1"
+ And As an "user1"
+ When sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=true&path=textfile1 (2).txt"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And last share_id is included in the answer
+ Scenario: Sharee can't see the share that is filtered out
+ Given user "user0" exists
+ And user "user1" exists
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
+ And file "textfile1.txt" of user "user0" is shared with user "user1"
+ And As an "user1"
+ When sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=true&path=textfile0 (2).txt"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And last share_id is not included in the answer
+ Scenario: Sharee can see the group share
+ Given As an "admin"
+ And user "user0" exists
+ And user "user1" exists
+ And group "group0" exists
+ And user "user1" belongs to group "group0"
+ And file "textfile0.txt" of user "user0" is shared with group "group0"
+ And As an "user1"
+ When sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=true"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And last share_id is included in the answer
+
+ Scenario: User is not allowed to reshare file
+ As an "admin"
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And As an "user0"
+ And creating a share with
+ | path | /textfile0.txt |
+ | shareType | 0 |
+ | shareWith | user1 |
+ | permissions | 8 |
+ And As an "user1"
+ When creating a share with
+ | path | /textfile0 (2).txt |
+ | shareType | 0 |
+ | shareWith | user2 |
+ | permissions | 31 |
+ Then the OCS status code should be "404"
+ And the HTTP status code should be "200"
+ Scenario: User is not allowed to reshare file with more permissions
+ As an "admin"
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And As an "user0"
+ And creating a share with
+ | path | /textfile0.txt |
+ | shareType | 0 |
+ | shareWith | user1 |
+ | permissions | 16 |
+ And As an "user1"
+ When creating a share with
+ | path | /textfile0 (2).txt |
+ | shareType | 0 |
+ | shareWith | user2 |
+ | permissions | 31 |
+ Then the OCS status code should be "404"
+ And the HTTP status code should be "200"
+ Scenario: Get a share with a user which didn't received the share
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
+ And As an "user2"
+ When Getting info of last share
+ Then the OCS status code should be "404"
+ And the HTTP status code should be "200"
+ Scenario: Share of folder and sub-folder to same user - core#20645
+ Given As an "admin"
+ And user "user0" exists
+ And user "user1" exists
+ And group "group0" exists
+ And user "user1" belongs to group "group0"
+ And file "/PARENT" of user "user0" is shared with user "user1"
+ When file "/PARENT/CHILD" of user "user0" is shared with group "group0"
+ Then user "user1" should see following elements
+ | /FOLDER/ |
+ | /PARENT/ |
+ | /CHILD/ |
+ | /PARENT/parent.txt |
+ | /CHILD/child.txt |
+ And the HTTP status code should be "200"
+ Scenario: Share a file by multiple channels
+ Given As an "admin"
+ And user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And group "group0" exists
+ And user "user1" belongs to group "group0"
+ And user "user2" belongs to group "group0"
+ And user "user0" created a folder "/common"
+ And user "user0" created a folder "/common/sub"
+ And file "common" of user "user0" is shared with group "group0"
+ And file "textfile0.txt" of user "user1" is shared with user "user2"
+ And User "user1" moved file "/textfile0.txt" to "/common/textfile0.txt"
+ And User "user1" moved file "/common/textfile0.txt" to "/common/sub/textfile0.txt"
+ And As an "user2"
+ When Downloading file "/common/sub/textfile0.txt" with range "bytes=9-17"
+ Then Downloaded content should be "test text"
+ And Downloaded content when downloading file "/textfile0.txt" with range "bytes=9-17" should be "test text"
+ And user "user2" should see following elements
+ | /common/sub/textfile0.txt |
+ Scenario: Share a file by multiple channels
+ Given As an "admin"
+ And user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And group "group0" exists
+ And user "user1" belongs to group "group0"
+ And user "user2" belongs to group "group0"
+ And user "user0" created a folder "/common"
+ And user "user0" created a folder "/common/sub"
+ And file "common" of user "user0" is shared with group "group0"
+ And file "textfile0.txt" of user "user1" is shared with user "user2"
+ And User "user1" moved file "/textfile0.txt" to "/common/textfile0.txt"
+ And User "user1" moved file "/common/textfile0.txt" to "/common/sub/textfile0.txt"
+ And As an "user2"
+ When Downloading file "/textfile0.txt" with range "bytes=9-17"
+ Then Downloaded content should be "test text"
+ And user "user2" should see following elements
+ | /common/sub/textfile0.txt |
+ Scenario: Delete all group shares
+ Given As an "admin"
+ And user "user0" exists
+ And user "user1" exists
+ And group "group1" exists
+ And user "user1" belongs to group "group1"
+ And file "textfile0.txt" of user "user0" is shared with group "group1"
+ And User "user1" moved file "/textfile0.txt" to "/FOLDER/textfile0.txt"
+ And As an "user0"
+ And Deleting last share
+ And As an "user1"
+ When sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=true"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And last share_id is not included in the answer
+ Scenario: delete a share
+ Given user "user0" exists
+ And user "user1" exists
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
+ And As an "user0"
+ When Deleting last share
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ Scenario: Keep usergroup shares (#22143)
+ Given As an "admin"
+ And user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And group "group" exists
+ And user "user1" belongs to group "group"
+ And user "user2" belongs to group "group"
+ And user "user0" created a folder "/TMP"
+ And file "TMP" of user "user0" is shared with group "group"
+ And user "user1" created a folder "/myFOLDER"
+ And User "user1" moves file "/TMP" to "/myFOLDER/myTMP"
+ And user "user2" does not exist
+ And user "user1" should see following elements
+ | /myFOLDER/myTMP/ |
diff --git a/build/integration/features/webdav-related.feature b/build/integration/features/webdav-related.feature
new file mode 100644
index 00000000000..8be2c196308
--- /dev/null
+++ b/build/integration/features/webdav-related.feature
@@ -0,0 +1,45 @@
+Feature: sharing
+ Background:
+ Given using api version "1"
+
+ Scenario: moving a file old way
+ Given using dav path "remote.php/webdav"
+ And As an "admin"
+ And user "user0" exists
+ When User "user0" moves file "/textfile0.txt" to "/FOLDER/textfile0.txt"
+ Then the HTTP status code should be "201"
+
+ Scenario: download a file with range
+ Given using dav path "remote.php/webdav"
+ And As an "admin"
+ When Downloading file "/welcome.txt" with range "bytes=51-77"
+ Then Downloaded content should be "example file for developers"
+
+
+ Scenario: Upload forbidden if quota is 0
+ Given using dav path "remote.php/webdav"
+ And As an "admin"
+ And user "user0" exists
+ And user "user0" has a quota of "0"
+ When User "user0" uploads file "data/textfile.txt" to "/asdf.txt"
+ Then the HTTP status code should be "507"
+
+ Scenario: download a public shared file with range
+ Given user "user0" exists
+ And As an "user0"
+ When creating a share with
+ | path | welcome.txt |
+ | shareType | 3 |
+ And Downloading last public shared file with range "bytes=51-77"
+ Then Downloaded content should be "example file for developers"
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/integration/federation_features/federated.feature b/build/integration/federation_features/federated.feature
new file mode 100644
index 00000000000..5437d01dee2
--- /dev/null
+++ b/build/integration/federation_features/federated.feature
@@ -0,0 +1,26 @@
+Feature: federated
+ Background:
+ Given using api version "1"
+
+ Scenario: Federate share a file with another server
+ Given Using server "REMOTE"
+ And user "user1" exists
+ And Using server "LOCAL"
+ And user "user0" exists
+ When User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/integration/run.sh b/build/integration/run.sh
index 5456a784404..5a222bda3e3 100755
--- a/build/integration/run.sh
+++ b/build/integration/run.sh
@@ -2,18 +2,37 @@
composer install
-# TODO: avoid port collision on jenkins - use $EXECUTOR_NUMBER
+SCENARIO_TO_RUN=$1
+HIDE_OC_LOGS=$2
+
+# avoid port collision on jenkins - use $EXECUTOR_NUMBER
if [ -z "$EXECUTOR_NUMBER" ]; then
EXECUTOR_NUMBER=0
fi
PORT=$((8080 + $EXECUTOR_NUMBER))
-#PORT=8080
echo $PORT
php -S localhost:$PORT -t ../.. &
PHPPID=$!
echo $PHPPID
+PORT_FED=$((8180 + $EXECUTOR_NUMBER))
+echo $PORT_FED
+php -S localhost:$PORT_FED -t ../.. &
+PHPPID_FED=$!
+echo $PHPPID_FED
+
export TEST_SERVER_URL="http://localhost:$PORT/ocs/"
-vendor/bin/behat -f junit -f pretty
+export TEST_SERVER_FED_URL="http://localhost:$PORT_FED/ocs/"
+
+vendor/bin/behat -f junit -f pretty $SCENARIO_TO_RUN
+RESULT=$?
kill $PHPPID
+kill $PHPPID_FED
+
+if [ -z $HIDE_OC_LOGS ]; then
+ tail "../../data/owncloud.log"
+fi
+
+exit $RESULT
+
diff --git a/build/license.php b/build/license.php
index 6f8388ee069..ce6fceb8160 100644
--- a/build/license.php
+++ b/build/license.php
@@ -118,6 +118,9 @@ With help from many libraries and frameworks including:
echo "License updated: $path" . PHP_EOL;
}
+ /**
+ * @param string $source
+ */
private function isMITLicensed($source) {
$lines = explode(PHP_EOL, $source);
while(!empty($lines)) {
@@ -131,6 +134,9 @@ With help from many libraries and frameworks including:
return false;
}
+ /**
+ * @param string $source
+ */
private function eatOldLicense($source) {
$lines = explode(PHP_EOL, $source);
while(!empty($lines)) {
@@ -186,8 +192,10 @@ if (isset($argv[1])) {
$licenses->exec($argv[1]);
} else {
$licenses->exec([
- '../apps/files',
+ '../apps/dav',
'../apps/encryption',
+ '../apps/federation',
+ '../apps/files',
'../apps/files_external',
'../apps/files_sharing',
'../apps/files_trashbin',
diff --git a/buildjsdocs.sh b/buildjsdocs.sh
index 90562558f66..57eefb29fd0 100755
--- a/buildjsdocs.sh
+++ b/buildjsdocs.sh
@@ -11,7 +11,7 @@ NPM="$(which npm 2>/dev/null)"
PREFIX="build"
OUTPUT_DIR="build/jsdocs"
-JS_FILES="core/js/*.js apps/*/js/*.js"
+JS_FILES="core/js/*.js core/js/**/*.js apps/*/js/*.js"
if test -z "$NPM"
then
diff --git a/config/config.sample.php b/config/config.sample.php
index 02e5aba3e94..81a02efb3f7 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -9,8 +9,8 @@
* consider important for your instance to your working ``config.php``, and
* apply configuration options that are pertinent for your instance.
*
- * This file is used to generate the config documentation. Please consider
- * following requirements of the current parser:
+ * This file is used to generate the configuration documentation.
+ * Please consider following requirements of the current parser:
* * all comments need to start with `/**` and end with ` *\/` - each on their
* own line
* * add a `@see CONFIG_INDEX` to copy a previously described config option
@@ -213,6 +213,13 @@ $CONFIG = array(
)
),
+/**
+ * If your user backend does not allow to reset the password (e.g. when it's a
+ * read-only user backend like LDAP), you can specify a custom link, where the
+ * user is redirected to, when clicking the "reset password" link after a failed
+ * login-attempt.
+ */
+'lost_password_link' => 'https://example.org/link/to/password/reset',
/**
* Mail Parameters
@@ -398,7 +405,7 @@ $CONFIG = array(
* delete all files in the trash bin that are older than D days
* automatically, delete other files anytime if space needed
* * ``D1, D2``
- * keep files and folders the in trash bin for at least D1 days and
+ * keep files and folders in the trash bin for at least D1 days and
* delete when exceeds D2 days
* * ``disabled``
* trash bin auto clean disabled, files and folders will be kept forever
@@ -470,20 +477,27 @@ $CONFIG = array(
'check_for_working_webdav' => true,
/**
+ * Allows ownCloud to verify a working .well-known URL redirects. This is done
+ * by attempting to make a request from JS to
+ * https://your-domain.com/.well-known/caldav/
+ */
+'check_for_working_wellknown_setup' => true,
+
+/**
* This is a crucial security check on Apache servers that should always be set
* to ``true``. This verifies that the ``.htaccess`` file is writable and works.
* If it is not, then any options controlled by ``.htaccess``, such as large
* file uploads, will not work. It also runs checks on the ``data/`` directory,
- * which verifies that it can't be accessed directly through the web server.
+ * which verifies that it can't be accessed directly through the Web server.
*/
'check_for_working_htaccess' => true,
/**
- * In certain environments it is desired to have a read-only config file.
+ * In certain environments it is desired to have a read-only configuration file.
* When this switch is set to ``true`` ownCloud will not verify whether the
* configuration is writable. However, it will not be possible to configure
- * all options via the web-interface. Furthermore, when updating ownCloud
- * it is required to make the config file writable again for the update
+ * all options via the Web interface. Furthermore, when updating ownCloud
+ * it is required to make the configuration file writable again for the update
* process.
*/
'config_is_read_only' => false,
@@ -646,9 +660,9 @@ $CONFIG = array(
* Use the ``apps_paths`` parameter to set the location of the Apps directory,
* which should be scanned for available apps, and where user-specific apps
* should be installed from the Apps store. The ``path`` defines the absolute
- * file system path to the app folder. The key ``url`` defines the HTTP web path
- * to that folder, starting from the ownCloud web root. The key ``writable``
- * indicates if a web server can write files to that folder.
+ * file system path to the app folder. The key ``url`` defines the HTTP Web path
+ * to that folder, starting from the ownCloud webroot. The key ``writable``
+ * indicates if a Web server can write files to that folder.
*/
'apps_paths' => array(
array(
@@ -792,20 +806,24 @@ $CONFIG = array(
'ldapUserCleanupInterval' => 51,
/**
- * Enforce the existence of the home folder naming rule for all users
- *
- * Following scenario:
- * * a home folder naming rule is set in LDAP advanced settings
- * * a user doesn't have the home folder naming rule attribute set
- *
- * If this is set to **true** (default) it will NOT fallback to the core's
- * default naming rule of using the internal user ID as home folder name.
- *
- * If this is set to **false** it will fallback for the users without the
- * attribute set to naming the home folder like the internal user ID.
+ * Comments
*
+ * Global settings for the Comments infrastructure
+ */
+
+/**
+ * Replaces the default Comments Manager Factory. This can be utilized if an
+ * own or 3rdParty CommentsManager should be used that – for instance – uses the
+ * filesystem instead of the database to keep the comments.
+ */
+'comments.managerFactory' => '\OC\Comments\ManagerFactory',
+
+/**
+ * Replaces the default System Tags Manager Factory. This can be utilized if an
+ * own or 3rdParty SystemTagsManager should be used that – for instance – uses the
+ * filesystem instead of the database to keep the comments.
*/
-'enforce_home_folder_naming_rule' => true,
+'systemtags.managerFactory' => '\OC\SystemTag\ManagerFactory',
/**
* Maintenance
@@ -843,6 +861,11 @@ $CONFIG = array(
),
/**
+ * Allow the configuration of system wide trusted certificates
+ */
+'enable_certificate_management' => false,
+
+/**
* Memory caching backend configuration
*
* Available cache backends:
@@ -954,11 +977,29 @@ $CONFIG = array(
// dev-/trystack uses swift by default, the lib defaults to 'cloudFiles'
// if omitted
'serviceName' => 'swift',
+ // The Interface / url Type, optional
+ 'urlType' => 'internal'
),
),
+
+/**
+ * Sharing
+ *
+ * Global settings for Sharing
+ */
+
/**
- * All other config options
+ * Replaces the default Share Provider Factory. This can be utilized if
+ * own or 3rdParty Share Providers be used that – for instance – uses the
+ * filesystem instead of the database to keep the share information.
+ */
+'sharing.managerFactory' => '\OC\Share20\ProviderFactory',
+
+
+
+/**
+ * All other configuration options
*/
/**
@@ -970,8 +1011,8 @@ $CONFIG = array(
),
/**
- * sqlite3 journal mode can be specified using this config parameter - can be
- * 'WAL' or 'DELETE' see for more details https://www.sqlite.org/wal.html
+ * sqlite3 journal mode can be specified using this configuration parameter -
+ * can be 'WAL' or 'DELETE' see for more details https://www.sqlite.org/wal.html
*/
'sqlite.journal_mode' => 'DELETE',
@@ -997,7 +1038,7 @@ $CONFIG = array(
* restricted, or if external storages which do not support streaming are in
* use.
*
- * The web server user must have write access to this directory.
+ * The Web server user must have write access to this directory.
*/
'tempdirectory' => '/tmp/owncloudtemp',
@@ -1059,14 +1100,11 @@ $CONFIG = array(
*
* 1 -> Check each file or folder at most once per request, recommended for
* general use if outside changes might happen.
- *
- * 2 -> Check every time the filesystem is used, causes a performance hit when
- * using external storages, not recommended for regular use.
*/
'filesystem_check_changes' => 0,
/**
- * All css and js files will be served by the web server statically in one js
+ * All css and js files will be served by the Web server statically in one js
* file and one css file if this is set to ``true``. This improves performance.
*/
'asset-pipeline.enabled' => false,
@@ -1077,7 +1115,7 @@ $CONFIG = array(
* will be stored in a subdirectory of this directory named 'assets'. The
* server *must* be configured to serve that directory as $WEBROOT/assets.
* You will only likely need to change this if the main ownCloud directory
- * is not writeable by the web server in your configuration.
+ * is not writeable by the Web server in your configuration.
*/
'assetdirectory' => '/var/www/owncloud',
diff --git a/console.php b/console.php
index 8bfbabf2a03..2073654fa8d 100644
--- a/console.php
+++ b/console.php
@@ -2,13 +2,14 @@
/**
* @author Bart Visscher <bartv@thisnet.nl>
* @author Christian Kampka <christian@kampka.net>
+ * @author Edward Crompton <edward.crompton@gmail.com>
* @author Jost Baron <Jost.Baron@gmx.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Philippe Le Brouster <plb@nebkha.net>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -60,10 +61,25 @@ try {
echo "Console has to be executed with the user that owns the file config/config.php" . PHP_EOL;
echo "Current user: " . $user['name'] . PHP_EOL;
echo "Owner of config.php: " . $configUser['name'] . PHP_EOL;
+ echo "Try adding 'sudo -u " . $configUser['name'] . " ' to the beginning of the command (without the single quotes)" . PHP_EOL;
exit(0);
}
}
+ $oldWorkingDir = getcwd();
+ if ($oldWorkingDir === false) {
+ echo "This script can be run from the ownCloud root directory only." . PHP_EOL;
+ echo "Can't determine current working dir - the script will continue to work but be aware of the above fact." . PHP_EOL;
+ } else if ($oldWorkingDir !== __DIR__ && !chdir(__DIR__)) {
+ echo "This script can be run from the ownCloud root directory only." . PHP_EOL;
+ echo "Can't change to ownCloud root diretory." . PHP_EOL;
+ exit(1);
+ }
+
+ if (!function_exists('pcntl_signal')) {
+ echo "The process control (PCNTL) extensions are required in case you want to interrupt long running commands - see http://php.net/manual/en/book.pcntl.php" . PHP_EOL;
+ }
+
$application = new Application(\OC::$server->getConfig());
$application->loadCommands(new ConsoleOutput());
$application->run();
diff --git a/core/ajax/appconfig.php b/core/ajax/appconfig.php
index 3ad32ff1a3e..9602269d7a7 100644
--- a/core/ajax/appconfig.php
+++ b/core/ajax/appconfig.php
@@ -5,7 +5,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/ajax/preview.php b/core/ajax/preview.php
index 05eb4b62b79..119bad1eea2 100644
--- a/core/ajax/preview.php
+++ b/core/ajax/preview.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/ajax/share.php b/core/ajax/share.php
index fd42a94de6e..cd4144bc6a7 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -16,9 +16,8 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,6 +34,8 @@
*
*/
+use OCP\IUser;
+
OC_JSON::checkLoggedIn();
OCP\JSON::callCheck();
@@ -135,17 +136,23 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
$itemSource = (string)$_POST['itemSource'];
$recipient = (string)$_POST['recipient'];
+ $userManager = \OC::$server->getUserManager();
+ $recipientList = [];
if($shareType === \OCP\Share::SHARE_TYPE_USER) {
- $recipientList[] = $recipient;
+ $recipientList[] = $userManager->get($recipient);
} elseif ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
$recipientList = \OC_Group::usersInGroup($recipient);
+ $group = \OC::$server->getGroupManager()->get($recipient);
+ $recipientList = $group->searchUsers('');
}
// don't send a mail to the user who shared the file
- $recipientList = array_diff($recipientList, array(\OCP\User::getUser()));
+ $recipientList = array_filter($recipientList, function($user) {
+ /** @var IUser $user */
+ return $user->getUID() !== \OCP\User::getUser();
+ });
$mailNotification = new \OC\Share\MailNotifications(
- \OC::$server->getUserSession()->getUser()->getUID(),
- \OC::$server->getConfig(),
+ \OC::$server->getUserSession()->getUser(),
\OC::$server->getL10N('lib'),
\OC::$server->getMailer(),
\OC::$server->getLogger(),
@@ -183,8 +190,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
$to_address = (string)$_POST['toaddress'];
$mailNotification = new \OC\Share\MailNotifications(
- \OC::$server->getUserSession()->getUser()->getUID(),
- \OC::$server->getConfig(),
+ \OC::$server->getUserSession()->getUser(),
\OC::$server->getL10N('lib'),
\OC::$server->getMailer(),
\OC::$server->getLogger(),
@@ -199,7 +205,6 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
} catch (Exception $e) {
\OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR);
}
-
}
$result = $mailNotification->sendLinkShareMail($to_address, $file, $link, $expiration);
diff --git a/core/ajax/update.php b/core/ajax/update.php
index 7da9b71b751..4d8fe19f168 100644
--- a/core/ajax/update.php
+++ b/core/ajax/update.php
@@ -1,6 +1,6 @@
<?php
/**
- * @author Bart Visscher <bartv@thisnet.nl>
+ * @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
@@ -10,7 +10,7 @@
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -47,6 +47,7 @@ if (OC::checkUpgrade(false)) {
$updater = new \OC\Updater(
\OC::$server->getHTTPHelper(),
$config,
+ \OC::$server->getIntegrityCodeChecker(),
$logger
);
$incompatibleApps = [];
@@ -103,10 +104,16 @@ if (OC::checkUpgrade(false)) {
$config->setSystemValue('maintenance', false);
});
$updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use($eventSource, $l) {
- $eventSource->send('success', (string)$l->t('Set log level to debug - current level: "%s"', [ $logLevelName ]));
+ $eventSource->send('success', (string)$l->t('Set log level to debug'));
});
$updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($eventSource, $l) {
- $eventSource->send('success', (string)$l->t('Reset log level to "%s"', [ $logLevelName ]));
+ $eventSource->send('success', (string)$l->t('Reset log level'));
+ });
+ $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($eventSource, $l) {
+ $eventSource->send('success', (string)$l->t('Starting code integrity check'));
+ });
+ $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($eventSource, $l) {
+ $eventSource->send('success', (string)$l->t('Finished code integrity check'));
});
try {
diff --git a/core/application.php b/core/application.php
index dfc4fc38c7d..30376ee4f2e 100644
--- a/core/application.php
+++ b/core/application.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,9 +29,9 @@ namespace OC\Core;
use OC\AppFramework\Utility\SimpleContainer;
use OC\AppFramework\Utility\TimeFactory;
use \OCP\AppFramework\App;
-use OC\Core\LostPassword\Controller\LostController;
-use OC\Core\User\UserController;
-use OC\Core\Avatar\AvatarController;
+use OC\Core\Controller\LostController;
+use OC\Core\Controller\UserController;
+use OC\Core\Controller\AvatarController;
use \OCP\Util;
/**
diff --git a/core/command/app/checkcode.php b/core/command/app/checkcode.php
index e186d458c01..78f4390e70a 100644
--- a/core/command/app/checkcode.php
+++ b/core/command/app/checkcode.php
@@ -2,10 +2,10 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -131,6 +131,10 @@ class CheckCode extends Command {
}
});
+ $infoChecker->listen('InfoChecker', 'missingRequirement', function($minMax) use ($output) {
+ $output->writeln("<comment>ownCloud $minMax version requirement missing (will be an error in ownCloud 11 and later)</comment>");
+ });
+
$infoChecker->listen('InfoChecker', 'duplicateRequirement', function($minMax) use ($output) {
$output->writeln("<error>Duplicate $minMax ownCloud version requirement found</error>");
});
diff --git a/core/command/app/disable.php b/core/command/app/disable.php
index 6c04860789f..b3157faf32e 100644
--- a/core/command/app/disable.php
+++ b/core/command/app/disable.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,12 +23,25 @@
namespace OC\Core\Command\App;
+use OCP\App\IAppManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class Disable extends Command {
+
+ /** @var IAppManager */
+ protected $manager;
+
+ /**
+ * @param IAppManager $manager
+ */
+ public function __construct(IAppManager $manager) {
+ parent::__construct();
+ $this->manager = $manager;
+ }
+
protected function configure() {
$this
->setName('app:disable')
@@ -42,9 +55,9 @@ class Disable extends Command {
protected function execute(InputInterface $input, OutputInterface $output) {
$appId = $input->getArgument('app-id');
- if (\OC_App::isEnabled($appId)) {
+ if ($this->manager->isInstalled($appId)) {
try {
- \OC_App::disable($appId);
+ $this->manager->disableApp($appId);
$output->writeln($appId . ' disabled');
} catch(\Exception $e) {
$output->writeln($e->getMessage());
diff --git a/core/command/app/enable.php b/core/command/app/enable.php
index f82c23e7e60..4315972bae2 100644
--- a/core/command/app/enable.php
+++ b/core/command/app/enable.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,12 +23,26 @@
namespace OC\Core\Command\App;
+use OCP\App\IAppManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class Enable extends Command {
+
+ /** @var IAppManager */
+ protected $manager;
+
+ /**
+ * @param IAppManager $manager
+ */
+ public function __construct(IAppManager $manager) {
+ parent::__construct();
+ $this->manager = $manager;
+ }
+
protected function configure() {
$this
->setName('app:enable')
@@ -37,19 +51,36 @@ class Enable extends Command {
'app-id',
InputArgument::REQUIRED,
'enable the specified app'
- );
+ )
+ ->addOption(
+ 'groups',
+ 'g',
+ InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
+ 'enable the app only for a list of groups'
+ )
+ ;
}
protected function execute(InputInterface $input, OutputInterface $output) {
$appId = $input->getArgument('app-id');
- if (\OC_App::isEnabled($appId)) {
- $output->writeln($appId . ' is already enabled');
- } else if (!\OC_App::getAppPath($appId)) {
+
+ if (!\OC_App::getAppPath($appId)) {
$output->writeln($appId . ' not found');
return 1;
- } else {
+ }
+
+ $groups = $input->getOption('groups');
+ if ($this->manager->isInstalled($appId) && empty($groups)) {
+ $output->writeln($appId . ' is already enabled');
+ }
+
+ if (empty($groups)) {
\OC_App::enable($appId);
$output->writeln($appId . ' enabled');
+ } else {
+ \OC_App::enable($appId, $groups);
+ $output->writeln($appId . ' enabled for groups: ' . implode(', ', $groups));
}
+ return 0;
}
}
diff --git a/core/command/app/getpath.php b/core/command/app/getpath.php
new file mode 100644
index 00000000000..33a3f64c53d
--- /dev/null
+++ b/core/command/app/getpath.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @author Victor Dubiniuk <dubiniuk@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\App;
+
+use OC\Core\Command\Base;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class GetPath extends Base {
+ protected function configure() {
+ parent::configure();
+
+ $this
+ ->setName('app:getpath')
+ ->setDescription('Get an absolute path to the app directory')
+ ->addArgument(
+ 'app',
+ InputArgument::REQUIRED,
+ 'Name of the app'
+ )
+ ;
+ }
+
+ /**
+ * Executes the current command.
+ *
+ * @param InputInterface $input An InputInterface instance
+ * @param OutputInterface $output An OutputInterface instance
+ * @return null|int null or 0 if everything went fine, or an error code
+ */
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $appName = $input->getArgument('app');
+ $path = \OC_App::getAppPath($appName);
+ if ($path !== false) {
+ $output->writeln($path);
+ return 0;
+ }
+
+ // App not found, exit with non-zero
+ return 1;
+ }
+}
diff --git a/core/command/app/listapps.php b/core/command/app/listapps.php
index e483037d45d..d7546b3c0c7 100644
--- a/core/command/app/listapps.php
+++ b/core/command/app/listapps.php
@@ -3,8 +3,9 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,27 +25,56 @@
namespace OC\Core\Command\App;
use OC\Core\Command\Base;
+use OCP\App\IAppManager;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class ListApps extends Base {
+
+ /** @var IAppManager */
+ protected $manager;
+
+ /**
+ * @param IAppManager $manager
+ */
+ public function __construct(IAppManager $manager) {
+ parent::__construct();
+ $this->manager = $manager;
+ }
+
protected function configure() {
parent::configure();
$this
->setName('app:list')
->setDescription('List all available apps')
+ ->addOption(
+ 'shipped',
+ null,
+ InputOption::VALUE_REQUIRED,
+ 'true - limit to shipped apps only, false - limit to non-shipped apps only'
+ )
;
}
protected function execute(InputInterface $input, OutputInterface $output) {
+ if ($input->getOption('shipped') === 'true' || $input->getOption('shipped') === 'false'){
+ $shippedFilter = $input->getOption('shipped') === 'true';
+ } else {
+ $shippedFilter = null;
+ }
+
$apps = \OC_App::getAllApps();
$enabledApps = $disabledApps = [];
$versions = \OC_App::getAppVersions();
//sort enabled apps above disabled apps
foreach ($apps as $app) {
- if (\OC_App::isEnabled($app)) {
+ if ($shippedFilter !== null && \OC_App::isShipped($app) !== $shippedFilter){
+ continue;
+ }
+ if ($this->manager->isInstalled($app)) {
$enabledApps[] = $app;
} else {
$disabledApps[] = $app;
diff --git a/core/command/base.php b/core/command/base.php
index 0a4b002c1ca..a34d7ec1c9a 100644
--- a/core/command/base.php
+++ b/core/command/base.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -33,6 +33,12 @@ class Base extends Command {
protected $defaultOutputFormat = self::OUTPUT_FORMAT_PLAIN;
+ /** @var boolean */
+ private $php_pcntl_signal = false;
+
+ /** @var boolean */
+ private $interrupted = false;
+
protected function configure() {
$this
->addOption(
@@ -43,6 +49,15 @@ class Base extends Command {
$this->defaultOutputFormat
)
;
+
+ // check if the php pcntl_signal functions are accessible
+ $this->php_pcntl_signal = function_exists('pcntl_signal');
+ if ($this->php_pcntl_signal) {
+ // Collect interrupts and notify the running command
+ pcntl_signal(SIGTERM, [$this, 'cancelOperation']);
+ pcntl_signal(SIGINT, [$this, 'cancelOperation']);
+ }
+
}
/**
@@ -116,4 +131,27 @@ class Base extends Command {
return $value;
}
}
+
+ /**
+ * @return bool
+ */
+ protected function hasBeenInterrupted() {
+ // return always false if pcntl_signal functions are not accessible
+ if ($this->php_pcntl_signal) {
+ pcntl_signal_dispatch();
+ return $this->interrupted;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Changes the status of the command to "interrupted" if ctrl-c has been pressed
+ *
+ * Gives a chance to the command to properly terminate what it's doing
+ */
+ private function cancelOperation() {
+ $this->interrupted = true;
+ }
+
}
diff --git a/core/command/check.php b/core/command/check.php
index cd7f8ee8e4c..c2e92f7a8da 100644
--- a/core/command/check.php
+++ b/core/command/check.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/config/app/deleteconfig.php b/core/command/config/app/deleteconfig.php
index bc031b0d589..cccd92ea3d6 100644
--- a/core/command/config/app/deleteconfig.php
+++ b/core/command/config/app/deleteconfig.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/config/app/getconfig.php b/core/command/config/app/getconfig.php
index 186ed46999f..abe71e57d8c 100644
--- a/core/command/config/app/getconfig.php
+++ b/core/command/config/app/getconfig.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/config/app/setconfig.php b/core/command/config/app/setconfig.php
index eea58a63c5e..097fde6ba95 100644
--- a/core/command/config/app/setconfig.php
+++ b/core/command/config/app/setconfig.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/config/import.php b/core/command/config/import.php
index c53fd7255f9..7f1e09d2c95 100644
--- a/core/command/config/import.php
+++ b/core/command/config/import.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/config/listconfigs.php b/core/command/config/listconfigs.php
index 37aeb53c6f5..afebe4c4c07 100644
--- a/core/command/config/listconfigs.php
+++ b/core/command/config/listconfigs.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/config/system/deleteconfig.php b/core/command/config/system/deleteconfig.php
index 4d193647c85..374f5ac69b7 100644
--- a/core/command/config/system/deleteconfig.php
+++ b/core/command/config/system/deleteconfig.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -48,8 +48,8 @@ class DeleteConfig extends Base {
->setDescription('Delete a system config value')
->addArgument(
'name',
- InputArgument::REQUIRED,
- 'Name of the config to delete'
+ InputArgument::REQUIRED | InputArgument::IS_ARRAY,
+ 'Name of the config to delete, specify multiple for array parameter'
)
->addOption(
'error-if-not-exists',
@@ -61,15 +61,57 @@ class DeleteConfig extends Base {
}
protected function execute(InputInterface $input, OutputInterface $output) {
- $configName = $input->getArgument('name');
+ $configNames = $input->getArgument('name');
+ $configName = $configNames[0];
- if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) {
- $output->writeln('<error>System config ' . $configName . ' could not be deleted because it did not exist</error>');
- return 1;
+ if (sizeof($configNames) > 1) {
+ if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) {
+ $output->writeln('<error>System config ' . implode(' => ', $configNames) . ' could not be deleted because it did not exist</error>');
+ return 1;
+ }
+
+ $value = $this->systemConfig->getValue($configName);
+
+ try {
+ $value = $this->removeSubValue(array_slice($configNames, 1), $value, $input->hasParameterOption('--error-if-not-exists'));
+ }
+ catch (\UnexpectedValueException $e) {
+ $output->writeln('<error>System config ' . implode(' => ', $configNames) . ' could not be deleted because it did not exist</error>');
+ return 1;
+ }
+
+ $this->systemConfig->setValue($configName, $value);
+ $output->writeln('<info>System config value ' . implode(' => ', $configNames) . ' deleted</info>');
+ return 0;
+ } else {
+ if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) {
+ $output->writeln('<error>System config ' . $configName . ' could not be deleted because it did not exist</error>');
+ return 1;
+ }
+
+ $this->systemConfig->deleteValue($configName);
+ $output->writeln('<info>System config value ' . $configName . ' deleted</info>');
+ return 0;
+ }
+ }
+
+ protected function removeSubValue($keys, $currentValue, $throwError) {
+ $nextKey = array_shift($keys);
+
+ if (is_array($currentValue)) {
+ if (isset($currentValue[$nextKey])) {
+ if (empty($keys)) {
+ unset($currentValue[$nextKey]);
+ } else {
+ $currentValue[$nextKey] = $this->removeSubValue($keys, $currentValue[$nextKey], $throwError);
+ }
+ } else if ($throwError) {
+ throw new \UnexpectedValueException('Config parameter does not exist');
+ }
+ } else if ($throwError) {
+ throw new \UnexpectedValueException('Config parameter does not exist');
}
- $this->systemConfig->deleteValue($configName);
- $output->writeln('<info>System config value ' . $configName . ' deleted</info>');
- return 0;
+ return $currentValue;
}
}
diff --git a/core/command/config/system/getconfig.php b/core/command/config/system/getconfig.php
index d53de18a0bb..b76474112a0 100644
--- a/core/command/config/system/getconfig.php
+++ b/core/command/config/system/getconfig.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -48,8 +48,8 @@ class GetConfig extends Base {
->setDescription('Get a system config value')
->addArgument(
'name',
- InputArgument::REQUIRED,
- 'Name of the config to get'
+ InputArgument::REQUIRED | InputArgument::IS_ARRAY,
+ 'Name of the config to get, specify multiple for array parameter'
)
->addOption(
'default-value',
@@ -68,7 +68,8 @@ class GetConfig extends Base {
* @return null|int null or 0 if everything went fine, or an error code
*/
protected function execute(InputInterface $input, OutputInterface $output) {
- $configName = $input->getArgument('name');
+ $configNames = $input->getArgument('name');
+ $configName = array_shift($configNames);
$defaultValue = $input->getOption('default-value');
if (!in_array($configName, $this->systemConfig->getKeys()) && !$input->hasParameterOption('--default-value')) {
@@ -79,6 +80,18 @@ class GetConfig extends Base {
$configValue = $defaultValue;
} else {
$configValue = $this->systemConfig->getValue($configName);
+ if (!empty($configNames)) {
+ foreach ($configNames as $configName) {
+ if (isset($configValue[$configName])) {
+ $configValue = $configValue[$configName];
+ } else if (!$input->hasParameterOption('--default-value')) {
+ return 1;
+ } else {
+ $configValue = $defaultValue;
+ break;
+ }
+ }
+ }
}
$this->writeMixedInOutputFormat($input, $output, $configValue);
diff --git a/core/command/config/system/setconfig.php b/core/command/config/system/setconfig.php
index 82b36cca164..45ba01e9284 100644
--- a/core/command/config/system/setconfig.php
+++ b/core/command/config/system/setconfig.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -48,8 +48,15 @@ class SetConfig extends Base {
->setDescription('Set a system config value')
->addArgument(
'name',
- InputArgument::REQUIRED,
- 'Name of the config to set'
+ InputArgument::REQUIRED | InputArgument::IS_ARRAY,
+ 'Name of the config parameter, specify multiple for array parameter'
+ )
+ ->addOption(
+ 'type',
+ null,
+ InputOption::VALUE_REQUIRED,
+ 'Value type [string, integer, double, boolean]',
+ 'string'
)
->addOption(
'value',
@@ -67,16 +74,124 @@ class SetConfig extends Base {
}
protected function execute(InputInterface $input, OutputInterface $output) {
- $configName = $input->getArgument('name');
+ $configNames = $input->getArgument('name');
+ $configName = $configNames[0];
+ $configValue = $this->castValue($input->getOption('value'), $input->getOption('type'));
+ $updateOnly = $input->getOption('update-only');
+
+ if (sizeof($configNames) > 1) {
+ $existingValue = $this->systemConfig->getValue($configName);
+
+ $newValue = $this->mergeArrayValue(
+ array_slice($configNames, 1), $existingValue, $configValue['value'], $updateOnly
+ );
+
+ $this->systemConfig->setValue($configName, $newValue);
+ } else {
+ if ($updateOnly && !in_array($configName, $this->systemConfig->getKeys(), true)) {
+ throw new \UnexpectedValueException('Config parameter does not exist');
+ }
- if (!in_array($configName, $this->systemConfig->getKeys()) && $input->hasParameterOption('--update-only')) {
- $output->writeln('<comment>Config value ' . $configName . ' not updated, as it has not been set before.</comment>');
- return 1;
+ $this->systemConfig->setValue($configName, $configValue['value']);
}
- $configValue = $input->getOption('value');
- $this->systemConfig->setValue($configName, $configValue);
- $output->writeln('<info>System config value ' . $configName . ' set to ' . $configValue . '</info>');
+ $output->writeln('<info>System config value ' . implode(' => ', $configNames) . ' set to ' . $configValue['readable-value'] . '</info>');
return 0;
}
+
+ /**
+ * @param string $value
+ * @param string $type
+ * @return mixed
+ * @throws \InvalidArgumentException
+ */
+ protected function castValue($value, $type) {
+ switch ($type) {
+ case 'integer':
+ case 'int':
+ if (!is_numeric($value)) {
+ throw new \InvalidArgumentException('Non-numeric value specified');
+ }
+ return [
+ 'value' => (int) $value,
+ 'readable-value' => 'integer ' . (int) $value,
+ ];
+
+ case 'double':
+ case 'float':
+ if (!is_numeric($value)) {
+ throw new \InvalidArgumentException('Non-numeric value specified');
+ }
+ return [
+ 'value' => (double) $value,
+ 'readable-value' => 'double ' . (double) $value,
+ ];
+
+ case 'boolean':
+ case 'bool':
+ $value = strtolower($value);
+ switch ($value) {
+ case 'true':
+ return [
+ 'value' => true,
+ 'readable-value' => 'boolean ' . $value,
+ ];
+
+ case 'false':
+ return [
+ 'value' => false,
+ 'readable-value' => 'boolean ' . $value,
+ ];
+
+ default:
+ throw new \InvalidArgumentException('Unable to parse value as boolean');
+ }
+
+ case 'null':
+ return [
+ 'value' => null,
+ 'readable-value' => 'null',
+ ];
+
+ case 'string':
+ $value = (string) $value;
+ return [
+ 'value' => $value,
+ 'readable-value' => ($value === '') ? 'empty string' : 'string ' . $value,
+ ];
+
+ default:
+ throw new \InvalidArgumentException('Invalid type');
+ }
+ }
+
+ /**
+ * @param array $configNames
+ * @param mixed $existingValues
+ * @param mixed $value
+ * @param bool $updateOnly
+ * @return array merged value
+ * @throws \UnexpectedValueException
+ */
+ protected function mergeArrayValue(array $configNames, $existingValues, $value, $updateOnly) {
+ $configName = array_shift($configNames);
+ if (!is_array($existingValues)) {
+ $existingValues = [];
+ }
+ if (!empty($configNames)) {
+ if (isset($existingValues[$configName])) {
+ $existingValue = $existingValues[$configName];
+ } else {
+ $existingValue = [];
+ }
+ $existingValues[$configName] = $this->mergeArrayValue($configNames, $existingValue, $value, $updateOnly);
+ } else {
+ if (!isset($existingValues[$configName]) && $updateOnly) {
+ throw new \UnexpectedValueException('Config parameter does not exist');
+ }
+ $existingValues[$configName] = $value;
+ }
+ return $existingValues;
+ }
+
}
diff --git a/core/command/db/converttype.php b/core/command/db/converttype.php
index dd91d86b8d7..864499dcce0 100644
--- a/core/command/db/converttype.php
+++ b/core/command/db/converttype.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author unclejamal3000 <andreas.pramhaas@posteo.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -166,7 +166,7 @@ class ConvertType extends Command {
$this->validateInput($input, $output);
$this->readPassword($input, $output);
- $fromDB = \OC_DB::getConnection();
+ $fromDB = \OC::$server->getDatabaseConnection();
$toDB = $this->getToDBConnection($input, $output);
if ($input->getOption('clear-schema')) {
diff --git a/core/command/db/generatechangescript.php b/core/command/db/generatechangescript.php
index 956921206f9..85436b02d65 100644
--- a/core/command/db/generatechangescript.php
+++ b/core/command/db/generatechangescript.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -45,7 +45,7 @@ class GenerateChangeScript extends Command {
$file = $input->getArgument('schema-xml');
- $schemaManager = new \OC\DB\MDB2SchemaManager(\OC_DB::getConnection());
+ $schemaManager = new \OC\DB\MDB2SchemaManager(\OC::$server->getDatabaseConnection());
try {
$result = $schemaManager->updateDbFromStructure($file, true);
diff --git a/core/command/encryption/changekeystorageroot.php b/core/command/encryption/changekeystorageroot.php
index 662e0a3161a..801a08b42a8 100644
--- a/core/command/encryption/changekeystorageroot.php
+++ b/core/command/encryption/changekeystorageroot.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/encryption/decryptall.php b/core/command/encryption/decryptall.php
index 4755a9dc7ba..0a126db5b17 100644
--- a/core/command/encryption/decryptall.php
+++ b/core/command/encryption/decryptall.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/encryption/disable.php b/core/command/encryption/disable.php
index e3c0b8d7489..0e08a314473 100644
--- a/core/command/encryption/disable.php
+++ b/core/command/encryption/disable.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/encryption/enable.php b/core/command/encryption/enable.php
index b615a7f4f85..273320e6155 100644
--- a/core/command/encryption/enable.php
+++ b/core/command/encryption/enable.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/encryption/encryptall.php b/core/command/encryption/encryptall.php
index 572991039ef..02f74a9dea4 100644
--- a/core/command/encryption/encryptall.php
+++ b/core/command/encryption/encryptall.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/encryption/listmodules.php b/core/command/encryption/listmodules.php
index cc436ea5629..9c061b6e764 100644
--- a/core/command/encryption/listmodules.php
+++ b/core/command/encryption/listmodules.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/encryption/setdefaultmodule.php b/core/command/encryption/setdefaultmodule.php
index a605b470d43..e9978536201 100644
--- a/core/command/encryption/setdefaultmodule.php
+++ b/core/command/encryption/setdefaultmodule.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/encryption/showkeystorageroot.php b/core/command/encryption/showkeystorageroot.php
index acb2e75a6ae..402352c4bcf 100644
--- a/core/command/encryption/showkeystorageroot.php
+++ b/core/command/encryption/showkeystorageroot.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/encryption/status.php b/core/command/encryption/status.php
index 1a52500cf29..b97ea8833fa 100644
--- a/core/command/encryption/status.php
+++ b/core/command/encryption/status.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/integrity/signapp.php b/core/command/integrity/signapp.php
new file mode 100644
index 00000000000..53df9619c6d
--- /dev/null
+++ b/core/command/integrity/signapp.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Integrity;
+
+use OC\IntegrityCheck\Checker;
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
+use OCP\IURLGenerator;
+use phpseclib\Crypt\RSA;
+use phpseclib\File\X509;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Class SignApp
+ *
+ * @package OC\Core\Command\Integrity
+ */
+class SignApp extends Command {
+ /** @var Checker */
+ private $checker;
+ /** @var FileAccessHelper */
+ private $fileAccessHelper;
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /**
+ * @param Checker $checker
+ * @param FileAccessHelper $fileAccessHelper
+ * @param IURLGenerator $urlGenerator
+ */
+ public function __construct(Checker $checker,
+ FileAccessHelper $fileAccessHelper,
+ IURLGenerator $urlGenerator) {
+ parent::__construct(null);
+ $this->checker = $checker;
+ $this->fileAccessHelper = $fileAccessHelper;
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('integrity:sign-app')
+ ->setDescription('Signs an app using a private key.')
+ ->addOption('path', null, InputOption::VALUE_REQUIRED, 'Application to sign')
+ ->addOption('privateKey', null, InputOption::VALUE_REQUIRED, 'Path to private key to use for signing')
+ ->addOption('certificate', null, InputOption::VALUE_REQUIRED, 'Path to certificate to use for signing');
+ }
+
+ /**
+ * {@inheritdoc }
+ */
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $path = $input->getOption('path');
+ $privateKeyPath = $input->getOption('privateKey');
+ $keyBundlePath = $input->getOption('certificate');
+ if(is_null($path) || is_null($privateKeyPath) || is_null($keyBundlePath)) {
+ $documentationUrl = $this->urlGenerator->linkToDocs('developer-code-integrity');
+ $output->writeln('This command requires the --path, --privateKey and --certificate.');
+ $output->writeln('Example: ./occ integrity:sign-app --path="/Users/lukasreschke/Programming/myapp/" --privateKey="/Users/lukasreschke/private/myapp.key" --certificate="/Users/lukasreschke/public/mycert.crt"');
+ $output->writeln('For more information please consult the documentation: '. $documentationUrl);
+ return null;
+ }
+
+ $privateKey = $this->fileAccessHelper->file_get_contents($privateKeyPath);
+ $keyBundle = $this->fileAccessHelper->file_get_contents($keyBundlePath);
+
+ if($privateKey === false) {
+ $output->writeln(sprintf('Private key "%s" does not exists.', $privateKeyPath));
+ return null;
+ }
+
+ if($keyBundle === false) {
+ $output->writeln(sprintf('Certificate "%s" does not exists.', $keyBundlePath));
+ return null;
+ }
+
+ $rsa = new RSA();
+ $rsa->loadKey($privateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $x509->setPrivateKey($rsa);
+ $this->checker->writeAppSignature($path, $x509, $rsa);
+
+ $output->writeln('Successfully signed "'.$path.'"');
+ }
+}
diff --git a/core/command/integrity/signcore.php b/core/command/integrity/signcore.php
new file mode 100644
index 00000000000..e5c2de73e00
--- /dev/null
+++ b/core/command/integrity/signcore.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Integrity;
+
+use OC\IntegrityCheck\Checker;
+use OC\IntegrityCheck\Helpers\EnvironmentHelper;
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
+use phpseclib\Crypt\RSA;
+use phpseclib\File\X509;
+use Symfony\Component\Console\Command\Command;
+use OCP\IConfig;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Class SignCore
+ *
+ * @package OC\Core\Command\Integrity
+ */
+class SignCore extends Command {
+ /** @var Checker */
+ private $checker;
+ /** @var FileAccessHelper */
+ private $fileAccessHelper;
+
+ /**
+ * @param Checker $checker
+ * @param FileAccessHelper $fileAccessHelper
+ */
+ public function __construct(Checker $checker,
+ FileAccessHelper $fileAccessHelper) {
+ parent::__construct(null);
+ $this->checker = $checker;
+ $this->fileAccessHelper = $fileAccessHelper;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('integrity:sign-core')
+ ->setDescription('Sign core using a private key.')
+ ->addOption('privateKey', null, InputOption::VALUE_REQUIRED, 'Path to private key to use for signing')
+ ->addOption('certificate', null, InputOption::VALUE_REQUIRED, 'Path to certificate to use for signing')
+ ->addOption('path', null, InputOption::VALUE_REQUIRED, 'Path of core to sign');
+ }
+
+ /**
+ * {@inheritdoc }
+ */
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $privateKeyPath = $input->getOption('privateKey');
+ $keyBundlePath = $input->getOption('certificate');
+ $path = $input->getOption('path');
+ if(is_null($privateKeyPath) || is_null($keyBundlePath) || is_null($path)) {
+ $output->writeln('--privateKey, --certificate and --path are required.');
+ return null;
+ }
+
+ $privateKey = $this->fileAccessHelper->file_get_contents($privateKeyPath);
+ $keyBundle = $this->fileAccessHelper->file_get_contents($keyBundlePath);
+
+ if($privateKey === false) {
+ $output->writeln(sprintf('Private key "%s" does not exists.', $privateKeyPath));
+ return null;
+ }
+
+ if($keyBundle === false) {
+ $output->writeln(sprintf('Certificate "%s" does not exists.', $keyBundlePath));
+ return null;
+ }
+
+ $rsa = new RSA();
+ $rsa->loadKey($privateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $x509->setPrivateKey($rsa);
+ $this->checker->writeCoreSignature($x509, $rsa, $path);
+
+ $output->writeln('Successfully signed "core"');
+ }
+}
diff --git a/core/command/l10n/createjs.php b/core/command/l10n/createjs.php
index 78f3229b179..c2cfc5d0934 100644
--- a/core/command/l10n/createjs.php
+++ b/core/command/l10n/createjs.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/log/manage.php b/core/command/log/manage.php
index 1a5cd142413..1d65d7ed0d8 100644
--- a/core/command/log/manage.php
+++ b/core/command/log/manage.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/log/owncloud.php b/core/command/log/owncloud.php
index 6200a8b6a53..7213f6726a2 100644
--- a/core/command/log/owncloud.php
+++ b/core/command/log/owncloud.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/maintenance/install.php b/core/command/maintenance/install.php
index b0235c518ec..b1b63b9b3bd 100644
--- a/core/command/maintenance/install.php
+++ b/core/command/maintenance/install.php
@@ -2,9 +2,10 @@
/**
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Christian Kampka <christian@kampka.net>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -68,7 +69,12 @@ class Install extends Command {
$errors = $sysInfo['errors'];
if (count($errors) > 0) {
$this->printErrors($output, $errors);
- return 1;
+
+ // ignore the OS X setup warning
+ if(count($errors) !== 1 ||
+ (string)($errors[0]['error']) !== 'Mac OS X is not supported and ownCloud will not work properly on this platform. Use it at your own risk! ') {
+ return 1;
+ }
}
// validate user input
diff --git a/core/command/maintenance/mimetype/updatedb.php b/core/command/maintenance/mimetype/updatedb.php
index 42d6af49baf..9532f9e1cd9 100644
--- a/core/command/maintenance/mimetype/updatedb.php
+++ b/core/command/maintenance/mimetype/updatedb.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/maintenance/mimetype/updatejs.php b/core/command/maintenance/mimetype/updatejs.php
index b2c57556cb4..8ee06e8cdc9 100644
--- a/core/command/maintenance/mimetype/updatejs.php
+++ b/core/command/maintenance/mimetype/updatejs.php
@@ -1,9 +1,9 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -71,6 +71,7 @@ class UpdateJS extends Command {
//Remove duplicates
$files = array_values(array_unique($files));
+ sort($files);
// Fetch all themes!
$themes = [];
@@ -100,6 +101,7 @@ class UpdateJS extends Command {
//Remove Duplicates
$themes[$theme] = array_values(array_unique($themes[$theme]));
+ sort($themes[$theme]);
}
//Generate the JS
diff --git a/core/command/maintenance/mode.php b/core/command/maintenance/mode.php
index e9d36510def..28f4fb2f7f1 100644
--- a/core/command/maintenance/mode.php
+++ b/core/command/maintenance/mode.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author scolebrook <scolebrook@mac.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/maintenance/repair.php b/core/command/maintenance/repair.php
index f7c0cc46048..95e2b872227 100644
--- a/core/command/maintenance/repair.php
+++ b/core/command/maintenance/repair.php
@@ -1,11 +1,11 @@
<?php
/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/maintenance/singleuser.php b/core/command/maintenance/singleuser.php
index 44e124e9d3b..2e6f1f136e7 100644
--- a/core/command/maintenance/singleuser.php
+++ b/core/command/maintenance/singleuser.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/security/importcertificate.php b/core/command/security/importcertificate.php
new file mode 100644
index 00000000000..a280eee6505
--- /dev/null
+++ b/core/command/security/importcertificate.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Security;
+
+use OC\Core\Command\Base;
+use OCP\ICertificateManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class ImportCertificate extends Base {
+
+ /** @var ICertificateManager */
+ protected $certificateManager;
+
+ public function __construct(ICertificateManager $certificateManager) {
+ $this->certificateManager = $certificateManager;
+ parent::__construct();
+ }
+
+ protected function configure() {
+ $this
+ ->setName('security:certificates:import')
+ ->setDescription('import trusted certificate')
+ ->addArgument(
+ 'path',
+ InputArgument::REQUIRED,
+ 'path to the certificate to import'
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $path = $input->getArgument('path');
+
+ if (!file_exists($path)) {
+ $output->writeln('<error>certificate not found</error>');
+ return;
+ }
+
+ $certData = file_get_contents($path);
+ $name = basename($path);
+
+ $this->certificateManager->addCertificate($certData, $name);
+ }
+}
diff --git a/core/command/security/listcertificates.php b/core/command/security/listcertificates.php
new file mode 100644
index 00000000000..eb25de172bd
--- /dev/null
+++ b/core/command/security/listcertificates.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Security;
+
+use OC\Core\Command\Base;
+use OCP\ICertificate;
+use OCP\ICertificateManager;
+use OCP\IL10N;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class ListCertificates extends Base {
+
+ /** @var ICertificateManager */
+ protected $certificateManager;
+ /** @var IL10N */
+ protected $l;
+
+ public function __construct(ICertificateManager $certificateManager, IL10N $l) {
+ $this->certificateManager = $certificateManager;
+ $this->l = $l;
+ parent::__construct();
+ }
+
+ protected function configure() {
+ $this
+ ->setName('security:certificates')
+ ->setDescription('list trusted certificates');
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $outputType = $input->getOption('output');
+ if ($outputType === self::OUTPUT_FORMAT_JSON || $outputType === self::OUTPUT_FORMAT_JSON_PRETTY) {
+ $certificates = array_map(function (ICertificate $certificate) {
+ return [
+ 'name' => $certificate->getName(),
+ 'common_name' => $certificate->getCommonName(),
+ 'organization' => $certificate->getOrganization(),
+ 'expire' => $certificate->getExpireDate()->format(\DateTime::ATOM),
+ 'issuer' => $certificate->getIssuerName(),
+ 'issuer_organization' => $certificate->getIssuerOrganization(),
+ 'issue_date' => $certificate->getIssueDate()->format(\DateTime::ATOM)
+ ];
+ }, $this->certificateManager->listCertificates());
+ if ($outputType === self::OUTPUT_FORMAT_JSON) {
+ $output->writeln(json_encode(array_values($certificates)));
+ } else {
+ $output->writeln(json_encode(array_values($certificates), JSON_PRETTY_PRINT));
+ }
+ } else {
+ $table = new Table($output);
+ $table->setHeaders([
+ 'File Name',
+ 'Common Name',
+ 'Organization',
+ 'Valid Until',
+ 'Issued By'
+ ]);
+
+ $rows = array_map(function (ICertificate $certificate) {
+ return [
+ $certificate->getName(),
+ $certificate->getCommonName(),
+ $certificate->getOrganization(),
+ $this->l->l('date', $certificate->getExpireDate()),
+ $certificate->getIssuerName()
+ ];
+ }, $this->certificateManager->listCertificates());
+ $table->setRows($rows);
+ $table->render();
+ }
+ }
+}
diff --git a/core/command/security/removecertificate.php b/core/command/security/removecertificate.php
new file mode 100644
index 00000000000..64078adab9c
--- /dev/null
+++ b/core/command/security/removecertificate.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Security;
+
+use OC\Core\Command\Base;
+use OCP\ICertificateManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class RemoveCertificate extends Base {
+
+ /** @var ICertificateManager */
+ protected $certificateManager;
+
+ public function __construct(ICertificateManager $certificateManager) {
+ $this->certificateManager = $certificateManager;
+ parent::__construct();
+ }
+
+ protected function configure() {
+ $this
+ ->setName('security:certificates:remove')
+ ->setDescription('import trusted certificate')
+ ->addArgument(
+ 'name',
+ InputArgument::REQUIRED,
+ 'the file name of the certificate to remove'
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $name = $input->getArgument('name');
+
+ $this->certificateManager->removeCertificate($name);
+ }
+}
diff --git a/core/command/status.php b/core/command/status.php
index 2eb58525d3e..6bc9c28d4d1 100644
--- a/core/command/status.php
+++ b/core/command/status.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -39,7 +39,7 @@ class Status extends Base {
protected function execute(InputInterface $input, OutputInterface $output) {
$values = array(
'installed' => (bool) \OC::$server->getConfig()->getSystemValue('installed', false),
- 'version' => implode('.', \OC_Util::getVersion()),
+ 'version' => implode('.', \OCP\Util::getVersion()),
'versionstring' => \OC_Util::getVersionString(),
'edition' => \OC_Util::getEditionString(),
);
diff --git a/core/command/upgrade.php b/core/command/upgrade.php
index d1a7c09c30c..c45984d7a30 100644
--- a/core/command/upgrade.php
+++ b/core/command/upgrade.php
@@ -1,14 +1,16 @@
<?php
/**
* @author Andreas Fischer <bantu@owncloud.com>
+ * @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Owen Winkler <a_github@midnightcircus.com>
* @author Steffen Lindner <mail@steffen-lindner.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -53,6 +55,7 @@ class Upgrade extends Command {
/**
* @param IConfig $config
+ * @param ILogger $logger
*/
public function __construct(IConfig $config, ILogger $logger) {
parent::__construct();
@@ -122,9 +125,12 @@ class Upgrade extends Command {
}
$self = $this;
- $updater = new Updater(\OC::$server->getHTTPHelper(),
- $this->config,
- $this->logger);
+ $updater = new Updater(
+ \OC::$server->getHTTPHelper(),
+ $this->config,
+ \OC::$server->getIntegrityCodeChecker(),
+ $this->logger
+ );
$updater->setSimulateStepEnabled($simulateStepEnabled);
$updater->setUpdateStepEnabled($updateStepEnabled);
@@ -195,10 +201,16 @@ class Upgrade extends Command {
$output->writeln("<error>$message</error>");
});
$updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use($output) {
- $output->writeln("<info>Set log level to debug - current level: '$logLevelName'</info>");
+ $output->writeln("<info>Set log level to debug</info>");
});
$updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($output) {
- $output->writeln("<info>Reset log level to '$logLevelName'</info>");
+ $output->writeln("<info>Reset log level</info>");
+ });
+ $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($output) {
+ $output->writeln("<info>Starting code integrity check...</info>");
+ });
+ $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($output) {
+ $output->writeln("<info>Finished code integrity check</info>");
});
if(OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
diff --git a/core/command/user/add.php b/core/command/user/add.php
index 426b8489ccf..cb0ab319bc0 100644
--- a/core/command/user/add.php
+++ b/core/command/user/add.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Laurens Post <lkpost@scept.re>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/user/delete.php b/core/command/user/delete.php
index e80c63bc732..b9a0a0e3950 100644
--- a/core/command/user/delete.php
+++ b/core/command/user/delete.php
@@ -5,7 +5,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/user/lastseen.php b/core/command/user/lastseen.php
index 931165ef9f6..1d2c17e3d3f 100644
--- a/core/command/user/lastseen.php
+++ b/core/command/user/lastseen.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/user/report.php b/core/command/user/report.php
index 7a830f64c07..df9f7e41620 100644
--- a/core/command/user/report.php
+++ b/core/command/user/report.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/command/user/resetpassword.php b/core/command/user/resetpassword.php
index 6c5846bcef3..f3f2d5b0630 100644
--- a/core/command/user/resetpassword.php
+++ b/core/command/user/resetpassword.php
@@ -7,7 +7,7 @@
* @author Laurens Post <lkpost@scept.re>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/avatar/avatarcontroller.php b/core/controller/avatarcontroller.php
index 6c0321e6b5e..adfe38ab2db 100644
--- a/core/avatar/avatarcontroller.php
+++ b/core/controller/avatarcontroller.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,12 +24,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-namespace OC\Core\Avatar;
+namespace OC\Core\Controller;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\DataDisplayResponse;
+use OCP\Files\NotFoundException;
use OCP\IAvatarManager;
use OCP\ILogger;
use OCP\IL10N;
@@ -41,7 +42,7 @@ use OCP\Files\Folder;
/**
* Class AvatarController
*
- * @package OC\Core\Avatar
+ * @package OC\Core\Controller
*/
class AvatarController extends Controller {
@@ -112,20 +113,23 @@ class AvatarController extends Controller {
$size = 64;
}
- $avatar = $this->avatarManager->getAvatar($userId);
- $image = $avatar->get($size);
-
- if ($image instanceof \OCP\IImage) {
- $resp = new DataDisplayResponse($image->data(),
+ try {
+ $avatar = $this->avatarManager->getAvatar($userId)->getFile($size);
+ $resp = new DataDisplayResponse($avatar->getContent(),
Http::STATUS_OK,
- ['Content-Type' => $image->mimeType()]);
- $resp->setETag(crc32($image->data()));
- } else {
+ ['Content-Type' => $avatar->getMimeType()]);
+ $resp->setETag($avatar->getEtag());
+ } catch (NotFoundException $e) {
$user = $this->userManager->get($userId);
- $userName = $user ? $user->getDisplayName() : '';
$resp = new DataResponse([
'data' => [
- 'displayname' => $userName,
+ 'displayname' => $user->getDisplayName(),
+ ],
+ ]);
+ } catch (\Exception $e) {
+ $resp = new DataResponse([
+ 'data' => [
+ 'displayname' => '',
],
]);
}
@@ -156,6 +160,9 @@ class AvatarController extends Controller {
if (isset($path)) {
$path = stripslashes($path);
$node = $this->userFolder->get($path);
+ if (!($node instanceof \OCP\Files\File)) {
+ return new DataResponse(['data' => ['message' => $this->l->t('Please select a file.')]], Http::STATUS_OK, $headers);
+ }
if ($node->getSize() > 20*1024*1024) {
return new DataResponse(
['data' => ['message' => $this->l->t('File is too big')]],
diff --git a/core/lostpassword/controller/lostcontroller.php b/core/controller/lostcontroller.php
index 7d983bd7e30..0e0932b288b 100644
--- a/core/lostpassword/controller/lostcontroller.php
+++ b/core/controller/lostcontroller.php
@@ -4,10 +4,11 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,7 +25,7 @@
*
*/
-namespace OC\Core\LostPassword\Controller;
+namespace OC\Core\Controller;
use \OCP\AppFramework\Controller;
use \OCP\AppFramework\Http\TemplateResponse;
@@ -44,7 +45,7 @@ use OCP\Security\StringUtils;
*
* Successfully changing a password will emit the post_passwordReset hook.
*
- * @package OC\Core\LostPassword\Controller
+ * @package OC\Core\Controller
*/
class LostController extends Controller {
@@ -121,8 +122,8 @@ class LostController extends Controller {
*/
public function resetform($token, $userId) {
return new TemplateResponse(
- 'core/lostpassword',
- 'resetpassword',
+ 'core',
+ 'lostpassword/resetpassword',
array(
'link' => $this->urlGenerator->linkToRouteAbsolute('core.lost.setPassword', array('userId' => $userId, 'token' => $token)),
),
@@ -218,17 +219,16 @@ class LostController extends Controller {
throw new \Exception($this->l10n->t('Couldn\'t send reset email. Please make sure your username is correct.'));
}
- $email = $this->config->getUserValue($user, 'settings', 'email');
+ $userObject = $this->userManager->get($user);
+ $email = $userObject->getEMailAddress();
if (empty($email)) {
throw new \Exception(
- $this->l10n->t('Couldn\'t send reset email because there is no '.
- 'email address for this username. Please ' .
- 'contact your administrator.')
+ $this->l10n->t('Could not send reset email because there is no email address for this username. Please contact your administrator.')
);
}
- $token = $this->secureRandom->getMediumStrengthGenerator()->generate(21,
+ $token = $this->secureRandom->generate(21,
ISecureRandom::CHAR_DIGITS.
ISecureRandom::CHAR_LOWER.
ISecureRandom::CHAR_UPPER);
@@ -236,7 +236,7 @@ class LostController extends Controller {
$link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', array('userId' => $user, 'token' => $token));
- $tmpl = new \OC_Template('core/lostpassword', 'email');
+ $tmpl = new \OC_Template('core', 'lostpassword/email');
$tmpl->assign('link', $link);
$msg = $tmpl->fetchPage();
diff --git a/core/setup/controller.php b/core/controller/setupcontroller.php
index 36ba33f2a42..f25c6f39a0b 100644
--- a/core/setup/controller.php
+++ b/core/controller/setupcontroller.php
@@ -5,10 +5,10 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,11 +25,11 @@
*
*/
-namespace OC\Core\Setup;
+namespace OC\Core\Controller;
use OC\Setup;
-class Controller {
+class SetupController {
/** @var Setup */
protected $setupHelper;
/** @var string */
@@ -99,6 +99,7 @@ class Controller {
if( file_exists( $this->autoConfigFile )) {
unlink($this->autoConfigFile);
}
+ \OC::$server->getIntegrityCodeChecker()->runInstanceVerification();
\OC_Util::redirectToDefaultPage();
}
diff --git a/core/user/usercontroller.php b/core/controller/usercontroller.php
index 5664ca55603..72193761022 100644
--- a/core/user/usercontroller.php
+++ b/core/controller/usercontroller.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,7 +20,7 @@
*
*/
-namespace OC\Core\User;
+namespace OC\Core\Controller;
use \OCP\AppFramework\Controller;
use \OCP\AppFramework\Http\JSONResponse;
diff --git a/core/css/apps.css b/core/css/apps.css
index e9abbe0aee1..9afd7044345 100644
--- a/core/css/apps.css
+++ b/core/css/apps.css
@@ -6,7 +6,7 @@
width: 100%;
}
#app * {
- -moz-box-sizing: border-box; box-sizing: border-box;
+ box-sizing: border-box;
}
@@ -21,7 +21,7 @@
width: 250px;
height: 100%;
float: left;
- -moz-box-sizing: border-box; box-sizing: border-box;
+ box-sizing: border-box;
background-color: #fff;
padding-bottom: 44px;
-webkit-user-select: none;
@@ -35,12 +35,12 @@
height: 100%;
width: inherit;
overflow: auto;
- -moz-box-sizing: border-box; box-sizing: border-box;
+ box-sizing: border-box;
}
#app-navigation li {
position: relative;
width: 100%;
- -moz-box-sizing: border-box; box-sizing: border-box;
+ box-sizing: border-box;
}
#app-navigation .active.with-menu > a,
@@ -67,7 +67,7 @@
min-height: 44px;
padding: 0 12px;
overflow: hidden;
- -moz-box-sizing: border-box; box-sizing: border-box;
+ box-sizing: border-box;
white-space: nowrap;
text-overflow: ellipsis;
color: #000;
@@ -109,17 +109,13 @@
}
#app-navigation .collapsible .collapse {
- -moz-transform: rotate(-90deg);
-webkit-transform: rotate(-90deg);
-ms-transform:rotate(-90deg);
- -o-transform:rotate(-90deg);
transform: rotate(-90deg);
}
#app-navigation .collapsible.open .collapse {
- -moz-transform: rotate(0);
-webkit-transform: rotate(0);
-ms-transform:rotate(0);
- -o-transform:rotate(0);
transform: rotate(0);
}
@@ -138,8 +134,6 @@
#app-navigation .collapsible.open {
background-image: linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
- background-image: -o-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
- background-image: -moz-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
background-image: -webkit-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
background-image: -ms-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
}
@@ -209,10 +203,7 @@
/* drag and drop */
#app-navigation .drag-and-drop {
- -moz-transition: padding-bottom 500ms ease 0s;
- -o-transition: padding-bottom 500ms ease 0s;
-webkit-transition: padding-bottom 500ms ease 0s;
- -ms-transition: padding-bottom 500ms ease 0s;
transition: padding-bottom 500ms ease 0s;
padding-bottom: 40px;
}
@@ -459,8 +450,6 @@
background: #fff;
border-left: 1px solid #eee;
-webkit-transition: margin-right 300ms;
- -moz-transition: margin-right 300ms;
- -o-transition: margin-right 300ms;
transition: margin-right 300ms;
overflow-x: hidden;
overflow-y: auto;
diff --git a/core/css/header.css b/core/css/header.css
index 37f06ef0632..4a5db088f96 100644
--- a/core/css/header.css
+++ b/core/css/header.css
@@ -39,7 +39,6 @@
height: 45px;
line-height: 2.5em;
background-color: #1d2d44;
- -moz-box-sizing: border-box;
box-sizing: border-box;
}
@@ -54,7 +53,6 @@
padding: 5px;
padding-bottom: 0;
height: 45px; /* header height */
- -moz-box-sizing: border-box;
box-sizing: border-box;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
opacity: 1;
@@ -185,7 +183,6 @@
}
#navigation, #navigation * {
- -moz-box-sizing:border-box;
box-sizing:border-box;
}
#navigation li {
@@ -272,7 +269,6 @@
height: 100%;
max-width: 80%;
white-space: nowrap;
- -moz-box-sizing: border-box;
box-sizing: border-box;
}
@@ -330,7 +326,7 @@
border-radius: 3px;
border-top-left-radius: 0;
border-top-right-radius: 0;
- -moz-box-sizing: border-box; box-sizing: border-box;
+ box-sizing: border-box;
}
#expanddiv a {
display: block;
@@ -339,7 +335,6 @@
padding: 4px 12px 0;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";
opacity: .7;
- -moz-box-sizing: border-box;
box-sizing: border-box;
}
#expanddiv a img {
diff --git a/core/css/icons.css b/core/css/icons.css
index 14b2101b331..836a84fd70e 100644
--- a/core/css/icons.css
+++ b/core/css/icons.css
@@ -24,7 +24,6 @@
background-image: url('../img/loading-small.gif');
}
.icon-32 {
- -webkit-background-size: 32px !important;
background-size: 32px !important;
}
@@ -47,10 +46,12 @@
.icon-checkmark {
background-image: url('../img/actions/checkmark.svg');
}
-
.icon-checkmark-white {
background-image: url('../img/actions/checkmark-white.svg');
}
+.icon-checkmark-color {
+ background-image: url('../img/actions/checkmark-color.svg');
+}
.icon-close {
background-image: url('../img/actions/close.svg');
@@ -82,6 +83,16 @@
background-image: url('../img/actions/edit.svg');
}
+.icon-error {
+ background-image: url('../img/actions/error.svg');
+}
+.icon-error-white {
+ background-image: url('../img/actions/error-white.svg');
+}
+.icon-error-color {
+ background-image: url('../img/actions/error-color.svg');
+}
+
.icon-external {
background-image: url('../img/actions/external.svg');
}
diff --git a/core/css/inputs.css b/core/css/inputs.css
index 9f440a6c359..fe03af85f61 100644
--- a/core/css/inputs.css
+++ b/core/css/inputs.css
@@ -55,7 +55,7 @@ input[type="email"],
input[type="url"],
input[type="time"] {
-webkit-appearance:textfield; -moz-appearance:textfield;
- -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box;
+ box-sizing:content-box;
}
input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,
input[type="password"]:hover, input[type="password"]:focus, input[type="password"]:active,
@@ -108,10 +108,26 @@ html:not(.ie8) input[type="checkbox"].checkbox:checked + label:before {
background-image: url('../img/actions/checkbox-checked.svg');
}
+html:not(.ie8) input[type="checkbox"].checkbox:disabled + label:before {
+ background-image: url('../img/actions/checkbox-disabled.svg');
+}
+
+html:not(.ie8) input[type="checkbox"].checkbox:checked:disabled + label:before {
+ background-image: url('../img/actions/checkbox-checked-disabled.svg');
+}
+
html:not(.ie8) input[type="checkbox"].checkbox--white:checked + label:before {
background-image: url('../img/actions/checkbox-checked-white.svg');
}
+html:not(.ie8) input[type="checkbox"].checkbox--white:disabled + label:before {
+ background-image: url('../img/actions/checkbox-disabled-white.svg');
+}
+
+html:not(.ie8) input[type="checkbox"].checkbox--white:checked:disabled + label:before {
+ background-image: url('../img/actions/checkbox-checked-disabled.svg');
+}
+
html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="checkbox"]:focus+label:before {
color:#111 !important;
}
@@ -119,7 +135,7 @@ html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="c
input[type="time"] {
width: initial;
height: 31px;
- -moz-box-sizing: border-box; box-sizing: border-box;
+ box-sizing: border-box;
}
select {
diff --git a/core/css/jquery.ocdialog.css b/core/css/jquery.ocdialog.css
index bada0b73a5e..b241dcfea6f 100644
--- a/core/css/jquery.ocdialog.css
+++ b/core/css/jquery.ocdialog.css
@@ -26,7 +26,7 @@
background: white;
float: right;
position: relative;
- bottom: 0;
+ bottom: 5px;
display: block;
margin-top: 10px;
width: 100%;
diff --git a/core/lostpassword/css/resetpassword.css b/core/css/lostpassword/resetpassword.css
index 0b3c251e8d7..0b3c251e8d7 100644
--- a/core/lostpassword/css/resetpassword.css
+++ b/core/css/lostpassword/resetpassword.css
diff --git a/core/css/mobile.css b/core/css/mobile.css
index 288ae2979de..131907eb09d 100644
--- a/core/css/mobile.css
+++ b/core/css/mobile.css
@@ -46,7 +46,6 @@
.error-wide {
width: 100%;
margin-left: 0 !important;
- -moz-box-sizing: border-box;
box-sizing: border-box;
}
diff --git a/core/css/share.css b/core/css/share.css
index 15f8061b068..55ee5996a75 100644
--- a/core/css/share.css
+++ b/core/css/share.css
@@ -125,8 +125,6 @@ a.unshare {
.shareTabView .error {
color: #e9322d;
border-color: #e9322d;
- -webkit-box-shadow: 0 0 6px #f8b9b7;
- -moz-box-shadow: 0 0 6px #f8b9b7;
box-shadow: 0 0 6px #f8b9b7;
}
diff --git a/core/css/styles.css b/core/css/styles.css
index 75bbb78fe52..e78db6fde01 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -29,8 +29,6 @@ body {
background: -moz-linear-gradient(top, #35537a 0%, #1d2d44 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#35537a), color-stop(100%,#1d2d44)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #35537a 0%,#1d2d44 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #35537a 0%,#1d2d44 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #35537a 0%,#1d2d44 100%); /* IE10+ */
background: linear-gradient(top, #35537a 0%,#1d2d44 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#35537a', endColorstr='#1d2d44',GradientType=0 ); /* IE6-9 */
}
@@ -99,8 +97,6 @@ body {
width: 0;
cursor: pointer;
-webkit-transition: all 100ms;
- -moz-transition: all 100ms;
- -o-transition: all 100ms;
transition: all 100ms;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";
opacity: .7;
@@ -117,8 +113,6 @@ body {
/* CONTENT ------------------------------------------------------------------ */
#controls {
- -moz-box-sizing: border-box;
- -webkit-box-sizing: border-box;
box-sizing: border-box;
position: fixed;
top: 45px;
@@ -149,8 +143,6 @@ body {
#controls input[type='text'],
#controls input[type='password'],
#controls select {
- -moz-box-sizing: border-box;
- -webkit-box-sizing: border-box;
box-sizing: border-box;
display: inline-block;
height: 36px;
@@ -175,7 +167,6 @@ body {
width: 100%;
overflow-x: hidden; /* prevent horizontal scrollbar */
padding-top: 45px;
- -moz-box-sizing:border-box;
box-sizing:border-box;
}
/* allow horizontal scrollbar for personal and admin settings */
@@ -240,8 +231,7 @@ body {
}
#body-login .update h2 {
- line-height: 130%;
- margin-bottom: 30px;
+ margin: 12px 0 20px;
}
#body-login .update a {
@@ -265,6 +255,10 @@ body {
width: 22em;
margin: 0 auto;
padding-top: 20px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
#body-login p.info a {
font-weight: 600;
@@ -302,6 +296,10 @@ body {
#body-login form fieldset {
margin-bottom: 20px;
text-align: left;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
#body-login form #sqliteInformation {
margin-top: -20px;
@@ -359,6 +357,10 @@ body {
.groupmiddle,
.groupbottom {
position: relative;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
#body-login .grouptop input,
.grouptop input {
@@ -384,6 +386,9 @@ body {
border-top-left-radius: 0;
box-shadow: 0 1px 0 rgba(0,0,0,.1) inset !important;
}
+#body-login .groupbottom input[type=submit] {
+ box-shadow: none !important;
+}
/* keep the labels for screen readers but hide them since we use placeholders */
label.infield {
@@ -396,6 +401,10 @@ label.infield {
padding: 14px;
padding-left: 28px;
vertical-align: middle;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
html.ie8 #body-login form input[type="checkbox"]+label {
margin-left: -28px;
@@ -538,6 +547,8 @@ html.ie8 #body-login form input[type="checkbox"] {
}
.error a.button {
color: #555 !important;
+ display: inline-block;
+ text-align: center;
}
.error pre {
white-space: pre-wrap;
@@ -698,9 +709,9 @@ code { font-family:"Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono
#quota {
cursor: default;
- margin: 30px;
+ margin: 30px !important;
position: relative;
- padding: 0;
+ padding: 0 !important;
}
#quota div {
padding: 0;
@@ -806,7 +817,7 @@ span.ui-icon {float: left; margin: 3px 7px 30px 0;}
width: 100%; height: 30px;
}
#tagsdialog .bottombuttons * { float:left;}
-#tagsdialog .taglist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; }
+#tagsdialog .taglist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; transition:background-color 500ms; }
#tagsdialog .taglist li:hover, #tagsdialog .taglist li:active { background:#eee; }
#tagsdialog .addinput { width: 90%; clear: both; }
@@ -825,9 +836,9 @@ span.ui-icon {float: left; margin: 3px 7px 30px 0;}
.popup .close { position:absolute; top:0.2em; right:0.2em; height:20px; width:20px; background:url('../img/actions/close.svg') no-repeat center; }
.popup h2 { font-size:20px; }
.arrow { border-bottom:10px solid white; border-left:10px solid transparent; border-right:10px solid transparent; display:block; height:0; position:absolute; width:0; z-index:201; }
-.arrow.left { left:-13px; bottom:1.2em; -webkit-transform:rotate(270deg); -moz-transform:rotate(270deg); -o-transform:rotate(270deg); -ms-transform:rotate(270deg); transform:rotate(270deg); }
+.arrow.left { left:-13px; bottom:1.2em; -webkit-transform:rotate(270deg); -ms-transform:rotate(270deg); transform:rotate(270deg); }
.arrow.up { top:-8px; right:6px; }
-.arrow.down { -webkit-transform:rotate(180deg); -moz-transform:rotate(180deg); -o-transform:rotate(180deg); -ms-transform:rotate(180deg); transform:rotate(180deg); }
+.arrow.down { -webkit-transform:rotate(180deg); -ms-transform:rotate(180deg); transform:rotate(180deg); }
/* ---- BREADCRUMB ---- */
diff --git a/core/css/systemtags.css b/core/css/systemtags.css
new file mode 100644
index 00000000000..588c76e1e3f
--- /dev/null
+++ b/core/css/systemtags.css
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+.systemtags-select2-dropdown .select2-selected {
+ display: list-item;
+ background-color: #f8f8f8;
+}
+.systemtags-select2-dropdown .select2-highlighted,
+.systemtags-select2-dropdown .select2-selected.select2-highlighted {
+ background: #3875d7;
+}
+
+.systemtags-select2-dropdown .select2-highlighted {
+ color: #000000;
+}
+.systemtags-select2-dropdown .select2-result-label .checkmark {
+ visibility: hidden;
+}
+
+.systemtags-select2-dropdown .select2-result-label .new-item .systemtags-actions {
+ display: none;
+}
+
+.systemtags-select2-dropdown .select2-selected .select2-result-label .checkmark {
+ visibility: visible;
+}
+
+.systemtags-select2-dropdown .select2-result-label .icon {
+ display: inline-block;
+}
+
+.systemtags-select2-dropdown .systemtags-actions {
+ float: right;
+}
+
+.systemtags-select2-dropdown .systemtags-rename-form {
+ display: inline;
+ margin-left: 10px;
+}
+
+.systemtags-select2-container {
+ width: 100%;
+}
+
+.systemtags-select2-container .select2-choices {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ background: #fff;
+ color: #555;
+ box-sizing: content-box;
+ border-radius: 3px;
+ border: 1px solid #ddd;
+ margin: 3px 3px 3px 0;
+ padding: 7px 6px 5px;
+ min-height: auto;
+}
+
+.systemtags-select2-container .select2-choices .select2-search-choice {
+ line-height: 20px;
+ padding-left: 5px;
+}
+
+.systemtags-select2-container .select2-choices .select2-search-choice.select2-locked .label {
+ opacity: 0.5;
+}
+
+.systemtags-select2-container .select2-choices .select2-search-choice-close {
+ display: none;
+}
+.systemtags-select2-container .select2-choices .select2-search-field input {
+ line-height: 20px;
+}
+.systemtags-select2-dropdown .label {
+ width:85%;
+ display:-moz-inline-box;
+ display:inline-block;
+ overflow:hidden;
+ text-overflow:ellipsis;
+}
diff --git a/core/img/actions/add.svg b/core/img/actions/add.svg
index ecbab6f13ac..c97431782fb 100644
--- a/core/img/actions/add.svg
+++ b/core/img/actions/add.svg
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <g transform="matrix(-0.70711,-0.70711,0.70711,-0.70711,-724.84998,753.15998)">
- <path d="m3.7547,1041.6,1.4142-1.4142,3.5355,3.5355,3.5355-3.5355,1.4142,1.4142-3.5355,3.5355,3.5355,3.5356-1.4142,1.4142-3.5355-3.5356-3.5164,3.5547-1.4333-1.4333,3.5355-3.5356z"/>
+ <g transform="matrix(-.70711 -.70711 .70711 -.70711 -724.85 753.16)">
+ <path d="m3.7547 1041.6 1.4142-1.4142 3.5355 3.5355 3.5355-3.5355 1.4142 1.4142-3.5355 3.5355 3.5355 3.5356-1.4142 1.4142-3.5355-3.5356-3.5164 3.5547-1.4333-1.4333 3.5355-3.5356z"/>
</g>
</svg>
diff --git a/core/img/actions/checkbox-checked-disabled.png b/core/img/actions/checkbox-checked-disabled.png
new file mode 100644
index 00000000000..55980ba730d
--- /dev/null
+++ b/core/img/actions/checkbox-checked-disabled.png
Binary files differ
diff --git a/core/img/actions/checkbox-checked-disabled.svg b/core/img/actions/checkbox-checked-disabled.svg
new file mode 100644
index 00000000000..de89df039dd
--- /dev/null
+++ b/core/img/actions/checkbox-checked-disabled.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m2.5 2.5h11v11h-11z" fill="#fff"/>
+ <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm8.924 2.0664l1.433 1.4316-6.3648 6.365-4.2422-4.2439 1.4141-1.414 2.8281 2.8301 4.9318-4.9688z" fill="#969696"/>
+</svg>
diff --git a/core/img/actions/checkbox-checked.svg b/core/img/actions/checkbox-checked.svg
index c5aa3cd73bb..c648957429e 100644
--- a/core/img/actions/checkbox-checked.svg
+++ b/core/img/actions/checkbox-checked.svg
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<path d="m2.5 2.5h11v11h-11z" fill="#fff"/>
- <path fill="#55739a" d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm8.924 2.0664l1.433 1.4316-6.3648 6.365-4.2422-4.2439 1.4141-1.414 2.8281 2.8301 4.9318-4.9688z"/>
+ <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm8.924 2.0664l1.433 1.4316-6.3648 6.365-4.2422-4.2439 1.4141-1.414 2.8281 2.8301 4.9318-4.9688z" fill="#55739a"/>
</svg>
diff --git a/core/img/actions/checkbox-disabled-white.png b/core/img/actions/checkbox-disabled-white.png
new file mode 100644
index 00000000000..e1f48439d27
--- /dev/null
+++ b/core/img/actions/checkbox-disabled-white.png
Binary files differ
diff --git a/core/img/actions/checkbox-disabled-white.svg b/core/img/actions/checkbox-disabled-white.svg
new file mode 100644
index 00000000000..52c2fee3b16
--- /dev/null
+++ b/core/img/actions/checkbox-disabled-white.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m2.5 2.5h11v11h-11z" fill="#dcdcdc"/>
+ <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm0 1h10v10h-10v-10z" fill="#fff"/>
+</svg>
diff --git a/core/img/actions/checkbox-disabled.png b/core/img/actions/checkbox-disabled.png
new file mode 100644
index 00000000000..a2ead209965
--- /dev/null
+++ b/core/img/actions/checkbox-disabled.png
Binary files differ
diff --git a/core/img/actions/checkbox-disabled.svg b/core/img/actions/checkbox-disabled.svg
new file mode 100644
index 00000000000..48d31f591fd
--- /dev/null
+++ b/core/img/actions/checkbox-disabled.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m2.5 2.5h11v11h-11z" fill="#dcdcdc"/>
+ <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm0 1h10v10h-10v-10z" fill="#969696"/>
+</svg>
diff --git a/core/img/actions/checkbox-mixed.svg b/core/img/actions/checkbox-mixed.svg
index 7f3642912da..5f873d6a96e 100644
--- a/core/img/actions/checkbox-mixed.svg
+++ b/core/img/actions/checkbox-mixed.svg
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<path d="m2.5 2.5h11v11h-11z" fill="#fff"/>
- <path fill="#969696" d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm1 5h8v2h-8v-2z"/>
+ <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm1 5h8v2h-8v-2z" fill="#969696"/>
</svg>
diff --git a/core/img/actions/checkbox.svg b/core/img/actions/checkbox.svg
index fe8f727b899..bfb83e3708c 100644
--- a/core/img/actions/checkbox.svg
+++ b/core/img/actions/checkbox.svg
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<path d="m2.5 2.5h11v11h-11z" fill="#fff"/>
- <path fill="#969696" d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm0 1h10v10h-10v-10z"/>
+ <path d="m3 2c-0.554 0-1 0.446-1 1v10c0 0.554 0.446 1 1 1h10c0.554 0 1-0.446 1-1v-10c0-0.554-0.446-1-1-1h-10zm0 1h10v10h-10v-10z" fill="#969696"/>
</svg>
diff --git a/core/img/actions/checkmark-color.png b/core/img/actions/checkmark-color.png
new file mode 100644
index 00000000000..a8ab849cad7
--- /dev/null
+++ b/core/img/actions/checkmark-color.png
Binary files differ
diff --git a/core/img/actions/checkmark-color.svg b/core/img/actions/checkmark-color.svg
new file mode 100644
index 00000000000..584997f0ac3
--- /dev/null
+++ b/core/img/actions/checkmark-color.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="16px" viewBox="-0.5 -0.5 16 16" width="16px" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new -0.5 -0.5 16 16" overflow="visible" xmlns:dc="http://purl.org/dc/elements/1.1/"><g transform="matrix(-1 0 0 -1 17.451 1056.3)" fill="#00d400"><path d="m11.362 1043.8 4.9497 4.9499-1.4141 1.4141-3.5356-3.5355-6.3448 6.3831-1.4333-1.4333z" fill="#00d400"/></g></svg>
diff --git a/core/img/actions/checkmark-white.svg b/core/img/actions/checkmark-white.svg
index e6b63a4d599..964624a9ce4 100644
--- a/core/img/actions/checkmark-white.svg
+++ b/core/img/actions/checkmark-white.svg
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" overflow="visible" height="16px" width="16px" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new -0.5 -0.5 16 16" viewBox="-0.5 -0.5 16 16" xmlns:dc="http://purl.org/dc/elements/1.1/">
-<path transform="translate(-.5 -.5)" d="m12.438 3.6875c-0.363 0-0.726 0.1314-1 0.4063l-4.5005 4.5-1.9687-2c-0.5498-0.5484-1.4489-0.5498-2 0l-0.5 0.5c-0.5512 0.5496-0.5512 1.4502 0 2l2.9687 2.9682c0.0063 0.007-0.0065 0.025 0 0.032l0.5 0.5c0.5497 0.55 1.4503 0.55 2 0l0.5-0.5 0.1875-0.219 5.313-5.2812c0.549-0.5498 0.549-1.4503 0-2l-0.5-0.5c-0.275-0.2749-0.638-0.4063-1-0.4063z" fill="#fff"/>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="16px" viewBox="-0.5 -0.5 16 16" width="16px" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new -0.5 -0.5 16 16" overflow="visible" xmlns:dc="http://purl.org/dc/elements/1.1/">
+<path fill="#fff" transform="translate(-.5 -.5)" d="m12.438 3.6875c-0.363 0-0.726 0.1314-1 0.4063l-4.5005 4.5-1.9687-2c-0.5498-0.5484-1.4489-0.5498-2 0l-0.5 0.5c-0.5512 0.5496-0.5512 1.4502 0 2l2.9687 2.9682c0.0063 0.007-0.0065 0.025 0 0.032l0.5 0.5c0.5497 0.55 1.4503 0.55 2 0l0.5-0.5 0.1875-0.219 5.313-5.2812c0.549-0.5498 0.549-1.4503 0-2l-0.5-0.5c-0.275-0.2749-0.638-0.4063-1-0.4063z"/>
</svg>
diff --git a/core/img/actions/checkmark.svg b/core/img/actions/checkmark.svg
index 3fa2a3f1bab..e41472c8ef7 100644
--- a/core/img/actions/checkmark.svg
+++ b/core/img/actions/checkmark.svg
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xml:space="preserve" overflow="visible" height="16px" viewBox="-0.5 -0.5 16 16" xmlns:dc="http://purl.org/dc/elements/1.1/" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" y="0px" x="0px" enable-background="new -0.5 -0.5 16 16"><g transform="matrix(-1 0 0 -1 17.451 1056.3)"><path d="m11.362 1043.8 4.9497 4.9499-1.4141 1.4141-3.5356-3.5355-6.3448 6.3831-1.4333-1.4333z"/></g></svg>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="16px" viewBox="-0.5 -0.5 16 16" width="16px" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new -0.5 -0.5 16 16" overflow="visible" xmlns:dc="http://purl.org/dc/elements/1.1/"><g transform="matrix(-1 0 0 -1 17.451 1056.3)"><path d="m11.362 1043.8 4.9497 4.9499-1.4141 1.4141-3.5356-3.5355-6.3448 6.3831-1.4333-1.4333z"/></g></svg>
diff --git a/core/img/actions/close.svg b/core/img/actions/close.svg
index e060da3f8bb..fb49c6ac893 100644
--- a/core/img/actions/close.svg
+++ b/core/img/actions/close.svg
@@ -5,6 +5,6 @@
<feGaussianBlur stdDeviation="1.2386625"/>
</filter>
</defs>
- <path d="m12.95 11.536-1.414 1.414-3.536-3.5358-3.5355 3.5358-1.4142-1.414 3.5355-3.536-3.5355-3.5356 1.4142-1.4142 3.5355 3.5356 3.516-3.5547 1.434 1.4333-3.5357 3.5356z" filter="url(#a)" stroke="#fff" stroke-width="2" fill="#fff"/>
+ <path filter="url(#a)" stroke="#fff" stroke-width="2" d="m12.95 11.536-1.414 1.414-3.536-3.5358-3.5355 3.5358-1.4142-1.414 3.5355-3.536-3.5355-3.5356 1.4142-1.4142 3.5355 3.5356 3.516-3.5547 1.434 1.4333-3.5357 3.5356z" fill="#fff"/>
<path d="m12.95 11.536-1.414 1.414-3.536-3.5358-3.5355 3.5358-1.4142-1.414 3.5355-3.536-3.5355-3.5356 1.4142-1.4142 3.5355 3.5356 3.516-3.5547 1.434 1.4333-3.5357 3.5356z"/>
</svg>
diff --git a/core/img/actions/comment.png b/core/img/actions/comment.png
new file mode 100644
index 00000000000..7ca20eba363
--- /dev/null
+++ b/core/img/actions/comment.png
Binary files differ
diff --git a/core/img/actions/comment.svg b/core/img/actions/comment.svg
new file mode 100644
index 00000000000..a8ab95e615b
--- /dev/null
+++ b/core/img/actions/comment.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.0" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path style="color:#000000;block-progression:tb;text-transform:none;text-indent:0" d="m2.3496 1.002c-0.1975 0.0382-0.3531 0.2333-0.3496 0.4375v13.122c0 0.23 0.2061 0.438 0.4316 0.438h11.138c0.226 0 0.432-0.208 0.432-0.438v-10.142c-0.004-0.0669-0.023-0.133-0.055-0.1915l-3.312-3.1992c-0.043-0.0164-0.089-0.0255-0.135-0.0273h-8.0684c-0.0268-0.00265-0.0552-0.00265-0.082 0zm1.6504 1.998h6v1h-6v-1zm0 3h5v1h-5v-1zm0 3h8v1h-8v-1zm0 3h4v1h-4v-1z"/>
+</svg>
diff --git a/core/img/actions/delete-hover.png b/core/img/actions/delete-hover.png
index 3f8cb6eff92..ed12640df71 100644
--- a/core/img/actions/delete-hover.png
+++ b/core/img/actions/delete-hover.png
Binary files differ
diff --git a/core/img/actions/delete-hover.svg b/core/img/actions/delete-hover.svg
index 9583ec15b32..ecc6139a5e6 100644
--- a/core/img/actions/delete-hover.svg
+++ b/core/img/actions/delete-hover.svg
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <path d="m6.5 1-0.5 1h-3c-0.554 0-1 0.446-1 1v1h12v-1c0-0.554-0.446-1-1-1h-3l-0.5-1zm-3.5 4 0.875 9c0.061 0.549 0.5729 1 1.125 1h6c0.55232 0 1.064-0.45102 1.125-1l0.875-9z" fill-rule="evenodd" fill="#d40000"/>
+ <path fill="#d40000" d="m6.5 1-0.5 1h-3c-0.554 0-1 0.446-1 1v1h12v-1c0-0.554-0.446-1-1-1h-3l-0.5-1zm-3.5 4 0.875 9c0.061 0.549 0.5729 1 1.125 1h6c0.55232 0 1.064-0.45102 1.125-1l0.875-9z" fill-rule="evenodd"/>
</svg>
diff --git a/core/img/actions/delete.png b/core/img/actions/delete.png
index e891b370cca..20e894c7f74 100644
--- a/core/img/actions/delete.png
+++ b/core/img/actions/delete.png
Binary files differ
diff --git a/core/img/actions/download.svg b/core/img/actions/download.svg
index 0d698bca8dc..f8513b63f78 100644
--- a/core/img/actions/download.svg
+++ b/core/img/actions/download.svg
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<g transform="translate(0 -1036.4)">
- <path d="m6,1037.4,4,0,0,7,5,0-7,7-7-7,5,0z"/>
+ <path d="m6 1037.4h4v7h5l-7 7-7-7h5z"/>
</g>
</svg>
diff --git a/core/img/actions/error-color.png b/core/img/actions/error-color.png
new file mode 100644
index 00000000000..7d00282312a
--- /dev/null
+++ b/core/img/actions/error-color.png
Binary files differ
diff --git a/core/img/actions/error-color.svg b/core/img/actions/error-color.svg
new file mode 100644
index 00000000000..93cb9ffe0ad
--- /dev/null
+++ b/core/img/actions/error-color.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m5.5156 2l-3.5156 3.5156v4.9684l3.5156 3.516h4.9684l3.516-3.516v-4.9684l-3.516-3.5156h-4.9684zm1.4844 2h2v5h-2v-5zm0 6h2v2h-2v-2z" fill="#d40000"/>
+</svg>
diff --git a/core/img/actions/error-white.png b/core/img/actions/error-white.png
new file mode 100644
index 00000000000..6e15865401d
--- /dev/null
+++ b/core/img/actions/error-white.png
Binary files differ
diff --git a/core/img/actions/error-white.svg b/core/img/actions/error-white.svg
new file mode 100644
index 00000000000..38c57f6e9c7
--- /dev/null
+++ b/core/img/actions/error-white.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m5.5156 2l-3.5156 3.5156v4.9684l3.5156 3.516h4.9684l3.516-3.516v-4.9684l-3.516-3.5156h-4.9684zm1.4844 2h2v5h-2v-5zm0 6h2v2h-2v-2z" fill="#fff"/>
+</svg>
diff --git a/core/img/actions/error.png b/core/img/actions/error.png
new file mode 100644
index 00000000000..61df76b53ea
--- /dev/null
+++ b/core/img/actions/error.png
Binary files differ
diff --git a/core/img/actions/error.svg b/core/img/actions/error.svg
new file mode 100644
index 00000000000..38e4053c333
--- /dev/null
+++ b/core/img/actions/error.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m5.5156 2l-3.5156 3.5156v4.9684l3.5156 3.516h4.9684l3.516-3.516v-4.9684l-3.516-3.5156h-4.9684zm1.4844 2h2v5h-2v-5zm0 6h2v2h-2v-2z"/>
+</svg>
diff --git a/core/img/actions/logout.png b/core/img/actions/logout.png
index bada7a12616..ad230de98f4 100644
--- a/core/img/actions/logout.png
+++ b/core/img/actions/logout.png
Binary files differ
diff --git a/core/img/actions/logout.svg b/core/img/actions/logout.svg
index 1a0ee167184..96bd2072849 100644
--- a/core/img/actions/logout.svg
+++ b/core/img/actions/logout.svg
@@ -1,58 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- height="16"
- width="16"
- version="1.0"
- id="svg2"
- inkscape:version="0.48.4 r9939"
- sodipodi:docname="logout.svg"
- inkscape:export-filename="logout.png"
- inkscape:export-xdpi="179.59"
- inkscape:export-ydpi="179.59">
- <metadata
- id="metadata12">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <defs
- id="defs10" />
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1920"
- inkscape:window-height="1002"
- id="namedview8"
- showgrid="false"
- inkscape:zoom="22.5"
- inkscape:cx="8"
- inkscape:cy="8"
- inkscape:window-x="0"
- inkscape:window-y="34"
- inkscape:window-maximized="1"
- inkscape:current-layer="svg2" />
- <path
- style="text-indent:0;text-transform:none;block-progression:tb;color:#000000;fill:#ffffff"
- d="m 8.0001,4.5e-4 c -0.4714,0 -0.96103,0.5419 -0.95,1 v 6 c -0.00747,0.52831 0.42163,1 0.95,1 0.52837,0 0.95747,-0.47169 0.95,-1 v -6 c 0.014622,-0.6051 -0.4786,-1 -0.95,-1 z m -3.3438,2.5 C 4.569114,2.519744 4.48467,2.551409 4.4063,2.5942 1.4068,4.1657 0.4879,7.3921 1.2813,10.063 2.0747,12.733 4.5612,15 7.9688,15 11.328,15 13.846,12.851 14.688,10.219 15.529,7.5869 14.63,4.3956 11.563,2.625 11.129,2.3714 10.504,2.5351 10.25,2.9687 c -0.2536,0.4336 -0.09,1.0589 0.344,1.3125 2.3908,1.3798 2.8825,3.4944 2.2812,5.375 -0.6012,1.8806 -2.344,3.4375 -4.9062,3.4375 -2.5759,0 -4.2976,-1.6502 -4.875,-3.5938 C 2.5164,7.5563 3.047,5.4518 5.2813,4.2811 5.66,4.0748 5.8604,3.5886 5.7371,3.1754 5.6139,2.7621 5.1799,2.4651 4.7501,2.4999 4.7188,2.4984 4.6875,2.4984 4.6563,2.4999 z"
- id="path6"
- inkscape:connector-curvature="0" />
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.0" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" fill="#fff" d="m8.0001 0.00045c-0.4714 0-0.96103 0.5419-0.95 1v6c-0.00747 0.52831 0.42163 1 0.95 1s0.95747-0.47169 0.95-1v-6c0.014622-0.6051-0.4786-1-0.95-1zm-3.3438 2.5c-0.0872 0.0193-0.1716 0.051-0.25 0.0938-2.9995 1.5715-3.9184 4.7979-3.125 7.4688 0.7934 2.67 3.2799 4.937 6.6875 4.937 3.3592 0 5.8772-2.149 6.7192-4.781 0.841-2.6321-0.058-5.8234-3.125-7.594-0.434-0.2536-1.059-0.0899-1.313 0.3437-0.2536 0.4336-0.09 1.0589 0.344 1.3125 2.3908 1.3798 2.8825 3.4944 2.2812 5.375-0.6012 1.8806-2.344 3.4375-4.9062 3.4375-2.5759 0-4.2976-1.6502-4.875-3.5938-0.5776-1.9436-0.047-4.0481 2.1873-5.2188 0.3787-0.2063 0.5791-0.6925 0.4558-1.1057-0.1232-0.4133-0.5572-0.7103-0.987-0.6755-0.0313-0.0015-0.0626-0.0015-0.0938 0z"/>
</svg>
diff --git a/core/img/actions/menu.svg b/core/img/actions/menu.svg
index f0e33df3737..24a057aac77 100644
--- a/core/img/actions/menu.svg
+++ b/core/img/actions/menu.svg
@@ -1,12 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <metadata>
- <rdf:RDF>
- <cc:Work rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
- <dc:title/>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <path d="m2,2,0,2,12,0,0-2zm0,5,0,2,12,0,0-2zm0,5,0,2,12,0,0-2z"/>
+ <path d="m2 2v2h12v-2zm0 5v2h12v-2zm0 5v2h12v-2z"/>
</svg>
diff --git a/core/img/actions/public.svg b/core/img/actions/public.svg
index 99a71c6cb5b..7721c9e3408 100644
--- a/core/img/actions/public.svg
+++ b/core/img/actions/public.svg
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<g transform="matrix(.67042 -.67042 .67042 .67042 .62542 93.143)">
- <path style="block-progression:tb;text-indent:0;color:#000000;text-transform:none" d="m69.5-61.5c-1.9217 0-3.5 1.5783-3.5 3.5 0 0.17425 0.0062 0.33232 0.03125 0.5h2.0625c-0.053-0.156-0.094-0.323-0.094-0.5 0-0.8483 0.6517-1.5 1.5-1.5h5c0.8483 0 1.5 0.6517 1.5 1.5s-0.6517 1.5-1.5 1.5h-1.6875c-0.28733 0.79501-0.78612 1.4793-1.4375 2h3.125c1.9217 0 3.5-1.5783 3.5-3.5s-1.5783-3.5-3.5-3.5h-5z"/>
- <path style="block-progression:tb;text-indent:0;color:#000000;text-transform:none" d="m68.5-54.5c1.9217 0 3.5-1.5783 3.5-3.5 0-0.17425-0.0062-0.33232-0.03125-0.5h-2.0625c0.053 0.156 0.094 0.323 0.094 0.5 0 0.8483-0.6517 1.5-1.5 1.5h-5c-0.8483 0-1.5-0.6517-1.5-1.5s0.6517-1.5 1.5-1.5h1.6875c0.28733-0.79501 0.78612-1.4793 1.4375-2h-3.125c-1.9217 0-3.5 1.5783-3.5 3.5s1.5783 3.5 3.5 3.5h5z"/>
+ <path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" d="m69.5-61.5c-1.9217 0-3.5 1.5783-3.5 3.5 0 0.17425 0.0062 0.33232 0.03125 0.5h2.0625c-0.053-0.156-0.094-0.323-0.094-0.5 0-0.8483 0.6517-1.5 1.5-1.5h5c0.8483 0 1.5 0.6517 1.5 1.5s-0.6517 1.5-1.5 1.5h-1.6875c-0.28733 0.79501-0.78612 1.4793-1.4375 2h3.125c1.9217 0 3.5-1.5783 3.5-3.5s-1.5783-3.5-3.5-3.5h-5z"/>
+ <path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" d="m68.5-54.5c1.9217 0 3.5-1.5783 3.5-3.5 0-0.17425-0.0062-0.33232-0.03125-0.5h-2.0625c0.053 0.156 0.094 0.323 0.094 0.5 0 0.8483-0.6517 1.5-1.5 1.5h-5c-0.8483 0-1.5-0.6517-1.5-1.5s0.6517-1.5 1.5-1.5h1.6875c0.28733-0.79501 0.78612-1.4793 1.4375-2h-3.125c-1.9217 0-3.5 1.5783-3.5 3.5s1.5783 3.5 3.5 3.5h5z"/>
</g>
</svg>
diff --git a/core/img/actions/radio-checked-disabled.png b/core/img/actions/radio-checked-disabled.png
new file mode 100644
index 00000000000..09abc410f61
--- /dev/null
+++ b/core/img/actions/radio-checked-disabled.png
Binary files differ
diff --git a/core/img/actions/radio-checked-disabled.svg b/core/img/actions/radio-checked-disabled.svg
new file mode 100644
index 00000000000..294f8a74773
--- /dev/null
+++ b/core/img/actions/radio-checked-disabled.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m8 1.5c-3.5899 0-6.5 2.9101-6.5 6.5s2.9101 6.5 6.5 6.5 6.5-2.9101 6.5-6.5-2.91-6.5-6.5-6.5z" fill="#fff"/>
+ <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6zm0 2c-2.2091 0-4 1.7909-4 4 0 2.209 1.7909 4 4 4 2.209 0 4-1.791 4-4 0-2.2091-1.791-4-4-4z" fill="#969696"/>
+</svg>
diff --git a/core/img/actions/radio-checked.png b/core/img/actions/radio-checked.png
new file mode 100644
index 00000000000..94933b7b69c
--- /dev/null
+++ b/core/img/actions/radio-checked.png
Binary files differ
diff --git a/core/img/actions/radio-checked.svg b/core/img/actions/radio-checked.svg
new file mode 100644
index 00000000000..31011c0ea22
--- /dev/null
+++ b/core/img/actions/radio-checked.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m8 1.5c-3.5899 0-6.5 2.9101-6.5 6.5s2.9101 6.5 6.5 6.5 6.5-2.9101 6.5-6.5-2.91-6.5-6.5-6.5z" fill="#fff"/>
+ <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6zm0 2c-2.2091 0-4 1.7909-4 4 0 2.209 1.7909 4 4 4 2.209 0 4-1.791 4-4 0-2.2091-1.791-4-4-4z" fill="#55739a"/>
+</svg>
diff --git a/core/img/actions/radio-disabled.png b/core/img/actions/radio-disabled.png
new file mode 100644
index 00000000000..ac7f49ed533
--- /dev/null
+++ b/core/img/actions/radio-disabled.png
Binary files differ
diff --git a/core/img/actions/radio-disabled.svg b/core/img/actions/radio-disabled.svg
new file mode 100644
index 00000000000..6058bb73fc5
--- /dev/null
+++ b/core/img/actions/radio-disabled.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m8 1.5c-3.5899 0-6.5 2.9101-6.5 6.5s2.9101 6.5 6.5 6.5 6.5-2.9101 6.5-6.5-2.91-6.5-6.5-6.5z" fill="#dcdcdc"/>
+ <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6z" fill="#969696"/>
+</svg>
diff --git a/core/img/actions/radio-white.png b/core/img/actions/radio-white.png
new file mode 100644
index 00000000000..04beefdff01
--- /dev/null
+++ b/core/img/actions/radio-white.png
Binary files differ
diff --git a/core/img/actions/radio-white.svg b/core/img/actions/radio-white.svg
new file mode 100644
index 00000000000..57611f4cdd0
--- /dev/null
+++ b/core/img/actions/radio-white.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6z" fill="#fff"/>
+</svg>
diff --git a/core/img/actions/radio.png b/core/img/actions/radio.png
new file mode 100644
index 00000000000..70ac4741b97
--- /dev/null
+++ b/core/img/actions/radio.png
Binary files differ
diff --git a/core/img/actions/radio.svg b/core/img/actions/radio.svg
new file mode 100644
index 00000000000..9df89251763
--- /dev/null
+++ b/core/img/actions/radio.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m8 1.5c-3.5899 0-6.5 2.9101-6.5 6.5s2.9101 6.5 6.5 6.5 6.5-2.9101 6.5-6.5-2.91-6.5-6.5-6.5z" fill="#fff"/>
+ <path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1 -6 6 6 6 0 0 1 -6 -6 6 6 0 0 1 6 -6z" fill="#969696"/>
+</svg>
diff --git a/core/img/actions/starred.svg b/core/img/actions/starred.svg
index 130bab366a2..07e38827b2d 100644
--- a/core/img/actions/starred.svg
+++ b/core/img/actions/starred.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="22" width="22" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<g transform="matrix(.068322 0 0 .068322 -10.114 -50.902)">
- <path d="m330.36 858.43 43.111 108.06 117.64 9.2572-89.445 74.392 27.55 114.75-98.391-62.079-100.62 61.66 28.637-112.76-89.734-76.638 116.09-7.6094z" transform="translate(-21.071,-112.5)" fill="#FC0"/>
+ <path fill="#FC0" d="m330.36 858.43 43.111 108.06 117.64 9.2572-89.445 74.392 27.55 114.75-98.391-62.079-100.62 61.66 28.637-112.76-89.734-76.638 116.09-7.6094z" transform="translate(-21.071,-112.5)"/>
</g>
</svg>
diff --git a/core/img/actions/toggle.svg b/core/img/actions/toggle.svg
index 730464a72ca..c426ab8099e 100644
--- a/core/img/actions/toggle.svg
+++ b/core/img/actions/toggle.svg
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 16 9" xml:space="preserve" overflow="visible" height="16" width="16" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 16 16"><path fill="#222" d="m8 3c-3.109 0-5.927 1.719-8 4.5 2.073 2.781 4.891 4.5 8 4.5 3.111 0 5.927-1.719 8-4.5-2.073-2.781-4.891-4.5-8-4.5zm0 1.5c1.657 0 3 1.343 3 3s-1.343 3-3 3-3-1.343-3-3 1.343-3 3-3zm0 1.5c-0.8284 0-1.5 0.6716-1.5 1.5s0.6716 1.5 1.5 1.5 1.5-0.6716 1.5-1.5-0.6716-1.5-1.5-1.5z"/></svg>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="16" viewBox="0 0 16 16" width="16" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" enable-background="new 0 0 16 9" overflow="visible" xmlns:dc="http://purl.org/dc/elements/1.1/"><path d="m8 3c-3.109 0-5.927 1.719-8 4.5 2.073 2.781 4.891 4.5 8 4.5 3.111 0 5.927-1.719 8-4.5-2.073-2.781-4.891-4.5-8-4.5zm0 1.5c1.657 0 3 1.343 3 3s-1.343 3-3 3-3-1.343-3-3 1.343-3 3-3zm0 1.5c-0.8284 0-1.5 0.6716-1.5 1.5s0.6716 1.5 1.5 1.5 1.5-0.6716 1.5-1.5-0.6716-1.5-1.5-1.5z" fill="#222"/></svg>
diff --git a/core/img/actions/view-close.png b/core/img/actions/view-close.png
index 0874381a576..eae9acc7a43 100644
--- a/core/img/actions/view-close.png
+++ b/core/img/actions/view-close.png
Binary files differ
diff --git a/core/img/actions/view-close.svg b/core/img/actions/view-close.svg
index 2b91e382eb1..e7dde9b79bb 100644
--- a/core/img/actions/view-close.svg
+++ b/core/img/actions/view-close.svg
@@ -5,6 +5,6 @@
<feGaussianBlur stdDeviation="2.2386623"/>
</filter>
</defs>
- <path d="m24.955 23.538-1.414 1.414-7.536-7.5358-7.5355 7.5358-1.4142-1.414 7.5355-7.536-7.5355-7.5356 1.4142-1.4142 7.5355 7.5356 7.516-7.5547 1.434 1.4333-7.5357 7.5356z" filter="url(#a)" stroke="#000" stroke-width="2"/>
+ <path filter="url(#a)" stroke="#000" stroke-width="2" d="m24.955 23.538-1.414 1.414-7.536-7.5358-7.5355 7.5358-1.4142-1.414 7.5355-7.536-7.5355-7.5356 1.4142-1.4142 7.5355 7.5356 7.516-7.5547 1.434 1.4333-7.5357 7.5356z"/>
<path d="m24.955 23.538-1.414 1.414-7.536-7.5358-7.5355 7.5358-1.4142-1.414 7.5355-7.536-7.5355-7.5356 1.4142-1.4142 7.5355 7.5356 7.516-7.5547 1.434 1.4333-7.5357 7.5356z" fill="#fff"/>
</svg>
diff --git a/core/img/actions/view-next.png b/core/img/actions/view-next.png
index d8c749bec9b..be8cc15cecd 100644
--- a/core/img/actions/view-next.png
+++ b/core/img/actions/view-next.png
Binary files differ
diff --git a/core/img/actions/view-next.svg b/core/img/actions/view-next.svg
index 4b719842efd..713d1bc7574 100644
--- a/core/img/actions/view-next.svg
+++ b/core/img/actions/view-next.svg
@@ -5,6 +5,6 @@
<feGaussianBlur stdDeviation="2.4158278"/>
</filter>
</defs>
- <path d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" filter="url(#a)" stroke="#000" stroke-width="2"/>
+ <path filter="url(#a)" stroke="#000" stroke-width="2" d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z"/>
<path d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" fill="#fff"/>
</svg>
diff --git a/core/img/actions/view-pause.png b/core/img/actions/view-pause.png
index 87a18128ade..94cd1a5dc6c 100644
--- a/core/img/actions/view-pause.png
+++ b/core/img/actions/view-pause.png
Binary files differ
diff --git a/core/img/actions/view-pause.svg b/core/img/actions/view-pause.svg
index e9ff43be0bf..8945bf4565a 100644
--- a/core/img/actions/view-pause.svg
+++ b/core/img/actions/view-pause.svg
@@ -5,10 +5,10 @@
<feGaussianBlur stdDeviation="2.5"/>
</filter>
</defs>
- <g transform="matrix(.9 0 0 .9 1.6 -916.76)" filter="url(#a)" stroke="#000" stroke-width="2.2222">
- <path d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z" stroke="#000" stroke-width="2.2222"/>
+ <g filter="url(#a)" stroke="#000" stroke-width="2.2222" transform="matrix(.9 0 0 .9 1.6 -916.76)">
+ <path stroke="#000" stroke-width="2.2222" d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z"/>
</g>
<g transform="matrix(.9 0 0 .9 1.6 -916.76)">
- <path fill="#fff" d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z"/>
+ <path d="m6 1026.4v20h8v-20h-8zm12 0v20h8v-20h-8z" fill="#fff"/>
</g>
</svg>
diff --git a/core/img/actions/view-play.png b/core/img/actions/view-play.png
index b07c6de3cfd..a8398d5758f 100644
--- a/core/img/actions/view-play.png
+++ b/core/img/actions/view-play.png
Binary files differ
diff --git a/core/img/actions/view-play.svg b/core/img/actions/view-play.svg
index e617e29cb01..6359e6d018f 100644
--- a/core/img/actions/view-play.svg
+++ b/core/img/actions/view-play.svg
@@ -5,10 +5,10 @@
<feGaussianBlur stdDeviation="3"/>
</filter>
</defs>
- <g transform="matrix(.83333 0 0 .83333 2.6667 -847.67)" filter="url(#a)" stroke="#000" stroke-width="2.4">
- <path d="m4 1024.4 24 12-24 12z" stroke="#000" stroke-width="2.4"/>
+ <g filter="url(#a)" stroke="#000" stroke-width="2.4" transform="matrix(.83333 0 0 .83333 2.6667 -847.67)">
+ <path stroke="#000" stroke-width="2.4" d="m4 1024.4 24 12-24 12z"/>
</g>
<g transform="matrix(.83333 0 0 .83333 2.6667 -847.67)">
- <path fill="#fff" d="m4 1024.4 24 12-24 12z"/>
+ <path d="m4 1024.4 24 12-24 12z" fill="#fff"/>
</g>
</svg>
diff --git a/core/img/actions/view-previous.png b/core/img/actions/view-previous.png
index f601ec2ba44..86e2a809626 100644
--- a/core/img/actions/view-previous.png
+++ b/core/img/actions/view-previous.png
Binary files differ
diff --git a/core/img/actions/view-previous.svg b/core/img/actions/view-previous.svg
index 8a5013aad40..60f6cd59285 100644
--- a/core/img/actions/view-previous.svg
+++ b/core/img/actions/view-previous.svg
@@ -5,6 +5,6 @@
<feGaussianBlur stdDeviation="2.4158278"/>
</filter>
</defs>
- <path d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" transform="matrix(-1 0 0 1 32.364 0)" filter="url(#a)" stroke="#000" stroke-width="2"/>
+ <path filter="url(#a)" stroke="#000" stroke-width="2" d="m10.414 28.952-1.414-1.414 11.535-11.536-11.535-11.536 1.414-1.4138 12.95 12.95z" transform="matrix(-1 0 0 1 32.364 0)"/>
<path d="m21.95 28.952 1.414-1.414-11.536-11.536 11.536-11.536-1.414-1.4138-12.95 12.95z" fill="#fff"/>
</svg>
diff --git a/core/img/default-app-icon.svg b/core/img/default-app-icon.svg
new file mode 100644
index 00000000000..b6ae35211a3
--- /dev/null
+++ b/core/img/default-app-icon.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.0" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path d="m13.733 0.00064c-0.52991 0-0.93331 0.40337-0.93331 0.93333v2.6666c-1.182 0.3034-2.243 0.7934-3.2668 1.4001l-1.9334-1.9334c-0.3747-0.3747-0.9586-0.3747-1.3333 0l-3.1999 3.2c-0.37473 0.37474-0.37473 0.95859 0 1.3333l1.9334 1.9335c-0.6067 1.0239-1.0967 2.0849-1.4001 3.2669h-2.6666c-0.52994 0-0.9333 0.403-0.9333 0.933v4.5333c2e-8 0.52996 0.40336 0.93333 0.93331 0.93333h2.6666c0.30335 1.1817 0.79332 2.2426 1.4 3.2666l-1.9334 1.9349c-0.37473 0.37474-0.37473 0.95859 0 1.3333l3.1999 3.2c0.37473 0.37474 0.95857 0.37474 1.3333 0l1.9334-1.9349c1.024 0.608 2.0849 1.0965 3.2665 1.3995v2.6667c0 0.53 0.403 0.933 0.933 0.933h4.5332c0.52991 0 0.93331-0.4032 0.93331-0.9344v-2.6667c1.1816-0.30336 2.2425-0.79335 3.2665-1.4l1.9333 1.9333c0.37473 0.37474 0.95857 0.37474 1.3333 0l3.1999-3.2c0.37473-0.37474 0.37473-0.95859 0-1.3333l-1.9327-1.9328c0.60798-1.024 1.0965-2.0845 1.3994-3.2661h2.6666c0.532 0 0.935-0.403 0.935-0.933v-4.534c0-0.53-0.403-0.933-0.934-0.933h-2.667c-0.303-1.182-0.791-2.243-1.399-3.2666l1.932-1.9334c0.37473-0.37474 0.37473-0.95859 0-1.3333l-3.2-3.2c-0.37473-0.37474-0.95857-0.37474-1.3333 0l-1.9327 1.9334c-1.024-0.6067-2.084-1.0967-3.266-1.4001v-2.6667c0-0.52993-0.403-0.9333-0.933-0.9333zm2.2666 8.8689c3.9361 0 7.1309 3.1947 7.1309 7.1311 0 3.9362-3.1946 7.1311-7.1309 7.1311-3.9361 0-7.1309-3.1955-7.1309-7.1317s3.1948-7.1311 7.1309-7.1311z" display="block" fill="#fff"/>
+</svg>
diff --git a/core/js/avatar.js b/core/js/avatar.js
deleted file mode 100644
index 8ff136d67ca..00000000000
--- a/core/js/avatar.js
+++ /dev/null
@@ -1,10 +0,0 @@
-$(document).ready(function(){
- if (OC.currentUser) {
- // Personal settings
- $('#avatar .avatardiv').avatar(OC.currentUser, 128);
- }
- // User settings
- $.each($('td.avatar .avatardiv'), function(i, element) {
- $(element).avatar($(element).parent().parent().data('uid'), 32);
- });
-});
diff --git a/core/js/config.php b/core/js/config.php
index 953bd2ede45..aac7630a1d8 100644
--- a/core/js/config.php
+++ b/core/js/config.php
@@ -2,12 +2,12 @@
/**
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
+ * @author Clark Tomlinson <fallen013@gmail.com>
* @author Guillaume AMAT <guillaume.amat@informatique-libre.com>
* @author Hasso Tepper <hasso@zone.ee>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
- * @author Matthias Rieber <matthias@zu-con.org>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Owen Winkler <a_github@midnightcircus.com>
* @author Robin Appelman <icewind@owncloud.com>
@@ -15,7 +15,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -62,12 +62,20 @@ if ($defaultExpireDateEnabled) {
}
$outgoingServer2serverShareEnabled = $config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
+$countOfDataLocation = 0;
+
+$dataLocation = str_replace(OC::$SERVERROOT .'/', '', $config->getSystemValue('datadirectory', ''), $countOfDataLocation);
+if($countOfDataLocation !== 1 || !OC_User::isAdminUser(OC_User::getUser())){
+ $dataLocation = false;
+}
+
$array = array(
"oc_debug" => $config->getSystemValue('debug', false) ? 'true' : 'false',
"oc_isadmin" => OC_User::isAdminUser(OC_User::getUser()) ? 'true' : 'false',
+ "oc_dataURL" => is_string($dataLocation) ? "\"".$dataLocation."\"" : 'false',
"oc_webroot" => "\"".OC::$WEBROOT."\"",
"oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution
- "datepickerFormatDate" => json_encode($l->getDateFormat()),
+ "datepickerFormatDate" => json_encode($l->l('jsdate', null)),
"dayNames" => json_encode(
array(
(string)$l->t('Sunday'),
@@ -133,14 +141,16 @@ $array = array(
(string)$l->t('Dec.')
)
),
- "firstDay" => json_encode($l->getFirstWeekDay()) ,
+ "firstDay" => json_encode($l->l('firstday', null)) ,
"oc_config" => json_encode(
array(
- 'session_lifetime' => min(\OCP\Config::getSystemValue('session_lifetime', ini_get('session.gc_maxlifetime')), ini_get('session.gc_maxlifetime')),
+ 'session_lifetime' => min(\OCP\Config::getSystemValue('session_lifetime', OC::$server->getIniWrapper()->getNumeric('session.gc_maxlifetime')), OC::$server->getIniWrapper()->getNumeric('session.gc_maxlifetime')),
'session_keepalive' => \OCP\Config::getSystemValue('session_keepalive', true),
- 'version' => implode('.', OC_Util::getVersion()),
+ 'version' => implode('.', \OCP\Util::getVersion()),
'versionstring' => OC_Util::getVersionString(),
- 'enable_avatars' => \OC::$server->getConfig()->getSystemValue('enable_avatars', true),
+ 'enable_avatars' => \OC::$server->getConfig()->getSystemValue('enable_avatars', true) === true,
+ 'lost_password_link'=> \OC::$server->getConfig()->getSystemValue('lost_password_link', null),
+ 'modRewriteWorking' => (getenv('front_controller_active') === 'true'),
)
),
"oc_appconfig" => json_encode(
@@ -164,6 +174,7 @@ $array = array(
'baseUrl' => $defaults->getBaseUrl(),
'syncClientUrl' => $defaults->getSyncClientUrl(),
'docBaseUrl' => $defaults->getDocBaseUrl(),
+ 'docPlaceholderUrl' => $defaults->buildDocLinkToKey('PLACEHOLDER'),
'slogan' => $defaults->getSlogan(),
'logoClaim' => $defaults->getLogoClaim(),
'shortFooter' => $defaults->getShortFooter(),
diff --git a/core/js/core.json b/core/js/core.json
index a80636e8463..d894d59ca54 100644
--- a/core/js/core.json
+++ b/core/js/core.json
@@ -8,7 +8,9 @@
"handlebars/handlebars.js",
"blueimp-md5/js/md5.js",
"bootstrap/js/tooltip.js",
- "backbone/backbone.js"
+ "backbone/backbone.js",
+ "es6-promise/dist/es6-promise.js",
+ "davclient.js/lib/client.js"
],
"libraries": [
"jquery-showpassword.js",
@@ -21,6 +23,7 @@
"oc-dialogs.js",
"js.js",
"oc-backbone.js",
+ "oc-backbone-webdav.js",
"l10n.js",
"apps.js",
"share.js",
@@ -39,6 +42,13 @@
"setupchecks.js",
"../search/js/search.js",
"mimetype.js",
- "mimetypelist.js"
+ "mimetypelist.js",
+ "files/fileinfo.js",
+ "files/client.js",
+ "systemtags/systemtags.js",
+ "systemtags/systemtagmodel.js",
+ "systemtags/systemtagscollection.js",
+ "systemtags/systemtagsmappingcollection.js",
+ "systemtags/systemtagsinputfield.js"
]
}
diff --git a/core/js/files/client.js b/core/js/files/client.js
new file mode 100644
index 00000000000..b736447d65e
--- /dev/null
+++ b/core/js/files/client.js
@@ -0,0 +1,685 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+/* global dav */
+
+(function(OC, FileInfo) {
+ /**
+ * @class OC.Files.Client
+ * @classdesc Client to access files on the server
+ *
+ * @param {Object} options
+ * @param {String} options.host host name
+ * @param {int} [options.port] port
+ * @param {boolean} [options.useHTTPS] whether to use https
+ * @param {String} [options.root] root path
+ * @param {String} [options.userName] user name
+ * @param {String} [options.password] password
+ *
+ * @since 8.2
+ */
+ var Client = function(options) {
+ this._root = options.root;
+ if (this._root.charAt(this._root.length - 1) === '/') {
+ this._root = this._root.substr(0, this._root.length - 1);
+ }
+
+ var url = 'http://';
+ if (options.useHTTPS) {
+ url = 'https://';
+ }
+
+ url += options.host + this._root;
+ this._defaultHeaders = options.defaultHeaders || {'X-Requested-With': 'XMLHttpRequest'};
+ this._baseUrl = url;
+
+ var clientOptions = {
+ baseUrl: this._baseUrl,
+ xmlNamespaces: {
+ 'DAV:': 'd',
+ 'http://owncloud.org/ns': 'oc'
+ }
+ };
+ if (options.userName) {
+ clientOptions.userName = options.userName;
+ }
+ if (options.password) {
+ clientOptions.password = options.password;
+ }
+ this._client = new dav.Client(clientOptions);
+ this._client.xhrProvider = _.bind(this._xhrProvider, this);
+ };
+
+ Client.NS_OWNCLOUD = 'http://owncloud.org/ns';
+ Client.NS_DAV = 'DAV:';
+ Client._PROPFIND_PROPERTIES = [
+ /**
+ * Modified time
+ */
+ [Client.NS_DAV, 'getlastmodified'],
+ /**
+ * Etag
+ */
+ [Client.NS_DAV, 'getetag'],
+ /**
+ * Mime type
+ */
+ [Client.NS_DAV, 'getcontenttype'],
+ /**
+ * Resource type "collection" for folders, empty otherwise
+ */
+ [Client.NS_DAV, 'resourcetype'],
+ /**
+ * File id
+ */
+ [Client.NS_OWNCLOUD, 'fileid'],
+ /**
+ * Letter-coded permissions
+ */
+ [Client.NS_OWNCLOUD, 'permissions'],
+ //[Client.NS_OWNCLOUD, 'downloadURL'],
+ /**
+ * Folder sizes
+ */
+ [Client.NS_OWNCLOUD, 'size'],
+ /**
+ * File sizes
+ */
+ [Client.NS_DAV, 'getcontentlength']
+ ];
+
+ /**
+ * @memberof OC.Files
+ */
+ Client.prototype = {
+
+ /**
+ * Root path of the Webdav endpoint
+ *
+ * @type string
+ */
+ _root: null,
+
+ /**
+ * Client from the library
+ *
+ * @type dav.Client
+ */
+ _client: null,
+
+ /**
+ * Array of file info parsing functions.
+ *
+ * @type Array<OC.Files.Client~parseFileInfo>
+ */
+ _fileInfoParsers: [],
+
+ /**
+ * Returns the configured XHR provider for davclient
+ * @return {XMLHttpRequest}
+ */
+ _xhrProvider: function() {
+ var headers = this._defaultHeaders;
+ var xhr = new XMLHttpRequest();
+ var oldOpen = xhr.open;
+ // override open() method to add headers
+ xhr.open = function() {
+ var result = oldOpen.apply(this, arguments);
+ _.each(headers, function(value, key) {
+ xhr.setRequestHeader(key, value);
+ });
+ return result;
+ };
+ return xhr;
+ },
+
+ /**
+ * Prepends the base url to the given path sections
+ *
+ * @param {...String} path sections
+ *
+ * @return {String} base url + joined path, any leading or trailing slash
+ * will be kept
+ */
+ _buildUrl: function() {
+ var path = this._buildPath.apply(this, arguments);
+ if (path.charAt([path.length - 1]) === '/') {
+ path = path.substr(0, path.length - 1);
+ }
+ if (path.charAt(0) === '/') {
+ path = path.substr(1);
+ }
+ return this._baseUrl + '/' + path;
+ },
+
+ /**
+ * Append the path to the root and also encode path
+ * sections
+ *
+ * @param {...String} path sections
+ *
+ * @return {String} joined path, any leading or trailing slash
+ * will be kept
+ */
+ _buildPath: function() {
+ var path = OC.joinPaths.apply(this, arguments);
+ var sections = path.split('/');
+ var i;
+ for (i = 0; i < sections.length; i++) {
+ sections[i] = encodeURIComponent(sections[i]);
+ }
+ path = sections.join('/');
+ return path;
+ },
+
+ /**
+ * Parse headers string into a map
+ *
+ * @param {string} headersString headers list as string
+ *
+ * @return {Object.<String,Array>} map of header name to header contents
+ */
+ _parseHeaders: function(headersString) {
+ var headerRows = headersString.split('\n');
+ var headers = {};
+ for (var i = 0; i < headerRows.length; i++) {
+ var sepPos = headerRows[i].indexOf(':');
+ if (sepPos < 0) {
+ continue;
+ }
+
+ var headerName = headerRows[i].substr(0, sepPos);
+ var headerValue = headerRows[i].substr(sepPos + 2);
+
+ if (!headers[headerName]) {
+ // make it an array
+ headers[headerName] = [];
+ }
+
+ headers[headerName].push(headerValue);
+ }
+ return headers;
+ },
+
+ /**
+ * Parses the etag response which is in double quotes.
+ *
+ * @param {string} etag etag value in double quotes
+ *
+ * @return {string} etag without double quotes
+ */
+ _parseEtag: function(etag) {
+ if (etag.charAt(0) === '"') {
+ return etag.split('"')[1];
+ }
+ return etag;
+ },
+
+ /**
+ * Parse Webdav result
+ *
+ * @param {Object} response XML object
+ *
+ * @return {Array.<FileInfo>} array of file info
+ */
+ _parseFileInfo: function(response) {
+ var path = response.href;
+ if (path.substr(0, this._root.length) === this._root) {
+ path = path.substr(this._root.length);
+ }
+
+ if (path.charAt(path.length - 1) === '/') {
+ path = path.substr(0, path.length - 1);
+ }
+
+ path = decodeURIComponent(path);
+
+ if (response.propStat.length === 1 && response.propStat[0].status !== 200) {
+ return null;
+ }
+
+ var props = response.propStat[0].properties;
+
+ var data = {
+ id: props['{' + Client.NS_OWNCLOUD + '}fileid'],
+ path: OC.dirname(path) || '/',
+ name: OC.basename(path),
+ mtime: (new Date(props['{' + Client.NS_DAV + '}getlastmodified'])).getTime()
+ };
+
+ var etagProp = props['{' + Client.NS_DAV + '}getetag'];
+ if (!_.isUndefined(etagProp)) {
+ data.etag = this._parseEtag(etagProp);
+ }
+
+ var sizeProp = props['{' + Client.NS_DAV + '}getcontentlength'];
+ if (!_.isUndefined(sizeProp)) {
+ data.size = parseInt(sizeProp, 10);
+ }
+
+ sizeProp = props['{' + Client.NS_OWNCLOUD + '}size'];
+ if (!_.isUndefined(sizeProp)) {
+ data.size = parseInt(sizeProp, 10);
+ }
+
+ var contentType = props['{' + Client.NS_DAV + '}getcontenttype'];
+ if (!_.isUndefined(contentType)) {
+ data.mimetype = contentType;
+ }
+
+ var resType = props['{' + Client.NS_DAV + '}resourcetype'];
+ var isFile = true;
+ if (!data.mimetype && resType) {
+ var xmlvalue = resType[0];
+ if (xmlvalue.namespaceURI === Client.NS_DAV && xmlvalue.nodeName.split(':')[1] === 'collection') {
+ data.mimetype = 'httpd/unix-directory';
+ isFile = false;
+ }
+ }
+
+ data.permissions = OC.PERMISSION_READ;
+ var permissionProp = props['{' + Client.NS_OWNCLOUD + '}permissions'];
+ if (!_.isUndefined(permissionProp)) {
+ var permString = permissionProp || '';
+ data.mountType = null;
+ for (var i = 0; i < permString.length; i++) {
+ var c = permString.charAt(i);
+ switch (c) {
+ // FIXME: twisted permissions
+ case 'C':
+ case 'K':
+ data.permissions |= OC.PERMISSION_CREATE;
+ if (!isFile) {
+ data.permissions |= OC.PERMISSION_UPDATE;
+ }
+ break;
+ case 'W':
+ data.permissions |= OC.PERMISSION_UPDATE;
+ break;
+ case 'D':
+ data.permissions |= OC.PERMISSION_DELETE;
+ break;
+ case 'R':
+ data.permissions |= OC.PERMISSION_SHARE;
+ break;
+ case 'M':
+ if (!data.mountType) {
+ // TODO: how to identify external-root ?
+ data.mountType = 'external';
+ }
+ break;
+ case 'S':
+ // TODO: how to identify shared-root ?
+ data.mountType = 'shared';
+ break;
+ }
+ }
+ }
+
+ // extend the parsed data using the custom parsers
+ _.each(this._fileInfoParsers, function(parserFunction) {
+ _.extend(data, parserFunction(response) || {});
+ });
+
+ return new FileInfo(data);
+ },
+
+ /**
+ * Parse Webdav multistatus
+ *
+ * @param {Array} responses
+ */
+ _parseResult: function(responses) {
+ var self = this;
+ return _.map(responses, function(response) {
+ return self._parseFileInfo(response);
+ });
+ },
+
+ /**
+ * Returns whether the given status code means success
+ *
+ * @param {int} status status code
+ *
+ * @return true if status code is between 200 and 299 included
+ */
+ _isSuccessStatus: function(status) {
+ return status >= 200 && status <= 299;
+ },
+
+ /**
+ * Returns the default PROPFIND properties to use during a call.
+ *
+ * @return {Array.<Object>} array of properties
+ */
+ getPropfindProperties: function() {
+ if (!this._propfindProperties) {
+ this._propfindProperties = _.map(Client._PROPFIND_PROPERTIES, function(propDef) {
+ return '{' + propDef[0] + '}' + propDef[1];
+ });
+ }
+ return this._propfindProperties;
+ },
+
+ /**
+ * Lists the contents of a directory
+ *
+ * @param {String} path path to retrieve
+ * @param {Object} [options] options
+ * @param {boolean} [options.includeParent=false] set to true to keep
+ * the parent folder in the result list
+ * @param {Array} [options.properties] list of Webdav properties to retrieve
+ *
+ * @return {Promise} promise
+ */
+ getFolderContents: function(path, options) {
+ if (!path) {
+ path = '';
+ }
+ options = options || {};
+ var self = this;
+ var deferred = $.Deferred();
+ var promise = deferred.promise();
+ var properties;
+ if (_.isUndefined(options.properties)) {
+ properties = this.getPropfindProperties();
+ } else {
+ properties = options.properties;
+ }
+
+ // TODO: headers
+ this._client.propFind(
+ this._buildUrl(path),
+ properties,
+ 1
+ ).then(function(result) {
+ if (self._isSuccessStatus(result.status)) {
+ var results = self._parseResult(result.body);
+ if (!options || !options.includeParent) {
+ // remove root dir, the first entry
+ results.shift();
+ }
+ deferred.resolve(result.status, results);
+ } else {
+ deferred.reject(result.status);
+ }
+ });
+ return promise;
+ },
+
+ /**
+ * Returns the file info of a given path.
+ *
+ * @param {String} path path
+ * @param {Array} [options.properties] list of Webdav properties to retrieve
+ *
+ * @return {Promise} promise
+ */
+ getFileInfo: function(path, options) {
+ if (!path) {
+ path = '';
+ }
+ options = options || {};
+ var self = this;
+ var deferred = $.Deferred();
+ var promise = deferred.promise();
+ var properties;
+ if (_.isUndefined(options.properties)) {
+ properties = this.getPropfindProperties();
+ } else {
+ properties = options.properties;
+ }
+
+ // TODO: headers
+ this._client.propFind(
+ this._buildUrl(path),
+ properties,
+ 0
+ ).then(
+ function(result) {
+ if (self._isSuccessStatus(result.status)) {
+ deferred.resolve(result.status, self._parseResult([result.body])[0]);
+ } else {
+ deferred.reject(result.status);
+ }
+ }
+ );
+ return promise;
+ },
+
+ /**
+ * Returns the contents of the given file.
+ *
+ * @param {String} path path to file
+ *
+ * @return {Promise}
+ */
+ getFileContents: function(path) {
+ if (!path) {
+ throw 'Missing argument "path"';
+ }
+ var self = this;
+ var deferred = $.Deferred();
+ var promise = deferred.promise();
+
+ this._client.request(
+ 'GET',
+ this._buildUrl(path),
+ this._defaultHeaders
+ ).then(
+ function(result) {
+ if (self._isSuccessStatus(result.status)) {
+ deferred.resolve(result.status, result.body);
+ } else {
+ deferred.reject(result.status);
+ }
+ }
+ );
+ return promise;
+ },
+
+ /**
+ * Puts the given data into the given file.
+ *
+ * @param {String} path path to file
+ * @param {String} body file body
+ * @param {Object} [options]
+ * @param {String} [options.contentType='text/plain'] content type
+ * @param {bool} [options.overwrite=true] whether to overwrite an existing file
+ *
+ * @return {Promise}
+ */
+ putFileContents: function(path, body, options) {
+ if (!path) {
+ throw 'Missing argument "path"';
+ }
+ var self = this;
+ var deferred = $.Deferred();
+ var promise = deferred.promise();
+ options = options || {};
+ var headers = _.extend({}, this._defaultHeaders);
+ var contentType = 'text/plain;charset=utf-8';
+ if (options.contentType) {
+ contentType = options.contentType;
+ }
+
+ headers['Content-Type'] = contentType;
+
+ if (_.isUndefined(options.overwrite) || options.overwrite) {
+ // will trigger 412 precondition failed if a file already exists
+ headers['If-None-Match'] = '*';
+ }
+
+ this._client.request(
+ 'PUT',
+ this._buildUrl(path),
+ headers,
+ body || ''
+ ).then(
+ function(result) {
+ if (self._isSuccessStatus(result.status)) {
+ deferred.resolve(result.status);
+ } else {
+ deferred.reject(result.status);
+ }
+ }
+ );
+ return promise;
+ },
+
+ _simpleCall: function(method, path) {
+ if (!path) {
+ throw 'Missing argument "path"';
+ }
+
+ var self = this;
+ var deferred = $.Deferred();
+ var promise = deferred.promise();
+
+ this._client.request(
+ method,
+ this._buildUrl(path),
+ this._defaultHeaders
+ ).then(
+ function(result) {
+ if (self._isSuccessStatus(result.status)) {
+ deferred.resolve(result.status);
+ } else {
+ deferred.reject(result.status);
+ }
+ }
+ );
+ return promise;
+ },
+
+ /**
+ * Creates a directory
+ *
+ * @param {String} path path to create
+ *
+ * @return {Promise}
+ */
+ createDirectory: function(path) {
+ return this._simpleCall('MKCOL', path);
+ },
+
+ /**
+ * Deletes a file or directory
+ *
+ * @param {String} path path to delete
+ *
+ * @return {Promise}
+ */
+ remove: function(path) {
+ return this._simpleCall('DELETE', path);
+ },
+
+ /**
+ * Moves path to another path
+ *
+ * @param {String} path path to move
+ * @param {String} destinationPath destination path
+ * @param {boolean} [allowOverwrite=false] true to allow overwriting,
+ * false otherwise
+ *
+ * @return {Promise} promise
+ */
+ move: function(path, destinationPath, allowOverwrite) {
+ if (!path) {
+ throw 'Missing argument "path"';
+ }
+ if (!destinationPath) {
+ throw 'Missing argument "destinationPath"';
+ }
+
+ var self = this;
+ var deferred = $.Deferred();
+ var promise = deferred.promise();
+ var headers =
+ _.extend({
+ 'Destination' : this._buildUrl(destinationPath)
+ }, this._defaultHeaders);
+
+ if (!allowOverwrite) {
+ headers['Overwrite'] = 'F';
+ }
+
+ this._client.request(
+ 'MOVE',
+ this._buildUrl(path),
+ headers
+ ).then(
+ function(response) {
+ if (self._isSuccessStatus(response.status)) {
+ deferred.resolve(response.status);
+ } else {
+ deferred.reject(response.status);
+ }
+ }
+ );
+ return promise;
+ },
+
+ /**
+ * Add a file info parser function
+ *
+ * @param {OC.Files.Client~parseFileInfo>}
+ */
+ addFileInfoParser: function(parserFunction) {
+ this._fileInfoParsers.push(parserFunction);
+ }
+
+ };
+
+ /**
+ * File info parser function
+ *
+ * This function receives a list of Webdav properties as input and
+ * should return a hash array of parsed properties, if applicable.
+ *
+ * @callback OC.Files.Client~parseFileInfo
+ * @param {Object} XML Webdav properties
+ * @return {Array} array of parsed property values
+ */
+
+ if (!OC.Files) {
+ /**
+ * @namespace OC.Files
+ *
+ * @since 8.2
+ */
+ OC.Files = {};
+ }
+
+ /**
+ * Returns the default instance of the files client
+ *
+ * @return {OC.Files.Client} default client
+ *
+ * @since 8.2
+ */
+ OC.Files.getClient = function() {
+ if (OC.Files._defaultClient) {
+ return OC.Files._defaultClient;
+ }
+
+ var client = new OC.Files.Client({
+ host: OC.getHost(),
+ port: OC.getPort(),
+ root: OC.linkToRemoteBase('webdav'),
+ useHTTPS: OC.getProtocol() === 'https'
+ });
+ OC.Files._defaultClient = client;
+ return client;
+ };
+
+ OC.Files.Client = Client;
+})(OC, OC.Files.FileInfo);
+
diff --git a/core/js/files/fileinfo.js b/core/js/files/fileinfo.js
new file mode 100644
index 00000000000..3bf68d88b15
--- /dev/null
+++ b/core/js/files/fileinfo.js
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC) {
+
+ /**
+ * @class OC.Files.FileInfo
+ * @classdesc File information
+ *
+ * @param {Object} data file data, see attributes for details
+ *
+ * @since 8.2
+ */
+ var FileInfo = function(data) {
+ var self = this;
+ _.each(data, function(value, key) {
+ if (!_.isFunction(value)) {
+ self[key] = value;
+ }
+ });
+
+ if (!_.isUndefined(this.id)) {
+ this.id = parseInt(data.id, 10);
+ }
+
+ // TODO: normalize path
+ this.path = data.path || '';
+
+ if (this.type === 'dir') {
+ this.mimetype = 'httpd/unix-directory';
+ } else {
+ this.mimetype = this.mimetype || 'application/octet-stream';
+ }
+
+ if (!this.type) {
+ if (this.mimetype === 'httpd/unix-directory') {
+ this.type = 'dir';
+ } else {
+ this.type = 'file';
+ }
+ }
+ };
+
+ /**
+ * @memberof OC.Files
+ */
+ FileInfo.prototype = {
+ /**
+ * File id
+ *
+ * @type int
+ */
+ id: null,
+
+ /**
+ * File name
+ *
+ * @type String
+ */
+ name: null,
+
+ /**
+ * Path leading to the file, without the file name,
+ * and with a leading slash.
+ *
+ * @type String
+ */
+ path: null,
+
+ /**
+ * Mime type
+ *
+ * @type String
+ */
+ mimetype: null,
+
+ /**
+ * Icon URL.
+ *
+ * Can be used to override the mime type icon.
+ *
+ * @type String
+ */
+ icon: null,
+
+ /**
+ * File type. 'file' for files, 'dir' for directories.
+ *
+ * @type String
+ * @deprecated rely on mimetype instead
+ */
+ type: null,
+
+ /**
+ * Permissions.
+ *
+ * @see OC#PERMISSION_ALL for permissions
+ * @type int
+ */
+ permissions: null,
+
+ /**
+ * Modification time
+ *
+ * @type int
+ */
+ mtime: null,
+
+ /**
+ * Etag
+ *
+ * @type String
+ */
+ etag: null,
+
+ /**
+ * Mount type.
+ *
+ * One of null, "external-root", "shared" or "shared-root"
+ *
+ * @type string
+ */
+ mountType: null
+ };
+
+ if (!OC.Files) {
+ OC.Files = {};
+ }
+ OC.Files.FileInfo = FileInfo;
+})(OC);
+
diff --git a/core/js/files/iedavclient.js b/core/js/files/iedavclient.js
new file mode 100644
index 00000000000..4fd9a3a3bf4
--- /dev/null
+++ b/core/js/files/iedavclient.js
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+/* global dav */
+(function(dav) {
+
+ /**
+ * Override davclient.js methods with IE-compatible logic
+ */
+ dav.Client.prototype = _.extend({}, dav.Client.prototype, {
+
+ /**
+ * Generates a propFind request.
+ *
+ * @param {string} url Url to do the propfind request on
+ * @param {Array} properties List of properties to retrieve.
+ * @return {Promise}
+ */
+ propFind : function(url, properties, depth) {
+
+ if(typeof depth == "undefined") {
+ depth = 0;
+ }
+
+ var headers = {
+ Depth : depth,
+ 'Content-Type' : 'application/xml; charset=utf-8'
+ };
+
+ var body =
+ '<?xml version="1.0"?>\n' +
+ '<d:propfind ';
+
+ var namespace;
+ for (namespace in this.xmlNamespaces) {
+ body += ' xmlns:' + this.xmlNamespaces[namespace] + '="' + namespace + '"';
+ }
+ body += '>\n' +
+ ' <d:prop>\n';
+
+ for(var ii in properties) {
+ var propText = properties[ii];
+ if (typeof propText !== 'string') {
+ // can happen on IE8
+ continue;
+ }
+ var property = this.parseClarkNotation(properties[ii]);
+ if (this.xmlNamespaces[property.namespace]) {
+ body+=' <' + this.xmlNamespaces[property.namespace] + ':' + property.name + ' />\n';
+ } else {
+ body+=' <x:' + property.name + ' xmlns:x="' + property.namespace + '" />\n';
+ }
+
+ }
+ body+=' </d:prop>\n';
+ body+='</d:propfind>';
+
+ return this.request('PROPFIND', url, headers, body).then(
+ function(result) {
+ var elements = this.parseMultiStatus(result.xhr.responseXML);
+ var response;
+ if (depth===0) {
+ response = {
+ status: result.status,
+ body: elements[0]
+ };
+ } else {
+ response = {
+ status: result.status,
+ body: elements
+ };
+ }
+ return response;
+
+ }.bind(this)
+ );
+
+ },
+
+
+ _getElementsByTagName: function(node, name, resolver) {
+ var parts = name.split(':');
+ var tagName = parts[1];
+ var namespace = resolver(parts[0]);
+ if (node.getElementsByTagNameNS) {
+ return node.getElementsByTagNameNS(namespace, tagName);
+ }
+ return node.getElementsByTagName(name);
+ },
+
+ /**
+ * Parses a multi-status response body.
+ *
+ * @param {string} xmlBody
+ * @param {Array}
+ */
+ parseMultiStatus : function(doc) {
+
+ var result = [];
+ var resolver = function(foo) {
+ var ii;
+ for(ii in this.xmlNamespaces) {
+ if (this.xmlNamespaces[ii] === foo) {
+ return ii;
+ }
+ }
+ }.bind(this);
+
+ var responses = this._getElementsByTagName(doc, 'd:response', resolver);
+ var i;
+ for (i = 0; i < responses.length; i++) {
+ var responseNode = responses[i];
+ var response = {
+ href : null,
+ propStat : []
+ };
+
+ var hrefNode = this._getElementsByTagName(responseNode, 'd:href', resolver)[0];
+
+ response.href = hrefNode.textContent || hrefNode.text;
+
+ var propStatNodes = this._getElementsByTagName(responseNode, 'd:propstat', resolver);
+ var j = 0;
+
+ for (j = 0; j < propStatNodes.length; j++) {
+ var propStatNode = propStatNodes[j];
+ var statusNode = this._getElementsByTagName(propStatNode, 'd:status', resolver)[0];
+
+ var propStat = {
+ status : statusNode.textContent || statusNode.text,
+ properties : []
+ };
+
+ var propNode = this._getElementsByTagName(propStatNode, 'd:prop', resolver)[0];
+ if (!propNode) {
+ continue;
+ }
+ var k = 0;
+ for (k = 0; k < propNode.childNodes.length; k++) {
+ var prop = propNode.childNodes[k];
+ var value = this._parsePropNode(prop);
+ propStat.properties['{' + prop.namespaceURI + '}' + (prop.localName || prop.baseName)] = value;
+
+ }
+ response.propStat.push(propStat);
+ }
+
+ result.push(response);
+ }
+
+ return result;
+
+ }
+
+
+ });
+
+})(dav);
+
diff --git a/core/js/integritycheck-failed-notification.js b/core/js/integritycheck-failed-notification.js
new file mode 100644
index 00000000000..5bc758d54cb
--- /dev/null
+++ b/core/js/integritycheck-failed-notification.js
@@ -0,0 +1,38 @@
+/**
+ * @author Lukas Reschke
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * This gets only loaded if the integrity check has failed and then shows a notification
+ */
+$(document).ready(function(){
+ var text = t(
+ 'core',
+ '<a href="{docUrl}">There were problems with the code integrity check. More information…</a>',
+ {
+ docUrl: OC.generateUrl('/settings/admin#security-warning')
+ }
+ );
+
+ OC.Notification.showHtml(
+ text,
+ {
+ isHTML: true
+ }
+ );
+});
+
diff --git a/core/js/jquery.avatar.js b/core/js/jquery.avatar.js
index 552657877e7..d87c234e14e 100644
--- a/core/js/jquery.avatar.js
+++ b/core/js/jquery.avatar.js
@@ -47,7 +47,7 @@
*/
(function ($) {
- $.fn.avatar = function(user, size, ie8fix, hidedefault, callback) {
+ $.fn.avatar = function(user, size, ie8fix, hidedefault, callback, displayname) {
if (typeof(size) === 'undefined') {
if (this.height() > 0) {
size = this.height();
@@ -79,30 +79,54 @@
'/avatar/{user}/{size}',
{user: user, size: Math.ceil(size * window.devicePixelRatio)});
- $.get(url, function(result) {
- if (typeof(result) === 'object') {
- if (!hidedefault) {
- if (result.data && result.data.displayname) {
- $div.imageplaceholder(user, result.data.displayname);
+ // If the displayname is not defined we use the old code path
+ if (typeof(displayname) === 'undefined') {
+ $.get(url).always(function(result, status) {
+ // if there is an error or an object returned (contains user information):
+ // -> show the fallback placeholder
+ if (typeof(result) === 'object' || status === 'error') {
+ if (!hidedefault) {
+ if (result.data && result.data.displayname) {
+ $div.imageplaceholder(user, result.data.displayname);
+ } else {
+ // User does not exist
+ $div.imageplaceholder(user, 'X');
+ $div.css('background-color', '#b9b9b9');
+ }
} else {
- // User does not exist
- $div.imageplaceholder(user, 'X');
- $div.css('background-color', '#b9b9b9');
+ $div.hide();
}
+ // else an image is transferred and should be shown
} else {
- $div.hide();
+ $div.show();
+ if (ie8fix === true) {
+ $div.html('<img width="' + size + '" height="' + size + '" src="'+url+'#'+Math.floor(Math.random()*1000)+'">');
+ } else {
+ $div.html('<img width="' + size + '" height="' + size + '" src="'+url+'">');
+ }
}
- } else {
- $div.show();
- if (ie8fix === true) {
- $div.html('<img width="' + size + '" height="' + size + '" src="'+url+'#'+Math.floor(Math.random()*1000)+'">');
- } else {
- $div.html('<img width="' + size + '" height="' + size + '" src="'+url+'">');
+ if(typeof callback === 'function') {
+ callback();
}
+ });
+ } else {
+ // We already have the displayname so set the placeholder (to show at least something)
+ if (!hidedefault) {
+ $div.imageplaceholder(displayname);
}
- if(typeof callback === 'function') {
- callback();
+
+ var img = new Image();
+
+ // If the new image loads successfull set it.
+ img.onload = function() {
+ $div.show();
+ $div.text('');
+ $div.append(img);
}
- });
+
+ img.width = size;
+ img.height = size;
+ img.src = url;
+ }
};
}(jQuery));
diff --git a/core/js/js.js b/core/js/js.js
index 57c9871233b..83658a537b8 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -1,11 +1,13 @@
/**
* Disable console output unless DEBUG mode is enabled.
* Add
- * define('DEBUG', true);
- * To the end of config/config.php to enable debug mode.
+ * 'debug' => true,
+ * To the definition of $CONFIG in config/config.php to enable debug mode.
* The undefined checks fix the broken ie8 console
*/
+/* global oc_isadmin */
+
var oc_debug;
var oc_webroot;
@@ -80,6 +82,12 @@ var OC={
webroot:oc_webroot,
appswebroots:(typeof oc_appswebroots !== 'undefined') ? oc_appswebroots:false,
+ /**
+ * Currently logged in user or null if none
+ *
+ * @type String
+ * @deprecated use {@link OC.getCurrentUser} instead
+ */
currentUser:(typeof oc_current_user!=='undefined')?oc_current_user:false,
config: window.oc_config,
appConfig: window.oc_appconfig || {},
@@ -160,7 +168,11 @@ var OC={
url = '/' + url;
}
- // TODO save somewhere whether the webserver is able to skip the index.php to have shorter links (e.g. for sharing)
+
+ if(oc_config.modRewriteWorking == true) {
+ return OC.webroot + _build(url, params);
+ }
+
return OC.webroot + '/index.php' + _build(url, params);
},
@@ -170,7 +182,6 @@ var OC={
* @param {string} type the type of the file to link to (e.g. css,img,ajax.template)
* @param {string} file the filename
* @return {string} Absolute URL for a file in an app
- * @deprecated use OC.generateUrl() instead
*/
filePath:function(app,type,file){
var isCore=OC.coreApps.indexOf(app)!==-1,
@@ -232,9 +243,15 @@ var OC={
},
/**
- * Returns the host name used to access this ownCloud instance
+ * Returns the host used to access this ownCloud instance
+ * Host is sometimes the same as the hostname but now always.
*
- * @return {string} host name
+ * Examples:
+ * http://example.com => example.com
+ * https://example.com => exmaple.com
+ * http://example.com:8080 => example.com:8080
+ *
+ * @return {string} host
*
* @since 8.2
*/
@@ -243,6 +260,17 @@ var OC={
},
/**
+ * Returns the hostname used to access this ownCloud instance
+ * The hostname is always stripped of the port
+ *
+ * @return {string} hostname
+ * @since 9.0
+ */
+ getHostName: function() {
+ return window.location.hostname;
+ },
+
+ /**
* Returns the port number used to access this ownCloud instance
*
* @return {int} port number
@@ -267,6 +295,23 @@ var OC={
},
/**
+ * Returns the currently logged in user or null if there is no logged in
+ * user (public page mode)
+ *
+ * @return {OC.CurrentUser} user spec
+ * @since 9.0.0
+ */
+ getCurrentUser: function() {
+ if (_.isUndefined(this._currentUserDisplayName)) {
+ this._currentUserDisplayName = document.getElementsByTagName('head')[0].getAttribute('data-user-displayname');
+ }
+ return {
+ uid: this.currentUser,
+ displayName: this._currentUserDisplayName
+ };
+ },
+
+ /**
* get the absolute path to an image file
* if no extension is given for the image, it will automatically decide
* between .png and .svg based on what the browser supports
@@ -671,10 +716,29 @@ var OC={
*/
getLocale: function() {
return $('html').prop('lang');
- }
+ },
+
+ /**
+ * Returns whether the current user is an administrator
+ *
+ * @return {bool} true if the user is an admin, false otherwise
+ * @since 9.0.0
+ */
+ isUserAdmin: function() {
+ return oc_isadmin;
+ },
};
/**
+ * Current user attributes
+ *
+ * @typedef {Object} OC.CurrentUser
+ *
+ * @property {String} uid user id
+ * @property {String} displayName display name
+ */
+
+/**
* @namespace OC.Plugins
*/
OC.Plugins = {
@@ -1428,7 +1492,6 @@ function initCore() {
$('body').delegate('#app-content', 'apprendered appresized', adjustControlsWidth);
}
-
}
$(document).ready(initCore);
@@ -1447,7 +1510,7 @@ $.fn.filterAttr = function(attr_name, attr_value) {
* @return {string}
*/
function humanFileSize(size, skipSmallSizes) {
- var humanList = ['B', 'kB', 'MB', 'GB', 'TB'];
+ var humanList = ['B', 'KB', 'MB', 'GB', 'TB'];
// Calculate Log with base 1024: size = 1024 ** order
var order = size > 0 ? Math.floor(Math.log(size) / Math.log(1024)) : 0;
// Stay in range of the byte sizes that are defined
@@ -1456,9 +1519,9 @@ function humanFileSize(size, skipSmallSizes) {
var relativeSize = (size / Math.pow(1024, order)).toFixed(1);
if(skipSmallSizes === true && order === 0) {
if(relativeSize !== "0.0"){
- return '< 1 kB';
+ return '< 1 KB';
} else {
- return '0 kB';
+ return '0 KB';
}
}
if(order < 2){
diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js
index 294a9d8c1cf..df28c2308cb 100644
--- a/core/js/lostpassword.js
+++ b/core/js/lostpassword.js
@@ -13,22 +13,26 @@ OC.Lostpassword = {
resetErrorMsg : t('core', 'Password can not be changed. Please contact your administrator.'),
init : function() {
- $('#lost-password').click(OC.Lostpassword.sendLink);
+ $('#lost-password').click(OC.Lostpassword.resetLink);
$('#reset-password #submit').click(OC.Lostpassword.resetPassword);
},
- sendLink : function(event){
+ resetLink : function(event){
event.preventDefault();
if (!$('#user').val().length){
$('#submit').trigger('click');
} else {
- $.post(
+ if (OC.config['lost_password_link']) {
+ window.location = OC.config['lost_password_link'];
+ } else {
+ $.post(
OC.generateUrl('/lostpassword/email'),
{
user : $('#user').val()
},
OC.Lostpassword.sendLinkDone
- );
+ );
+ }
}
},
diff --git a/core/js/mimetypelist.js b/core/js/mimetypelist.js
index 43f01273f55..89c6e8c4d4e 100644
--- a/core/js/mimetypelist.js
+++ b/core/js/mimetypelist.js
@@ -17,12 +17,14 @@ OC.MimeTypeList={
"application/json": "text/code",
"application/msaccess": "file",
"application/msexcel": "x-office/spreadsheet",
+ "application/msonenote": "x-office/document",
"application/mspowerpoint": "x-office/presentation",
"application/msword": "x-office/document",
"application/octet-stream": "file",
"application/postscript": "image",
"application/rss+xml": "application/xml",
"application/vnd.android.package-archive": "package/x-generic",
+ "application/vnd.lotus-wordpro": "x-office/document",
"application/vnd.ms-excel": "x-office/spreadsheet",
"application/vnd.ms-excel.addin.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-excel.sheet.binary.macroEnabled.12": "x-office/spreadsheet",
@@ -51,6 +53,8 @@ OC.MimeTypeList={
"application/vnd.openxmlformats-officedocument.spreadsheetml.template": "x-office/spreadsheet",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "x-office/document",
"application/vnd.openxmlformats-officedocument.wordprocessingml.template": "x-office/document",
+ "application/vnd.visio": "x-office/document",
+ "application/vnd.wordperfect": "x-office/document",
"application/x-7z-compressed": "package/x-generic",
"application/x-cbr": "text",
"application/x-compressed": "package/x-generic",
@@ -82,26 +86,26 @@ OC.MimeTypeList={
"web": "text/code"
},
files: [
- "video",
+ "application",
+ "application-pdf",
+ "audio",
+ "file",
+ "folder",
"folder-drag-accept",
- "folder-starred",
+ "folder-external",
"folder-public",
+ "folder-shared",
+ "folder-starred",
+ "image",
"package-x-generic",
"text",
- "folder-external",
- "text-vcard",
- "application",
+ "text-calendar",
"text-code",
- "x-office-spreadsheet",
- "application-pdf",
- "folder",
+ "text-vcard",
+ "video",
"x-office-document",
- "text-calendar",
"x-office-presentation",
- "file",
- "folder-shared",
- "image",
- "audio"
+ "x-office-spreadsheet"
],
themes: []
};
diff --git a/core/js/oc-backbone-webdav.js b/core/js/oc-backbone-webdav.js
new file mode 100644
index 00000000000..ba678a32fcf
--- /dev/null
+++ b/core/js/oc-backbone-webdav.js
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+/**
+ * Webdav transport for Backbone.
+ *
+ * This makes it possible to use Webdav endpoints when
+ * working with Backbone models and collections.
+ *
+ * Requires the davclient.js library.
+ *
+ * Usage example:
+ *
+ * var PersonModel = OC.Backbone.Model.extend({
+ * // make it use the DAV transport
+ * sync: OC.Backbone.davSync,
+ *
+ * // DAV properties mapping
+ * davProperties: {
+ * 'id': '{http://example.com/ns}id',
+ * 'firstName': '{http://example.com/ns}first-name',
+ * 'lastName': '{http://example.com/ns}last-name',
+ * 'age': '{http://example.com/ns}age'
+ * },
+ *
+ * // additional parsing, if needed
+ * parse: function(props) {
+ * // additional parsing (DAV property values are always strings)
+ * props.age = parseInt(props.age, 10);
+ * return props;
+ * }
+ * });
+ *
+ * var PersonCollection = OC.Backbone.Collection.extend({
+ * // make it use the DAV transport
+ * sync: OC.Backbone.davSync,
+ *
+ * // use person model
+ * // note that davProperties will be inherited
+ * model: PersonModel,
+ *
+ * // DAV collection URL
+ * url: function() {
+ * return OC.linkToRemote('dav') + '/person/';
+ * },
+ * });
+ */
+
+/* global dav */
+
+(function(Backbone) {
+ var methodMap = {
+ 'create': 'POST',
+ 'update': 'PROPPATCH',
+ 'patch': 'PROPPATCH',
+ 'delete': 'DELETE',
+ 'read': 'PROPFIND'
+ };
+
+ // Throw an error when a URL is needed, and none is supplied.
+ function urlError() {
+ throw new Error('A "url" property or function must be specified');
+ }
+
+ /**
+ * Convert a single propfind result to JSON
+ *
+ * @param {Object} result
+ * @param {Object} davProperties properties mapping
+ */
+ function parsePropFindResult(result, davProperties) {
+ if (_.isArray(result)) {
+ return _.map(result, function(subResult) {
+ return parsePropFindResult(subResult, davProperties);
+ });
+ }
+ var props = {
+ href: result.href
+ };
+
+ _.each(result.propStat, function(propStat) {
+ if (propStat.status !== 'HTTP/1.1 200 OK') {
+ return;
+ }
+
+ for (var key in propStat.properties) {
+ var propKey = key;
+ if (key in davProperties) {
+ propKey = davProperties[key];
+ }
+ props[propKey] = propStat.properties[key];
+ }
+ });
+
+ if (!props.id) {
+ // parse id from href
+ props.id = parseIdFromLocation(props.href);
+ }
+
+ return props;
+ }
+
+ /**
+ * Parse ID from location
+ *
+ * @param {string} url url
+ * @return {string} id
+ */
+ function parseIdFromLocation(url) {
+ var queryPos = url.indexOf('?');
+ if (queryPos > 0) {
+ url = url.substr(0, queryPos);
+ }
+
+ var parts = url.split('/');
+ return parts[parts.length - 1];
+ }
+
+ function isSuccessStatus(status) {
+ return status >= 200 && status <= 299;
+ }
+
+ function convertModelAttributesToDavProperties(attrs, davProperties) {
+ var props = {};
+ var key;
+ for (key in attrs) {
+ var changedProp = davProperties[key];
+ var value = attrs[key];
+ if (!changedProp) {
+ console.warn('No matching DAV property for property "' + key);
+ changedProp = key;
+ }
+ if (_.isBoolean(value) || _.isNumber(value)) {
+ // convert to string
+ value = '' + value;
+ }
+ props[changedProp] = value;
+ }
+ return props;
+ }
+
+ function callPropFind(client, options, model, headers) {
+ return client.propFind(
+ options.url,
+ _.values(options.davProperties) || [],
+ options.depth,
+ headers
+ ).then(function(response) {
+ if (isSuccessStatus(response.status)) {
+ if (_.isFunction(options.success)) {
+ var propsMapping = _.invert(options.davProperties);
+ var results = parsePropFindResult(response.body, propsMapping);
+ if (options.depth > 0) {
+ // discard root entry
+ results.shift();
+ }
+
+ options.success(results);
+ return;
+ }
+ } else if (_.isFunction(options.error)) {
+ options.error(response);
+ }
+ });
+ }
+
+ function callPropPatch(client, options, model, headers) {
+ return client.propPatch(
+ options.url,
+ convertModelAttributesToDavProperties(model.changed, options.davProperties),
+ headers
+ ).then(function(result) {
+ if (isSuccessStatus(result.status)) {
+ if (_.isFunction(options.success)) {
+ // pass the object's own values because the server
+ // does not return the updated model
+ options.success(model.toJSON());
+ }
+ } else if (_.isFunction(options.error)) {
+ options.error(result);
+ }
+ });
+
+ }
+
+ function callMethod(client, options, model, headers) {
+ headers['Content-Type'] = 'application/json';
+ return client.request(
+ options.type,
+ options.url,
+ headers,
+ options.data
+ ).then(function(result) {
+ if (!isSuccessStatus(result.status)) {
+ if (_.isFunction(options.error)) {
+ options.error(result);
+ }
+ return;
+ }
+
+ if (_.isFunction(options.success)) {
+ if (options.type === 'PUT' || options.type === 'POST') {
+ // pass the object's own values because the server
+ // does not return anything
+ var responseJson = result.body || model.toJSON();
+ var locationHeader = result.xhr.getResponseHeader('Content-Location');
+ if (options.type === 'POST' && locationHeader) {
+ responseJson.id = parseIdFromLocation(locationHeader);
+ }
+ options.success(responseJson);
+ return;
+ }
+ // if multi-status, parse
+ if (result.status === 207) {
+ var propsMapping = _.invert(options.davProperties);
+ options.success(parsePropFindResult(result.body, propsMapping));
+ } else {
+ options.success(result.body);
+ }
+ }
+ });
+ }
+
+ function davCall(options, model) {
+ var client = new dav.Client({
+ baseUrl: options.url,
+ xmlNamespaces: _.extend({
+ 'DAV:': 'd',
+ 'http://owncloud.org/ns': 'oc'
+ }, options.xmlNamespaces || {})
+ });
+ client.resolveUrl = function() {
+ return options.url;
+ };
+ var headers = _.extend({
+ 'X-Requested-With': 'XMLHttpRequest'
+ }, options.headers);
+ if (options.type === 'PROPFIND') {
+ return callPropFind(client, options, model, headers);
+ } else if (options.type === 'PROPPATCH') {
+ return callPropPatch(client, options, model, headers);
+ } else {
+ return callMethod(client, options, model, headers);
+ }
+ }
+
+ /**
+ * DAV transport
+ */
+ function davSync(method, model, options) {
+ var params = {type: methodMap[method] || method};
+ var isCollection = (model instanceof Backbone.Collection);
+
+ if (method === 'update' && (model.usePUT || (model.collection && model.collection.usePUT))) {
+ // use PUT instead of PROPPATCH
+ params.type = 'PUT';
+ }
+
+ // Ensure that we have a URL.
+ if (!options.url) {
+ params.url = _.result(model, 'url') || urlError();
+ }
+
+ // Ensure that we have the appropriate request data.
+ if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
+ params.data = JSON.stringify(options.attrs || model.toJSON(options));
+ }
+
+ // Don't process data on a non-GET request.
+ if (params.type !== 'PROPFIND') {
+ params.processData = false;
+ }
+
+ if (params.type === 'PROPFIND' || params.type === 'PROPPATCH') {
+ var davProperties = model.davProperties;
+ if (!davProperties && model.model) {
+ // use dav properties from model in case of collection
+ davProperties = model.model.prototype.davProperties;
+ }
+ if (davProperties) {
+ if (_.isFunction(davProperties)) {
+ params.davProperties = davProperties.call(model);
+ } else {
+ params.davProperties = davProperties;
+ }
+ }
+
+ params.davProperties = _.extend(params.davProperties || {}, options.davProperties);
+
+ if (_.isUndefined(options.depth)) {
+ if (isCollection) {
+ options.depth = 1;
+ } else {
+ options.depth = 0;
+ }
+ }
+ }
+
+ // Pass along `textStatus` and `errorThrown` from jQuery.
+ var error = options.error;
+ options.error = function(xhr, textStatus, errorThrown) {
+ options.textStatus = textStatus;
+ options.errorThrown = errorThrown;
+ if (error) {
+ error.call(options.context, xhr, textStatus, errorThrown);
+ }
+ };
+
+ // Make the request, allowing the user to override any Ajax options.
+ var xhr = options.xhr = Backbone.davCall(_.extend(params, options), model);
+ model.trigger('request', model, xhr, options);
+ return xhr;
+ }
+
+ // exports
+ Backbone.davCall = davCall;
+ Backbone.davSync = davSync;
+
+})(OC.Backbone);
+
diff --git a/core/js/oc-backbone.js b/core/js/oc-backbone.js
index 75a40979340..5c4eb2d24c8 100644
--- a/core/js/oc-backbone.js
+++ b/core/js/oc-backbone.js
@@ -7,6 +7,8 @@
* See the COPYING-README file.
*
*/
+
+/* global Backbone */
if(!_.isUndefined(Backbone)) {
OC.Backbone = Backbone.noConflict();
}
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
index 4448b813021..b77063a9eae 100644
--- a/core/js/oc-dialogs.js
+++ b/core/js/oc-dialogs.js
@@ -753,13 +753,14 @@ var OCdialogs = {
var sorted = dirs.concat(others);
$.each(sorted, function(idx, entry) {
+ entry.icon = OC.MimeType.getIconUrl(entry.mimetype);
var $li = self.$listTmpl.octemplate({
type: entry.type,
dir: dir,
filename: entry.name,
date: OC.Util.relativeModifiedDate(entry.mtime)
});
- if (entry.isPreviewAvailable) {
+ if (entry.type === 'file') {
var urlSpec = {
file: dir + '/' + entry.name
};
diff --git a/core/js/placeholder.js b/core/js/placeholder.js
index 74bb9b1881d..5fb5b5b8f80 100644
--- a/core/js/placeholder.js
+++ b/core/js/placeholder.js
@@ -47,16 +47,20 @@
*/
(function ($) {
- $.fn.imageplaceholder = function(seed, text) {
+ $.fn.imageplaceholder = function(seed, text, size) {
// set optional argument "text" to value of "seed" if undefined
text = text || seed;
- var hash = md5(seed),
- maxRange = parseInt('ffffffffffffffffffffffffffffffff', 16),
+ var hash = md5(seed).substring(0, 4),
+ maxRange = parseInt('ffff', 16),
hue = parseInt(hash, 16) / maxRange * 256,
- height = this.height();
+ height = this.height() || size || 32;
this.css('background-color', 'hsl(' + hue + ', 90%, 65%)');
+ // Placeholders are square
+ this.height(height);
+ this.width(height);
+
// CSS rules
this.css('color', '#fff');
this.css('font-weight', 'normal');
diff --git a/core/js/select2-toggleselect.js b/core/js/select2-toggleselect.js
new file mode 100644
index 00000000000..4fada592a3b
--- /dev/null
+++ b/core/js/select2-toggleselect.js
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+/* global Select2 */
+
+/**
+ * Select2 extension for toggling values in a multi-select dropdown
+ */
+(function(Select2) {
+
+ var Select2FindHighlightableChoices = Select2.class.multi.prototype.findHighlightableChoices;
+ Select2.class.multi.prototype.findHighlightableChoices = function () {
+ if (this.opts.toggleSelect) {
+ return this.results.find('.select2-result-selectable:not(.select2-disabled)');
+ }
+ return Select2FindHighlightableChoices.apply(this, arguments);
+ };
+
+ var Select2TriggerSelect = Select2.class.multi.prototype.triggerSelect;
+ Select2.class.multi.prototype.triggerSelect = function (data) {
+ if (this.opts.toggleSelect && this.val().indexOf(this.id(data)) !== -1) {
+ var self = this;
+ var val = this.id(data);
+
+ var selectionEls = this.container.find('.select2-search-choice').filter(function() {
+ return (self.id($(this).data('select2-data')) === val);
+ });
+
+ if (this.unselect(selectionEls)) {
+ // also unselect in dropdown
+ this.results.find('.select2-result.select2-selected').each(function () {
+ var $this = $(this);
+ if (self.id($this.data('select2-data')) === val) {
+ $this.removeClass('select2-selected');
+ }
+ });
+ this.clearSearch();
+ }
+
+ return false;
+ } else {
+ return Select2TriggerSelect.apply(this, arguments);
+ }
+ };
+
+})(Select2);
+
diff --git a/core/js/setupchecks.js b/core/js/setupchecks.js
index 6e2058d54fc..de41b66ec32 100644
--- a/core/js/setupchecks.js
+++ b/core/js/setupchecks.js
@@ -15,7 +15,6 @@
MESSAGE_TYPE_INFO:0,
MESSAGE_TYPE_WARNING:1,
MESSAGE_TYPE_ERROR:2,
-
/**
* Check whether the WebDAV connection works.
*
@@ -47,6 +46,41 @@
},
/**
+ * Check whether the .well-known URLs works.
+ *
+ * @param url the URL to test
+ * @param placeholderUrl the placeholder URL - can be found at oc_defaults.docPlaceholderUrl
+ * @param {boolean} runCheck if this is set to false the check is skipped and no error is returned
+ * @return $.Deferred object resolved with an array of error messages
+ */
+ checkWellKnownUrl: function(url, placeholderUrl, runCheck) {
+ var deferred = $.Deferred();
+
+ if(runCheck === false) {
+ deferred.resolve([]);
+ return deferred.promise();
+ }
+ var afterCall = function(xhr) {
+ var messages = [];
+ if (xhr.status !== 207) {
+ var docUrl = placeholderUrl.replace('PLACEHOLDER', 'admin-setup-well-known-URL');
+ messages.push({
+ msg: t('core', 'Your web server is not set up properly to resolve "{url}". Further information can be found in our <a target="_blank" href="{docLink}">documentation</a>.', { docLink: docUrl, url: url }),
+ type: OC.SetupChecks.MESSAGE_TYPE_INFO
+ });
+ }
+ deferred.resolve(messages);
+ };
+
+ $.ajax({
+ type: 'PROPFIND',
+ url: url,
+ complete: afterCall
+ });
+ return deferred.promise();
+ },
+
+ /**
* Runs setup checks on the server side
*
* @return $.Deferred object resolved with an array of error messages
@@ -62,21 +96,15 @@
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
});
}
- if(!data.dataDirectoryProtected) {
- messages.push({
- msg: t('core', 'Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.'),
- type: OC.SetupChecks.MESSAGE_TYPE_ERROR
- });
- }
if(!data.isMemcacheConfigured) {
messages.push({
- msg: t('core', 'No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href="{docLink}">documentation</a>.', {docLink: data.memcacheDocs}),
+ msg: t('core', 'No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target="_blank" href="{docLink}">documentation</a>.', {docLink: data.memcacheDocs}),
type: OC.SetupChecks.MESSAGE_TYPE_INFO
});
}
if(!data.isUrandomAvailable) {
messages.push({
- msg: t('core', '/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href="{docLink}">documentation</a>.', {docLink: data.securityDocs}),
+ msg: t('core', '/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target="_blank" href="{docLink}">documentation</a>.', {docLink: data.securityDocs}),
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
});
}
@@ -88,22 +116,36 @@
}
if(data.phpSupported && data.phpSupported.eol) {
messages.push({
- msg: t('core', 'Your PHP version ({version}) is no longer <a href="{phpLink}">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP.', {version: data.phpSupported.version, phpLink: 'https://secure.php.net/supported-versions.php'}),
+ msg: t('core', 'Your PHP version ({version}) is no longer <a target="_blank" href="{phpLink}">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP.', {version: data.phpSupported.version, phpLink: 'https://secure.php.net/supported-versions.php'}),
type: OC.SetupChecks.MESSAGE_TYPE_INFO
});
}
if(!data.forwardedForHeadersWorking) {
messages.push({
- msg: t('core', 'The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href="{docLink}">documentation</a>.', {docLink: data.reverseProxyDocs}),
+ msg: t('core', 'The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target="_blank" href="{docLink}">documentation</a>.', {docLink: data.reverseProxyDocs}),
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
});
}
if(!data.isCorrectMemcachedPHPModuleInstalled) {
messages.push({
- msg: t('core', 'Memcached is configured as distributed cache, but the wrong PHP module "memcache" is installed. \\OC\\Memcache\\Memcached only supports "memcached" and not "memcache". See the <a href="{wikiLink}">memcached wiki about both modules</a>.', {wikiLink: 'https://code.google.com/p/memcached/wiki/PHPClientComparison'}),
+ msg: t('core', 'Memcached is configured as distributed cache, but the wrong PHP module "memcache" is installed. \\OC\\Memcache\\Memcached only supports "memcached" and not "memcache". See the <a target="_blank" href="{wikiLink}">memcached wiki about both modules</a>.', {wikiLink: 'https://code.google.com/p/memcached/wiki/PHPClientComparison'}),
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
});
}
+ if(!data.hasPassedCodeIntegrityCheck) {
+ messages.push({
+ msg: t(
+ 'core',
+ 'Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target="_blank" href="{docLink}">documentation</a>. (<a href="{codeIntegrityDownloadEndpoint}">List of invalid files…</a> / <a href="{rescanEndpoint}">Rescan…</a>)',
+ {
+ docLink: data.codeIntegrityCheckerDocumentation,
+ codeIntegrityDownloadEndpoint: OC.generateUrl('/settings/integrity/failed'),
+ rescanEndpoint: OC.generateUrl('/settings/integrity/rescan?requesttoken={requesttoken}', {'requesttoken': OC.requestToken})
+ }
+ ),
+ type: OC.SetupChecks.MESSAGE_TYPE_ERROR
+ });
+ }
} else {
messages.push({
msg: t('core', 'Error occurred while checking server setup'),
@@ -145,6 +187,30 @@
return deferred.promise();
},
+ checkDataProtected: function() {
+ var deferred = $.Deferred();
+ if(oc_dataURL === false){
+ return deferred.resolve([]);
+ }
+ var afterCall = function(xhr) {
+ var messages = [];
+ if (xhr.status !== 403 && xhr.status !== 307 && xhr.status !== 301 && xhr.responseText === '') {
+ messages.push({
+ msg: t('core', 'Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.'),
+ type: OC.SetupChecks.MESSAGE_TYPE_ERROR
+ });
+ }
+ deferred.resolve(messages);
+ };
+
+ $.ajax({
+ type: 'GET',
+ url: OC.linkTo('', oc_dataURL+'/.ocdata'),
+ complete: afterCall
+ });
+ return deferred.promise();
+ },
+
/**
* Runs check for some generic security headers on the server side
*
@@ -159,7 +225,9 @@
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
- 'X-Frame-Options': 'SAMEORIGIN'
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
};
for (var header in securityHeaders) {
diff --git a/core/js/share.js b/core/js/share.js
index e14e19a2543..9baa34d9bb7 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -387,13 +387,6 @@ OC.Share = _.extend(OC.Share || {}, {
}
});
},
- setPermissions:function(itemType, itemSource, shareType, shareWith, permissions) {
- $.post(OC.filePath('core', 'ajax', 'share.php'), { action: 'setPermissions', itemType: itemType, itemSource: itemSource, shareType: shareType, shareWith: shareWith, permissions: permissions }, function(result) {
- if (!result || result.status !== 'success') {
- OC.dialogs.alert(t('core', 'Error while changing permissions'), t('core', 'Error'));
- }
- });
- },
showDropDown:function(itemType, itemSource, appendTo, link, possiblePermissions, filename) {
var configModel = new OC.Share.ShareConfigModel();
var attributes = {itemType: itemType, itemSource: itemSource, possiblePermissions: possiblePermissions};
diff --git a/core/js/shareconfigmodel.js b/core/js/shareconfigmodel.js
index 8729698d136..5494feaf7fa 100644
--- a/core/js/shareconfigmodel.js
+++ b/core/js/shareconfigmodel.js
@@ -8,6 +8,8 @@
*
*/
+/* global moment */
+
(function() {
if (!OC.Share) {
OC.Share = {};
@@ -52,6 +54,13 @@
/**
* @returns {boolean}
*/
+ isMailNotificationEnabled: function() {
+ return $('input:hidden[name=mailNotificationEnabled]').val() === 'yes';
+ },
+
+ /**
+ * @returns {boolean}
+ */
isShareWithLinkAllowed: function() {
return $('#allowShareWithLink').val() === 'yes';
},
@@ -66,13 +75,10 @@
getDefaultExpirationDateString: function () {
var expireDateString = '';
if (this.get('isDefaultExpireDateEnabled')) {
- var date = new Date().getTime();
- var expireAfterMs = this.get('defaultExpireDate') * 24 * 60 * 60 * 1000;
- var expireDate = new Date(date + expireAfterMs);
- var month = expireDate.getMonth() + 1;
- var year = expireDate.getFullYear();
- var day = expireDate.getDate();
- expireDateString = year + "-" + month + '-' + day + ' 00:00:00';
+ var date = moment.utc();
+ var expireAfterDays = this.get('defaultExpireDate');
+ date.add(expireAfterDays, 'days');
+ expireDateString = date.format('YYYY-MM-DD 00:00:00');
}
return expireDateString;
}
diff --git a/core/js/sharedialogexpirationview.js b/core/js/sharedialogexpirationview.js
index eef440c9af5..fa5c0c00986 100644
--- a/core/js/sharedialogexpirationview.js
+++ b/core/js/sharedialogexpirationview.js
@@ -93,8 +93,9 @@
this.$el.find('.expirationDateContainer').toggleClass('hidden', !state);
if (!state) {
// discard expiration date
- this.model.setExpirationDate('');
- this.model.saveLinkShare();
+ this.model.saveLinkShare({
+ expireDate: ''
+ });
}
},
@@ -103,8 +104,9 @@
$target.tooltip('hide');
$target.removeClass('error');
- this.model.setExpirationDate($target.val());
- this.model.saveLinkShare(null, {
+ this.model.saveLinkShare({
+ expiration: moment($target.val(), 'DD-MM-YYYY').format('YYYY-MM-DD')
+ }, {
error: function(model, message) {
if (!message) {
$target.attr('title', t('core', 'Error setting expiration date'));
diff --git a/core/js/sharedialoglinkshareview.js b/core/js/sharedialoglinkshareview.js
index 29dce21486c..efae618ba99 100644
--- a/core/js/sharedialoglinkshareview.js
+++ b/core/js/sharedialoglinkshareview.js
@@ -48,7 +48,7 @@
' {{/if}}' +
'{{else}}' +
// FIXME: this doesn't belong in this view
- '<input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{noSharingPlaceholder}}" disabled="disabled"/>' +
+ '{{#if noSharingPlaceholder}}<input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{noSharingPlaceholder}}" disabled="disabled"/>{{/if}}' +
'{{/if}}'
;
@@ -157,8 +157,9 @@
onShowPasswordClick: function() {
this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
if(!this.$el.find('.showPasswordCheckbox').is(':checked')) {
- this.model.setPassword('');
- this.model.saveLinkShare();
+ this.model.saveLinkShare({
+ password: ''
+ });
} else {
this.$el.find('.linkPassText').focus();
}
@@ -171,7 +172,6 @@
},
onPasswordEntered: function() {
- var self = this;
var $loading = this.$el.find('.linkPass .icon-loading-small');
if (!$loading.hasClass('hidden')) {
// still in process
@@ -189,8 +189,9 @@
.removeClass('hidden')
.addClass('inlineblock');
- this.model.setPassword(password);
- this.model.saveLinkShare({}, {
+ this.model.saveLinkShare({
+ password: password
+ }, {
error: function(model, msg) {
$loading.removeClass('inlineblock').addClass('hidden');
$input.addClass('error');
@@ -204,8 +205,15 @@
onAllowPublicUploadChange: function() {
var $checkbox = this.$('.publicUploadCheckbox');
$checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock');
- this.model.setPublicUpload($checkbox.is(':checked'));
- this.model.saveLinkShare();
+
+ var permissions = OC.PERMISSION_READ;
+ if($checkbox.is(':checked')) {
+ permissions = OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ;
+ }
+
+ this.model.saveLinkShare({
+ permissions: permissions
+ });
},
_onEmailPrivateLink: function(event) {
@@ -238,15 +246,18 @@
render: function() {
var linkShareTemplate = this.template();
+ var resharingAllowed = this.model.sharePermissionPossible();
- if( !this.model.sharePermissionPossible()
+ if(!resharingAllowed
|| !this.showLink
|| !this.configModel.isShareWithLinkAllowed())
{
- this.$el.html(linkShareTemplate({
- shareAllowed: false,
- noSharingPlaceholder: t('core', 'Resharing is not allowed')
- }));
+ var templateData = {shareAllowed: false};
+ if (!resharingAllowed) {
+ // add message
+ templateData.noSharingPlaceholder = t('core', 'Resharing is not allowed');
+ }
+ this.$el.html(linkShareTemplate(templateData));
return this;
}
diff --git a/core/js/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js
index dfe5789e774..e26421dcaed 100644
--- a/core/js/sharedialogshareelistview.js
+++ b/core/js/sharedialogshareelistview.js
@@ -16,17 +16,13 @@
var TEMPLATE =
'<ul id="shareWithList" class="shareWithList">' +
'{{#each sharees}}' +
- ' {{#if isCollection}}' +
- ' <li data-collection="{{collectionID}}">{{text}}</li>' +
- ' {{/if}}' +
- ' {{#unless isCollection}}' +
- ' <li data-share-type="{{shareType}}" data-share-with="{{shareWith}}" title="{{shareWith}}">' +
+ ' <li data-share-id="{{shareId}}" data-share-type="{{shareType}}" data-share-with="{{shareWith}}" title="{{shareWith}}">' +
' <a href="#" class="unshare"><span class="icon-loading-small hidden"></span><img class="svg" alt="{{unshareLabel}}" title="{{unshareLabel}}" src="{{unshareImage}}" /></a>' +
' {{#if avatarEnabled}}' +
' <div class="avatar {{#if modSeed}}imageplaceholderseed{{/if}}" data-username="{{shareWith}}" {{#if modSeed}}data-seed="{{shareWith}} {{shareType}}"{{/if}}></div>' +
' {{/if}}' +
' <span class="username">{{shareWithDisplayName}}</span>' +
- ' {{#if mailPublicNotificationEnabled}} {{#unless isRemoteShare}}' +
+ ' {{#if mailNotificationEnabled}} {{#unless isRemoteShare}}' +
' <input id="mail-{{cid}}-{{shareWith}}" type="checkbox" name="mailNotification" class="mailNotification checkbox" {{#if wasMailSent}}checked="checked"{{/if}} />' +
' <label for="mail-{{cid}}-{{shareWith}}">{{notifyByMailLabel}}</label>' +
' {{/unless}} {{/if}}' +
@@ -56,7 +52,6 @@
' </div>' +
' {{/unless}}' +
' </li>' +
- ' {{/unless}}' +
'{{/each}}' +
'</ul>'
;
@@ -81,12 +76,6 @@
/** @type {Function} **/
_template: undefined,
- /** @type {boolean} **/
- showLink: true,
-
- /** @type {object} **/
- _collections: {},
-
events: {
'click .unshare': 'onUnshare',
'click .permissions': 'onPermissionChange',
@@ -107,23 +96,6 @@
});
},
- processCollectionShare: function(shareIndex) {
- var type = this.model.getCollectionType(shareIndex);
- var id = this.model.getCollectionPath(shareIndex);
- if(type !== 'file' && type !== 'folder') {
- id = this.model.getCollectionSource(shareIndex);
- }
- var displayName = this.model.getShareWithDisplayName(shareIndex);
- if(!_.isUndefined(this._collections[id])) {
- this._collections[id].text = this._collections[id].text + ", " + displayName;
- } else {
- this._collections[id] = {};
- this._collections[id].text = t('core', 'Shared in {item} with {user}', {'item': id, user: displayName});
- this._collections[id].id = id;
- this._collections[id].isCollection = true;
- }
- },
-
/**
*
* @param {OC.Share.Types.ShareInfo} shareInfo
@@ -156,6 +128,7 @@
shareWith: shareWith,
shareWithDisplayName: shareWithDisplayName,
shareType: shareType,
+ shareId: this.model.get('shares')[shareIndex].id,
modSeed: shareType !== OC.Share.SHARE_TYPE_USER,
isRemoteShare: shareType === OC.Share.SHARE_TYPE_REMOTE
});
@@ -164,7 +137,7 @@
getShareeList: function() {
var universal = {
avatarEnabled: this.configModel.areAvatarsEnabled(),
- mailPublicNotificationEnabled: this.configModel.isMailPublicNotificationEnabled(),
+ mailNotificationEnabled: this.configModel.isMailNotificationEnabled(),
notifyByMailLabel: t('core', 'notify by email'),
unshareLabel: t('core', 'Unshare'),
unshareImage: OC.imagePath('core', 'actions/delete'),
@@ -187,8 +160,6 @@
deletePermission: OC.PERMISSION_DELETE
};
- this._collections = {};
-
if(!this.model.hasUserShares()) {
return [];
}
@@ -196,15 +167,10 @@
var shares = this.model.get('shares');
var list = [];
for(var index = 0; index < shares.length; index++) {
- if(this.model.isCollection(index)) {
- this.processCollectionShare(index);
- } else {
- // first empty {} is necessary, otherwise we get in trouble
- // with references
- list.push(_.extend({}, universal, this.getShareeObject(index)));
- }
+ // first empty {} is necessary, otherwise we get in trouble
+ // with references
+ list.push(_.extend({}, universal, this.getShareeObject(index)));
}
- list = _.union(_.values(this._collections), list);
return list;
},
@@ -244,28 +210,38 @@
},
onUnshare: function(event) {
+ var self = this;
var $element = $(event.target);
- console.log($element);
+ if (!$element.is('a')) {
+ $element = $element.closest('a');
+ }
- var $loading = $element.siblings('.icon-loading-small').eq(0);
+ var $loading = $element.find('.icon-loading-small').eq(0);
if(!$loading.hasClass('hidden')) {
// in process
- return;
+ return false;
}
$loading.removeClass('hidden');
var $li = $element.closest('li');
- var shareType = $li.data('share-type');
- var shareWith = $li.attr('data-share-with');
- this.model.removeShare(shareType, shareWith);
+ var shareId = $li.data('share-id');
+ self.model.removeShare(shareId)
+ .done(function() {
+ $li.remove();
+ })
+ .fail(function() {
+ $loading.addClass('hidden');
+ OC.Notification.showTemporary(t('core', 'Could not unshare'));
+ });
return false;
},
onPermissionChange: function(event) {
var $element = $(event.target);
var $li = $element.closest('li');
+ var shareId = $li.data('share-id');
var shareType = $li.data('share-type');
var shareWith = $li.attr('data-share-with');
@@ -287,7 +263,7 @@
permissions |= $(checkbox).data('permissions');
});
- this.model.setPermissions(shareType, shareWith, permissions);
+ this.model.updateShare(shareId, {permissions: permissions});
},
onCrudsToggle: function(event) {
diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js
index dd07adceac4..4cebf7962e8 100644
--- a/core/js/sharedialogview.js
+++ b/core/js/sharedialogview.js
@@ -117,22 +117,95 @@
var $loading = this.$el.find('.shareWithLoading');
$loading.removeClass('hidden');
$loading.addClass('inlineblock');
- $.get(OC.filePath('core', 'ajax', 'share.php'), {
- fetch: 'getShareWith',
- search: search.term.trim(),
- limit: 200,
- itemShares: OC.Share.itemShares,
- itemType: view.model.get('itemType')
- }, function (result) {
- $loading.addClass('hidden');
- $loading.removeClass('inlineblock');
- if (result.status == 'success' && result.data.length > 0) {
- $('.shareWithField').autocomplete("option", "autoFocus", true);
- response(result.data);
- } else {
- response();
+ $.get(
+ OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees',
+ {
+ format: 'json',
+ search: search.term.trim(),
+ perPage: 200,
+ itemType: view.model.get('itemType')
+ },
+ function (result) {
+ $loading.addClass('hidden');
+ $loading.removeClass('inlineblock');
+ if (result.ocs.meta.statuscode == 100) {
+ var users = result.ocs.data.exact.users.concat(result.ocs.data.users);
+ var groups = result.ocs.data.exact.groups.concat(result.ocs.data.groups);
+ var remotes = result.ocs.data.exact.remotes.concat(result.ocs.data.remotes);
+
+ var usersLength;
+ var groupsLength;
+ var remotesLength;
+
+ var i, j;
+
+ //Filter out the current user
+ usersLength = users.length;
+ for (i = 0 ; i < usersLength; i++) {
+ if (users[i].value.shareWith === OC.currentUser) {
+ users.splice(i, 1);
+ break;
+ }
+ }
+
+ // Filter out the owner of the share
+ if (view.model.hasReshare()) {
+ usersLength = users.length;
+ for (i = 0 ; i < usersLength; i++) {
+ if (users[i].value.shareWith === view.model.getReshareOwner()) {
+ users.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ var shares = view.model.get('shares');
+ var sharesLength = shares.length;
+
+ // Now filter out all sharees that are already shared with
+ for (i = 0; i < sharesLength; i++) {
+ var share = shares[i];
+
+ if (share.share_type === OC.Share.SHARE_TYPE_USER) {
+ usersLength = users.length;
+ for (j = 0; j < usersLength; j++) {
+ if (users[j].value.shareWith === share.share_with) {
+ users.splice(j, 1);
+ break;
+ }
+ }
+ } else if (share.share_type === OC.Share.SHARE_TYPE_GROUP) {
+ groupsLength = groups.length;
+ for (j = 0; j < groupsLength; j++) {
+ if (groups[j].value.shareWith === share.share_with) {
+ groups.splice(j, 1);
+ break;
+ }
+ }
+ } else if (share.share_type === OC.Share.SHARE_TYPE_REMOTE) {
+ remotesLength = remotes.length;
+ for (j = 0; j < remotesLength; j++) {
+ if (remotes[j].value.shareWith === share.share_with) {
+ remotes.splice(j, 1);
+ break;
+ }
+ }
+ }
+ }
+
+ var suggestions = users.concat(groups).concat(remotes);
+
+ if (suggestions.length > 0) {
+ $('.shareWithField').autocomplete("option", "autoFocus", true);
+ response(suggestions);
+ } else {
+ response();
+ }
+ } else {
+ response();
+ }
}
- }).fail(function () {
+ ).fail(function() {
$loading.addClass('hidden');
$loading.removeClass('inlineblock');
OC.Notification.show(t('core', 'An error occured. Please try again'));
diff --git a/core/js/shareitemmodel.js b/core/js/shareitemmodel.js
index ae3cb0ce2e3..a7764dd6266 100644
--- a/core/js/shareitemmodel.js
+++ b/core/js/shareitemmodel.js
@@ -26,13 +26,6 @@
*/
/**
- * @typedef {object} OC.Share.Types.Collection
- * @property {string} item_type
- * @property {string} path
- * @property {string} item_source TODO: verify
- */
-
- /**
* @typedef {object} OC.Share.Types.Reshare
* @property {string} uid_owner
* @property {number} share_type
@@ -51,7 +44,6 @@
* @property {string} share_with
* @property {string} share_with_displayname
* @property {string} mail_send
- * @property {OC.Share.Types.Collection|undefined} collection
* @property {Date} expiration optional?
* @property {number} stime optional?
*/
@@ -84,6 +76,11 @@
* where the link share is one of them
*/
var ShareItemModel = OC.Backbone.Model.extend({
+ /**
+ * @type share id of the link share, if applicable
+ */
+ _linkShareId: null,
+
initialize: function(attributes, options) {
if(!_.isUndefined(options.configModel)) {
this.configModel = options.configModel;
@@ -110,118 +107,48 @@
* TODO: this should be a separate model
*/
saveLinkShare: function(attributes, options) {
- var model = this;
- var itemType = this.get('itemType');
- var itemSource = this.get('itemSource');
-
- // TODO: use backbone's default value mechanism once this is a separate model
- var requiredAttributes = [
- { name: 'password', defaultValue: '' },
- { name: 'passwordChanged', defaultValue: false },
- { name: 'permissions', defaultValue: OC.PERMISSION_READ },
- { name: 'expiration', defaultValue: this.configModel.getDefaultExpirationDateString() }
- ];
-
- attributes = attributes || {};
-
- // get attributes from the model and fill in with default values
- _.each(requiredAttributes, function(attribute) {
- // a provided options overrides a present value of the link
- // share. If neither is given, the default value is used.
- if(_.isUndefined(attribute[attribute.name])) {
- attributes[attribute.name] = attribute.defaultValue;
- var currentValue = model.get('linkShare')[attribute.name];
- if(!_.isUndefined(currentValue)) {
- attributes[attribute.name] = currentValue;
- }
- }
- });
+ options = options || {};
+ attributes = _.extend({}, attributes);
- var password = {
- password: attributes.password,
- passwordChanged: attributes.passwordChanged
- };
+ var shareId = null;
+ var call;
- OC.Share.share(
- itemType,
- itemSource,
- OC.Share.SHARE_TYPE_LINK,
- password,
- attributes.permissions,
- this.fileInfoModel.get('name'),
- attributes.expiration,
- function(result) {
- if (!result || result.status !== 'success') {
- model.fetch({
- success: function() {
- if (options && _.isFunction(options.success)) {
- options.success(model);
- }
- }
- });
- } else {
- if (options && _.isFunction(options.error)) {
- options.error(model);
- }
- }
- },
- function(result) {
- var msg = t('core', 'Error');
- if (result.data && result.data.message) {
- msg = result.data.message;
- }
+ // oh yeah...
+ if (attributes.expiration) {
+ attributes.expireDate = attributes.expiration;
+ delete attributes.expiration;
+ }
- if (options && _.isFunction(options.error)) {
- options.error(model, msg);
- } else {
- OC.dialogs.alert(msg, t('core', 'Error while sharing'));
- }
- }
- );
- },
+ if (this.get('linkShare') && this.get('linkShare').isLinkShare) {
+ shareId = this.get('linkShare').id;
- removeLinkShare: function() {
- this.removeShare(OC.Share.SHARE_TYPE_LINK, '');
- },
+ // note: update can only update a single value at a time
+ call = this.updateShare(shareId, attributes, options);
+ } else {
+ attributes = _.defaults(attributes, {
+ password: '',
+ passwordChanged: false,
+ permissions: OC.PERMISSION_READ,
+ expireDate: this.configModel.getDefaultExpirationDateString(),
+ shareType: OC.Share.SHARE_TYPE_LINK
+ });
- /**
- * Sets the public upload flag
- *
- * @param {bool} allow whether public upload is allowed
- */
- setPublicUpload: function(allow) {
- var permissions = OC.PERMISSION_READ;
- if(allow) {
- permissions = OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ;
+ call = this.addShare(attributes, options);
}
- this.get('linkShare').permissions = permissions;
+ return call;
},
- /**
- * Sets the expiration date of the public link
- *
- * @param {string} expiration expiration date
- */
- setExpirationDate: function(expiration) {
- this.get('linkShare').expiration = expiration;
- },
-
- /**
- * Set password of the public link share
- *
- * @param {string} password
- */
- setPassword: function(password) {
- this.get('linkShare').password = password;
- this.get('linkShare').passwordChanged = true;
+ removeLinkShare: function() {
+ if (this.get('linkShare')) {
+ return this.removeShare(this.get('linkShare').id);
+ }
},
addShare: function(attributes, options) {
var shareType = attributes.shareType;
- var shareWith = attributes.shareWith;
- var fileName = this.fileInfoModel.get('name');
options = options || {};
+ attributes = _.extend({}, attributes);
// Default permissions are Edit (CRUD) and Share
// Check if these permissions are possible
@@ -243,29 +170,103 @@
}
}
- var model = this;
- var itemType = this.get('itemType');
- var itemSource = this.get('itemSource');
- OC.Share.share(itemType, itemSource, shareType, shareWith, permissions, fileName, options.expiration, function() {
- model.fetch();
+ attributes.permissions = permissions;
+ if (_.isUndefined(attributes.path)) {
+ attributes.path = this.fileInfoModel.getFullPath();
+ }
+
+ var self = this;
+ return $.ajax({
+ type: 'POST',
+ url: this._getUrl('shares'),
+ data: attributes,
+ dataType: 'json'
+ }).done(function() {
+ self.fetch({
+ success: function() {
+ if (_.isFunction(options.success)) {
+ options.success(self);
+ }
+ }
+ });
+ }).fail(function(xhr) {
+ var msg = t('core', 'Error');
+ var result = xhr.responseJSON;
+ if (result.ocs && result.ocs.meta) {
+ msg = result.ocs.meta.message;
+ }
+
+ if (_.isFunction(options.error)) {
+ options.error(self, msg);
+ } else {
+ OC.dialogs.alert(msg, t('core', 'Error while sharing'));
+ }
});
},
- setPermissions: function(shareType, shareWith, permissions) {
- var itemType = this.get('itemType');
- var itemSource = this.get('itemSource');
+ updateShare: function(shareId, attrs, options) {
+ var self = this;
+ options = options || {};
+ return $.ajax({
+ type: 'PUT',
+ url: this._getUrl('shares/' + encodeURIComponent(shareId)),
+ data: attrs,
+ dataType: 'json'
+ }).done(function() {
+ self.fetch({
+ success: function() {
+ if (_.isFunction(options.success)) {
+ options.success(self);
+ }
+ }
+ });
+ }).fail(function(xhr) {
+ var msg = t('core', 'Error');
+ var result = xhr.responseJSON;
+ if (result.ocs && result.ocs.meta) {
+ msg = result.ocs.meta.message;
+ }
- // TODO: in the future, only set the permissions on the model but don't save directly
- OC.Share.setPermissions(itemType, itemSource, shareType, shareWith, permissions);
+ if (_.isFunction(options.error)) {
+ options.error(self, msg);
+ } else {
+ OC.dialogs.alert(msg, t('core', 'Error while sharing'));
+ }
+ });
},
- removeShare: function(shareType, shareWith) {
- var model = this;
- var itemType = this.get('itemType');
- var itemSource = this.get('itemSource');
+ /**
+ * Deletes the share with the given id
+ *
+ * @param {int} shareId share id
+ * @return {jQuery}
+ */
+ removeShare: function(shareId, options) {
+ var self = this;
+ options = options || {};
+ return $.ajax({
+ type: 'DELETE',
+ url: this._getUrl('shares/' + encodeURIComponent(shareId)),
+ }).done(function() {
+ self.fetch({
+ success: function() {
+ if (_.isFunction(options.success)) {
+ options.success(self);
+ }
+ }
+ });
+ }).fail(function(xhr) {
+ var msg = t('core', 'Error');
+ var result = xhr.responseJSON;
+ if (result.ocs && result.ocs.meta) {
+ msg = result.ocs.meta.message;
+ }
- OC.Share.unshare(itemType, itemSource, shareType, shareWith, function() {
- model.fetch();
+ if (_.isFunction(options.error)) {
+ options.error(self, msg);
+ } else {
+ OC.dialogs.alert(msg, t('core', 'Error removing share'));
+ }
});
},
@@ -321,71 +322,6 @@
},
/**
- * @param {number} shareIndex
- * @returns {string}
- */
- getCollectionType: function(shareIndex) {
- /** @type OC.Share.Types.ShareInfo **/
- var share = this.get('shares')[shareIndex];
- if(!_.isObject(share)) {
- throw "Unknown Share";
- } else if(_.isUndefined(share.collection)) {
- throw "Share is not a collection";
- }
-
- return share.collection.item_type;
- },
-
- /**
- * @param {number} shareIndex
- * @returns {string}
- */
- getCollectionPath: function(shareIndex) {
- /** @type OC.Share.Types.ShareInfo **/
- var share = this.get('shares')[shareIndex];
- if(!_.isObject(share)) {
- throw "Unknown Share";
- } else if(_.isUndefined(share.collection)) {
- throw "Share is not a collection";
- }
-
- return share.collection.path;
- },
-
- /**
- * @param {number} shareIndex
- * @returns {string}
- */
- getCollectionSource: function(shareIndex) {
- /** @type OC.Share.Types.ShareInfo **/
- var share = this.get('shares')[shareIndex];
- if(!_.isObject(share)) {
- throw "Unknown Share";
- } else if(_.isUndefined(share.collection)) {
- throw "Share is not a collection";
- }
-
- return share.collection.item_source;
- },
-
- /**
- * @param {number} shareIndex
- * @returns {boolean}
- */
- isCollection: function(shareIndex) {
- /** @type OC.Share.Types.ShareInfo **/
- var share = this.get('shares')[shareIndex];
- if(!_.isObject(share)) {
- throw "Unknown Share";
- }
- if(_.isUndefined(share.collection)) {
- return false;
- }
- return true;
- },
-
-
- /**
* @returns {string}
*/
getReshareOwner: function() {
@@ -635,13 +571,64 @@
|| this.hasDeletePermission(shareIndex);
},
+ _getUrl: function(base, params) {
+ params = _.extend({format: 'json'}, params || {});
+ return OC.linkToOCS('apps/files_sharing/api/v1', 2) + base + '?' + OC.buildQueryString(params);
+ },
+
+ _fetchShares: function() {
+ var path = this.fileInfoModel.getFullPath();
+ return $.ajax({
+ type: 'GET',
+ url: this._getUrl('shares', {path: path, reshares: true})
+ });
+ },
+
+ _fetchReshare: function() {
+ // only fetch original share once
+ if (!this._reshareFetched) {
+ var path = this.fileInfoModel.getFullPath();
+ this._reshareFetched = true;
+ return $.ajax({
+ type: 'GET',
+ url: this._getUrl('shares', {path: path, shared_with_me: true})
+ });
+ } else {
+ return $.Deferred().resolve([{
+ ocs: {
+ data: [this.get('reshare')]
+ }
+ }]);
+ }
+ },
+
fetch: function() {
var model = this;
this.trigger('request', this);
- OC.Share.loadItem(this.get('itemType'), this.get('itemSource'), function(data) {
+
+ var deferred = $.when(
+ this._fetchShares(),
+ this._fetchReshare()
+ );
+ deferred.done(function(data1, data2) {
model.trigger('sync', 'GET', this);
- model.set(model.parse(data));
+ var sharesMap = {};
+ _.each(data1[0].ocs.data, function(shareItem) {
+ sharesMap[shareItem.id] = shareItem;
+ });
+
+ var reshare = false;
+ if (data2[0].ocs.data.length) {
+ reshare = data2[0].ocs.data[0];
+ }
+
+ model.set(model.parse({
+ shares: sharesMap,
+ reshare: reshare
+ }));
});
+
+ return deferred;
},
/**
@@ -690,7 +677,7 @@
parse: function(data) {
if(data === false) {
console.warn('no data was returned');
- trigger('fetchError');
+ this.trigger('fetchError');
return {};
}
@@ -752,6 +739,7 @@
}
linkShare = {
isLinkShare: true,
+ id: share.id,
token: share.token,
password: share.share_with,
link: link,
diff --git a/core/js/systemtags/systemtagmodel.js b/core/js/systemtags/systemtagmodel.js
new file mode 100644
index 00000000000..b41fbdde61e
--- /dev/null
+++ b/core/js/systemtags/systemtagmodel.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC) {
+ var NS_OWNCLOUD = 'http://owncloud.org/ns';
+ /**
+ * @class OCA.SystemTags.SystemTagsCollection
+ * @classdesc
+ *
+ * System tag
+ *
+ */
+ var SystemTagModel = OC.Backbone.Model.extend(
+ /** @lends OCA.SystemTags.SystemTagModel.prototype */ {
+ sync: OC.Backbone.davSync,
+
+ defaults: {
+ userVisible: true,
+ userAssignable: true
+ },
+
+ davProperties: {
+ 'id': '{' + NS_OWNCLOUD + '}id',
+ 'name': '{' + NS_OWNCLOUD + '}display-name',
+ 'userVisible': '{' + NS_OWNCLOUD + '}user-visible',
+ 'userAssignable': '{' + NS_OWNCLOUD + '}user-assignable'
+ },
+
+ parse: function(data) {
+ return {
+ id: data.id,
+ name: data.name,
+ userVisible: data.userVisible === true || data.userVisible === 'true',
+ userAssignable: data.userAssignable === true || data.userAssignable === 'true'
+ };
+ }
+ });
+
+ OC.SystemTags = OC.SystemTags || {};
+ OC.SystemTags.SystemTagModel = SystemTagModel;
+})(OC);
+
diff --git a/core/js/systemtags/systemtags.js b/core/js/systemtags/systemtags.js
new file mode 100644
index 00000000000..042f49bb8ed
--- /dev/null
+++ b/core/js/systemtags/systemtags.js
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC) {
+ /**
+ * @namespace
+ */
+ OC.SystemTags = {
+ /**
+ *
+ * @param {OC.SystemTags.SystemTagModel|Object|String} tag
+ * @return {jQuery}
+ */
+ getDescriptiveTag: function(tag) {
+ if (_.isUndefined(tag.name) && !_.isUndefined(tag.toJSON)) {
+ tag = tag.toJSON();
+ }
+
+ if (_.isUndefined(tag.name)) {
+ return $('<span>').addClass('non-existing-tag').text(
+ t('core', 'Non-existing tag #{tag}', {
+ tag: tag
+ })
+ );
+ }
+
+ var $span = $('<span>');
+ $span.append(escapeHTML(tag.name));
+
+ var scope;
+ if (!tag.userAssignable) {
+ scope = t('core', 'not assignable');
+ }
+ if (!tag.userVisible) {
+ // invisible also implicitly means not assignable
+ scope = t('core', 'invisible');
+ }
+ if (scope) {
+ var $tag = $('<em>').text(' ' +
+ t('core', '({scope})', {
+ scope: scope
+ })
+ );
+ $span.append($tag);
+ }
+ return $span;
+ }
+ };
+})(OC);
+
diff --git a/core/js/systemtags/systemtagscollection.js b/core/js/systemtags/systemtagscollection.js
new file mode 100644
index 00000000000..0f8a7aa980e
--- /dev/null
+++ b/core/js/systemtags/systemtagscollection.js
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC) {
+
+ function filterFunction(model, term) {
+ return model.get('name').substr(0, term.length) === term;
+ }
+
+ /**
+ * @class OCA.SystemTags.SystemTagsCollection
+ * @classdesc
+ *
+ * Collection of tags assigned to a file
+ *
+ */
+ var SystemTagsCollection = OC.Backbone.Collection.extend(
+ /** @lends OC.SystemTags.SystemTagsCollection.prototype */ {
+
+ sync: OC.Backbone.davSync,
+
+ model: OC.SystemTags.SystemTagModel,
+
+ url: function() {
+ return OC.linkToRemote('dav') + '/systemtags/';
+ },
+
+ filterByName: function(name) {
+ return this.filter(function(model) {
+ return filterFunction(model, name);
+ });
+ },
+
+ reset: function() {
+ this.fetched = false;
+ return OC.Backbone.Collection.prototype.reset.apply(this, arguments);
+ },
+
+ /**
+ * Lazy fetch.
+ * Only fetches once, subsequent calls will directly call the success handler.
+ *
+ * @param options
+ * @param [options.force] true to force fetch even if cached entries exist
+ *
+ * @see Backbone.Collection#fetch
+ */
+ fetch: function(options) {
+ var self = this;
+ options = options || {};
+ if (this.fetched || options.force) {
+ // directly call handler
+ if (options.success) {
+ options.success(this, null, options);
+ }
+ // trigger sync event
+ this.trigger('sync', this, null, options);
+ return Promise.resolve();
+ }
+
+ var success = options.success;
+ options = _.extend({}, options);
+ options.success = function() {
+ self.fetched = true;
+ if (success) {
+ return success.apply(this, arguments);
+ }
+ };
+
+ return OC.Backbone.Collection.prototype.fetch.call(this, options);
+ }
+ });
+
+ OC.SystemTags = OC.SystemTags || {};
+ OC.SystemTags.SystemTagsCollection = SystemTagsCollection;
+
+ /**
+ * @type OC.SystemTags.SystemTagsCollection
+ */
+ OC.SystemTags.collection = new OC.SystemTags.SystemTagsCollection();
+})(OC);
+
diff --git a/core/js/systemtags/systemtagsinputfield.js b/core/js/systemtags/systemtagsinputfield.js
new file mode 100644
index 00000000000..48fc98c6188
--- /dev/null
+++ b/core/js/systemtags/systemtagsinputfield.js
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+/* global Handlebars */
+
+(function(OC) {
+ var TEMPLATE =
+ '<input class="systemTagsInputField" type="hidden" name="tags" value=""/>';
+
+ var RESULT_TEMPLATE =
+ '<span class="systemtags-item{{#if isNew}} new-item{{/if}}" data-id="{{id}}">' +
+ ' <span class="checkmark icon icon-checkmark"></span>' +
+ '{{#if isAdmin}}' +
+ ' <span class="label">{{{tagMarkup}}}</span>' +
+ '{{else}}' +
+ ' <span class="label">{{name}}</span>' +
+ '{{/if}}' +
+ '{{#allowActions}}' +
+ ' <span class="systemtags-actions">' +
+ ' <a href="#" class="rename icon icon-rename" title="{{renameTooltip}}"></a>' +
+ ' </span>' +
+ '{{/allowActions}}' +
+ '</span>';
+
+ var SELECTION_TEMPLATE =
+ '{{#if isAdmin}}' +
+ ' <span class="label">{{{tagMarkup}}}</span>' +
+ '{{else}}' +
+ ' <span class="label">{{name}}</span>' +
+ '{{/if}}';
+
+ var RENAME_FORM_TEMPLATE =
+ '<form class="systemtags-rename-form">' +
+ ' <label class="hidden-visually" for="{{cid}}-rename-input">{{renameLabel}}</label>' +
+ ' <input id="{{cid}}-rename-input" type="text" value="{{name}}">' +
+ ' <a href="#" class="delete icon icon-delete" title="{{deleteTooltip}}"></a>' +
+ '</form>';
+
+ /**
+ * @class OC.SystemTags.SystemTagsInputField
+ * @classdesc
+ *
+ * Displays a file's system tags
+ *
+ */
+ var SystemTagsInputField = OC.Backbone.View.extend(
+ /** @lends OC.SystemTags.SystemTagsInputField.prototype */ {
+
+ _rendered: false,
+
+ _newTag: null,
+
+ className: 'systemTagsInputFieldContainer',
+
+ template: function(data) {
+ if (!this._template) {
+ this._template = Handlebars.compile(TEMPLATE);
+ }
+ return this._template(data);
+ },
+
+ /**
+ * Creates a new SystemTagsInputField
+ *
+ * @param {Object} [options]
+ * @param {string} [options.objectType=files] object type for which tags are assigned to
+ * @param {bool} [options.multiple=false] whether to allow selecting multiple tags
+ * @param {bool} [options.allowActions=true] whether tags can be renamed/delete within the dropdown
+ * @param {bool} [options.allowCreate=true] whether new tags can be created
+ * @param {bool} [options.isAdmin=true] whether the user is an administrator
+ * @param {Function} options.initSelection function to convert selection to data
+ */
+ initialize: function(options) {
+ options = options || {};
+
+ this._multiple = !!options.multiple;
+ this._allowActions = _.isUndefined(options.allowActions) || !!options.allowActions;
+ this._allowCreate = _.isUndefined(options.allowCreate) || !!options.allowCreate;
+ this._isAdmin = !!options.isAdmin;
+
+ if (_.isFunction(options.initSelection)) {
+ this._initSelection = options.initSelection;
+ }
+
+ this.collection = options.collection || OC.SystemTags.collection;
+
+ var self = this;
+ this.collection.on('change:name remove', function() {
+ // refresh selection
+ _.defer(self._refreshSelection);
+ });
+
+ _.bindAll(
+ this,
+ '_refreshSelection',
+ '_onClickRenameTag',
+ '_onClickDeleteTag',
+ '_onSelectTag',
+ '_onDeselectTag',
+ '_onSubmitRenameTag'
+ );
+ },
+
+ /**
+ * Refreshes the selection, triggering a call to
+ * select2's initSelection
+ */
+ _refreshSelection: function() {
+ this.$tagsField.select2('val', this.$tagsField.val());
+ },
+
+ /**
+ * Event handler whenever the user clicked the "rename" action.
+ * This will display the rename field.
+ */
+ _onClickRenameTag: function(ev) {
+ var $item = $(ev.target).closest('.systemtags-item');
+ var tagId = $item.attr('data-id');
+ var tagModel = this.collection.get(tagId);
+ if (!this._renameFormTemplate) {
+ this._renameFormTemplate = Handlebars.compile(RENAME_FORM_TEMPLATE);
+ }
+
+ var oldName = tagModel.get('name');
+ var $renameForm = $(this._renameFormTemplate({
+ cid: this.cid,
+ name: oldName,
+ deleteTooltip: t('core', 'Delete'),
+ renameLabel: t('core', 'Rename')
+ }));
+ $item.find('.label').after($renameForm);
+ $item.find('.label, .systemtags-actions').addClass('hidden');
+ $item.closest('.select2-result').addClass('has-form');
+
+ $renameForm.find('[title]').tooltip({
+ placement: 'bottom',
+ container: 'body'
+ });
+ $renameForm.find('input').focus().selectRange(0, oldName.length);
+ return false;
+ },
+
+ /**
+ * Event handler whenever the rename form has been submitted after
+ * the user entered a new tag name.
+ * This will submit the change to the server.
+ *
+ * @param {Object} ev event
+ */
+ _onSubmitRenameTag: function(ev) {
+ ev.preventDefault();
+ var $form = $(ev.target);
+ var $item = $form.closest('.systemtags-item');
+ var tagId = $item.attr('data-id');
+ var tagModel = this.collection.get(tagId);
+ var newName = $(ev.target).find('input').val().trim();
+ if (newName && newName !== tagModel.get('name')) {
+ tagModel.save({'name': newName});
+ // TODO: spinner, and only change text after finished saving
+ $item.find('.label').text(newName);
+ }
+ $item.find('.label, .systemtags-actions').removeClass('hidden');
+ $form.remove();
+ $item.closest('.select2-result').removeClass('has-form');
+ },
+
+ /**
+ * Event handler whenever a tag must be deleted
+ *
+ * @param {Object} ev event
+ */
+ _onClickDeleteTag: function(ev) {
+ var $item = $(ev.target).closest('.systemtags-item');
+ var tagId = $item.attr('data-id');
+ this.collection.get(tagId).destroy();
+ $item.closest('.select2-result').remove();
+ // TODO: spinner
+ return false;
+ },
+
+ _addToSelect2Selection: function(selection) {
+ var data = this.$tagsField.select2('data');
+ data.push(selection);
+ this.$tagsField.select2('data', data);
+ },
+
+ /**
+ * Event handler whenever a tag is selected.
+ * Also called whenever tag creation is requested through the dummy tag object.
+ *
+ * @param {Object} e event
+ */
+ _onSelectTag: function(e) {
+ var self = this;
+ var tag;
+ if (e.object && e.object.isNew) {
+ // newly created tag, check if existing
+ // create a new tag
+ tag = this.collection.create({
+ name: e.object.name.trim(),
+ userVisible: true,
+ userAssignable: true
+ }, {
+ success: function(model) {
+ self._addToSelect2Selection(model.toJSON());
+ self.trigger('select', model);
+ },
+ error: function(model, xhr) {
+ if (xhr.status === 409) {
+ // re-fetch collection to get the missing tag
+ self.collection.reset();
+ self.collection.fetch({
+ success: function(collection) {
+ // find the tag in the collection
+ var model = collection.where({name: e.object.name.trim(), userVisible: true, userAssignable: true});
+ if (model.length) {
+ model = model[0];
+ // the tag already exists or was already assigned,
+ // add it to the list anyway
+ self._addToSelect2Selection(model.toJSON());
+ self.trigger('select', model);
+ }
+ }
+ });
+ }
+ }
+ });
+ this.$tagsField.select2('close');
+ e.preventDefault();
+ return false;
+ } else {
+ tag = this.collection.get(e.object.id);
+ }
+ this._newTag = null;
+ this.trigger('select', tag);
+ },
+
+ /**
+ * Event handler whenever a tag gets deselected.
+ *
+ * @param {Object} e event
+ */
+ _onDeselectTag: function(e) {
+ this.trigger('deselect', e.choice.id);
+ },
+
+ /**
+ * Autocomplete function for dropdown results
+ *
+ * @param {Object} query select2 query object
+ */
+ _queryTagsAutocomplete: function(query) {
+ var self = this;
+ this.collection.fetch({
+ success: function(collection) {
+ var tagModels = collection.filterByName(query.term.trim());
+ if (!self._isAdmin) {
+ tagModels = _.filter(tagModels, function(tagModel) {
+ return tagModel.get('userAssignable');
+ });
+ }
+ query.callback({
+ results: _.invoke(tagModels, 'toJSON')
+ });
+ }
+ });
+ },
+
+ _preventDefault: function(e) {
+ e.stopPropagation();
+ },
+
+ /**
+ * Formats a single dropdown result
+ *
+ * @param {Object} data data to format
+ * @return {string} HTML markup
+ */
+ _formatDropDownResult: function(data) {
+ if (!this._resultTemplate) {
+ this._resultTemplate = Handlebars.compile(RESULT_TEMPLATE);
+ }
+ return this._resultTemplate(_.extend({
+ renameTooltip: t('core', 'Rename'),
+ allowActions: this._allowActions,
+ tagMarkup: this._isAdmin ? OC.SystemTags.getDescriptiveTag(data)[0].innerHTML : null,
+ isAdmin: this._isAdmin
+ }, data));
+ },
+
+ /**
+ * Formats a single selection item
+ *
+ * @param {Object} data data to format
+ * @return {string} HTML markup
+ */
+ _formatSelection: function(data) {
+ if (!this._selectionTemplate) {
+ this._selectionTemplate = Handlebars.compile(SELECTION_TEMPLATE);
+ }
+ return this._selectionTemplate(_.extend({
+ tagMarkup: this._isAdmin ? OC.SystemTags.getDescriptiveTag(data)[0].innerHTML : null,
+ isAdmin: this._isAdmin
+ }, data));
+ },
+
+ /**
+ * Create new dummy choice for select2 when the user
+ * types an arbitrary string
+ *
+ * @param {string} term entered term
+ * @return {Object} dummy tag
+ */
+ _createSearchChoice: function(term) {
+ term = term.trim();
+ if (this.collection.filterByName(term).length) {
+ return;
+ }
+ if (!this._newTag) {
+ this._newTag = {
+ id: -1,
+ name: term,
+ userAssignable: true,
+ userVisible: true,
+ isNew: true
+ };
+ } else {
+ this._newTag.name = term;
+ }
+
+ return this._newTag;
+ },
+
+ _initSelection: function(element, callback) {
+ var self = this;
+ var ids = $(element).val().split(',');
+
+ function modelToSelection(model) {
+ var data = model.toJSON();
+ if (!self._isAdmin && !data.userAssignable) {
+ // lock static tags for non-admins
+ data.locked = true;
+ }
+ return data;
+ }
+
+ function findSelectedObjects(ids) {
+ var selectedModels = self.collection.filter(function(model) {
+ return ids.indexOf(model.id) >= 0 && (self._isAdmin || model.get('userVisible'));
+ });
+ return _.map(selectedModels, modelToSelection);
+ }
+
+ this.collection.fetch({
+ success: function() {
+ callback(findSelectedObjects(ids));
+ }
+ });
+ },
+
+ /**
+ * Renders this details view
+ */
+ render: function() {
+ var self = this;
+ this.$el.html(this.template());
+
+ this.$el.find('[title]').tooltip({placement: 'bottom'});
+ this.$tagsField = this.$el.find('[name=tags]');
+ this.$tagsField.select2({
+ placeholder: t('core', 'Global tags'),
+ containerCssClass: 'systemtags-select2-container',
+ dropdownCssClass: 'systemtags-select2-dropdown',
+ closeOnSelect: false,
+ allowClear: false,
+ multiple: this._multiple,
+ toggleSelect: this._multiple,
+ query: _.bind(this._queryTagsAutocomplete, this),
+ id: function(tag) {
+ return tag.id;
+ },
+ initSelection: _.bind(this._initSelection, this),
+ formatResult: _.bind(this._formatDropDownResult, this),
+ formatSelection: _.bind(this._formatSelection, this),
+ createSearchChoice: this._allowCreate ? _.bind(this._createSearchChoice, this) : undefined,
+ sortResults: function(results) {
+ var selectedItems = _.pluck(self.$tagsField.select2('data'), 'id');
+ results.sort(function(a, b) {
+ var aSelected = selectedItems.indexOf(a.id) >= 0;
+ var bSelected = selectedItems.indexOf(b.id) >= 0;
+ if (aSelected === bSelected) {
+ return OC.Util.naturalSortCompare(a.name, b.name);
+ }
+ if (aSelected && !bSelected) {
+ return -1;
+ }
+ return 1;
+ });
+ return results;
+ }
+ })
+ .on('select2-selecting', this._onSelectTag)
+ .on('select2-removing', this._onDeselectTag);
+
+ var $dropDown = this.$tagsField.select2('dropdown');
+ // register events for inside the dropdown
+ $dropDown.on('mouseup', '.rename', this._onClickRenameTag);
+ $dropDown.on('mouseup', '.delete', this._onClickDeleteTag);
+ $dropDown.on('mouseup', '.select2-result-selectable.has-form', this._preventDefault);
+ $dropDown.on('submit', '.systemtags-rename-form', this._onSubmitRenameTag);
+
+ this.delegateEvents();
+ },
+
+ remove: function() {
+ if (this.$tagsField) {
+ this.$tagsField.select2('destroy');
+ }
+ },
+
+ setValues: function(values) {
+ this.$tagsField.select2('val', values);
+ },
+
+ setData: function(data) {
+ this.$tagsField.select2('data', data);
+ }
+ });
+
+ OC.SystemTags = OC.SystemTags || {};
+ OC.SystemTags.SystemTagsInputField = SystemTagsInputField;
+
+})(OC);
+
diff --git a/core/js/systemtags/systemtagsmappingcollection.js b/core/js/systemtags/systemtagsmappingcollection.js
new file mode 100644
index 00000000000..f30a9dbd98e
--- /dev/null
+++ b/core/js/systemtags/systemtagsmappingcollection.js
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC) {
+ /**
+ * @class OC.SystemTags.SystemTagsMappingCollection
+ * @classdesc
+ *
+ * Collection of tags assigned to a an object
+ *
+ */
+ var SystemTagsMappingCollection = OC.Backbone.Collection.extend(
+ /** @lends OC.SystemTags.SystemTagsMappingCollection.prototype */ {
+
+ sync: OC.Backbone.davSync,
+
+ /**
+ * Use PUT instead of PROPPATCH
+ */
+ usePUT: true,
+
+ /**
+ * Id of the file for which to filter activities by
+ *
+ * @var int
+ */
+ _objectId: null,
+
+ /**
+ * Type of the object to filter by
+ *
+ * @var string
+ */
+ _objectType: 'files',
+
+ model: OC.SystemTags.SystemTagModel,
+
+ url: function() {
+ return OC.linkToRemote('dav') + '/systemtags-relations/' + this._objectType + '/' + this._objectId;
+ },
+
+ /**
+ * Sets the object id to filter by or null for all.
+ *
+ * @param {int} objectId file id or null
+ */
+ setObjectId: function(objectId) {
+ this._objectId = objectId;
+ },
+
+ /**
+ * Sets the object type to filter by or null for all.
+ *
+ * @param {int} objectType file id or null
+ */
+ setObjectType: function(objectType) {
+ this._objectType = objectType;
+ },
+
+ initialize: function(models, options) {
+ options = options || {};
+ if (!_.isUndefined(options.objectId)) {
+ this._objectId = options.objectId;
+ }
+ if (!_.isUndefined(options.objectType)) {
+ this._objectType = options.objectType;
+ }
+ },
+
+ getTagIds: function() {
+ return this.map(function(model) {
+ return model.id;
+ });
+ }
+ });
+
+ OC.SystemTags = OC.SystemTags || {};
+ OC.SystemTags.SystemTagsMappingCollection = SystemTagsMappingCollection;
+})(OC);
+
diff --git a/core/js/tests/specHelper.js b/core/js/tests/specHelper.js
index cd387d76ce8..d13691845a7 100644
--- a/core/js/tests/specHelper.js
+++ b/core/js/tests/specHelper.js
@@ -86,6 +86,8 @@ window.firstDay = 0;
// setup dummy webroots
/* jshint camelcase: false */
window.oc_debug = true;
+window.oc_isadmin = false;
+// FIXME: oc_webroot is supposed to be only the path!!!
window.oc_webroot = location.href + '/';
window.oc_appswebroots = {
"files": window.oc_webroot + '/apps/files/'
@@ -159,7 +161,7 @@ window.isPhantom = /phantom/i.test(navigator.userAgent);
OC.Plugins._plugins = [];
// dummy select2 (which isn't loaded during the tests)
- $.fn.select2 = function() {};
+ $.fn.select2 = function() { return this; };
});
afterEach(function() {
diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js
index f653fc88637..2e970f7e707 100644
--- a/core/js/tests/specs/coreSpec.js
+++ b/core/js/tests/specs/coreSpec.js
@@ -524,7 +524,7 @@ describe('Core base tests', function() {
["0", '0 B'],
["A", 'NaN B'],
[125, '125 B'],
- [128000, '125 kB'],
+ [128000, '125 KB'],
[128000000, '122.1 MB'],
[128000000000, '119.2 GB'],
[128000000000000, '116.4 TB']
@@ -535,9 +535,9 @@ describe('Core base tests', function() {
});
it('renders file sizes with the correct unit for small sizes', function() {
var data = [
- [0, '0 kB'],
- [125, '< 1 kB'],
- [128000, '125 kB'],
+ [0, '0 KB'],
+ [125, '< 1 KB'],
+ [128000, '125 KB'],
[128000000, '122.1 MB'],
[128000000000, '119.2 GB'],
[128000000000000, '116.4 TB']
diff --git a/core/js/tests/specs/files/clientSpec.js b/core/js/tests/specs/files/clientSpec.js
new file mode 100644
index 00000000000..b945e1bb4da
--- /dev/null
+++ b/core/js/tests/specs/files/clientSpec.js
@@ -0,0 +1,705 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2015 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+/* global dav */
+
+describe('OC.Files.Client tests', function() {
+ var Client = OC.Files.Client;
+ var baseUrl;
+ var client;
+ var requestStub;
+ var requestDeferred;
+
+ beforeEach(function() {
+ requestDeferred = new $.Deferred();
+ requestStub = sinon.stub(dav.Client.prototype, 'request').returns(requestDeferred.promise());
+ baseUrl = 'https://testhost/owncloud/remote.php/webdav/';
+
+ client = new Client({
+ host: 'testhost',
+ root: '/owncloud/remote.php/webdav',
+ useHTTPS: true
+ });
+ });
+ afterEach(function() {
+ client = null;
+ requestStub.restore();
+ });
+
+ /**
+ * Send an status response and check that the given
+ * promise gets its success handler called with the error
+ * status code
+ *
+ * @param {Promise} promise promise
+ * @param {int} status status to test
+ */
+ function respondAndCheckStatus(promise, status) {
+ var successHandler = sinon.stub();
+ var failHandler = sinon.stub();
+ promise.done(successHandler);
+ promise.fail(failHandler);
+
+ requestDeferred.resolve({
+ status: status,
+ body: ''
+ });
+
+ promise.then(function() {
+ expect(successHandler.calledOnce).toEqual(true);
+ expect(successHandler.getCall(0).args[0]).toEqual(status);
+
+ expect(failHandler.notCalled).toEqual(true);
+ });
+
+ return promise;
+ }
+
+ /**
+ * Send an error response and check that the given
+ * promise gets its fail handler called with the error
+ * status code
+ *
+ * @param {Promise} promise promise object
+ * @param {int} status error status to test
+ */
+ function respondAndCheckError(promise, status) {
+ var successHandler = sinon.stub();
+ var failHandler = sinon.stub();
+ promise.done(successHandler);
+ promise.fail(failHandler);
+
+ requestDeferred.resolve({
+ status: status,
+ body: ''
+ });
+
+ promise.then(function() {
+ expect(failHandler.calledOnce).toEqual(true);
+ expect(failHandler.calledWith(status)).toEqual(true);
+
+ expect(successHandler.notCalled).toEqual(true);
+ });
+
+ return promise;
+ }
+
+ /**
+ * Returns a list of request properties parsed from the given request body.
+ *
+ * @param {string} requestBody request XML
+ *
+ * @return {Array.<String>} array of request properties in the format
+ * "{NS:}propname"
+ */
+ function getRequestedProperties(requestBody) {
+ var doc = (new window.DOMParser()).parseFromString(
+ requestBody,
+ 'application/xml'
+ );
+ var propRoots = doc.getElementsByTagNameNS('DAV:', 'prop');
+ var propsList = propRoots.item(0).childNodes;
+ return _.map(propsList, function(propNode) {
+ return '{' + propNode.namespaceURI + '}' + propNode.localName;
+ });
+ }
+
+ function makePropBlock(props) {
+ var s = '<d:prop>\n';
+
+ _.each(props, function(value, key) {
+ s += '<' + key + '>' + value + '</' + key + '>\n';
+ });
+
+ return s + '</d:prop>\n';
+ }
+
+ function makeResponseBlock(href, props, failedProps) {
+ var s = '<d:response>\n';
+ s += '<d:href>' + href + '</d:href>\n';
+ s += '<d:propstat>\n';
+ s += makePropBlock(props);
+ s += '<d:status>HTTP/1.1 200 OK</d:status>';
+ s += '</d:propstat>\n';
+ if (failedProps) {
+ s += '<d:propstat>\n';
+ _.each(failedProps, function(prop) {
+ s += '<' + prop + '/>\n';
+ });
+ s += '<d:status>HTTP/1.1 404 Not Found</d:status>\n';
+ s += '</d:propstat>\n';
+ }
+ return s + '</d:response>\n';
+ }
+
+ describe('file listing', function() {
+
+ // TODO: switch this to the already parsed structure
+ var folderContentsXml = dav.Client.prototype.parseMultiStatus(
+ '<?xml version="1.0" encoding="utf-8"?>' +
+ '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">' +
+ makeResponseBlock(
+ '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/',
+ {
+ 'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
+ 'd:getetag': '"56cfcabd79abb"',
+ 'd:resourcetype': '<d:collection/>',
+ 'oc:id': '00000011oc2d13a6a068',
+ 'oc:fileid': '11',
+ 'oc:permissions': 'RDNVCK',
+ 'oc:size': '120'
+ },
+ [
+ 'd:getcontenttype',
+ 'd:getcontentlength'
+ ]
+ ) +
+ makeResponseBlock(
+ '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt',
+ {
+ 'd:getlastmodified': 'Fri, 10 Jul 2015 13:38:05 GMT',
+ 'd:getetag': '"559fcabd79a38"',
+ 'd:getcontenttype': 'text/plain',
+ 'd:getcontentlength': 250,
+ 'd:resourcetype': '',
+ 'oc:id': '00000051oc2d13a6a068',
+ 'oc:fileid': '51',
+ 'oc:permissions': 'RDNVW'
+ },
+ [
+ 'oc:size',
+ ]
+ ) +
+ makeResponseBlock(
+ '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/sub',
+ {
+ 'd:getlastmodified': 'Fri, 10 Jul 2015 14:00:00 GMT',
+ 'd:getetag': '"66cfcabd79abb"',
+ 'd:resourcetype': '<d:collection/>',
+ 'oc:id': '00000015oc2d13a6a068',
+ 'oc:fileid': '15',
+ 'oc:permissions': 'RDNVCK',
+ 'oc:size': '100'
+ },
+ [
+ 'd:getcontenttype',
+ 'd:getcontentlength'
+ ]
+ ) +
+ '</d:multistatus>'
+ );
+
+ it('sends PROPFIND with explicit properties to get file list', function() {
+ client.getFolderContents('path/to space/文件夹');
+
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[0]).toEqual('PROPFIND');
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
+ expect(requestStub.lastCall.args[2].Depth).toEqual(1);
+
+ var props = getRequestedProperties(requestStub.lastCall.args[3]);
+ expect(props).toContain('{DAV:}getlastmodified');
+ expect(props).toContain('{DAV:}getcontentlength');
+ expect(props).toContain('{DAV:}getcontenttype');
+ expect(props).toContain('{DAV:}getetag');
+ expect(props).toContain('{DAV:}resourcetype');
+ expect(props).toContain('{http://owncloud.org/ns}fileid');
+ expect(props).toContain('{http://owncloud.org/ns}size');
+ expect(props).toContain('{http://owncloud.org/ns}permissions');
+ });
+ it('sends PROPFIND to base url when empty path given', function() {
+ client.getFolderContents('');
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl);
+ });
+ it('sends PROPFIND to base url when root path given', function() {
+ client.getFolderContents('/');
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl);
+ });
+ it('parses the result list into a FileInfo array', function() {
+ var promise = client.getFolderContents('path/to space/文件夹');
+
+ expect(requestStub.calledOnce).toEqual(true);
+
+ requestDeferred.resolve({
+ status: 207,
+ body: folderContentsXml
+ });
+
+ promise.then(function(status, response) {
+ expect(status).toEqual(207);
+ expect(_.isArray(response)).toEqual(true);
+
+ expect(response.length).toEqual(2);
+
+ // file entry
+ var info = response[0];
+ expect(info instanceof OC.Files.FileInfo).toEqual(true);
+ expect(info.id).toEqual(51);
+ expect(info.path).toEqual('/path/to space/文件夹');
+ expect(info.name).toEqual('One.txt');
+ expect(info.permissions).toEqual(27);
+ expect(info.size).toEqual(250);
+ expect(info.mtime).toEqual(1436535485000);
+ expect(info.mimetype).toEqual('text/plain');
+ expect(info.etag).toEqual('559fcabd79a38');
+
+ // sub entry
+ info = response[1];
+ expect(info instanceof OC.Files.FileInfo).toEqual(true);
+ expect(info.id).toEqual(15);
+ expect(info.path).toEqual('/path/to space/文件夹');
+ expect(info.name).toEqual('sub');
+ expect(info.permissions).toEqual(31);
+ expect(info.size).toEqual(100);
+ expect(info.mtime).toEqual(1436536800000);
+ expect(info.mimetype).toEqual('httpd/unix-directory');
+ expect(info.etag).toEqual('66cfcabd79abb');
+ });
+ });
+ it('returns parent node in result if specified', function() {
+ var promise = client.getFolderContents('path/to space/文件夹', {includeParent: true});
+
+ expect(requestStub.calledOnce).toEqual(true);
+
+ requestDeferred.resolve({
+ status: 207,
+ body: folderContentsXml
+ });
+
+ promise.then(function(status, response) {
+ expect(status).toEqual(207);
+ expect(_.isArray(response)).toEqual(true);
+
+ expect(response.length).toEqual(3);
+
+ // root entry
+ var info = response[0];
+ expect(info instanceof OC.Files.FileInfo).toEqual(true);
+ expect(info.id).toEqual(11);
+ expect(info.path).toEqual('/path/to space');
+ expect(info.name).toEqual('文件夹');
+ expect(info.permissions).toEqual(31);
+ expect(info.size).toEqual(120);
+ expect(info.mtime).toEqual(1436522405000);
+ expect(info.mimetype).toEqual('httpd/unix-directory');
+ expect(info.etag).toEqual('56cfcabd79abb');
+
+ // the two other entries follow
+ expect(response[1].id).toEqual(51);
+ expect(response[2].id).toEqual(15);
+ });
+ });
+ it('rejects promise when an error occurred', function() {
+ var promise = client.getFolderContents('path/to space/文件夹', {includeParent: true});
+ respondAndCheckError(promise, 404);
+ });
+ it('throws exception if arguments are missing', function() {
+ // TODO
+ });
+ });
+
+ describe('file info', function() {
+ var responseXml = dav.Client.prototype.parseMultiStatus(
+ '<?xml version="1.0" encoding="utf-8"?>' +
+ '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">' +
+ makeResponseBlock(
+ '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/',
+ {
+ 'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
+ 'd:getetag': '"56cfcabd79abb"',
+ 'd:resourcetype': '<d:collection/>',
+ 'oc:id': '00000011oc2d13a6a068',
+ 'oc:fileid': '11',
+ 'oc:permissions': 'RDNVCK',
+ 'oc:size': '120'
+ },
+ [
+ 'd:getcontenttype',
+ 'd:getcontentlength'
+ ]
+ ) +
+ '</d:multistatus>'
+ );
+
+ it('sends PROPFIND with zero depth to get single file info', function() {
+ client.getFileInfo('path/to space/文件夹');
+
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[0]).toEqual('PROPFIND');
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
+ expect(requestStub.lastCall.args[2].Depth).toEqual(0);
+
+ var props = getRequestedProperties(requestStub.lastCall.args[3]);
+ expect(props).toContain('{DAV:}getlastmodified');
+ expect(props).toContain('{DAV:}getcontentlength');
+ expect(props).toContain('{DAV:}getcontenttype');
+ expect(props).toContain('{DAV:}getetag');
+ expect(props).toContain('{DAV:}resourcetype');
+ expect(props).toContain('{http://owncloud.org/ns}fileid');
+ expect(props).toContain('{http://owncloud.org/ns}size');
+ expect(props).toContain('{http://owncloud.org/ns}permissions');
+ });
+ it('parses the result into a FileInfo', function() {
+ var promise = client.getFileInfo('path/to space/文件夹');
+
+ expect(requestStub.calledOnce).toEqual(true);
+
+ requestDeferred.resolve({
+ status: 207,
+ body: responseXml
+ });
+
+ promise.then(function(status, response) {
+ expect(status).toEqual(207);
+ expect(_.isArray(response)).toEqual(false);
+
+ var info = response;
+ expect(info instanceof OC.Files.FileInfo).toEqual(true);
+ expect(info.id).toEqual(11);
+ expect(info.path).toEqual('/path/to space');
+ expect(info.name).toEqual('文件夹');
+ expect(info.permissions).toEqual(31);
+ expect(info.size).toEqual(120);
+ expect(info.mtime).toEqual(1436522405000);
+ expect(info.mimetype).toEqual('httpd/unix-directory');
+ expect(info.etag).toEqual('56cfcabd79abb');
+ });
+ });
+ it('properly parses entry inside root', function() {
+ var responseXml = dav.Client.prototype.parseMultiStatus(
+ '<?xml version="1.0" encoding="utf-8"?>' +
+ '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">' +
+ makeResponseBlock(
+ '/owncloud/remote.php/webdav/in%20root',
+ {
+ 'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
+ 'd:getetag': '"56cfcabd79abb"',
+ 'd:resourcetype': '<d:collection/>',
+ 'oc:id': '00000011oc2d13a6a068',
+ 'oc:fileid': '11',
+ 'oc:permissions': 'RDNVCK',
+ 'oc:size': '120'
+ },
+ [
+ 'd:getcontenttype',
+ 'd:getcontentlength'
+ ]
+ ) +
+ '</d:multistatus>'
+ );
+
+ var promise = client.getFileInfo('in root');
+
+ expect(requestStub.calledOnce).toEqual(true);
+
+ requestDeferred.resolve({
+ status: 207,
+ body: responseXml
+ });
+
+ promise.then(function(status, response) {
+ expect(status).toEqual(207);
+ expect(_.isArray(response)).toEqual(false);
+
+ var info = response;
+ expect(info instanceof OC.Files.FileInfo).toEqual(true);
+ expect(info.id).toEqual(11);
+ expect(info.path).toEqual('/');
+ expect(info.name).toEqual('in root');
+ expect(info.permissions).toEqual(31);
+ expect(info.size).toEqual(120);
+ expect(info.mtime).toEqual(1436522405000);
+ expect(info.mimetype).toEqual('httpd/unix-directory');
+ expect(info.etag).toEqual('56cfcabd79abb');
+ });
+ });
+ it('rejects promise when an error occurred', function() {
+ var promise = client.getFileInfo('path/to space/文件夹');
+ respondAndCheckError(promise, 404);
+ });
+ it('throws exception if arguments are missing', function() {
+ // TODO
+ });
+ });
+
+ describe('permissions', function() {
+
+ function getFileInfoWithPermission(webdavPerm, isFile) {
+ var props = {
+ 'd:getlastmodified': 'Fri, 10 Jul 2015 13:38:05 GMT',
+ 'd:getetag': '"559fcabd79a38"',
+ 'd:getcontentlength': 250,
+ 'oc:id': '00000051oc2d13a6a068',
+ 'oc:fileid': '51',
+ 'oc:permissions': webdavPerm,
+ };
+
+ if (isFile) {
+ props['d:getcontenttype'] = 'text/plain';
+ } else {
+ props['d:resourcetype'] = '<d:collection/>';
+ }
+
+ var def = new $.Deferred();
+ requestStub.reset();
+ requestStub.returns(def);
+
+ var responseXml = dav.Client.prototype.parseMultiStatus(
+ '<?xml version="1.0" encoding="utf-8"?>' +
+ '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">' +
+ makeResponseBlock(
+ '/owncloud/remote.php/webdav/file.txt',
+ props
+ ) +
+ '</d:multistatus>'
+ );
+
+ var promise = client.getFileInfo('file.txt');
+
+ expect(requestStub.calledOnce).toEqual(true);
+
+ def.resolve({
+ status: 207,
+ body: responseXml
+ });
+
+ return promise;
+ }
+
+ function testPermission(permission, isFile, expectedPermissions) {
+ var promise = getFileInfoWithPermission(permission, isFile);
+ promise.then(function(result) {
+ expect(result.permissions).toEqual(expectedPermissions);
+ });
+ }
+
+ function testMountType(permission, isFile, expectedMountType) {
+ var promise = getFileInfoWithPermission(permission, isFile);
+ promise.then(function(result) {
+ expect(result.mountType).toEqual(expectedMountType);
+ });
+ }
+
+ it('properly parses file permissions', function() {
+ // permission, isFile, expectedPermissions
+ var testCases = [
+ ['', true, OC.PERMISSION_READ],
+ ['C', true, OC.PERMISSION_READ | OC.PERMISSION_CREATE],
+ ['K', true, OC.PERMISSION_READ | OC.PERMISSION_CREATE],
+ ['W', true, OC.PERMISSION_READ | OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE],
+ ['D', true, OC.PERMISSION_READ | OC.PERMISSION_DELETE],
+ ['R', true, OC.PERMISSION_READ | OC.PERMISSION_SHARE],
+ ['CKWDR', true, OC.PERMISSION_ALL]
+ ];
+ _.each(testCases, function(testCase) {
+ return testPermission.apply(testCase);
+ });
+ });
+ it('properly parses folder permissions', function() {
+ var testCases = [
+ ['', false, OC.PERMISSION_READ],
+ ['C', false, OC.PERMISSION_READ | OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE],
+ ['K', false, OC.PERMISSION_READ | OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE],
+ ['W', false, OC.PERMISSION_READ | OC.PERMISSION_UPDATE],
+ ['D', false, OC.PERMISSION_READ | OC.PERMISSION_DELETE],
+ ['R', false, OC.PERMISSION_READ | OC.PERMISSION_SHARE],
+ ['CKWDR', false, OC.PERMISSION_ALL]
+ ];
+
+ _.each(testCases, function(testCase) {
+ return testPermission.apply(testCase);
+ });
+ });
+ it('properly parses mount types', function() {
+ var testCases = [
+ ['CKWDR', false, null],
+ ['M', false, 'external'],
+ ['S', false, 'shared'],
+ ['SM', false, 'shared']
+ ];
+
+ _.each(testCases, function(testCase) {
+ return testMountType.apply(testCase);
+ });
+ });
+ });
+
+ describe('get file contents', function() {
+ it('returns file contents', function() {
+ var promise = client.getFileContents('path/to space/文件夹/One.txt');
+
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[0]).toEqual('GET');
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt');
+
+ requestDeferred.resolve({
+ status: 200,
+ body: 'some contents'
+ });
+
+ promise.then(function(status, response) {
+ expect(status).toEqual(200);
+ expect(response).toEqual('some contents');
+ });
+ });
+ it('rejects promise when an error occurred', function() {
+ var promise = client.getFileContents('path/to space/文件夹/One.txt');
+ respondAndCheckError(promise, 409);
+ });
+ it('throws exception if arguments are missing', function() {
+ // TODO
+ });
+ });
+
+ describe('put file contents', function() {
+ it('sends PUT with file contents', function() {
+ var promise = client.putFileContents(
+ 'path/to space/文件夹/One.txt',
+ 'some contents'
+ );
+
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[0]).toEqual('PUT');
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt');
+ expect(requestStub.lastCall.args[2]['If-None-Match']).toEqual('*');
+ expect(requestStub.lastCall.args[2]['Content-Type']).toEqual('text/plain;charset=utf-8');
+ expect(requestStub.lastCall.args[3]).toEqual('some contents');
+
+ respondAndCheckStatus(promise, 201);
+ });
+ it('sends PUT with file contents with headers matching options', function() {
+ var promise = client.putFileContents(
+ 'path/to space/文件夹/One.txt',
+ 'some contents',
+ {
+ overwrite: false,
+ contentType: 'text/markdown'
+ }
+ );
+
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[0]).toEqual('PUT');
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt');
+ expect(requestStub.lastCall.args[2]['If-None-Match']).not.toBeDefined();
+ expect(requestStub.lastCall.args[2]['Content-Type']).toEqual('text/markdown');
+ expect(requestStub.lastCall.args[3]).toEqual('some contents');
+
+ respondAndCheckStatus(promise, 201);
+ });
+ it('rejects promise when an error occurred', function() {
+ var promise = client.putFileContents(
+ 'path/to space/文件夹/One.txt',
+ 'some contents'
+ );
+ respondAndCheckError(promise, 409);
+ });
+ it('throws exception if arguments are missing', function() {
+ // TODO
+ });
+ });
+
+ describe('create directory', function() {
+ it('sends MKCOL with specified path', function() {
+ var promise = client.createDirectory('path/to space/文件夹/new dir');
+
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[0]).toEqual('MKCOL');
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/new%20dir');
+
+ respondAndCheckStatus(promise, 201);
+ });
+ it('rejects promise when an error occurred', function() {
+ var promise = client.createDirectory('path/to space/文件夹/new dir');
+ respondAndCheckError(promise, 404);
+ });
+ it('throws exception if arguments are missing', function() {
+ // TODO
+ });
+ });
+
+ describe('deletion', function() {
+ it('sends DELETE with specified path', function() {
+ var promise = client.remove('path/to space/文件夹');
+
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[0]).toEqual('DELETE');
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
+
+ respondAndCheckStatus(promise, 201);
+ });
+ it('rejects promise when an error occurred', function() {
+ var promise = client.remove('path/to space/文件夹');
+ respondAndCheckError(promise, 404);
+ });
+ it('throws exception if arguments are missing', function() {
+ // TODO
+ });
+ });
+
+ describe('move', function() {
+ it('sends MOVE with specified paths with fail on overwrite by default', function() {
+ var promise = client.move(
+ 'path/to space/文件夹',
+ 'path/to space/anotherdir/文件夹'
+ );
+
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[0]).toEqual('MOVE');
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
+ expect(requestStub.lastCall.args[2].Destination)
+ .toEqual(baseUrl + 'path/to%20space/anotherdir/%E6%96%87%E4%BB%B6%E5%A4%B9');
+ expect(requestStub.lastCall.args[2].Overwrite)
+ .toEqual('F');
+
+ respondAndCheckStatus(promise, 201);
+ });
+ it('sends MOVE with silent overwrite mode when specified', function() {
+ var promise = client.move(
+ 'path/to space/文件夹',
+ 'path/to space/anotherdir/文件夹',
+ {allowOverwrite: true}
+ );
+
+ expect(requestStub.calledOnce).toEqual(true);
+ expect(requestStub.lastCall.args[0]).toEqual('MOVE');
+ expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
+ expect(requestStub.lastCall.args[2].Destination)
+ .toEqual(baseUrl + 'path/to%20space/anotherdir/%E6%96%87%E4%BB%B6%E5%A4%B9');
+ expect(requestStub.lastCall.args[2].Overwrite)
+ .not.toBeDefined();
+
+ respondAndCheckStatus(promise, 201);
+ });
+ it('rejects promise when an error occurred', function() {
+ var promise = client.move(
+ 'path/to space/文件夹',
+ 'path/to space/anotherdir/文件夹',
+ {allowOverwrite: true}
+ );
+ respondAndCheckError(promise, 404);
+ });
+ it('throws exception if arguments are missing', function() {
+ // TODO
+ });
+ });
+});
diff --git a/core/js/tests/specs/oc-backbone-webdavSpec.js b/core/js/tests/specs/oc-backbone-webdavSpec.js
new file mode 100644
index 00000000000..97281e982ce
--- /dev/null
+++ b/core/js/tests/specs/oc-backbone-webdavSpec.js
@@ -0,0 +1,390 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+/* global dav */
+
+describe('Backbone Webdav extension', function() {
+ var davClientRequestStub;
+ var davClientPropPatchStub;
+ var davClientPropFindStub;
+ var deferredRequest;
+
+ beforeEach(function() {
+ deferredRequest = $.Deferred();
+ davClientRequestStub = sinon.stub(dav.Client.prototype, 'request');
+ davClientPropPatchStub = sinon.stub(dav.Client.prototype, 'propPatch');
+ davClientPropFindStub = sinon.stub(dav.Client.prototype, 'propFind');
+ davClientRequestStub.returns(deferredRequest.promise());
+ davClientPropPatchStub.returns(deferredRequest.promise());
+ davClientPropFindStub.returns(deferredRequest.promise());
+ });
+ afterEach(function() {
+ davClientRequestStub.restore();
+ davClientPropPatchStub.restore();
+ davClientPropFindStub.restore();
+ });
+
+ describe('collections', function() {
+ var TestModel;
+ var TestCollection;
+ beforeEach(function() {
+ TestModel = OC.Backbone.Model.extend({
+ sync: OC.Backbone.davSync,
+ davProperties: {
+ 'firstName': '{http://owncloud.org/ns}first-name',
+ 'lastName': '{http://owncloud.org/ns}last-name',
+ 'age': '{http://owncloud.org/ns}age',
+ 'married': '{http://owncloud.org/ns}married'
+ },
+ parse: function(data) {
+ return {
+ id: data.id,
+ firstName: data.firstName,
+ lastName: data.lastName,
+ age: parseInt(data.age, 10),
+ married: data.married === 'true' || data.married === true
+ };
+ }
+ });
+ TestCollection = OC.Backbone.Collection.extend({
+ sync: OC.Backbone.davSync,
+ model: TestModel,
+ url: 'http://example.com/owncloud/remote.php/test/'
+ });
+ });
+
+ it('makes a POST request to create model into collection', function() {
+ var collection = new TestCollection();
+ var model = collection.create({
+ firstName: 'Hello',
+ lastName: 'World'
+ });
+
+ expect(davClientRequestStub.calledOnce).toEqual(true);
+ expect(davClientRequestStub.getCall(0).args[0])
+ .toEqual('POST');
+ expect(davClientRequestStub.getCall(0).args[1])
+ .toEqual('http://example.com/owncloud/remote.php/test/');
+ expect(davClientRequestStub.getCall(0).args[2]['Content-Type'])
+ .toEqual('application/json');
+ expect(davClientRequestStub.getCall(0).args[2]['X-Requested-With'])
+ .toEqual('XMLHttpRequest');
+ expect(davClientRequestStub.getCall(0).args[3])
+ .toEqual(JSON.stringify({
+ 'firstName': 'Hello',
+ 'lastName': 'World'
+ }));
+
+ var responseHeaderStub = sinon.stub()
+ .withArgs('Content-Location')
+ .returns('http://example.com/owncloud/remote.php/test/123');
+ deferredRequest.resolve({
+ status: 201,
+ body: '',
+ xhr: {
+ getResponseHeader: responseHeaderStub
+ }
+ });
+
+ expect(model.id).toEqual('123');
+ });
+
+ it('uses PROPFIND to retrieve collection', function() {
+ var successStub = sinon.stub();
+ var errorStub = sinon.stub();
+ var collection = new TestCollection();
+ collection.fetch({
+ success: successStub,
+ error: errorStub
+ });
+
+ expect(davClientPropFindStub.calledOnce).toEqual(true);
+ expect(davClientPropFindStub.getCall(0).args[0])
+ .toEqual('http://example.com/owncloud/remote.php/test/');
+ expect(davClientPropFindStub.getCall(0).args[1])
+ .toEqual([
+ '{http://owncloud.org/ns}first-name',
+ '{http://owncloud.org/ns}last-name',
+ '{http://owncloud.org/ns}age',
+ '{http://owncloud.org/ns}married'
+ ]);
+ expect(davClientPropFindStub.getCall(0).args[2])
+ .toEqual(1);
+ expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With'])
+ .toEqual('XMLHttpRequest');
+
+ deferredRequest.resolve({
+ status: 207,
+ body: [
+ // root element
+ {
+ href: 'http://example.org/owncloud/remote.php/test/',
+ propStat: []
+ },
+ // first model
+ {
+ href: 'http://example.org/owncloud/remote.php/test/123',
+ propStat: [{
+ status: 'HTTP/1.1 200 OK',
+ properties: {
+ '{http://owncloud.org/ns}first-name': 'Hello',
+ '{http://owncloud.org/ns}last-name': 'World'
+ }
+ }]
+ },
+ // second model
+ {
+ href: 'http://example.org/owncloud/remote.php/test/456',
+ propStat: [{
+ status: 'HTTP/1.1 200 OK',
+ properties: {
+ '{http://owncloud.org/ns}first-name': 'Test',
+ '{http://owncloud.org/ns}last-name': 'Person'
+ }
+ }]
+ }
+ ]
+ });
+
+ expect(collection.length).toEqual(2);
+
+ var model = collection.get('123');
+ expect(model.id).toEqual('123');
+ expect(model.get('firstName')).toEqual('Hello');
+ expect(model.get('lastName')).toEqual('World');
+
+ model = collection.get('456');
+ expect(model.id).toEqual('456');
+ expect(model.get('firstName')).toEqual('Test');
+ expect(model.get('lastName')).toEqual('Person');
+
+ expect(successStub.calledOnce).toEqual(true);
+ expect(errorStub.notCalled).toEqual(true);
+ });
+
+ function testMethodError(doCall) {
+ var successStub = sinon.stub();
+ var errorStub = sinon.stub();
+
+ doCall(successStub, errorStub);
+
+ deferredRequest.resolve({
+ status: 404,
+ body: ''
+ });
+
+ expect(successStub.notCalled).toEqual(true);
+ expect(errorStub.calledOnce).toEqual(true);
+ }
+
+ it('calls error handler if error status in PROPFIND response', function() {
+ testMethodError(function(success, error) {
+ var collection = new TestCollection();
+ collection.fetch({
+ success: success,
+ error: error
+ });
+ });
+ });
+ it('calls error handler if error status in POST response', function() {
+ testMethodError(function(success, error) {
+ var collection = new TestCollection();
+ collection.create({
+ firstName: 'Hello',
+ lastName: 'World'
+ }, {
+ success: success,
+ error: error
+ });
+ });
+ });
+ });
+ describe('models', function() {
+ var TestModel;
+ beforeEach(function() {
+ TestModel = OC.Backbone.Model.extend({
+ sync: OC.Backbone.davSync,
+ davProperties: {
+ 'firstName': '{http://owncloud.org/ns}first-name',
+ 'lastName': '{http://owncloud.org/ns}last-name',
+ 'age': '{http://owncloud.org/ns}age', // int
+ 'married': '{http://owncloud.org/ns}married', // bool
+ },
+ url: function() {
+ return 'http://example.com/owncloud/remote.php/test/' + this.id;
+ },
+ parse: function(data) {
+ return {
+ id: data.id,
+ firstName: data.firstName,
+ lastName: data.lastName,
+ age: parseInt(data.age, 10),
+ married: data.married === 'true' || data.married === true
+ };
+ }
+ });
+ });
+
+ it('makes a PROPPATCH request to update model', function() {
+ var model = new TestModel({
+ id: '123',
+ firstName: 'Hello',
+ lastName: 'World',
+ age: 32,
+ married: false
+ });
+
+ model.save({
+ firstName: 'Hey',
+ age: 33,
+ married: true
+ });
+
+ expect(davClientPropPatchStub.calledOnce).toEqual(true);
+ expect(davClientPropPatchStub.getCall(0).args[0])
+ .toEqual('http://example.com/owncloud/remote.php/test/123');
+ expect(davClientPropPatchStub.getCall(0).args[1])
+ .toEqual({
+ '{http://owncloud.org/ns}first-name': 'Hey',
+ '{http://owncloud.org/ns}age': '33',
+ '{http://owncloud.org/ns}married': 'true'
+ });
+ expect(davClientPropPatchStub.getCall(0).args[2]['X-Requested-With'])
+ .toEqual('XMLHttpRequest');
+
+ deferredRequest.resolve({
+ status: 201,
+ body: ''
+ });
+
+ expect(model.id).toEqual('123');
+ expect(model.get('firstName')).toEqual('Hey');
+ expect(model.get('age')).toEqual(33);
+ expect(model.get('married')).toEqual(true);
+ });
+
+ it('uses PROPFIND to fetch single model', function() {
+ var model = new TestModel({
+ id: '123'
+ });
+
+ model.fetch();
+
+ expect(davClientPropFindStub.calledOnce).toEqual(true);
+ expect(davClientPropFindStub.getCall(0).args[0])
+ .toEqual('http://example.com/owncloud/remote.php/test/123');
+ expect(davClientPropFindStub.getCall(0).args[1])
+ .toEqual([
+ '{http://owncloud.org/ns}first-name',
+ '{http://owncloud.org/ns}last-name',
+ '{http://owncloud.org/ns}age',
+ '{http://owncloud.org/ns}married'
+ ]);
+ expect(davClientPropFindStub.getCall(0).args[2])
+ .toEqual(0);
+ expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With'])
+ .toEqual('XMLHttpRequest');
+
+ deferredRequest.resolve({
+ status: 207,
+ body: {
+ href: 'http://example.org/owncloud/remote.php/test/123',
+ propStat: [{
+ status: 'HTTP/1.1 200 OK',
+ properties: {
+ '{http://owncloud.org/ns}first-name': 'Hello',
+ '{http://owncloud.org/ns}last-name': 'World',
+ '{http://owncloud.org/ns}age': '35',
+ '{http://owncloud.org/ns}married': 'true'
+ }
+ }]
+ }
+ });
+
+ expect(model.id).toEqual('123');
+ expect(model.get('firstName')).toEqual('Hello');
+ expect(model.get('lastName')).toEqual('World');
+ expect(model.get('age')).toEqual(35);
+ expect(model.get('married')).toEqual(true);
+ });
+ it('makes a DELETE request to destroy model', function() {
+ var model = new TestModel({
+ id: '123',
+ firstName: 'Hello',
+ lastName: 'World'
+ });
+
+ model.destroy();
+
+ expect(davClientRequestStub.calledOnce).toEqual(true);
+ expect(davClientRequestStub.getCall(0).args[0])
+ .toEqual('DELETE');
+ expect(davClientRequestStub.getCall(0).args[1])
+ .toEqual('http://example.com/owncloud/remote.php/test/123');
+ expect(davClientRequestStub.getCall(0).args[2]['X-Requested-With'])
+ .toEqual('XMLHttpRequest');
+ expect(davClientRequestStub.getCall(0).args[3])
+ .toBeFalsy();
+
+ deferredRequest.resolve({
+ status: 200,
+ body: ''
+ });
+ });
+
+ function testMethodError(doCall) {
+ var successStub = sinon.stub();
+ var errorStub = sinon.stub();
+
+ doCall(successStub, errorStub);
+
+ deferredRequest.resolve({
+ status: 404,
+ body: ''
+ });
+
+ expect(successStub.notCalled).toEqual(true);
+ expect(errorStub.calledOnce).toEqual(true);
+ }
+
+ it('calls error handler if error status in PROPFIND response', function() {
+ testMethodError(function(success, error) {
+ var model = new TestModel();
+ model.fetch({
+ success: success,
+ error: error
+ });
+ });
+ });
+ it('calls error handler if error status in PROPPATCH response', function() {
+ testMethodError(function(success, error) {
+ var model = new TestModel();
+ model.save({
+ firstName: 'Hey'
+ }, {
+ success: success,
+ error: error
+ });
+ });
+ });
+ });
+});
+
diff --git a/core/js/tests/specs/setupchecksSpec.js b/core/js/tests/specs/setupchecksSpec.js
index 8dd2214621a..59df3a58746 100644
--- a/core/js/tests/specs/setupchecksSpec.js
+++ b/core/js/tests/specs/setupchecksSpec.js
@@ -60,6 +60,85 @@ describe('OC.SetupChecks tests', function() {
});
});
+ describe('checkWellKnownUrl', function() {
+ it('should fail with another response status code than 207', function(done) {
+ var async = OC.SetupChecks.checkWellKnownUrl('/.well-known/caldav/', 'http://example.org/PLACEHOLDER', true);
+
+ suite.server.requests[0].respond(200);
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([{
+ msg: 'Your web server is not set up properly to resolve "/.well-known/caldav/". Further information can be found in our <a target="_blank" href="http://example.org/admin-setup-well-known-URL">documentation</a>.',
+ type: OC.SetupChecks.MESSAGE_TYPE_INFO
+ }]);
+ done();
+ });
+ });
+
+ it('should return no error with a response status code of 207', function(done) {
+ var async = OC.SetupChecks.checkWellKnownUrl('/.well-known/caldav/', 'http://example.org/PLACEHOLDER', true);
+
+ suite.server.requests[0].respond(207);
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ done();
+ });
+ });
+
+ it('should return no error when no check should be run', function(done) {
+ var async = OC.SetupChecks.checkWellKnownUrl('/.well-known/caldav/', 'http://example.org/PLACEHOLDER', false);
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ done();
+ });
+ });
+ });
+
+ describe('checkDataProtected', function() {
+
+ oc_dataURL = "data";
+
+ it('should return an error if data directory is not protected', function(done) {
+ var async = OC.SetupChecks.checkDataProtected();
+
+ suite.server.requests[0].respond(200);
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([
+ {
+ msg: 'Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.',
+ type: OC.SetupChecks.MESSAGE_TYPE_ERROR
+ }]);
+ done();
+ });
+ });
+
+ it('should not return an error if data directory is protected', function(done) {
+ var async = OC.SetupChecks.checkDataProtected();
+
+ suite.server.requests[0].respond(403);
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ done();
+ });
+ });
+
+ it('should return an error if data directory is a boolean', function(done) {
+
+ oc_dataURL = false;
+
+ var async = OC.SetupChecks.checkDataProtected();
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ done();
+ });
+ });
+ });
+
describe('checkSetup', function() {
it('should return an error if server has no internet connection', function(done) {
var async = OC.SetupChecks.checkSetup();
@@ -75,6 +154,7 @@ describe('OC.SetupChecks tests', function() {
memcacheDocs: 'https://doc.owncloud.org/server/go.php?to=admin-performance',
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
@@ -84,10 +164,7 @@ describe('OC.SetupChecks tests', function() {
msg: 'This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features.',
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
}, {
- msg: 'Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.',
- type: OC.SetupChecks.MESSAGE_TYPE_ERROR
- }, {
- msg: 'No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href="https://doc.owncloud.org/server/go.php?to=admin-performance">documentation</a>.',
+ msg: 'No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target="_blank" href="https://doc.owncloud.org/server/go.php?to=admin-performance">documentation</a>.',
type: OC.SetupChecks.MESSAGE_TYPE_INFO
}]);
done();
@@ -105,10 +182,10 @@ describe('OC.SetupChecks tests', function() {
JSON.stringify({
isUrandomAvailable: true,
serverHasInternetConnection: false,
- dataDirectoryProtected: false,
memcacheDocs: 'https://doc.owncloud.org/server/go.php?to=admin-performance',
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
@@ -119,11 +196,7 @@ describe('OC.SetupChecks tests', function() {
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
},
{
- msg: 'Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.',
- type: OC.SetupChecks.MESSAGE_TYPE_ERROR
- },
- {
- msg: 'No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href="https://doc.owncloud.org/server/go.php?to=admin-performance">documentation</a>.',
+ msg: 'No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target="_blank" href="https://doc.owncloud.org/server/go.php?to=admin-performance">documentation</a>.',
type: OC.SetupChecks.MESSAGE_TYPE_INFO
}]);
done();
@@ -141,10 +214,10 @@ describe('OC.SetupChecks tests', function() {
JSON.stringify({
isUrandomAvailable: true,
serverHasInternetConnection: false,
- dataDirectoryProtected: false,
isMemcacheConfigured: true,
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
@@ -153,11 +226,8 @@ describe('OC.SetupChecks tests', function() {
{
msg: 'This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features.',
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
- },
- {
- msg: 'Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.',
- type: OC.SetupChecks.MESSAGE_TYPE_ERROR
- }]);
+ }
+ ]);
done();
});
});
@@ -174,16 +244,16 @@ describe('OC.SetupChecks tests', function() {
isUrandomAvailable: false,
securityDocs: 'https://docs.owncloud.org/myDocs.html',
serverHasInternetConnection: true,
- dataDirectoryProtected: true,
isMemcacheConfigured: true,
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
async.done(function( data, s, x ){
expect(data).toEqual([{
- msg: '/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href="https://docs.owncloud.org/myDocs.html">documentation</a>.',
+ msg: '/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target="_blank" href="https://docs.owncloud.org/myDocs.html">documentation</a>.',
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
}]);
done();
@@ -202,16 +272,16 @@ describe('OC.SetupChecks tests', function() {
isUrandomAvailable: true,
securityDocs: 'https://docs.owncloud.org/myDocs.html',
serverHasInternetConnection: true,
- dataDirectoryProtected: true,
isMemcacheConfigured: true,
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: false,
+ hasPassedCodeIntegrityCheck: true,
})
);
async.done(function( data, s, x ){
expect(data).toEqual([{
- msg: 'Memcached is configured as distributed cache, but the wrong PHP module "memcache" is installed. \\OC\\Memcache\\Memcached only supports "memcached" and not "memcache". See the <a href="https://code.google.com/p/memcached/wiki/PHPClientComparison">memcached wiki about both modules</a>.',
+ msg: 'Memcached is configured as distributed cache, but the wrong PHP module "memcache" is installed. \\OC\\Memcache\\Memcached only supports "memcached" and not "memcache". See the <a target="_blank" href="https://code.google.com/p/memcached/wiki/PHPClientComparison">memcached wiki about both modules</a>.',
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
}]);
done();
@@ -229,17 +299,17 @@ describe('OC.SetupChecks tests', function() {
JSON.stringify({
isUrandomAvailable: true,
serverHasInternetConnection: true,
- dataDirectoryProtected: true,
isMemcacheConfigured: true,
forwardedForHeadersWorking: false,
reverseProxyDocs: 'https://docs.owncloud.org/foo/bar.html',
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
async.done(function( data, s, x ){
expect(data).toEqual([{
- msg: 'The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href="https://docs.owncloud.org/foo/bar.html">documentation</a>.',
+ msg: 'The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target="_blank" href="https://docs.owncloud.org/foo/bar.html">documentation</a>.',
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
}]);
done();
@@ -254,7 +324,7 @@ describe('OC.SetupChecks tests', function() {
{
'Content-Type': 'application/json'
},
- JSON.stringify({data: {serverHasInternetConnection: false, dataDirectoryProtected: false}})
+ JSON.stringify({data: {serverHasInternetConnection: false}})
);
async.done(function( data, s, x ){
@@ -278,17 +348,17 @@ describe('OC.SetupChecks tests', function() {
isUrandomAvailable: true,
securityDocs: 'https://docs.owncloud.org/myDocs.html',
serverHasInternetConnection: true,
- dataDirectoryProtected: true,
isMemcacheConfigured: true,
forwardedForHeadersWorking: true,
phpSupported: {eol: true, version: '5.4.0'},
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
async.done(function( data, s, x ){
expect(data).toEqual([{
- msg: 'Your PHP version (5.4.0) is no longer <a href="https://secure.php.net/supported-versions.php">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP.',
+ msg: 'Your PHP version (5.4.0) is no longer <a target="_blank" href="https://secure.php.net/supported-versions.php">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP.',
type: OC.SetupChecks.MESSAGE_TYPE_INFO
}]);
done();
@@ -346,7 +416,14 @@ describe('OC.SetupChecks tests', function() {
}, {
msg: 'The "X-Frame-Options" HTTP header is not configured to equal to "SAMEORIGIN". This is a potential security or privacy risk and we recommend adjusting this setting.',
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
- }]);
+ }, {
+ msg: 'The "X-Download-Options" HTTP header is not configured to equal to "noopen". This is a potential security or privacy risk and we recommend adjusting this setting.',
+ type: OC.SetupChecks.MESSAGE_TYPE_WARNING
+ }, {
+ msg: 'The "X-Permitted-Cross-Domain-Policies" HTTP header is not configured to equal to "none". This is a potential security or privacy risk and we recommend adjusting this setting.',
+ type: OC.SetupChecks.MESSAGE_TYPE_WARNING
+ },
+ ]);
done();
});
});
@@ -360,7 +437,9 @@ describe('OC.SetupChecks tests', function() {
{
'X-Robots-Tag': 'none',
'X-Frame-Options': 'SAMEORIGIN',
- 'Strict-Transport-Security': 'max-age=15768000;preload'
+ 'Strict-Transport-Security': 'max-age=15768000;preload',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
}
);
@@ -387,7 +466,9 @@ describe('OC.SetupChecks tests', function() {
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
'X-Frame-Options': 'SAMEORIGIN',
- 'Strict-Transport-Security': 'max-age=15768000'
+ 'Strict-Transport-Security': 'max-age=15768000',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
}
);
@@ -407,7 +488,9 @@ describe('OC.SetupChecks tests', function() {
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
- 'X-Frame-Options': 'SAMEORIGIN'
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
}
);
@@ -428,7 +511,7 @@ describe('OC.SetupChecks tests', function() {
{
'Content-Type': 'application/json'
},
- JSON.stringify({data: {serverHasInternetConnection: false, dataDirectoryProtected: false}})
+ JSON.stringify({data: {serverHasInternetConnection: false}})
);
async.done(function( data, s, x ){
expect(data).toEqual([{
@@ -451,7 +534,9 @@ describe('OC.SetupChecks tests', function() {
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
- 'X-Frame-Options': 'SAMEORIGIN'
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
}
);
@@ -474,7 +559,9 @@ describe('OC.SetupChecks tests', function() {
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
- 'X-Frame-Options': 'SAMEORIGIN'
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
}
);
@@ -497,7 +584,9 @@ describe('OC.SetupChecks tests', function() {
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
- 'X-Frame-Options': 'SAMEORIGIN'
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
}
);
@@ -519,7 +608,9 @@ describe('OC.SetupChecks tests', function() {
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
- 'X-Frame-Options': 'SAMEORIGIN'
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
});
async.done(function( data, s, x ){
@@ -537,7 +628,9 @@ describe('OC.SetupChecks tests', function() {
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
- 'X-Frame-Options': 'SAMEORIGIN'
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
});
async.done(function( data, s, x ){
@@ -555,7 +648,9 @@ describe('OC.SetupChecks tests', function() {
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
- 'X-Frame-Options': 'SAMEORIGIN'
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
});
async.done(function( data, s, x ){
@@ -573,7 +668,9 @@ describe('OC.SetupChecks tests', function() {
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Robots-Tag': 'none',
- 'X-Frame-Options': 'SAMEORIGIN'
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'X-Download-Options': 'noopen',
+ 'X-Permitted-Cross-Domain-Policies': 'none',
});
async.done(function( data, s, x ){
diff --git a/core/js/tests/specs/sharedialogshareelistview.js b/core/js/tests/specs/sharedialogshareelistview.js
index d468ce790dc..cef97469753 100644
--- a/core/js/tests/specs/sharedialogshareelistview.js
+++ b/core/js/tests/specs/sharedialogshareelistview.js
@@ -27,14 +27,14 @@ describe('OC.Share.ShareDialogShareeListView', function () {
var configModel;
var shareModel;
var listView;
- var setPermissionsStub;
+ var updateShareStub;
beforeEach(function () {
/* jshint camelcase:false */
oldAppConfig = _.extend({}, oc_appconfig.core);
oc_appconfig.core.enforcePasswordForPublicLink = false;
- $('#testArea').append('<input id="mailPublicNotificationEnabled" name="mailPublicNotificationEnabled" type="hidden" value="yes">');
+ $('#testArea').append('<input id="mailNotificationEnabled" name="mailNotificationEnabled" type="hidden" value="yes">');
fileInfoModel = new OCA.Files.FileInfoModel({
id: 123,
@@ -81,7 +81,7 @@ describe('OC.Share.ShareDialogShareeListView', function () {
oldCurrentUser = OC.currentUser;
OC.currentUser = 'user0';
- setPermissionsStub = sinon.stub(listView.model, 'setPermissions');
+ updateShareStub = sinon.stub(OC.Share.ShareItemModel.prototype, 'updateShare');
});
afterEach(function () {
@@ -89,7 +89,7 @@ describe('OC.Share.ShareDialogShareeListView', function () {
/* jshint camelcase:false */
oc_appconfig.core = oldAppConfig;
listView.remove();
- setPermissionsStub.restore();
+ updateShareStub.restore();
});
describe('Manages checkbox events correctly', function () {
@@ -105,7 +105,7 @@ describe('OC.Share.ShareDialogShareeListView', function () {
listView.render();
listView.$el.find("input[name='edit']").click();
expect(listView.$el.find("input[name='update']").is(':checked')).toEqual(true);
- expect(setPermissionsStub.called).toEqual(true);
+ expect(updateShareStub.calledOnce).toEqual(true);
});
it('Checks edit box when create/update/delete are checked', function () {
@@ -120,7 +120,7 @@ describe('OC.Share.ShareDialogShareeListView', function () {
listView.render();
listView.$el.find("input[name='update']").click();
expect(listView.$el.find("input[name='edit']").is(':checked')).toEqual(true);
- expect(setPermissionsStub.called).toEqual(true);
+ expect(updateShareStub.calledOnce).toEqual(true);
});
it('shows cruds checkboxes when toggled', function () {
diff --git a/core/js/tests/specs/sharedialogviewSpec.js b/core/js/tests/specs/sharedialogviewSpec.js
index 6d5243b0e86..6899e625c45 100644
--- a/core/js/tests/specs/sharedialogviewSpec.js
+++ b/core/js/tests/specs/sharedialogviewSpec.js
@@ -28,8 +28,10 @@ describe('OC.Share.ShareDialogView', function() {
var avatarStub;
var placeholderStub;
var oldCurrentUser;
+ var saveLinkShareStub;
var fetchStub;
+ var notificationStub;
var configModel;
var shareModel;
@@ -46,6 +48,7 @@ describe('OC.Share.ShareDialogView', function() {
oc_appconfig.core.enforcePasswordForPublicLink = false;
fetchStub = sinon.stub(OC.Share.ShareItemModel.prototype, 'fetch');
+ saveLinkShareStub = sinon.stub(OC.Share.ShareItemModel.prototype, 'saveLinkShare');
fileInfoModel = new OCA.Files.FileInfoModel({
id: 123,
@@ -116,6 +119,7 @@ describe('OC.Share.ShareDialogView', function() {
dialog.remove();
fetchStub.restore();
+ saveLinkShareStub.restore();
autocompleteStub.restore();
avatarStub.restore();
@@ -128,55 +132,32 @@ describe('OC.Share.ShareDialogView', function() {
it('update password on focus out', function() {
$('#allowShareWithLink').val('yes');
+ dialog.model.set('linkShare', {
+ isLinkShare: true
+ });
dialog.render();
- // Toggle linkshare
- dialog.$el.find('.linkCheckbox').click();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
-
// Enable password, enter password and focusout
dialog.$el.find('[name=showPassword]').click();
dialog.$el.find('.linkPassText').focus();
dialog.$el.find('.linkPassText').val('foo');
dialog.$el.find('.linkPassText').focusout();
- expect(fakeServer.requests[1].method).toEqual('POST');
- var body = OC.parseQueryString(fakeServer.requests[1].requestBody);
- expect(body['shareWith[password]']).toEqual('foo');
- expect(body['shareWith[passwordChanged]']).toEqual('true');
-
- fetchStub.reset();
-
- // Set password response
- fakeServer.requests[1].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
-
- expect(fetchStub.calledOnce).toEqual(true);
- // fetching the model will rerender the view
- dialog.render();
-
- expect(dialog.$el.find('.linkPassText').val()).toEqual('');
- expect(dialog.$el.find('.linkPassText').attr('placeholder')).toEqual('**********');
+ expect(saveLinkShareStub.calledOnce).toEqual(true);
+ expect(saveLinkShareStub.firstCall.args[0]).toEqual({
+ password: 'foo'
+ });
});
it('update password on enter', function() {
$('#allowShareWithLink').val('yes');
+ dialog.model.set('linkShare', {
+ isLinkShare: true
+ });
dialog.render();
// Toggle linkshare
dialog.$el.find('.linkCheckbox').click();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
// Enable password and enter password
dialog.$el.find('[name=showPassword]').click();
@@ -184,26 +165,10 @@ describe('OC.Share.ShareDialogView', function() {
dialog.$el.find('.linkPassText').val('foo');
dialog.$el.find('.linkPassText').trigger(new $.Event('keyup', {keyCode: 13}));
- expect(fakeServer.requests[1].method).toEqual('POST');
- var body = OC.parseQueryString(fakeServer.requests[1].requestBody);
- expect(body['shareWith[password]']).toEqual('foo');
- expect(body['shareWith[passwordChanged]']).toEqual('true');
-
- fetchStub.reset();
-
- // Set password response
- fakeServer.requests[1].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
-
- expect(fetchStub.calledOnce).toEqual(true);
- // fetching the model will rerender the view
- dialog.render();
-
- expect(dialog.$el.find('.linkPassText').val()).toEqual('');
- expect(dialog.$el.find('.linkPassText').attr('placeholder')).toEqual('**********');
+ expect(saveLinkShareStub.calledOnce).toEqual(true);
+ expect(saveLinkShareStub.firstCall.args[0]).toEqual({
+ password: 'foo'
+ });
});
it('shows share with link checkbox when allowed', function() {
$('#allowShareWithLink').val('yes');
@@ -218,6 +183,7 @@ describe('OC.Share.ShareDialogView', function() {
dialog.render();
expect(dialog.$el.find('.linkCheckbox').length).toEqual(0);
+ expect(dialog.$el.find('.shareWithField').length).toEqual(1);
});
it('shows populated link share when a link share exists', function() {
// this is how the OC.Share class does it...
@@ -240,16 +206,11 @@ describe('OC.Share.ShareDialogView', function() {
it('autofocus link text when clicked', function() {
$('#allowShareWithLink').val('yes');
+ dialog.model.set('linkShare', {
+ isLinkShare: true
+ });
dialog.render();
- // Toggle linkshare
- dialog.$el.find('.linkCheckbox').click();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
-
var focusStub = sinon.stub($.fn, 'focus');
var selectStub = sinon.stub($.fn, 'select');
dialog.$el.find('.linkText').click();
@@ -602,105 +563,6 @@ describe('OC.Share.ShareDialogView', function() {
});
});
});
- describe('share permissions', function() {
- beforeEach(function() {
- oc_appconfig.core.resharingAllowed = true;
- });
-
- /**
- * Tests sharing with the given possible permissions
- *
- * @param {int} possiblePermissions
- * @return {int} permissions sent to the server
- */
- function testWithPermissions(possiblePermissions) {
- shareModel.set({
- permissions: possiblePermissions,
- possiblePermissions: possiblePermissions
- });
- dialog.render();
- var autocompleteOptions = autocompleteStub.getCall(0).args[0];
- // simulate autocomplete selection
- autocompleteOptions.select(new $.Event('select'), {
- item: {
- label: 'User Two',
- value: {
- shareType: OC.Share.SHARE_TYPE_USER,
- shareWith: 'user2'
- }
- }
- });
- autocompleteStub.reset();
- var requestBody = OC.parseQueryString(_.last(fakeServer.requests).requestBody);
- return parseInt(requestBody.permissions, 10);
- }
-
- describe('regular sharing', function() {
- it('shares with given permissions with default config', function() {
- shareModel.set({
- reshare: {},
- shares: []
- });
- expect(
- testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
- ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE);
- expect(
- testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_SHARE)
- ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_SHARE);
- });
- it('removes share permission when not allowed', function() {
- configModel.set('isResharingAllowed', false);
- shareModel.set({
- reshare: {},
- shares: []
- });
- expect(
- testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
- ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE);
- });
- it('automatically adds READ permission even when not specified', function() {
- configModel.set('isResharingAllowed', false);
- shareModel.set({
- reshare: {},
- shares: []
- });
- expect(
- testWithPermissions(OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
- ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_UPDATE);
- });
- it('does not show sharing options when sharing not allowed', function() {
- shareModel.set({
- reshare: {},
- shares: [],
- permissions: OC.PERMISSION_READ
- });
- dialog.render();
- expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true);
- });
- it('shows reshare owner', function() {
- shareModel.set({
- reshare: {
- uid_owner: 'user1'
- },
- shares: [],
- permissions: OC.PERMISSION_READ
- });
- dialog.render();
- expect(dialog.$el.find('.resharerInfoView .reshare').length).toEqual(1);
- });
- it('does not show reshare owner if owner is current user', function() {
- shareModel.set({
- reshare: {
- uid_owner: OC.currentUser
- },
- shares: [],
- permissions: OC.PERMISSION_READ
- });
- dialog.render();
- expect(dialog.$el.find('.resharerInfoView .reshare').length).toEqual(0);
- });
- });
- });
describe('remote sharing', function() {
it('shows remote share info when allowed', function() {
configModel.set({
@@ -723,23 +585,336 @@ describe('OC.Share.ShareDialogView', function() {
var response = sinon.stub();
dialog.autocompleteHandler({term: 'bob'}, response);
var jsonData = JSON.stringify({
- "data": [{"label": "bob", "value": {"shareType": 0, "shareWith": "test"}}],
- "status": "success"
+ 'ocs' : {
+ 'meta' : {
+ 'status' : 'success',
+ 'statuscode' : 100,
+ 'message' : null
+ },
+ 'data' : {
+ 'exact' : {
+ 'users' : [],
+ 'groups' : [],
+ 'remotes': []
+ },
+ 'users' : [{'label': 'bob', 'value': {'shareType': 0, 'shareWith': 'test'}}],
+ 'groups' : [],
+ 'remotes': []
+ }
+ }
});
fakeServer.requests[0].respond(
200,
{'Content-Type': 'application/json'},
jsonData
);
- expect(response.calledWithExactly(JSON.parse(jsonData).data)).toEqual(true);
+ expect(response.calledWithExactly(JSON.parse(jsonData).ocs.data.users)).toEqual(true);
expect(autocompleteStub.calledWith("option", "autoFocus", true)).toEqual(true);
});
+ describe('filter out', function() {
+ it('the current user', function () {
+ dialog.render();
+ var response = sinon.stub();
+ dialog.autocompleteHandler({term: 'bob'}, response);
+ var jsonData = JSON.stringify({
+ 'ocs': {
+ 'meta': {
+ 'status': 'success',
+ 'statuscode': 100,
+ 'message': null
+ },
+ 'data': {
+ 'exact': {
+ 'users': [],
+ 'groups': [],
+ 'remotes': []
+ },
+ 'users': [
+ {
+ 'label': 'bob',
+ 'value': {
+ 'shareType': 0,
+ 'shareWith': OC.currentUser
+ }
+ },
+ {
+ 'label': 'bobby',
+ 'value': {
+ 'shareType': 0,
+ 'shareWith': 'imbob'
+ }
+ }
+ ],
+ 'groups': [],
+ 'remotes': []
+ }
+ }
+ });
+ fakeServer.requests[0].respond(
+ 200,
+ {'Content-Type': 'application/json'},
+ jsonData
+ );
+ expect(response.calledWithExactly([{
+ 'label': 'bobby',
+ 'value': {'shareType': 0, 'shareWith': 'imbob'}
+ }])).toEqual(true);
+ expect(autocompleteStub.calledWith("option", "autoFocus", true)).toEqual(true);
+ });
+
+ it('the share owner', function () {
+ shareModel.set({
+ reshare: {
+ uid_owner: 'user1'
+ },
+ shares: [],
+ permissions: OC.PERMISSION_READ
+ });
+
+ dialog.render();
+ var response = sinon.stub();
+ dialog.autocompleteHandler({term: 'bob'}, response);
+ var jsonData = JSON.stringify({
+ 'ocs': {
+ 'meta': {
+ 'status': 'success',
+ 'statuscode': 100,
+ 'message': null
+ },
+ 'data': {
+ 'exact': {
+ 'users': [],
+ 'groups': [],
+ 'remotes': []
+ },
+ 'users': [
+ {
+ 'label': 'bob',
+ 'value': {
+ 'shareType': 0,
+ 'shareWith': 'user1'
+ }
+ },
+ {
+ 'label': 'bobby',
+ 'value': {
+ 'shareType': 0,
+ 'shareWith': 'imbob'
+ }
+ }
+ ],
+ 'groups': [],
+ 'remotes': []
+ }
+ }
+ });
+ fakeServer.requests[0].respond(
+ 200,
+ {'Content-Type': 'application/json'},
+ jsonData
+ );
+ expect(response.calledWithExactly([{
+ 'label': 'bobby',
+ 'value': {'shareType': 0, 'shareWith': 'imbob'}
+ }])).toEqual(true);
+ expect(autocompleteStub.calledWith("option", "autoFocus", true)).toEqual(true);
+ });
+
+ describe('already shared with', function () {
+ beforeEach(function() {
+ shareModel.set({
+ reshare: {},
+ shares: [{
+ id: 100,
+ item_source: 123,
+ permissions: 31,
+ share_type: OC.Share.SHARE_TYPE_USER,
+ share_with: 'user1',
+ share_with_displayname: 'User One'
+ },{
+ id: 101,
+ item_source: 123,
+ permissions: 31,
+ share_type: OC.Share.SHARE_TYPE_GROUP,
+ share_with: 'group',
+ share_with_displayname: 'group'
+ },{
+ id: 102,
+ item_source: 123,
+ permissions: 31,
+ share_type: OC.Share.SHARE_TYPE_REMOTE,
+ share_with: 'foo@bar.com/baz',
+ share_with_displayname: 'foo@bar.com/baz'
+
+ }]
+ });
+ });
+
+ it('users', function () {
+ dialog.render();
+ var response = sinon.stub();
+ dialog.autocompleteHandler({term: 'bob'}, response);
+ var jsonData = JSON.stringify({
+ 'ocs': {
+ 'meta': {
+ 'status': 'success',
+ 'statuscode': 100,
+ 'message': null
+ },
+ 'data': {
+ 'exact': {
+ 'users': [],
+ 'groups': [],
+ 'remotes': []
+ },
+ 'users': [
+ {
+ 'label': 'bob',
+ 'value': {
+ 'shareType': OC.Share.SHARE_TYPE_USER,
+ 'shareWith': 'user1'
+ }
+ },
+ {
+ 'label': 'bobby',
+ 'value': {
+ 'shareType': OC.Share.SHARE_TYPE_USER,
+ 'shareWith': 'imbob'
+ }
+ }
+ ],
+ 'groups': [],
+ 'remotes': []
+ }
+ }
+ });
+ fakeServer.requests[0].respond(
+ 200,
+ {'Content-Type': 'application/json'},
+ jsonData
+ );
+ expect(response.calledWithExactly([{
+ 'label': 'bobby',
+ 'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'imbob'}
+ }])).toEqual(true);
+ expect(autocompleteStub.calledWith("option", "autoFocus", true)).toEqual(true);
+ });
+
+ it('groups', function () {
+ dialog.render();
+ var response = sinon.stub();
+ dialog.autocompleteHandler({term: 'group'}, response);
+ var jsonData = JSON.stringify({
+ 'ocs': {
+ 'meta': {
+ 'status': 'success',
+ 'statuscode': 100,
+ 'message': null
+ },
+ 'data': {
+ 'exact': {
+ 'users': [],
+ 'groups': [],
+ 'remotes': []
+ },
+ 'users': [],
+ 'groups': [
+ {
+ 'label': 'group',
+ 'value': {
+ 'shareType': OC.Share.SHARE_TYPE_GROUP,
+ 'shareWith': 'group'
+ }
+ },
+ {
+ 'label': 'group2',
+ 'value': {
+ 'shareType': OC.Share.SHARE_TYPE_GROUP,
+ 'shareWith': 'group2'
+ }
+ }
+ ],
+ 'remotes': []
+ }
+ }
+ });
+ fakeServer.requests[0].respond(
+ 200,
+ {'Content-Type': 'application/json'},
+ jsonData
+ );
+ expect(response.calledWithExactly([{
+ 'label': 'group2',
+ 'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'group2'}
+ }])).toEqual(true);
+ expect(autocompleteStub.calledWith("option", "autoFocus", true)).toEqual(true);
+ });
+
+ it('remotes', function () {
+ dialog.render();
+ var response = sinon.stub();
+ dialog.autocompleteHandler({term: 'bob'}, response);
+ var jsonData = JSON.stringify({
+ 'ocs': {
+ 'meta': {
+ 'status': 'success',
+ 'statuscode': 100,
+ 'message': null
+ },
+ 'data': {
+ 'exact': {
+ 'users': [],
+ 'groups': [],
+ 'remotes': []
+ },
+ 'users': [],
+ 'groups': [],
+ 'remotes': [
+ {
+ 'label': 'foo@bar.com/baz',
+ 'value': {
+ 'shareType': OC.Share.SHARE_TYPE_REMOTE,
+ 'shareWith': 'foo@bar.com/baz'
+ }
+ },
+ {
+ 'label': 'foo2@bar.com/baz',
+ 'value': {
+ 'shareType': OC.Share.SHARE_TYPE_REMOTE,
+ 'shareWith': 'foo2@bar.com/baz'
+ }
+ }
+ ]
+ }
+ }
+ });
+ fakeServer.requests[0].respond(
+ 200,
+ {'Content-Type': 'application/json'},
+ jsonData
+ );
+ expect(response.calledWithExactly([{
+ 'label': 'foo2@bar.com/baz',
+ 'value': {'shareType': OC.Share.SHARE_TYPE_REMOTE, 'shareWith': 'foo2@bar.com/baz'}
+ }])).toEqual(true);
+ expect(autocompleteStub.calledWith("option", "autoFocus", true)).toEqual(true);
+ });
+ });
+ });
+
it('gracefully handles successful ajax call with failure content', function () {
dialog.render();
var response = sinon.stub();
dialog.autocompleteHandler({term: 'bob'}, response);
- var jsonData = JSON.stringify({"status": "failure"});
+ var jsonData = JSON.stringify({
+ 'ocs' : {
+ 'meta' : {
+ 'status': 'failure',
+ 'statuscode': 400
+ }
+ }
+ });
fakeServer.requests[0].respond(
200,
{'Content-Type': 'application/json'},
@@ -778,5 +953,61 @@ describe('OC.Share.ShareDialogView', function() {
expect(el.hasClass('user')).toEqual(true);
});
});
+
+ it('calls addShare after selection', function() {
+ dialog.render();
+ var addShareStub = sinon.stub(shareModel, 'addShare');
+ var autocompleteOptions = autocompleteStub.getCall(0).args[0];
+ autocompleteOptions.select(new $.Event('select'), {
+ item: {
+ label: 'User Two',
+ value: {
+ shareType: OC.Share.SHARE_TYPE_USER,
+ shareWith: 'user2'
+ }
+ }
+ });
+
+ expect(addShareStub.calledOnce).toEqual(true);
+ expect(addShareStub.firstCall.args[0]).toEqual({
+ shareType: OC.Share.SHARE_TYPE_USER,
+ shareWith: 'user2'
+ });
+
+ addShareStub.restore();
+ });
+ });
+ describe('reshare permissions', function() {
+ it('does not show sharing options when sharing not allowed', function() {
+ shareModel.set({
+ reshare: {},
+ shares: [],
+ permissions: OC.PERMISSION_READ
+ });
+ dialog.render();
+ expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true);
+ });
+ it('shows reshare owner', function() {
+ shareModel.set({
+ reshare: {
+ uid_owner: 'user1'
+ },
+ shares: [],
+ permissions: OC.PERMISSION_READ
+ });
+ dialog.render();
+ expect(dialog.$el.find('.resharerInfoView .reshare').length).toEqual(1);
+ });
+ it('does not show reshare owner if owner is current user', function() {
+ shareModel.set({
+ reshare: {
+ uid_owner: OC.currentUser
+ },
+ shares: [],
+ permissions: OC.PERMISSION_READ
+ });
+ dialog.render();
+ expect(dialog.$el.find('.resharerInfoView .reshare').length).toEqual(0);
+ });
});
});
diff --git a/core/js/tests/specs/shareitemmodelSpec.js b/core/js/tests/specs/shareitemmodelSpec.js
index 28daf860393..b2480a8beaa 100644
--- a/core/js/tests/specs/shareitemmodelSpec.js
+++ b/core/js/tests/specs/shareitemmodelSpec.js
@@ -21,14 +21,20 @@
/* global oc_appconfig */
describe('OC.Share.ShareItemModel', function() {
- var loadItemStub;
+ var fetchSharesStub, fetchReshareStub;
+ var fetchSharesDeferred, fetchReshareDeferred;
var fileInfoModel, configModel, model;
var oldCurrentUser;
beforeEach(function() {
oldCurrentUser = OC.currentUser;
- loadItemStub = sinon.stub(OC.Share, 'loadItem');
+ fetchSharesDeferred = new $.Deferred();
+ fetchSharesStub = sinon.stub(OC.Share.ShareItemModel.prototype, '_fetchShares')
+ .returns(fetchSharesDeferred.promise());
+ fetchReshareDeferred = new $.Deferred();
+ fetchReshareStub = sinon.stub(OC.Share.ShareItemModel.prototype, '_fetchReshare')
+ .returns(fetchReshareDeferred.promise());
fileInfoModel = new OCA.Files.FileInfoModel({
id: 123,
@@ -52,27 +58,70 @@ describe('OC.Share.ShareItemModel', function() {
});
});
afterEach(function() {
- loadItemStub.restore();
+ if (fetchSharesStub) {
+ fetchSharesStub.restore();
+ }
+ if (fetchReshareStub) {
+ fetchReshareStub.restore();
+ }
OC.currentUser = oldCurrentUser;
});
+ function makeOcsResponse(data) {
+ return [{
+ ocs: {
+ data: data
+ }
+ }];
+ }
+
describe('Fetching and parsing', function() {
- it('fetching calls loadItem with the correct arguments', function() {
+ it('fetches both outgoing shares and the current incoming share', function() {
model.fetch();
- expect(loadItemStub.calledOnce).toEqual(true);
- expect(loadItemStub.calledWith('file', 123)).toEqual(true);
+ expect(fetchSharesStub.calledOnce).toEqual(true);
+ expect(fetchReshareStub.calledOnce).toEqual(true);
+ });
+ it('fetches shares for the current path', function() {
+ fetchSharesStub.restore();
+
+ model._fetchShares();
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('GET');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares?format=json&path=%2Fsubdir%2Fshared_file_name.txt&reshares=true'
+ );
+
+ fetchSharesStub = null;
+ });
+ it('fetches reshare for the current path', function() {
+ fetchReshareStub.restore();
+
+ model._fetchReshare();
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('GET');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares?format=json&path=%2Fsubdir%2Fshared_file_name.txt&shared_with_me=true'
+ );
+
+ fetchReshareStub = null;
});
it('populates attributes with parsed response', function() {
- loadItemStub.yields({
- /* jshint camelcase: false */
- reshare: {
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([
+ {
share_type: OC.Share.SHARE_TYPE_USER,
uid_owner: 'owner',
displayname_owner: 'Owner',
permissions: 31
- },
- shares: [{
+ }
+ ]));
+ fetchSharesDeferred.resolve(makeOcsResponse([
+ {
id: 100,
item_source: 123,
permissions: 31,
@@ -112,8 +161,9 @@ describe('OC.Share.ShareItemModel', function() {
storage: 1,
token: 'tehtoken',
uid_owner: 'root'
- }]
- });
+ }
+ ]));
+
model.fetch();
var shares = model.get('shares');
@@ -130,10 +180,9 @@ describe('OC.Share.ShareItemModel', function() {
// TODO: check more attributes
});
it('does not parse link share when for a different file', function() {
- loadItemStub.yields({
- reshare: [],
- /* jshint camelcase: false */
- shares: [{
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
displayname_owner: 'root',
expiration: null,
file_source: 456,
@@ -152,7 +201,7 @@ describe('OC.Share.ShareItemModel', function() {
token: 'tehtoken',
uid_owner: 'root'
}]
- });
+ ));
model.fetch();
@@ -164,10 +213,9 @@ describe('OC.Share.ShareItemModel', function() {
expect(linkShare.isLinkShare).toEqual(false);
});
it('parses correct link share when a nested link share exists along with parent one', function() {
- loadItemStub.yields({
- reshare: [],
- /* jshint camelcase: false */
- shares: [{
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
displayname_owner: 'root',
expiration: '2015-10-12 00:00:00',
file_source: 123,
@@ -204,7 +252,7 @@ describe('OC.Share.ShareItemModel', function() {
token: 'anothertoken',
uid_owner: 'root'
}]
- });
+ ));
model.fetch();
@@ -219,26 +267,26 @@ describe('OC.Share.ShareItemModel', function() {
// TODO: check child too
});
it('reduces reshare permissions to the ones from the original share', function() {
- loadItemStub.yields({
- reshare: {
- permissions: OC.PERMISSION_READ,
- uid_owner: 'user1'
- },
- shares: []
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([{
+ id: 123,
+ permissions: OC.PERMISSION_READ,
+ uid_owner: 'user1'
+ }]));
+ fetchSharesDeferred.resolve(makeOcsResponse([]));
model.fetch();
// no resharing allowed
expect(model.get('permissions')).toEqual(OC.PERMISSION_READ);
});
it('reduces reshare permissions to possible permissions', function() {
- loadItemStub.yields({
- reshare: {
- permissions: OC.PERMISSION_ALL,
- uid_owner: 'user1'
- },
- shares: []
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([{
+ id: 123,
+ permissions: OC.PERMISSION_ALL,
+ uid_owner: 'user1'
+ }]));
+ fetchSharesDeferred.resolve(makeOcsResponse([]));
model.set('possiblePermissions', OC.PERMISSION_READ);
model.fetch();
@@ -248,10 +296,8 @@ describe('OC.Share.ShareItemModel', function() {
});
it('allows owner to share their own share when they are also the recipient', function() {
OC.currentUser = 'user1';
- loadItemStub.yields({
- reshare: {},
- shares: []
- });
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([]));
model.fetch();
@@ -259,9 +305,9 @@ describe('OC.Share.ShareItemModel', function() {
expect(model.get('permissions') & OC.PERMISSION_SHARE).toEqual(OC.PERMISSION_SHARE);
});
it('properly parses integer values when the server is in the mood of returning ints as string', function() {
- loadItemStub.yields({
- reshare: {},
- shares: [{
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
displayname_owner: 'root',
expiration: '2015-10-12 00:00:00',
file_source: '123',
@@ -280,7 +326,7 @@ describe('OC.Share.ShareItemModel', function() {
token: 'tehtoken',
uid_owner: 'root'
}]
- });
+ ));
model.fetch();
@@ -306,55 +352,50 @@ describe('OC.Share.ShareItemModel', function() {
});
describe('hasUserShares', function() {
it('returns false when no user shares exist', function() {
- loadItemStub.yields({
- reshare: {},
- shares: []
- });
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([]));
model.fetch();
expect(model.hasUserShares()).toEqual(false);
});
it('returns true when user shares exist on the current item', function() {
- loadItemStub.yields({
- reshare: {},
- shares: [{
- id: 1,
- share_type: OC.Share.SHARE_TYPE_USER,
- share_with: 'user1',
- item_source: '123'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ id: 1,
+ share_type: OC.Share.SHARE_TYPE_USER,
+ share_with: 'user1',
+ item_source: '123'
+ }]));
model.fetch();
expect(model.hasUserShares()).toEqual(true);
});
it('returns true when group shares exist on the current item', function() {
- loadItemStub.yields({
- reshare: {},
- shares: [{
- id: 1,
- share_type: OC.Share.SHARE_TYPE_GROUP,
- share_with: 'group1',
- item_source: '123'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ id: 1,
+ share_type: OC.Share.SHARE_TYPE_GROUP,
+ share_with: 'group1',
+ item_source: '123'
+ }]));
model.fetch();
expect(model.hasUserShares()).toEqual(true);
});
it('returns false when share exist on parent item', function() {
- loadItemStub.yields({
- reshare: {},
- shares: [{
- id: 1,
- share_type: OC.Share.SHARE_TYPE_GROUP,
- share_with: 'group1',
- item_source: '111'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ id: 1,
+ share_type: OC.Share.SHARE_TYPE_GROUP,
+ share_with: 'group1',
+ item_source: '111'
+ }]));
model.fetch();
@@ -381,27 +422,28 @@ describe('OC.Share.ShareItemModel', function() {
describe('sendEmailPrivateLink', function() {
it('succeeds', function() {
- loadItemStub.yields({
- shares: [{
- displayname_owner: 'root',
- expiration: null,
- file_source: 123,
- file_target: '/folder',
- id: 20,
- item_source: '123',
- item_type: 'folder',
- mail_send: '0',
- parent: null,
- path: '/folder',
- permissions: OC.PERMISSION_READ,
- share_type: OC.Share.SHARE_TYPE_LINK,
- share_with: null,
- stime: 1403884258,
- storage: 1,
- token: 'tehtoken',
- uid_owner: 'root'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ displayname_owner: 'root',
+ expiration: null,
+ file_source: 123,
+ file_target: '/folder',
+ id: 20,
+ item_source: '123',
+ item_type: 'folder',
+ mail_send: '0',
+ parent: null,
+ path: '/folder',
+ permissions: OC.PERMISSION_READ,
+ share_type: OC.Share.SHARE_TYPE_LINK,
+ share_with: null,
+ stime: 1403884258,
+ storage: 1,
+ token: 'tehtoken',
+ uid_owner: 'root'
+ }]));
+
model.fetch();
var res = model.sendEmailPrivateLink('foo@bar.com');
@@ -430,27 +472,28 @@ describe('OC.Share.ShareItemModel', function() {
});
it('fails', function() {
- loadItemStub.yields({
- shares: [{
- displayname_owner: 'root',
- expiration: null,
- file_source: 123,
- file_target: '/folder',
- id: 20,
- item_source: '123',
- item_type: 'folder',
- mail_send: '0',
- parent: null,
- path: '/folder',
- permissions: OC.PERMISSION_READ,
- share_type: OC.Share.SHARE_TYPE_LINK,
- share_with: null,
- stime: 1403884258,
- storage: 1,
- token: 'tehtoken',
- uid_owner: 'root'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ displayname_owner: 'root',
+ expiration: null,
+ file_source: 123,
+ file_target: '/folder',
+ id: 20,
+ item_source: '123',
+ item_type: 'folder',
+ mail_send: '0',
+ parent: null,
+ path: '/folder',
+ permissions: OC.PERMISSION_READ,
+ share_type: OC.Share.SHARE_TYPE_LINK,
+ share_with: null,
+ stime: 1403884258,
+ storage: 1,
+ token: 'tehtoken',
+ uid_owner: 'root'
+ }]));
+
model.fetch();
var res = model.sendEmailPrivateLink('foo@bar.com');
@@ -478,5 +521,306 @@ describe('OC.Share.ShareItemModel', function() {
expect(res.state()).toEqual('rejected');
});
});
+ describe('share permissions', function() {
+ beforeEach(function() {
+ oc_appconfig.core.resharingAllowed = true;
+ });
+
+ /**
+ * Tests sharing with the given possible permissions
+ *
+ * @param {int} possiblePermissions
+ * @return {int} permissions sent to the server
+ */
+ function testWithPermissions(possiblePermissions) {
+ model.set({
+ permissions: possiblePermissions,
+ possiblePermissions: possiblePermissions
+ });
+ model.addShare({
+ shareType: OC.Share.SHARE_TYPE_USER,
+ shareWith: 'user2'
+ });
+
+ var requestBody = OC.parseQueryString(_.last(fakeServer.requests).requestBody);
+ return parseInt(requestBody.permissions, 10);
+ }
+
+ describe('regular sharing', function() {
+ it('shares with given permissions with default config', function() {
+ configModel.set('isResharingAllowed', true);
+ model.set({
+ reshare: {},
+ shares: []
+ });
+ expect(
+ testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
+ ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE);
+ expect(
+ testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_SHARE)
+ ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_SHARE);
+ });
+ it('removes share permission when not allowed', function() {
+ configModel.set('isResharingAllowed', false);
+ model.set({
+ reshare: {},
+ shares: []
+ });
+ expect(
+ testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
+ ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE);
+ });
+ it('automatically adds READ permission even when not specified', function() {
+ configModel.set('isResharingAllowed', false);
+ model.set({
+ reshare: {},
+ shares: []
+ });
+ expect(
+ testWithPermissions(OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
+ ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_UPDATE);
+ });
+ });
+ });
+
+ describe('saveLinkShare', function() {
+ var addShareStub;
+ var updateShareStub;
+
+ beforeEach(function() {
+ addShareStub = sinon.stub(model, 'addShare');
+ updateShareStub = sinon.stub(model, 'updateShare');
+ });
+ afterEach(function() {
+ addShareStub.restore();
+ updateShareStub.restore();
+ });
+
+ it('creates a new share if no link share exists', function() {
+ model.set({
+ linkShare: {
+ isLinkShare: false
+ }
+ });
+
+ model.saveLinkShare();
+
+ expect(addShareStub.calledOnce).toEqual(true);
+ expect(addShareStub.firstCall.args[0]).toEqual({
+ password: '',
+ passwordChanged: false,
+ permissions: OC.PERMISSION_READ,
+ expireDate: '',
+ shareType: OC.Share.SHARE_TYPE_LINK
+ });
+ expect(updateShareStub.notCalled).toEqual(true);
+ });
+ it('creates a new share with default expiration date', function() {
+ var clock = sinon.useFakeTimers(Date.UTC(2015, 6, 17, 1, 2, 0, 3));
+ configModel.set({
+ isDefaultExpireDateEnabled: true,
+ defaultExpireDate: 7
+ });
+ model.set({
+ linkShare: {
+ isLinkShare: false
+ }
+ });
+
+ model.saveLinkShare();
+
+ expect(addShareStub.calledOnce).toEqual(true);
+ expect(addShareStub.firstCall.args[0]).toEqual({
+ password: '',
+ passwordChanged: false,
+ permissions: OC.PERMISSION_READ,
+ expireDate: '2015-07-24 00:00:00',
+ shareType: OC.Share.SHARE_TYPE_LINK
+ });
+ expect(updateShareStub.notCalled).toEqual(true);
+ clock.restore();
+ });
+ it('updates link share if it exists', function() {
+ model.set({
+ linkShare: {
+ isLinkShare: true,
+ id: 123
+ }
+ });
+
+ model.saveLinkShare({
+ password: 'test'
+ });
+
+ expect(addShareStub.notCalled).toEqual(true);
+ expect(updateShareStub.calledOnce).toEqual(true);
+ expect(updateShareStub.firstCall.args[0]).toEqual(123);
+ expect(updateShareStub.firstCall.args[1]).toEqual({
+ password: 'test'
+ });
+ });
+ it('forwards error message on add', function() {
+ var errorStub = sinon.stub();
+ model.set({
+ linkShare: {
+ isLinkShare: false
+ }
+ }, {
+ });
+
+ model.saveLinkShare({
+ password: 'test'
+ }, {
+ error: errorStub
+ });
+
+ addShareStub.yieldTo('error', 'Some error message');
+
+ expect(errorStub.calledOnce).toEqual(true);
+ expect(errorStub.lastCall.args[0]).toEqual('Some error message');
+ });
+ it('forwards error message on update', function() {
+ var errorStub = sinon.stub();
+ model.set({
+ linkShare: {
+ isLinkShare: true,
+ id: '123'
+ }
+ }, {
+ });
+
+ model.saveLinkShare({
+ password: 'test'
+ }, {
+ error: errorStub
+ });
+
+ updateShareStub.yieldTo('error', 'Some error message');
+
+ expect(errorStub.calledOnce).toEqual(true);
+ expect(errorStub.lastCall.args[0]).toEqual('Some error message');
+ });
+ });
+ describe('creating shares', function() {
+ it('sends POST method to endpoint with passed values', function() {
+ model.addShare({
+ shareType: OC.Share.SHARE_TYPE_GROUP,
+ shareWith: 'group1'
+ });
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('POST');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares?format=json'
+ );
+ expect(OC.parseQueryString(fakeServer.requests[0].requestBody)).toEqual({
+ path: '/subdir/shared_file_name.txt',
+ permissions: '' + OC.PERMISSION_READ,
+ shareType: '' + OC.Share.SHARE_TYPE_GROUP,
+ shareWith: 'group1'
+ });
+ });
+ it('calls error handler with error message', function() {
+ var errorStub = sinon.stub();
+ model.addShare({
+ shareType: OC.Share.SHARE_TYPE_GROUP,
+ shareWith: 'group1'
+ }, {
+ error: errorStub
+ });
+
+ expect(fakeServer.requests.length).toEqual(1);
+ fakeServer.requests[0].respond(
+ 400,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({
+ ocs: {
+ meta: {
+ message: 'Some error message'
+ }
+ }
+ })
+ );
+
+ expect(errorStub.calledOnce).toEqual(true);
+ expect(errorStub.lastCall.args[1]).toEqual('Some error message');
+ });
+ });
+ describe('updating shares', function() {
+ it('sends PUT method to endpoint with passed values', function() {
+ model.updateShare(123, {
+ permissions: OC.PERMISSION_READ | OC.PERMISSION_SHARE
+ });
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('PUT');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares/123?format=json'
+ );
+ expect(OC.parseQueryString(fakeServer.requests[0].requestBody)).toEqual({
+ permissions: '' + (OC.PERMISSION_READ | OC.PERMISSION_SHARE)
+ });
+ });
+ it('calls error handler with error message', function() {
+ var errorStub = sinon.stub();
+ model.updateShare(123, {
+ permissions: OC.PERMISSION_READ | OC.PERMISSION_SHARE
+ }, {
+ error: errorStub
+ });
+
+ expect(fakeServer.requests.length).toEqual(1);
+ fakeServer.requests[0].respond(
+ 400,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({
+ ocs: {
+ meta: {
+ message: 'Some error message'
+ }
+ }
+ })
+ );
+
+ expect(errorStub.calledOnce).toEqual(true);
+ expect(errorStub.lastCall.args[1]).toEqual('Some error message');
+ });
+ });
+ describe('removing shares', function() {
+ it('sends DELETE method to endpoint with share id', function() {
+ model.removeShare(123);
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('DELETE');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares/123?format=json'
+ );
+ });
+ it('calls error handler with error message', function() {
+ var errorStub = sinon.stub();
+ model.removeShare(123, {
+ error: errorStub
+ });
+
+ expect(fakeServer.requests.length).toEqual(1);
+ fakeServer.requests[0].respond(
+ 400,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({
+ ocs: {
+ meta: {
+ message: 'Some error message'
+ }
+ }
+ })
+ );
+
+ expect(errorStub.calledOnce).toEqual(true);
+ expect(errorStub.lastCall.args[1]).toEqual('Some error message');
+ });
+ });
});
diff --git a/core/js/tests/specs/systemtags/systemtagsSpec.js b/core/js/tests/specs/systemtags/systemtagsSpec.js
new file mode 100644
index 00000000000..515b75258a0
--- /dev/null
+++ b/core/js/tests/specs/systemtags/systemtagsSpec.js
@@ -0,0 +1,69 @@
+/**
+* ownCloud
+*
+* @author Joas Schilling
+* @copyright 2016 Joas Schilling <nickvergessen@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+describe('OC.SystemTags tests', function() {
+ it('describes non existing tag', function() {
+ var $return = OC.SystemTags.getDescriptiveTag('23');
+ expect($return.text()).toEqual('Non-existing tag #23');
+ expect($return.hasClass('non-existing-tag')).toEqual(true);
+ });
+
+ it('describes SystemTagModel', function() {
+ var tag = new OC.SystemTags.SystemTagModel({
+ id: 23,
+ name: 'Twenty Three',
+ userAssignable: true,
+ userVisible: true
+ });
+ var $return = OC.SystemTags.getDescriptiveTag(tag);
+ expect($return.text()).toEqual('Twenty Three');
+ expect($return.hasClass('non-existing-tag')).toEqual(false);
+ });
+
+ it('describes JSON tag object', function() {
+ var $return = OC.SystemTags.getDescriptiveTag({
+ id: 42,
+ name: 'Fourty Two',
+ userAssignable: true,
+ userVisible: true
+ });
+ expect($return.text()).toEqual('Fourty Two');
+ expect($return.hasClass('non-existing-tag')).toEqual(false);
+ });
+
+ it('scope', function() {
+ function testScope(userVisible, userAssignable, expectedText) {
+ var $return = OC.SystemTags.getDescriptiveTag({
+ id: 42,
+ name: 'Fourty Two',
+ userAssignable: userAssignable,
+ userVisible: userVisible
+ });
+ expect($return.text()).toEqual(expectedText);
+ expect($return.hasClass('non-existing-tag')).toEqual(false);
+ }
+
+ testScope(true, true, 'Fourty Two');
+ testScope(false, true, 'Fourty Two (invisible)');
+ testScope(false, false, 'Fourty Two (invisible)');
+ testScope(true, false, 'Fourty Two (not assignable)');
+ });
+});
diff --git a/core/js/tests/specs/systemtags/systemtagscollectionSpec.js b/core/js/tests/specs/systemtags/systemtagscollectionSpec.js
new file mode 100644
index 00000000000..6f2d8361754
--- /dev/null
+++ b/core/js/tests/specs/systemtags/systemtagscollectionSpec.js
@@ -0,0 +1,84 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2016 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+describe('OC.SystemTags.SystemTagsCollection tests', function() {
+ var collection;
+
+ beforeEach(function() {
+ collection = new OC.SystemTags.SystemTagsCollection();
+ });
+ it('fetches only once, until reset', function() {
+ var syncStub = sinon.stub(collection, 'sync');
+ var callback = sinon.stub();
+ var callback2 = sinon.stub();
+ var callback3 = sinon.stub();
+ var eventHandler = sinon.stub();
+
+ collection.on('sync', eventHandler);
+
+ collection.fetch({
+ success: callback
+ });
+
+ expect(callback.notCalled).toEqual(true);
+ expect(syncStub.calledOnce).toEqual(true);
+ expect(eventHandler.notCalled).toEqual(true);
+
+ syncStub.yieldTo('success', collection);
+
+ expect(callback.calledOnce).toEqual(true);
+ expect(callback.firstCall.args[0]).toEqual(collection);
+ expect(eventHandler.calledOnce).toEqual(true);
+ expect(eventHandler.firstCall.args[0]).toEqual(collection);
+
+ collection.fetch({
+ success: callback2
+ });
+
+ expect(eventHandler.calledTwice).toEqual(true);
+ expect(eventHandler.secondCall.args[0]).toEqual(collection);
+
+ // not re-called
+ expect(syncStub.calledOnce).toEqual(true);
+
+ expect(callback.calledOnce).toEqual(true);
+ expect(callback2.calledOnce).toEqual(true);
+ expect(callback2.firstCall.args[0]).toEqual(collection);
+
+ expect(collection.fetched).toEqual(true);
+
+ collection.reset();
+
+ expect(collection.fetched).toEqual(false);
+
+ collection.fetch({
+ success: callback3
+ });
+
+ expect(syncStub.calledTwice).toEqual(true);
+
+ syncStub.yieldTo('success', collection);
+ expect(callback3.calledOnce).toEqual(true);
+ expect(callback3.firstCall.args[0]).toEqual(collection);
+
+ syncStub.restore();
+ });
+});
diff --git a/core/js/tests/specs/systemtags/systemtagsinputfieldSpec.js b/core/js/tests/specs/systemtags/systemtagsinputfieldSpec.js
new file mode 100644
index 00000000000..08470fbdd8a
--- /dev/null
+++ b/core/js/tests/specs/systemtags/systemtagsinputfieldSpec.js
@@ -0,0 +1,476 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2016 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+describe('OC.SystemTags.SystemTagsInputField tests', function() {
+ var view, select2Stub;
+
+ beforeEach(function() {
+ var $container = $('<div class="testInputContainer"></div>');
+ select2Stub = sinon.stub($.fn, 'select2');
+ select2Stub.returnsThis();
+ $('#testArea').append($container);
+ });
+ afterEach(function() {
+ select2Stub.restore();
+ OC.SystemTags.collection.reset();
+ view.remove();
+ view = undefined;
+ });
+
+ describe('general behavior', function() {
+ var $dropdown;
+
+ beforeEach(function() {
+ view = new OC.SystemTags.SystemTagsInputField();
+ $('.testInputContainer').append(view.$el);
+ $dropdown = $('<div class="select2-dropdown"></div>');
+ select2Stub.withArgs('dropdown').returns($dropdown);
+ $('#testArea').append($dropdown);
+
+ view.render();
+ });
+ describe('rendering', function() {
+ it('calls select2 on rendering', function() {
+ expect(view.$el.find('input[name=tags]').length).toEqual(1);
+ expect(select2Stub.called).toEqual(true);
+ });
+ it('formatResult renders rename button', function() {
+ var opts = select2Stub.getCall(0).args[0];
+ var $el = $(opts.formatResult({id: '1', name: 'test'}));
+ expect($el.find('.rename').length).toEqual(1);
+ });
+ });
+ describe('tag selection', function() {
+ beforeEach(function() {
+ var $el = view.$el.find('input');
+ $el.val('1');
+
+ view.collection.add([
+ new OC.SystemTags.SystemTagModel({id: '1', name: 'abc'}),
+ new OC.SystemTags.SystemTagModel({id: '2', name: 'def'}),
+ new OC.SystemTags.SystemTagModel({id: '3', name: 'abd', userAssignable: false}),
+ ]);
+ });
+ it('does not create dummy tag when user types non-matching name', function() {
+ var opts = select2Stub.getCall(0).args[0];
+ var result = opts.createSearchChoice('abc');
+ expect(result).not.toBeDefined();
+ });
+ it('creates dummy tag when user types non-matching name', function() {
+ var opts = select2Stub.getCall(0).args[0];
+ var result = opts.createSearchChoice('abnew');
+ expect(result.id).toEqual(-1);
+ expect(result.name).toEqual('abnew');
+ expect(result.isNew).toEqual(true);
+ expect(result.userVisible).toEqual(true);
+ expect(result.userAssignable).toEqual(true);
+ });
+ it('creates the real tag and fires select event after user selects the dummy tag', function() {
+ var selectHandler = sinon.stub();
+ view.on('select', selectHandler);
+ var createStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'create');
+ view.$el.find('input').trigger(new $.Event('select2-selecting', {
+ object: {
+ id: -1,
+ name: 'newname',
+ isNew: true
+ }
+ }));
+
+ expect(createStub.calledOnce).toEqual(true);
+ expect(createStub.getCall(0).args[0]).toEqual({
+ name: 'newname',
+ userVisible: true,
+ userAssignable: true
+ });
+
+ var newModel = new OC.SystemTags.SystemTagModel({
+ id: '123',
+ name: 'newname',
+ userVisible: true,
+ userAssignable: true
+ });
+
+ // not called yet
+ expect(selectHandler.notCalled).toEqual(true);
+
+ select2Stub.withArgs('data').returns([{
+ id: '1',
+ name: 'abc'
+ }]);
+
+ createStub.yieldTo('success', newModel);
+
+ expect(select2Stub.lastCall.args[0]).toEqual('data');
+ expect(select2Stub.lastCall.args[1]).toEqual([{
+ id: '1',
+ name: 'abc'
+ },
+ newModel.toJSON()
+ ]);
+
+ expect(selectHandler.calledOnce).toEqual(true);
+ expect(selectHandler.getCall(0).args[0]).toEqual(newModel);
+
+ createStub.restore();
+ });
+ it('triggers select event after selecting an existing tag', function() {
+ var selectHandler = sinon.stub();
+ view.on('select', selectHandler);
+ view.$el.find('input').trigger(new $.Event('select2-selecting', {
+ object: {
+ id: '2',
+ name: 'def'
+ }
+ }));
+
+ expect(selectHandler.calledOnce).toEqual(true);
+ expect(selectHandler.getCall(0).args[0]).toEqual(view.collection.get('2'));
+ });
+ it('triggers deselect event after deselecting an existing tag', function() {
+ var selectHandler = sinon.stub();
+ view.on('deselect', selectHandler);
+ view.$el.find('input').trigger(new $.Event('select2-removing', {
+ choice: {
+ id: '2',
+ name: 'def'
+ }
+ }));
+
+ expect(selectHandler.calledOnce).toEqual(true);
+ expect(selectHandler.getCall(0).args[0]).toEqual('2');
+ });
+ it('triggers select event and still adds to list even in case of conflict', function() {
+ var selectHandler = sinon.stub();
+ view.on('select', selectHandler);
+ var fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
+ var createStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'create');
+ view.$el.find('input').trigger(new $.Event('select2-selecting', {
+ object: {
+ id: -1,
+ name: 'newname',
+ isNew: true
+ }
+ }));
+
+ expect(createStub.calledOnce).toEqual(true);
+ expect(createStub.getCall(0).args[0]).toEqual({
+ name: 'newname',
+ userVisible: true,
+ userAssignable: true
+ });
+
+ var newModel = new OC.SystemTags.SystemTagModel({
+ id: '123',
+ name: 'newname',
+ userVisible: true,
+ userAssignable: true
+ });
+
+ // not called yet
+ expect(selectHandler.notCalled).toEqual(true);
+
+ select2Stub.withArgs('data').returns([{
+ id: '1',
+ name: 'abc'
+ }]);
+
+ // simulate conflict response for tag creation
+ createStub.yieldTo('error', view.collection, {status: 409});
+
+ // at this point it fetches from the server
+ expect(fetchStub.calledOnce).toEqual(true);
+ // simulate fetch result by adding model to the collection
+ view.collection.add(newModel);
+ fetchStub.yieldTo('success', view.collection);
+
+ expect(select2Stub.lastCall.args[0]).toEqual('data');
+ expect(select2Stub.lastCall.args[1]).toEqual([{
+ id: '1',
+ name: 'abc'
+ },
+ newModel.toJSON()
+ ]);
+
+ // select event still called
+ expect(selectHandler.calledOnce).toEqual(true);
+ expect(selectHandler.getCall(0).args[0]).toEqual(newModel);
+
+ createStub.restore();
+ fetchStub.restore();
+ });
+ });
+ describe('tag actions', function() {
+ var opts;
+
+ beforeEach(function() {
+
+ opts = select2Stub.getCall(0).args[0];
+
+ view.collection.add([
+ new OC.SystemTags.SystemTagModel({id: '1', name: 'abc'}),
+ ]);
+
+ $dropdown.append(opts.formatResult(view.collection.get('1').toJSON()));
+
+ });
+ it('displays rename form when clicking rename', function() {
+ $dropdown.find('.rename').mouseup();
+ expect($dropdown.find('form.systemtags-rename-form').length).toEqual(1);
+ expect($dropdown.find('form.systemtags-rename-form input').val()).toEqual('abc');
+ });
+ it('renames model and submits change when submitting form', function() {
+ var saveStub = sinon.stub(OC.SystemTags.SystemTagModel.prototype, 'save');
+ $dropdown.find('.rename').mouseup();
+ $dropdown.find('form input').val('abc_renamed');
+ $dropdown.find('form').trigger(new $.Event('submit'));
+
+ expect(saveStub.calledOnce).toEqual(true);
+ expect(saveStub.getCall(0).args[0]).toEqual({'name': 'abc_renamed'});
+
+ expect($dropdown.find('.label').text()).toEqual('abc_renamed');
+ expect($dropdown.find('form').length).toEqual(0);
+
+ saveStub.restore();
+ });
+ it('deletes model and submits change when clicking delete', function() {
+ var destroyStub = sinon.stub(OC.SystemTags.SystemTagModel.prototype, 'destroy');
+
+ expect($dropdown.find('.delete').length).toEqual(0);
+ $dropdown.find('.rename').mouseup();
+ // delete button appears
+ expect($dropdown.find('.delete').length).toEqual(1);
+ $dropdown.find('.delete').mouseup();
+
+ expect(destroyStub.calledOnce).toEqual(true);
+ expect(destroyStub.calledOn(view.collection.get('1')));
+
+ destroyStub.restore();
+ });
+ });
+ describe('setting data', function() {
+ it('sets value when calling setValues', function() {
+ var vals = ['1', '2'];
+ view.setValues(vals);
+ expect(select2Stub.lastCall.args[0]).toEqual('val');
+ expect(select2Stub.lastCall.args[1]).toEqual(vals);
+ });
+ it('sets data when calling setData', function() {
+ var vals = [{id: '1', name: 'test1'}, {id: '2', name: 'test2'}];
+ view.setData(vals);
+ expect(select2Stub.lastCall.args[0]).toEqual('data');
+ expect(select2Stub.lastCall.args[1]).toEqual(vals);
+ });
+ });
+ });
+
+ describe('as admin', function() {
+ beforeEach(function() {
+ view = new OC.SystemTags.SystemTagsInputField({
+ isAdmin: true
+ });
+ view.render();
+ $('.testInputContainer').append(view.$el);
+ });
+ it('formatResult renders tag name with visibility', function() {
+ var opts = select2Stub.getCall(0).args[0];
+ var $el = $(opts.formatResult({id: '1', name: 'test', userVisible: false, userAssignable: false}));
+ expect($el.find('.label').text()).toEqual('test (invisible)');
+ });
+ it('formatSelection renders tag name with visibility', function() {
+ var opts = select2Stub.getCall(0).args[0];
+ var $el = $(opts.formatSelection({id: '1', name: 'test', userVisible: false, userAssignable: false}));
+ expect($el.text().trim()).toEqual('test (invisible)');
+ });
+ describe('initSelection', function() {
+ var fetchStub;
+ var testTags;
+
+ beforeEach(function() {
+ fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
+ testTags = [
+ new OC.SystemTags.SystemTagModel({id: '1', name: 'test1'}),
+ new OC.SystemTags.SystemTagModel({id: '2', name: 'test2'}),
+ new OC.SystemTags.SystemTagModel({id: '3', name: 'test3', userAssignable: false}),
+ ];
+ });
+ afterEach(function() {
+ fetchStub.restore();
+ });
+ it('grabs values from the full collection', function() {
+ var $el = view.$el.find('input');
+ $el.val('1,3');
+ var opts = select2Stub.getCall(0).args[0];
+ var callback = sinon.stub();
+ opts.initSelection($el, callback);
+
+ expect(fetchStub.calledOnce).toEqual(true);
+ view.collection.add(testTags);
+ fetchStub.yieldTo('success', view.collection);
+
+ expect(callback.calledOnce).toEqual(true);
+ var models = callback.getCall(0).args[0];
+ expect(models.length).toEqual(2);
+ expect(models[0].id).toEqual('1');
+ expect(models[0].name).toEqual('test1');
+ expect(models[1].id).toEqual('3');
+ expect(models[1].name).toEqual('test3');
+ });
+ });
+ describe('autocomplete', function() {
+ var fetchStub, opts;
+
+ beforeEach(function() {
+ fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
+ opts = select2Stub.getCall(0).args[0];
+
+ view.collection.add([
+ new OC.SystemTags.SystemTagModel({id: '1', name: 'abc'}),
+ new OC.SystemTags.SystemTagModel({id: '2', name: 'def'}),
+ new OC.SystemTags.SystemTagModel({id: '3', name: 'abd', userAssignable: false}),
+ ]);
+ });
+ afterEach(function() {
+ fetchStub.restore();
+ });
+ it('completes results', function() {
+ var callback = sinon.stub();
+ opts.query({
+ term: 'ab',
+ callback: callback
+ });
+ expect(fetchStub.calledOnce).toEqual(true);
+
+ fetchStub.yieldTo('success', view.collection);
+
+ expect(callback.calledOnce).toEqual(true);
+ expect(callback.getCall(0).args[0].results).toEqual([
+ {
+ id: '1',
+ name: 'abc',
+ userVisible: true,
+ userAssignable: true
+ },
+ {
+ id: '3',
+ name: 'abd',
+ userVisible: true,
+ userAssignable: false
+ }
+ ]);
+ });
+ });
+ });
+
+ describe('as user', function() {
+ beforeEach(function() {
+ view = new OC.SystemTags.SystemTagsInputField({
+ isAdmin: false
+ });
+ view.render();
+ $('.testInputContainer').append(view.$el);
+ });
+ it('formatResult renders tag name only', function() {
+ var opts = select2Stub.getCall(0).args[0];
+ var $el = $(opts.formatResult({id: '1', name: 'test'}));
+ expect($el.find('.label').text()).toEqual('test');
+ });
+ it('formatSelection renders tag name only', function() {
+ var opts = select2Stub.getCall(0).args[0];
+ var $el = $(opts.formatSelection({id: '1', name: 'test'}));
+ expect($el.text().trim()).toEqual('test');
+ });
+ describe('initSelection', function() {
+ var fetchStub;
+ var testTags;
+
+ beforeEach(function() {
+ fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
+ testTags = [
+ new OC.SystemTags.SystemTagModel({id: '1', name: 'test1'}),
+ new OC.SystemTags.SystemTagModel({id: '2', name: 'test2'}),
+ new OC.SystemTags.SystemTagModel({id: '3', name: 'test3', userAssignable: false}),
+ ];
+ view.render();
+ });
+ afterEach(function() {
+ fetchStub.restore();
+ });
+ it('grabs values from the full collection', function() {
+ var $el = view.$el.find('input');
+ $el.val('1,3');
+ var opts = select2Stub.getCall(0).args[0];
+ var callback = sinon.stub();
+ opts.initSelection($el, callback);
+
+ expect(fetchStub.calledOnce).toEqual(true);
+ view.collection.add(testTags);
+ fetchStub.yieldTo('success', view.collection);
+
+ expect(callback.calledOnce).toEqual(true);
+ var models = callback.getCall(0).args[0];
+ expect(models.length).toEqual(2);
+ expect(models[0].id).toEqual('1');
+ expect(models[0].name).toEqual('test1');
+ expect(models[1].id).toEqual('3');
+ expect(models[1].name).toEqual('test3');
+ });
+ });
+ describe('autocomplete', function() {
+ var fetchStub, opts;
+
+ beforeEach(function() {
+ fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
+ view.render();
+ opts = select2Stub.getCall(0).args[0];
+
+ view.collection.add([
+ new OC.SystemTags.SystemTagModel({id: '1', name: 'abc'}),
+ new OC.SystemTags.SystemTagModel({id: '2', name: 'def'}),
+ new OC.SystemTags.SystemTagModel({id: '3', name: 'abd', userAssignable: false}),
+ ]);
+ });
+ afterEach(function() {
+ fetchStub.restore();
+ });
+ it('completes results excluding non-assignable tags', function() {
+ var callback = sinon.stub();
+ opts.query({
+ term: 'ab',
+ callback: callback
+ });
+ expect(fetchStub.calledOnce).toEqual(true);
+
+ fetchStub.yieldTo('success', view.collection);
+
+ expect(callback.calledOnce).toEqual(true);
+ expect(callback.getCall(0).args[0].results).toEqual([
+ {
+ id: '1',
+ name: 'abc',
+ userVisible: true,
+ userAssignable: true
+ }
+ ]);
+ });
+ });
+ });
+});
diff --git a/core/js/update.js b/core/js/update.js
index 090f8fa5d23..1626b6f2c49 100644
--- a/core/js/update.js
+++ b/core/js/update.js
@@ -84,7 +84,7 @@
.append(t('core', 'The update was successful. Redirecting you to ownCloud now.'))
.appendTo($el);
setTimeout(function () {
- OC.redirect(OC.webroot);
+ OC.redirect(OC.webroot + '/');
}, 3000);
}
});
diff --git a/core/l10n/af_ZA.js b/core/l10n/af_ZA.js
index 151311b4848..1d7b1bda361 100644
--- a/core/l10n/af_ZA.js
+++ b/core/l10n/af_ZA.js
@@ -15,6 +15,8 @@ OC.L10N.register(
"Invalid image" : "Ongeldige prent",
"No temporary profile picture available, try again" : "Geen tydelike profiel foto beskikbaar nie, probeer weer",
"No crop data provided" : "Geen \"crop\" data verskaf",
+ "%s password reset" : "%s wagwoord herstel",
+ "Couldn't send reset email. Please contact your administrator." : "Die herstel epos kon nie gestuur word nie. Kontak asseblief die stelsel administrateur.",
"Sunday" : "Sondag",
"Monday" : "Maandag",
"Tuesday" : "Dinsdag",
@@ -37,7 +39,6 @@ OC.L10N.register(
"Settings" : "Instellings",
"Saving..." : "Stoor...",
"seconds ago" : "sekondes gelede",
- "Couldn't send reset email. Please contact your administrator." : "Die herstel epos kon nie gestuur word nie. Kontak asseblief die stelsel administrateur.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Die \"link\" vir die herstel van jou wagwoord is na jou epos gestuur. As jy dit nie binne 'n redelike tyd ontvang nie, soek deur jou \"spam/junk\" omslagte.<br>As dit nie daar is nie vra jou administrateur vir hulp.",
"I know what I'm doing" : "Ek weet wat ek doen",
"Password can not be changed. Please contact your administrator." : "Wagwoord kan nie verander word nie. Kontak asseblief jou stelsel administrateur.",
@@ -60,7 +61,6 @@ OC.L10N.register(
"Error" : "Fout",
"Error while sharing" : "Deel veroorsaak fout",
"Error while unsharing" : "Deel terugneem veroorsaak fout",
- "Error while changing permissions" : "Fout met verandering van regte",
"Error setting expiration date" : "Fout met opstel van verval datum",
"Set expiration date" : "Stel verval datum",
"Expiration date" : "Verval datum",
@@ -73,7 +73,6 @@ OC.L10N.register(
"Send" : "Stuur",
"Shared with you and the group {group} by {owner}" : "Met jou en die groep {group} gedeel deur {owner}",
"Shared with you by {owner}" : "Met jou gedeel deur {owner}",
- "Shared in {item} with {user}" : "Gedeel in {item} met {user}",
"group" : "groep",
"Unshare" : "Deel terug neem",
"can edit" : "kan wysig",
@@ -85,10 +84,6 @@ OC.L10N.register(
"The object type is not specified." : "Hierdie objek tipe is nie gespesifiseer nie.",
"Add" : "Voeg by",
"The update was successful. Redirecting you to ownCloud now." : "Die opdatering was suksesvol. Jy word nou aan ownCloud terug gelei.",
- "%s password reset" : "%s wagwoord herstel",
- "Use the following link to reset your password: {link}" : "Gebruik die volgende skakel om jou wagwoord te herstel: {link}",
- "New password" : "Nuwe wagwoord",
- "Reset password" : "Herstel wagwoord",
"Personal" : "Persoonlik",
"Users" : "Gebruikers",
"Apps" : "Toepassings",
@@ -110,6 +105,9 @@ OC.L10N.register(
"Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Halo daar,<br><br>wou jou net laat weet dat %s <strong>%s</strong> met jou gedeel het.<br><a href=\"%s\">Sien alles!</a><br><br>",
"Log out" : "Teken uit",
"Log in" : "Teken aan",
- "Alternative Logins" : "Alternatiewe aantekeninge"
+ "Alternative Logins" : "Alternatiewe aantekeninge",
+ "Use the following link to reset your password: {link}" : "Gebruik die volgende skakel om jou wagwoord te herstel: {link}",
+ "New password" : "Nuwe wagwoord",
+ "Reset password" : "Herstel wagwoord"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/af_ZA.json b/core/l10n/af_ZA.json
index 7d30b3c6566..fc83949b361 100644
--- a/core/l10n/af_ZA.json
+++ b/core/l10n/af_ZA.json
@@ -13,6 +13,8 @@
"Invalid image" : "Ongeldige prent",
"No temporary profile picture available, try again" : "Geen tydelike profiel foto beskikbaar nie, probeer weer",
"No crop data provided" : "Geen \"crop\" data verskaf",
+ "%s password reset" : "%s wagwoord herstel",
+ "Couldn't send reset email. Please contact your administrator." : "Die herstel epos kon nie gestuur word nie. Kontak asseblief die stelsel administrateur.",
"Sunday" : "Sondag",
"Monday" : "Maandag",
"Tuesday" : "Dinsdag",
@@ -35,7 +37,6 @@
"Settings" : "Instellings",
"Saving..." : "Stoor...",
"seconds ago" : "sekondes gelede",
- "Couldn't send reset email. Please contact your administrator." : "Die herstel epos kon nie gestuur word nie. Kontak asseblief die stelsel administrateur.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Die \"link\" vir die herstel van jou wagwoord is na jou epos gestuur. As jy dit nie binne 'n redelike tyd ontvang nie, soek deur jou \"spam/junk\" omslagte.<br>As dit nie daar is nie vra jou administrateur vir hulp.",
"I know what I'm doing" : "Ek weet wat ek doen",
"Password can not be changed. Please contact your administrator." : "Wagwoord kan nie verander word nie. Kontak asseblief jou stelsel administrateur.",
@@ -58,7 +59,6 @@
"Error" : "Fout",
"Error while sharing" : "Deel veroorsaak fout",
"Error while unsharing" : "Deel terugneem veroorsaak fout",
- "Error while changing permissions" : "Fout met verandering van regte",
"Error setting expiration date" : "Fout met opstel van verval datum",
"Set expiration date" : "Stel verval datum",
"Expiration date" : "Verval datum",
@@ -71,7 +71,6 @@
"Send" : "Stuur",
"Shared with you and the group {group} by {owner}" : "Met jou en die groep {group} gedeel deur {owner}",
"Shared with you by {owner}" : "Met jou gedeel deur {owner}",
- "Shared in {item} with {user}" : "Gedeel in {item} met {user}",
"group" : "groep",
"Unshare" : "Deel terug neem",
"can edit" : "kan wysig",
@@ -83,10 +82,6 @@
"The object type is not specified." : "Hierdie objek tipe is nie gespesifiseer nie.",
"Add" : "Voeg by",
"The update was successful. Redirecting you to ownCloud now." : "Die opdatering was suksesvol. Jy word nou aan ownCloud terug gelei.",
- "%s password reset" : "%s wagwoord herstel",
- "Use the following link to reset your password: {link}" : "Gebruik die volgende skakel om jou wagwoord te herstel: {link}",
- "New password" : "Nuwe wagwoord",
- "Reset password" : "Herstel wagwoord",
"Personal" : "Persoonlik",
"Users" : "Gebruikers",
"Apps" : "Toepassings",
@@ -108,6 +103,9 @@
"Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Halo daar,<br><br>wou jou net laat weet dat %s <strong>%s</strong> met jou gedeel het.<br><a href=\"%s\">Sien alles!</a><br><br>",
"Log out" : "Teken uit",
"Log in" : "Teken aan",
- "Alternative Logins" : "Alternatiewe aantekeninge"
+ "Alternative Logins" : "Alternatiewe aantekeninge",
+ "Use the following link to reset your password: {link}" : "Gebruik die volgende skakel om jou wagwoord te herstel: {link}",
+ "New password" : "Nuwe wagwoord",
+ "Reset password" : "Herstel wagwoord"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/ar.js b/core/l10n/ar.js
index 9a5a9119991..ce1d76ff01a 100644
--- a/core/l10n/ar.js
+++ b/core/l10n/ar.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"No image or file provided" : "لم يتم توفير صورة أو ملف",
"Unknown filetype" : "نوع الملف غير معروف",
"Invalid image" : "الصورة غير صالحة",
+ "%s password reset" : "تمت إعادة ضبط كلمة مرور %s",
"Sunday" : "الأحد",
"Monday" : "الأثنين",
"Tuesday" : "الثلاثاء",
@@ -68,7 +69,6 @@ OC.L10N.register(
"Error" : "خطأ",
"Error while sharing" : "حصل خطأ عند عملية المشاركة",
"Error while unsharing" : "حصل خطأ عند عملية إزالة المشاركة",
- "Error while changing permissions" : "حصل خطأ عند عملية إعادة تعيين التصريح بالتوصل",
"Error setting expiration date" : "حصل خطأ عند عملية تعيين تاريخ إنتهاء الصلاحية",
"Set expiration date" : "تعيين تاريخ إنتهاء الصلاحية",
"Expiration" : "إنتهاء",
@@ -86,7 +86,6 @@ OC.L10N.register(
"Send" : "أرسل",
"Shared with you and the group {group} by {owner}" : "شورك معك ومع المجموعة {group} من قبل {owner}",
"Shared with you by {owner}" : "شورك معك من قبل {owner}",
- "Shared in {item} with {user}" : "شورك في {item} مع {user}",
"group" : "مجموعة",
"remote" : "عن بعد",
"notify by email" : "الإشعار عن طريق البريد",
@@ -99,15 +98,12 @@ OC.L10N.register(
"access control" : "ضبط الوصول",
"Share" : "شارك",
"Warning" : "تحذير",
+ "Delete" : "إلغاء",
+ "Rename" : "إعادة التسمية",
"The object type is not specified." : "نوع العنصر غير محدد.",
"Enter new" : "إدخال جديد",
- "Delete" : "إلغاء",
"Add" : "اضف",
"The update was successful. Redirecting you to ownCloud now." : "تم التحديث بنجاح , يتم اعادة توجيهك الان الى Owncloud",
- "%s password reset" : "تمت إعادة ضبط كلمة مرور %s",
- "Use the following link to reset your password: {link}" : "استخدم هذه الوصلة لاسترجاع كلمة السر: {link}",
- "New password" : "كلمات سر جديدة",
- "Reset password" : "تعديل كلمة السر",
"Personal" : "شخصي",
"Users" : "المستخدمين",
"Apps" : "التطبيقات",
@@ -129,6 +125,9 @@ OC.L10N.register(
"Log out" : "الخروج",
"Search" : "البحث",
"Log in" : "أدخل",
- "Alternative Logins" : "اسماء دخول بديلة"
+ "Alternative Logins" : "اسماء دخول بديلة",
+ "Use the following link to reset your password: {link}" : "استخدم هذه الوصلة لاسترجاع كلمة السر: {link}",
+ "New password" : "كلمات سر جديدة",
+ "Reset password" : "تعديل كلمة السر"
},
"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");
diff --git a/core/l10n/ar.json b/core/l10n/ar.json
index 0e3db12b2c3..7bb2812790c 100644
--- a/core/l10n/ar.json
+++ b/core/l10n/ar.json
@@ -3,6 +3,7 @@
"No image or file provided" : "لم يتم توفير صورة أو ملف",
"Unknown filetype" : "نوع الملف غير معروف",
"Invalid image" : "الصورة غير صالحة",
+ "%s password reset" : "تمت إعادة ضبط كلمة مرور %s",
"Sunday" : "الأحد",
"Monday" : "الأثنين",
"Tuesday" : "الثلاثاء",
@@ -66,7 +67,6 @@
"Error" : "خطأ",
"Error while sharing" : "حصل خطأ عند عملية المشاركة",
"Error while unsharing" : "حصل خطأ عند عملية إزالة المشاركة",
- "Error while changing permissions" : "حصل خطأ عند عملية إعادة تعيين التصريح بالتوصل",
"Error setting expiration date" : "حصل خطأ عند عملية تعيين تاريخ إنتهاء الصلاحية",
"Set expiration date" : "تعيين تاريخ إنتهاء الصلاحية",
"Expiration" : "إنتهاء",
@@ -84,7 +84,6 @@
"Send" : "أرسل",
"Shared with you and the group {group} by {owner}" : "شورك معك ومع المجموعة {group} من قبل {owner}",
"Shared with you by {owner}" : "شورك معك من قبل {owner}",
- "Shared in {item} with {user}" : "شورك في {item} مع {user}",
"group" : "مجموعة",
"remote" : "عن بعد",
"notify by email" : "الإشعار عن طريق البريد",
@@ -97,15 +96,12 @@
"access control" : "ضبط الوصول",
"Share" : "شارك",
"Warning" : "تحذير",
+ "Delete" : "إلغاء",
+ "Rename" : "إعادة التسمية",
"The object type is not specified." : "نوع العنصر غير محدد.",
"Enter new" : "إدخال جديد",
- "Delete" : "إلغاء",
"Add" : "اضف",
"The update was successful. Redirecting you to ownCloud now." : "تم التحديث بنجاح , يتم اعادة توجيهك الان الى Owncloud",
- "%s password reset" : "تمت إعادة ضبط كلمة مرور %s",
- "Use the following link to reset your password: {link}" : "استخدم هذه الوصلة لاسترجاع كلمة السر: {link}",
- "New password" : "كلمات سر جديدة",
- "Reset password" : "تعديل كلمة السر",
"Personal" : "شخصي",
"Users" : "المستخدمين",
"Apps" : "التطبيقات",
@@ -127,6 +123,9 @@
"Log out" : "الخروج",
"Search" : "البحث",
"Log in" : "أدخل",
- "Alternative Logins" : "اسماء دخول بديلة"
+ "Alternative Logins" : "اسماء دخول بديلة",
+ "Use the following link to reset your password: {link}" : "استخدم هذه الوصلة لاسترجاع كلمة السر: {link}",
+ "New password" : "كلمات سر جديدة",
+ "Reset password" : "تعديل كلمة السر"
},"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"
} \ No newline at end of file
diff --git a/core/l10n/ast.js b/core/l10n/ast.js
index e0775c75569..5ec58b0051c 100644
--- a/core/l10n/ast.js
+++ b/core/l10n/ast.js
@@ -13,6 +13,10 @@ OC.L10N.register(
"Invalid image" : "Imaxe inválida",
"No temporary profile picture available, try again" : "Nengún perfil d'imaxe temporal disponible, intentalo de nueves",
"No crop data provided" : "Nun s'apurrió'l retayu de datos",
+ "Couldn't reset password because the token is invalid" : "Nun pudo reaniciase la contraseña porque'l token ye inválidu",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nun pudo unviase'l corréu. Por favor, asegurate que'l to nome d'usuariu seya correutu",
+ "%s password reset" : "%s restablecer contraseña",
+ "Couldn't send reset email. Please contact your administrator." : "Nun pudo unviase'l corréu de reaniciu. Por favor, contauta col alministrador.",
"Sunday" : "Domingu",
"Monday" : "Llunes",
"Tuesday" : "Martes",
@@ -54,7 +58,6 @@ OC.L10N.register(
"Settings" : "Axustes",
"Saving..." : "Guardando...",
"seconds ago" : "hai segundos",
- "Couldn't send reset email. Please contact your administrator." : "Nun pudo unviase'l corréu de reaniciu. Por favor, contauta col alministrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Unviósete al corréu l'enllaz pa reaniciar la to contraseña. Si nun lu recibes nuna cantidá razonable de tiempu, comprueba les tos carpetes de corréu puxarra. <br>Si nun ta ehí, entruga al to alministrador llocal",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Los tos ficheros tán crifraos. Si nun habilitesti la clave de recuperación, nun habrá forma de recuperar los tos datos dempués de que se reanicie la to contraseña.<br />Si nun tas seguru de qué facer, por favor contauta col to alministrador enantes que sigas. <br />¿De xuru quies siguir?",
"I know what I'm doing" : "Sé lo que toi faciendo",
@@ -86,7 +89,6 @@ OC.L10N.register(
"Error" : "Fallu",
"Error while sharing" : "Fallu mientres la compartición",
"Error while unsharing" : "Fallu mientres se dexaba de compartir",
- "Error while changing permissions" : "Fallu mientres camudaben los permisos",
"Error setting expiration date" : "Fallu afitando la fecha de caducidá",
"The public link will expire no later than {days} days after it is created" : "L'enllaz públicu va caducar enantes de {days} díes dende la so creación",
"Set expiration date" : "Afitar la data de caducidá",
@@ -105,7 +107,6 @@ OC.L10N.register(
"Send" : "Unviar",
"Shared with you and the group {group} by {owner}" : "Compartíu contigo y col grupu {group} por {owner}",
"Shared with you by {owner}" : "Compartíu contigo por {owner}",
- "Shared in {item} with {user}" : "Compartíu en {item} con {user}",
"group" : "grupu",
"remote" : "remotu",
"notify by email" : "notificar per corréu",
@@ -122,9 +123,10 @@ OC.L10N.register(
"Share with users or groups …" : "Compartir con usuarios o grupos",
"Share with users, groups or remote users …" : "Compartir con usuarios, grupos o usuarios remotos",
"Warning" : "Avisu",
+ "Delete" : "Desaniciar",
+ "Rename" : "Renomar",
"The object type is not specified." : "El tipu d'oxetu nun ta especificáu.",
"Enter new" : "Introducir nueva",
- "Delete" : "Desaniciar",
"Add" : "Amestar",
"Edit tags" : "Editar etiquetes",
"Error loading dialog template: {error}" : "Fallu cargando plantía de diálogu: {error}",
@@ -132,14 +134,6 @@ OC.L10N.register(
"Updating {productName} to version {version}, this may take a while." : "Anovando {productName} a la versión {version}, esto pue llevar un tiempu.",
"Please reload the page." : "Por favor, recarga la páxina",
"The update was successful. Redirecting you to ownCloud now." : "L'anovamientu fízose con ésitu. Redirixiendo agora al to ownCloud.",
- "Couldn't reset password because the token is invalid" : "Nun pudo reaniciase la contraseña porque'l token ye inválidu",
- "Couldn't send reset email. Please make sure your username is correct." : "Nun pudo unviase'l corréu. Por favor, asegurate que'l to nome d'usuariu seya correutu",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nun pudo unviase'l corréu porque nun hai direición de corréu pa esti nome d'usuariu. Por favor, contauta col alministrador",
- "%s password reset" : "%s restablecer contraseña",
- "Use the following link to reset your password: {link}" : "Usa'l siguiente enllaz pa restablecer la to contraseña: {link}",
- "New password" : "Contraseña nueva",
- "New Password" : "Contraseña nueva",
- "Reset password" : "Restablecer contraseña",
"Personal" : "Personal",
"Users" : "Usuarios",
"Apps" : "Aplicaciones",
@@ -178,6 +172,10 @@ OC.L10N.register(
"Please contact your administrator." : "Por favor, contauta col to alministrador",
"Log in" : "Aniciar sesión",
"Alternative Logins" : "Anicios de sesión alternativos",
+ "Use the following link to reset your password: {link}" : "Usa'l siguiente enllaz pa restablecer la to contraseña: {link}",
+ "New password" : "Contraseña nueva",
+ "New Password" : "Contraseña nueva",
+ "Reset password" : "Restablecer contraseña",
"This ownCloud instance is currently in single user mode." : "Esta instalación d'ownCloud ta en mou d'usuariu únicu.",
"This means only administrators can use the instance." : "Esto quier dicir que namái pue usala un alministrador.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contauta col alministrador si esti problema sigui apaeciendo.",
diff --git a/core/l10n/ast.json b/core/l10n/ast.json
index a4324339829..ecb77d5415a 100644
--- a/core/l10n/ast.json
+++ b/core/l10n/ast.json
@@ -11,6 +11,10 @@
"Invalid image" : "Imaxe inválida",
"No temporary profile picture available, try again" : "Nengún perfil d'imaxe temporal disponible, intentalo de nueves",
"No crop data provided" : "Nun s'apurrió'l retayu de datos",
+ "Couldn't reset password because the token is invalid" : "Nun pudo reaniciase la contraseña porque'l token ye inválidu",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nun pudo unviase'l corréu. Por favor, asegurate que'l to nome d'usuariu seya correutu",
+ "%s password reset" : "%s restablecer contraseña",
+ "Couldn't send reset email. Please contact your administrator." : "Nun pudo unviase'l corréu de reaniciu. Por favor, contauta col alministrador.",
"Sunday" : "Domingu",
"Monday" : "Llunes",
"Tuesday" : "Martes",
@@ -52,7 +56,6 @@
"Settings" : "Axustes",
"Saving..." : "Guardando...",
"seconds ago" : "hai segundos",
- "Couldn't send reset email. Please contact your administrator." : "Nun pudo unviase'l corréu de reaniciu. Por favor, contauta col alministrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Unviósete al corréu l'enllaz pa reaniciar la to contraseña. Si nun lu recibes nuna cantidá razonable de tiempu, comprueba les tos carpetes de corréu puxarra. <br>Si nun ta ehí, entruga al to alministrador llocal",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Los tos ficheros tán crifraos. Si nun habilitesti la clave de recuperación, nun habrá forma de recuperar los tos datos dempués de que se reanicie la to contraseña.<br />Si nun tas seguru de qué facer, por favor contauta col to alministrador enantes que sigas. <br />¿De xuru quies siguir?",
"I know what I'm doing" : "Sé lo que toi faciendo",
@@ -84,7 +87,6 @@
"Error" : "Fallu",
"Error while sharing" : "Fallu mientres la compartición",
"Error while unsharing" : "Fallu mientres se dexaba de compartir",
- "Error while changing permissions" : "Fallu mientres camudaben los permisos",
"Error setting expiration date" : "Fallu afitando la fecha de caducidá",
"The public link will expire no later than {days} days after it is created" : "L'enllaz públicu va caducar enantes de {days} díes dende la so creación",
"Set expiration date" : "Afitar la data de caducidá",
@@ -103,7 +105,6 @@
"Send" : "Unviar",
"Shared with you and the group {group} by {owner}" : "Compartíu contigo y col grupu {group} por {owner}",
"Shared with you by {owner}" : "Compartíu contigo por {owner}",
- "Shared in {item} with {user}" : "Compartíu en {item} con {user}",
"group" : "grupu",
"remote" : "remotu",
"notify by email" : "notificar per corréu",
@@ -120,9 +121,10 @@
"Share with users or groups …" : "Compartir con usuarios o grupos",
"Share with users, groups or remote users …" : "Compartir con usuarios, grupos o usuarios remotos",
"Warning" : "Avisu",
+ "Delete" : "Desaniciar",
+ "Rename" : "Renomar",
"The object type is not specified." : "El tipu d'oxetu nun ta especificáu.",
"Enter new" : "Introducir nueva",
- "Delete" : "Desaniciar",
"Add" : "Amestar",
"Edit tags" : "Editar etiquetes",
"Error loading dialog template: {error}" : "Fallu cargando plantía de diálogu: {error}",
@@ -130,14 +132,6 @@
"Updating {productName} to version {version}, this may take a while." : "Anovando {productName} a la versión {version}, esto pue llevar un tiempu.",
"Please reload the page." : "Por favor, recarga la páxina",
"The update was successful. Redirecting you to ownCloud now." : "L'anovamientu fízose con ésitu. Redirixiendo agora al to ownCloud.",
- "Couldn't reset password because the token is invalid" : "Nun pudo reaniciase la contraseña porque'l token ye inválidu",
- "Couldn't send reset email. Please make sure your username is correct." : "Nun pudo unviase'l corréu. Por favor, asegurate que'l to nome d'usuariu seya correutu",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nun pudo unviase'l corréu porque nun hai direición de corréu pa esti nome d'usuariu. Por favor, contauta col alministrador",
- "%s password reset" : "%s restablecer contraseña",
- "Use the following link to reset your password: {link}" : "Usa'l siguiente enllaz pa restablecer la to contraseña: {link}",
- "New password" : "Contraseña nueva",
- "New Password" : "Contraseña nueva",
- "Reset password" : "Restablecer contraseña",
"Personal" : "Personal",
"Users" : "Usuarios",
"Apps" : "Aplicaciones",
@@ -176,6 +170,10 @@
"Please contact your administrator." : "Por favor, contauta col to alministrador",
"Log in" : "Aniciar sesión",
"Alternative Logins" : "Anicios de sesión alternativos",
+ "Use the following link to reset your password: {link}" : "Usa'l siguiente enllaz pa restablecer la to contraseña: {link}",
+ "New password" : "Contraseña nueva",
+ "New Password" : "Contraseña nueva",
+ "Reset password" : "Restablecer contraseña",
"This ownCloud instance is currently in single user mode." : "Esta instalación d'ownCloud ta en mou d'usuariu únicu.",
"This means only administrators can use the instance." : "Esto quier dicir que namái pue usala un alministrador.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contauta col alministrador si esti problema sigui apaeciendo.",
diff --git a/core/l10n/az.js b/core/l10n/az.js
index 234431ec3b9..e4d04335921 100644
--- a/core/l10n/az.js
+++ b/core/l10n/az.js
@@ -74,8 +74,8 @@ OC.L10N.register(
"Share" : "Yayımla",
"Warning" : "Xəbərdarlıq",
"Delete" : "Sil",
+ "Rename" : "Adı dəyiş",
"Add" : "Əlavə etmək",
- "New password" : "Yeni şifrə",
"Personal" : "Şəxsi",
"Users" : "İstifadəçilər",
"Admin" : "İnzibatçı",
@@ -85,6 +85,7 @@ OC.L10N.register(
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Xüsusilə fayl sinxronizasiyası üçün desktop client-dən istifadə edilərsə, SQLite məsləhət görülmür.",
"Search" : "Axtarış",
"Log in" : "Giriş",
+ "New password" : "Yeni şifrə",
"You are accessing the server from an untrusted domain." : "Siz serverə inamsız domain-dən girməyə çalışırsız."
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/az.json b/core/l10n/az.json
index 4d45bdd9d96..e2242fe95c5 100644
--- a/core/l10n/az.json
+++ b/core/l10n/az.json
@@ -72,8 +72,8 @@
"Share" : "Yayımla",
"Warning" : "Xəbərdarlıq",
"Delete" : "Sil",
+ "Rename" : "Adı dəyiş",
"Add" : "Əlavə etmək",
- "New password" : "Yeni şifrə",
"Personal" : "Şəxsi",
"Users" : "İstifadəçilər",
"Admin" : "İnzibatçı",
@@ -83,6 +83,7 @@
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Xüsusilə fayl sinxronizasiyası üçün desktop client-dən istifadə edilərsə, SQLite məsləhət görülmür.",
"Search" : "Axtarış",
"Log in" : "Giriş",
+ "New password" : "Yeni şifrə",
"You are accessing the server from an untrusted domain." : "Siz serverə inamsız domain-dən girməyə çalışırsız."
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/bg_BG.js b/core/l10n/bg_BG.js
index 34df1311847..b7c3bb29c98 100644
--- a/core/l10n/bg_BG.js
+++ b/core/l10n/bg_BG.js
@@ -16,6 +16,10 @@ OC.L10N.register(
"Invalid image" : "Невалидно изображение",
"No temporary profile picture available, try again" : "Не е налична временна профилна снимка, опитайте отново",
"No crop data provided" : "Липсват данни за изрязването",
+ "Couldn't reset password because the token is invalid" : "Промяната на паролата е невъзможно, защото връзката за удостоверение не е валидна",
+ "Couldn't send reset email. Please make sure your username is correct." : "Неуспешно изпращане на имейл за възстановяване на паролата. Моля, уверете се, че потребителското име е правилно.",
+ "%s password reset" : "Паролата на %s е променена.",
+ "Couldn't send reset email. Please contact your administrator." : "Изпращането на електронна поща е неуспешно. Моля, свържете се с вашия администратор.",
"Sunday" : "Неделя",
"Monday" : "Понеделник",
"Tuesday" : "Вторник",
@@ -57,7 +61,6 @@ OC.L10N.register(
"Settings" : "Настройки",
"Saving..." : "Запазване...",
"seconds ago" : "преди секунди",
- "Couldn't send reset email. Please contact your administrator." : "Изпращането на електронна поща е неуспешно. Моля, свържете се с вашия администратор.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Връзката за възстановяване на паролата беше изпратена до вашата електронна поща. Ако не я получите в разумен период от време, проверете папките си за спам и junk.<br>Ако не я откривате и там, се свържете с местния администратор.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Файловете Ви са криптирани. Ако не сте настроили ключ за възстановяване, няма да е възможно да се възстановят данните Ви след смяна на паролата.<br />Ако не сте сигурни какво да направите, моля, свържете се с Вашия администратор преди да продължите. <br/>Наистина ли искате да продължите?",
"I know what I'm doing" : "Знам какво правя",
@@ -94,7 +97,6 @@ OC.L10N.register(
"Error" : "Грешка",
"Error while sharing" : "Грешка при споделяне",
"Error while unsharing" : "Грешка при премахване на споделянето",
- "Error while changing permissions" : "Грешка при промяна на привилегиите",
"Error setting expiration date" : "Грешка при настройване на датата за изтичане",
"The public link will expire no later than {days} days after it is created" : "Общодостъпната връзка ще изтече не по-късно от {days} дни след създаването ѝ.",
"Set expiration date" : "Задаване на дата на изтичане",
@@ -113,7 +115,6 @@ OC.L10N.register(
"Send" : "Изпращане",
"Shared with you and the group {group} by {owner}" : "Споделено от {owner} с Вас и групата {group} .",
"Shared with you by {owner}" : "Споделено с Вас от {owner}.",
- "Shared in {item} with {user}" : "Споделено в {item} с {user}.",
"group" : "група",
"remote" : "отдалечен",
"notify by email" : "уведомяване по електронна поща",
@@ -126,9 +127,10 @@ OC.L10N.register(
"access control" : "контрол на достъпа",
"Share" : "Споделяне",
"Warning" : "Предупреждение",
+ "Delete" : "Изтриване",
+ "Rename" : "Преименуване",
"The object type is not specified." : "Видът на обекта не е избран.",
"Enter new" : "Въвеждане на нов",
- "Delete" : "Изтриване",
"Add" : "Добавяне",
"Edit tags" : "Промяна на етикетите",
"Error loading dialog template: {error}" : "Грешка при зареждането на шаблон за диалог: {error}.",
@@ -143,14 +145,6 @@ OC.L10N.register(
"Please reload the page." : "Моля, презаредете страницата.",
"The update was unsuccessful. " : "Обновяването бе неуспешно.",
"The update was successful. Redirecting you to ownCloud now." : "Обновяването е успешно. Сега Ви пренасочваме към ownCloud.",
- "Couldn't reset password because the token is invalid" : "Промяната на паролата е невъзможно, защото връзката за удостоверение не е валидна",
- "Couldn't send reset email. Please make sure your username is correct." : "Неуспешно изпращане на имейл за възстановяване на паролата. Моля, уверете се, че потребителското име е правилно.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Неуспешно изпращане на имейл за възстановяване на паролата, защото липсва имейл, свързан с това потребителско име. Моля, свържете се с администратора.",
- "%s password reset" : "Паролата на %s е променена.",
- "Use the following link to reset your password: {link}" : "Използвайте следната връзка, за да възстановите паролата си: {link}",
- "New password" : "Нова парола",
- "New Password" : "Нова Парола",
- "Reset password" : "Възстановяване на паролата",
"Searching other places" : "Търсене в други места",
"Personal" : "Лични",
"Users" : "Потребители",
@@ -210,6 +204,10 @@ OC.L10N.register(
"Please contact your administrator." : "Моля, свържете се с администратора.",
"Log in" : "Вписване",
"Alternative Logins" : "Алтернативни методи на вписване",
+ "Use the following link to reset your password: {link}" : "Използвайте следната връзка, за да възстановите паролата си: {link}",
+ "New password" : "Нова парола",
+ "New Password" : "Нова Парола",
+ "Reset password" : "Възстановяване на паролата",
"This ownCloud instance is currently in single user mode." : "В момента този ownCloud е в режим допускащ само един потребител.",
"This means only administrators can use the instance." : "Това означава, че само администраторът може да го използва.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Свържи се със системния си администратор ако това съобщение се задържи твърде дълго или се е появило неочаквано.",
diff --git a/core/l10n/bg_BG.json b/core/l10n/bg_BG.json
index bcce1747bbd..70a30ad8719 100644
--- a/core/l10n/bg_BG.json
+++ b/core/l10n/bg_BG.json
@@ -14,6 +14,10 @@
"Invalid image" : "Невалидно изображение",
"No temporary profile picture available, try again" : "Не е налична временна профилна снимка, опитайте отново",
"No crop data provided" : "Липсват данни за изрязването",
+ "Couldn't reset password because the token is invalid" : "Промяната на паролата е невъзможно, защото връзката за удостоверение не е валидна",
+ "Couldn't send reset email. Please make sure your username is correct." : "Неуспешно изпращане на имейл за възстановяване на паролата. Моля, уверете се, че потребителското име е правилно.",
+ "%s password reset" : "Паролата на %s е променена.",
+ "Couldn't send reset email. Please contact your administrator." : "Изпращането на електронна поща е неуспешно. Моля, свържете се с вашия администратор.",
"Sunday" : "Неделя",
"Monday" : "Понеделник",
"Tuesday" : "Вторник",
@@ -55,7 +59,6 @@
"Settings" : "Настройки",
"Saving..." : "Запазване...",
"seconds ago" : "преди секунди",
- "Couldn't send reset email. Please contact your administrator." : "Изпращането на електронна поща е неуспешно. Моля, свържете се с вашия администратор.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Връзката за възстановяване на паролата беше изпратена до вашата електронна поща. Ако не я получите в разумен период от време, проверете папките си за спам и junk.<br>Ако не я откривате и там, се свържете с местния администратор.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Файловете Ви са криптирани. Ако не сте настроили ключ за възстановяване, няма да е възможно да се възстановят данните Ви след смяна на паролата.<br />Ако не сте сигурни какво да направите, моля, свържете се с Вашия администратор преди да продължите. <br/>Наистина ли искате да продължите?",
"I know what I'm doing" : "Знам какво правя",
@@ -92,7 +95,6 @@
"Error" : "Грешка",
"Error while sharing" : "Грешка при споделяне",
"Error while unsharing" : "Грешка при премахване на споделянето",
- "Error while changing permissions" : "Грешка при промяна на привилегиите",
"Error setting expiration date" : "Грешка при настройване на датата за изтичане",
"The public link will expire no later than {days} days after it is created" : "Общодостъпната връзка ще изтече не по-късно от {days} дни след създаването ѝ.",
"Set expiration date" : "Задаване на дата на изтичане",
@@ -111,7 +113,6 @@
"Send" : "Изпращане",
"Shared with you and the group {group} by {owner}" : "Споделено от {owner} с Вас и групата {group} .",
"Shared with you by {owner}" : "Споделено с Вас от {owner}.",
- "Shared in {item} with {user}" : "Споделено в {item} с {user}.",
"group" : "група",
"remote" : "отдалечен",
"notify by email" : "уведомяване по електронна поща",
@@ -124,9 +125,10 @@
"access control" : "контрол на достъпа",
"Share" : "Споделяне",
"Warning" : "Предупреждение",
+ "Delete" : "Изтриване",
+ "Rename" : "Преименуване",
"The object type is not specified." : "Видът на обекта не е избран.",
"Enter new" : "Въвеждане на нов",
- "Delete" : "Изтриване",
"Add" : "Добавяне",
"Edit tags" : "Промяна на етикетите",
"Error loading dialog template: {error}" : "Грешка при зареждането на шаблон за диалог: {error}.",
@@ -141,14 +143,6 @@
"Please reload the page." : "Моля, презаредете страницата.",
"The update was unsuccessful. " : "Обновяването бе неуспешно.",
"The update was successful. Redirecting you to ownCloud now." : "Обновяването е успешно. Сега Ви пренасочваме към ownCloud.",
- "Couldn't reset password because the token is invalid" : "Промяната на паролата е невъзможно, защото връзката за удостоверение не е валидна",
- "Couldn't send reset email. Please make sure your username is correct." : "Неуспешно изпращане на имейл за възстановяване на паролата. Моля, уверете се, че потребителското име е правилно.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Неуспешно изпращане на имейл за възстановяване на паролата, защото липсва имейл, свързан с това потребителско име. Моля, свържете се с администратора.",
- "%s password reset" : "Паролата на %s е променена.",
- "Use the following link to reset your password: {link}" : "Използвайте следната връзка, за да възстановите паролата си: {link}",
- "New password" : "Нова парола",
- "New Password" : "Нова Парола",
- "Reset password" : "Възстановяване на паролата",
"Searching other places" : "Търсене в други места",
"Personal" : "Лични",
"Users" : "Потребители",
@@ -208,6 +202,10 @@
"Please contact your administrator." : "Моля, свържете се с администратора.",
"Log in" : "Вписване",
"Alternative Logins" : "Алтернативни методи на вписване",
+ "Use the following link to reset your password: {link}" : "Използвайте следната връзка, за да възстановите паролата си: {link}",
+ "New password" : "Нова парола",
+ "New Password" : "Нова Парола",
+ "Reset password" : "Възстановяване на паролата",
"This ownCloud instance is currently in single user mode." : "В момента този ownCloud е в режим допускащ само един потребител.",
"This means only administrators can use the instance." : "Това означава, че само администраторът може да го използва.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Свържи се със системния си администратор ако това съобщение се задържи твърде дълго или се е появило неочаквано.",
diff --git a/core/l10n/bn_BD.js b/core/l10n/bn_BD.js
index 4730e70c633..57af67dd00e 100644
--- a/core/l10n/bn_BD.js
+++ b/core/l10n/bn_BD.js
@@ -65,7 +65,6 @@ OC.L10N.register(
"Error" : "সমস্যা",
"Error while sharing" : "ভাগাভাগি করতে সমস্যা দেখা দিয়েছে ",
"Error while unsharing" : "ভাগাভাগি বাতিল করতে সমস্যা দেখা দিয়েছে",
- "Error while changing permissions" : "অনুমতিসমূহ পরিবর্তন করতে সমস্যা দেখা দিয়েছে",
"Error setting expiration date" : "মেয়াদোত্তীর্ণ হওয়ার তারিখ নির্ধারণ করতে সমস্যা দেখা দিয়েছে",
"Set expiration date" : "মেয়াদোত্তীর্ণ হওয়ার তারিখ নির্ধারণ করুন",
"Expiration date" : "মেয়াদোত্তীর্ণ হওয়ার তারিখ",
@@ -79,7 +78,6 @@ OC.L10N.register(
"Send" : "পাঠাও",
"Shared with you and the group {group} by {owner}" : "{owner} আপনার এবং {group} গোষ্ঠীর সাথে ভাগাভাগি করেছেন",
"Shared with you by {owner}" : "{owner} আপনার সাথে ভাগাভাগি করেছেন",
- "Shared in {item} with {user}" : "{user} এর সাথে {item} ভাগাভাগি করা হয়েছে",
"group" : "দল",
"Unshare" : "ভাগাভাগি বাতিল ",
"can share" : "ভাগাভাগি করেত পারেন",
@@ -89,16 +87,13 @@ OC.L10N.register(
"access control" : "অধিগম্যতা নিয়ন্ত্রণ",
"Share" : "ভাগাভাগি কর",
"Warning" : "সতর্কবাণী",
+ "Delete" : "মুছে",
+ "Rename" : "পূনঃনামকরণ",
"The object type is not specified." : "অবজেক্টের ধরণটি সুনির্দিষ্ট নয়।",
"Enter new" : "নতুন লিখুন",
- "Delete" : "মুছে",
"Add" : "যোগ কর",
"Edit tags" : "ট্যাগ সম্পাদনা",
"Please reload the page." : "দয়া করে পৃষ্ঠাটি পূনরায় লোড করুন।",
- "Use the following link to reset your password: {link}" : "আপনার কূটশব্দটি পূনঃনির্ধারণ করার জন্য নিম্নোক্ত লিংকটি ব্যবহার করুনঃ {link}",
- "New password" : "নতুন কূটশব্দ",
- "New Password" : "নতুন কূটশব্দ",
- "Reset password" : "কূটশব্দ পূনঃনির্ধারণ কর",
"Personal" : "ব্যক্তিগত",
"Users" : "ব্যবহারকারী",
"Apps" : "অ্যাপ",
@@ -125,6 +120,10 @@ OC.L10N.register(
"Log out" : "প্রস্থান",
"Search" : "অনুসন্ধান",
"Log in" : "প্রবেশ",
- "Alternative Logins" : "বিকল্প লগইন"
+ "Alternative Logins" : "বিকল্প লগইন",
+ "Use the following link to reset your password: {link}" : "আপনার কূটশব্দটি পূনঃনির্ধারণ করার জন্য নিম্নোক্ত লিংকটি ব্যবহার করুনঃ {link}",
+ "New password" : "নতুন কূটশব্দ",
+ "New Password" : "নতুন কূটশব্দ",
+ "Reset password" : "কূটশব্দ পূনঃনির্ধারণ কর"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/bn_BD.json b/core/l10n/bn_BD.json
index d4de5a67aa9..11f75ab9f46 100644
--- a/core/l10n/bn_BD.json
+++ b/core/l10n/bn_BD.json
@@ -63,7 +63,6 @@
"Error" : "সমস্যা",
"Error while sharing" : "ভাগাভাগি করতে সমস্যা দেখা দিয়েছে ",
"Error while unsharing" : "ভাগাভাগি বাতিল করতে সমস্যা দেখা দিয়েছে",
- "Error while changing permissions" : "অনুমতিসমূহ পরিবর্তন করতে সমস্যা দেখা দিয়েছে",
"Error setting expiration date" : "মেয়াদোত্তীর্ণ হওয়ার তারিখ নির্ধারণ করতে সমস্যা দেখা দিয়েছে",
"Set expiration date" : "মেয়াদোত্তীর্ণ হওয়ার তারিখ নির্ধারণ করুন",
"Expiration date" : "মেয়াদোত্তীর্ণ হওয়ার তারিখ",
@@ -77,7 +76,6 @@
"Send" : "পাঠাও",
"Shared with you and the group {group} by {owner}" : "{owner} আপনার এবং {group} গোষ্ঠীর সাথে ভাগাভাগি করেছেন",
"Shared with you by {owner}" : "{owner} আপনার সাথে ভাগাভাগি করেছেন",
- "Shared in {item} with {user}" : "{user} এর সাথে {item} ভাগাভাগি করা হয়েছে",
"group" : "দল",
"Unshare" : "ভাগাভাগি বাতিল ",
"can share" : "ভাগাভাগি করেত পারেন",
@@ -87,16 +85,13 @@
"access control" : "অধিগম্যতা নিয়ন্ত্রণ",
"Share" : "ভাগাভাগি কর",
"Warning" : "সতর্কবাণী",
+ "Delete" : "মুছে",
+ "Rename" : "পূনঃনামকরণ",
"The object type is not specified." : "অবজেক্টের ধরণটি সুনির্দিষ্ট নয়।",
"Enter new" : "নতুন লিখুন",
- "Delete" : "মুছে",
"Add" : "যোগ কর",
"Edit tags" : "ট্যাগ সম্পাদনা",
"Please reload the page." : "দয়া করে পৃষ্ঠাটি পূনরায় লোড করুন।",
- "Use the following link to reset your password: {link}" : "আপনার কূটশব্দটি পূনঃনির্ধারণ করার জন্য নিম্নোক্ত লিংকটি ব্যবহার করুনঃ {link}",
- "New password" : "নতুন কূটশব্দ",
- "New Password" : "নতুন কূটশব্দ",
- "Reset password" : "কূটশব্দ পূনঃনির্ধারণ কর",
"Personal" : "ব্যক্তিগত",
"Users" : "ব্যবহারকারী",
"Apps" : "অ্যাপ",
@@ -123,6 +118,10 @@
"Log out" : "প্রস্থান",
"Search" : "অনুসন্ধান",
"Log in" : "প্রবেশ",
- "Alternative Logins" : "বিকল্প লগইন"
+ "Alternative Logins" : "বিকল্প লগইন",
+ "Use the following link to reset your password: {link}" : "আপনার কূটশব্দটি পূনঃনির্ধারণ করার জন্য নিম্নোক্ত লিংকটি ব্যবহার করুনঃ {link}",
+ "New password" : "নতুন কূটশব্দ",
+ "New Password" : "নতুন কূটশব্দ",
+ "Reset password" : "কূটশব্দ পূনঃনির্ধারণ কর"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/bn_IN.js b/core/l10n/bn_IN.js
index 21b59beec80..94a8e320f50 100644
--- a/core/l10n/bn_IN.js
+++ b/core/l10n/bn_IN.js
@@ -8,6 +8,7 @@ OC.L10N.register(
"Share" : "শেয়ার",
"Warning" : "সতর্কীকরণ",
"Delete" : "মুছে ফেলা",
+ "Rename" : "পুনঃনামকরণ",
"Add" : "যোগ করা",
"Username" : "ইউজারনেম",
"Search" : "অনুসন্ধান"
diff --git a/core/l10n/bn_IN.json b/core/l10n/bn_IN.json
index 67eddf4cfb4..7e396f78886 100644
--- a/core/l10n/bn_IN.json
+++ b/core/l10n/bn_IN.json
@@ -6,6 +6,7 @@
"Share" : "শেয়ার",
"Warning" : "সতর্কীকরণ",
"Delete" : "মুছে ফেলা",
+ "Rename" : "পুনঃনামকরণ",
"Add" : "যোগ করা",
"Username" : "ইউজারনেম",
"Search" : "অনুসন্ধান"
diff --git a/core/l10n/bs.js b/core/l10n/bs.js
index 7d0664e38ee..32766081862 100644
--- a/core/l10n/bs.js
+++ b/core/l10n/bs.js
@@ -12,6 +12,10 @@ OC.L10N.register(
"Unknown filetype" : "Nepoznat tip datoteke",
"Invalid image" : "Nevažeća datoteka",
"No temporary profile picture available, try again" : "Trenutna slika profila nije dostupna, pokušajte ponovo",
+ "Couldn't reset password because the token is invalid" : "Nemoguće resetiranje lozinke jer znak nije validan.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Slanje emaila resetovanja nije moguće. Osigurajte se da vam je ispravno korisničko ime.",
+ "%s password reset" : "%s lozinka resetovana",
+ "Couldn't send reset email. Please contact your administrator." : "Slanje emaila resetovanja nije moguće. Molim kontaktirajte administratora.",
"Sunday" : "Nedjelja",
"Monday" : "Ponedjeljak",
"Tuesday" : "Utorak",
@@ -52,7 +56,6 @@ OC.L10N.register(
"Dec." : "Dec.",
"Settings" : "Postavke",
"Saving..." : "Spašavam...",
- "Couldn't send reset email. Please contact your administrator." : "Slanje emaila resetovanja nije moguće. Molim kontaktirajte administratora.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Veza za resetovanje vaše lozinke poslana je na vašu adresu e-pošte. Ako je ne primite u nekom razumnom vremenskom roku, provjerite svoje spam/junk direktorij. <br> Ako nije tamo, kontaktirajte vašeg lokalnog administratora.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vaše datoteke su šifrirane. Ako niste aktivirali povratni ključ, neećete imati mogućnost povratka vaših podataka nakon što vaša lozinka bude resetovana.<br />Ako niste sigurni šta učiniti, prije nego nastavite, molimo kontaktirajte vašeg administratora. <br />Želite li zaista nastaviti?",
"I know what I'm doing" : "Ja znam šta radim",
@@ -85,7 +88,6 @@ OC.L10N.register(
"Error" : "Greška",
"Error while sharing" : "Greška pri dijeljenju",
"Error while unsharing" : "Ggreška pri prestanku dijeljenja",
- "Error while changing permissions" : "Greška pri mijenjanju dozvola",
"Error setting expiration date" : "Pogrešno postavljanje datuma isteka",
"The public link will expire no later than {days} days after it is created" : "Javna veza ističe najkasnije {days} dana nakon što je kreirana",
"Set expiration date" : "Postavite datum isteka",
@@ -104,7 +106,6 @@ OC.L10N.register(
"Send" : "Pošalji",
"Shared with you and the group {group} by {owner}" : "Dijeljeno s vama i grupom {group} vlasnika {owner}",
"Shared with you by {owner}" : "Podijeljeno sa vama od {owner}",
- "Shared in {item} with {user}" : "Podijeljeno u {item} s {user}",
"group" : "grupa",
"remote" : "daljinski",
"notify by email" : "Obavijesti e-poštom",
@@ -117,9 +118,10 @@ OC.L10N.register(
"access control" : "Kontrola pristupa",
"Share" : "Podijeli",
"Warning" : "Upozorenje",
+ "Delete" : "Izbriši",
+ "Rename" : "Preimenuj",
"The object type is not specified." : "Vrsta objekta nije određena.",
"Enter new" : "Unesi novi",
- "Delete" : "Izbriši",
"Add" : "Dodaj",
"Edit tags" : "Izmjeni oznake",
"Error loading dialog template: {error}" : "Pogrešno učitavanje šablona dijaloga: {error}",
@@ -132,14 +134,6 @@ OC.L10N.register(
"Please reload the page." : "Molim, ponovno učitajte stranicu",
"The update was unsuccessful. " : "Ažuriranje nije uspjelo.",
"The update was successful. Redirecting you to ownCloud now." : "Ažuriranje je uspjelo. Preusmjeravam vas na ownCloud.",
- "Couldn't reset password because the token is invalid" : "Nemoguće resetiranje lozinke jer znak nije validan.",
- "Couldn't send reset email. Please make sure your username is correct." : "Slanje emaila resetovanja nije moguće. Osigurajte se da vam je ispravno korisničko ime.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Slanje emaila resetovanja nije moguće jer za ovo korisničko ime ne postoji email adresa. Molim, kontaktirajte administratora.",
- "%s password reset" : "%s lozinka resetovana",
- "Use the following link to reset your password: {link}" : "Za resetovanje vaše lozinke koristite slijedeću vezu: {link}",
- "New password" : "Nova lozinka",
- "New Password" : "Nova Lozinka",
- "Reset password" : "Resetuj lozinku",
"Personal" : "Osobno",
"Users" : "Korisnici",
"Apps" : "Aplikacije",
@@ -189,6 +183,10 @@ OC.L10N.register(
"Please contact your administrator." : "Molim kontaktirajte svog administratora.",
"Log in" : "Prijava",
"Alternative Logins" : "Alternativne Prijave",
+ "Use the following link to reset your password: {link}" : "Za resetovanje vaše lozinke koristite slijedeću vezu: {link}",
+ "New password" : "Nova lozinka",
+ "New Password" : "Nova Lozinka",
+ "Reset password" : "Resetuj lozinku",
"This ownCloud instance is currently in single user mode." : "Ova ownCloud instanca je trenutno u jednokorisničkom načinu rada.",
"This means only administrators can use the instance." : "To znači da tu instancu mogu koristiti samo administratori.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktirajte svog administratora sistema ako se ova poruka ponavlja ili se pojavila neočekivano.",
diff --git a/core/l10n/bs.json b/core/l10n/bs.json
index e221dba005d..77a7fb6fa44 100644
--- a/core/l10n/bs.json
+++ b/core/l10n/bs.json
@@ -10,6 +10,10 @@
"Unknown filetype" : "Nepoznat tip datoteke",
"Invalid image" : "Nevažeća datoteka",
"No temporary profile picture available, try again" : "Trenutna slika profila nije dostupna, pokušajte ponovo",
+ "Couldn't reset password because the token is invalid" : "Nemoguće resetiranje lozinke jer znak nije validan.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Slanje emaila resetovanja nije moguće. Osigurajte se da vam je ispravno korisničko ime.",
+ "%s password reset" : "%s lozinka resetovana",
+ "Couldn't send reset email. Please contact your administrator." : "Slanje emaila resetovanja nije moguće. Molim kontaktirajte administratora.",
"Sunday" : "Nedjelja",
"Monday" : "Ponedjeljak",
"Tuesday" : "Utorak",
@@ -50,7 +54,6 @@
"Dec." : "Dec.",
"Settings" : "Postavke",
"Saving..." : "Spašavam...",
- "Couldn't send reset email. Please contact your administrator." : "Slanje emaila resetovanja nije moguće. Molim kontaktirajte administratora.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Veza za resetovanje vaše lozinke poslana je na vašu adresu e-pošte. Ako je ne primite u nekom razumnom vremenskom roku, provjerite svoje spam/junk direktorij. <br> Ako nije tamo, kontaktirajte vašeg lokalnog administratora.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vaše datoteke su šifrirane. Ako niste aktivirali povratni ključ, neećete imati mogućnost povratka vaših podataka nakon što vaša lozinka bude resetovana.<br />Ako niste sigurni šta učiniti, prije nego nastavite, molimo kontaktirajte vašeg administratora. <br />Želite li zaista nastaviti?",
"I know what I'm doing" : "Ja znam šta radim",
@@ -83,7 +86,6 @@
"Error" : "Greška",
"Error while sharing" : "Greška pri dijeljenju",
"Error while unsharing" : "Ggreška pri prestanku dijeljenja",
- "Error while changing permissions" : "Greška pri mijenjanju dozvola",
"Error setting expiration date" : "Pogrešno postavljanje datuma isteka",
"The public link will expire no later than {days} days after it is created" : "Javna veza ističe najkasnije {days} dana nakon što je kreirana",
"Set expiration date" : "Postavite datum isteka",
@@ -102,7 +104,6 @@
"Send" : "Pošalji",
"Shared with you and the group {group} by {owner}" : "Dijeljeno s vama i grupom {group} vlasnika {owner}",
"Shared with you by {owner}" : "Podijeljeno sa vama od {owner}",
- "Shared in {item} with {user}" : "Podijeljeno u {item} s {user}",
"group" : "grupa",
"remote" : "daljinski",
"notify by email" : "Obavijesti e-poštom",
@@ -115,9 +116,10 @@
"access control" : "Kontrola pristupa",
"Share" : "Podijeli",
"Warning" : "Upozorenje",
+ "Delete" : "Izbriši",
+ "Rename" : "Preimenuj",
"The object type is not specified." : "Vrsta objekta nije određena.",
"Enter new" : "Unesi novi",
- "Delete" : "Izbriši",
"Add" : "Dodaj",
"Edit tags" : "Izmjeni oznake",
"Error loading dialog template: {error}" : "Pogrešno učitavanje šablona dijaloga: {error}",
@@ -130,14 +132,6 @@
"Please reload the page." : "Molim, ponovno učitajte stranicu",
"The update was unsuccessful. " : "Ažuriranje nije uspjelo.",
"The update was successful. Redirecting you to ownCloud now." : "Ažuriranje je uspjelo. Preusmjeravam vas na ownCloud.",
- "Couldn't reset password because the token is invalid" : "Nemoguće resetiranje lozinke jer znak nije validan.",
- "Couldn't send reset email. Please make sure your username is correct." : "Slanje emaila resetovanja nije moguće. Osigurajte se da vam je ispravno korisničko ime.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Slanje emaila resetovanja nije moguće jer za ovo korisničko ime ne postoji email adresa. Molim, kontaktirajte administratora.",
- "%s password reset" : "%s lozinka resetovana",
- "Use the following link to reset your password: {link}" : "Za resetovanje vaše lozinke koristite slijedeću vezu: {link}",
- "New password" : "Nova lozinka",
- "New Password" : "Nova Lozinka",
- "Reset password" : "Resetuj lozinku",
"Personal" : "Osobno",
"Users" : "Korisnici",
"Apps" : "Aplikacije",
@@ -187,6 +181,10 @@
"Please contact your administrator." : "Molim kontaktirajte svog administratora.",
"Log in" : "Prijava",
"Alternative Logins" : "Alternativne Prijave",
+ "Use the following link to reset your password: {link}" : "Za resetovanje vaše lozinke koristite slijedeću vezu: {link}",
+ "New password" : "Nova lozinka",
+ "New Password" : "Nova Lozinka",
+ "Reset password" : "Resetuj lozinku",
"This ownCloud instance is currently in single user mode." : "Ova ownCloud instanca je trenutno u jednokorisničkom načinu rada.",
"This means only administrators can use the instance." : "To znači da tu instancu mogu koristiti samo administratori.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktirajte svog administratora sistema ako se ova poruka ponavlja ili se pojavila neočekivano.",
diff --git a/core/l10n/ca.js b/core/l10n/ca.js
index f1eb5f51db9..d437b19d614 100644
--- a/core/l10n/ca.js
+++ b/core/l10n/ca.js
@@ -23,6 +23,11 @@ OC.L10N.register(
"No crop data provided" : "No heu proporcionat dades del retall",
"No valid crop data provided" : "Les dades del retall proporcionades no són vàlides",
"Crop is not square" : "El retall no és quadrat",
+ "Couldn't reset password because the token is invalid" : "No es pot restablir la contrasenya perquè el testimoni no és vàlid",
+ "Couldn't reset password because the token is expired" : "No es pot restablir la contrasenya perquè el testimoni ha vençut",
+ "Couldn't send reset email. Please make sure your username is correct." : "No s'ha pogut enviar el correu de restabliment. Assegureu-vos que el vostre nom d'usuari és correcte.",
+ "%s password reset" : "restableix la contrasenya %s",
+ "Couldn't send reset email. Please contact your administrator." : "No s'ha pogut restablir el correu. Contacteu amb l'administrador.",
"Sunday" : "Diumenge",
"Monday" : "Dilluns",
"Tuesday" : "Dimarts",
@@ -71,7 +76,6 @@ OC.L10N.register(
"Settings" : "Configuració",
"Saving..." : "Desant...",
"seconds ago" : "segons enrere",
- "Couldn't send reset email. Please contact your administrator." : "No s'ha pogut restablir el correu. Contacteu amb l'administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "L'enllaç per reiniciar la vostra contrasenya s'ha enviat al vostre correu. Si no el rebeu en un temps raonable comproveu les carpetes de spam. <br>Si no és allà, pregunteu a l'administrador local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Els vostres fitxers estan encriptats. Si no heu habilitat la clau de recuperació no hi haurà manera de recuperar les dades després que reestabliu la contrasenya. <br />Si sabeu què fer, contacteu amb l'administrador abans de continuar.<br />Voleu continuar?",
"I know what I'm doing" : "Sé el que faig",
@@ -102,9 +106,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "El servidor web no està configurat correctament per permetre la sincronització de fitxers perquè la interfície WebDAV sembla no funcionar correctament.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Aquest servidor no té connexió a internet. Això significa que algunes de les característiques com el muntatge d'emmagatzemament extern, les notificacions quant a actualitzacions o la instal·lació d'aplicacions de tercers no funcionarà. L'accés remot a fitxers i l'enviament de correus electrònics podria tampoc no funcionar. Us suggerim que habiliteu la connexió a internet per aquest servidor si voleu tenir totes les característiques.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "La carpeta de dades i els vostres fitxers probablement són accessibles des d'Internet. El fitxer .htaccess no funciona. Us recomanem que configureu el servidor web de tal manera que la carpeta de dades no sigui accessible o que moveu la carpeta de dades fora de l'arrel de documents del servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "No hi ha configurada cap memòria cau. Per millorar el rendiment configureu una memòria cau si està disponible. Podeu trobar més informació a la <a href=\"{docLink}\">documentació</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP no pot llegir /dev/urandom, cosa poc recomanable per raons de seguretat. Podeu trobar més informació a la <a href=\"{docLink}\">documentació</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La versió de PHP ({version}) ja no està <a href=\"{phpLink}\">mantinguda per PHP</a>. Us recomanem que actualitzeu la versió per gaudir de les millores de rendiment i seguretat proporcionades per PHP.",
"Error occurred while checking server setup" : "Hi ha hagut un error en comprovar la configuració del servidor",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Esteu accedint aquesta web a través de HTTP. Us recomanem que configureu el servidor per requerir HTTPS tal i com es descriu als <a href=\"{docUrl}\">consells de seguretat</a>",
"Shared" : "Compartit",
@@ -112,7 +113,6 @@ OC.L10N.register(
"Error" : "Error",
"Error while sharing" : "Error en compartir",
"Error while unsharing" : "Error en deixar de compartir",
- "Error while changing permissions" : "Error en canviar els permisos",
"Error setting expiration date" : "Error en establir la data de venciment",
"The public link will expire no later than {days} days after it is created" : "L'enllaç públic tindrà venciment abans de {days} dies després de crear-lo",
"Set expiration date" : "Estableix la data de venciment",
@@ -131,7 +131,6 @@ OC.L10N.register(
"Send" : "Envia",
"Shared with you and the group {group} by {owner}" : "Compartit amb vos i amb el grup {group} per {owner}",
"Shared with you by {owner}" : "Compartit amb vos per {owner}",
- "Shared in {item} with {user}" : "Compartit en {item} amb {user}",
"group" : "grup",
"remote" : "remot",
"notify by email" : "notifica per correu electrònic",
@@ -148,9 +147,10 @@ OC.L10N.register(
"Share with users or groups …" : "Comparteix amb usuaris o grups ...",
"Share with users, groups or remote users …" : "Comparteix amb usuaris, grups o usuaris remots ...",
"Warning" : "Avís",
+ "Delete" : "Esborra",
+ "Rename" : "Reanomena",
"The object type is not specified." : "No s'ha especificat el tipus d'objecte.",
"Enter new" : "Escriu nou",
- "Delete" : "Esborra",
"Add" : "Afegeix",
"Edit tags" : "Edita etiquetes",
"Error loading dialog template: {error}" : "Error en carregar la plantilla de diàleg: {error}",
@@ -167,15 +167,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "La actualització no ha tingut èxit",
"The update was successful. There were warnings." : "La actualització ha estat exitosa. Hi ha alertes.",
"The update was successful. Redirecting you to ownCloud now." : "L'actualització ha estat correcte. Ara us redirigim a ownCloud.",
- "Couldn't reset password because the token is invalid" : "No es pot restablir la contrasenya perquè el testimoni no és vàlid",
- "Couldn't reset password because the token is expired" : "No es pot restablir la contrasenya perquè el testimoni ha vençut",
- "Couldn't send reset email. Please make sure your username is correct." : "No s'ha pogut enviar el correu de restabliment. Assegureu-vos que el vostre nom d'usuari és correcte.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "No s'ha pogut enviar el correu de restabliment perquè no hi ha cap correu electrònic per aquest usuari. Contacteu amb l'administrador.",
- "%s password reset" : "restableix la contrasenya %s",
- "Use the following link to reset your password: {link}" : "Useu l'enllaç següent per restablir la contrasenya: {link}",
- "New password" : "Contrasenya nova",
- "New Password" : "Contrasenya nova",
- "Reset password" : "Reinicialitza la contrasenya",
"Searching other places" : "Buscant altres ubicacions",
"Personal" : "Personal",
"Users" : "Usuaris",
@@ -243,7 +234,13 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Intenti-ho de nou o posi's en contacte amb el seu administrador.",
"Log in" : "Inici de sessió",
"Wrong password. Reset it?" : "Contrasenya incorrecta. Voleu restablir-la?",
+ "Wrong password." : "Contrasenya incorrecta.",
+ "Stay logged in" : "Mantén la sessió connectada",
"Alternative Logins" : "Acreditacions alternatives",
+ "Use the following link to reset your password: {link}" : "Useu l'enllaç següent per restablir la contrasenya: {link}",
+ "New password" : "Contrasenya nova",
+ "New Password" : "Contrasenya nova",
+ "Reset password" : "Reinicialitza la contrasenya",
"This ownCloud instance is currently in single user mode." : "La instància ownCloud està en mode d'usuari únic.",
"This means only administrators can use the instance." : "Això significa que només els administradors poden usar la instància.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacteu amb l'administrador del sistema si aquest missatge persisteix o apareix inesperadament.",
diff --git a/core/l10n/ca.json b/core/l10n/ca.json
index 0b14ef2ff2a..46cd0fabae1 100644
--- a/core/l10n/ca.json
+++ b/core/l10n/ca.json
@@ -21,6 +21,11 @@
"No crop data provided" : "No heu proporcionat dades del retall",
"No valid crop data provided" : "Les dades del retall proporcionades no són vàlides",
"Crop is not square" : "El retall no és quadrat",
+ "Couldn't reset password because the token is invalid" : "No es pot restablir la contrasenya perquè el testimoni no és vàlid",
+ "Couldn't reset password because the token is expired" : "No es pot restablir la contrasenya perquè el testimoni ha vençut",
+ "Couldn't send reset email. Please make sure your username is correct." : "No s'ha pogut enviar el correu de restabliment. Assegureu-vos que el vostre nom d'usuari és correcte.",
+ "%s password reset" : "restableix la contrasenya %s",
+ "Couldn't send reset email. Please contact your administrator." : "No s'ha pogut restablir el correu. Contacteu amb l'administrador.",
"Sunday" : "Diumenge",
"Monday" : "Dilluns",
"Tuesday" : "Dimarts",
@@ -69,7 +74,6 @@
"Settings" : "Configuració",
"Saving..." : "Desant...",
"seconds ago" : "segons enrere",
- "Couldn't send reset email. Please contact your administrator." : "No s'ha pogut restablir el correu. Contacteu amb l'administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "L'enllaç per reiniciar la vostra contrasenya s'ha enviat al vostre correu. Si no el rebeu en un temps raonable comproveu les carpetes de spam. <br>Si no és allà, pregunteu a l'administrador local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Els vostres fitxers estan encriptats. Si no heu habilitat la clau de recuperació no hi haurà manera de recuperar les dades després que reestabliu la contrasenya. <br />Si sabeu què fer, contacteu amb l'administrador abans de continuar.<br />Voleu continuar?",
"I know what I'm doing" : "Sé el que faig",
@@ -100,9 +104,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "El servidor web no està configurat correctament per permetre la sincronització de fitxers perquè la interfície WebDAV sembla no funcionar correctament.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Aquest servidor no té connexió a internet. Això significa que algunes de les característiques com el muntatge d'emmagatzemament extern, les notificacions quant a actualitzacions o la instal·lació d'aplicacions de tercers no funcionarà. L'accés remot a fitxers i l'enviament de correus electrònics podria tampoc no funcionar. Us suggerim que habiliteu la connexió a internet per aquest servidor si voleu tenir totes les característiques.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "La carpeta de dades i els vostres fitxers probablement són accessibles des d'Internet. El fitxer .htaccess no funciona. Us recomanem que configureu el servidor web de tal manera que la carpeta de dades no sigui accessible o que moveu la carpeta de dades fora de l'arrel de documents del servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "No hi ha configurada cap memòria cau. Per millorar el rendiment configureu una memòria cau si està disponible. Podeu trobar més informació a la <a href=\"{docLink}\">documentació</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP no pot llegir /dev/urandom, cosa poc recomanable per raons de seguretat. Podeu trobar més informació a la <a href=\"{docLink}\">documentació</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La versió de PHP ({version}) ja no està <a href=\"{phpLink}\">mantinguda per PHP</a>. Us recomanem que actualitzeu la versió per gaudir de les millores de rendiment i seguretat proporcionades per PHP.",
"Error occurred while checking server setup" : "Hi ha hagut un error en comprovar la configuració del servidor",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Esteu accedint aquesta web a través de HTTP. Us recomanem que configureu el servidor per requerir HTTPS tal i com es descriu als <a href=\"{docUrl}\">consells de seguretat</a>",
"Shared" : "Compartit",
@@ -110,7 +111,6 @@
"Error" : "Error",
"Error while sharing" : "Error en compartir",
"Error while unsharing" : "Error en deixar de compartir",
- "Error while changing permissions" : "Error en canviar els permisos",
"Error setting expiration date" : "Error en establir la data de venciment",
"The public link will expire no later than {days} days after it is created" : "L'enllaç públic tindrà venciment abans de {days} dies després de crear-lo",
"Set expiration date" : "Estableix la data de venciment",
@@ -129,7 +129,6 @@
"Send" : "Envia",
"Shared with you and the group {group} by {owner}" : "Compartit amb vos i amb el grup {group} per {owner}",
"Shared with you by {owner}" : "Compartit amb vos per {owner}",
- "Shared in {item} with {user}" : "Compartit en {item} amb {user}",
"group" : "grup",
"remote" : "remot",
"notify by email" : "notifica per correu electrònic",
@@ -146,9 +145,10 @@
"Share with users or groups …" : "Comparteix amb usuaris o grups ...",
"Share with users, groups or remote users …" : "Comparteix amb usuaris, grups o usuaris remots ...",
"Warning" : "Avís",
+ "Delete" : "Esborra",
+ "Rename" : "Reanomena",
"The object type is not specified." : "No s'ha especificat el tipus d'objecte.",
"Enter new" : "Escriu nou",
- "Delete" : "Esborra",
"Add" : "Afegeix",
"Edit tags" : "Edita etiquetes",
"Error loading dialog template: {error}" : "Error en carregar la plantilla de diàleg: {error}",
@@ -165,15 +165,6 @@
"The update was unsuccessful. " : "La actualització no ha tingut èxit",
"The update was successful. There were warnings." : "La actualització ha estat exitosa. Hi ha alertes.",
"The update was successful. Redirecting you to ownCloud now." : "L'actualització ha estat correcte. Ara us redirigim a ownCloud.",
- "Couldn't reset password because the token is invalid" : "No es pot restablir la contrasenya perquè el testimoni no és vàlid",
- "Couldn't reset password because the token is expired" : "No es pot restablir la contrasenya perquè el testimoni ha vençut",
- "Couldn't send reset email. Please make sure your username is correct." : "No s'ha pogut enviar el correu de restabliment. Assegureu-vos que el vostre nom d'usuari és correcte.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "No s'ha pogut enviar el correu de restabliment perquè no hi ha cap correu electrònic per aquest usuari. Contacteu amb l'administrador.",
- "%s password reset" : "restableix la contrasenya %s",
- "Use the following link to reset your password: {link}" : "Useu l'enllaç següent per restablir la contrasenya: {link}",
- "New password" : "Contrasenya nova",
- "New Password" : "Contrasenya nova",
- "Reset password" : "Reinicialitza la contrasenya",
"Searching other places" : "Buscant altres ubicacions",
"Personal" : "Personal",
"Users" : "Usuaris",
@@ -241,7 +232,13 @@
"Please try again or contact your administrator." : "Intenti-ho de nou o posi's en contacte amb el seu administrador.",
"Log in" : "Inici de sessió",
"Wrong password. Reset it?" : "Contrasenya incorrecta. Voleu restablir-la?",
+ "Wrong password." : "Contrasenya incorrecta.",
+ "Stay logged in" : "Mantén la sessió connectada",
"Alternative Logins" : "Acreditacions alternatives",
+ "Use the following link to reset your password: {link}" : "Useu l'enllaç següent per restablir la contrasenya: {link}",
+ "New password" : "Contrasenya nova",
+ "New Password" : "Contrasenya nova",
+ "Reset password" : "Reinicialitza la contrasenya",
"This ownCloud instance is currently in single user mode." : "La instància ownCloud està en mode d'usuari únic.",
"This means only administrators can use the instance." : "Això significa que només els administradors poden usar la instància.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacteu amb l'administrador del sistema si aquest missatge persisteix o apareix inesperadament.",
diff --git a/core/l10n/cs_CZ.js b/core/l10n/cs_CZ.js
index 8f6f3b38d9e..8fcfef6f2b4 100644
--- a/core/l10n/cs_CZ.js
+++ b/core/l10n/cs_CZ.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Aktualizováno z \"%s\" na %s",
"Repair warning: " : "Upozornění opravy:",
"Repair error: " : "Chyba opravy:",
- "Set log level to debug - current level: \"%s\"" : "Nastavit úroveň logování na debug - aktuální úroveň: \"%s\"",
- "Reset log level to \"%s\"" : "Vrátit úroveň logování na \"%s\"",
+ "Set log level to debug" : "Nastavit úroveň logování na debug",
+ "Reset log level" : "Resetovat úroveň logování",
+ "Starting code integrity check" : "Spouští se kontrola integrity kódu",
+ "Finished code integrity check" : "Kontrola integrity kódu dokončena",
"%s (3rdparty)" : "%s (3. strana)",
"%s (incompatible)" : "%s (nekompatibilní)",
"Following apps have been disabled: %s" : "Následující aplikace byly vypnuty: %s",
"Already up to date" : "Je již aktuální",
+ "Please select a file." : "Prosím vyberte soubor.",
"File is too big" : "Soubor je příliš velký",
"Invalid file provided" : "Zadán neplatný soubor",
"No image or file provided" : "Soubor nebo obrázek nebyl zadán",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "Nebyla poskytnuta data pro oříznutí obrázku",
"No valid crop data provided" : "Nebyla poskytnuta platná data pro oříznutí obrázku",
"Crop is not square" : "Ořez není čtvercový",
+ "Couldn't reset password because the token is invalid" : "Heslo nebylo změněno kvůli neplatnému tokenu",
+ "Couldn't reset password because the token is expired" : "Heslo nebylo změněno z důvodu vypršení tokenu",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nelze odeslat email pro změnu hesla. Ujistěte se prosím, že zadáváte správné uživatelské jméno.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Nelze odeslat email pro změnu hesla, protože u tohoto uživatelského jména není uvedena emailová adresa. Kontaktujte prosím svého administrátora.",
+ "%s password reset" : "reset hesla %s",
+ "Couldn't send reset email. Please contact your administrator." : "Nepodařilo se odeslat email pro změnu hesla. Kontaktujte svého správce systému.",
"Sunday" : "Neděle",
"Monday" : "Pondělí",
"Tuesday" : "Úterý",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "íjen",
"Nov." : "listopad",
"Dec." : "prosinec",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Došlo k problémům při kontrole integrity kódu. Více informací…</a>",
"Settings" : "Nastavení",
"Saving..." : "Ukládám...",
"seconds ago" : "před pár sekundami",
- "Couldn't send reset email. Please contact your administrator." : "Nepodařilo se odeslat email pro změnu hesla. Kontaktujte svého správce systému.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Odkaz na obnovení hesla byl odeslán na vaši emailovou adresu. Pokud jej v krátké době neobdržíte, zkontrolujte složku nevyžádané pošty a koš.<br>Pokud jej nenaleznete, kontaktujte svého správce systému.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vaše soubory jsou šifrovány. Pokud jste nepovolili klíč pro obnovení, neexistuje způsob jak získat po změně hesla vaše data zpět.<br />Pokud si nejste jisti co dělat, kontaktujte nejprve svého správce systému, než budete pokračovat. <br />Opravdu si přejete pokračovat?",
"I know what I'm doing" : "Vím co dělám",
@@ -109,13 +118,15 @@ OC.L10N.register(
"Good password" : "Dobré heslo",
"Strong password" : "Silné heslo",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Váš webový server ještě není správně nastaven pro umožnění synchronizace souborů, protože rozhraní WebDAV je pravděpodobně rozbité.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Tento webový server není správně nastaven pro rozpoznání \"{url}\". Více informací lze nalézt v naší <a target=\"_blank\" href=\"{docLink}\">dokumentaci</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Tento server nemá funkční připojení k Internetu. Některé moduly jako např. externí úložiště, oznámení o dostupných aktualizacích nebo instalace aplikací třetích stran nebudou fungovat. Přístup k souborům z jiných míst a odesílání oznamovacích emailů také nemusí fungovat. Pokud chcete využívat všechny možnosti ownCloud, doporučujeme povolit pro tento server připojení k Internetu.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Váš datový adresář i vaše soubory jsou pravděpodobně přístupné z Internetu. Soubor .htaccess nefunguje. Důrazně doporučujeme nakonfigurovat webový server tak, aby datový adresář nebyl nadále přístupný, nebo přesunout datový adresář mimo prostor zpřístupňovaný webovým serverem.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nebyla nakonfigurována paměťová cache. Pro zlepšení výkonu a dostupnosti ji prosím nakonfigurujte. Další informace lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP nemá práva pro čtení v /dev/urandom, to je ale z bezpečnostních důvodů velmi doporučováno. Více informací lze nalézt v <a href=\"{docLink}\">dokumentaci</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Vaše verze PHP ({version}) již není <a href=\"{phpLink}\">podporována</a>. Doporučujeme aktualizovat na poslední verzi PHP pro využití vylepšení výkonu a bezpečnosti.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Konfigurace hlaviček zpětné proxy není správná nebo přistupujete na ownCloud přes důvěryhodnou proxy. Pokud přistupujete na ownCloud přes nedůvěryhodnou proxy je toto považováno za bezpečnostní problém který může útočníkovi umožnit záměnu IP adresy viděné ownCloudem. Více informací lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached je nakonfigurován jako distribuovaná cache, ale je nainstalován nesprávný PHP modul \"memcache\". \\OC\\Memcache\\Memcached podporuje pouze \"memcached\" a ne \"memcache\". Projděte si <a href=\"{wikiLink}\">memcached wiki popisující oba moduly</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Nebyla nakonfigurována paměťová cache. Pro zlepšení výkonu a dostupnosti ji prosím nakonfigurujte. Další informace lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "PHP nemá práva pro čtení v /dev/urandom, to je ale z bezpečnostních důvodů velmi doporučováno. Více informací lze nalézt v <a href=\"{docLink}\">dokumentaci</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Vaše verze PHP ({version}) již není <a href=\"{phpLink}\">podporována</a>. Doporučujeme aktualizovat na poslední verzi PHP pro využití vylepšení výkonu a bezpečnosti.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Konfigurace hlaviček zpětné proxy není správná nebo přistupujete na ownCloud přes důvěryhodnou proxy. Pokud přistupujete na ownCloud přes nedůvěryhodnou proxy je toto považováno za bezpečnostní problém který může útočníkovi umožnit záměnu IP adresy viděné ownCloudem. Více informací lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached je nakonfigurován jako distribuovaná cache, ale je nainstalován nesprávný PHP modul \"memcache\". \\OC\\Memcache\\Memcached podporuje pouze \"memcached\" a ne \"memcache\". Projděte si <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki popisující oba moduly</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Některé soubory neprošly kontrolou integrity. Více informací o tom jak tento problém vyřešit, lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>. (<a target=\"_blank\" href=\"{codeIntegrityDownloadEndpoint}\">Seznam neplatných souborů…</a> / <a href=\"{rescanEndpoint}\">Znovu ověřit…</a>)",
"Error occurred while checking server setup" : "Při ověřování nastavení serveru došlo k chybě",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP hlavička \"{header}\" není nakonfigurována ve shodě s \"{expected}\". To značí možné ohrožení bezpečnosti a soukromí a je doporučeno toto nastavení upravit.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP hlavička \"Strict-Transport-Security\" není nakonfigurována na minimum \"{seconds}\" sekund. Pro vylepšení bezpečnosti doporučujeme povolit HSTS dle popisu v našich <a href=\"{docUrl}\">bezpečnostních tipech</a>.",
@@ -125,7 +136,6 @@ OC.L10N.register(
"Error" : "Chyba",
"Error while sharing" : "Chyba při sdílení",
"Error while unsharing" : "Chyba při rušení sdílení",
- "Error while changing permissions" : "Chyba při změně oprávnění",
"Error setting expiration date" : "Chyba při nastavení data vypršení platnosti",
"The public link will expire no later than {days} days after it is created" : "Veřejný odkaz vyprší nejpozději {days} dní od svého vytvoření",
"Set expiration date" : "Nastavit datum vypršení platnosti",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "Odeslat",
"Shared with you and the group {group} by {owner}" : "S Vámi a skupinou {group} sdílí {owner}",
"Shared with you by {owner}" : "S Vámi sdílí {owner}",
- "Shared in {item} with {user}" : "Sdíleno v {item} s {user}",
"group" : "skupina",
"remote" : "vzdálený",
"notify by email" : "upozornit emailem",
@@ -155,17 +164,25 @@ OC.L10N.register(
"change" : "změnit",
"delete" : "smazat",
"access control" : "řízení přístupu",
+ "Could not unshare" : "Nelze zrušit sdílení",
"Share details could not be loaded for this item." : "Detaily sdílení pro tuto položku nelze načíst.",
"An error occured. Please try again" : "Nastala chyba. Prosím zkuste to znovu",
"Share" : "Sdílet",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Sdílejte s lidmi na ownClouds použitím syntaxe username@example.com/owncloud",
"Share with users or groups …" : "Sdílet s uživateli nebo skupinami",
"Share with users, groups or remote users …" : "Sdílet s uživateli, skupinami nebo vzdálenými uživateli",
+ "Error removing share" : "Chyba při odstraňování sdílení",
"Warning" : "Varování",
"Error while sending notification" : "Chyba při odesílání upozornění",
+ "Non-existing tag #{tag}" : "Neexistující tag #{tag}",
+ "not assignable" : "nepřiřaditelný",
+ "invisible" : "neviditelný",
+ "({scope})" : "({scope})",
+ "Delete" : "Smazat",
+ "Rename" : "Přejmenovat",
+ "Global tags" : "Globální tagy",
"The object type is not specified." : "Není určen typ objektu.",
"Enter new" : "Zadat nový",
- "Delete" : "Smazat",
"Add" : "Přidat",
"Edit tags" : "Editovat štítky",
"Error loading dialog template: {error}" : "Chyba při načítání šablony dialogu: {error}",
@@ -184,15 +201,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Aktualizace nebyla úspěšná.",
"The update was successful. There were warnings." : "Aktualizace byla úspěšná. Zachycen výskyt varování.",
"The update was successful. Redirecting you to ownCloud now." : "Aktualizace byla úspěšná. Přesměrovávám na ownCloud.",
- "Couldn't reset password because the token is invalid" : "Heslo nebylo změněno kvůli neplatnému tokenu",
- "Couldn't reset password because the token is expired" : "Heslo nebylo změněno z důvodu vypršení tokenu",
- "Couldn't send reset email. Please make sure your username is correct." : "Nelze odeslat email pro změnu hesla. Ujistěte se prosím, že zadáváte správné uživatelské jméno.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nelze odeslat email pro změnu hesla, protože u tohoto uživatelského jména není uvedena emailová adresa. Kontaktujte prosím svého správce systému.",
- "%s password reset" : "reset hesla %s",
- "Use the following link to reset your password: {link}" : "Heslo obnovíte použitím následujícího odkazu: {link}",
- "New password" : "Nové heslo",
- "New Password" : "Nové heslo",
- "Reset password" : "Obnovit heslo",
"Searching other places" : "Prohledávání ostatních umístění",
"No search results in other folders" : "V ostatních adresářích nebylo nic nalezeno",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} nález v dalším adresáři","{count} nálezy v dalších adresářích","{count} nálezů v dalších adresářích"],
@@ -262,8 +270,13 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Prosím zkuste to znovu nebo kontaktujte vašeho správce.",
"Log in" : "Přihlásit",
"Wrong password. Reset it?" : "Nesprávné heslo. Resetovat?",
+ "Wrong password." : "Chybné heslo.",
"Stay logged in" : "Neodhlašovat",
"Alternative Logins" : "Alternativní přihlášení",
+ "Use the following link to reset your password: {link}" : "Heslo obnovíte použitím následujícího odkazu: {link}",
+ "New password" : "Nové heslo",
+ "New Password" : "Nové heslo",
+ "Reset password" : "Obnovit heslo",
"This ownCloud instance is currently in single user mode." : "Tato instalace ownCloudu je momentálně v jednouživatelském módu.",
"This means only administrators can use the instance." : "To znamená, že pouze správci systému mohou aplikaci používat.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktujte prosím správce systému, pokud se tato zpráva objevuje opakovaně nebo nečekaně.",
diff --git a/core/l10n/cs_CZ.json b/core/l10n/cs_CZ.json
index 024e00159b3..19c22abd616 100644
--- a/core/l10n/cs_CZ.json
+++ b/core/l10n/cs_CZ.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "Aktualizováno z \"%s\" na %s",
"Repair warning: " : "Upozornění opravy:",
"Repair error: " : "Chyba opravy:",
- "Set log level to debug - current level: \"%s\"" : "Nastavit úroveň logování na debug - aktuální úroveň: \"%s\"",
- "Reset log level to \"%s\"" : "Vrátit úroveň logování na \"%s\"",
+ "Set log level to debug" : "Nastavit úroveň logování na debug",
+ "Reset log level" : "Resetovat úroveň logování",
+ "Starting code integrity check" : "Spouští se kontrola integrity kódu",
+ "Finished code integrity check" : "Kontrola integrity kódu dokončena",
"%s (3rdparty)" : "%s (3. strana)",
"%s (incompatible)" : "%s (nekompatibilní)",
"Following apps have been disabled: %s" : "Následující aplikace byly vypnuty: %s",
"Already up to date" : "Je již aktuální",
+ "Please select a file." : "Prosím vyberte soubor.",
"File is too big" : "Soubor je příliš velký",
"Invalid file provided" : "Zadán neplatný soubor",
"No image or file provided" : "Soubor nebo obrázek nebyl zadán",
@@ -30,6 +33,12 @@
"No crop data provided" : "Nebyla poskytnuta data pro oříznutí obrázku",
"No valid crop data provided" : "Nebyla poskytnuta platná data pro oříznutí obrázku",
"Crop is not square" : "Ořez není čtvercový",
+ "Couldn't reset password because the token is invalid" : "Heslo nebylo změněno kvůli neplatnému tokenu",
+ "Couldn't reset password because the token is expired" : "Heslo nebylo změněno z důvodu vypršení tokenu",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nelze odeslat email pro změnu hesla. Ujistěte se prosím, že zadáváte správné uživatelské jméno.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Nelze odeslat email pro změnu hesla, protože u tohoto uživatelského jména není uvedena emailová adresa. Kontaktujte prosím svého administrátora.",
+ "%s password reset" : "reset hesla %s",
+ "Couldn't send reset email. Please contact your administrator." : "Nepodařilo se odeslat email pro změnu hesla. Kontaktujte svého správce systému.",
"Sunday" : "Neděle",
"Monday" : "Pondělí",
"Tuesday" : "Úterý",
@@ -75,10 +84,10 @@
"Oct." : "íjen",
"Nov." : "listopad",
"Dec." : "prosinec",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Došlo k problémům při kontrole integrity kódu. Více informací…</a>",
"Settings" : "Nastavení",
"Saving..." : "Ukládám...",
"seconds ago" : "před pár sekundami",
- "Couldn't send reset email. Please contact your administrator." : "Nepodařilo se odeslat email pro změnu hesla. Kontaktujte svého správce systému.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Odkaz na obnovení hesla byl odeslán na vaši emailovou adresu. Pokud jej v krátké době neobdržíte, zkontrolujte složku nevyžádané pošty a koš.<br>Pokud jej nenaleznete, kontaktujte svého správce systému.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vaše soubory jsou šifrovány. Pokud jste nepovolili klíč pro obnovení, neexistuje způsob jak získat po změně hesla vaše data zpět.<br />Pokud si nejste jisti co dělat, kontaktujte nejprve svého správce systému, než budete pokračovat. <br />Opravdu si přejete pokračovat?",
"I know what I'm doing" : "Vím co dělám",
@@ -107,13 +116,15 @@
"Good password" : "Dobré heslo",
"Strong password" : "Silné heslo",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Váš webový server ještě není správně nastaven pro umožnění synchronizace souborů, protože rozhraní WebDAV je pravděpodobně rozbité.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Tento webový server není správně nastaven pro rozpoznání \"{url}\". Více informací lze nalézt v naší <a target=\"_blank\" href=\"{docLink}\">dokumentaci</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Tento server nemá funkční připojení k Internetu. Některé moduly jako např. externí úložiště, oznámení o dostupných aktualizacích nebo instalace aplikací třetích stran nebudou fungovat. Přístup k souborům z jiných míst a odesílání oznamovacích emailů také nemusí fungovat. Pokud chcete využívat všechny možnosti ownCloud, doporučujeme povolit pro tento server připojení k Internetu.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Váš datový adresář i vaše soubory jsou pravděpodobně přístupné z Internetu. Soubor .htaccess nefunguje. Důrazně doporučujeme nakonfigurovat webový server tak, aby datový adresář nebyl nadále přístupný, nebo přesunout datový adresář mimo prostor zpřístupňovaný webovým serverem.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nebyla nakonfigurována paměťová cache. Pro zlepšení výkonu a dostupnosti ji prosím nakonfigurujte. Další informace lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP nemá práva pro čtení v /dev/urandom, to je ale z bezpečnostních důvodů velmi doporučováno. Více informací lze nalézt v <a href=\"{docLink}\">dokumentaci</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Vaše verze PHP ({version}) již není <a href=\"{phpLink}\">podporována</a>. Doporučujeme aktualizovat na poslední verzi PHP pro využití vylepšení výkonu a bezpečnosti.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Konfigurace hlaviček zpětné proxy není správná nebo přistupujete na ownCloud přes důvěryhodnou proxy. Pokud přistupujete na ownCloud přes nedůvěryhodnou proxy je toto považováno za bezpečnostní problém který může útočníkovi umožnit záměnu IP adresy viděné ownCloudem. Více informací lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached je nakonfigurován jako distribuovaná cache, ale je nainstalován nesprávný PHP modul \"memcache\". \\OC\\Memcache\\Memcached podporuje pouze \"memcached\" a ne \"memcache\". Projděte si <a href=\"{wikiLink}\">memcached wiki popisující oba moduly</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Nebyla nakonfigurována paměťová cache. Pro zlepšení výkonu a dostupnosti ji prosím nakonfigurujte. Další informace lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "PHP nemá práva pro čtení v /dev/urandom, to je ale z bezpečnostních důvodů velmi doporučováno. Více informací lze nalézt v <a href=\"{docLink}\">dokumentaci</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Vaše verze PHP ({version}) již není <a href=\"{phpLink}\">podporována</a>. Doporučujeme aktualizovat na poslední verzi PHP pro využití vylepšení výkonu a bezpečnosti.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Konfigurace hlaviček zpětné proxy není správná nebo přistupujete na ownCloud přes důvěryhodnou proxy. Pokud přistupujete na ownCloud přes nedůvěryhodnou proxy je toto považováno za bezpečnostní problém který může útočníkovi umožnit záměnu IP adresy viděné ownCloudem. Více informací lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached je nakonfigurován jako distribuovaná cache, ale je nainstalován nesprávný PHP modul \"memcache\". \\OC\\Memcache\\Memcached podporuje pouze \"memcached\" a ne \"memcache\". Projděte si <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki popisující oba moduly</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Některé soubory neprošly kontrolou integrity. Více informací o tom jak tento problém vyřešit, lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>. (<a target=\"_blank\" href=\"{codeIntegrityDownloadEndpoint}\">Seznam neplatných souborů…</a> / <a href=\"{rescanEndpoint}\">Znovu ověřit…</a>)",
"Error occurred while checking server setup" : "Při ověřování nastavení serveru došlo k chybě",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP hlavička \"{header}\" není nakonfigurována ve shodě s \"{expected}\". To značí možné ohrožení bezpečnosti a soukromí a je doporučeno toto nastavení upravit.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP hlavička \"Strict-Transport-Security\" není nakonfigurována na minimum \"{seconds}\" sekund. Pro vylepšení bezpečnosti doporučujeme povolit HSTS dle popisu v našich <a href=\"{docUrl}\">bezpečnostních tipech</a>.",
@@ -123,7 +134,6 @@
"Error" : "Chyba",
"Error while sharing" : "Chyba při sdílení",
"Error while unsharing" : "Chyba při rušení sdílení",
- "Error while changing permissions" : "Chyba při změně oprávnění",
"Error setting expiration date" : "Chyba při nastavení data vypršení platnosti",
"The public link will expire no later than {days} days after it is created" : "Veřejný odkaz vyprší nejpozději {days} dní od svého vytvoření",
"Set expiration date" : "Nastavit datum vypršení platnosti",
@@ -142,7 +152,6 @@
"Send" : "Odeslat",
"Shared with you and the group {group} by {owner}" : "S Vámi a skupinou {group} sdílí {owner}",
"Shared with you by {owner}" : "S Vámi sdílí {owner}",
- "Shared in {item} with {user}" : "Sdíleno v {item} s {user}",
"group" : "skupina",
"remote" : "vzdálený",
"notify by email" : "upozornit emailem",
@@ -153,17 +162,25 @@
"change" : "změnit",
"delete" : "smazat",
"access control" : "řízení přístupu",
+ "Could not unshare" : "Nelze zrušit sdílení",
"Share details could not be loaded for this item." : "Detaily sdílení pro tuto položku nelze načíst.",
"An error occured. Please try again" : "Nastala chyba. Prosím zkuste to znovu",
"Share" : "Sdílet",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Sdílejte s lidmi na ownClouds použitím syntaxe username@example.com/owncloud",
"Share with users or groups …" : "Sdílet s uživateli nebo skupinami",
"Share with users, groups or remote users …" : "Sdílet s uživateli, skupinami nebo vzdálenými uživateli",
+ "Error removing share" : "Chyba při odstraňování sdílení",
"Warning" : "Varování",
"Error while sending notification" : "Chyba při odesílání upozornění",
+ "Non-existing tag #{tag}" : "Neexistující tag #{tag}",
+ "not assignable" : "nepřiřaditelný",
+ "invisible" : "neviditelný",
+ "({scope})" : "({scope})",
+ "Delete" : "Smazat",
+ "Rename" : "Přejmenovat",
+ "Global tags" : "Globální tagy",
"The object type is not specified." : "Není určen typ objektu.",
"Enter new" : "Zadat nový",
- "Delete" : "Smazat",
"Add" : "Přidat",
"Edit tags" : "Editovat štítky",
"Error loading dialog template: {error}" : "Chyba při načítání šablony dialogu: {error}",
@@ -182,15 +199,6 @@
"The update was unsuccessful. " : "Aktualizace nebyla úspěšná.",
"The update was successful. There were warnings." : "Aktualizace byla úspěšná. Zachycen výskyt varování.",
"The update was successful. Redirecting you to ownCloud now." : "Aktualizace byla úspěšná. Přesměrovávám na ownCloud.",
- "Couldn't reset password because the token is invalid" : "Heslo nebylo změněno kvůli neplatnému tokenu",
- "Couldn't reset password because the token is expired" : "Heslo nebylo změněno z důvodu vypršení tokenu",
- "Couldn't send reset email. Please make sure your username is correct." : "Nelze odeslat email pro změnu hesla. Ujistěte se prosím, že zadáváte správné uživatelské jméno.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nelze odeslat email pro změnu hesla, protože u tohoto uživatelského jména není uvedena emailová adresa. Kontaktujte prosím svého správce systému.",
- "%s password reset" : "reset hesla %s",
- "Use the following link to reset your password: {link}" : "Heslo obnovíte použitím následujícího odkazu: {link}",
- "New password" : "Nové heslo",
- "New Password" : "Nové heslo",
- "Reset password" : "Obnovit heslo",
"Searching other places" : "Prohledávání ostatních umístění",
"No search results in other folders" : "V ostatních adresářích nebylo nic nalezeno",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} nález v dalším adresáři","{count} nálezy v dalších adresářích","{count} nálezů v dalších adresářích"],
@@ -260,8 +268,13 @@
"Please try again or contact your administrator." : "Prosím zkuste to znovu nebo kontaktujte vašeho správce.",
"Log in" : "Přihlásit",
"Wrong password. Reset it?" : "Nesprávné heslo. Resetovat?",
+ "Wrong password." : "Chybné heslo.",
"Stay logged in" : "Neodhlašovat",
"Alternative Logins" : "Alternativní přihlášení",
+ "Use the following link to reset your password: {link}" : "Heslo obnovíte použitím následujícího odkazu: {link}",
+ "New password" : "Nové heslo",
+ "New Password" : "Nové heslo",
+ "Reset password" : "Obnovit heslo",
"This ownCloud instance is currently in single user mode." : "Tato instalace ownCloudu je momentálně v jednouživatelském módu.",
"This means only administrators can use the instance." : "To znamená, že pouze správci systému mohou aplikaci používat.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktujte prosím správce systému, pokud se tato zpráva objevuje opakovaně nebo nečekaně.",
diff --git a/core/l10n/cy_GB.js b/core/l10n/cy_GB.js
index 2aa8280d96a..ae9868886b9 100644
--- a/core/l10n/cy_GB.js
+++ b/core/l10n/cy_GB.js
@@ -51,7 +51,6 @@ OC.L10N.register(
"Error" : "Gwall",
"Error while sharing" : "Gwall wrth rannu",
"Error while unsharing" : "Gwall wrth ddad-rannu",
- "Error while changing permissions" : "Gwall wrth newid caniatâd",
"Error setting expiration date" : "Gwall wrth osod dyddiad dod i ben",
"Set expiration date" : "Gosod dyddiad dod i ben",
"Expiration date" : "Dyddiad dod i ben",
@@ -64,7 +63,6 @@ OC.L10N.register(
"Send" : "Anfon",
"Shared with you and the group {group} by {owner}" : "Rhannwyd â chi a'r grŵp {group} gan {owner}",
"Shared with you by {owner}" : "Rhannwyd â chi gan {owner}",
- "Shared in {item} with {user}" : "Rhannwyd yn {item} â {user}",
"group" : "grŵp",
"Unshare" : "Dad-rannu",
"can edit" : "yn gallu golygu",
@@ -73,13 +71,11 @@ OC.L10N.register(
"access control" : "rheolaeth mynediad",
"Share" : "Rhannu",
"Warning" : "Rhybudd",
- "The object type is not specified." : "Nid yw'r math o wrthrych wedi cael ei nodi.",
"Delete" : "Dileu",
+ "Rename" : "Ailenwi",
+ "The object type is not specified." : "Nid yw'r math o wrthrych wedi cael ei nodi.",
"Add" : "Ychwanegu",
"The update was successful. Redirecting you to ownCloud now." : "Roedd y diweddariad yn llwyddiannus. Cewch eich ailgyfeirio i ownCloud nawr.",
- "Use the following link to reset your password: {link}" : "Defnyddiwch y ddolen hon i ailosod eich cyfrinair: {link}",
- "New password" : "Cyfrinair newydd",
- "Reset password" : "Ailosod cyfrinair",
"Personal" : "Personol",
"Users" : "Defnyddwyr",
"Apps" : "Pecynnau",
@@ -100,6 +96,9 @@ OC.L10N.register(
"Log out" : "Allgofnodi",
"Search" : "Chwilio",
"Log in" : "Mewngofnodi",
- "Alternative Logins" : "Mewngofnodiadau Amgen"
+ "Alternative Logins" : "Mewngofnodiadau Amgen",
+ "Use the following link to reset your password: {link}" : "Defnyddiwch y ddolen hon i ailosod eich cyfrinair: {link}",
+ "New password" : "Cyfrinair newydd",
+ "Reset password" : "Ailosod cyfrinair"
},
"nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;");
diff --git a/core/l10n/cy_GB.json b/core/l10n/cy_GB.json
index e4a46ace1be..a2b3046442b 100644
--- a/core/l10n/cy_GB.json
+++ b/core/l10n/cy_GB.json
@@ -49,7 +49,6 @@
"Error" : "Gwall",
"Error while sharing" : "Gwall wrth rannu",
"Error while unsharing" : "Gwall wrth ddad-rannu",
- "Error while changing permissions" : "Gwall wrth newid caniatâd",
"Error setting expiration date" : "Gwall wrth osod dyddiad dod i ben",
"Set expiration date" : "Gosod dyddiad dod i ben",
"Expiration date" : "Dyddiad dod i ben",
@@ -62,7 +61,6 @@
"Send" : "Anfon",
"Shared with you and the group {group} by {owner}" : "Rhannwyd â chi a'r grŵp {group} gan {owner}",
"Shared with you by {owner}" : "Rhannwyd â chi gan {owner}",
- "Shared in {item} with {user}" : "Rhannwyd yn {item} â {user}",
"group" : "grŵp",
"Unshare" : "Dad-rannu",
"can edit" : "yn gallu golygu",
@@ -71,13 +69,11 @@
"access control" : "rheolaeth mynediad",
"Share" : "Rhannu",
"Warning" : "Rhybudd",
- "The object type is not specified." : "Nid yw'r math o wrthrych wedi cael ei nodi.",
"Delete" : "Dileu",
+ "Rename" : "Ailenwi",
+ "The object type is not specified." : "Nid yw'r math o wrthrych wedi cael ei nodi.",
"Add" : "Ychwanegu",
"The update was successful. Redirecting you to ownCloud now." : "Roedd y diweddariad yn llwyddiannus. Cewch eich ailgyfeirio i ownCloud nawr.",
- "Use the following link to reset your password: {link}" : "Defnyddiwch y ddolen hon i ailosod eich cyfrinair: {link}",
- "New password" : "Cyfrinair newydd",
- "Reset password" : "Ailosod cyfrinair",
"Personal" : "Personol",
"Users" : "Defnyddwyr",
"Apps" : "Pecynnau",
@@ -98,6 +94,9 @@
"Log out" : "Allgofnodi",
"Search" : "Chwilio",
"Log in" : "Mewngofnodi",
- "Alternative Logins" : "Mewngofnodiadau Amgen"
+ "Alternative Logins" : "Mewngofnodiadau Amgen",
+ "Use the following link to reset your password: {link}" : "Defnyddiwch y ddolen hon i ailosod eich cyfrinair: {link}",
+ "New password" : "Cyfrinair newydd",
+ "Reset password" : "Ailosod cyfrinair"
},"pluralForm" :"nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;"
} \ No newline at end of file
diff --git a/core/l10n/da.js b/core/l10n/da.js
index eed02acd3be..1c665f51620 100644
--- a/core/l10n/da.js
+++ b/core/l10n/da.js
@@ -16,8 +16,6 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Opdaterede \"%s\" til %s",
"Repair warning: " : "Reparationsadvarsel:",
"Repair error: " : "Reparationsfejl:",
- "Set log level to debug - current level: \"%s\"" : "Sæt log niveau til fejlfinding - nuværende niveau: \"%s\"",
- "Reset log level to \"%s\"" : "Nulstil log niveau til \"%s\"",
"%s (3rdparty)" : "%s (3rdparty)",
"%s (incompatible)" : "%s (inkombatible)",
"Following apps have been disabled: %s" : "Følgende apps er blevet deaktiveret: %s",
@@ -32,6 +30,11 @@ OC.L10N.register(
"No crop data provided" : "Ingen beskæringsdata give",
"No valid crop data provided" : "Der er ikke angivet gyldige data om beskæring",
"Crop is not square" : "Beskæringen er ikke kvadratisk",
+ "Couldn't reset password because the token is invalid" : "Kunne ikke nulstille kodeordet, fordi symboludtrykket er ugyldigt",
+ "Couldn't reset password because the token is expired" : "Kunne ikke nulstille kodeord, da tokenet er udløbet",
+ "Couldn't send reset email. Please make sure your username is correct." : "Der opstod et problem under afsendelse af nulstillings-e-mailen. Kontroller venligst om dit brugernavnet er korrekt",
+ "%s password reset" : "%s adgangskode nulstillet",
+ "Couldn't send reset email. Please contact your administrator." : "Der opstod et problem under afsending af e-mailen til nulstilling. Kontakt venligst systemadministratoren.",
"Sunday" : "Søndag",
"Monday" : "Mandag",
"Tuesday" : "Tirsdag",
@@ -80,7 +83,6 @@ OC.L10N.register(
"Settings" : "Indstillinger",
"Saving..." : "Gemmer...",
"seconds ago" : "sekunder siden",
- "Couldn't send reset email. Please contact your administrator." : "Der opstod et problem under afsending af e-mailen til nulstilling. Kontakt venligst systemadministratoren.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Linket til at nulstille dit kodeord er blevet sendt til din e-post: hvis du ikke modtager den inden for en rimelig tid, så tjek dine spam/junk-mapper.<br> Hvis det ikke er der, så spørg din lokale administrator.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Dine filer er krypterede. Hvis du ikke har aktiveret gendannelsesnøglen kan du ikke få dine data tilbage efter at du har ændret adgangskode.<br />Hvis du ikke er sikker på, hvad du skal gøre så kontakt din administrator før du fortsætter.<br />Vil du fortsætte?",
"I know what I'm doing" : "Jeg ved, hvad jeg har gang i",
@@ -111,10 +113,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Din webserver er endnu ikke sat korrekt op til at tillade filsynkronisering, fordi WebDAV-grænsefladen ser ud til at være i stykker.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Denne ownCloud-server har ikke en fungerende forbindelse til internettet. Det betyder, at visse funktioner som montering af eksterne drev, oplysninger om opdatering eller installation af applikationer fra tredjepart ikke fungerer. Det vil sandsynligvis heller ikke være muligt at tilgå filer fra eksterne drev eller afsendelse af e-mail med notifikationer virker sandsynligvis heller ikke. Vi opfordrer til at etablere forbindelse til internettet for denne server, såfremt du ønsker samtlige funktioner.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Din data mappe og dine filer er muligvis tilgængelige fra internettet. Filen .htaccess fungerer ikke. Vi anbefaler på det kraftigste, at du konfigurerer din webserver således at datamappen ikke længere er tilgængelig, eller at du flytter datamappen uden for webserverens dokumentrod. ",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Der er ikke konfigureret et hukommelsesmellemlager. For at forbedre din ydelse, skal du konfigurere et mellemlager, hvis den er tilgængelig. Du finder mere information i din <a href=\"{docLink}\">dokumentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom kan ikke læses af PHP, hvilket stærkt frarådes af sikkerhedsmæssige årsager. Der fås mere information i vores <a href=\"{docLink}\">dokumentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Din version af PHP ({version}) bliver ikke længere <a href=\"{phpLink}\">understøttet af PHP</a>. Vi opfordrer dig til at opgradere din PHP-version, for at opnå fordelene i ydelse og sikkerhed gennem opdateringerne som fås fra PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Den omvendte konnfiguration af proxyen er ikke korrekt, eller også tilgår du ownCloud fra en proxy som der er tillid til. Hvis ikke tilgår ownCloud fra en proxy som der er tillid til, så er der er et sikkerhedsproblem, hvilket kan tillade at en angriber kan forfalske deres IP-adresse som synlig for ownCloud. Mere information fås i vores <a href=\"{docLink}\">dokumentation</a>.",
"Error occurred while checking server setup" : "Der opstod fejl under tjek af serveropsætningen",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP-hovedet \"{header}\" er ikke konfigureret til at være lig med \"{expected}\". Dette er en potentiel sikkerhedsrisiko, og vi anbefaler at du justerer denne indstilling.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP-hovedet \"Strict-Transport-Security\" er ikke konfigureret til mindst \"{seconds}\" sekunder. For udvidet sikkerhed anbefaler vi at aktivere HSTS, som foreskrevet i vores <a href=\"{docUrl}\">sikkerhedstips</a>.",
@@ -124,7 +122,6 @@ OC.L10N.register(
"Error" : "Fejl",
"Error while sharing" : "Fejl under deling",
"Error while unsharing" : "Fejl under annullering af deling",
- "Error while changing permissions" : "Fejl under justering af rettigheder",
"Error setting expiration date" : "Fejl under sætning af udløbsdato",
"The public link will expire no later than {days} days after it is created" : "Det offentlige link udløber senest {days} dage efter det blev oprettet",
"Set expiration date" : "Vælg udløbsdato",
@@ -143,7 +140,6 @@ OC.L10N.register(
"Send" : "Send",
"Shared with you and the group {group} by {owner}" : "Delt med dig og gruppen {group} af {owner}",
"Shared with you by {owner}" : "Delt med dig af {owner}",
- "Shared in {item} with {user}" : "Delt i {item} med {user}",
"group" : "gruppe",
"remote" : "ekstern",
"notify by email" : "Giv besked med mail",
@@ -162,9 +158,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Del med brugere, grupper eller eksterne brugere...",
"Warning" : "Advarsel",
"Error while sending notification" : "Fejl ved afsendelse af notifikation",
+ "Delete" : "Slet",
+ "Rename" : "Omdøb",
"The object type is not specified." : "Objekttypen er ikke angivet.",
"Enter new" : "Indtast nyt",
- "Delete" : "Slet",
"Add" : "Tilføj",
"Edit tags" : "Redigér mærker",
"Error loading dialog template: {error}" : "Fejl ved indlæsning dialog skabelon: {error}",
@@ -183,15 +180,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Opdateringen blev ikke gennemført.",
"The update was successful. There were warnings." : "Opdateringen blev gennemført. Der fremkom advarsler.",
"The update was successful. Redirecting you to ownCloud now." : "Opdateringen blev udført korrekt. Du bliver nu viderestillet til ownCloud.",
- "Couldn't reset password because the token is invalid" : "Kunne ikke nulstille kodeordet, fordi symboludtrykket er ugyldigt",
- "Couldn't reset password because the token is expired" : "Kunne ikke nulstille kodeord, da tokenet er udløbet",
- "Couldn't send reset email. Please make sure your username is correct." : "Der opstod et problem under afsendelse af nulstillings-e-mailen. Kontroller venligst om dit brugernavnet er korrekt",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Der opstod et problem under afsendelse af nulstillings-e-mailen. Der ikke er nogen email adresse tilknyttet denne bruger konto. Kontakt venligst systemadministratoren",
- "%s password reset" : "%s adgangskode nulstillet",
- "Use the following link to reset your password: {link}" : "Anvend følgende link til at nulstille din adgangskode: {link}",
- "New password" : "Ny adgangskode",
- "New Password" : "Ny adgangskode",
- "Reset password" : "Nulstil kodeord",
"Searching other places" : "Søger på andre steder",
"No search results in other folders" : "Søgning gav ingen resultater in andre mapper",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} søgeresultat fundet i andre mapper","{count} søgeresultater fundet i andre mapper"],
@@ -263,6 +251,10 @@ OC.L10N.register(
"Wrong password. Reset it?" : "Forkert kodeord. Skal det nulstilles?",
"Stay logged in" : "Forbliv logget ind",
"Alternative Logins" : "Alternative logins",
+ "Use the following link to reset your password: {link}" : "Anvend følgende link til at nulstille din adgangskode: {link}",
+ "New password" : "Ny adgangskode",
+ "New Password" : "Ny adgangskode",
+ "Reset password" : "Nulstil kodeord",
"This ownCloud instance is currently in single user mode." : "Denne ownCloud instans er lige nu i enkeltbruger tilstand.",
"This means only administrators can use the instance." : "Det betyder at det kun er administrator, som kan benytte ownCloud.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontakt systemadministratoren, hvis denne meddelelse fortsætter eller optrådte uventet.",
diff --git a/core/l10n/da.json b/core/l10n/da.json
index 35aff828922..854e11ec5f8 100644
--- a/core/l10n/da.json
+++ b/core/l10n/da.json
@@ -14,8 +14,6 @@
"Updated \"%s\" to %s" : "Opdaterede \"%s\" til %s",
"Repair warning: " : "Reparationsadvarsel:",
"Repair error: " : "Reparationsfejl:",
- "Set log level to debug - current level: \"%s\"" : "Sæt log niveau til fejlfinding - nuværende niveau: \"%s\"",
- "Reset log level to \"%s\"" : "Nulstil log niveau til \"%s\"",
"%s (3rdparty)" : "%s (3rdparty)",
"%s (incompatible)" : "%s (inkombatible)",
"Following apps have been disabled: %s" : "Følgende apps er blevet deaktiveret: %s",
@@ -30,6 +28,11 @@
"No crop data provided" : "Ingen beskæringsdata give",
"No valid crop data provided" : "Der er ikke angivet gyldige data om beskæring",
"Crop is not square" : "Beskæringen er ikke kvadratisk",
+ "Couldn't reset password because the token is invalid" : "Kunne ikke nulstille kodeordet, fordi symboludtrykket er ugyldigt",
+ "Couldn't reset password because the token is expired" : "Kunne ikke nulstille kodeord, da tokenet er udløbet",
+ "Couldn't send reset email. Please make sure your username is correct." : "Der opstod et problem under afsendelse af nulstillings-e-mailen. Kontroller venligst om dit brugernavnet er korrekt",
+ "%s password reset" : "%s adgangskode nulstillet",
+ "Couldn't send reset email. Please contact your administrator." : "Der opstod et problem under afsending af e-mailen til nulstilling. Kontakt venligst systemadministratoren.",
"Sunday" : "Søndag",
"Monday" : "Mandag",
"Tuesday" : "Tirsdag",
@@ -78,7 +81,6 @@
"Settings" : "Indstillinger",
"Saving..." : "Gemmer...",
"seconds ago" : "sekunder siden",
- "Couldn't send reset email. Please contact your administrator." : "Der opstod et problem under afsending af e-mailen til nulstilling. Kontakt venligst systemadministratoren.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Linket til at nulstille dit kodeord er blevet sendt til din e-post: hvis du ikke modtager den inden for en rimelig tid, så tjek dine spam/junk-mapper.<br> Hvis det ikke er der, så spørg din lokale administrator.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Dine filer er krypterede. Hvis du ikke har aktiveret gendannelsesnøglen kan du ikke få dine data tilbage efter at du har ændret adgangskode.<br />Hvis du ikke er sikker på, hvad du skal gøre så kontakt din administrator før du fortsætter.<br />Vil du fortsætte?",
"I know what I'm doing" : "Jeg ved, hvad jeg har gang i",
@@ -109,10 +111,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Din webserver er endnu ikke sat korrekt op til at tillade filsynkronisering, fordi WebDAV-grænsefladen ser ud til at være i stykker.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Denne ownCloud-server har ikke en fungerende forbindelse til internettet. Det betyder, at visse funktioner som montering af eksterne drev, oplysninger om opdatering eller installation af applikationer fra tredjepart ikke fungerer. Det vil sandsynligvis heller ikke være muligt at tilgå filer fra eksterne drev eller afsendelse af e-mail med notifikationer virker sandsynligvis heller ikke. Vi opfordrer til at etablere forbindelse til internettet for denne server, såfremt du ønsker samtlige funktioner.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Din data mappe og dine filer er muligvis tilgængelige fra internettet. Filen .htaccess fungerer ikke. Vi anbefaler på det kraftigste, at du konfigurerer din webserver således at datamappen ikke længere er tilgængelig, eller at du flytter datamappen uden for webserverens dokumentrod. ",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Der er ikke konfigureret et hukommelsesmellemlager. For at forbedre din ydelse, skal du konfigurere et mellemlager, hvis den er tilgængelig. Du finder mere information i din <a href=\"{docLink}\">dokumentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom kan ikke læses af PHP, hvilket stærkt frarådes af sikkerhedsmæssige årsager. Der fås mere information i vores <a href=\"{docLink}\">dokumentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Din version af PHP ({version}) bliver ikke længere <a href=\"{phpLink}\">understøttet af PHP</a>. Vi opfordrer dig til at opgradere din PHP-version, for at opnå fordelene i ydelse og sikkerhed gennem opdateringerne som fås fra PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Den omvendte konnfiguration af proxyen er ikke korrekt, eller også tilgår du ownCloud fra en proxy som der er tillid til. Hvis ikke tilgår ownCloud fra en proxy som der er tillid til, så er der er et sikkerhedsproblem, hvilket kan tillade at en angriber kan forfalske deres IP-adresse som synlig for ownCloud. Mere information fås i vores <a href=\"{docLink}\">dokumentation</a>.",
"Error occurred while checking server setup" : "Der opstod fejl under tjek af serveropsætningen",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP-hovedet \"{header}\" er ikke konfigureret til at være lig med \"{expected}\". Dette er en potentiel sikkerhedsrisiko, og vi anbefaler at du justerer denne indstilling.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP-hovedet \"Strict-Transport-Security\" er ikke konfigureret til mindst \"{seconds}\" sekunder. For udvidet sikkerhed anbefaler vi at aktivere HSTS, som foreskrevet i vores <a href=\"{docUrl}\">sikkerhedstips</a>.",
@@ -122,7 +120,6 @@
"Error" : "Fejl",
"Error while sharing" : "Fejl under deling",
"Error while unsharing" : "Fejl under annullering af deling",
- "Error while changing permissions" : "Fejl under justering af rettigheder",
"Error setting expiration date" : "Fejl under sætning af udløbsdato",
"The public link will expire no later than {days} days after it is created" : "Det offentlige link udløber senest {days} dage efter det blev oprettet",
"Set expiration date" : "Vælg udløbsdato",
@@ -141,7 +138,6 @@
"Send" : "Send",
"Shared with you and the group {group} by {owner}" : "Delt med dig og gruppen {group} af {owner}",
"Shared with you by {owner}" : "Delt med dig af {owner}",
- "Shared in {item} with {user}" : "Delt i {item} med {user}",
"group" : "gruppe",
"remote" : "ekstern",
"notify by email" : "Giv besked med mail",
@@ -160,9 +156,10 @@
"Share with users, groups or remote users …" : "Del med brugere, grupper eller eksterne brugere...",
"Warning" : "Advarsel",
"Error while sending notification" : "Fejl ved afsendelse af notifikation",
+ "Delete" : "Slet",
+ "Rename" : "Omdøb",
"The object type is not specified." : "Objekttypen er ikke angivet.",
"Enter new" : "Indtast nyt",
- "Delete" : "Slet",
"Add" : "Tilføj",
"Edit tags" : "Redigér mærker",
"Error loading dialog template: {error}" : "Fejl ved indlæsning dialog skabelon: {error}",
@@ -181,15 +178,6 @@
"The update was unsuccessful. " : "Opdateringen blev ikke gennemført.",
"The update was successful. There were warnings." : "Opdateringen blev gennemført. Der fremkom advarsler.",
"The update was successful. Redirecting you to ownCloud now." : "Opdateringen blev udført korrekt. Du bliver nu viderestillet til ownCloud.",
- "Couldn't reset password because the token is invalid" : "Kunne ikke nulstille kodeordet, fordi symboludtrykket er ugyldigt",
- "Couldn't reset password because the token is expired" : "Kunne ikke nulstille kodeord, da tokenet er udløbet",
- "Couldn't send reset email. Please make sure your username is correct." : "Der opstod et problem under afsendelse af nulstillings-e-mailen. Kontroller venligst om dit brugernavnet er korrekt",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Der opstod et problem under afsendelse af nulstillings-e-mailen. Der ikke er nogen email adresse tilknyttet denne bruger konto. Kontakt venligst systemadministratoren",
- "%s password reset" : "%s adgangskode nulstillet",
- "Use the following link to reset your password: {link}" : "Anvend følgende link til at nulstille din adgangskode: {link}",
- "New password" : "Ny adgangskode",
- "New Password" : "Ny adgangskode",
- "Reset password" : "Nulstil kodeord",
"Searching other places" : "Søger på andre steder",
"No search results in other folders" : "Søgning gav ingen resultater in andre mapper",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} søgeresultat fundet i andre mapper","{count} søgeresultater fundet i andre mapper"],
@@ -261,6 +249,10 @@
"Wrong password. Reset it?" : "Forkert kodeord. Skal det nulstilles?",
"Stay logged in" : "Forbliv logget ind",
"Alternative Logins" : "Alternative logins",
+ "Use the following link to reset your password: {link}" : "Anvend følgende link til at nulstille din adgangskode: {link}",
+ "New password" : "Ny adgangskode",
+ "New Password" : "Ny adgangskode",
+ "Reset password" : "Nulstil kodeord",
"This ownCloud instance is currently in single user mode." : "Denne ownCloud instans er lige nu i enkeltbruger tilstand.",
"This means only administrators can use the instance." : "Det betyder at det kun er administrator, som kan benytte ownCloud.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontakt systemadministratoren, hvis denne meddelelse fortsætter eller optrådte uventet.",
diff --git a/core/l10n/de.js b/core/l10n/de.js
index 0580f88d33b..411d02d01be 100644
--- a/core/l10n/de.js
+++ b/core/l10n/de.js
@@ -6,16 +6,23 @@ OC.L10N.register(
"Turned on maintenance mode" : "Wartungsmodus eingeschaltet",
"Turned off maintenance mode" : "Wartungsmodus ausgeschaltet",
"Maintenance mode is kept active" : "Wartungsmodus wird aktiv gehalten",
+ "Updating database schema" : "Datenbank-Schema wird upgedatet",
"Updated database" : "Datenbank aktualisiert",
"Checked database schema update" : "Datenbankschema-Aktualisierung überprüft",
+ "Checking updates of apps" : "Es wird nach Updates für die Apps gesucht",
"Checked database schema update for apps" : "Datenbankschema-Aktualisierung für Apps überprüft",
"Updated \"%s\" to %s" : "„%s“ zu %s aktualisiert",
"Repair warning: " : "Reperaturwarnung:",
"Repair error: " : "Reperaturfehler:",
- "Set log level to debug - current level: \"%s\"" : "Log-Level auf Debug gesetzt - aktuelles Level: \"%s\"",
- "Reset log level to \"%s\"" : "Log-Level auf \"%s\" zurückgesetzt",
+ "Set log level to debug" : "Log-Level auf \"debug\" gesetzt",
+ "Reset log level" : "Ursprüngliches Log-Level wiederhergestellt",
+ "Starting code integrity check" : "Code-Integrität wird überprüft",
+ "Finished code integrity check" : "Code-Integritätsprüfung abgeschlossen",
+ "%s (3rdparty)" : "%s (3rdparty)",
+ "%s (incompatible)" : "%s (nicht kompatibel)",
"Following apps have been disabled: %s" : "Die folgenden Apps sind deaktiviert worden: %s",
"Already up to date" : "Bereits aktuell",
+ "Please select a file." : "Bitte wähle eine Datei aus.",
"File is too big" : "Datei ist zu groß",
"Invalid file provided" : "Ungültige Datei zur Verfügung gestellt",
"No image or file provided" : "Es wurde weder ein Bild noch eine Datei zur Verfügung gestellt",
@@ -26,6 +33,12 @@ OC.L10N.register(
"No crop data provided" : "Keine Beschnittdaten zur Verfügung gestellt",
"No valid crop data provided" : "Keine gültigen Zuschnittdaten zur Verfügung gestellt",
"Crop is not square" : "Zuschnitt ist nicht quadratisch",
+ "Couldn't reset password because the token is invalid" : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht zurückgesetzt werden",
+ "Couldn't reset password because the token is expired" : "Das Passwort konnte nicht zurückgesetzt werden, da der Token abgelaufen ist",
+ "Couldn't send reset email. Please make sure your username is correct." : "E-Mail zum Zurücksetzen kann nicht versendet werden. Bitte stelle sicher, dass Dein Benutzername korrekt ist.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Es konnte keine E-Mail verschickt werden um das Passwort zurückzusetzten, da keine E-Mail im Benutzerkonto hinterlegt ist. Bitte kontaktiere den Administrator.",
+ "%s password reset" : "%s-Passwort zurücksetzen",
+ "Couldn't send reset email. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versendet werden. Bitte kontaktiere Deinen Administrator.",
"Sunday" : "Sonntag",
"Monday" : "Montag",
"Tuesday" : "Dienstag",
@@ -74,7 +87,6 @@ OC.L10N.register(
"Settings" : "Einstellungen",
"Saving..." : "Speichern…",
"seconds ago" : "Gerade eben",
- "Couldn't send reset email. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versendet werden. Bitte kontaktiere Deinen Administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Der Link zum Rücksetzen Deines Passworts ist an Deine E-Mail-Adresse versandt worden. Solltest Du ihn innerhalb eines annehmbaren Zeitraums nicht empfangen, prüfe bitte Deine Spam-Ordner.<br>Wenn er sich nicht darin befindet, frage bitte bei Deinem lokalen Administrator nach.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Deine Dateien sind verschlüsselt. Solltest Du den Wiederherstellungsschlüssel nicht aktiviert haben, gibt es keine Möglichkeit, Deine Daten zurückzuerhalten, nachdem Dein Passwort zurückgesetzt ist.<br />Falls Du Dir nicht sicher bist, was zu tun ist, kontaktiere bitte Deinen Administrator, bevor Du fortfährst.<br />Willst Du wirklich fortfahren?",
"I know what I'm doing" : "Ich weiß, was ich mache",
@@ -105,9 +117,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Dein Webserver ist noch nicht hinreichend für Datei-Synchronisation konfiguriert, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Dieser Server hat keine funktionierende Internetverbindung. Dies bedeutet, dass einige Funktionen wie das Einhängen externen Speicherplatzes, Update-Benachrichtigungen oder die Installation von Drittanbieter-Apps nicht funktionieren werden. Der Fernzugriff auf Dateien und der Versand von E-Mail-Benachrichtigungen kann ebenfalls nicht funktionieren. Es wird empfohlen, die Internetverbindung dieses Servers zu aktivieren, wenn Du alle Funktionen nutzen möchtest.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Dein Datenverzeichnis und Deine Dateien sind wahrscheinlich vom Internet aus erreichbar. Die .htaccess-Datei funktioniert nicht. Es wird dringend empfohlen, Deinen Webserver dahingehend zu konfigurieren, dass das Datenverzeichnis nicht mehr vom Internet aus erreichbar ist oder dass Du es aus dem Document-Root-Verzeichnis des Webservers herausverschiebst.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Es wurde kein PHP Memory Cache konfiguriert. Konfiguriere zur Erhöhung der Leistungsfähigkeit, soweit verfügbar, einen Memory Cache. Weitere Informationen finden Sie in unserer <a href=\"{docLink}\">Dokumentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ist für PHP nicht lesbar, wovon aus Sicherheitsgründen dringend abgeraten wird. Weitere Informationen hierzu findest Du in unserer <a href=\"{docLink}\">Dokumentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Deine PHP Version ({version}) wird nicht länger <a href=\"{phpLink}\">unterstützt</a>. Wir empfehlen ein Upgrade deiner PHP Version, um die volle Performance und Sicherheit zu gewährleisten.",
"Error occurred while checking server setup" : "Fehler beim Überprüfen der Servereinrichtung",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Der „{header}“-HTTP-Header ist nicht so konfiguriert, dass er „{expected}“ entspricht. Dies ist ein potentielles Sicherheitsrisiko und es wird empfohlen, diese Einstellung zu ändern.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Der „Strict-Transport-Security“-HTTP-Header ist nicht auf mindestens „{seconds}“ Sekunden eingestellt. Für umfassende Sicherheit wird das Aktivieren von HSTS empfohlen, wie es in unseren <a href=\"{docUrl}\">Sicherheitshinweisen</a> erläutert ist.",
@@ -117,7 +126,6 @@ OC.L10N.register(
"Error" : "Fehler",
"Error while sharing" : "Fehler beim Teilen",
"Error while unsharing" : "Fehler beim Aufheben der Freigabe",
- "Error while changing permissions" : "Fehler beim Ändern der Rechte",
"Error setting expiration date" : "Fehler beim Setzen des Ablaufdatums",
"The public link will expire no later than {days} days after it is created" : "Der öffentliche Link wird spätestens {days} Tage nach seiner Erstellung ablaufen",
"Set expiration date" : "Setze ein Ablaufdatum",
@@ -136,7 +144,6 @@ OC.L10N.register(
"Send" : "Senden",
"Shared with you and the group {group} by {owner}" : "{owner} hat dies mit Dir und der Gruppe {group} geteilt",
"Shared with you by {owner}" : "{owner} hat dies mit Dir geteilt",
- "Shared in {item} with {user}" : "Für {user} in {item} freigegeben",
"group" : "Gruppe",
"remote" : "Entfernte Freigabe",
"notify by email" : "per E-Mail benachrichtigen",
@@ -154,9 +161,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Mit Benutzern, Gruppen oder entfernten Benutzern teilen…",
"Warning" : "Warnung",
"Error while sending notification" : "Fehler beim Senden der Benachrichtigung",
+ "Delete" : "Löschen",
+ "Rename" : "Umbenennen",
"The object type is not specified." : "Der Objekttyp ist nicht angegeben.",
"Enter new" : "Neuen eingeben",
- "Delete" : "Löschen",
"Add" : "Hinzufügen",
"Edit tags" : "Schlagwörter bearbeiten",
"Error loading dialog template: {error}" : "Fehler beim Laden der Dialogvorlage: {error}",
@@ -168,21 +176,13 @@ OC.L10N.register(
"Hello {name}" : "Hallo {name}",
"_download %n file_::_download %n files_" : ["Lade %n Datei herunter","Lade %n Dateien herunter"],
"{version} is available. Get more information on how to update." : "{version} ist verfügbar. Hole weitere Informationen zu Aktualisierungen ein.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Das Update läuft gerade. Das Verlassen dieser Seite könnte den Update Prozess in einigen Umgebungen unterbrechen.",
"Updating {productName} to version {version}, this may take a while." : "Aktualisiere {productName} auf Version {version}. Dies könnte eine Weile dauern.",
"An error occurred." : "Es ist ein Fehler aufgetreten.",
"Please reload the page." : "Bitte lade die Seite neu.",
"The update was unsuccessful. " : "Die Aktualisierung war nicht erfolgreich.",
"The update was successful. There were warnings." : "Das Update war erfolgreich. Warnungen wurden ausgegeben.",
"The update was successful. Redirecting you to ownCloud now." : "Das Update war erfolgreich. Du wirst nun zu ownCloud weitergeleitet.",
- "Couldn't reset password because the token is invalid" : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht zurückgesetzt werden",
- "Couldn't reset password because the token is expired" : "Das Passwort konnte nicht zurückgesetzt werden, da der Token abgelaufen ist",
- "Couldn't send reset email. Please make sure your username is correct." : "E-Mail zum Zurücksetzen kann nicht versendet werden. Bitte stelle sicher, dass Dein Benutzername korrekt ist.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versandt werden, weil für diesen Benutzernamen keine E-Mail-Adresse hinterlegt ist. Bitte kontaktiere Deinen Administrator.",
- "%s password reset" : "%s-Passwort zurücksetzen",
- "Use the following link to reset your password: {link}" : "Benutze den folgenden Link, um Dein Passwort zurückzusetzen: {link}",
- "New password" : "Neues Passwort",
- "New Password" : "Neues Passwort",
- "Reset password" : "Passwort zurücksetzen",
"Searching other places" : "Andere Orte durchsuchen",
"No search results in other folders" : "Keine Suchergebnisse in anderen Ordnern",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} Suchergebnis im anderen Ordner","{count} Suchergebnisse in anderen Ordnern"],
@@ -252,7 +252,13 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Bitte versuche es noch einmal oder kontaktiere Deinen Administrator.",
"Log in" : "Anmelden",
"Wrong password. Reset it?" : "Falsches Passwort. Soll es zurückgesetzt werden?",
+ "Wrong password." : "Falsches Passwort.",
+ "Stay logged in" : "Angemeldet bleiben",
"Alternative Logins" : "Alternative Logins",
+ "Use the following link to reset your password: {link}" : "Benutze den folgenden Link, um Dein Passwort zurückzusetzen: {link}",
+ "New password" : "Neues Passwort",
+ "New Password" : "Neues Passwort",
+ "Reset password" : "Passwort zurücksetzen",
"This ownCloud instance is currently in single user mode." : "Diese ownClound-Instanz befindet sich derzeit im Einzelbenutzermodus.",
"This means only administrators can use the instance." : "Dies bedeutet, dass diese Instanz nur von Administratoren genutzt werden kann.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktiere Deinen Systemadministrator, wenn diese Meldung dauerhaft oder unerwartet erscheint.",
diff --git a/core/l10n/de.json b/core/l10n/de.json
index 285d38429e7..3e50e1ad20c 100644
--- a/core/l10n/de.json
+++ b/core/l10n/de.json
@@ -4,16 +4,23 @@
"Turned on maintenance mode" : "Wartungsmodus eingeschaltet",
"Turned off maintenance mode" : "Wartungsmodus ausgeschaltet",
"Maintenance mode is kept active" : "Wartungsmodus wird aktiv gehalten",
+ "Updating database schema" : "Datenbank-Schema wird upgedatet",
"Updated database" : "Datenbank aktualisiert",
"Checked database schema update" : "Datenbankschema-Aktualisierung überprüft",
+ "Checking updates of apps" : "Es wird nach Updates für die Apps gesucht",
"Checked database schema update for apps" : "Datenbankschema-Aktualisierung für Apps überprüft",
"Updated \"%s\" to %s" : "„%s“ zu %s aktualisiert",
"Repair warning: " : "Reperaturwarnung:",
"Repair error: " : "Reperaturfehler:",
- "Set log level to debug - current level: \"%s\"" : "Log-Level auf Debug gesetzt - aktuelles Level: \"%s\"",
- "Reset log level to \"%s\"" : "Log-Level auf \"%s\" zurückgesetzt",
+ "Set log level to debug" : "Log-Level auf \"debug\" gesetzt",
+ "Reset log level" : "Ursprüngliches Log-Level wiederhergestellt",
+ "Starting code integrity check" : "Code-Integrität wird überprüft",
+ "Finished code integrity check" : "Code-Integritätsprüfung abgeschlossen",
+ "%s (3rdparty)" : "%s (3rdparty)",
+ "%s (incompatible)" : "%s (nicht kompatibel)",
"Following apps have been disabled: %s" : "Die folgenden Apps sind deaktiviert worden: %s",
"Already up to date" : "Bereits aktuell",
+ "Please select a file." : "Bitte wähle eine Datei aus.",
"File is too big" : "Datei ist zu groß",
"Invalid file provided" : "Ungültige Datei zur Verfügung gestellt",
"No image or file provided" : "Es wurde weder ein Bild noch eine Datei zur Verfügung gestellt",
@@ -24,6 +31,12 @@
"No crop data provided" : "Keine Beschnittdaten zur Verfügung gestellt",
"No valid crop data provided" : "Keine gültigen Zuschnittdaten zur Verfügung gestellt",
"Crop is not square" : "Zuschnitt ist nicht quadratisch",
+ "Couldn't reset password because the token is invalid" : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht zurückgesetzt werden",
+ "Couldn't reset password because the token is expired" : "Das Passwort konnte nicht zurückgesetzt werden, da der Token abgelaufen ist",
+ "Couldn't send reset email. Please make sure your username is correct." : "E-Mail zum Zurücksetzen kann nicht versendet werden. Bitte stelle sicher, dass Dein Benutzername korrekt ist.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Es konnte keine E-Mail verschickt werden um das Passwort zurückzusetzten, da keine E-Mail im Benutzerkonto hinterlegt ist. Bitte kontaktiere den Administrator.",
+ "%s password reset" : "%s-Passwort zurücksetzen",
+ "Couldn't send reset email. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versendet werden. Bitte kontaktiere Deinen Administrator.",
"Sunday" : "Sonntag",
"Monday" : "Montag",
"Tuesday" : "Dienstag",
@@ -72,7 +85,6 @@
"Settings" : "Einstellungen",
"Saving..." : "Speichern…",
"seconds ago" : "Gerade eben",
- "Couldn't send reset email. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versendet werden. Bitte kontaktiere Deinen Administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Der Link zum Rücksetzen Deines Passworts ist an Deine E-Mail-Adresse versandt worden. Solltest Du ihn innerhalb eines annehmbaren Zeitraums nicht empfangen, prüfe bitte Deine Spam-Ordner.<br>Wenn er sich nicht darin befindet, frage bitte bei Deinem lokalen Administrator nach.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Deine Dateien sind verschlüsselt. Solltest Du den Wiederherstellungsschlüssel nicht aktiviert haben, gibt es keine Möglichkeit, Deine Daten zurückzuerhalten, nachdem Dein Passwort zurückgesetzt ist.<br />Falls Du Dir nicht sicher bist, was zu tun ist, kontaktiere bitte Deinen Administrator, bevor Du fortfährst.<br />Willst Du wirklich fortfahren?",
"I know what I'm doing" : "Ich weiß, was ich mache",
@@ -103,9 +115,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Dein Webserver ist noch nicht hinreichend für Datei-Synchronisation konfiguriert, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Dieser Server hat keine funktionierende Internetverbindung. Dies bedeutet, dass einige Funktionen wie das Einhängen externen Speicherplatzes, Update-Benachrichtigungen oder die Installation von Drittanbieter-Apps nicht funktionieren werden. Der Fernzugriff auf Dateien und der Versand von E-Mail-Benachrichtigungen kann ebenfalls nicht funktionieren. Es wird empfohlen, die Internetverbindung dieses Servers zu aktivieren, wenn Du alle Funktionen nutzen möchtest.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Dein Datenverzeichnis und Deine Dateien sind wahrscheinlich vom Internet aus erreichbar. Die .htaccess-Datei funktioniert nicht. Es wird dringend empfohlen, Deinen Webserver dahingehend zu konfigurieren, dass das Datenverzeichnis nicht mehr vom Internet aus erreichbar ist oder dass Du es aus dem Document-Root-Verzeichnis des Webservers herausverschiebst.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Es wurde kein PHP Memory Cache konfiguriert. Konfiguriere zur Erhöhung der Leistungsfähigkeit, soweit verfügbar, einen Memory Cache. Weitere Informationen finden Sie in unserer <a href=\"{docLink}\">Dokumentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ist für PHP nicht lesbar, wovon aus Sicherheitsgründen dringend abgeraten wird. Weitere Informationen hierzu findest Du in unserer <a href=\"{docLink}\">Dokumentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Deine PHP Version ({version}) wird nicht länger <a href=\"{phpLink}\">unterstützt</a>. Wir empfehlen ein Upgrade deiner PHP Version, um die volle Performance und Sicherheit zu gewährleisten.",
"Error occurred while checking server setup" : "Fehler beim Überprüfen der Servereinrichtung",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Der „{header}“-HTTP-Header ist nicht so konfiguriert, dass er „{expected}“ entspricht. Dies ist ein potentielles Sicherheitsrisiko und es wird empfohlen, diese Einstellung zu ändern.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Der „Strict-Transport-Security“-HTTP-Header ist nicht auf mindestens „{seconds}“ Sekunden eingestellt. Für umfassende Sicherheit wird das Aktivieren von HSTS empfohlen, wie es in unseren <a href=\"{docUrl}\">Sicherheitshinweisen</a> erläutert ist.",
@@ -115,7 +124,6 @@
"Error" : "Fehler",
"Error while sharing" : "Fehler beim Teilen",
"Error while unsharing" : "Fehler beim Aufheben der Freigabe",
- "Error while changing permissions" : "Fehler beim Ändern der Rechte",
"Error setting expiration date" : "Fehler beim Setzen des Ablaufdatums",
"The public link will expire no later than {days} days after it is created" : "Der öffentliche Link wird spätestens {days} Tage nach seiner Erstellung ablaufen",
"Set expiration date" : "Setze ein Ablaufdatum",
@@ -134,7 +142,6 @@
"Send" : "Senden",
"Shared with you and the group {group} by {owner}" : "{owner} hat dies mit Dir und der Gruppe {group} geteilt",
"Shared with you by {owner}" : "{owner} hat dies mit Dir geteilt",
- "Shared in {item} with {user}" : "Für {user} in {item} freigegeben",
"group" : "Gruppe",
"remote" : "Entfernte Freigabe",
"notify by email" : "per E-Mail benachrichtigen",
@@ -152,9 +159,10 @@
"Share with users, groups or remote users …" : "Mit Benutzern, Gruppen oder entfernten Benutzern teilen…",
"Warning" : "Warnung",
"Error while sending notification" : "Fehler beim Senden der Benachrichtigung",
+ "Delete" : "Löschen",
+ "Rename" : "Umbenennen",
"The object type is not specified." : "Der Objekttyp ist nicht angegeben.",
"Enter new" : "Neuen eingeben",
- "Delete" : "Löschen",
"Add" : "Hinzufügen",
"Edit tags" : "Schlagwörter bearbeiten",
"Error loading dialog template: {error}" : "Fehler beim Laden der Dialogvorlage: {error}",
@@ -166,21 +174,13 @@
"Hello {name}" : "Hallo {name}",
"_download %n file_::_download %n files_" : ["Lade %n Datei herunter","Lade %n Dateien herunter"],
"{version} is available. Get more information on how to update." : "{version} ist verfügbar. Hole weitere Informationen zu Aktualisierungen ein.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Das Update läuft gerade. Das Verlassen dieser Seite könnte den Update Prozess in einigen Umgebungen unterbrechen.",
"Updating {productName} to version {version}, this may take a while." : "Aktualisiere {productName} auf Version {version}. Dies könnte eine Weile dauern.",
"An error occurred." : "Es ist ein Fehler aufgetreten.",
"Please reload the page." : "Bitte lade die Seite neu.",
"The update was unsuccessful. " : "Die Aktualisierung war nicht erfolgreich.",
"The update was successful. There were warnings." : "Das Update war erfolgreich. Warnungen wurden ausgegeben.",
"The update was successful. Redirecting you to ownCloud now." : "Das Update war erfolgreich. Du wirst nun zu ownCloud weitergeleitet.",
- "Couldn't reset password because the token is invalid" : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht zurückgesetzt werden",
- "Couldn't reset password because the token is expired" : "Das Passwort konnte nicht zurückgesetzt werden, da der Token abgelaufen ist",
- "Couldn't send reset email. Please make sure your username is correct." : "E-Mail zum Zurücksetzen kann nicht versendet werden. Bitte stelle sicher, dass Dein Benutzername korrekt ist.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versandt werden, weil für diesen Benutzernamen keine E-Mail-Adresse hinterlegt ist. Bitte kontaktiere Deinen Administrator.",
- "%s password reset" : "%s-Passwort zurücksetzen",
- "Use the following link to reset your password: {link}" : "Benutze den folgenden Link, um Dein Passwort zurückzusetzen: {link}",
- "New password" : "Neues Passwort",
- "New Password" : "Neues Passwort",
- "Reset password" : "Passwort zurücksetzen",
"Searching other places" : "Andere Orte durchsuchen",
"No search results in other folders" : "Keine Suchergebnisse in anderen Ordnern",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} Suchergebnis im anderen Ordner","{count} Suchergebnisse in anderen Ordnern"],
@@ -250,7 +250,13 @@
"Please try again or contact your administrator." : "Bitte versuche es noch einmal oder kontaktiere Deinen Administrator.",
"Log in" : "Anmelden",
"Wrong password. Reset it?" : "Falsches Passwort. Soll es zurückgesetzt werden?",
+ "Wrong password." : "Falsches Passwort.",
+ "Stay logged in" : "Angemeldet bleiben",
"Alternative Logins" : "Alternative Logins",
+ "Use the following link to reset your password: {link}" : "Benutze den folgenden Link, um Dein Passwort zurückzusetzen: {link}",
+ "New password" : "Neues Passwort",
+ "New Password" : "Neues Passwort",
+ "Reset password" : "Passwort zurücksetzen",
"This ownCloud instance is currently in single user mode." : "Diese ownClound-Instanz befindet sich derzeit im Einzelbenutzermodus.",
"This means only administrators can use the instance." : "Dies bedeutet, dass diese Instanz nur von Administratoren genutzt werden kann.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktiere Deinen Systemadministrator, wenn diese Meldung dauerhaft oder unerwartet erscheint.",
diff --git a/core/l10n/de_DE.js b/core/l10n/de_DE.js
index 8dd5132dcd9..eb3cff6bef5 100644
--- a/core/l10n/de_DE.js
+++ b/core/l10n/de_DE.js
@@ -6,25 +6,38 @@ OC.L10N.register(
"Turned on maintenance mode" : "Wartungsmodus eingeschaltet ",
"Turned off maintenance mode" : "Wartungsmodus ausgeschaltet",
"Maintenance mode is kept active" : "Wartungsmodus wird aktiv gehalten",
+ "Updating database schema" : "Das Datenbankschema wird aktualisiert",
"Updated database" : "Datenbank aktualisiert",
"Checked database schema update" : "Datenbankschema-Aktualisierung überprüft",
+ "Checking updates of apps" : "Es wird nach Updates für die Apps gesucht",
"Checked database schema update for apps" : "Datenbankschema-Aktualisierung für Apps überprüft",
"Updated \"%s\" to %s" : "„%s“ zu %s aktualisiert",
"Repair warning: " : "Reperaturwarnung:",
"Repair error: " : "Reperaturfehler:",
- "Set log level to debug - current level: \"%s\"" : "Log-Level auf Debug gesetzt - aktuelles Level: \"%s\"",
- "Reset log level to \"%s\"" : "Log-Level auf \"%s\" zurückgesetzt",
+ "Set log level to debug" : "Log-Level auf \"debug\" gesetzt",
+ "Reset log level" : "Ursprüngliches Log-Level wiederhergestellt",
+ "Starting code integrity check" : "Code-Integrität wird überprüft",
+ "Finished code integrity check" : "Code-Integritätsprüfung abgeschlossen",
+ "%s (3rdparty)" : "%s (Drittanbieter)",
+ "%s (incompatible)" : "%s (inkompatibel)",
"Following apps have been disabled: %s" : "Die folgenden Apps sind deaktiviert worden: %s",
"Already up to date" : "Bereits aktuell",
+ "Please select a file." : "Bitte wählen Sie eine Datei aus.",
"File is too big" : "Datei ist zu groß",
"Invalid file provided" : "Ungültige Datei zur Verfügung gestellt",
"No image or file provided" : "Es wurde weder ein Bild noch eine Datei zur Verfügung gestellt",
"Unknown filetype" : "Unbekannter Dateityp",
"Invalid image" : "Ungültiges Bild",
+ "An error occurred. Please contact your admin." : "Es ist ein Fehler aufgetreten, bitte kontaktieren Sie Ihren Administrator.",
"No temporary profile picture available, try again" : "Kein temporäres Profilbild verfügbar, bitte versuchen Sie es noch einmal",
"No crop data provided" : "Keine Beschnittdaten zur Verfügung gestellt",
"No valid crop data provided" : "Keine gültigen Zuschnittdaten zur Verfügung gestellt",
"Crop is not square" : "Zuschnitt ist nicht quadratisch",
+ "Couldn't reset password because the token is invalid" : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht zurückgesetzt werden",
+ "Couldn't reset password because the token is expired" : "Das Passwort konnte nicht zurückgesetzt werden, da der Token abgelaufen ist",
+ "Couldn't send reset email. Please make sure your username is correct." : "E-Mail zum Zurücksetzen kann nicht versendet werden. Bitte stellen Sie sicher, dass Ihr Benutzername richtig ist.",
+ "%s password reset" : "%s-Passwort zurücksetzen",
+ "Couldn't send reset email. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versendet werden. Bitte kontaktieren Sie Ihren Administrator.",
"Sunday" : "Sonntag",
"Monday" : "Montag",
"Tuesday" : "Dienstag",
@@ -73,7 +86,6 @@ OC.L10N.register(
"Settings" : "Einstellungen",
"Saving..." : "Speichervorgang…",
"seconds ago" : "Gerade eben",
- "Couldn't send reset email. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versendet werden. Bitte kontaktieren Sie Ihren Administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Der Link zum Rücksetzen Ihres Passworts ist an Ihre E-Mail-Adresse versandt worden. Sollten Sie ihn innerhalb eines annehmbaren Zeitraums nicht empfangen, prüfen Sie bitte Ihren Spam-Ordner.<br>Wenn er sich nicht darin befindet, fragen Sie bitte bei Ihrem lokalen Administrator nach.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Ihre Dateien sind verschlüsselt. Wenn Sie den Wiederherstellungsschlüssel nicht aktiviert haben, wird es keine Möglichkeit geben, um Ihre Daten wieder zu erhalten, nachdem Ihr Passwort zurückgesetzt wurde.<br />Wenn Sie sich nicht sicher sind, was Sie tun sollen, wenden Sie sich bitte an Ihren Administrator, bevor Sie fortfahren.<br />Wollen Sie wirklich fortfahren?",
"I know what I'm doing" : "Ich weiß, was ich mache",
@@ -104,9 +116,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ihr Webserver ist noch nicht hinreichend für Datei-Synchronisation konfiguriert, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Dieser Server hat keine funktionierende Internetverbindung. Dies bedeutet, dass einige Funktionen wie das Einhängen externen Speicherplatzes, Update-Benachrichtigungen oder die Installation von Drittanbieter-Apps nicht funktionieren werden. Der Fernzugriff auf Dateien und der Versand von E-Mail-Benachrichtigungen kann ebenfalls nicht funktionieren. Es wird empfohlen, die Internetverbindung dieses Servers zu aktivieren, wenn Sie alle Funktionen nutzen möchten.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ihr Datenverzeichnis und Ihre Dateien sind wahrscheinlich vom Internet aus erreichbar. Die .htaccess-Datei funktioniert nicht. Es wird dringend empfohlen, Ihren Webserver dahingehend zu konfigurieren, dass das Datenverzeichnis nicht mehr vom Internet aus erreichbar ist oder dass Sie es aus dem Document-Root-Verzeichnis des Webservers herausverschieben.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Es wurde kein PHP Memory Cache konfiguriert. Konfiguriere zur Erhöhung der Leistungsfähigkeit, soweit verfügbar, einen Memory Cache. Weitere Informationen finden Sie in unserer <a href=\"{docLink}\">Dokumentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ist von PHP nicht lesbar, wovon aus Sicherheitsgründen dringend abgeraten wird. Weitere Informationen hierzu finden Sie in unserer <a href=\"{docLink}\">Dokumentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Ihre PHP Version ({version}) wird nicht länger <a href=\"{phpLink}\">unterstützt</a>. Wir empfehlen ein Upgrade ihrer PHP Version, um die volle Performance und Sicherheit zu gewährleisten.",
"Error occurred while checking server setup" : "Fehler beim Überprüfen der Servereinrichtung",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Der „{header}“-HTTP-Header ist nicht so konfiguriert, dass er „{expected}“ entspricht. Dies ist ein potentielles Sicherheitsrisiko und es wird empfohlen, diese Einstellung zu ändern.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Der „Strict-Transport-Security“-HTTP-Header ist nicht auf mindestens „{seconds}“ Sekunden eingestellt. Für umfassende Sicherheit wird das Aktivieren von HSTS empfohlen, wie es in unseren <a href=\"{docUrl}\">Sicherheitshinweisen</a> erläutert ist.",
@@ -116,7 +125,6 @@ OC.L10N.register(
"Error" : "Fehler",
"Error while sharing" : "Fehler beim Teilen",
"Error while unsharing" : "Fehler beim Aufheben der Freigabe",
- "Error while changing permissions" : "Fehler bei der Änderung der Rechte",
"Error setting expiration date" : "Fehler beim Setzen des Ablaufdatums",
"The public link will expire no later than {days} days after it is created" : "Der öffentliche Link wird spätestens {days} Tage nach seiner Erstellung ablaufen",
"Set expiration date" : "Ein Ablaufdatum setzen",
@@ -135,7 +143,6 @@ OC.L10N.register(
"Send" : "Senden",
"Shared with you and the group {group} by {owner}" : "Von {owner} mit Ihnen und der Gruppe {group} geteilt.",
"Shared with you by {owner}" : "Von {owner} mit Ihnen geteilt.",
- "Shared in {item} with {user}" : "Freigegeben in {item} von {user}",
"group" : "Gruppe",
"remote" : "Entfernte Freigabe",
"notify by email" : "per E-Mail benachrichtigen",
@@ -153,9 +160,11 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Mit Benutzern, Gruppen oder entfernten Benutzern teilen…",
"Warning" : "Warnung",
"Error while sending notification" : "Fehler beim Senden der Benachrichtigung",
+ "invisible" : "unsichtbar",
+ "Delete" : "Löschen",
+ "Rename" : "Umbenennen",
"The object type is not specified." : "Der Objekttyp ist nicht angegeben.",
"Enter new" : "Neuen eingeben",
- "Delete" : "Löschen",
"Add" : "Hinzufügen",
"Edit tags" : "Schlagwörter bearbeiten",
"Error loading dialog template: {error}" : "Fehler beim Laden der Dialogvorlage: {error}",
@@ -167,20 +176,13 @@ OC.L10N.register(
"Hello {name}" : "Hallo {name}",
"_download %n file_::_download %n files_" : ["Lade %n Datei herunter","Lade %n Dateien herunter"],
"{version} is available. Get more information on how to update." : "{version} ist verfügbar. Holen Sie weitere Informationen zu Aktualisierungen ein.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Das Upgrade läuft noch , diese Seite zu verlassen könnte das Verfahren in einigen Umgebungen unterbrechen.",
"Updating {productName} to version {version}, this may take a while." : "{productName} wird auf Version {version} aktualisiert. Das könnte eine Weile dauern.",
+ "An error occurred." : "Ein Fehler ist aufgetreten.",
"Please reload the page." : "Bitte laden Sie die Seite neu.",
"The update was unsuccessful. " : "Die Aktualisierung war nicht erfolgreich.",
"The update was successful. There were warnings." : "Das Update war erfolgreich. Warnungen wurden ausgegeben.",
"The update was successful. Redirecting you to ownCloud now." : "Das Update war erfolgreich. Sie werden nun zu ownCloud weitergeleitet.",
- "Couldn't reset password because the token is invalid" : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht zurückgesetzt werden",
- "Couldn't reset password because the token is expired" : "Das Passwort konnte nicht zurückgesetzt werden, da der Token abgelaufen ist",
- "Couldn't send reset email. Please make sure your username is correct." : "E-Mail zum Zurücksetzen kann nicht versendet werden. Bitte stellen Sie sicher, dass Ihr Benutzername richtig ist.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versandt werden, weil für diesen Benutzernamen keine E-Mail-Adresse hinterlegt ist. Bitte kontaktieren Sie Ihren Administrator.",
- "%s password reset" : "%s-Passwort zurücksetzen",
- "Use the following link to reset your password: {link}" : "Benutzen Sie den folgenden Link, um Ihr Passwort zurückzusetzen: {link}",
- "New password" : "Neues Passwort",
- "New Password" : "Neues Passwort",
- "Reset password" : "Passwort zurücksetzen",
"Searching other places" : "Andere Orte durchsuchen",
"No search results in other folders" : "Keine Suchergebnisse in anderen Ordnern",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} Suchergebnis in anderen Ordnern","{count} Suchergebnisse in anderen Ordnern"],
@@ -250,7 +252,13 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Bitte versuchen Sie es noch einmal oder kontaktieren Sie Ihren Administrator.",
"Log in" : "Einloggen",
"Wrong password. Reset it?" : "Falsches Passwort. Soll es zurückgesetzt werden?",
+ "Wrong password." : "Falsches Passwort.",
+ "Stay logged in" : "Angemeldet bleiben",
"Alternative Logins" : "Alternative Logins",
+ "Use the following link to reset your password: {link}" : "Benutzen Sie den folgenden Link, um Ihr Passwort zurückzusetzen: {link}",
+ "New password" : "Neues Passwort",
+ "New Password" : "Neues Passwort",
+ "Reset password" : "Passwort zurücksetzen",
"This ownCloud instance is currently in single user mode." : "Diese ownClound-Instanz befindet sich derzeit im Einzelbenutzermodus.",
"This means only administrators can use the instance." : "Das bedeutet, dass diese Instanz nur von Administratoren benutzt werden kann.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktieren Sie Ihren Systemadministrator, wenn diese Meldung dauerhaft oder unerwartet erscheint.",
diff --git a/core/l10n/de_DE.json b/core/l10n/de_DE.json
index a1b4a6e72d7..4eec4c90246 100644
--- a/core/l10n/de_DE.json
+++ b/core/l10n/de_DE.json
@@ -4,25 +4,38 @@
"Turned on maintenance mode" : "Wartungsmodus eingeschaltet ",
"Turned off maintenance mode" : "Wartungsmodus ausgeschaltet",
"Maintenance mode is kept active" : "Wartungsmodus wird aktiv gehalten",
+ "Updating database schema" : "Das Datenbankschema wird aktualisiert",
"Updated database" : "Datenbank aktualisiert",
"Checked database schema update" : "Datenbankschema-Aktualisierung überprüft",
+ "Checking updates of apps" : "Es wird nach Updates für die Apps gesucht",
"Checked database schema update for apps" : "Datenbankschema-Aktualisierung für Apps überprüft",
"Updated \"%s\" to %s" : "„%s“ zu %s aktualisiert",
"Repair warning: " : "Reperaturwarnung:",
"Repair error: " : "Reperaturfehler:",
- "Set log level to debug - current level: \"%s\"" : "Log-Level auf Debug gesetzt - aktuelles Level: \"%s\"",
- "Reset log level to \"%s\"" : "Log-Level auf \"%s\" zurückgesetzt",
+ "Set log level to debug" : "Log-Level auf \"debug\" gesetzt",
+ "Reset log level" : "Ursprüngliches Log-Level wiederhergestellt",
+ "Starting code integrity check" : "Code-Integrität wird überprüft",
+ "Finished code integrity check" : "Code-Integritätsprüfung abgeschlossen",
+ "%s (3rdparty)" : "%s (Drittanbieter)",
+ "%s (incompatible)" : "%s (inkompatibel)",
"Following apps have been disabled: %s" : "Die folgenden Apps sind deaktiviert worden: %s",
"Already up to date" : "Bereits aktuell",
+ "Please select a file." : "Bitte wählen Sie eine Datei aus.",
"File is too big" : "Datei ist zu groß",
"Invalid file provided" : "Ungültige Datei zur Verfügung gestellt",
"No image or file provided" : "Es wurde weder ein Bild noch eine Datei zur Verfügung gestellt",
"Unknown filetype" : "Unbekannter Dateityp",
"Invalid image" : "Ungültiges Bild",
+ "An error occurred. Please contact your admin." : "Es ist ein Fehler aufgetreten, bitte kontaktieren Sie Ihren Administrator.",
"No temporary profile picture available, try again" : "Kein temporäres Profilbild verfügbar, bitte versuchen Sie es noch einmal",
"No crop data provided" : "Keine Beschnittdaten zur Verfügung gestellt",
"No valid crop data provided" : "Keine gültigen Zuschnittdaten zur Verfügung gestellt",
"Crop is not square" : "Zuschnitt ist nicht quadratisch",
+ "Couldn't reset password because the token is invalid" : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht zurückgesetzt werden",
+ "Couldn't reset password because the token is expired" : "Das Passwort konnte nicht zurückgesetzt werden, da der Token abgelaufen ist",
+ "Couldn't send reset email. Please make sure your username is correct." : "E-Mail zum Zurücksetzen kann nicht versendet werden. Bitte stellen Sie sicher, dass Ihr Benutzername richtig ist.",
+ "%s password reset" : "%s-Passwort zurücksetzen",
+ "Couldn't send reset email. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versendet werden. Bitte kontaktieren Sie Ihren Administrator.",
"Sunday" : "Sonntag",
"Monday" : "Montag",
"Tuesday" : "Dienstag",
@@ -71,7 +84,6 @@
"Settings" : "Einstellungen",
"Saving..." : "Speichervorgang…",
"seconds ago" : "Gerade eben",
- "Couldn't send reset email. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versendet werden. Bitte kontaktieren Sie Ihren Administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Der Link zum Rücksetzen Ihres Passworts ist an Ihre E-Mail-Adresse versandt worden. Sollten Sie ihn innerhalb eines annehmbaren Zeitraums nicht empfangen, prüfen Sie bitte Ihren Spam-Ordner.<br>Wenn er sich nicht darin befindet, fragen Sie bitte bei Ihrem lokalen Administrator nach.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Ihre Dateien sind verschlüsselt. Wenn Sie den Wiederherstellungsschlüssel nicht aktiviert haben, wird es keine Möglichkeit geben, um Ihre Daten wieder zu erhalten, nachdem Ihr Passwort zurückgesetzt wurde.<br />Wenn Sie sich nicht sicher sind, was Sie tun sollen, wenden Sie sich bitte an Ihren Administrator, bevor Sie fortfahren.<br />Wollen Sie wirklich fortfahren?",
"I know what I'm doing" : "Ich weiß, was ich mache",
@@ -102,9 +114,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ihr Webserver ist noch nicht hinreichend für Datei-Synchronisation konfiguriert, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Dieser Server hat keine funktionierende Internetverbindung. Dies bedeutet, dass einige Funktionen wie das Einhängen externen Speicherplatzes, Update-Benachrichtigungen oder die Installation von Drittanbieter-Apps nicht funktionieren werden. Der Fernzugriff auf Dateien und der Versand von E-Mail-Benachrichtigungen kann ebenfalls nicht funktionieren. Es wird empfohlen, die Internetverbindung dieses Servers zu aktivieren, wenn Sie alle Funktionen nutzen möchten.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ihr Datenverzeichnis und Ihre Dateien sind wahrscheinlich vom Internet aus erreichbar. Die .htaccess-Datei funktioniert nicht. Es wird dringend empfohlen, Ihren Webserver dahingehend zu konfigurieren, dass das Datenverzeichnis nicht mehr vom Internet aus erreichbar ist oder dass Sie es aus dem Document-Root-Verzeichnis des Webservers herausverschieben.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Es wurde kein PHP Memory Cache konfiguriert. Konfiguriere zur Erhöhung der Leistungsfähigkeit, soweit verfügbar, einen Memory Cache. Weitere Informationen finden Sie in unserer <a href=\"{docLink}\">Dokumentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ist von PHP nicht lesbar, wovon aus Sicherheitsgründen dringend abgeraten wird. Weitere Informationen hierzu finden Sie in unserer <a href=\"{docLink}\">Dokumentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Ihre PHP Version ({version}) wird nicht länger <a href=\"{phpLink}\">unterstützt</a>. Wir empfehlen ein Upgrade ihrer PHP Version, um die volle Performance und Sicherheit zu gewährleisten.",
"Error occurred while checking server setup" : "Fehler beim Überprüfen der Servereinrichtung",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Der „{header}“-HTTP-Header ist nicht so konfiguriert, dass er „{expected}“ entspricht. Dies ist ein potentielles Sicherheitsrisiko und es wird empfohlen, diese Einstellung zu ändern.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Der „Strict-Transport-Security“-HTTP-Header ist nicht auf mindestens „{seconds}“ Sekunden eingestellt. Für umfassende Sicherheit wird das Aktivieren von HSTS empfohlen, wie es in unseren <a href=\"{docUrl}\">Sicherheitshinweisen</a> erläutert ist.",
@@ -114,7 +123,6 @@
"Error" : "Fehler",
"Error while sharing" : "Fehler beim Teilen",
"Error while unsharing" : "Fehler beim Aufheben der Freigabe",
- "Error while changing permissions" : "Fehler bei der Änderung der Rechte",
"Error setting expiration date" : "Fehler beim Setzen des Ablaufdatums",
"The public link will expire no later than {days} days after it is created" : "Der öffentliche Link wird spätestens {days} Tage nach seiner Erstellung ablaufen",
"Set expiration date" : "Ein Ablaufdatum setzen",
@@ -133,7 +141,6 @@
"Send" : "Senden",
"Shared with you and the group {group} by {owner}" : "Von {owner} mit Ihnen und der Gruppe {group} geteilt.",
"Shared with you by {owner}" : "Von {owner} mit Ihnen geteilt.",
- "Shared in {item} with {user}" : "Freigegeben in {item} von {user}",
"group" : "Gruppe",
"remote" : "Entfernte Freigabe",
"notify by email" : "per E-Mail benachrichtigen",
@@ -151,9 +158,11 @@
"Share with users, groups or remote users …" : "Mit Benutzern, Gruppen oder entfernten Benutzern teilen…",
"Warning" : "Warnung",
"Error while sending notification" : "Fehler beim Senden der Benachrichtigung",
+ "invisible" : "unsichtbar",
+ "Delete" : "Löschen",
+ "Rename" : "Umbenennen",
"The object type is not specified." : "Der Objekttyp ist nicht angegeben.",
"Enter new" : "Neuen eingeben",
- "Delete" : "Löschen",
"Add" : "Hinzufügen",
"Edit tags" : "Schlagwörter bearbeiten",
"Error loading dialog template: {error}" : "Fehler beim Laden der Dialogvorlage: {error}",
@@ -165,20 +174,13 @@
"Hello {name}" : "Hallo {name}",
"_download %n file_::_download %n files_" : ["Lade %n Datei herunter","Lade %n Dateien herunter"],
"{version} is available. Get more information on how to update." : "{version} ist verfügbar. Holen Sie weitere Informationen zu Aktualisierungen ein.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Das Upgrade läuft noch , diese Seite zu verlassen könnte das Verfahren in einigen Umgebungen unterbrechen.",
"Updating {productName} to version {version}, this may take a while." : "{productName} wird auf Version {version} aktualisiert. Das könnte eine Weile dauern.",
+ "An error occurred." : "Ein Fehler ist aufgetreten.",
"Please reload the page." : "Bitte laden Sie die Seite neu.",
"The update was unsuccessful. " : "Die Aktualisierung war nicht erfolgreich.",
"The update was successful. There were warnings." : "Das Update war erfolgreich. Warnungen wurden ausgegeben.",
"The update was successful. Redirecting you to ownCloud now." : "Das Update war erfolgreich. Sie werden nun zu ownCloud weitergeleitet.",
- "Couldn't reset password because the token is invalid" : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht zurückgesetzt werden",
- "Couldn't reset password because the token is expired" : "Das Passwort konnte nicht zurückgesetzt werden, da der Token abgelaufen ist",
- "Couldn't send reset email. Please make sure your username is correct." : "E-Mail zum Zurücksetzen kann nicht versendet werden. Bitte stellen Sie sicher, dass Ihr Benutzername richtig ist.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Die E-Mail zum Zurücksetzen konnte nicht versandt werden, weil für diesen Benutzernamen keine E-Mail-Adresse hinterlegt ist. Bitte kontaktieren Sie Ihren Administrator.",
- "%s password reset" : "%s-Passwort zurücksetzen",
- "Use the following link to reset your password: {link}" : "Benutzen Sie den folgenden Link, um Ihr Passwort zurückzusetzen: {link}",
- "New password" : "Neues Passwort",
- "New Password" : "Neues Passwort",
- "Reset password" : "Passwort zurücksetzen",
"Searching other places" : "Andere Orte durchsuchen",
"No search results in other folders" : "Keine Suchergebnisse in anderen Ordnern",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} Suchergebnis in anderen Ordnern","{count} Suchergebnisse in anderen Ordnern"],
@@ -248,7 +250,13 @@
"Please try again or contact your administrator." : "Bitte versuchen Sie es noch einmal oder kontaktieren Sie Ihren Administrator.",
"Log in" : "Einloggen",
"Wrong password. Reset it?" : "Falsches Passwort. Soll es zurückgesetzt werden?",
+ "Wrong password." : "Falsches Passwort.",
+ "Stay logged in" : "Angemeldet bleiben",
"Alternative Logins" : "Alternative Logins",
+ "Use the following link to reset your password: {link}" : "Benutzen Sie den folgenden Link, um Ihr Passwort zurückzusetzen: {link}",
+ "New password" : "Neues Passwort",
+ "New Password" : "Neues Passwort",
+ "Reset password" : "Passwort zurücksetzen",
"This ownCloud instance is currently in single user mode." : "Diese ownClound-Instanz befindet sich derzeit im Einzelbenutzermodus.",
"This means only administrators can use the instance." : "Das bedeutet, dass diese Instanz nur von Administratoren benutzt werden kann.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktieren Sie Ihren Systemadministrator, wenn diese Meldung dauerhaft oder unerwartet erscheint.",
diff --git a/core/l10n/el.js b/core/l10n/el.js
index 2f264730565..bbee35b0a45 100644
--- a/core/l10n/el.js
+++ b/core/l10n/el.js
@@ -16,8 +16,6 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Αναβαθμίστηκε \"%s\" σε %s",
"Repair warning: " : "Προειδοποίηση διόρθωσης:",
"Repair error: " : "Σφάλμα διόρθωσης:",
- "Set log level to debug - current level: \"%s\"" : "Καθορισμός του επιπέδου καταγραφής σε αποσφαλμάτωση - τρέχον επίπεδο: \"%s\"",
- "Reset log level to \"%s\"" : "Επαναφορά επιπέδου καταγραφής σε \"%s\"",
"%s (3rdparty)" : "%s (3ου μέρους)",
"%s (incompatible)" : "%s (ασύμβατη)",
"Following apps have been disabled: %s" : "Οι ακόλουθες εφαρμογές έχουν απενεργοποιηθεί: %s",
@@ -32,6 +30,11 @@ OC.L10N.register(
"No crop data provided" : "Δεν δόθηκαν δεδομένα περικοπής",
"No valid crop data provided" : "Έχουν δοθεί μη έγκυρα δεδομένα περικοπής",
"Crop is not square" : "Η περικοπή δεν εχει τετραγωνικό σχήμα",
+ "Couldn't reset password because the token is invalid" : "Αδυναμία επαναφοράς κωδικού πρόσβασης καθώς το τεκμήριο είναι άκυρο",
+ "Couldn't reset password because the token is expired" : "Αδυναμία επαναφοράς κωδικού πρόσβασης επειδή το token έχει λήξει",
+ "Couldn't send reset email. Please make sure your username is correct." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς. Παρακαλώ ελέγξτε ότι το όνομα χρήστη σας είναι ορθό.",
+ "%s password reset" : "%s επαναφορά κωδικού πρόσβασης",
+ "Couldn't send reset email. Please contact your administrator." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς. Παρακαλώ επικοινωνήστε με το διαχειριστή σας.",
"Sunday" : "Κυριακή",
"Monday" : "Δευτέρα",
"Tuesday" : "Τρίτη",
@@ -80,7 +83,6 @@ OC.L10N.register(
"Settings" : "Ρυθμίσεις",
"Saving..." : "Γίνεται αποθήκευση...",
"seconds ago" : "δευτερόλεπτα πριν",
- "Couldn't send reset email. Please contact your administrator." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς. Παρακαλώ επικοινωνήστε με το διαχειριστή σας.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Ο σύνδεσμος για την επαναφορά του κωδικού πρόσβασής σας απεστάλη στο ηλ. ταχυδρομείο σας. Εάν δεν το παραλάβετε μέσα σε ένα εύλογο χρονικό διάστημα, ελέγξτε το φάκελο ανεπιθύμητων μηνυμάτων σας. <br>Εάν δεν βρίσκεται εκεί ρωτήστε τον τοπικό διαχειριστή σας.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Τα αρχεία σας είναι κρυπτογραφημένα. Εάν δεν έχετε ενεργοποιήσει το κλειδί επαναφοράς, δεν θα υπάρχει τρόπος να ανακτήσετε τα δεδομένα σας μετά την επαναφορά του κωδικού πρόσβασής σας.<br />Εάν δεν είστε σίγουροι για το τι θα θέλατε να κάνετε, παρακαλώ επικοινωνήστε με το διαχειριστή σας πριν συνεχίσετε. <br />Θέλετε στ' αλήθεια να συνεχίσετε;",
"I know what I'm doing" : "Γνωρίζω τι κάνω",
@@ -111,11 +113,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ο διακομιστής σας δεν έχει ρυθμιστεί κατάλληλα ώστε να επιτρέπει τον συγχρονισμό αρχείων γιατί η διεπαφή WebDAV πιθανόν είναι κατεστραμμένη.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Αυτός ο διακομιστής δεν έχει ενεργή σύνδεση στο διαδίκτυο. Αυτό σημαίνει ότι κάποιες υπηρεσίες όπως η σύνδεση με εξωτερικούς αποθηκευτικούς χώρους, ειδοποιήσεις για ενημερώσεις ή η εγκατάσταση εφαρμογών 3ων δεν θα είναι διαθέσιμες. Η πρόσβαση απομακρυσμένων αρχείων και η αποστολή ειδοποιήσεων μέσω ηλεκτρονικού ταχυδρομείου μπορεί επίσης να μην είναι διαθέσιμες. Προτείνουμε να ενεργοποιήσετε την πρόσβαση στο διαδίκτυο για αυτόν το διακομιστή εάν θέλετε να χρησιμοποιήσετε όλες τις υπηρεσίες.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ο κατάλογος δεδομένων και τα αρχεία σας είναι πιθανόν διαθέσιμα στο διαδίκτυο. Το αρχείο .htaccess δεν λειτουργεί. Σας προτείνουμε ανεπιφύλακτα να ρυθμίσετε το διακομιστή σας με τέτοιο τρόπο ώστε ο κατάλογος δεδομένων να μην είναι πλέον προσβάσιμος ή να μετακινήσετε τον κατάλογο δεδομένων εκτός του καταλόγου της ρίζας εγγράφων-document root του διακομιστή.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Δεν έχει οριστεί προσωρινή μνήμη. Για να βελτιώσετε την απόδοσή σας παρακαλούμε να διαμορφώσετε ένα χώρο προσωρινής αποθήκευσης εάν υπάρχει διαθέσιμος. Περαιτέρω πληροφορίες μπορείτε να βρείτε στην <a href=\"{docLink}\">τεκμηρίωση</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Το /dev/urandom δεν είναι αναγνώσιμο από την PHP, το οποίο δεν συνίσταται για λόγους ασφαλείας. Περισσότερες πληροφορίες υπάρχουν στην <a href=\"{docLink}\">τεκμηρίωσή</a> μας.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Η έκδοσή σας της PHP ({version}) <a href=\"{phpLink}\">δεν υποστηρίζεται πια από την PHP</a>. Σας παροτρύνουμε να αναβαθμίσετε την PHP για να επωφεληθείτε από την απόδοση και την ασφάλεια που παρέχει η PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Η διαμόρφωση των reverse proxy headers δεν είναι σωστή ή συνδέεστε στο ownCloud από ένα έμπιστο διαμεσολαβητή. Αν δεν συνδέεστε στο ownCloud από έμπιστο διαμεσολαβητή, αυτό είναι ένα θέμα ασφαλείας και μπορεί να επιτρέψει σε έναν επιτιθέμενο να μασκαρέψει τη διεύθυνση IP του ως ορατή στο ownCloud. Περισσότερες πληροφορίες υπάρχουν στην <a href=\"{docLink}\">τεκμηρίωση</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Το Memcached είναι ρυθμισμένο ως κατανεμημένη cache, αλλά είναι εγκατεστημένη η λάθος μονάδα \"memcache\" της PHP. Το \\OC\\Memcache\\Memcached υποστηρίζει μόνο τη \"memcached\" και όχι τη \"memcache\". Δείτε τη <a href=\"{wikiLink}\">memcached wiki και για τις δύο μονάδες</a>.",
"Error occurred while checking server setup" : "Παρουσιάστηκε σφάλμα κατά τον έλεγχο της εγκατάστασης με το διακομιστή",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "H \"{header}\" κεφαλίδα HTTP δεν έχει ρυθμιστεί ώστε να ισούται με \"{expected}\". Αυτό αποτελεί ενδεχόμενο κίνδυνο ασφάλειας ή ιδιωτικότητας και συστήνουμε τη διόρθωση αυτής της ρύθμισης.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Η «Strict-Transport-Security\" κεφαλίδα HTTP δεν έχει ρυθμιστεί για τουλάχιστον \"{seconds}\" δευτερόλεπτα. Για αυξημένη ασφάλεια συστήνουμε την ενεργοποίηση του HSTS όπως περιγράφεται στις <a href=\"{docUrl}\">προτάσεις ασφαλείας</a> μας.",
@@ -125,7 +122,6 @@ OC.L10N.register(
"Error" : "Σφάλμα",
"Error while sharing" : "Σφάλμα κατά τον διαμοιρασμό",
"Error while unsharing" : "Σφάλμα κατά το σταμάτημα του διαμοιρασμού",
- "Error while changing permissions" : "Σφάλμα κατά την αλλαγή των δικαιωμάτων",
"Error setting expiration date" : "Σφάλμα κατά τον ορισμό ημ. λήξης",
"The public link will expire no later than {days} days after it is created" : "Ο δημόσιος σύνδεσμος θα απενεργοποιηθεί το πολύ {days} ημέρες μετά την δημιουργία του",
"Set expiration date" : "Ορισμός ημ. λήξης",
@@ -144,7 +140,6 @@ OC.L10N.register(
"Send" : "Αποστολή",
"Shared with you and the group {group} by {owner}" : "Διαμοιράστηκε με σας και με την ομάδα {group} του {owner}",
"Shared with you by {owner}" : "Διαμοιράστηκε με σας από τον {owner}",
- "Shared in {item} with {user}" : "Διαμοιρασμός του {item} με τον {user}",
"group" : "ομάδα",
"remote" : "απομακρυσμένα",
"notify by email" : "ειδοποίηση με email",
@@ -163,9 +158,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Διαμοιρασμός με χρήστες, ομάδες ή απομακρυσμένους χρήστες ...",
"Warning" : "Προειδοποίηση",
"Error while sending notification" : "Σφάλμα κατά την αποστολή ειδοποίησης",
+ "Delete" : "Διαγραφή",
+ "Rename" : "Μετονομασία",
"The object type is not specified." : "Δεν καθορίστηκε ο τύπος του αντικειμένου.",
"Enter new" : "Εισαγωγή νέου",
- "Delete" : "Διαγραφή",
"Add" : "Προσθήκη",
"Edit tags" : "Επεξεργασία ετικετών",
"Error loading dialog template: {error}" : "Σφάλμα φόρτωσης προτύπου διαλόγων: {σφάλμα}",
@@ -184,15 +180,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Η ενημέρωση ήταν ανεπιτυχής.",
"The update was successful. There were warnings." : "Η ενημέρωση ήταν επιτυχής. Υπήρχαν προειδοποιήσεις.",
"The update was successful. Redirecting you to ownCloud now." : "Η ενημέρωση ήταν επιτυχής. Μετάβαση στο ownCloud.",
- "Couldn't reset password because the token is invalid" : "Αδυναμία επαναφοράς κωδικού πρόσβασης καθώς το τεκμήριο είναι άκυρο",
- "Couldn't reset password because the token is expired" : "Αδυναμία επαναφοράς κωδικού πρόσβασης επειδή το token έχει λήξει",
- "Couldn't send reset email. Please make sure your username is correct." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς. Παρακαλώ ελέγξτε ότι το όνομα χρήστη σας είναι ορθό.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς καθώς δεν αντιστοιχεί καμμία διεύθυνση ηλ. ταχυδρομείου σε αυτό το όνομα χρήστη. Παρακαλώ επικοινωνήστε με το διαχειριστή σας.",
- "%s password reset" : "%s επαναφορά κωδικού πρόσβασης",
- "Use the following link to reset your password: {link}" : "Χρησιμοποιήστε τον ακόλουθο σύνδεσμο για να επανεκδόσετε τον κωδικό: {link}",
- "New password" : "Νέο συνθηματικό",
- "New Password" : "Νέος Κωδικός",
- "Reset password" : "Επαναφορά συνθηματικού",
"Searching other places" : "Έρευνα σε άλλα σημεία.",
"No search results in other folders" : "Δεν υπάρχουν αποτελέσματα αναζήτησης σε άλλους φακέλους",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} αποτέλεσμα αναζήτησης σε άλλο φάκελο","{count} αποτελέσματα αναζήτησης σε άλλους φακέλους"],
@@ -264,6 +251,10 @@ OC.L10N.register(
"Wrong password. Reset it?" : "Λάθος Κωδικός. Επαναφορά;",
"Stay logged in" : "Μείνετε συνδεδεμένος",
"Alternative Logins" : "Εναλλακτικές Συνδέσεις",
+ "Use the following link to reset your password: {link}" : "Χρησιμοποιήστε τον ακόλουθο σύνδεσμο για να επανεκδόσετε τον κωδικό: {link}",
+ "New password" : "Νέο συνθηματικό",
+ "New Password" : "Νέος Κωδικός",
+ "Reset password" : "Επαναφορά συνθηματικού",
"This ownCloud instance is currently in single user mode." : "Αυτή η εγκατάσταση ownCloud είναι τώρα σε κατάσταση ενός χρήστη.",
"This means only administrators can use the instance." : "Αυτό σημαίνει ότι μόνο διαχειριστές μπορούν να χρησιμοποιήσουν την εγκατάσταση.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Επικοινωνήστε με το διαχειριστή του συστήματος αν αυτό το μήνυμα συνεχίζει να εμφανίζεται ή εμφανίστηκε απρόσμενα.",
diff --git a/core/l10n/el.json b/core/l10n/el.json
index cafa289fc32..90068f5cddb 100644
--- a/core/l10n/el.json
+++ b/core/l10n/el.json
@@ -14,8 +14,6 @@
"Updated \"%s\" to %s" : "Αναβαθμίστηκε \"%s\" σε %s",
"Repair warning: " : "Προειδοποίηση διόρθωσης:",
"Repair error: " : "Σφάλμα διόρθωσης:",
- "Set log level to debug - current level: \"%s\"" : "Καθορισμός του επιπέδου καταγραφής σε αποσφαλμάτωση - τρέχον επίπεδο: \"%s\"",
- "Reset log level to \"%s\"" : "Επαναφορά επιπέδου καταγραφής σε \"%s\"",
"%s (3rdparty)" : "%s (3ου μέρους)",
"%s (incompatible)" : "%s (ασύμβατη)",
"Following apps have been disabled: %s" : "Οι ακόλουθες εφαρμογές έχουν απενεργοποιηθεί: %s",
@@ -30,6 +28,11 @@
"No crop data provided" : "Δεν δόθηκαν δεδομένα περικοπής",
"No valid crop data provided" : "Έχουν δοθεί μη έγκυρα δεδομένα περικοπής",
"Crop is not square" : "Η περικοπή δεν εχει τετραγωνικό σχήμα",
+ "Couldn't reset password because the token is invalid" : "Αδυναμία επαναφοράς κωδικού πρόσβασης καθώς το τεκμήριο είναι άκυρο",
+ "Couldn't reset password because the token is expired" : "Αδυναμία επαναφοράς κωδικού πρόσβασης επειδή το token έχει λήξει",
+ "Couldn't send reset email. Please make sure your username is correct." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς. Παρακαλώ ελέγξτε ότι το όνομα χρήστη σας είναι ορθό.",
+ "%s password reset" : "%s επαναφορά κωδικού πρόσβασης",
+ "Couldn't send reset email. Please contact your administrator." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς. Παρακαλώ επικοινωνήστε με το διαχειριστή σας.",
"Sunday" : "Κυριακή",
"Monday" : "Δευτέρα",
"Tuesday" : "Τρίτη",
@@ -78,7 +81,6 @@
"Settings" : "Ρυθμίσεις",
"Saving..." : "Γίνεται αποθήκευση...",
"seconds ago" : "δευτερόλεπτα πριν",
- "Couldn't send reset email. Please contact your administrator." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς. Παρακαλώ επικοινωνήστε με το διαχειριστή σας.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Ο σύνδεσμος για την επαναφορά του κωδικού πρόσβασής σας απεστάλη στο ηλ. ταχυδρομείο σας. Εάν δεν το παραλάβετε μέσα σε ένα εύλογο χρονικό διάστημα, ελέγξτε το φάκελο ανεπιθύμητων μηνυμάτων σας. <br>Εάν δεν βρίσκεται εκεί ρωτήστε τον τοπικό διαχειριστή σας.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Τα αρχεία σας είναι κρυπτογραφημένα. Εάν δεν έχετε ενεργοποιήσει το κλειδί επαναφοράς, δεν θα υπάρχει τρόπος να ανακτήσετε τα δεδομένα σας μετά την επαναφορά του κωδικού πρόσβασής σας.<br />Εάν δεν είστε σίγουροι για το τι θα θέλατε να κάνετε, παρακαλώ επικοινωνήστε με το διαχειριστή σας πριν συνεχίσετε. <br />Θέλετε στ' αλήθεια να συνεχίσετε;",
"I know what I'm doing" : "Γνωρίζω τι κάνω",
@@ -109,11 +111,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ο διακομιστής σας δεν έχει ρυθμιστεί κατάλληλα ώστε να επιτρέπει τον συγχρονισμό αρχείων γιατί η διεπαφή WebDAV πιθανόν είναι κατεστραμμένη.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Αυτός ο διακομιστής δεν έχει ενεργή σύνδεση στο διαδίκτυο. Αυτό σημαίνει ότι κάποιες υπηρεσίες όπως η σύνδεση με εξωτερικούς αποθηκευτικούς χώρους, ειδοποιήσεις για ενημερώσεις ή η εγκατάσταση εφαρμογών 3ων δεν θα είναι διαθέσιμες. Η πρόσβαση απομακρυσμένων αρχείων και η αποστολή ειδοποιήσεων μέσω ηλεκτρονικού ταχυδρομείου μπορεί επίσης να μην είναι διαθέσιμες. Προτείνουμε να ενεργοποιήσετε την πρόσβαση στο διαδίκτυο για αυτόν το διακομιστή εάν θέλετε να χρησιμοποιήσετε όλες τις υπηρεσίες.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ο κατάλογος δεδομένων και τα αρχεία σας είναι πιθανόν διαθέσιμα στο διαδίκτυο. Το αρχείο .htaccess δεν λειτουργεί. Σας προτείνουμε ανεπιφύλακτα να ρυθμίσετε το διακομιστή σας με τέτοιο τρόπο ώστε ο κατάλογος δεδομένων να μην είναι πλέον προσβάσιμος ή να μετακινήσετε τον κατάλογο δεδομένων εκτός του καταλόγου της ρίζας εγγράφων-document root του διακομιστή.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Δεν έχει οριστεί προσωρινή μνήμη. Για να βελτιώσετε την απόδοσή σας παρακαλούμε να διαμορφώσετε ένα χώρο προσωρινής αποθήκευσης εάν υπάρχει διαθέσιμος. Περαιτέρω πληροφορίες μπορείτε να βρείτε στην <a href=\"{docLink}\">τεκμηρίωση</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Το /dev/urandom δεν είναι αναγνώσιμο από την PHP, το οποίο δεν συνίσταται για λόγους ασφαλείας. Περισσότερες πληροφορίες υπάρχουν στην <a href=\"{docLink}\">τεκμηρίωσή</a> μας.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Η έκδοσή σας της PHP ({version}) <a href=\"{phpLink}\">δεν υποστηρίζεται πια από την PHP</a>. Σας παροτρύνουμε να αναβαθμίσετε την PHP για να επωφεληθείτε από την απόδοση και την ασφάλεια που παρέχει η PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Η διαμόρφωση των reverse proxy headers δεν είναι σωστή ή συνδέεστε στο ownCloud από ένα έμπιστο διαμεσολαβητή. Αν δεν συνδέεστε στο ownCloud από έμπιστο διαμεσολαβητή, αυτό είναι ένα θέμα ασφαλείας και μπορεί να επιτρέψει σε έναν επιτιθέμενο να μασκαρέψει τη διεύθυνση IP του ως ορατή στο ownCloud. Περισσότερες πληροφορίες υπάρχουν στην <a href=\"{docLink}\">τεκμηρίωση</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Το Memcached είναι ρυθμισμένο ως κατανεμημένη cache, αλλά είναι εγκατεστημένη η λάθος μονάδα \"memcache\" της PHP. Το \\OC\\Memcache\\Memcached υποστηρίζει μόνο τη \"memcached\" και όχι τη \"memcache\". Δείτε τη <a href=\"{wikiLink}\">memcached wiki και για τις δύο μονάδες</a>.",
"Error occurred while checking server setup" : "Παρουσιάστηκε σφάλμα κατά τον έλεγχο της εγκατάστασης με το διακομιστή",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "H \"{header}\" κεφαλίδα HTTP δεν έχει ρυθμιστεί ώστε να ισούται με \"{expected}\". Αυτό αποτελεί ενδεχόμενο κίνδυνο ασφάλειας ή ιδιωτικότητας και συστήνουμε τη διόρθωση αυτής της ρύθμισης.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Η «Strict-Transport-Security\" κεφαλίδα HTTP δεν έχει ρυθμιστεί για τουλάχιστον \"{seconds}\" δευτερόλεπτα. Για αυξημένη ασφάλεια συστήνουμε την ενεργοποίηση του HSTS όπως περιγράφεται στις <a href=\"{docUrl}\">προτάσεις ασφαλείας</a> μας.",
@@ -123,7 +120,6 @@
"Error" : "Σφάλμα",
"Error while sharing" : "Σφάλμα κατά τον διαμοιρασμό",
"Error while unsharing" : "Σφάλμα κατά το σταμάτημα του διαμοιρασμού",
- "Error while changing permissions" : "Σφάλμα κατά την αλλαγή των δικαιωμάτων",
"Error setting expiration date" : "Σφάλμα κατά τον ορισμό ημ. λήξης",
"The public link will expire no later than {days} days after it is created" : "Ο δημόσιος σύνδεσμος θα απενεργοποιηθεί το πολύ {days} ημέρες μετά την δημιουργία του",
"Set expiration date" : "Ορισμός ημ. λήξης",
@@ -142,7 +138,6 @@
"Send" : "Αποστολή",
"Shared with you and the group {group} by {owner}" : "Διαμοιράστηκε με σας και με την ομάδα {group} του {owner}",
"Shared with you by {owner}" : "Διαμοιράστηκε με σας από τον {owner}",
- "Shared in {item} with {user}" : "Διαμοιρασμός του {item} με τον {user}",
"group" : "ομάδα",
"remote" : "απομακρυσμένα",
"notify by email" : "ειδοποίηση με email",
@@ -161,9 +156,10 @@
"Share with users, groups or remote users …" : "Διαμοιρασμός με χρήστες, ομάδες ή απομακρυσμένους χρήστες ...",
"Warning" : "Προειδοποίηση",
"Error while sending notification" : "Σφάλμα κατά την αποστολή ειδοποίησης",
+ "Delete" : "Διαγραφή",
+ "Rename" : "Μετονομασία",
"The object type is not specified." : "Δεν καθορίστηκε ο τύπος του αντικειμένου.",
"Enter new" : "Εισαγωγή νέου",
- "Delete" : "Διαγραφή",
"Add" : "Προσθήκη",
"Edit tags" : "Επεξεργασία ετικετών",
"Error loading dialog template: {error}" : "Σφάλμα φόρτωσης προτύπου διαλόγων: {σφάλμα}",
@@ -182,15 +178,6 @@
"The update was unsuccessful. " : "Η ενημέρωση ήταν ανεπιτυχής.",
"The update was successful. There were warnings." : "Η ενημέρωση ήταν επιτυχής. Υπήρχαν προειδοποιήσεις.",
"The update was successful. Redirecting you to ownCloud now." : "Η ενημέρωση ήταν επιτυχής. Μετάβαση στο ownCloud.",
- "Couldn't reset password because the token is invalid" : "Αδυναμία επαναφοράς κωδικού πρόσβασης καθώς το τεκμήριο είναι άκυρο",
- "Couldn't reset password because the token is expired" : "Αδυναμία επαναφοράς κωδικού πρόσβασης επειδή το token έχει λήξει",
- "Couldn't send reset email. Please make sure your username is correct." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς. Παρακαλώ ελέγξτε ότι το όνομα χρήστη σας είναι ορθό.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Αδυναμία αποστολής ηλ. μηνύματος επαναφοράς καθώς δεν αντιστοιχεί καμμία διεύθυνση ηλ. ταχυδρομείου σε αυτό το όνομα χρήστη. Παρακαλώ επικοινωνήστε με το διαχειριστή σας.",
- "%s password reset" : "%s επαναφορά κωδικού πρόσβασης",
- "Use the following link to reset your password: {link}" : "Χρησιμοποιήστε τον ακόλουθο σύνδεσμο για να επανεκδόσετε τον κωδικό: {link}",
- "New password" : "Νέο συνθηματικό",
- "New Password" : "Νέος Κωδικός",
- "Reset password" : "Επαναφορά συνθηματικού",
"Searching other places" : "Έρευνα σε άλλα σημεία.",
"No search results in other folders" : "Δεν υπάρχουν αποτελέσματα αναζήτησης σε άλλους φακέλους",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} αποτέλεσμα αναζήτησης σε άλλο φάκελο","{count} αποτελέσματα αναζήτησης σε άλλους φακέλους"],
@@ -262,6 +249,10 @@
"Wrong password. Reset it?" : "Λάθος Κωδικός. Επαναφορά;",
"Stay logged in" : "Μείνετε συνδεδεμένος",
"Alternative Logins" : "Εναλλακτικές Συνδέσεις",
+ "Use the following link to reset your password: {link}" : "Χρησιμοποιήστε τον ακόλουθο σύνδεσμο για να επανεκδόσετε τον κωδικό: {link}",
+ "New password" : "Νέο συνθηματικό",
+ "New Password" : "Νέος Κωδικός",
+ "Reset password" : "Επαναφορά συνθηματικού",
"This ownCloud instance is currently in single user mode." : "Αυτή η εγκατάσταση ownCloud είναι τώρα σε κατάσταση ενός χρήστη.",
"This means only administrators can use the instance." : "Αυτό σημαίνει ότι μόνο διαχειριστές μπορούν να χρησιμοποιήσουν την εγκατάσταση.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Επικοινωνήστε με το διαχειριστή του συστήματος αν αυτό το μήνυμα συνεχίζει να εμφανίζεται ή εμφανίστηκε απρόσμενα.",
diff --git a/core/l10n/en_GB.js b/core/l10n/en_GB.js
index e8c85405d16..b7e897f8fef 100644
--- a/core/l10n/en_GB.js
+++ b/core/l10n/en_GB.js
@@ -18,6 +18,10 @@ OC.L10N.register(
"No crop data provided" : "No crop data provided",
"No valid crop data provided" : "No valid crop data provided",
"Crop is not square" : "Crop is not square",
+ "Couldn't reset password because the token is invalid" : "Couldn't reset password because the token is invalid",
+ "Couldn't send reset email. Please make sure your username is correct." : "Couldn't send reset email. Please make sure your username is correct.",
+ "%s password reset" : "%s password reset",
+ "Couldn't send reset email. Please contact your administrator." : "Couldn't send reset email. Please contact your administrator.",
"Sunday" : "Sunday",
"Monday" : "Monday",
"Tuesday" : "Tuesday",
@@ -59,7 +63,6 @@ OC.L10N.register(
"Settings" : "Settings",
"Saving..." : "Saving...",
"seconds ago" : "seconds ago",
- "Couldn't send reset email. Please contact your administrator." : "Couldn't send reset email. Please contact your administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?",
"I know what I'm doing" : "I know what I'm doing",
@@ -90,8 +93,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Your web server is not yet set up properly to allow file synchronisation because the WebDAV interface seems to be broken.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest enabling the Internet connection for this server.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>.",
"Error occurred while checking server setup" : "Error occurred whilst checking server setup",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting.",
"Shared" : "Shared",
@@ -99,7 +100,6 @@ OC.L10N.register(
"Error" : "Error",
"Error while sharing" : "Error whilst sharing",
"Error while unsharing" : "Error whilst unsharing",
- "Error while changing permissions" : "Error whilst changing permissions",
"Error setting expiration date" : "Error setting expiration date",
"The public link will expire no later than {days} days after it is created" : "The public link will expire no later than {days} days after it is created",
"Set expiration date" : "Set expiration date",
@@ -118,7 +118,6 @@ OC.L10N.register(
"Send" : "Send",
"Shared with you and the group {group} by {owner}" : "Shared with you and the group {group} by {owner}",
"Shared with you by {owner}" : "Shared with you by {owner}",
- "Shared in {item} with {user}" : "Shared in {item} with {user}",
"group" : "group",
"remote" : "remote",
"notify by email" : "notify by email",
@@ -135,9 +134,10 @@ OC.L10N.register(
"Share with users or groups …" : "Share with users or groups …",
"Share with users, groups or remote users …" : "Share with users, groups or remote users …",
"Warning" : "Warning",
+ "Delete" : "Delete",
+ "Rename" : "Rename",
"The object type is not specified." : "The object type is not specified.",
"Enter new" : "Enter new",
- "Delete" : "Delete",
"Add" : "Add",
"Edit tags" : "Edit tags",
"Error loading dialog template: {error}" : "Error loading dialog template: {error}",
@@ -153,14 +153,6 @@ OC.L10N.register(
"Please reload the page." : "Please reload the page.",
"The update was unsuccessful. " : "The update was unsuccessful. ",
"The update was successful. Redirecting you to ownCloud now." : "The update was successful. Redirecting you to ownCloud now.",
- "Couldn't reset password because the token is invalid" : "Couldn't reset password because the token is invalid",
- "Couldn't send reset email. Please make sure your username is correct." : "Couldn't send reset email. Please make sure your username is correct.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Couldn't send reset email because there is no email address for this username. Please contact your administrator.",
- "%s password reset" : "%s password reset",
- "Use the following link to reset your password: {link}" : "Use the following link to reset your password: {link}",
- "New password" : "New password",
- "New Password" : "New Password",
- "Reset password" : "Reset password",
"Searching other places" : "Searching other places",
"Personal" : "Personal",
"Users" : "Users",
@@ -228,6 +220,10 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Please try again or contact your administrator.",
"Log in" : "Log in",
"Alternative Logins" : "Alternative Logins",
+ "Use the following link to reset your password: {link}" : "Use the following link to reset your password: {link}",
+ "New password" : "New password",
+ "New Password" : "New Password",
+ "Reset password" : "Reset password",
"This ownCloud instance is currently in single user mode." : "This ownCloud instance is currently in single user mode.",
"This means only administrators can use the instance." : "This means only administrators can use the instance.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contact your system administrator if this message persists or appeared unexpectedly.",
diff --git a/core/l10n/en_GB.json b/core/l10n/en_GB.json
index 1a2c794895a..1ed840aa71f 100644
--- a/core/l10n/en_GB.json
+++ b/core/l10n/en_GB.json
@@ -16,6 +16,10 @@
"No crop data provided" : "No crop data provided",
"No valid crop data provided" : "No valid crop data provided",
"Crop is not square" : "Crop is not square",
+ "Couldn't reset password because the token is invalid" : "Couldn't reset password because the token is invalid",
+ "Couldn't send reset email. Please make sure your username is correct." : "Couldn't send reset email. Please make sure your username is correct.",
+ "%s password reset" : "%s password reset",
+ "Couldn't send reset email. Please contact your administrator." : "Couldn't send reset email. Please contact your administrator.",
"Sunday" : "Sunday",
"Monday" : "Monday",
"Tuesday" : "Tuesday",
@@ -57,7 +61,6 @@
"Settings" : "Settings",
"Saving..." : "Saving...",
"seconds ago" : "seconds ago",
- "Couldn't send reset email. Please contact your administrator." : "Couldn't send reset email. Please contact your administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?",
"I know what I'm doing" : "I know what I'm doing",
@@ -88,8 +91,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Your web server is not yet set up properly to allow file synchronisation because the WebDAV interface seems to be broken.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest enabling the Internet connection for this server.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>.",
"Error occurred while checking server setup" : "Error occurred whilst checking server setup",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting.",
"Shared" : "Shared",
@@ -97,7 +98,6 @@
"Error" : "Error",
"Error while sharing" : "Error whilst sharing",
"Error while unsharing" : "Error whilst unsharing",
- "Error while changing permissions" : "Error whilst changing permissions",
"Error setting expiration date" : "Error setting expiration date",
"The public link will expire no later than {days} days after it is created" : "The public link will expire no later than {days} days after it is created",
"Set expiration date" : "Set expiration date",
@@ -116,7 +116,6 @@
"Send" : "Send",
"Shared with you and the group {group} by {owner}" : "Shared with you and the group {group} by {owner}",
"Shared with you by {owner}" : "Shared with you by {owner}",
- "Shared in {item} with {user}" : "Shared in {item} with {user}",
"group" : "group",
"remote" : "remote",
"notify by email" : "notify by email",
@@ -133,9 +132,10 @@
"Share with users or groups …" : "Share with users or groups …",
"Share with users, groups or remote users …" : "Share with users, groups or remote users …",
"Warning" : "Warning",
+ "Delete" : "Delete",
+ "Rename" : "Rename",
"The object type is not specified." : "The object type is not specified.",
"Enter new" : "Enter new",
- "Delete" : "Delete",
"Add" : "Add",
"Edit tags" : "Edit tags",
"Error loading dialog template: {error}" : "Error loading dialog template: {error}",
@@ -151,14 +151,6 @@
"Please reload the page." : "Please reload the page.",
"The update was unsuccessful. " : "The update was unsuccessful. ",
"The update was successful. Redirecting you to ownCloud now." : "The update was successful. Redirecting you to ownCloud now.",
- "Couldn't reset password because the token is invalid" : "Couldn't reset password because the token is invalid",
- "Couldn't send reset email. Please make sure your username is correct." : "Couldn't send reset email. Please make sure your username is correct.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Couldn't send reset email because there is no email address for this username. Please contact your administrator.",
- "%s password reset" : "%s password reset",
- "Use the following link to reset your password: {link}" : "Use the following link to reset your password: {link}",
- "New password" : "New password",
- "New Password" : "New Password",
- "Reset password" : "Reset password",
"Searching other places" : "Searching other places",
"Personal" : "Personal",
"Users" : "Users",
@@ -226,6 +218,10 @@
"Please try again or contact your administrator." : "Please try again or contact your administrator.",
"Log in" : "Log in",
"Alternative Logins" : "Alternative Logins",
+ "Use the following link to reset your password: {link}" : "Use the following link to reset your password: {link}",
+ "New password" : "New password",
+ "New Password" : "New Password",
+ "Reset password" : "Reset password",
"This ownCloud instance is currently in single user mode." : "This ownCloud instance is currently in single user mode.",
"This means only administrators can use the instance." : "This means only administrators can use the instance.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contact your system administrator if this message persists or appeared unexpectedly.",
diff --git a/core/l10n/eo.js b/core/l10n/eo.js
index 87d049b88e4..0580060804d 100644
--- a/core/l10n/eo.js
+++ b/core/l10n/eo.js
@@ -66,7 +66,6 @@ OC.L10N.register(
"Error" : "Eraro",
"Error while sharing" : "Eraro dum kunhavigo",
"Error while unsharing" : "Eraro dum malkunhavigo",
- "Error while changing permissions" : "Eraro dum ŝanĝo de permesoj",
"Error setting expiration date" : "Eraro dum agordado de limdato",
"Set expiration date" : "Agordi limdaton",
"Expiration" : "Eksvalidiĝo",
@@ -81,7 +80,6 @@ OC.L10N.register(
"Send" : "Sendi",
"Shared with you and the group {group} by {owner}" : "Kunhavigita kun vi kaj la grupo {group} de {owner}",
"Shared with you by {owner}" : "Kunhavigita kun vi de {owner}",
- "Shared in {item} with {user}" : "Kunhavigita en {item} kun {user}",
"group" : "grupo",
"notify by email" : "avizi per retpoŝto",
"Unshare" : "Malkunhavigi",
@@ -92,17 +90,15 @@ OC.L10N.register(
"access control" : "alirkontrolo",
"Share" : "Kunhavigi",
"Warning" : "Averto",
+ "Delete" : "Forigi",
+ "Rename" : "Alinomigi",
"The object type is not specified." : "Ne indikiĝis tipo de la objekto.",
"Enter new" : "Enigu novan",
- "Delete" : "Forigi",
"Add" : "Aldoni",
"Edit tags" : "Redakti etikedojn",
"No tags selected for deletion." : "Neniu etikedo elektitas por forigo.",
"Please reload the page." : "Bonvolu reŝargi la paĝon.",
"The update was successful. Redirecting you to ownCloud now." : "La ĝisdatigo estis sukcesa. Alidirektante nun al ownCloud.",
- "Use the following link to reset your password: {link}" : "Uzu la jenan ligilon por restarigi vian pasvorton: {link}",
- "New password" : "Nova pasvorto",
- "Reset password" : "Rekomenci la pasvorton",
"Personal" : "Persona",
"Users" : "Uzantoj",
"Apps" : "Aplikaĵoj",
@@ -130,6 +126,9 @@ OC.L10N.register(
"Please contact your administrator." : "Bonvolu kontakti vian administranton.",
"Log in" : "Ensaluti",
"Alternative Logins" : "Alternativaj ensalutoj",
+ "Use the following link to reset your password: {link}" : "Uzu la jenan ligilon por restarigi vian pasvorton: {link}",
+ "New password" : "Nova pasvorto",
+ "Reset password" : "Rekomenci la pasvorton",
"Thank you for your patience." : "Dankon pro via pacienco."
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/eo.json b/core/l10n/eo.json
index cc5b680d580..df32f15060a 100644
--- a/core/l10n/eo.json
+++ b/core/l10n/eo.json
@@ -64,7 +64,6 @@
"Error" : "Eraro",
"Error while sharing" : "Eraro dum kunhavigo",
"Error while unsharing" : "Eraro dum malkunhavigo",
- "Error while changing permissions" : "Eraro dum ŝanĝo de permesoj",
"Error setting expiration date" : "Eraro dum agordado de limdato",
"Set expiration date" : "Agordi limdaton",
"Expiration" : "Eksvalidiĝo",
@@ -79,7 +78,6 @@
"Send" : "Sendi",
"Shared with you and the group {group} by {owner}" : "Kunhavigita kun vi kaj la grupo {group} de {owner}",
"Shared with you by {owner}" : "Kunhavigita kun vi de {owner}",
- "Shared in {item} with {user}" : "Kunhavigita en {item} kun {user}",
"group" : "grupo",
"notify by email" : "avizi per retpoŝto",
"Unshare" : "Malkunhavigi",
@@ -90,17 +88,15 @@
"access control" : "alirkontrolo",
"Share" : "Kunhavigi",
"Warning" : "Averto",
+ "Delete" : "Forigi",
+ "Rename" : "Alinomigi",
"The object type is not specified." : "Ne indikiĝis tipo de la objekto.",
"Enter new" : "Enigu novan",
- "Delete" : "Forigi",
"Add" : "Aldoni",
"Edit tags" : "Redakti etikedojn",
"No tags selected for deletion." : "Neniu etikedo elektitas por forigo.",
"Please reload the page." : "Bonvolu reŝargi la paĝon.",
"The update was successful. Redirecting you to ownCloud now." : "La ĝisdatigo estis sukcesa. Alidirektante nun al ownCloud.",
- "Use the following link to reset your password: {link}" : "Uzu la jenan ligilon por restarigi vian pasvorton: {link}",
- "New password" : "Nova pasvorto",
- "Reset password" : "Rekomenci la pasvorton",
"Personal" : "Persona",
"Users" : "Uzantoj",
"Apps" : "Aplikaĵoj",
@@ -128,6 +124,9 @@
"Please contact your administrator." : "Bonvolu kontakti vian administranton.",
"Log in" : "Ensaluti",
"Alternative Logins" : "Alternativaj ensalutoj",
+ "Use the following link to reset your password: {link}" : "Uzu la jenan ligilon por restarigi vian pasvorton: {link}",
+ "New password" : "Nova pasvorto",
+ "Reset password" : "Rekomenci la pasvorton",
"Thank you for your patience." : "Dankon pro via pacienco."
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/es.js b/core/l10n/es.js
index 316f938798d..30cdf6e4547 100644
--- a/core/l10n/es.js
+++ b/core/l10n/es.js
@@ -8,15 +8,23 @@ OC.L10N.register(
"Maintenance mode is kept active" : "El modo mantenimiento aún está activo.",
"Updating database schema" : "Actualizando el esquema del base de datos",
"Updated database" : "Base de datos actualizada",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "Comprobar si se puede actualizar el esquema de la base de datos (esto puede tardar bastante tiempo, dependiendo del tamaño de la base de datos)",
"Checked database schema update" : "Actualización del esquema de base de datos revisado",
+ "Checking updates of apps" : "Comprobar actualizaciones de apps",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "Comprobar si se puede actualizar el esquema de la base de datos %s (esto puede tardar bastante tiempo, dependiendo del tamaño de la base de datos)",
"Checked database schema update for apps" : "Comprobada la actualización del esquema de la base de datos para aplicaciones",
"Updated \"%s\" to %s" : "Se ha actualizado \"%s\" a %s",
"Repair warning: " : "Advertencia de reparación:",
"Repair error: " : "Error que reparar:",
- "Set log level to debug - current level: \"%s\"" : "Establecer nivel de registro para depurar - nivel actual: \"%s\"",
- "Reset log level to \"%s\"" : "Restablecer nivel de registro a \"%s\"",
+ "Set log level to debug" : "Establecer el nivel de registro a depuración",
+ "Reset log level" : "Restablecer el nivel de registro",
+ "Starting code integrity check" : "Comenzando comprobación de integridad de código",
+ "Finished code integrity check" : "Terminando comprobación de integridad de código",
+ "%s (3rdparty)" : "%s (tercer parte)",
+ "%s (incompatible)" : "%s (incompatible)",
"Following apps have been disabled: %s" : "Siguiendo aplicaciones ha sido deshabilitado: %s",
"Already up to date" : "Ya actualizado",
+ "Please select a file." : "Por favor, seleccione un archivo",
"File is too big" : "El archivo es demasiado grande",
"Invalid file provided" : "Archivo inválido",
"No image or file provided" : "No se especificó ningún archivo o imagen",
@@ -27,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "No se proporcionó datos del recorte",
"No valid crop data provided" : "Recorte inválido",
"Crop is not square" : "El recorte no es cuadrado",
+ "Couldn't reset password because the token is invalid" : "No se puede restablecer la contraseña porque el vale de identificación es inválido.",
+ "Couldn't reset password because the token is expired" : "No se puede restablecer la contraseña porque el vale de identificación ha caducado.",
+ "Couldn't send reset email. Please make sure your username is correct." : "No se pudo enviar el correo electrónico para el restablecimiento. Por favor, asegúrese de que su nombre de usuario es el correcto.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "No se pudo enviar el correo electrónico de restablecimiento porque no hay una dirección de correo electrónico para este nombre de usuario. Póngase en contacto con un administrador.",
+ "%s password reset" : "%s restablecer contraseña",
+ "Couldn't send reset email. Please contact your administrator." : "No pudo enviarse el correo para restablecer la contraseña. Por favor, contacte con su administrador.",
"Sunday" : "Domingo",
"Monday" : "Lunes",
"Tuesday" : "Martes",
@@ -72,10 +86,10 @@ OC.L10N.register(
"Oct." : "Oct.",
"Nov." : "Nov.",
"Dec." : "Dic.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Ha habido problemas durante la comprobación de la integridad del código. Más información…</a>",
"Settings" : "Ajustes",
"Saving..." : "Guardando...",
"seconds ago" : "hace segundos",
- "Couldn't send reset email. Please contact your administrator." : "No pudo enviarse el correo para restablecer la contraseña. Por favor, contacte con su administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Se ha enviado un enlace para restablecer su contraseña a su correo electrónico. Si usted no lo recibe en un tiempo razonable, revise su carpeta de spam/chatarra/basura.<br>Si no lo encuentra, consulte a su administrador local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Sus archivos están cifrados. Si no ha activado la clave de recuperación, no habrá manera de recuperar los datos una vez su contraseña sea restablecida.<br /> Si no está seguro de lo que debe hacer, por favor contacte con su administrador antes de continuar.<br />¿Realmente desea continuar?",
"I know what I'm doing" : "Sé lo que estoy haciendo",
@@ -104,13 +118,15 @@ OC.L10N.register(
"Good password" : "Contraseña buena",
"Strong password" : "Contraseña muy buena",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Su servidor web aún no está configurado adecuadamente para permitir sincronización de archivos ya que la interfaz WebDAV parece no estar funcionando.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Su servidor web no está configurado correctamente para resolver \"{url}\". Más información puede ser encontrada en nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Este servidor no tiene una conexión a Internet. Esto significa que algunas de las características como el montaje de almacenamiento externo, las notificaciones sobre actualizaciones o instalación de aplicaciones de terceros no funcionan. Podría no funcionar el acceso a los archivos de forma remota y el envío de correos electrónicos de notificación. Sugerimos habilitar la conexión a Internet de este servidor, si quiere tener todas las funciones.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Su directorio de datos y sus archivos probablemente sean accesibles desde Internet. El archivo .htaccess no está funcionando. Le sugerimos encarecidamente que configure su servidor web de modo que el directorio de datos ya no sea accesible o que mueva el directorio de datos fuera de la raíz de documentos del servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La memoria caché no ha sido configurada. Para aumentar su performance por favor configure memcache si está disponible. Más información puede ser encontrada en nuestra <a href=\"{docLink}\">documentación</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom no es legible por PHP el mismo es altamente desalentado por razones de seguridad. Más información puede ser encontrada en nuestra <a href=\"{docLink}\">documentación</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Su versión PHP ({version}) ya no es <a href=\"{phpLink}\">respaldada por PHP</a>. Recomendamos actualizar su versión de PHP para aprovechar las actualizaciones de rendimiento y seguridad proporcionadas por PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La configuración de las cabeceras inversas del proxy son incorrectas, o está accediendo a ownCloud desde un proxy confiable. Si no está accediendo a ownCloud desde un proxy certificado y confiable, este es un problema de seguridad y puede permitirle a un hacker camuflar su dirección IP a ownCloud. Más información puede ser encontrada en nuestra <a href=\"{docLink}\">documentación</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "memcached es un sistema de cache distribuido. pero ha sido instalado por error el modulo PHP memcache.\nConsulte <a href=\"{wikiLink}\">memcached wiki acerca de ambos modulos</a>",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La memoria caché no ha sido configurada. Para aumentar su rendimiento por favor configure memcache si está disponible. Más información puede ser encontrada en nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom no es legible por PHP el mismo es altamente desalentado por razones de seguridad. Más información puede ser encontrada en nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Su versión PHP ({version}) ya no es <a target=\"_blank\" href=\"{phpLink}\">respaldada por PHP</a>. Recomendamos actualizar su versión de PHP para aprovechar las actualizaciones de rendimiento y seguridad proporcionadas por PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La configuración de las cabeceras inversas del proxy son incorrectas, o está accediendo a ownCloud desde un proxy confiable. Si no está accediendo a ownCloud desde un proxy certificado y confiable, este es un problema de seguridad y puede permitirle a un hacker camuflar su dirección IP a ownCloud. Más información puede ser encontrada en nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "memcached es un sistema de cache distribuido. pero ha sido instalado por error el modulo PHP memcache.\nConsulte <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki acerca de ambos modulos</a>",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Algunos archivos no han superado la comprobación de integridad. Para más información sobre cómo resolver este inconveniente consulte nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lista de archivos inválidos…</a> / <a href=\"{rescanEndpoint}\">Reescanear…</a>)",
"Error occurred while checking server setup" : "Ha ocurrido un error al revisar la configuración del servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "La \"{header}\" cabecera HTTP no está configurado para ser igual a \"{expected}\". Esto puede suponer un riesgo para la seguridad o la privacidad, por lo que se recomienda ajustar esta opción.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "La cabecera HTTP \"Strict-Transport-Security\" no está configurada en al menos \"{segundos}\" segundos. Para una mejor seguridad recomendamos que habilite HSTS como es descripta en nuestros <a href=\"{docUrl}\">consejos de seguridad</a>.",
@@ -120,7 +136,6 @@ OC.L10N.register(
"Error" : "Error",
"Error while sharing" : "Error al compartir",
"Error while unsharing" : "Error al dejar de compartir",
- "Error while changing permissions" : "Error al cambiar permisos",
"Error setting expiration date" : "Error estableciendo fecha de caducidad",
"The public link will expire no later than {days} days after it is created" : "El vínculo público no expirará antes de {days} desde que se creó",
"Set expiration date" : "Establecer fecha de caducidad",
@@ -139,7 +154,6 @@ OC.L10N.register(
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Compartido contigo y el grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartido contigo por {owner}",
- "Shared in {item} with {user}" : "Compartido en {item} con {user}",
"group" : "grupo",
"remote" : "remoto",
"notify by email" : "notificar por correo electrónico",
@@ -158,9 +172,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Comparte con usuarios, grupos o usuarios remotos...",
"Warning" : "Precaución",
"Error while sending notification" : "Error mientras se enviaba la notificación",
+ "Delete" : "Eliminar",
+ "Rename" : "Renombrar",
"The object type is not specified." : "El tipo de objeto no está especificado.",
"Enter new" : "Ingresar nueva",
- "Delete" : "Eliminar",
"Add" : "Agregar",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Error al cargar plantilla de diálogo: {error}",
@@ -172,21 +187,13 @@ OC.L10N.register(
"Hello {name}" : "Hola {name}",
"_download %n file_::_download %n files_" : ["descargar %n ficheros","descargar %n archivos"],
"{version} is available. Get more information on how to update." : "Una nueva {version} está disponible. Obtenga más información sobre cómo actualizar.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "La actualización está en curso, salir de esta página podrían interrumpir el proceso en algunos entornos.",
"Updating {productName} to version {version}, this may take a while." : "Actualizando {productName} a la versión {version}. Esto puede tardar un poco.",
"An error occurred." : "Ocurrió un error.",
"Please reload the page." : "Recargue/Actualice la página",
"The update was unsuccessful. " : "La actualización ha fallado.",
"The update was successful. There were warnings." : "La actualización fue exitosa. Había advertencias.",
"The update was successful. Redirecting you to ownCloud now." : "La actualización se ha realizado con éxito. Redireccionando a ownCloud ahora.",
- "Couldn't reset password because the token is invalid" : "No se puede restablecer la contraseña porque el vale de identificación es inválido.",
- "Couldn't reset password because the token is expired" : "No se puede restablecer la contraseña porque el vale de identificación ha caducado.",
- "Couldn't send reset email. Please make sure your username is correct." : "No se pudo enviar el correo electrónico para el restablecimiento. Por favor, asegúrese de que su nombre de usuario es el correcto.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "No se pudo enviar el correo electrónico para el restablecimiento, porque no hay una dirección de correo electrónico asociada con este nombre de usuario. Por favor, contacte a su administrador.",
- "%s password reset" : "%s restablecer contraseña",
- "Use the following link to reset your password: {link}" : "Utilice el siguiente enlace para restablecer su contraseña: {link}",
- "New password" : "Nueva contraseña",
- "New Password" : "Contraseña nueva",
- "Reset password" : "Restablecer contraseña",
"Searching other places" : "Buscando en otros lugares",
"No search results in other folders" : "Ningún resultado de búsqueda en otras carpetas",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} resultado de búsqueda en otra carpeta","{count} resultados de búsqueda en otras carpetas"],
@@ -256,13 +263,19 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Por favor reintente nuevamente o contáctese con su administrador.",
"Log in" : "Ingresar",
"Wrong password. Reset it?" : "Contraseña incorrecta. ¿Restablecerla?",
+ "Wrong password." : "Contraseña incorrecta.",
"Stay logged in" : "Permanecer autenticado",
"Alternative Logins" : "Inicios de sesión alternativos",
+ "Use the following link to reset your password: {link}" : "Utilice el siguiente enlace para restablecer su contraseña: {link}",
+ "New password" : "Nueva contraseña",
+ "New Password" : "Contraseña nueva",
+ "Reset password" : "Restablecer contraseña",
"This ownCloud instance is currently in single user mode." : "Esta instalación de ownCloud se encuentra en modo de usuario único.",
"This means only administrators can use the instance." : "Esto quiere decir que solo un administrador puede usarla.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte con su administrador de sistemas si este mensaje persiste o aparece de forma inesperada.",
"Thank you for your patience." : "Gracias por su paciencia.",
"You are accessing the server from an untrusted domain." : "Está accediendo al servidor desde un dominio inseguro.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Contacte con su administrador. Si usted es el administrador, configure \"trusted_domains\" en config/config.php. En config/config.sample.php se encuentra un ejemplo para la configuración.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Dependiendo de su configuración, como administrador, debería poder usar el botón de abajo para confiar en este dominio.",
"Add \"%s\" as trusted domain" : "Agregar \"%s\" como dominio de confianza",
"App update required" : "Es necesaria una actualización en la aplicación",
diff --git a/core/l10n/es.json b/core/l10n/es.json
index aa865fbd542..2f8395f0dd6 100644
--- a/core/l10n/es.json
+++ b/core/l10n/es.json
@@ -6,15 +6,23 @@
"Maintenance mode is kept active" : "El modo mantenimiento aún está activo.",
"Updating database schema" : "Actualizando el esquema del base de datos",
"Updated database" : "Base de datos actualizada",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "Comprobar si se puede actualizar el esquema de la base de datos (esto puede tardar bastante tiempo, dependiendo del tamaño de la base de datos)",
"Checked database schema update" : "Actualización del esquema de base de datos revisado",
+ "Checking updates of apps" : "Comprobar actualizaciones de apps",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "Comprobar si se puede actualizar el esquema de la base de datos %s (esto puede tardar bastante tiempo, dependiendo del tamaño de la base de datos)",
"Checked database schema update for apps" : "Comprobada la actualización del esquema de la base de datos para aplicaciones",
"Updated \"%s\" to %s" : "Se ha actualizado \"%s\" a %s",
"Repair warning: " : "Advertencia de reparación:",
"Repair error: " : "Error que reparar:",
- "Set log level to debug - current level: \"%s\"" : "Establecer nivel de registro para depurar - nivel actual: \"%s\"",
- "Reset log level to \"%s\"" : "Restablecer nivel de registro a \"%s\"",
+ "Set log level to debug" : "Establecer el nivel de registro a depuración",
+ "Reset log level" : "Restablecer el nivel de registro",
+ "Starting code integrity check" : "Comenzando comprobación de integridad de código",
+ "Finished code integrity check" : "Terminando comprobación de integridad de código",
+ "%s (3rdparty)" : "%s (tercer parte)",
+ "%s (incompatible)" : "%s (incompatible)",
"Following apps have been disabled: %s" : "Siguiendo aplicaciones ha sido deshabilitado: %s",
"Already up to date" : "Ya actualizado",
+ "Please select a file." : "Por favor, seleccione un archivo",
"File is too big" : "El archivo es demasiado grande",
"Invalid file provided" : "Archivo inválido",
"No image or file provided" : "No se especificó ningún archivo o imagen",
@@ -25,6 +33,12 @@
"No crop data provided" : "No se proporcionó datos del recorte",
"No valid crop data provided" : "Recorte inválido",
"Crop is not square" : "El recorte no es cuadrado",
+ "Couldn't reset password because the token is invalid" : "No se puede restablecer la contraseña porque el vale de identificación es inválido.",
+ "Couldn't reset password because the token is expired" : "No se puede restablecer la contraseña porque el vale de identificación ha caducado.",
+ "Couldn't send reset email. Please make sure your username is correct." : "No se pudo enviar el correo electrónico para el restablecimiento. Por favor, asegúrese de que su nombre de usuario es el correcto.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "No se pudo enviar el correo electrónico de restablecimiento porque no hay una dirección de correo electrónico para este nombre de usuario. Póngase en contacto con un administrador.",
+ "%s password reset" : "%s restablecer contraseña",
+ "Couldn't send reset email. Please contact your administrator." : "No pudo enviarse el correo para restablecer la contraseña. Por favor, contacte con su administrador.",
"Sunday" : "Domingo",
"Monday" : "Lunes",
"Tuesday" : "Martes",
@@ -70,10 +84,10 @@
"Oct." : "Oct.",
"Nov." : "Nov.",
"Dec." : "Dic.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Ha habido problemas durante la comprobación de la integridad del código. Más información…</a>",
"Settings" : "Ajustes",
"Saving..." : "Guardando...",
"seconds ago" : "hace segundos",
- "Couldn't send reset email. Please contact your administrator." : "No pudo enviarse el correo para restablecer la contraseña. Por favor, contacte con su administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Se ha enviado un enlace para restablecer su contraseña a su correo electrónico. Si usted no lo recibe en un tiempo razonable, revise su carpeta de spam/chatarra/basura.<br>Si no lo encuentra, consulte a su administrador local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Sus archivos están cifrados. Si no ha activado la clave de recuperación, no habrá manera de recuperar los datos una vez su contraseña sea restablecida.<br /> Si no está seguro de lo que debe hacer, por favor contacte con su administrador antes de continuar.<br />¿Realmente desea continuar?",
"I know what I'm doing" : "Sé lo que estoy haciendo",
@@ -102,13 +116,15 @@
"Good password" : "Contraseña buena",
"Strong password" : "Contraseña muy buena",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Su servidor web aún no está configurado adecuadamente para permitir sincronización de archivos ya que la interfaz WebDAV parece no estar funcionando.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Su servidor web no está configurado correctamente para resolver \"{url}\". Más información puede ser encontrada en nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Este servidor no tiene una conexión a Internet. Esto significa que algunas de las características como el montaje de almacenamiento externo, las notificaciones sobre actualizaciones o instalación de aplicaciones de terceros no funcionan. Podría no funcionar el acceso a los archivos de forma remota y el envío de correos electrónicos de notificación. Sugerimos habilitar la conexión a Internet de este servidor, si quiere tener todas las funciones.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Su directorio de datos y sus archivos probablemente sean accesibles desde Internet. El archivo .htaccess no está funcionando. Le sugerimos encarecidamente que configure su servidor web de modo que el directorio de datos ya no sea accesible o que mueva el directorio de datos fuera de la raíz de documentos del servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La memoria caché no ha sido configurada. Para aumentar su performance por favor configure memcache si está disponible. Más información puede ser encontrada en nuestra <a href=\"{docLink}\">documentación</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom no es legible por PHP el mismo es altamente desalentado por razones de seguridad. Más información puede ser encontrada en nuestra <a href=\"{docLink}\">documentación</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Su versión PHP ({version}) ya no es <a href=\"{phpLink}\">respaldada por PHP</a>. Recomendamos actualizar su versión de PHP para aprovechar las actualizaciones de rendimiento y seguridad proporcionadas por PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La configuración de las cabeceras inversas del proxy son incorrectas, o está accediendo a ownCloud desde un proxy confiable. Si no está accediendo a ownCloud desde un proxy certificado y confiable, este es un problema de seguridad y puede permitirle a un hacker camuflar su dirección IP a ownCloud. Más información puede ser encontrada en nuestra <a href=\"{docLink}\">documentación</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "memcached es un sistema de cache distribuido. pero ha sido instalado por error el modulo PHP memcache.\nConsulte <a href=\"{wikiLink}\">memcached wiki acerca de ambos modulos</a>",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La memoria caché no ha sido configurada. Para aumentar su rendimiento por favor configure memcache si está disponible. Más información puede ser encontrada en nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom no es legible por PHP el mismo es altamente desalentado por razones de seguridad. Más información puede ser encontrada en nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Su versión PHP ({version}) ya no es <a target=\"_blank\" href=\"{phpLink}\">respaldada por PHP</a>. Recomendamos actualizar su versión de PHP para aprovechar las actualizaciones de rendimiento y seguridad proporcionadas por PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La configuración de las cabeceras inversas del proxy son incorrectas, o está accediendo a ownCloud desde un proxy confiable. Si no está accediendo a ownCloud desde un proxy certificado y confiable, este es un problema de seguridad y puede permitirle a un hacker camuflar su dirección IP a ownCloud. Más información puede ser encontrada en nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "memcached es un sistema de cache distribuido. pero ha sido instalado por error el modulo PHP memcache.\nConsulte <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki acerca de ambos modulos</a>",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Algunos archivos no han superado la comprobación de integridad. Para más información sobre cómo resolver este inconveniente consulte nuestra <a target=\"_blank\" href=\"{docLink}\">documentación</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lista de archivos inválidos…</a> / <a href=\"{rescanEndpoint}\">Reescanear…</a>)",
"Error occurred while checking server setup" : "Ha ocurrido un error al revisar la configuración del servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "La \"{header}\" cabecera HTTP no está configurado para ser igual a \"{expected}\". Esto puede suponer un riesgo para la seguridad o la privacidad, por lo que se recomienda ajustar esta opción.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "La cabecera HTTP \"Strict-Transport-Security\" no está configurada en al menos \"{segundos}\" segundos. Para una mejor seguridad recomendamos que habilite HSTS como es descripta en nuestros <a href=\"{docUrl}\">consejos de seguridad</a>.",
@@ -118,7 +134,6 @@
"Error" : "Error",
"Error while sharing" : "Error al compartir",
"Error while unsharing" : "Error al dejar de compartir",
- "Error while changing permissions" : "Error al cambiar permisos",
"Error setting expiration date" : "Error estableciendo fecha de caducidad",
"The public link will expire no later than {days} days after it is created" : "El vínculo público no expirará antes de {days} desde que se creó",
"Set expiration date" : "Establecer fecha de caducidad",
@@ -137,7 +152,6 @@
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Compartido contigo y el grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartido contigo por {owner}",
- "Shared in {item} with {user}" : "Compartido en {item} con {user}",
"group" : "grupo",
"remote" : "remoto",
"notify by email" : "notificar por correo electrónico",
@@ -156,9 +170,10 @@
"Share with users, groups or remote users …" : "Comparte con usuarios, grupos o usuarios remotos...",
"Warning" : "Precaución",
"Error while sending notification" : "Error mientras se enviaba la notificación",
+ "Delete" : "Eliminar",
+ "Rename" : "Renombrar",
"The object type is not specified." : "El tipo de objeto no está especificado.",
"Enter new" : "Ingresar nueva",
- "Delete" : "Eliminar",
"Add" : "Agregar",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Error al cargar plantilla de diálogo: {error}",
@@ -170,21 +185,13 @@
"Hello {name}" : "Hola {name}",
"_download %n file_::_download %n files_" : ["descargar %n ficheros","descargar %n archivos"],
"{version} is available. Get more information on how to update." : "Una nueva {version} está disponible. Obtenga más información sobre cómo actualizar.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "La actualización está en curso, salir de esta página podrían interrumpir el proceso en algunos entornos.",
"Updating {productName} to version {version}, this may take a while." : "Actualizando {productName} a la versión {version}. Esto puede tardar un poco.",
"An error occurred." : "Ocurrió un error.",
"Please reload the page." : "Recargue/Actualice la página",
"The update was unsuccessful. " : "La actualización ha fallado.",
"The update was successful. There were warnings." : "La actualización fue exitosa. Había advertencias.",
"The update was successful. Redirecting you to ownCloud now." : "La actualización se ha realizado con éxito. Redireccionando a ownCloud ahora.",
- "Couldn't reset password because the token is invalid" : "No se puede restablecer la contraseña porque el vale de identificación es inválido.",
- "Couldn't reset password because the token is expired" : "No se puede restablecer la contraseña porque el vale de identificación ha caducado.",
- "Couldn't send reset email. Please make sure your username is correct." : "No se pudo enviar el correo electrónico para el restablecimiento. Por favor, asegúrese de que su nombre de usuario es el correcto.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "No se pudo enviar el correo electrónico para el restablecimiento, porque no hay una dirección de correo electrónico asociada con este nombre de usuario. Por favor, contacte a su administrador.",
- "%s password reset" : "%s restablecer contraseña",
- "Use the following link to reset your password: {link}" : "Utilice el siguiente enlace para restablecer su contraseña: {link}",
- "New password" : "Nueva contraseña",
- "New Password" : "Contraseña nueva",
- "Reset password" : "Restablecer contraseña",
"Searching other places" : "Buscando en otros lugares",
"No search results in other folders" : "Ningún resultado de búsqueda en otras carpetas",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} resultado de búsqueda en otra carpeta","{count} resultados de búsqueda en otras carpetas"],
@@ -254,13 +261,19 @@
"Please try again or contact your administrator." : "Por favor reintente nuevamente o contáctese con su administrador.",
"Log in" : "Ingresar",
"Wrong password. Reset it?" : "Contraseña incorrecta. ¿Restablecerla?",
+ "Wrong password." : "Contraseña incorrecta.",
"Stay logged in" : "Permanecer autenticado",
"Alternative Logins" : "Inicios de sesión alternativos",
+ "Use the following link to reset your password: {link}" : "Utilice el siguiente enlace para restablecer su contraseña: {link}",
+ "New password" : "Nueva contraseña",
+ "New Password" : "Contraseña nueva",
+ "Reset password" : "Restablecer contraseña",
"This ownCloud instance is currently in single user mode." : "Esta instalación de ownCloud se encuentra en modo de usuario único.",
"This means only administrators can use the instance." : "Esto quiere decir que solo un administrador puede usarla.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte con su administrador de sistemas si este mensaje persiste o aparece de forma inesperada.",
"Thank you for your patience." : "Gracias por su paciencia.",
"You are accessing the server from an untrusted domain." : "Está accediendo al servidor desde un dominio inseguro.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Contacte con su administrador. Si usted es el administrador, configure \"trusted_domains\" en config/config.php. En config/config.sample.php se encuentra un ejemplo para la configuración.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Dependiendo de su configuración, como administrador, debería poder usar el botón de abajo para confiar en este dominio.",
"Add \"%s\" as trusted domain" : "Agregar \"%s\" como dominio de confianza",
"App update required" : "Es necesaria una actualización en la aplicación",
diff --git a/core/l10n/es_AR.js b/core/l10n/es_AR.js
index e1fd168fbb8..d556884a095 100644
--- a/core/l10n/es_AR.js
+++ b/core/l10n/es_AR.js
@@ -10,6 +10,7 @@ OC.L10N.register(
"Invalid image" : "Imagen inválida",
"No temporary profile picture available, try again" : "No hay una imágen temporal del perfil disponible, intente de nuevo",
"No crop data provided" : "No se proveyeron datos de recorte",
+ "%s password reset" : "%s restablecer contraseña",
"Sunday" : "Domingo",
"Monday" : "Lunes",
"Tuesday" : "Martes",
@@ -76,7 +77,6 @@ OC.L10N.register(
"Error" : "Error",
"Error while sharing" : "Error al compartir",
"Error while unsharing" : "Error en al dejar de compartir",
- "Error while changing permissions" : "Error al cambiar permisos",
"Error setting expiration date" : "Error al asignar fecha de vencimiento",
"Set expiration date" : "Asignar fecha de vencimiento",
"Expiration" : "Vencimiento",
@@ -91,7 +91,6 @@ OC.L10N.register(
"Send" : "Mandar",
"Shared with you and the group {group} by {owner}" : "Compartido con vos y el grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartido con vos por {owner}",
- "Shared in {item} with {user}" : "Compartido en {item} con {user}",
"group" : "grupo",
"notify by email" : "notificar por correo",
"Unshare" : "Dejar de compartir",
@@ -102,19 +101,16 @@ OC.L10N.register(
"access control" : "control de acceso",
"Share" : "Compartir",
"Warning" : "Atención",
+ "Delete" : "Borrar",
+ "Rename" : "Cambiar nombre",
"The object type is not specified." : "El tipo de objeto no está especificado. ",
"Enter new" : "Entrar nuevo",
- "Delete" : "Borrar",
"Add" : "Agregar",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Error cargando la plantilla de dialogo: {error}",
"No tags selected for deletion." : "No se han seleccionado etiquetas para eliminar.",
"Please reload the page." : "Por favor, recargue la página.",
"The update was successful. Redirecting you to ownCloud now." : "La actualización fue exitosa. Estás siendo redirigido a ownCloud.",
- "%s password reset" : "%s restablecer contraseña",
- "Use the following link to reset your password: {link}" : "Usá este enlace para restablecer tu contraseña: {link}",
- "New password" : "Nueva contraseña:",
- "Reset password" : "Restablecer contraseña",
"Personal" : "Personal",
"Users" : "Usuarios",
"Apps" : "Apps",
@@ -150,6 +146,9 @@ OC.L10N.register(
"Please contact your administrator." : "Por favor, contacte a su administrador.",
"Log in" : "Iniciar sesión",
"Alternative Logins" : "Nombre alternativos de usuarios",
+ "Use the following link to reset your password: {link}" : "Usá este enlace para restablecer tu contraseña: {link}",
+ "New password" : "Nueva contraseña:",
+ "Reset password" : "Restablecer contraseña",
"This ownCloud instance is currently in single user mode." : "Esta instancia de ownCloud está en modo de usuario único.",
"This means only administrators can use the instance." : "Esto significa que solo administradores pueden usar esta instancia.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte su administrador de sistema si este mensaje persiste o aparece inesperadamente.",
diff --git a/core/l10n/es_AR.json b/core/l10n/es_AR.json
index 9f70252b189..cd8ee56e11b 100644
--- a/core/l10n/es_AR.json
+++ b/core/l10n/es_AR.json
@@ -8,6 +8,7 @@
"Invalid image" : "Imagen inválida",
"No temporary profile picture available, try again" : "No hay una imágen temporal del perfil disponible, intente de nuevo",
"No crop data provided" : "No se proveyeron datos de recorte",
+ "%s password reset" : "%s restablecer contraseña",
"Sunday" : "Domingo",
"Monday" : "Lunes",
"Tuesday" : "Martes",
@@ -74,7 +75,6 @@
"Error" : "Error",
"Error while sharing" : "Error al compartir",
"Error while unsharing" : "Error en al dejar de compartir",
- "Error while changing permissions" : "Error al cambiar permisos",
"Error setting expiration date" : "Error al asignar fecha de vencimiento",
"Set expiration date" : "Asignar fecha de vencimiento",
"Expiration" : "Vencimiento",
@@ -89,7 +89,6 @@
"Send" : "Mandar",
"Shared with you and the group {group} by {owner}" : "Compartido con vos y el grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartido con vos por {owner}",
- "Shared in {item} with {user}" : "Compartido en {item} con {user}",
"group" : "grupo",
"notify by email" : "notificar por correo",
"Unshare" : "Dejar de compartir",
@@ -100,19 +99,16 @@
"access control" : "control de acceso",
"Share" : "Compartir",
"Warning" : "Atención",
+ "Delete" : "Borrar",
+ "Rename" : "Cambiar nombre",
"The object type is not specified." : "El tipo de objeto no está especificado. ",
"Enter new" : "Entrar nuevo",
- "Delete" : "Borrar",
"Add" : "Agregar",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Error cargando la plantilla de dialogo: {error}",
"No tags selected for deletion." : "No se han seleccionado etiquetas para eliminar.",
"Please reload the page." : "Por favor, recargue la página.",
"The update was successful. Redirecting you to ownCloud now." : "La actualización fue exitosa. Estás siendo redirigido a ownCloud.",
- "%s password reset" : "%s restablecer contraseña",
- "Use the following link to reset your password: {link}" : "Usá este enlace para restablecer tu contraseña: {link}",
- "New password" : "Nueva contraseña:",
- "Reset password" : "Restablecer contraseña",
"Personal" : "Personal",
"Users" : "Usuarios",
"Apps" : "Apps",
@@ -148,6 +144,9 @@
"Please contact your administrator." : "Por favor, contacte a su administrador.",
"Log in" : "Iniciar sesión",
"Alternative Logins" : "Nombre alternativos de usuarios",
+ "Use the following link to reset your password: {link}" : "Usá este enlace para restablecer tu contraseña: {link}",
+ "New password" : "Nueva contraseña:",
+ "Reset password" : "Restablecer contraseña",
"This ownCloud instance is currently in single user mode." : "Esta instancia de ownCloud está en modo de usuario único.",
"This means only administrators can use the instance." : "Esto significa que solo administradores pueden usar esta instancia.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte su administrador de sistema si este mensaje persiste o aparece inesperadamente.",
diff --git a/core/l10n/es_CL.js b/core/l10n/es_CL.js
index 46e2ece071d..4171b8e73ae 100644
--- a/core/l10n/es_CL.js
+++ b/core/l10n/es_CL.js
@@ -33,9 +33,9 @@ OC.L10N.register(
"Error" : "Error",
"Error while sharing" : "Ocurrió un error mientras compartía",
"Error while unsharing" : "Ocurrió un error mientras dejaba de compartir",
- "Error while changing permissions" : "Ocurrió un error mientras se cambiaban los permisos",
"Password" : "Clave",
"Share" : "Compartir",
+ "Rename" : "Renombrar",
"The object type is not specified." : "El tipo de objeto no está especificado.",
"Personal" : "Personal",
"Users" : "Usuarios",
diff --git a/core/l10n/es_CL.json b/core/l10n/es_CL.json
index ffddc11b753..e88e2b0175e 100644
--- a/core/l10n/es_CL.json
+++ b/core/l10n/es_CL.json
@@ -31,9 +31,9 @@
"Error" : "Error",
"Error while sharing" : "Ocurrió un error mientras compartía",
"Error while unsharing" : "Ocurrió un error mientras dejaba de compartir",
- "Error while changing permissions" : "Ocurrió un error mientras se cambiaban los permisos",
"Password" : "Clave",
"Share" : "Compartir",
+ "Rename" : "Renombrar",
"The object type is not specified." : "El tipo de objeto no está especificado.",
"Personal" : "Personal",
"Users" : "Usuarios",
diff --git a/core/l10n/es_MX.js b/core/l10n/es_MX.js
index 2d56f7428fe..9c68992ffae 100644
--- a/core/l10n/es_MX.js
+++ b/core/l10n/es_MX.js
@@ -10,6 +10,7 @@ OC.L10N.register(
"Invalid image" : "Imagen inválida",
"No temporary profile picture available, try again" : "No hay disponible una imagen temporal de perfil, pruebe de nuevo",
"No crop data provided" : "No se proporcionó datos del recorte",
+ "%s password reset" : "%s restablecer contraseña",
"Sunday" : "Domingo",
"Monday" : "Lunes",
"Tuesday" : "Martes",
@@ -70,7 +71,6 @@ OC.L10N.register(
"Error" : "Error",
"Error while sharing" : "Error al compartir",
"Error while unsharing" : "Error al dejar de compartir",
- "Error while changing permissions" : "Error al cambiar permisos",
"Error setting expiration date" : "Error estableciendo fecha de caducidad",
"Set expiration date" : "Establecer fecha de caducidad",
"Expiration" : "Caducidad",
@@ -85,7 +85,6 @@ OC.L10N.register(
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Compartido contigo y el grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartido contigo por {owner}",
- "Shared in {item} with {user}" : "Compartido en {item} con {user}",
"group" : "grupo",
"notify by email" : "notificar al usuario por correo electrónico",
"Unshare" : "Dejar de compartir",
@@ -96,19 +95,16 @@ OC.L10N.register(
"access control" : "control de acceso",
"Share" : "Compartir",
"Warning" : "Precaución",
+ "Delete" : "Eliminar",
+ "Rename" : "Renombrar",
"The object type is not specified." : "El tipo de objeto no está especificado.",
"Enter new" : "Ingresar nueva",
- "Delete" : "Eliminar",
"Add" : "Agregar",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Error cargando plantilla de diálogo: {error}",
"No tags selected for deletion." : "No hay etiquetas seleccionadas para borrar.",
"Please reload the page." : "Vuelva a cargar la página.",
"The update was successful. Redirecting you to ownCloud now." : "La actualización se ha realizado con éxito. Redireccionando a ownCloud ahora.",
- "%s password reset" : "%s restablecer contraseña",
- "Use the following link to reset your password: {link}" : "Utilice el siguiente enlace para restablecer su contraseña: {link}",
- "New password" : "Nueva contraseña",
- "Reset password" : "Restablecer contraseña",
"Personal" : "Personal",
"Users" : "Usuarios",
"Apps" : "Aplicaciones",
@@ -144,6 +140,9 @@ OC.L10N.register(
"Please contact your administrator." : "Por favor, contacte con el administrador.",
"Log in" : "Entrar",
"Alternative Logins" : "Accesos Alternativos",
+ "Use the following link to reset your password: {link}" : "Utilice el siguiente enlace para restablecer su contraseña: {link}",
+ "New password" : "Nueva contraseña",
+ "Reset password" : "Restablecer contraseña",
"This ownCloud instance is currently in single user mode." : "Esta instalación de ownCloud se encuentra en modo de usuario único.",
"This means only administrators can use the instance." : "Esto quiere decir que solo un administrador puede usarla.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte con su administrador de sistemas si este mensaje persiste o aparece de forma inesperada.",
diff --git a/core/l10n/es_MX.json b/core/l10n/es_MX.json
index 94cd0efbe8a..9c7f89d95d3 100644
--- a/core/l10n/es_MX.json
+++ b/core/l10n/es_MX.json
@@ -8,6 +8,7 @@
"Invalid image" : "Imagen inválida",
"No temporary profile picture available, try again" : "No hay disponible una imagen temporal de perfil, pruebe de nuevo",
"No crop data provided" : "No se proporcionó datos del recorte",
+ "%s password reset" : "%s restablecer contraseña",
"Sunday" : "Domingo",
"Monday" : "Lunes",
"Tuesday" : "Martes",
@@ -68,7 +69,6 @@
"Error" : "Error",
"Error while sharing" : "Error al compartir",
"Error while unsharing" : "Error al dejar de compartir",
- "Error while changing permissions" : "Error al cambiar permisos",
"Error setting expiration date" : "Error estableciendo fecha de caducidad",
"Set expiration date" : "Establecer fecha de caducidad",
"Expiration" : "Caducidad",
@@ -83,7 +83,6 @@
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Compartido contigo y el grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartido contigo por {owner}",
- "Shared in {item} with {user}" : "Compartido en {item} con {user}",
"group" : "grupo",
"notify by email" : "notificar al usuario por correo electrónico",
"Unshare" : "Dejar de compartir",
@@ -94,19 +93,16 @@
"access control" : "control de acceso",
"Share" : "Compartir",
"Warning" : "Precaución",
+ "Delete" : "Eliminar",
+ "Rename" : "Renombrar",
"The object type is not specified." : "El tipo de objeto no está especificado.",
"Enter new" : "Ingresar nueva",
- "Delete" : "Eliminar",
"Add" : "Agregar",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Error cargando plantilla de diálogo: {error}",
"No tags selected for deletion." : "No hay etiquetas seleccionadas para borrar.",
"Please reload the page." : "Vuelva a cargar la página.",
"The update was successful. Redirecting you to ownCloud now." : "La actualización se ha realizado con éxito. Redireccionando a ownCloud ahora.",
- "%s password reset" : "%s restablecer contraseña",
- "Use the following link to reset your password: {link}" : "Utilice el siguiente enlace para restablecer su contraseña: {link}",
- "New password" : "Nueva contraseña",
- "Reset password" : "Restablecer contraseña",
"Personal" : "Personal",
"Users" : "Usuarios",
"Apps" : "Aplicaciones",
@@ -142,6 +138,9 @@
"Please contact your administrator." : "Por favor, contacte con el administrador.",
"Log in" : "Entrar",
"Alternative Logins" : "Accesos Alternativos",
+ "Use the following link to reset your password: {link}" : "Utilice el siguiente enlace para restablecer su contraseña: {link}",
+ "New password" : "Nueva contraseña",
+ "Reset password" : "Restablecer contraseña",
"This ownCloud instance is currently in single user mode." : "Esta instalación de ownCloud se encuentra en modo de usuario único.",
"This means only administrators can use the instance." : "Esto quiere decir que solo un administrador puede usarla.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte con su administrador de sistemas si este mensaje persiste o aparece de forma inesperada.",
diff --git a/core/l10n/et_EE.js b/core/l10n/et_EE.js
index b782b43999a..4184239fc39 100644
--- a/core/l10n/et_EE.js
+++ b/core/l10n/et_EE.js
@@ -5,12 +5,15 @@ OC.L10N.register(
"Preparing update" : "Uuendamise ettevalmistamine",
"Turned on maintenance mode" : "Haldusrežiimis sisse lülitatud",
"Turned off maintenance mode" : "Haldusrežiimis välja lülitatud",
+ "Maintenance mode is kept active" : "Hooldusrežiim on aktiivne",
"Updated database" : "Uuendatud andmebaas",
"Checked database schema update" : "Andmebaasi skeemi uuendus kontrollitud",
"Checked database schema update for apps" : "Andmebaasi skeemi uuendus rakendustele on kontrollitud",
"Updated \"%s\" to %s" : "Uuendatud \"%s\" -> %s",
"Repair warning: " : "Paranda hoiatus:",
"Repair error: " : "Paranda viga:",
+ "%s (3rdparty)" : "%s (3nda osapoole arendaja)",
+ "%s (incompatible)" : "%s (pole ühilduv)",
"Following apps have been disabled: %s" : "Järgnevad rakendused on välja lülitatud: %s",
"Already up to date" : "On juba ajakohane",
"File is too big" : "Fail on liiga suur",
@@ -18,9 +21,14 @@ OC.L10N.register(
"No image or file provided" : "Ühtegi pilti või faili pole pakutud",
"Unknown filetype" : "Tundmatu failitüüp",
"Invalid image" : "Vigane pilt",
+ "An error occurred. Please contact your admin." : "Tekkis tõrge. Palun võta ühendust administraatoriga.",
"No temporary profile picture available, try again" : "Ühtegi ajutist profiili pilti pole saadaval, proovi uuesti",
"No crop data provided" : "Lõikeandmeid ei leitud",
"Crop is not square" : "Lõikamine pole ruudukujuline",
+ "Couldn't reset password because the token is invalid" : "Ei saanud parooli taastada, kuna märgend on vigane",
+ "Couldn't send reset email. Please make sure your username is correct." : "Ei suutnud lähtestada e-maili. Palun veendu, et kasutajatunnus on õige.",
+ "%s password reset" : "%s parooli lähtestus",
+ "Couldn't send reset email. Please contact your administrator." : "Ei suutnud lähtestada e-maili. Palun kontakteeru süsteemihalduriga.",
"Sunday" : "Pühapäev",
"Monday" : "Esmaspäev",
"Tuesday" : "Teisipäev",
@@ -69,7 +77,6 @@ OC.L10N.register(
"Settings" : "Seaded",
"Saving..." : "Salvestamine...",
"seconds ago" : "sekundit tagasi",
- "Couldn't send reset email. Please contact your administrator." : "Ei suutnud lähtestada e-maili. Palun kontakteeru süsteemihalduriga.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Link parooli vahetuseks on saadetud Sinu e-posti aadressil.<br>Kui kiri pole saabunud mõistliku aja jooksul, siis kontrolli oma spam-/rämpskirjade katalooge<br>.Kui kirja pole ka seal, siis küsi abi süsteemihaldurilt.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Sinu failid on krüpteeritud. Kui sa pole taastamise võtit veel määranud, siis pole präast parooli taastamist mingit võimalust sinu andmeid tagasi saada. <br />Kui sa pole kindel, mida teha, siis palun väta enne jätkamist ühendust oma administaatoriga. <br />Oled sa kindel, et sa soovid jätkata?",
"I know what I'm doing" : "Ma tean mida teen",
@@ -104,7 +111,6 @@ OC.L10N.register(
"Error" : "Viga",
"Error while sharing" : "Viga jagamisel",
"Error while unsharing" : "Viga jagamise lõpetamisel",
- "Error while changing permissions" : "Viga õiguste muutmisel",
"Error setting expiration date" : "Viga aegumise kuupäeva määramisel",
"The public link will expire no later than {days} days after it is created" : "Avalik link aegub mitte hiljem kui pärast {days} päeva selle loomist",
"Set expiration date" : "Määra aegumise kuupäev",
@@ -123,7 +129,6 @@ OC.L10N.register(
"Send" : "Saada",
"Shared with you and the group {group} by {owner}" : "Jagatud sinu ja {group} grupiga {owner} poolt",
"Shared with you by {owner}" : "Sinuga jagas {owner}",
- "Shared in {item} with {user}" : "Jagatud {item} kasutajaga {user}",
"group" : "grupp",
"notify by email" : "teavita e-postiga",
"Unshare" : "Lõpeta jagamine",
@@ -138,9 +143,11 @@ OC.L10N.register(
"Share with users or groups …" : "Jaga kasutajate või gruppidega ...",
"Share with users, groups or remote users …" : "Jaga kasutajate, gruppide või eemal olevate kasutajatega ...",
"Warning" : "Hoiatus",
+ "Error while sending notification" : "Tõrge teavituse saatmisel",
+ "Delete" : "Kustuta",
+ "Rename" : "Nimeta ümber",
"The object type is not specified." : "Objekti tüüp pole määratletud.",
"Enter new" : "Sisesta uus",
- "Delete" : "Kustuta",
"Add" : "Lisa",
"Edit tags" : "Muuda silte",
"Error loading dialog template: {error}" : "Viga dialoogi malli laadimisel: {error}",
@@ -156,14 +163,6 @@ OC.L10N.register(
"Please reload the page." : "Palun laadi see uuesti.",
"The update was unsuccessful. " : "Uuendamine ebaõnnestus.",
"The update was successful. Redirecting you to ownCloud now." : "Uuendus oli edukas. Kohe suunatakse Sind ownCloudi.",
- "Couldn't reset password because the token is invalid" : "Ei saanud parooli taastada, kuna märgend on vigane",
- "Couldn't send reset email. Please make sure your username is correct." : "Ei suutnud lähtestada e-maili. Palun veendu, et kasutajatunnus on õige.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Ei suutnud lähtestada e-maili, kuna sellel kasutajal pole e-posti määratud. Palun kontakteeru süsteemihalduriga.",
- "%s password reset" : "%s parooli lähtestus",
- "Use the following link to reset your password: {link}" : "Kasuta järgnevat linki oma parooli taastamiseks: {link}",
- "New password" : "Uus parool",
- "New Password" : "Uus parool",
- "Reset password" : "Nulli parool",
"Searching other places" : "Otsi teistest kohtadest",
"Personal" : "Isiklik",
"Users" : "Kasutajad",
@@ -227,7 +226,14 @@ OC.L10N.register(
"An internal error occured." : "Tekkis sisemine tõrge.",
"Please try again or contact your administrator." : "Palun proovi uuesti või võta ühendust oma administraatoriga.",
"Log in" : "Logi sisse",
+ "Wrong password. Reset it?" : "Vale parool. Kas vajad parooli taastamist?",
+ "Wrong password." : "Vale parool.",
+ "Stay logged in" : "Püsi sisselogituna",
"Alternative Logins" : "Alternatiivsed sisselogimisviisid",
+ "Use the following link to reset your password: {link}" : "Kasuta järgnevat linki oma parooli taastamiseks: {link}",
+ "New password" : "Uus parool",
+ "New Password" : "Uus parool",
+ "Reset password" : "Nulli parool",
"This ownCloud instance is currently in single user mode." : "See ownCloud on momendil seadistatud ühe kasutaja jaoks.",
"This means only administrators can use the instance." : "See tähendab, et seda saavad kasutada ainult administraatorid.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontakteeru oma süsteemihalduriga, kui see teade püsib või on tekkinud ootamatult.",
diff --git a/core/l10n/et_EE.json b/core/l10n/et_EE.json
index c25b9f166c9..dfc0cc0525c 100644
--- a/core/l10n/et_EE.json
+++ b/core/l10n/et_EE.json
@@ -3,12 +3,15 @@
"Preparing update" : "Uuendamise ettevalmistamine",
"Turned on maintenance mode" : "Haldusrežiimis sisse lülitatud",
"Turned off maintenance mode" : "Haldusrežiimis välja lülitatud",
+ "Maintenance mode is kept active" : "Hooldusrežiim on aktiivne",
"Updated database" : "Uuendatud andmebaas",
"Checked database schema update" : "Andmebaasi skeemi uuendus kontrollitud",
"Checked database schema update for apps" : "Andmebaasi skeemi uuendus rakendustele on kontrollitud",
"Updated \"%s\" to %s" : "Uuendatud \"%s\" -> %s",
"Repair warning: " : "Paranda hoiatus:",
"Repair error: " : "Paranda viga:",
+ "%s (3rdparty)" : "%s (3nda osapoole arendaja)",
+ "%s (incompatible)" : "%s (pole ühilduv)",
"Following apps have been disabled: %s" : "Järgnevad rakendused on välja lülitatud: %s",
"Already up to date" : "On juba ajakohane",
"File is too big" : "Fail on liiga suur",
@@ -16,9 +19,14 @@
"No image or file provided" : "Ühtegi pilti või faili pole pakutud",
"Unknown filetype" : "Tundmatu failitüüp",
"Invalid image" : "Vigane pilt",
+ "An error occurred. Please contact your admin." : "Tekkis tõrge. Palun võta ühendust administraatoriga.",
"No temporary profile picture available, try again" : "Ühtegi ajutist profiili pilti pole saadaval, proovi uuesti",
"No crop data provided" : "Lõikeandmeid ei leitud",
"Crop is not square" : "Lõikamine pole ruudukujuline",
+ "Couldn't reset password because the token is invalid" : "Ei saanud parooli taastada, kuna märgend on vigane",
+ "Couldn't send reset email. Please make sure your username is correct." : "Ei suutnud lähtestada e-maili. Palun veendu, et kasutajatunnus on õige.",
+ "%s password reset" : "%s parooli lähtestus",
+ "Couldn't send reset email. Please contact your administrator." : "Ei suutnud lähtestada e-maili. Palun kontakteeru süsteemihalduriga.",
"Sunday" : "Pühapäev",
"Monday" : "Esmaspäev",
"Tuesday" : "Teisipäev",
@@ -67,7 +75,6 @@
"Settings" : "Seaded",
"Saving..." : "Salvestamine...",
"seconds ago" : "sekundit tagasi",
- "Couldn't send reset email. Please contact your administrator." : "Ei suutnud lähtestada e-maili. Palun kontakteeru süsteemihalduriga.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Link parooli vahetuseks on saadetud Sinu e-posti aadressil.<br>Kui kiri pole saabunud mõistliku aja jooksul, siis kontrolli oma spam-/rämpskirjade katalooge<br>.Kui kirja pole ka seal, siis küsi abi süsteemihaldurilt.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Sinu failid on krüpteeritud. Kui sa pole taastamise võtit veel määranud, siis pole präast parooli taastamist mingit võimalust sinu andmeid tagasi saada. <br />Kui sa pole kindel, mida teha, siis palun väta enne jätkamist ühendust oma administaatoriga. <br />Oled sa kindel, et sa soovid jätkata?",
"I know what I'm doing" : "Ma tean mida teen",
@@ -102,7 +109,6 @@
"Error" : "Viga",
"Error while sharing" : "Viga jagamisel",
"Error while unsharing" : "Viga jagamise lõpetamisel",
- "Error while changing permissions" : "Viga õiguste muutmisel",
"Error setting expiration date" : "Viga aegumise kuupäeva määramisel",
"The public link will expire no later than {days} days after it is created" : "Avalik link aegub mitte hiljem kui pärast {days} päeva selle loomist",
"Set expiration date" : "Määra aegumise kuupäev",
@@ -121,7 +127,6 @@
"Send" : "Saada",
"Shared with you and the group {group} by {owner}" : "Jagatud sinu ja {group} grupiga {owner} poolt",
"Shared with you by {owner}" : "Sinuga jagas {owner}",
- "Shared in {item} with {user}" : "Jagatud {item} kasutajaga {user}",
"group" : "grupp",
"notify by email" : "teavita e-postiga",
"Unshare" : "Lõpeta jagamine",
@@ -136,9 +141,11 @@
"Share with users or groups …" : "Jaga kasutajate või gruppidega ...",
"Share with users, groups or remote users …" : "Jaga kasutajate, gruppide või eemal olevate kasutajatega ...",
"Warning" : "Hoiatus",
+ "Error while sending notification" : "Tõrge teavituse saatmisel",
+ "Delete" : "Kustuta",
+ "Rename" : "Nimeta ümber",
"The object type is not specified." : "Objekti tüüp pole määratletud.",
"Enter new" : "Sisesta uus",
- "Delete" : "Kustuta",
"Add" : "Lisa",
"Edit tags" : "Muuda silte",
"Error loading dialog template: {error}" : "Viga dialoogi malli laadimisel: {error}",
@@ -154,14 +161,6 @@
"Please reload the page." : "Palun laadi see uuesti.",
"The update was unsuccessful. " : "Uuendamine ebaõnnestus.",
"The update was successful. Redirecting you to ownCloud now." : "Uuendus oli edukas. Kohe suunatakse Sind ownCloudi.",
- "Couldn't reset password because the token is invalid" : "Ei saanud parooli taastada, kuna märgend on vigane",
- "Couldn't send reset email. Please make sure your username is correct." : "Ei suutnud lähtestada e-maili. Palun veendu, et kasutajatunnus on õige.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Ei suutnud lähtestada e-maili, kuna sellel kasutajal pole e-posti määratud. Palun kontakteeru süsteemihalduriga.",
- "%s password reset" : "%s parooli lähtestus",
- "Use the following link to reset your password: {link}" : "Kasuta järgnevat linki oma parooli taastamiseks: {link}",
- "New password" : "Uus parool",
- "New Password" : "Uus parool",
- "Reset password" : "Nulli parool",
"Searching other places" : "Otsi teistest kohtadest",
"Personal" : "Isiklik",
"Users" : "Kasutajad",
@@ -225,7 +224,14 @@
"An internal error occured." : "Tekkis sisemine tõrge.",
"Please try again or contact your administrator." : "Palun proovi uuesti või võta ühendust oma administraatoriga.",
"Log in" : "Logi sisse",
+ "Wrong password. Reset it?" : "Vale parool. Kas vajad parooli taastamist?",
+ "Wrong password." : "Vale parool.",
+ "Stay logged in" : "Püsi sisselogituna",
"Alternative Logins" : "Alternatiivsed sisselogimisviisid",
+ "Use the following link to reset your password: {link}" : "Kasuta järgnevat linki oma parooli taastamiseks: {link}",
+ "New password" : "Uus parool",
+ "New Password" : "Uus parool",
+ "Reset password" : "Nulli parool",
"This ownCloud instance is currently in single user mode." : "See ownCloud on momendil seadistatud ühe kasutaja jaoks.",
"This means only administrators can use the instance." : "See tähendab, et seda saavad kasutada ainult administraatorid.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontakteeru oma süsteemihalduriga, kui see teade püsib või on tekkinud ootamatult.",
diff --git a/core/l10n/eu.js b/core/l10n/eu.js
index d24a7cd42e2..c352fc6d091 100644
--- a/core/l10n/eu.js
+++ b/core/l10n/eu.js
@@ -13,6 +13,10 @@ OC.L10N.register(
"Invalid image" : "Baliogabeko irudia",
"No temporary profile picture available, try again" : "Ez dago behin-behineko profil irudirik, saiatu berriro",
"No crop data provided" : "Ez da ebaketarako daturik zehaztu",
+ "Couldn't reset password because the token is invalid" : "Ezin izan da pasahitza berrezarri tokena baliogabea delako",
+ "Couldn't send reset email. Please make sure your username is correct." : "Ezin izan da berrezartzeko eposta bidali. Ziurtatu zure erabiltzaile izena egokia dela.",
+ "%s password reset" : "%s pasahitza berrezarri",
+ "Couldn't send reset email. Please contact your administrator." : "Ezin da berrezartzeko eposta bidali. Mesedez jarri harremetan zure administradorearekin.",
"Sunday" : "Igandea",
"Monday" : "Astelehena",
"Tuesday" : "Asteartea",
@@ -27,6 +31,8 @@ OC.L10N.register(
"Thu." : "og.",
"Fri." : "ol.",
"Sat." : "lr.",
+ "Su" : "Ig",
+ "Sa" : "La",
"January" : "Urtarrila",
"February" : "Otsaila",
"March" : "Martxoa",
@@ -54,7 +60,6 @@ OC.L10N.register(
"Settings" : "Ezarpenak",
"Saving..." : "Gordetzen...",
"seconds ago" : "segundu",
- "Couldn't send reset email. Please contact your administrator." : "Ezin da berrezartzeko eposta bidali. Mesedez jarri harremetan zure administradorearekin.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Zure pasahitza berrezartzeko lotura zure postara bidalia izan da.<br>Ez baduzu arrazoizko denbora epe batean jasotzen begiratu zure zabor-posta karpetan.<br>Hor ere ez badago kudeatzailearekin harremanetan jarri.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Zure fitxategiak enkriptaturik daude. Ez baduzu berreskuratze gakoa gaitzen pasahitza berrabiaraztean ez da zure fitxategiak berreskuratzeko modurik egongo. <br />Zer egin ziur ez bazaude kudeatzailearekin harremanetan ipini jarraitu aurretik.<br /> Ziur zaude aurrera jarraitu nahi duzula?",
"I know what I'm doing" : "Badakit zer ari naizen egiten",
@@ -88,7 +93,6 @@ OC.L10N.register(
"Error" : "Errorea",
"Error while sharing" : "Errore bat egon da elkarbanatzean",
"Error while unsharing" : "Errore bat egon da elkarbanaketa desegitean",
- "Error while changing permissions" : "Errore bat egon da baimenak aldatzean",
"Error setting expiration date" : "Errore bat egon da muga data ezartzean",
"The public link will expire no later than {days} days after it is created" : "Esteka publikoak iraungi egingo du, askoz jota, sortu eta {days} egunetara.",
"Set expiration date" : "Ezarri muga data",
@@ -107,7 +111,6 @@ OC.L10N.register(
"Send" : "Bidali",
"Shared with you and the group {group} by {owner}" : "{owner}-k zu eta {group} taldearekin elkarbanatuta",
"Shared with you by {owner}" : "{owner}-k zurekin elkarbanatuta",
- "Shared in {item} with {user}" : "{user}ekin {item}-n elkarbanatuta",
"group" : "taldea",
"remote" : "urrunekoa",
"notify by email" : "jakinarazi eposta bidez",
@@ -120,9 +123,10 @@ OC.L10N.register(
"access control" : "sarrera kontrola",
"Share" : "Elkarbanatu",
"Warning" : "Abisua",
+ "Delete" : "Ezabatu",
+ "Rename" : "Berrizendatu",
"The object type is not specified." : "Objetu mota ez dago zehaztuta.",
"Enter new" : "Sartu berria",
- "Delete" : "Ezabatu",
"Add" : "Gehitu",
"Edit tags" : "Editatu etiketak",
"Error loading dialog template: {error}" : "Errorea elkarrizketa txantiloia kargatzean: {errorea}",
@@ -134,18 +138,12 @@ OC.L10N.register(
"Hello {name}" : "Kaixo {name}",
"_download %n file_::_download %n files_" : ["%n fitxategia jaitsi","jaitsi %n fitxategiak"],
"Updating {productName} to version {version}, this may take a while." : "Eguneratu {productName} {version} bertsiora, bere denbora behar du.",
+ "An error occurred." : "Errore bat gertatu da.",
"Please reload the page." : "Mesedez birkargatu orria.",
"The update was unsuccessful. " : "Eguneraketa ongi burutu da.",
"The update was successful. Redirecting you to ownCloud now." : "Eguneraketa ongi egin da. Orain zure ownClouderea berbideratua izango zara.",
- "Couldn't reset password because the token is invalid" : "Ezin izan da pasahitza berrezarri tokena baliogabea delako",
- "Couldn't send reset email. Please make sure your username is correct." : "Ezin izan da berrezartzeko eposta bidali. Ziurtatu zure erabiltzaile izena egokia dela.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Ezin izan da berrezartzeko eposta bidali erabiltzaile izen honetarako eposta helbiderik ez dagoelako. Mesedez harremanetan jarri kudeatzailearekin.",
- "%s password reset" : "%s pasahitza berrezarri",
- "Use the following link to reset your password: {link}" : "Eribili hurrengo lotura zure pasahitza berrezartzeko: {link}",
- "New password" : "Pasahitz berria",
- "New Password" : "Pasahitz Berria",
- "Reset password" : "Berrezarri pasahitza",
"Searching other places" : "Beste lekuak bilatzen",
+ "No search results in other folders" : "Ez da bilaketaren emaitzik lortu beste karpetatan",
"Personal" : "Pertsonala",
"Users" : "Erabiltzaileak",
"Apps" : "Aplikazioak",
@@ -177,6 +175,7 @@ OC.L10N.register(
"File: %s" : "Fitxategia: %s",
"Line: %s" : "Lerroa: %s",
"Trace" : "Arrastoa",
+ "Security warning" : "Segurtasun abisua",
"Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Zure data karpeta eta fitxategiak interneten bidez eskuragarri egon daitezke .htaccess fitxategia ez delako funtzionatzen ari.",
"For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "Zure zerbitrzaria ongi konfiguratzeko, mezedez <a href=\"%s\" target=\"_blank\">dokumentazioa</a> ikusi.",
"Create an <strong>admin account</strong>" : "Sortu <strong>kudeatzaile kontu<strong> bat",
@@ -192,6 +191,7 @@ OC.L10N.register(
"Database host" : "Datubasearen hostalaria",
"Finish setup" : "Bukatu konfigurazioa",
"Finishing …" : "Bukatzen...",
+ "Need help?" : "Laguntza behar al duzu?",
"Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Kaixo<br><br>%s-ek %s zurekin partekatu duela jakin dezazun.\nIkusi ezazu: %s",
"Log out" : "Saioa bukatu",
"Search" : "Bilatu",
@@ -199,6 +199,10 @@ OC.L10N.register(
"Please contact your administrator." : "Mesedez jarri harremetan zure administradorearekin.",
"Log in" : "Hasi saioa",
"Alternative Logins" : "Beste erabiltzaile izenak",
+ "Use the following link to reset your password: {link}" : "Eribili hurrengo lotura zure pasahitza berrezartzeko: {link}",
+ "New password" : "Pasahitz berria",
+ "New Password" : "Pasahitz Berria",
+ "Reset password" : "Berrezarri pasahitza",
"This ownCloud instance is currently in single user mode." : "ownCloud instantzia hau erabiltzaile bakar moduan dago.",
"This means only administrators can use the instance." : "Honek administradoreak bakarrik erabili dezakeela esan nahi du.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Jarri harremanetan zure sistema administratzailearekin mezu hau irauten badu edo bat-batean agertu bada.",
diff --git a/core/l10n/eu.json b/core/l10n/eu.json
index 81849897490..8bdb8e754e8 100644
--- a/core/l10n/eu.json
+++ b/core/l10n/eu.json
@@ -11,6 +11,10 @@
"Invalid image" : "Baliogabeko irudia",
"No temporary profile picture available, try again" : "Ez dago behin-behineko profil irudirik, saiatu berriro",
"No crop data provided" : "Ez da ebaketarako daturik zehaztu",
+ "Couldn't reset password because the token is invalid" : "Ezin izan da pasahitza berrezarri tokena baliogabea delako",
+ "Couldn't send reset email. Please make sure your username is correct." : "Ezin izan da berrezartzeko eposta bidali. Ziurtatu zure erabiltzaile izena egokia dela.",
+ "%s password reset" : "%s pasahitza berrezarri",
+ "Couldn't send reset email. Please contact your administrator." : "Ezin da berrezartzeko eposta bidali. Mesedez jarri harremetan zure administradorearekin.",
"Sunday" : "Igandea",
"Monday" : "Astelehena",
"Tuesday" : "Asteartea",
@@ -25,6 +29,8 @@
"Thu." : "og.",
"Fri." : "ol.",
"Sat." : "lr.",
+ "Su" : "Ig",
+ "Sa" : "La",
"January" : "Urtarrila",
"February" : "Otsaila",
"March" : "Martxoa",
@@ -52,7 +58,6 @@
"Settings" : "Ezarpenak",
"Saving..." : "Gordetzen...",
"seconds ago" : "segundu",
- "Couldn't send reset email. Please contact your administrator." : "Ezin da berrezartzeko eposta bidali. Mesedez jarri harremetan zure administradorearekin.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Zure pasahitza berrezartzeko lotura zure postara bidalia izan da.<br>Ez baduzu arrazoizko denbora epe batean jasotzen begiratu zure zabor-posta karpetan.<br>Hor ere ez badago kudeatzailearekin harremanetan jarri.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Zure fitxategiak enkriptaturik daude. Ez baduzu berreskuratze gakoa gaitzen pasahitza berrabiaraztean ez da zure fitxategiak berreskuratzeko modurik egongo. <br />Zer egin ziur ez bazaude kudeatzailearekin harremanetan ipini jarraitu aurretik.<br /> Ziur zaude aurrera jarraitu nahi duzula?",
"I know what I'm doing" : "Badakit zer ari naizen egiten",
@@ -86,7 +91,6 @@
"Error" : "Errorea",
"Error while sharing" : "Errore bat egon da elkarbanatzean",
"Error while unsharing" : "Errore bat egon da elkarbanaketa desegitean",
- "Error while changing permissions" : "Errore bat egon da baimenak aldatzean",
"Error setting expiration date" : "Errore bat egon da muga data ezartzean",
"The public link will expire no later than {days} days after it is created" : "Esteka publikoak iraungi egingo du, askoz jota, sortu eta {days} egunetara.",
"Set expiration date" : "Ezarri muga data",
@@ -105,7 +109,6 @@
"Send" : "Bidali",
"Shared with you and the group {group} by {owner}" : "{owner}-k zu eta {group} taldearekin elkarbanatuta",
"Shared with you by {owner}" : "{owner}-k zurekin elkarbanatuta",
- "Shared in {item} with {user}" : "{user}ekin {item}-n elkarbanatuta",
"group" : "taldea",
"remote" : "urrunekoa",
"notify by email" : "jakinarazi eposta bidez",
@@ -118,9 +121,10 @@
"access control" : "sarrera kontrola",
"Share" : "Elkarbanatu",
"Warning" : "Abisua",
+ "Delete" : "Ezabatu",
+ "Rename" : "Berrizendatu",
"The object type is not specified." : "Objetu mota ez dago zehaztuta.",
"Enter new" : "Sartu berria",
- "Delete" : "Ezabatu",
"Add" : "Gehitu",
"Edit tags" : "Editatu etiketak",
"Error loading dialog template: {error}" : "Errorea elkarrizketa txantiloia kargatzean: {errorea}",
@@ -132,18 +136,12 @@
"Hello {name}" : "Kaixo {name}",
"_download %n file_::_download %n files_" : ["%n fitxategia jaitsi","jaitsi %n fitxategiak"],
"Updating {productName} to version {version}, this may take a while." : "Eguneratu {productName} {version} bertsiora, bere denbora behar du.",
+ "An error occurred." : "Errore bat gertatu da.",
"Please reload the page." : "Mesedez birkargatu orria.",
"The update was unsuccessful. " : "Eguneraketa ongi burutu da.",
"The update was successful. Redirecting you to ownCloud now." : "Eguneraketa ongi egin da. Orain zure ownClouderea berbideratua izango zara.",
- "Couldn't reset password because the token is invalid" : "Ezin izan da pasahitza berrezarri tokena baliogabea delako",
- "Couldn't send reset email. Please make sure your username is correct." : "Ezin izan da berrezartzeko eposta bidali. Ziurtatu zure erabiltzaile izena egokia dela.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Ezin izan da berrezartzeko eposta bidali erabiltzaile izen honetarako eposta helbiderik ez dagoelako. Mesedez harremanetan jarri kudeatzailearekin.",
- "%s password reset" : "%s pasahitza berrezarri",
- "Use the following link to reset your password: {link}" : "Eribili hurrengo lotura zure pasahitza berrezartzeko: {link}",
- "New password" : "Pasahitz berria",
- "New Password" : "Pasahitz Berria",
- "Reset password" : "Berrezarri pasahitza",
"Searching other places" : "Beste lekuak bilatzen",
+ "No search results in other folders" : "Ez da bilaketaren emaitzik lortu beste karpetatan",
"Personal" : "Pertsonala",
"Users" : "Erabiltzaileak",
"Apps" : "Aplikazioak",
@@ -175,6 +173,7 @@
"File: %s" : "Fitxategia: %s",
"Line: %s" : "Lerroa: %s",
"Trace" : "Arrastoa",
+ "Security warning" : "Segurtasun abisua",
"Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Zure data karpeta eta fitxategiak interneten bidez eskuragarri egon daitezke .htaccess fitxategia ez delako funtzionatzen ari.",
"For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "Zure zerbitrzaria ongi konfiguratzeko, mezedez <a href=\"%s\" target=\"_blank\">dokumentazioa</a> ikusi.",
"Create an <strong>admin account</strong>" : "Sortu <strong>kudeatzaile kontu<strong> bat",
@@ -190,6 +189,7 @@
"Database host" : "Datubasearen hostalaria",
"Finish setup" : "Bukatu konfigurazioa",
"Finishing …" : "Bukatzen...",
+ "Need help?" : "Laguntza behar al duzu?",
"Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Kaixo<br><br>%s-ek %s zurekin partekatu duela jakin dezazun.\nIkusi ezazu: %s",
"Log out" : "Saioa bukatu",
"Search" : "Bilatu",
@@ -197,6 +197,10 @@
"Please contact your administrator." : "Mesedez jarri harremetan zure administradorearekin.",
"Log in" : "Hasi saioa",
"Alternative Logins" : "Beste erabiltzaile izenak",
+ "Use the following link to reset your password: {link}" : "Eribili hurrengo lotura zure pasahitza berrezartzeko: {link}",
+ "New password" : "Pasahitz berria",
+ "New Password" : "Pasahitz Berria",
+ "Reset password" : "Berrezarri pasahitza",
"This ownCloud instance is currently in single user mode." : "ownCloud instantzia hau erabiltzaile bakar moduan dago.",
"This means only administrators can use the instance." : "Honek administradoreak bakarrik erabili dezakeela esan nahi du.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Jarri harremanetan zure sistema administratzailearekin mezu hau irauten badu edo bat-batean agertu bada.",
diff --git a/core/l10n/fa.js b/core/l10n/fa.js
index 9f9fe7eb3f7..21adcff280a 100644
--- a/core/l10n/fa.js
+++ b/core/l10n/fa.js
@@ -19,6 +19,8 @@ OC.L10N.register(
"An error occurred. Please contact your admin." : "یک خطا رخ داده است. لطفا با مدیر سیستم تماس بگیرید.",
"No temporary profile picture available, try again" : "تصویر پروفایل موقت در حال حاضر در دسترس نیست ، دوباره تلاش کنید ",
"Crop is not square" : "بخش بریده شده مربع نیست",
+ "%s password reset" : "%s رمزعبور تغییر کرد",
+ "Couldn't send reset email. Please contact your administrator." : "ارسال ایمیل مجدد با مشکل مواجه شد . لطفا با مدیر سیستم تماس بگیرید .",
"Sunday" : "یکشنبه",
"Monday" : "دوشنبه",
"Tuesday" : "سه شنبه",
@@ -67,7 +69,6 @@ OC.L10N.register(
"Settings" : "تنظیمات",
"Saving..." : "در حال ذخیره سازی...",
"seconds ago" : "ثانیه‌ها پیش",
- "Couldn't send reset email. Please contact your administrator." : "ارسال ایمیل مجدد با مشکل مواجه شد . لطفا با مدیر سیستم تماس بگیرید .",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "لینک تنظیم مجدد رمز عبور به ایمیل شما ارسال شده است.<br>اگر آن رادر یک زمان مشخصی دریافت نکرده اید، لطفا هرزنامه/ پوشه های ناخواسته را بررسی کنید.<br>در صورت نبودن از مدیر خود بپرسید.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "فایل های شما رمزگذاری شده اند. اگر شما کلید بازیابی را فعال نکرده اید، پس از راه اندازی مجدد رمزعبور هیچ راهی برای بازگشت اطلاعاتتان وجود نخواهد داشت.در صورت عدم اطمینان به انجام کار، لطفا ابتدا با مدیر خود تماس بگیرید. آیا واقعا میخواهید ادامه دهید ؟",
"I know what I'm doing" : "اطلاع از انجام این کار دارم",
@@ -99,7 +100,6 @@ OC.L10N.register(
"Error" : "خطا",
"Error while sharing" : "خطا درحال به اشتراک گذاشتن",
"Error while unsharing" : "خطا درحال لغو اشتراک",
- "Error while changing permissions" : "خطا در حال تغییر مجوز",
"Error setting expiration date" : "خطا در تنظیم تاریخ انقضا",
"The public link will expire no later than {days} days after it is created" : "لینک عمومی پس از {days} روز پس از ایجاد منقضی خواهد شد",
"Set expiration date" : "تنظیم تاریخ انقضا",
@@ -118,7 +118,6 @@ OC.L10N.register(
"Send" : "ارسال",
"Shared with you and the group {group} by {owner}" : "به اشتراک گذاشته شده با شما و گروه {گروه} توسط {دارنده}",
"Shared with you by {owner}" : "به اشتراک گذاشته شده با شما توسط { دارنده}",
- "Shared in {item} with {user}" : "به اشتراک گذاشته شده در {بخش} با {کاربر}",
"group" : "گروه",
"remote" : "از راه دور",
"notify by email" : "دریافت هشدار از طریق ایمیل",
@@ -136,9 +135,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "اشتراک گذاری با کاربران، گروه‌ها یا کاربران راه دور...",
"Warning" : "اخطار",
"Error while sending notification" : "خطا در حین ارسال نوتیفیکیشن",
+ "Delete" : "حذف",
+ "Rename" : "تغییرنام",
"The object type is not specified." : "نوع شی تعیین نشده است.",
"Enter new" : "مورد جدید را وارد کنید",
- "Delete" : "حذف",
"Add" : "افزودن",
"Edit tags" : "ویرایش تگ ها",
"No tags selected for deletion." : "هیچ تگی برای حذف انتخاب نشده است.",
@@ -154,11 +154,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "بروزرسانی ناموفق بود.",
"The update was successful. There were warnings." : "بروزرسانی با موفقیت انجام شد، اخطارهایی وجود دارد.",
"The update was successful. Redirecting you to ownCloud now." : "به روزرسانی موفقیت آمیز بود. در حال انتقال شما به OwnCloud.",
- "%s password reset" : "%s رمزعبور تغییر کرد",
- "Use the following link to reset your password: {link}" : "از لینک زیر جهت دوباره سازی پسورد استفاده کنید :\n{link}",
- "New password" : "گذرواژه جدید",
- "New Password" : "رمزعبور جدید",
- "Reset password" : "تنظیم مجدد رمز عبور",
"Searching other places" : "جستجو در مکان‌های دیگر",
"Personal" : "شخصی",
"Users" : "کاربران",
@@ -216,6 +211,10 @@ OC.L10N.register(
"Please try again or contact your administrator." : "لطفا مجددا تلاش کنید یا با مدیر سیستم تماس بگیرید.",
"Log in" : "ورود",
"Alternative Logins" : "ورود متناوب",
+ "Use the following link to reset your password: {link}" : "از لینک زیر جهت دوباره سازی پسورد استفاده کنید :\n{link}",
+ "New password" : "گذرواژه جدید",
+ "New Password" : "رمزعبور جدید",
+ "Reset password" : "تنظیم مجدد رمز عبور",
"Thank you for your patience." : "از صبر شما متشکریم",
"Add \"%s\" as trusted domain" : "افزودن \"%s\" به عنوان دامنه مورد اعتماد",
"App update required" : "نیاز به بروزرسانی برنامه وجود دارد",
diff --git a/core/l10n/fa.json b/core/l10n/fa.json
index 383c0ec1ef3..ddfab9455b6 100644
--- a/core/l10n/fa.json
+++ b/core/l10n/fa.json
@@ -17,6 +17,8 @@
"An error occurred. Please contact your admin." : "یک خطا رخ داده است. لطفا با مدیر سیستم تماس بگیرید.",
"No temporary profile picture available, try again" : "تصویر پروفایل موقت در حال حاضر در دسترس نیست ، دوباره تلاش کنید ",
"Crop is not square" : "بخش بریده شده مربع نیست",
+ "%s password reset" : "%s رمزعبور تغییر کرد",
+ "Couldn't send reset email. Please contact your administrator." : "ارسال ایمیل مجدد با مشکل مواجه شد . لطفا با مدیر سیستم تماس بگیرید .",
"Sunday" : "یکشنبه",
"Monday" : "دوشنبه",
"Tuesday" : "سه شنبه",
@@ -65,7 +67,6 @@
"Settings" : "تنظیمات",
"Saving..." : "در حال ذخیره سازی...",
"seconds ago" : "ثانیه‌ها پیش",
- "Couldn't send reset email. Please contact your administrator." : "ارسال ایمیل مجدد با مشکل مواجه شد . لطفا با مدیر سیستم تماس بگیرید .",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "لینک تنظیم مجدد رمز عبور به ایمیل شما ارسال شده است.<br>اگر آن رادر یک زمان مشخصی دریافت نکرده اید، لطفا هرزنامه/ پوشه های ناخواسته را بررسی کنید.<br>در صورت نبودن از مدیر خود بپرسید.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "فایل های شما رمزگذاری شده اند. اگر شما کلید بازیابی را فعال نکرده اید، پس از راه اندازی مجدد رمزعبور هیچ راهی برای بازگشت اطلاعاتتان وجود نخواهد داشت.در صورت عدم اطمینان به انجام کار، لطفا ابتدا با مدیر خود تماس بگیرید. آیا واقعا میخواهید ادامه دهید ؟",
"I know what I'm doing" : "اطلاع از انجام این کار دارم",
@@ -97,7 +98,6 @@
"Error" : "خطا",
"Error while sharing" : "خطا درحال به اشتراک گذاشتن",
"Error while unsharing" : "خطا درحال لغو اشتراک",
- "Error while changing permissions" : "خطا در حال تغییر مجوز",
"Error setting expiration date" : "خطا در تنظیم تاریخ انقضا",
"The public link will expire no later than {days} days after it is created" : "لینک عمومی پس از {days} روز پس از ایجاد منقضی خواهد شد",
"Set expiration date" : "تنظیم تاریخ انقضا",
@@ -116,7 +116,6 @@
"Send" : "ارسال",
"Shared with you and the group {group} by {owner}" : "به اشتراک گذاشته شده با شما و گروه {گروه} توسط {دارنده}",
"Shared with you by {owner}" : "به اشتراک گذاشته شده با شما توسط { دارنده}",
- "Shared in {item} with {user}" : "به اشتراک گذاشته شده در {بخش} با {کاربر}",
"group" : "گروه",
"remote" : "از راه دور",
"notify by email" : "دریافت هشدار از طریق ایمیل",
@@ -134,9 +133,10 @@
"Share with users, groups or remote users …" : "اشتراک گذاری با کاربران، گروه‌ها یا کاربران راه دور...",
"Warning" : "اخطار",
"Error while sending notification" : "خطا در حین ارسال نوتیفیکیشن",
+ "Delete" : "حذف",
+ "Rename" : "تغییرنام",
"The object type is not specified." : "نوع شی تعیین نشده است.",
"Enter new" : "مورد جدید را وارد کنید",
- "Delete" : "حذف",
"Add" : "افزودن",
"Edit tags" : "ویرایش تگ ها",
"No tags selected for deletion." : "هیچ تگی برای حذف انتخاب نشده است.",
@@ -152,11 +152,6 @@
"The update was unsuccessful. " : "بروزرسانی ناموفق بود.",
"The update was successful. There were warnings." : "بروزرسانی با موفقیت انجام شد، اخطارهایی وجود دارد.",
"The update was successful. Redirecting you to ownCloud now." : "به روزرسانی موفقیت آمیز بود. در حال انتقال شما به OwnCloud.",
- "%s password reset" : "%s رمزعبور تغییر کرد",
- "Use the following link to reset your password: {link}" : "از لینک زیر جهت دوباره سازی پسورد استفاده کنید :\n{link}",
- "New password" : "گذرواژه جدید",
- "New Password" : "رمزعبور جدید",
- "Reset password" : "تنظیم مجدد رمز عبور",
"Searching other places" : "جستجو در مکان‌های دیگر",
"Personal" : "شخصی",
"Users" : "کاربران",
@@ -214,6 +209,10 @@
"Please try again or contact your administrator." : "لطفا مجددا تلاش کنید یا با مدیر سیستم تماس بگیرید.",
"Log in" : "ورود",
"Alternative Logins" : "ورود متناوب",
+ "Use the following link to reset your password: {link}" : "از لینک زیر جهت دوباره سازی پسورد استفاده کنید :\n{link}",
+ "New password" : "گذرواژه جدید",
+ "New Password" : "رمزعبور جدید",
+ "Reset password" : "تنظیم مجدد رمز عبور",
"Thank you for your patience." : "از صبر شما متشکریم",
"Add \"%s\" as trusted domain" : "افزودن \"%s\" به عنوان دامنه مورد اعتماد",
"App update required" : "نیاز به بروزرسانی برنامه وجود دارد",
diff --git a/core/l10n/fi_FI.js b/core/l10n/fi_FI.js
index 6e4a2c438d9..12c131f8410 100644
--- a/core/l10n/fi_FI.js
+++ b/core/l10n/fi_FI.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Päivitetty \"%s\" versioon %s",
"Repair warning: " : "Korjausvaroitus:",
"Repair error: " : "Korjausvirhe:",
- "Set log level to debug - current level: \"%s\"" : "Aseta lokitasoksi vianjäljitys - nykyinen taso: \"%s\"",
- "Reset log level to \"%s\"" : "Palauta lokitasoksi \"%s\"",
+ "Set log level to debug" : "Aseta lokitustasoksi vianetsintä",
+ "Reset log level" : "Nollaa lokitustaso",
+ "Starting code integrity check" : "Aloitetaan koodin eheystarkistus",
+ "Finished code integrity check" : "Koodin eheystarkistus suoritettu",
"%s (3rdparty)" : "%s (kolmannen osapuolen)",
"%s (incompatible)" : "%s (ei yhteensopiva)",
"Following apps have been disabled: %s" : "Seuraavat sovellukset on poistettu käytöstä: %s",
"Already up to date" : "Kaikki on jo ajan tasalla",
+ "Please select a file." : "Valitse tiedosto.",
"File is too big" : "Tiedosto on liian suuri",
"Invalid file provided" : "Määritetty virheellinen tiedosto",
"No image or file provided" : "Kuvaa tai tiedostoa ei määritelty",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "Puutteellinen tieto",
"No valid crop data provided" : "Kelvollisia leikkaustietoja ei määritetty",
"Crop is not square" : "Leikkaus ei ole neliö",
+ "Couldn't reset password because the token is invalid" : "Salasanaa ei voitu palauttaa koska valtuutus on virheellinen",
+ "Couldn't reset password because the token is expired" : "Salasanan palauttaminen ei onnistunut, koska valtuutus on vanhentunut",
+ "Couldn't send reset email. Please make sure your username is correct." : "Palautussähköpostin lähettäminen ei onnistunut. Varmista, että käyttäjätunnuksesi on oikein.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Salasanan palautusiviestiä ei voitu lähettää sähköpostitse, koska tälle käyttäjätunnukselle ei ole määritetty sähköpostiosoitetta. Ota yhteys ylläpitäjään.",
+ "%s password reset" : "%s salasanan palautus",
+ "Couldn't send reset email. Please contact your administrator." : "Palautussähköpostin lähettäminen ei onnistunut. Ota yhteys ylläpitäjään.",
"Sunday" : "sunnuntai",
"Monday" : "maanantai",
"Tuesday" : "tiistai",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "Loka",
"Nov." : "Marras",
"Dec." : "Joulu",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Eheystarkistus tuotti ongelmia. Lisätietoja…</a>",
"Settings" : "Asetukset",
"Saving..." : "Tallennetaan...",
"seconds ago" : "sekuntia sitten",
- "Couldn't send reset email. Please contact your administrator." : "Palautussähköpostin lähettäminen ei onnistunut. Ota yhteys ylläpitäjään.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Linkki salasanan palauttamista varten on lähetetty sähköpostitse. Jos et saa sähköpostiviestiä kohtuullisessa ajassa, tarkista roskapostikansiot.<br>Jos et saa sähköpostiviestiä, ota yhteys paikalliseen ylläpitäjään.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Tiedostosi on salattu. Jos et ole ottanut käyttöön palautusavainta, tietojasi ei ole mahdollista palauttaa salasanan nollaamisen jälkeen.<br />Jos et ole varma mitä tehdä, ota yhteys ylläpitäjään.<br />Haluatko varmasti jatkaa?",
"I know what I'm doing" : "Tiedän mitä teen",
@@ -109,13 +118,15 @@ OC.L10N.register(
"Good password" : "Hyvä salasana",
"Strong password" : "Vahva salasana",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "HTTP-palvelinta ei ole määritetty oikein tiedostojen synkronointia varten, koska WebDAV-liittymä vaikuttaa olevan rikki.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "HTTP-palvelintasi ei ole määritetty kelvollisesti selvittämään osoitetta \"{url}\". Lisätietoja on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiosta</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Tällä palvelimella ei ole toimivaa internetyhteyttä. Sen seurauksena jotkin ominaisuudet, kuten erillinen tallennustila, ilmoitukset päivityksistä ja kolmansien osapuolten sovellusten asennus eivät toimi. Tiedostojen käyttö etänä tai ilmoitusten lähetys sähköpostitse eivät välttämättä toimi myöskään. Suosittelemme kytkemään palvelimen internetyhteyteen, jos haluat käyttää kaikkia ownCloudin ominaisuuksia.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Datahakemistosi ja tiedostosi ovat luultavasti käytettävissä suoraan internetistä. .htaccess-tiedosto ei toimi oikein. Suosittelemme määrittämään http-palvelimen asetukset siten, ettei datahakemisto ole suoraan käytettävissä internetistä, tai siirtämään datahakemiston http-palvelimen juurihakemiston ulkopuolelle.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Muistissa toimivaa cachea ei ole määritetty. Paranna suorituskykyä ottamalla memcache käyttöön. Lisätietoja on saatavilla <a href=\"{docLink}\">dokumentaatiosta</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ei ole luettavissa PHP:n toimesta. Turvallisuussyistä tämä ei ole suositeltava asetus. Lisätietoja on tarjolla <a href=\"{docLink}\">dokumentaatiossa</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Käytössäsi oleva PHP-versio ({version}) ei ole enää <a href=\"{phpLink}\">PHP:n tukema</a>. Päivitä PHP:n versio, jotta hyödyt suorituskykyyn ja tietoturvaan vaikuttavista päivityksistä.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Käänteisen välityspalvelimen otsakkaiden asetukset ovat väärin, tai vaihtoehtoisesti käytät ownCloudia luotetun välityspalvelimen kautta. Jos et käytä ownCloudia luotetun välityspalvelimen kautta, kyseessä on tietoturvaongelma, joka mahdollistaa hyökkääjän väärentää ownCloudille näkyvän IP-osoitteen. Lisätietoja on saatavilla <a href=\"{docLink}\">dokumentaatiosta</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached on määritelty hajautetuksi välimuistiksi, mutta väärä PHP-moduuli \"memcache\" on asennettuna. \\OC\\Memcache\\Memcached tukee vain \"memcached\":ia, ei \"memcache\":a. Lisätietoja <a href=\"{wikiLink}\">memcachedin wikissä molemmista moduuleista</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Välimuistia ei ole määritetty. Paranna suorituskykyä ottamalla memcache käyttöön. Lisätietoja on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiossa</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom ei ole PHP:n luettavissa, eikä tätä missään tapauksessa suositella tietoturvasyistä. Lisätietoja on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiossa</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "PHP-versiosi ({version}) ei ole enää tuettu <a target=\"_blank\" href=\"{phpLink}\"> PHP:n toimesta</a>. Suosittelemme päivittämään PHP:n version, jotta hyödyt suorituskykyparannuksista sekä tietoturvakorjauksista.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Käänteisen välityspalvelimen otsakemääritykset ovat väärin, tai olet yhteydessä ownCloudiin luotetun välityspalvelimen kautta. Jos et ole yhteydessä luotetun välityspalvelimen kautta, kyseessä on tietoturvaongelma, joka mahdollistaa hyökkääjän väärentävän ownCloudille näkyvän IP-osoitteen. Lisätietoja on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiossa</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached on määritetty hajautetuksi välimuistiksi, mutta väärä PHP-moduuli \"memcache\" on asennettu. \\OC\\Memcache\\Memcached tukee vain moduulia \"memcached\", ei moduulia \"memcache\". Lisätietoja <a target=\"_blank\" href=\"{wikiLink}\">memcachedin wikissä molemmista moduuleista</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Jotkin tiedostot eivät läpäisseet eheystarkistusta. Lisätietoja ongelman selvittämiseksi on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiossa</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Luettelo virheellisistä tiedostoista…</a> / <a href=\"{rescanEndpoint}\">Tarkista uudelleen…</a>)",
"Error occurred while checking server setup" : "Virhe palvelimen määrityksiä tarkistaessa",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP-otsaketta \"{header}\" ei ole määritetty vastaamaan arvoa \"{expected}\". Kyseessä on mahdollinen tietoturvaan tai -suojaan liittyvä riski, joten suosittelemme muuttamaan asetuksen arvoa.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP-otsaketta \"Strict-Transport-Security\" ei ole määritetty vähintään \"{seconds}\" sekuntiin. Suosittelemme HSTS:n käyttöä paremman tietoturvan vuoksi, kuten <a href=\"{docUrl}\">tietoturvavinkeissä</a> neuvotaan.",
@@ -125,7 +136,6 @@ OC.L10N.register(
"Error" : "Virhe",
"Error while sharing" : "Virhe jaettaessa",
"Error while unsharing" : "Virhe jakoa peruttaessa",
- "Error while changing permissions" : "Virhe oikeuksia muuttaessa",
"Error setting expiration date" : "Virhe päättymispäivää asettaessa",
"The public link will expire no later than {days} days after it is created" : "Julkinen linkki vanhenee {days} päivän jälkeen sen luomisesta",
"Set expiration date" : "Aseta päättymispäivä",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "Lähetä",
"Shared with you and the group {group} by {owner}" : "Jaettu sinun ja ryhmän {group} kanssa käyttäjän {owner} toimesta",
"Shared with you by {owner}" : "Jaettu kanssasi käyttäjän {owner} toimesta",
- "Shared in {item} with {user}" : "{item} on jaettu {user} kanssa",
"group" : "ryhmä",
"remote" : "etä",
"notify by email" : "ilmoita sähköpostitse",
@@ -155,17 +164,25 @@ OC.L10N.register(
"change" : "muuta",
"delete" : "poista",
"access control" : "Pääsyn hallinta",
+ "Could not unshare" : "Jakamisen lopettaminen epäonnistui",
"Share details could not be loaded for this item." : "Tämän kohteen jakamistietoja ei voitu ladata.",
"An error occured. Please try again" : "Tapahtui virhe. Yritä myöhemmin uudestaan",
"Share" : "Jaa",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Jaa toisia ownCloud-järjestelmiä käyttävien kesken käyttäen syntaksia käyttäjätunnus@esimerkki.fi/owncloud",
"Share with users or groups …" : "Jaa käyttäjien tai ryhmien kanssa…",
"Share with users, groups or remote users …" : "Jaa käyttäjien, ryhmien tai etäkäyttäjien kanssa…",
+ "Error removing share" : "Virhe jakoa poistaessa",
"Warning" : "Varoitus",
"Error while sending notification" : "Virhe ilmoitusta lähettäessä",
+ "Non-existing tag #{tag}" : "Ei olemassa oleva tunniste #{tag}",
+ "not assignable" : "ei määritettävissä",
+ "invisible" : "näkymätön",
+ "({scope})" : "({scope})",
+ "Delete" : "Poista",
+ "Rename" : "Nimeä uudelleen",
+ "Global tags" : "Yleiset tunnisteet",
"The object type is not specified." : "The object type is not specified.",
"Enter new" : "Kirjoita uusi",
- "Delete" : "Poista",
"Add" : "Lisää",
"Edit tags" : "Muokkaa tunnisteita",
"Error loading dialog template: {error}" : "Virhe ladatessa keskustelupohja: {error}",
@@ -184,15 +201,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Päivitys epäonnistui.",
"The update was successful. There were warnings." : "Päivitys onnistui, tosin ilmeni varoituksia.",
"The update was successful. Redirecting you to ownCloud now." : "Päivitys onnistui. Selain ohjautuu nyt ownCloudiisi.",
- "Couldn't reset password because the token is invalid" : "Salasanaa ei voitu palauttaa koska valtuutus on virheellinen",
- "Couldn't reset password because the token is expired" : "Salasanan nollaaminen ei onnistunut, koska valtuutus on vanhentunut",
- "Couldn't send reset email. Please make sure your username is correct." : "Palautussähköpostin lähettäminen ei onnistunut. Varmista, että käyttäjätunnuksesi on oikein.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Palautussähköpostin lähettäminen ei onnistunut, koska tälle käyttäjätunnukselle ei ole määritelty sähköpostiosoitetta. Ota yhteys ylläpitäjään.",
- "%s password reset" : "%s salasanan palautus",
- "Use the following link to reset your password: {link}" : "Voit palauttaa salasanasi seuraavassa osoitteessa: {link}",
- "New password" : "Uusi salasana",
- "New Password" : "Uusi salasana",
- "Reset password" : "Palauta salasana",
"Searching other places" : "Etsitään muista paikoista",
"No search results in other folders" : "Ei hakutuloksia muissa kansioissa",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} hakutulos muussa kansiossa","{count} hakutulosta muissa kansioissa"],
@@ -262,8 +270,13 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Yritä uudestaan tai ota yhteys ylläpitäjään.",
"Log in" : "Kirjaudu sisään",
"Wrong password. Reset it?" : "Väärä salasana. Haluatko palauttaa salasanan?",
+ "Wrong password." : "Väärä salasana.",
"Stay logged in" : "Pysy sisäänkirjautuneena",
"Alternative Logins" : "Vaihtoehtoiset kirjautumiset",
+ "Use the following link to reset your password: {link}" : "Voit palauttaa salasanasi seuraavassa osoitteessa: {link}",
+ "New password" : "Uusi salasana",
+ "New Password" : "Uusi salasana",
+ "Reset password" : "Palauta salasana",
"This ownCloud instance is currently in single user mode." : "Tämä ownCloud-asennus on parhaillaan single user -tilassa.",
"This means only administrators can use the instance." : "Se tarkoittaa, että vain ylläpitäjät voivat nyt käyttää tätä ownCloudia.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Ota yhteys järjestelmän ylläpitäjään, jos tämä viesti ilmenee uudelleen tai odottamatta.",
diff --git a/core/l10n/fi_FI.json b/core/l10n/fi_FI.json
index bf88973a83c..89944f4e153 100644
--- a/core/l10n/fi_FI.json
+++ b/core/l10n/fi_FI.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "Päivitetty \"%s\" versioon %s",
"Repair warning: " : "Korjausvaroitus:",
"Repair error: " : "Korjausvirhe:",
- "Set log level to debug - current level: \"%s\"" : "Aseta lokitasoksi vianjäljitys - nykyinen taso: \"%s\"",
- "Reset log level to \"%s\"" : "Palauta lokitasoksi \"%s\"",
+ "Set log level to debug" : "Aseta lokitustasoksi vianetsintä",
+ "Reset log level" : "Nollaa lokitustaso",
+ "Starting code integrity check" : "Aloitetaan koodin eheystarkistus",
+ "Finished code integrity check" : "Koodin eheystarkistus suoritettu",
"%s (3rdparty)" : "%s (kolmannen osapuolen)",
"%s (incompatible)" : "%s (ei yhteensopiva)",
"Following apps have been disabled: %s" : "Seuraavat sovellukset on poistettu käytöstä: %s",
"Already up to date" : "Kaikki on jo ajan tasalla",
+ "Please select a file." : "Valitse tiedosto.",
"File is too big" : "Tiedosto on liian suuri",
"Invalid file provided" : "Määritetty virheellinen tiedosto",
"No image or file provided" : "Kuvaa tai tiedostoa ei määritelty",
@@ -30,6 +33,12 @@
"No crop data provided" : "Puutteellinen tieto",
"No valid crop data provided" : "Kelvollisia leikkaustietoja ei määritetty",
"Crop is not square" : "Leikkaus ei ole neliö",
+ "Couldn't reset password because the token is invalid" : "Salasanaa ei voitu palauttaa koska valtuutus on virheellinen",
+ "Couldn't reset password because the token is expired" : "Salasanan palauttaminen ei onnistunut, koska valtuutus on vanhentunut",
+ "Couldn't send reset email. Please make sure your username is correct." : "Palautussähköpostin lähettäminen ei onnistunut. Varmista, että käyttäjätunnuksesi on oikein.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Salasanan palautusiviestiä ei voitu lähettää sähköpostitse, koska tälle käyttäjätunnukselle ei ole määritetty sähköpostiosoitetta. Ota yhteys ylläpitäjään.",
+ "%s password reset" : "%s salasanan palautus",
+ "Couldn't send reset email. Please contact your administrator." : "Palautussähköpostin lähettäminen ei onnistunut. Ota yhteys ylläpitäjään.",
"Sunday" : "sunnuntai",
"Monday" : "maanantai",
"Tuesday" : "tiistai",
@@ -75,10 +84,10 @@
"Oct." : "Loka",
"Nov." : "Marras",
"Dec." : "Joulu",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Eheystarkistus tuotti ongelmia. Lisätietoja…</a>",
"Settings" : "Asetukset",
"Saving..." : "Tallennetaan...",
"seconds ago" : "sekuntia sitten",
- "Couldn't send reset email. Please contact your administrator." : "Palautussähköpostin lähettäminen ei onnistunut. Ota yhteys ylläpitäjään.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Linkki salasanan palauttamista varten on lähetetty sähköpostitse. Jos et saa sähköpostiviestiä kohtuullisessa ajassa, tarkista roskapostikansiot.<br>Jos et saa sähköpostiviestiä, ota yhteys paikalliseen ylläpitäjään.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Tiedostosi on salattu. Jos et ole ottanut käyttöön palautusavainta, tietojasi ei ole mahdollista palauttaa salasanan nollaamisen jälkeen.<br />Jos et ole varma mitä tehdä, ota yhteys ylläpitäjään.<br />Haluatko varmasti jatkaa?",
"I know what I'm doing" : "Tiedän mitä teen",
@@ -107,13 +116,15 @@
"Good password" : "Hyvä salasana",
"Strong password" : "Vahva salasana",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "HTTP-palvelinta ei ole määritetty oikein tiedostojen synkronointia varten, koska WebDAV-liittymä vaikuttaa olevan rikki.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "HTTP-palvelintasi ei ole määritetty kelvollisesti selvittämään osoitetta \"{url}\". Lisätietoja on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiosta</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Tällä palvelimella ei ole toimivaa internetyhteyttä. Sen seurauksena jotkin ominaisuudet, kuten erillinen tallennustila, ilmoitukset päivityksistä ja kolmansien osapuolten sovellusten asennus eivät toimi. Tiedostojen käyttö etänä tai ilmoitusten lähetys sähköpostitse eivät välttämättä toimi myöskään. Suosittelemme kytkemään palvelimen internetyhteyteen, jos haluat käyttää kaikkia ownCloudin ominaisuuksia.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Datahakemistosi ja tiedostosi ovat luultavasti käytettävissä suoraan internetistä. .htaccess-tiedosto ei toimi oikein. Suosittelemme määrittämään http-palvelimen asetukset siten, ettei datahakemisto ole suoraan käytettävissä internetistä, tai siirtämään datahakemiston http-palvelimen juurihakemiston ulkopuolelle.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Muistissa toimivaa cachea ei ole määritetty. Paranna suorituskykyä ottamalla memcache käyttöön. Lisätietoja on saatavilla <a href=\"{docLink}\">dokumentaatiosta</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ei ole luettavissa PHP:n toimesta. Turvallisuussyistä tämä ei ole suositeltava asetus. Lisätietoja on tarjolla <a href=\"{docLink}\">dokumentaatiossa</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Käytössäsi oleva PHP-versio ({version}) ei ole enää <a href=\"{phpLink}\">PHP:n tukema</a>. Päivitä PHP:n versio, jotta hyödyt suorituskykyyn ja tietoturvaan vaikuttavista päivityksistä.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Käänteisen välityspalvelimen otsakkaiden asetukset ovat väärin, tai vaihtoehtoisesti käytät ownCloudia luotetun välityspalvelimen kautta. Jos et käytä ownCloudia luotetun välityspalvelimen kautta, kyseessä on tietoturvaongelma, joka mahdollistaa hyökkääjän väärentää ownCloudille näkyvän IP-osoitteen. Lisätietoja on saatavilla <a href=\"{docLink}\">dokumentaatiosta</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached on määritelty hajautetuksi välimuistiksi, mutta väärä PHP-moduuli \"memcache\" on asennettuna. \\OC\\Memcache\\Memcached tukee vain \"memcached\":ia, ei \"memcache\":a. Lisätietoja <a href=\"{wikiLink}\">memcachedin wikissä molemmista moduuleista</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Välimuistia ei ole määritetty. Paranna suorituskykyä ottamalla memcache käyttöön. Lisätietoja on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiossa</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom ei ole PHP:n luettavissa, eikä tätä missään tapauksessa suositella tietoturvasyistä. Lisätietoja on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiossa</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "PHP-versiosi ({version}) ei ole enää tuettu <a target=\"_blank\" href=\"{phpLink}\"> PHP:n toimesta</a>. Suosittelemme päivittämään PHP:n version, jotta hyödyt suorituskykyparannuksista sekä tietoturvakorjauksista.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Käänteisen välityspalvelimen otsakemääritykset ovat väärin, tai olet yhteydessä ownCloudiin luotetun välityspalvelimen kautta. Jos et ole yhteydessä luotetun välityspalvelimen kautta, kyseessä on tietoturvaongelma, joka mahdollistaa hyökkääjän väärentävän ownCloudille näkyvän IP-osoitteen. Lisätietoja on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiossa</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached on määritetty hajautetuksi välimuistiksi, mutta väärä PHP-moduuli \"memcache\" on asennettu. \\OC\\Memcache\\Memcached tukee vain moduulia \"memcached\", ei moduulia \"memcache\". Lisätietoja <a target=\"_blank\" href=\"{wikiLink}\">memcachedin wikissä molemmista moduuleista</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Jotkin tiedostot eivät läpäisseet eheystarkistusta. Lisätietoja ongelman selvittämiseksi on saatavilla <a target=\"_blank\" href=\"{docLink}\">dokumentaatiossa</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Luettelo virheellisistä tiedostoista…</a> / <a href=\"{rescanEndpoint}\">Tarkista uudelleen…</a>)",
"Error occurred while checking server setup" : "Virhe palvelimen määrityksiä tarkistaessa",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP-otsaketta \"{header}\" ei ole määritetty vastaamaan arvoa \"{expected}\". Kyseessä on mahdollinen tietoturvaan tai -suojaan liittyvä riski, joten suosittelemme muuttamaan asetuksen arvoa.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP-otsaketta \"Strict-Transport-Security\" ei ole määritetty vähintään \"{seconds}\" sekuntiin. Suosittelemme HSTS:n käyttöä paremman tietoturvan vuoksi, kuten <a href=\"{docUrl}\">tietoturvavinkeissä</a> neuvotaan.",
@@ -123,7 +134,6 @@
"Error" : "Virhe",
"Error while sharing" : "Virhe jaettaessa",
"Error while unsharing" : "Virhe jakoa peruttaessa",
- "Error while changing permissions" : "Virhe oikeuksia muuttaessa",
"Error setting expiration date" : "Virhe päättymispäivää asettaessa",
"The public link will expire no later than {days} days after it is created" : "Julkinen linkki vanhenee {days} päivän jälkeen sen luomisesta",
"Set expiration date" : "Aseta päättymispäivä",
@@ -142,7 +152,6 @@
"Send" : "Lähetä",
"Shared with you and the group {group} by {owner}" : "Jaettu sinun ja ryhmän {group} kanssa käyttäjän {owner} toimesta",
"Shared with you by {owner}" : "Jaettu kanssasi käyttäjän {owner} toimesta",
- "Shared in {item} with {user}" : "{item} on jaettu {user} kanssa",
"group" : "ryhmä",
"remote" : "etä",
"notify by email" : "ilmoita sähköpostitse",
@@ -153,17 +162,25 @@
"change" : "muuta",
"delete" : "poista",
"access control" : "Pääsyn hallinta",
+ "Could not unshare" : "Jakamisen lopettaminen epäonnistui",
"Share details could not be loaded for this item." : "Tämän kohteen jakamistietoja ei voitu ladata.",
"An error occured. Please try again" : "Tapahtui virhe. Yritä myöhemmin uudestaan",
"Share" : "Jaa",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Jaa toisia ownCloud-järjestelmiä käyttävien kesken käyttäen syntaksia käyttäjätunnus@esimerkki.fi/owncloud",
"Share with users or groups …" : "Jaa käyttäjien tai ryhmien kanssa…",
"Share with users, groups or remote users …" : "Jaa käyttäjien, ryhmien tai etäkäyttäjien kanssa…",
+ "Error removing share" : "Virhe jakoa poistaessa",
"Warning" : "Varoitus",
"Error while sending notification" : "Virhe ilmoitusta lähettäessä",
+ "Non-existing tag #{tag}" : "Ei olemassa oleva tunniste #{tag}",
+ "not assignable" : "ei määritettävissä",
+ "invisible" : "näkymätön",
+ "({scope})" : "({scope})",
+ "Delete" : "Poista",
+ "Rename" : "Nimeä uudelleen",
+ "Global tags" : "Yleiset tunnisteet",
"The object type is not specified." : "The object type is not specified.",
"Enter new" : "Kirjoita uusi",
- "Delete" : "Poista",
"Add" : "Lisää",
"Edit tags" : "Muokkaa tunnisteita",
"Error loading dialog template: {error}" : "Virhe ladatessa keskustelupohja: {error}",
@@ -182,15 +199,6 @@
"The update was unsuccessful. " : "Päivitys epäonnistui.",
"The update was successful. There were warnings." : "Päivitys onnistui, tosin ilmeni varoituksia.",
"The update was successful. Redirecting you to ownCloud now." : "Päivitys onnistui. Selain ohjautuu nyt ownCloudiisi.",
- "Couldn't reset password because the token is invalid" : "Salasanaa ei voitu palauttaa koska valtuutus on virheellinen",
- "Couldn't reset password because the token is expired" : "Salasanan nollaaminen ei onnistunut, koska valtuutus on vanhentunut",
- "Couldn't send reset email. Please make sure your username is correct." : "Palautussähköpostin lähettäminen ei onnistunut. Varmista, että käyttäjätunnuksesi on oikein.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Palautussähköpostin lähettäminen ei onnistunut, koska tälle käyttäjätunnukselle ei ole määritelty sähköpostiosoitetta. Ota yhteys ylläpitäjään.",
- "%s password reset" : "%s salasanan palautus",
- "Use the following link to reset your password: {link}" : "Voit palauttaa salasanasi seuraavassa osoitteessa: {link}",
- "New password" : "Uusi salasana",
- "New Password" : "Uusi salasana",
- "Reset password" : "Palauta salasana",
"Searching other places" : "Etsitään muista paikoista",
"No search results in other folders" : "Ei hakutuloksia muissa kansioissa",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} hakutulos muussa kansiossa","{count} hakutulosta muissa kansioissa"],
@@ -260,8 +268,13 @@
"Please try again or contact your administrator." : "Yritä uudestaan tai ota yhteys ylläpitäjään.",
"Log in" : "Kirjaudu sisään",
"Wrong password. Reset it?" : "Väärä salasana. Haluatko palauttaa salasanan?",
+ "Wrong password." : "Väärä salasana.",
"Stay logged in" : "Pysy sisäänkirjautuneena",
"Alternative Logins" : "Vaihtoehtoiset kirjautumiset",
+ "Use the following link to reset your password: {link}" : "Voit palauttaa salasanasi seuraavassa osoitteessa: {link}",
+ "New password" : "Uusi salasana",
+ "New Password" : "Uusi salasana",
+ "Reset password" : "Palauta salasana",
"This ownCloud instance is currently in single user mode." : "Tämä ownCloud-asennus on parhaillaan single user -tilassa.",
"This means only administrators can use the instance." : "Se tarkoittaa, että vain ylläpitäjät voivat nyt käyttää tätä ownCloudia.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Ota yhteys järjestelmän ylläpitäjään, jos tämä viesti ilmenee uudelleen tai odottamatta.",
diff --git a/core/l10n/fr.js b/core/l10n/fr.js
index 5a73540f141..2f1ebc3a9cb 100644
--- a/core/l10n/fr.js
+++ b/core/l10n/fr.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Mise à jour de « %s » vers %s",
"Repair warning: " : "Avertissement de réparation :",
"Repair error: " : "Erreur de réparation :",
- "Set log level to debug - current level: \"%s\"" : "Réglage du niveau de log à \"debug\" - niveau actuel: \"%s\"",
- "Reset log level to \"%s\"" : "Réglage du niveau de log à \"%s\"",
+ "Set log level to debug" : "Réglage du niveau de log à \"debug\"",
+ "Reset log level" : "Réinitialisation du niveau de journalisation",
+ "Starting code integrity check" : "Lancement de la vérification d'intégrité du code",
+ "Finished code integrity check" : "Fin de la vérification d’intégrité du code",
"%s (3rdparty)" : "%s (origine tierce)",
"%s (incompatible)" : "%s (non compatible)",
"Following apps have been disabled: %s" : "Les applications suivantes ont été désactivées : %s",
"Already up to date" : "Déjà à jour",
+ "Please select a file." : "Veuillez sélectionner un fichier.",
"File is too big" : "Fichier trop volumineux",
"Invalid file provided" : "Fichier non valide",
"No image or file provided" : "Aucun fichier fourni",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "Aucune donnée de recadrage fournie",
"No valid crop data provided" : "Données de recadrage non valides",
"Crop is not square" : "Le recadrage n'est pas carré",
+ "Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable.",
+ "Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.",
+ "%s password reset" : "Réinitialisation de votre mot de passe %s",
+ "Couldn't send reset email. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez contacter votre administrateur.",
"Sunday" : "Dimanche",
"Monday" : "Lundi",
"Tuesday" : "Mardi",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "Oct.",
"Nov." : "Nov.",
"Dec." : "Déc.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Il y a eu des problèmes à la vérification d’intégrité du code. Plus d'infos...</a>",
"Settings" : "Paramètres",
"Saving..." : "Enregistrement…",
"seconds ago" : "à l'instant",
- "Couldn't send reset email. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez contacter votre administrateur.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Un lien permettant de réinitialiser votre mot de passe vient de vous être envoyé par courriel.<br>Si vous ne le recevez pas dans un délai raisonnable, contactez votre administrateur.<br>N'oubliez pas de vérifier dans votre dossier pourriel / spam!",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vos fichiers sont chiffrés. Si vous n'avez pas activé la clef de récupération, il n'y aura aucun moyen de récupérer vos données une fois le mot de passe réinitialisé.<br />Si vous n'êtes pas sûr de ce que vous faites, veuillez contacter votre administrateur avant de continuer. <br />Voulez-vous vraiment continuer ?",
"I know what I'm doing" : "Je sais ce que je fais",
@@ -109,14 +118,16 @@ OC.L10N.register(
"Good password" : "Mot de passe de sécurité suffisante",
"Strong password" : "Mot de passe fort",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Votre serveur web n'est pas correctement configuré pour la synchronisation de fichiers : l'interface WebDAV semble ne pas fonctionner.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La configuration du serveur web ne permet pas d'atteindre \"{url}\". Consultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations à ce sujet.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Ce serveur ne peut se connecter à internet. Cela signifie que certaines fonctionnalités, telles que le montage de supports de stockage distants, les notifications de mises à jour ou l'installation d'applications tierces ne fonctionneront pas. L'accès aux fichiers à distance, ainsi que les notifications par mail peuvent aussi être indisponibles. Il est recommandé d'activer la connexion internet pour ce serveur si vous souhaitez disposer de l'ensemble des fonctionnalités offertes.",
- "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Votre dossier de données et vos fichiers sont probablement accessibles depuis internet. Le fichier .htaccess ne fonctionne pas. Nous vous recommandons vivement de configurer votre serveur web de façon à ce que ce dossier de données ne soit plus accessible, ou de le déplacer hors de la racine du serveur web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Aucun cache de la mémoire n'est configuré. Si possible, configurez un \"memcache\" pour augmenter les performances. Pour plus d'information consultez la <a href=\"{docLink}\">documentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom n'est pas lisible par PHP, ce qui est fortement déconseillé pour des raisons de sécurité. Plus d'informations peuvent être trouvées dans notre <a href=\"{docLink}\">documentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La version de PHP utilisée ({version}) <a href=\"{phpLink}\">n'est plus prise en charge par les créateurs de PHP</a>. Nous vous recommandons de mettre à niveau votre installation de PHP pour bénéficier de meilleures performances et des mises à jour de sécurité fournies par PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La configuration des headers du reverse proxy est incorrecte, ou vous accédez ownCloud depuis un proxy de confiance. Si vous n'êtes pas en train d’accéder à ownCloud depuis un proxy de confiance, ceci est un problème de sécurité qui peut permettre à un attaquant de masquer sa véritable adresse IP. <a href=\"{docLink}\">Plus d'info dans la documentation.</a>",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "\"memcached\" est configuré comme cache distribué, mais le module installé est \"memcache\". \\OC\\Memcache\\Memcached ne prend en charge que \"memcached\" et non \"memcache\". <a href=\"{wikiLink}\">Consulter le wiki memcached parlant de ces deux modules.</a>",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Aucun cache mémoire n'est configuré. Si possible, configurez un cache pour augmenter les performances. Consultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations à ce sujet.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom n'est pas lisible par PHP, ce qui est fortement déconseillé pour des raisons de sécurité. Consultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations à ce sujet.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Votre version de PHP ({version}) <a target=\"_blank\" href=\"{phpLink}\">n'est plus prise en charge par les créateurs de PHP</a>. Nous vous recommandons de mettre à niveau votre installation de PHP pour bénéficier de meilleures performances et des mises à jour de sécurité fournies par PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La configuration des entêtes du proxy inverse est incorrecte, ou vous accédez à ownCloud depuis un proxy de confiance. Si vous n'êtes pas en train d’accéder à ownCloud depuis un proxy de confiance, ceci est un problème de sécurité qui peut permettre à un attaquant de masquer sa véritable adresse IP. Consultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations à ce sujet.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "\"memcached\" est configuré comme cache distribué, mais le module installé est \"memcache\". \\OC\\Memcache\\Memcached ne prend en charge que \"memcached\" et non \"memcache\". <a target=\"_blank\" href=\"{wikiLink}\">Consulter le wiki de memcached à propos de ces deux modules.</a>",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Des fichiers n'ont pas passé la vérification d’intégrité. \nConsultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations sur comment résoudre ce problème.\n(<a target=\"_blank\" href=\"{codeIntegrityDownloadEndpoint}\">Liste des fichiers non valides…</a> / <a href=\"{rescanEndpoint}\">Relancer…</a>)",
"Error occurred while checking server setup" : "Une erreur s'est produite lors de la vérification de la configuration du serveur",
+ "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Votre dossier de données et vos fichiers sont probablement accessibles depuis internet. Le fichier .htaccess ne fonctionne pas. Nous vous recommandons vivement de configurer votre serveur web de façon à ce que ce dossier de données ne soit plus accessible, ou de le déplacer hors de la racine du serveur web.",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "L'en-tête HTTP \"{header}\" n'est pas configurée pour être égale à \"{expected}\" créant potentiellement un risque relié à la sécurité et à la vie privée. Il est donc recommandé d'ajuster ce paramètre.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "L'en-tête HTTP \"Strict-Transport-Security\" n'est pas configurée à \"{seconds}\" secondes. Pour renforcer la sécurité nous recommandons d'activer HSTS comme décrit dans notre <a href=\"{docUrl}\">Guide pour le renforcement et la sécurité</a>.",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Vous accédez à ce site via HTTP. Nous vous recommandons fortement de configurer votre serveur pour forcer l'utilisation de HTTPS, comme expliqué dans notre <a href=\"{docUrl}\">Guide pour le renforcement et la sécurité</a>.",
@@ -125,7 +136,6 @@ OC.L10N.register(
"Error" : "Erreur",
"Error while sharing" : "Erreur lors de la mise en partage",
"Error while unsharing" : "Erreur lors de l'annulation du partage",
- "Error while changing permissions" : "Erreur lors du changement des permissions",
"Error setting expiration date" : "Erreur lors de la spécification de la date d'expiration",
"The public link will expire no later than {days} days after it is created" : "Ce lien public expirera au plus tard {days} jours après sa création.",
"Set expiration date" : "Spécifier une date d'expiration",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "Envoyer",
"Shared with you and the group {group} by {owner}" : "Partagé avec vous et le groupe {group} par {owner}",
"Shared with you by {owner}" : "Partagé avec vous par {owner}",
- "Shared in {item} with {user}" : "Partagé dans {item} avec {user}",
"group" : "groupe",
"remote" : "distant",
"notify by email" : "notifier par courriel",
@@ -155,17 +164,25 @@ OC.L10N.register(
"change" : "modification",
"delete" : "suppression",
"access control" : "contrôle d'accès",
+ "Could not unshare" : "Impossible d'arrêter de partager",
"Share details could not be loaded for this item." : "Les informations de partage n'ont pu être chargées pour cet élément.",
"An error occured. Please try again" : "Une erreur est survenue. Merci de réessayer",
"Share" : "Partager",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Partagez avec des personnes sur d'autres ownClouds en utilisant la syntaxe utilisateur@exemple.com/owncloud",
"Share with users or groups …" : "Partager avec des utilisateurs ou groupes...",
"Share with users, groups or remote users …" : "Partager avec des utilisateurs, groupes, ou utilisateurs distants",
+ "Error removing share" : "Erreur lors de l'arrêt du partage",
"Warning" : "Attention",
"Error while sending notification" : "Erreur lors de l'envoi de la notification",
+ "Non-existing tag #{tag}" : "Étiquette #{tag} inexistante",
+ "not assignable" : "inassignable",
+ "invisible" : "invisible",
+ "({scope})" : "({scope})",
+ "Delete" : "Supprimer",
+ "Rename" : "Renommer",
+ "Global tags" : "Étiquettes globales",
"The object type is not specified." : "Le type d'objet n'est pas spécifié.",
"Enter new" : "Saisir un nouveau",
- "Delete" : "Supprimer",
"Add" : "Ajouter",
"Edit tags" : "Modifier les étiquettes",
"Error loading dialog template: {error}" : "Erreur lors du chargement du modèle de dialogue : {error}",
@@ -184,15 +201,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "La mise à jour a échoué.",
"The update was successful. There were warnings." : "La mise à jour a réussi, mais il y a eu des avertissements",
"The update was successful. Redirecting you to ownCloud now." : "La mise à jour a réussi. Vous êtes maintenant redirigé vers ownCloud.",
- "Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable.",
- "Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré.",
- "Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.",
- "%s password reset" : "Réinitialisation de votre mot de passe %s",
- "Use the following link to reset your password: {link}" : "Utilisez le lien suivant pour réinitialiser votre mot de passe : {link}",
- "New password" : "Nouveau mot de passe",
- "New Password" : "Nouveau mot de passe",
- "Reset password" : "Réinitialiser le mot de passe",
"Searching other places" : "Recherche en cours dans d'autres emplacements",
"No search results in other folders" : "Aucun résultat dans d'autres dossiers",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} résultat dans un autre dossier","{count} résultats dans d'autres dossiers"],
@@ -262,14 +270,19 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Veuillez réessayer ou contacter votre administrateur.",
"Log in" : "Se connecter",
"Wrong password. Reset it?" : "Mot de passe incorrect. Réinitialiser ?",
+ "Wrong password." : "Mot de passe incorrect.",
"Stay logged in" : "Rester connecté",
"Alternative Logins" : "Identifiants alternatifs",
+ "Use the following link to reset your password: {link}" : "Utilisez le lien suivant pour réinitialiser votre mot de passe : {link}",
+ "New password" : "Nouveau mot de passe",
+ "New Password" : "Nouveau mot de passe",
+ "Reset password" : "Réinitialiser le mot de passe",
"This ownCloud instance is currently in single user mode." : "Cette instance de ownCloud est actuellement en mode utilisateur unique.",
"This means only administrators can use the instance." : "Cela signifie que seuls les administrateurs peuvent utiliser l'instance.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Veuillez contacter votre administrateur système si ce message persiste ou apparaît de façon inattendue.",
"Thank you for your patience." : "Merci de votre patience.",
"You are accessing the server from an untrusted domain." : "Vous accédez au serveur à partir d'un domaine non approuvé.",
- "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Veuillez contacter votre administrateur. Si vous être l'administrateur de cette instance, il faut configurer la variable \"trusted_domains\" dans le fichier config/config.php. Un exemple de configuration est fournit dans le fichier config/config.sample.php.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Veuillez contacter votre administrateur. Si vous être l'administrateur de cette instance, configurez la variable \"trusted_domains\" dans le fichier config/config.php. Un exemple de configuration est fournit dans le fichier config/config.sample.php.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "En fonction de votre configuration, en tant qu'administrateur vous pouvez également utiliser le bouton ci-dessous pour approuver ce domaine.",
"Add \"%s\" as trusted domain" : "Ajouter \"%s\" à la liste des domaines approuvés",
"App update required" : "Mise à jour de l'application nécessaire",
diff --git a/core/l10n/fr.json b/core/l10n/fr.json
index 088381169db..df7cd0cf3c5 100644
--- a/core/l10n/fr.json
+++ b/core/l10n/fr.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "Mise à jour de « %s » vers %s",
"Repair warning: " : "Avertissement de réparation :",
"Repair error: " : "Erreur de réparation :",
- "Set log level to debug - current level: \"%s\"" : "Réglage du niveau de log à \"debug\" - niveau actuel: \"%s\"",
- "Reset log level to \"%s\"" : "Réglage du niveau de log à \"%s\"",
+ "Set log level to debug" : "Réglage du niveau de log à \"debug\"",
+ "Reset log level" : "Réinitialisation du niveau de journalisation",
+ "Starting code integrity check" : "Lancement de la vérification d'intégrité du code",
+ "Finished code integrity check" : "Fin de la vérification d’intégrité du code",
"%s (3rdparty)" : "%s (origine tierce)",
"%s (incompatible)" : "%s (non compatible)",
"Following apps have been disabled: %s" : "Les applications suivantes ont été désactivées : %s",
"Already up to date" : "Déjà à jour",
+ "Please select a file." : "Veuillez sélectionner un fichier.",
"File is too big" : "Fichier trop volumineux",
"Invalid file provided" : "Fichier non valide",
"No image or file provided" : "Aucun fichier fourni",
@@ -30,6 +33,12 @@
"No crop data provided" : "Aucune donnée de recadrage fournie",
"No valid crop data provided" : "Données de recadrage non valides",
"Crop is not square" : "Le recadrage n'est pas carré",
+ "Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable.",
+ "Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.",
+ "%s password reset" : "Réinitialisation de votre mot de passe %s",
+ "Couldn't send reset email. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez contacter votre administrateur.",
"Sunday" : "Dimanche",
"Monday" : "Lundi",
"Tuesday" : "Mardi",
@@ -75,10 +84,10 @@
"Oct." : "Oct.",
"Nov." : "Nov.",
"Dec." : "Déc.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Il y a eu des problèmes à la vérification d’intégrité du code. Plus d'infos...</a>",
"Settings" : "Paramètres",
"Saving..." : "Enregistrement…",
"seconds ago" : "à l'instant",
- "Couldn't send reset email. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez contacter votre administrateur.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Un lien permettant de réinitialiser votre mot de passe vient de vous être envoyé par courriel.<br>Si vous ne le recevez pas dans un délai raisonnable, contactez votre administrateur.<br>N'oubliez pas de vérifier dans votre dossier pourriel / spam!",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vos fichiers sont chiffrés. Si vous n'avez pas activé la clef de récupération, il n'y aura aucun moyen de récupérer vos données une fois le mot de passe réinitialisé.<br />Si vous n'êtes pas sûr de ce que vous faites, veuillez contacter votre administrateur avant de continuer. <br />Voulez-vous vraiment continuer ?",
"I know what I'm doing" : "Je sais ce que je fais",
@@ -107,14 +116,16 @@
"Good password" : "Mot de passe de sécurité suffisante",
"Strong password" : "Mot de passe fort",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Votre serveur web n'est pas correctement configuré pour la synchronisation de fichiers : l'interface WebDAV semble ne pas fonctionner.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La configuration du serveur web ne permet pas d'atteindre \"{url}\". Consultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations à ce sujet.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Ce serveur ne peut se connecter à internet. Cela signifie que certaines fonctionnalités, telles que le montage de supports de stockage distants, les notifications de mises à jour ou l'installation d'applications tierces ne fonctionneront pas. L'accès aux fichiers à distance, ainsi que les notifications par mail peuvent aussi être indisponibles. Il est recommandé d'activer la connexion internet pour ce serveur si vous souhaitez disposer de l'ensemble des fonctionnalités offertes.",
- "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Votre dossier de données et vos fichiers sont probablement accessibles depuis internet. Le fichier .htaccess ne fonctionne pas. Nous vous recommandons vivement de configurer votre serveur web de façon à ce que ce dossier de données ne soit plus accessible, ou de le déplacer hors de la racine du serveur web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Aucun cache de la mémoire n'est configuré. Si possible, configurez un \"memcache\" pour augmenter les performances. Pour plus d'information consultez la <a href=\"{docLink}\">documentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom n'est pas lisible par PHP, ce qui est fortement déconseillé pour des raisons de sécurité. Plus d'informations peuvent être trouvées dans notre <a href=\"{docLink}\">documentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La version de PHP utilisée ({version}) <a href=\"{phpLink}\">n'est plus prise en charge par les créateurs de PHP</a>. Nous vous recommandons de mettre à niveau votre installation de PHP pour bénéficier de meilleures performances et des mises à jour de sécurité fournies par PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La configuration des headers du reverse proxy est incorrecte, ou vous accédez ownCloud depuis un proxy de confiance. Si vous n'êtes pas en train d’accéder à ownCloud depuis un proxy de confiance, ceci est un problème de sécurité qui peut permettre à un attaquant de masquer sa véritable adresse IP. <a href=\"{docLink}\">Plus d'info dans la documentation.</a>",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "\"memcached\" est configuré comme cache distribué, mais le module installé est \"memcache\". \\OC\\Memcache\\Memcached ne prend en charge que \"memcached\" et non \"memcache\". <a href=\"{wikiLink}\">Consulter le wiki memcached parlant de ces deux modules.</a>",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Aucun cache mémoire n'est configuré. Si possible, configurez un cache pour augmenter les performances. Consultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations à ce sujet.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom n'est pas lisible par PHP, ce qui est fortement déconseillé pour des raisons de sécurité. Consultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations à ce sujet.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Votre version de PHP ({version}) <a target=\"_blank\" href=\"{phpLink}\">n'est plus prise en charge par les créateurs de PHP</a>. Nous vous recommandons de mettre à niveau votre installation de PHP pour bénéficier de meilleures performances et des mises à jour de sécurité fournies par PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La configuration des entêtes du proxy inverse est incorrecte, ou vous accédez à ownCloud depuis un proxy de confiance. Si vous n'êtes pas en train d’accéder à ownCloud depuis un proxy de confiance, ceci est un problème de sécurité qui peut permettre à un attaquant de masquer sa véritable adresse IP. Consultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations à ce sujet.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "\"memcached\" est configuré comme cache distribué, mais le module installé est \"memcache\". \\OC\\Memcache\\Memcached ne prend en charge que \"memcached\" et non \"memcache\". <a target=\"_blank\" href=\"{wikiLink}\">Consulter le wiki de memcached à propos de ces deux modules.</a>",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Des fichiers n'ont pas passé la vérification d’intégrité. \nConsultez la <a target=\"_blank\" href=\"{docLink}\">documentation</a> pour avoir plus d'informations sur comment résoudre ce problème.\n(<a target=\"_blank\" href=\"{codeIntegrityDownloadEndpoint}\">Liste des fichiers non valides…</a> / <a href=\"{rescanEndpoint}\">Relancer…</a>)",
"Error occurred while checking server setup" : "Une erreur s'est produite lors de la vérification de la configuration du serveur",
+ "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Votre dossier de données et vos fichiers sont probablement accessibles depuis internet. Le fichier .htaccess ne fonctionne pas. Nous vous recommandons vivement de configurer votre serveur web de façon à ce que ce dossier de données ne soit plus accessible, ou de le déplacer hors de la racine du serveur web.",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "L'en-tête HTTP \"{header}\" n'est pas configurée pour être égale à \"{expected}\" créant potentiellement un risque relié à la sécurité et à la vie privée. Il est donc recommandé d'ajuster ce paramètre.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "L'en-tête HTTP \"Strict-Transport-Security\" n'est pas configurée à \"{seconds}\" secondes. Pour renforcer la sécurité nous recommandons d'activer HSTS comme décrit dans notre <a href=\"{docUrl}\">Guide pour le renforcement et la sécurité</a>.",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Vous accédez à ce site via HTTP. Nous vous recommandons fortement de configurer votre serveur pour forcer l'utilisation de HTTPS, comme expliqué dans notre <a href=\"{docUrl}\">Guide pour le renforcement et la sécurité</a>.",
@@ -123,7 +134,6 @@
"Error" : "Erreur",
"Error while sharing" : "Erreur lors de la mise en partage",
"Error while unsharing" : "Erreur lors de l'annulation du partage",
- "Error while changing permissions" : "Erreur lors du changement des permissions",
"Error setting expiration date" : "Erreur lors de la spécification de la date d'expiration",
"The public link will expire no later than {days} days after it is created" : "Ce lien public expirera au plus tard {days} jours après sa création.",
"Set expiration date" : "Spécifier une date d'expiration",
@@ -142,7 +152,6 @@
"Send" : "Envoyer",
"Shared with you and the group {group} by {owner}" : "Partagé avec vous et le groupe {group} par {owner}",
"Shared with you by {owner}" : "Partagé avec vous par {owner}",
- "Shared in {item} with {user}" : "Partagé dans {item} avec {user}",
"group" : "groupe",
"remote" : "distant",
"notify by email" : "notifier par courriel",
@@ -153,17 +162,25 @@
"change" : "modification",
"delete" : "suppression",
"access control" : "contrôle d'accès",
+ "Could not unshare" : "Impossible d'arrêter de partager",
"Share details could not be loaded for this item." : "Les informations de partage n'ont pu être chargées pour cet élément.",
"An error occured. Please try again" : "Une erreur est survenue. Merci de réessayer",
"Share" : "Partager",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Partagez avec des personnes sur d'autres ownClouds en utilisant la syntaxe utilisateur@exemple.com/owncloud",
"Share with users or groups …" : "Partager avec des utilisateurs ou groupes...",
"Share with users, groups or remote users …" : "Partager avec des utilisateurs, groupes, ou utilisateurs distants",
+ "Error removing share" : "Erreur lors de l'arrêt du partage",
"Warning" : "Attention",
"Error while sending notification" : "Erreur lors de l'envoi de la notification",
+ "Non-existing tag #{tag}" : "Étiquette #{tag} inexistante",
+ "not assignable" : "inassignable",
+ "invisible" : "invisible",
+ "({scope})" : "({scope})",
+ "Delete" : "Supprimer",
+ "Rename" : "Renommer",
+ "Global tags" : "Étiquettes globales",
"The object type is not specified." : "Le type d'objet n'est pas spécifié.",
"Enter new" : "Saisir un nouveau",
- "Delete" : "Supprimer",
"Add" : "Ajouter",
"Edit tags" : "Modifier les étiquettes",
"Error loading dialog template: {error}" : "Erreur lors du chargement du modèle de dialogue : {error}",
@@ -182,15 +199,6 @@
"The update was unsuccessful. " : "La mise à jour a échoué.",
"The update was successful. There were warnings." : "La mise à jour a réussi, mais il y a eu des avertissements",
"The update was successful. Redirecting you to ownCloud now." : "La mise à jour a réussi. Vous êtes maintenant redirigé vers ownCloud.",
- "Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable.",
- "Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré.",
- "Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.",
- "%s password reset" : "Réinitialisation de votre mot de passe %s",
- "Use the following link to reset your password: {link}" : "Utilisez le lien suivant pour réinitialiser votre mot de passe : {link}",
- "New password" : "Nouveau mot de passe",
- "New Password" : "Nouveau mot de passe",
- "Reset password" : "Réinitialiser le mot de passe",
"Searching other places" : "Recherche en cours dans d'autres emplacements",
"No search results in other folders" : "Aucun résultat dans d'autres dossiers",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} résultat dans un autre dossier","{count} résultats dans d'autres dossiers"],
@@ -260,14 +268,19 @@
"Please try again or contact your administrator." : "Veuillez réessayer ou contacter votre administrateur.",
"Log in" : "Se connecter",
"Wrong password. Reset it?" : "Mot de passe incorrect. Réinitialiser ?",
+ "Wrong password." : "Mot de passe incorrect.",
"Stay logged in" : "Rester connecté",
"Alternative Logins" : "Identifiants alternatifs",
+ "Use the following link to reset your password: {link}" : "Utilisez le lien suivant pour réinitialiser votre mot de passe : {link}",
+ "New password" : "Nouveau mot de passe",
+ "New Password" : "Nouveau mot de passe",
+ "Reset password" : "Réinitialiser le mot de passe",
"This ownCloud instance is currently in single user mode." : "Cette instance de ownCloud est actuellement en mode utilisateur unique.",
"This means only administrators can use the instance." : "Cela signifie que seuls les administrateurs peuvent utiliser l'instance.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Veuillez contacter votre administrateur système si ce message persiste ou apparaît de façon inattendue.",
"Thank you for your patience." : "Merci de votre patience.",
"You are accessing the server from an untrusted domain." : "Vous accédez au serveur à partir d'un domaine non approuvé.",
- "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Veuillez contacter votre administrateur. Si vous être l'administrateur de cette instance, il faut configurer la variable \"trusted_domains\" dans le fichier config/config.php. Un exemple de configuration est fournit dans le fichier config/config.sample.php.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Veuillez contacter votre administrateur. Si vous être l'administrateur de cette instance, configurez la variable \"trusted_domains\" dans le fichier config/config.php. Un exemple de configuration est fournit dans le fichier config/config.sample.php.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "En fonction de votre configuration, en tant qu'administrateur vous pouvez également utiliser le bouton ci-dessous pour approuver ce domaine.",
"Add \"%s\" as trusted domain" : "Ajouter \"%s\" à la liste des domaines approuvés",
"App update required" : "Mise à jour de l'application nécessaire",
diff --git a/core/l10n/gl.js b/core/l10n/gl.js
index 92fa9a74f35..957f1f5df4b 100644
--- a/core/l10n/gl.js
+++ b/core/l10n/gl.js
@@ -21,6 +21,10 @@ OC.L10N.register(
"No crop data provided" : "Non indicou como recortar",
"No valid crop data provided" : "Os datos cortados fornecidos non son válidos",
"Crop is not square" : "O corte non é cadrado",
+ "Couldn't reset password because the token is invalid" : "No, foi posíbel restabelecer o contrasinal, a marca non é correcta",
+ "Couldn't send reset email. Please make sure your username is correct." : "Non foi posíbel enviar o correo do restabelecemento. Asegúrese de que o nome de usuario é o correcto.",
+ "%s password reset" : "Restabelecer o contrasinal %s",
+ "Couldn't send reset email. Please contact your administrator." : "Non foi posíbel enviar o correo do restabelecemento. Póñase en contacto co administrador.",
"Sunday" : "domingo",
"Monday" : "luns",
"Tuesday" : "martes",
@@ -69,7 +73,6 @@ OC.L10N.register(
"Settings" : "Axustes",
"Saving..." : "Gardando...",
"seconds ago" : "segundos atrás",
- "Couldn't send reset email. Please contact your administrator." : "Non foi posíbel enviar o correo do restabelecemento. Póñase en contacto co administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "A ligazón para restabelecer o seu contrasinal foi enviada ao seu correo. Se non a recibe nun prazo razoábel de tempo, vexa o seu cartafol de correo lixo. <br> Se non está ali pregúntelle ao administrador local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Os seus ficheiros están cifrados. Se non activou a chave de recuperación, non haberá maneira de recuperar os datos após o restabelecemento do contrasinal. <br />Se non está seguro de que facer, póñase en contacto co administrador antes de continuar. <br /> Confirma que quere continuar?",
"I know what I'm doing" : "Sei o estou a facer",
@@ -100,8 +103,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "O servidor aínda non está configurado correctamente para permitir a sincronización de ficheiros, semella que a interface WebDAV non está a funcionar.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Este servidor non ten conexión activa a Internet. Isto significa que algunhas características como a montaxe do almacenamento externo, as notificacións sobre actualizacións ou a instalación de engadidos de terceiros non funcionarán. Así mesmo, o acceso remoto a ficheiros e enviar correos de notificación poderían non funcionar. Suxerímoslle que active a conexión a Internet para este servidor se quere ter todos estes servizos.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "O directorio de datos e os seus ficheiros probabelmente son accesíbeis desde a Internet. O ficheiro .htaccess non funciona. Recomendámoslle que configure o seu servidor web de xeito que o directorio de datos non sexa accesíbel ou que mova o directorio de datos fora do directorio root do servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Non foi configurada a memoria cache. Para mellorar o rendemento configure unha «memcache», se está dispoñíbel. Pode atopar máis información na nosa <a href=\"{docLink}\">documentación</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom non é lexíbel por PHP xa que esta absolutamente desaconsellado por razóns de seguridade. Pode atopar máis información na nosa <a href=\"{docLink}\">documentación</a>.",
"Error occurred while checking server setup" : "Aconteceu un erro mentras se comprobaba a configuración do servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "A cabeceira HTTP «{header}» non está configurada como igual a «{expected}». Isto é un posíbel risco para a seguridade ou a intimidade, recomendámoslle que axuste esta opción.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "A cabeceira HTTP «Strict-Transport-Security» non está configurada para menos de «{seconds}» segundos . Para mellorar a seguridade, recomendámoslle que active o uso de HTTPS, tal e como se describe nos <a href=\"{docUrl}\">consellos de seguridade</a>.",
@@ -111,7 +112,6 @@ OC.L10N.register(
"Error" : "Erro",
"Error while sharing" : "Produciuse un erro ao compartir",
"Error while unsharing" : "Produciuse un erro ao deixar de compartir",
- "Error while changing permissions" : "Produciuse un erro ao cambiar os permisos",
"Error setting expiration date" : "Produciuse un erro ao definir a data de caducidade",
"The public link will expire no later than {days} days after it is created" : "A ligazón pública caducará, a máis tardar, {days} días após a súa creación",
"Set expiration date" : "Definir a data de caducidade",
@@ -130,7 +130,6 @@ OC.L10N.register(
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Compartido con vostede e co grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartido con vostede por {owner}",
- "Shared in {item} with {user}" : "Compartido en {item} con {user}",
"group" : "grupo",
"remote" : "remoto",
"notify by email" : "notificar por correo",
@@ -147,9 +146,10 @@ OC.L10N.register(
"Share with users or groups …" : "Compartir con usuarios ou grupos ...",
"Share with users, groups or remote users …" : "Compartir con usuarios, grupos ou usuarios remotos ...",
"Warning" : "Aviso",
+ "Delete" : "Eliminar",
+ "Rename" : "Renomear",
"The object type is not specified." : "Non se especificou o tipo de obxecto.",
"Enter new" : "Introduza o novo",
- "Delete" : "Eliminar",
"Add" : "Engadir",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Produciuse un erro ao cargar o modelo do dialogo: {error}",
@@ -166,14 +166,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Fracasou a actualización.",
"The update was successful. There were warnings." : "A actualización realizouse correctamente. Houbo algún aviso.",
"The update was successful. Redirecting you to ownCloud now." : "A actualización realizouse correctamente. Redirixíndoo agora á ownCloud.",
- "Couldn't reset password because the token is invalid" : "No, foi posíbel restabelecer o contrasinal, a marca non é correcta",
- "Couldn't send reset email. Please make sure your username is correct." : "Non foi posíbel enviar o correo do restabelecemento. Asegúrese de que o nome de usuario é o correcto.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Non foi posíbel enviar o correo do restabelecemento. Semella que este correo non corresponde con este nome de usuario. Póñase en contacto co administrador.",
- "%s password reset" : "Restabelecer o contrasinal %s",
- "Use the following link to reset your password: {link}" : "Usa a seguinte ligazón para restabelecer o contrasinal: {link}",
- "New password" : "Novo contrasinal",
- "New Password" : "Novo contrasinal",
- "Reset password" : "Restabelecer o contrasinal",
"Searching other places" : "Buscando noutros lugares",
"Personal" : "Persoal",
"Users" : "Usuarios",
@@ -241,6 +233,10 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Ténteo de novo ou póñase en contacto co administrador.",
"Log in" : "Acceder",
"Alternative Logins" : "Accesos alternativos",
+ "Use the following link to reset your password: {link}" : "Usa a seguinte ligazón para restabelecer o contrasinal: {link}",
+ "New password" : "Novo contrasinal",
+ "New Password" : "Novo contrasinal",
+ "Reset password" : "Restabelecer o contrasinal",
"This ownCloud instance is currently in single user mode." : "Esta instancia do ownCloud está actualmente en modo de usuario único.",
"This means only administrators can use the instance." : "Isto significa que só os administradores poden utilizar a instancia.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Póñase en contacto co administrador do sistema se persiste esta mensaxe ou se aparece de forma inesperada.",
diff --git a/core/l10n/gl.json b/core/l10n/gl.json
index ebc7313cccc..e572387c179 100644
--- a/core/l10n/gl.json
+++ b/core/l10n/gl.json
@@ -19,6 +19,10 @@
"No crop data provided" : "Non indicou como recortar",
"No valid crop data provided" : "Os datos cortados fornecidos non son válidos",
"Crop is not square" : "O corte non é cadrado",
+ "Couldn't reset password because the token is invalid" : "No, foi posíbel restabelecer o contrasinal, a marca non é correcta",
+ "Couldn't send reset email. Please make sure your username is correct." : "Non foi posíbel enviar o correo do restabelecemento. Asegúrese de que o nome de usuario é o correcto.",
+ "%s password reset" : "Restabelecer o contrasinal %s",
+ "Couldn't send reset email. Please contact your administrator." : "Non foi posíbel enviar o correo do restabelecemento. Póñase en contacto co administrador.",
"Sunday" : "domingo",
"Monday" : "luns",
"Tuesday" : "martes",
@@ -67,7 +71,6 @@
"Settings" : "Axustes",
"Saving..." : "Gardando...",
"seconds ago" : "segundos atrás",
- "Couldn't send reset email. Please contact your administrator." : "Non foi posíbel enviar o correo do restabelecemento. Póñase en contacto co administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "A ligazón para restabelecer o seu contrasinal foi enviada ao seu correo. Se non a recibe nun prazo razoábel de tempo, vexa o seu cartafol de correo lixo. <br> Se non está ali pregúntelle ao administrador local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Os seus ficheiros están cifrados. Se non activou a chave de recuperación, non haberá maneira de recuperar os datos após o restabelecemento do contrasinal. <br />Se non está seguro de que facer, póñase en contacto co administrador antes de continuar. <br /> Confirma que quere continuar?",
"I know what I'm doing" : "Sei o estou a facer",
@@ -98,8 +101,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "O servidor aínda non está configurado correctamente para permitir a sincronización de ficheiros, semella que a interface WebDAV non está a funcionar.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Este servidor non ten conexión activa a Internet. Isto significa que algunhas características como a montaxe do almacenamento externo, as notificacións sobre actualizacións ou a instalación de engadidos de terceiros non funcionarán. Así mesmo, o acceso remoto a ficheiros e enviar correos de notificación poderían non funcionar. Suxerímoslle que active a conexión a Internet para este servidor se quere ter todos estes servizos.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "O directorio de datos e os seus ficheiros probabelmente son accesíbeis desde a Internet. O ficheiro .htaccess non funciona. Recomendámoslle que configure o seu servidor web de xeito que o directorio de datos non sexa accesíbel ou que mova o directorio de datos fora do directorio root do servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Non foi configurada a memoria cache. Para mellorar o rendemento configure unha «memcache», se está dispoñíbel. Pode atopar máis información na nosa <a href=\"{docLink}\">documentación</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom non é lexíbel por PHP xa que esta absolutamente desaconsellado por razóns de seguridade. Pode atopar máis información na nosa <a href=\"{docLink}\">documentación</a>.",
"Error occurred while checking server setup" : "Aconteceu un erro mentras se comprobaba a configuración do servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "A cabeceira HTTP «{header}» non está configurada como igual a «{expected}». Isto é un posíbel risco para a seguridade ou a intimidade, recomendámoslle que axuste esta opción.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "A cabeceira HTTP «Strict-Transport-Security» non está configurada para menos de «{seconds}» segundos . Para mellorar a seguridade, recomendámoslle que active o uso de HTTPS, tal e como se describe nos <a href=\"{docUrl}\">consellos de seguridade</a>.",
@@ -109,7 +110,6 @@
"Error" : "Erro",
"Error while sharing" : "Produciuse un erro ao compartir",
"Error while unsharing" : "Produciuse un erro ao deixar de compartir",
- "Error while changing permissions" : "Produciuse un erro ao cambiar os permisos",
"Error setting expiration date" : "Produciuse un erro ao definir a data de caducidade",
"The public link will expire no later than {days} days after it is created" : "A ligazón pública caducará, a máis tardar, {days} días após a súa creación",
"Set expiration date" : "Definir a data de caducidade",
@@ -128,7 +128,6 @@
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Compartido con vostede e co grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartido con vostede por {owner}",
- "Shared in {item} with {user}" : "Compartido en {item} con {user}",
"group" : "grupo",
"remote" : "remoto",
"notify by email" : "notificar por correo",
@@ -145,9 +144,10 @@
"Share with users or groups …" : "Compartir con usuarios ou grupos ...",
"Share with users, groups or remote users …" : "Compartir con usuarios, grupos ou usuarios remotos ...",
"Warning" : "Aviso",
+ "Delete" : "Eliminar",
+ "Rename" : "Renomear",
"The object type is not specified." : "Non se especificou o tipo de obxecto.",
"Enter new" : "Introduza o novo",
- "Delete" : "Eliminar",
"Add" : "Engadir",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Produciuse un erro ao cargar o modelo do dialogo: {error}",
@@ -164,14 +164,6 @@
"The update was unsuccessful. " : "Fracasou a actualización.",
"The update was successful. There were warnings." : "A actualización realizouse correctamente. Houbo algún aviso.",
"The update was successful. Redirecting you to ownCloud now." : "A actualización realizouse correctamente. Redirixíndoo agora á ownCloud.",
- "Couldn't reset password because the token is invalid" : "No, foi posíbel restabelecer o contrasinal, a marca non é correcta",
- "Couldn't send reset email. Please make sure your username is correct." : "Non foi posíbel enviar o correo do restabelecemento. Asegúrese de que o nome de usuario é o correcto.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Non foi posíbel enviar o correo do restabelecemento. Semella que este correo non corresponde con este nome de usuario. Póñase en contacto co administrador.",
- "%s password reset" : "Restabelecer o contrasinal %s",
- "Use the following link to reset your password: {link}" : "Usa a seguinte ligazón para restabelecer o contrasinal: {link}",
- "New password" : "Novo contrasinal",
- "New Password" : "Novo contrasinal",
- "Reset password" : "Restabelecer o contrasinal",
"Searching other places" : "Buscando noutros lugares",
"Personal" : "Persoal",
"Users" : "Usuarios",
@@ -239,6 +231,10 @@
"Please try again or contact your administrator." : "Ténteo de novo ou póñase en contacto co administrador.",
"Log in" : "Acceder",
"Alternative Logins" : "Accesos alternativos",
+ "Use the following link to reset your password: {link}" : "Usa a seguinte ligazón para restabelecer o contrasinal: {link}",
+ "New password" : "Novo contrasinal",
+ "New Password" : "Novo contrasinal",
+ "Reset password" : "Restabelecer o contrasinal",
"This ownCloud instance is currently in single user mode." : "Esta instancia do ownCloud está actualmente en modo de usuario único.",
"This means only administrators can use the instance." : "Isto significa que só os administradores poden utilizar a instancia.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Póñase en contacto co administrador do sistema se persiste esta mensaxe ou se aparece de forma inesperada.",
diff --git a/core/l10n/he.js b/core/l10n/he.js
index d66e67605f0..9a7bfeede44 100644
--- a/core/l10n/he.js
+++ b/core/l10n/he.js
@@ -1,6 +1,46 @@
OC.L10N.register(
"core",
{
+ "Couldn't send mail to following users: %s " : "לא ניתן היה לשלוח דואר אלקטרוני למשתמשים הבאים %s ",
+ "Preparing update" : "מכין עדכון",
+ "Turned on maintenance mode" : "הפעלת מצב אחזקה",
+ "Turned off maintenance mode" : "כיבוי מצב אחזקה",
+ "Maintenance mode is kept active" : "מצב אחזקה נשמר פעיל",
+ "Updating database schema" : "עדכון סכימת מסד נתונים",
+ "Updated database" : "עדכון מסד נתונים",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "בודק אם סכימת מסד הנתונים ניתנת לעדכון (פעולה זו יכולה להמשך זמן רב תלוי בגודל מסד הנתונים)",
+ "Checked database schema update" : "עדכון סכימת מסד נתונים נבדק",
+ "Checking updates of apps" : "בדיקת עדכוני יישומים",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "בודק אם סכימת מסד הנתונים עבור %s ניתנת לעדכון (פעולה זו יכולה להמשך זמן רב תלוי בגודל מסד הנתונים)",
+ "Checked database schema update for apps" : "עדכון סכימת מסד נתונים ליישומים נבדק",
+ "Updated \"%s\" to %s" : "מעדכן \"%s\" ל- %s",
+ "Repair warning: " : "אזהרת תיקון:",
+ "Repair error: " : "שגיאת תיקון:",
+ "Set log level to debug" : "קביעת רמת דיווח לתהליך ניפוי בשגיאות",
+ "Reset log level" : "קביעה מחדש לרמת דיווח",
+ "Starting code integrity check" : "התחלת בדיקת תקינות קוד",
+ "Finished code integrity check" : "סיום בדיקת תקינות קוד",
+ "%s (3rdparty)" : "%s (צד שלישי)",
+ "%s (incompatible)" : "%s (לא תואם)",
+ "Following apps have been disabled: %s" : "היישומים הבאים נוטרלו: %s",
+ "Already up to date" : "כבר עדכני",
+ "Please select a file." : "יש לבחור קובץ.",
+ "File is too big" : "הקובץ גדול מדי",
+ "Invalid file provided" : "סופק קובץ לא חוקי",
+ "No image or file provided" : "לא סופקו תמונה או קובץ",
+ "Unknown filetype" : "סוג קובץ לא מוכר",
+ "Invalid image" : "תמונה לא חוקית",
+ "An error occurred. Please contact your admin." : "אירעה שגיאה. יש ליצור קשר עם המנהל שלך.",
+ "No temporary profile picture available, try again" : "לא קיימת תמונת פרופיל זמנית, יש לנסות שוב",
+ "No crop data provided" : "לא סופק מידע קיטום",
+ "No valid crop data provided" : "לא סופק מידע קיטום חוקי",
+ "Crop is not square" : "הקיטום אינו מרובע",
+ "Couldn't reset password because the token is invalid" : "לא ניתן לאפס סיסמא כיוון שמחרוזת האימות אינה חוקית",
+ "Couldn't reset password because the token is expired" : "לא ניתן לאפס סיסמא כיוון שמחרוזת האימות פגה תוקף",
+ "Couldn't send reset email. Please make sure your username is correct." : "לא ניתן היה לשלוח דואר אלקטרוני לאיפוס. יש לוודא ששם המשתמש נכון.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "לא ניתן היה לשלוח דואר אלקטרוני כיוון שלא מוגדר דואר אלקטרוני למשתמש זה. יש ליצור קשר עם מנהל.",
+ "%s password reset" : "%s הסיסמא אופסה",
+ "Couldn't send reset email. Please contact your administrator." : "לא ניתן היה לשלוח דואר אלקטרוני לאיפוס. יש לפנות למנהל שלך.",
"Sunday" : "יום ראשון",
"Monday" : "יום שני",
"Tuesday" : "יום שלישי",
@@ -15,6 +55,13 @@ OC.L10N.register(
"Thu." : "חמישי",
"Fri." : "שישי",
"Sat." : "שבת",
+ "Su" : "א",
+ "Mo" : "ב",
+ "Tu" : "ג",
+ "We" : "ד",
+ "Th" : "ה",
+ "Fr" : "ו",
+ "Sa" : "ש",
"January" : "ינואר",
"February" : "פברואר",
"March" : "מרץ",
@@ -39,70 +86,214 @@ OC.L10N.register(
"Oct." : "אוק׳",
"Nov." : "נוב׳",
"Dec." : "דצמ׳",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">קיימות בעיות עם בדיקת תקינות קוד. למידע נוסף…</a>",
"Settings" : "הגדרות",
"Saving..." : "שמירה…",
"seconds ago" : "שניות",
+ "The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "הקישור לאיפוס הסיסמא שלך נשלח אליך בדואר אלקטרוני. אם לא קיבלת את הקישור תוך זמן סביר, מוטב לבדוק את תיבת דואר הזבל/ספאם שלך.<br>אם ההודעה אינה שם, יש לשאול את המנהל המקומי שלך .",
+ "Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "הקבצים שלך מוצפנים. אם לא הפעלת את מפתח השחזור, לא תהיה דרך לקבל את המידע מחדש אחרי שהסיסמא תאופס.<br />אם אין לך מושג מה לעשות what to do, מוטב לפנות למנהל שלך לפני ההמשך. <br />האם באמת ברצונך להמשיך?",
+ "I know what I'm doing" : "אני יודע/ת מה אני עושה",
+ "Password can not be changed. Please contact your administrator." : "לא ניתן לשנות את הסיסמא. יש לפנות למנהל שלך.",
"No" : "לא",
"Yes" : "כן",
"Choose" : "בחירה",
+ "Error loading file picker template: {error}" : "שגיאה בטעינת תבנית בחירת הקבצים: {error}",
"Ok" : "בסדר",
+ "Error loading message template: {error}" : "שגיאה בטעינת תבנית ההודעות: {error}",
+ "read-only" : "לקריאה בלבד",
+ "_{count} file conflict_::_{count} file conflicts_" : ["{count} הנגשות קובץ","{count} התנגשויות קבצים"],
+ "One file conflict" : "התנגשות קובץ אחת",
"New Files" : "קבצים חדשים",
+ "Already existing files" : "קבצים קיימים כבר",
+ "Which files do you want to keep?" : "אילו קבצים ברצונך לשמור?",
+ "If you select both versions, the copied file will have a number added to its name." : "אם תבחר האפשרות לשמור את שתי הגרסאות, לשם קובץ המועתק יתווסף מספר.",
"Cancel" : "ביטול",
+ "Continue" : "המשך",
+ "(all selected)" : "(הכול נבחר)",
+ "({count} selected)" : "({count} נבחרו)",
+ "Error loading file exists template" : "שגיאה בטעינת קובץ תבנית קיימים",
+ "Very weak password" : "סיסמא מאוד חלשה",
+ "Weak password" : "סיסמא חלשה",
+ "So-so password" : "סיסמא ככה-ככה",
+ "Good password" : "סיסמא טובה",
+ "Strong password" : "סיסמא חזקה",
+ "Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "שרת האינטרנט שלך אינו מוגדר כהלכה לאפשר סנכרון כיוון שממשק ה־WebDAV כנראה שבור.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "שרת האינטרנט שלך לא מוגדר כהלכה לפתור \"{url}\". מידע נוסף קיים <a target=\"_blank\" href=\"{docLink}\">במסמכים</a> שלנו.",
+ "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "לשרת זה אין חיבור אינטרנט פעיל. לפיכך חלק מהתכונות כגון עגינת אחסון חיצוני, הודעות על עדכונים או התקנת יישומי צד שלישי לא יעבדו. ייתכן ולא יעבדו גם כניסה לקבצים מבחוץ ושליחת הודעות דואר אלקטרוני. אנו ממליצים לאפשר חיבור אינטרנט לשרת זה אם ברצונך שיהיו לך את כל התכונות.",
+ "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "כנראה וניתן לגשת אל תיקיית data והקבצים שלך מהאינטרנט. קובץ .htaccess אינו עובד. אנו ממליצים בכל תוקף שתגדיר את השרת בצורה כזאת שלא ניתן יהיה לגשת לתיקיית ה- data או להעביר את תיקיית ה- dta מחוץ לנתיב המסמכים של שרת האינטרנט.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "לא הוגדר memory cache. על מנת לשפר את הביצועים יש להגדיר memcache אם קיים. מידע נוסף ניתן לצפות ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom אינו ניתן לקריאה על ידי PHP אשר אינו מומלץ בשל סיבות אבטחה. מידע נוסף ניתן לראות ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "גרסת ה- PHP שלך ({version}) אינה <a target=\"_blank\" href=\"{phpLink}\">נתמכת כבר על ידי PHP</a>. אנו ממליצים לשדרג את גרסת ה- PHP ולהנות מהיתרון של עדכוני האבטחה והביצועים שמספק ה- PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "תצורת כותרות פרוקסי ההפוכה אינה נכונה, או שהגישה ל- ownCloud מתבצעת מ- proxy אמין. אם הגישה ל- ownCloud אינה מ- proxy אמין, מדובר בבעיית אבטחה שמאפשרת לתוקף לזיין את כתובת ה- IP כגלויה ל- ownCloud. מידע נוסף ניתן למצוא ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a> שלנו.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached מוגדר כמטמון מופץ, אבל מותקן מודול PHP לא נכון \"memcache\". רק \\OC\\Memcache\\Memcached תומך ב- \"memcached\" אבל לא ב- \"memcache\". ניתן לצפות ב- <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki בנושא שני המודולים</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "חלק מהקבצים לא עברו את בדיקת התקינות. מידע נוסף איך לפתור את הבעיה ניתן למצוא ב- to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a> שלנו. (<a href=\"{codeIntegrityDownloadEndpoint}\">רשימה של קבצים לא תקינים…</a> / <a href=\"{rescanEndpoint}\">סריקה מחדש…</a>)",
+ "Error occurred while checking server setup" : "שגיאה אירעה בזמן בדיקת התקנת השרת",
+ "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "כותרת ה- HTTP \"{header}\" אינה מוגדרת להיות שווה ל- \"{expected}\". הדבר מהווה פוטנציאל סיכון אבטחה או פגיעה בפרטיות ואנו ממליצים לתקן את הגדרה זו.",
+ "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "כותרת HTTP \"Strict-Transport-Security\" אינה מוגדרת לפחות \"{seconds}\" שניות. להגברת האבטחה אנו ממליצים לאפשר HSTS כפי שמוסבר ב- <a href=\"{docUrl}\">טיפים לאבטחה</a> שלנו.",
+ "You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "הנך נכנס לאתר באמצעות פרוטוקול HTTP. אנו ממליצים מאוד להגדיר את השרת לעבוד עם פרוטוקול HTTPS במקום כפי שמוסבר ב- <a href=\"{docUrl}\">טיפים לאבטחה</a> שלנו.",
"Shared" : "שותף",
+ "Shared with {recipients}" : "שיתוף עם {recipients}",
"Error" : "שגיאה",
"Error while sharing" : "שגיאה במהלך השיתוף",
"Error while unsharing" : "שגיאה במהלך ביטול השיתוף",
- "Error while changing permissions" : "שגיאה במהלך שינוי ההגדרות",
"Error setting expiration date" : "אירעה שגיאה בעת הגדרת תאריך התפוגה",
+ "The public link will expire no later than {days} days after it is created" : "הקישור הציבורי יפוג עד {days} ימים לאחר שנוצר",
"Set expiration date" : "הגדרת תאריך תפוגה",
+ "Expiration" : "תפוגה",
"Expiration date" : "תאריך התפוגה",
+ "Choose a password for the public link" : "בחירת סיסמא לקישור ציבורי",
"Sending ..." : "מתבצעת שליחה ...",
"Email sent" : "הודעת הדוא״ל נשלחה",
"Resharing is not allowed" : "אסור לעשות שיתוף מחדש",
"Share link" : "קישור לשיתוף",
+ "Link" : "קישור",
"Password protect" : "הגנה בססמה",
"Password" : "סיסמא",
+ "Allow editing" : "אישור עריכה",
"Email link to person" : "שליחת קישור בדוא״ל למשתמש",
"Send" : "שליחה",
"Shared with you and the group {group} by {owner}" : "שותף אתך ועם הקבוצה {group} שבבעלות {owner}",
"Shared with you by {owner}" : "שותף אתך על ידי {owner}",
- "Shared in {item} with {user}" : "שותף תחת {item} עם {user}",
"group" : "קבוצה",
+ "remote" : "נשלט מרחוק",
+ "notify by email" : "קבלת הודעה בדואר אלקטרוני",
"Unshare" : "הסר שיתוף",
"can share" : "ניתן לשתף",
"can edit" : "ניתן לערוך",
"create" : "יצירה",
+ "change" : "שינוי",
"delete" : "מחיקה",
"access control" : "בקרת גישה",
+ "Could not unshare" : "לא ניתן לבטל שיתוף",
+ "Share details could not be loaded for this item." : "לא ניתן היה לטעון מידע שיתוף לפריט זה",
+ "An error occured. Please try again" : "אירעה שגיאה. יש לנסות בבקשה שוב",
"Share" : "שתף",
+ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "ניתן לשתף עם אנשים אחרים המשתמשים ב- ownClouds בעזרת הפורמט הבא username@example.com/owncloud",
+ "Share with users or groups …" : "שיתוף עם משתמשים או קבוצות...",
+ "Share with users, groups or remote users …" : "שיתוף עם משתמשים, קבוצות או משתמשים חצוניים...",
+ "Error removing share" : "שגיאה בזמן הסרת שיתוף",
"Warning" : "אזהרה",
- "The object type is not specified." : "סוג הפריט לא צוין.",
+ "Error while sending notification" : "שגיאה בזמן שליחת הודעה",
+ "Non-existing tag #{tag}" : "תגית לא קיימת #{tag}",
+ "not assignable" : "לא ניתן להקצאה",
+ "invisible" : "בלתי גלוי",
+ "({scope})" : "({scope})",
"Delete" : "מחיקה",
+ "Rename" : "שינוי שם",
+ "Global tags" : "תגיות גלובליות",
+ "The object type is not specified." : "סוג הפריט לא צוין.",
+ "Enter new" : "הכנסת חדש",
"Add" : "הוספה",
+ "Edit tags" : "עריכת תגים",
+ "Error loading dialog template: {error}" : "שגיאה בזמן טעינת תבנית דיאלוג: {error}",
+ "No tags selected for deletion." : "לא סומנו תגים למחיקה.",
+ "unknown text" : "מלל לא מוכר",
+ "Hello world!" : "שלום עולם!",
+ "sunny" : "שמשי",
+ "Hello {name}, the weather is {weather}" : "שלום {name}, מזג האוויר הנו {weather}",
+ "Hello {name}" : "שלום {name}",
+ "_download %n file_::_download %n files_" : ["הורד %n קובץ","הורדו %n קבצים"],
+ "{version} is available. Get more information on how to update." : "{version} זמינה. ניתן לקבל מידע נוסף על איך לעדכן.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "מתבצע עכשיו שדרוג, מעבר מדף זה עלול לפגוע בתהליך בסביבות הפעלה מסויימות.",
+ "Updating {productName} to version {version}, this may take a while." : "מעדכן {productName} לגרסה {version}, זה יקח זמן מה.",
+ "An error occurred." : "אירעה שגיאה.",
+ "Please reload the page." : "יש להעלות מחדש דף זה.",
+ "The update was unsuccessful. " : "העדכון בוצע בהצלחה.",
+ "The update was successful. There were warnings." : "העדכון בוצע בהצלחה. היו הזהרות.",
"The update was successful. Redirecting you to ownCloud now." : "תהליך העדכון הסתיים בהצלחה. עכשיו מנתב אותך אל ownCloud.",
- "Use the following link to reset your password: {link}" : "יש להשתמש בקישור הבא כדי לאפס את הססמה שלך: {link}",
- "New password" : "ססמה חדשה",
- "Reset password" : "איפוס ססמה",
+ "Searching other places" : "מחפש במקומות אחרים",
+ "No search results in other folders" : "אין תוצאות חיפוש בתיקיות אחרות",
+ "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} תוצאת חיפוש בתיקייה אחרות","{count} תוצאות חיפוש בתיקיות אחרות"],
"Personal" : "אישי",
"Users" : "משתמשים",
"Apps" : "יישומים",
"Admin" : "מנהל",
"Help" : "עזרה",
+ "Error loading tags" : "שגיאה בטעינת תגיות",
+ "Tag already exists" : "תגית כבר קיימת",
+ "Error deleting tag(s)" : "שגיאה במחיקת תגית(יות)",
+ "Error tagging" : "שגיאה בביצוע תגיות",
+ "Error untagging" : "שגיאה בהסרת תגיות",
+ "Error favoriting" : "שגיאה בקביעת מועדפים",
+ "Error unfavoriting" : "שגיאה בהסרת מועדפים",
"Access forbidden" : "הגישה נחסמה",
+ "File not found" : "קובץ לא נמצא",
+ "The specified document has not been found on the server." : "המסמך המבוקש לא נמצא על השרת.",
+ "You can click here to return to %s." : "ניתן ללחוץ כאן לחזרה אל %s.",
+ "Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\n" : "שלום רב,\n\nרצינו לעדכן אותך ש- %s שיתף/שיתפה %s איתך.\nניתן לצפות בשיתוף כאן: %s\n\n",
+ "The share will expire on %s." : "השיתוף יפוג תוקף ב- %s.",
+ "Cheers!" : "לחיים!",
+ "Internal Server Error" : "שגיאה פנימית בשרת",
+ "The server encountered an internal error and was unable to complete your request." : "השרת נתקל בשגיאה פנימית ולא הצליח לסיים את הבקשה שלך.",
+ "Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "יש ליצור קשר עם מנהל השרת אם שגיאה זו חוזרת מספר פעמים, יש לצרף לדיווח את הפרטים הטכניים למטה.",
+ "More details can be found in the server log." : "פרטים נוספים ניתן למצוא בלוג של הרשת.",
+ "Technical details" : "פרטים טכנים",
+ "Remote Address: %s" : "כתובת מרוחקת: %s",
+ "Request ID: %s" : "מספר זיהוי מבוקש: %s",
+ "Type: %s" : "סוג: %s",
+ "Code: %s" : "קוד: %s",
+ "Message: %s" : "הודעה: %s",
+ "File: %s" : "קובץ: %s",
+ "Line: %s" : "שורה: %s",
+ "Trace" : "עקבות",
+ "Security warning" : "אזהרת אבטחה",
"Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "תיקיית וקבצי המידע שלך כנראה נגישים מהאינטרנט מכיוון שקובץ ה.htaccess לא עובד.",
+ "For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "למידע איך להגדיר את השרת שלך, ניתן לראות ב- <a href=\"%s\" target=\"_blank\">מסמכי התיעוד</a>.",
"Create an <strong>admin account</strong>" : "יצירת <strong>חשבון מנהל</strong>",
"Username" : "שם משתמש",
+ "Storage & database" : "אחסון ומסד נתונים",
"Data folder" : "תיקיית נתונים",
"Configure the database" : "הגדרת מסד הנתונים",
+ "Only %s is available." : "רק %s זמין.",
+ "Install and activate additional PHP modules to choose other database types." : "לבחירת סוגים אחרים של מסדי נתונים יש להתקין ולהפעיל מודולי PHP נוספים.",
+ "For more details check out the documentation." : "למידע נוסף יש לבדוק במסמכי התיעוד.",
"Database user" : "שם משתמש במסד הנתונים",
"Database password" : "ססמת מסד הנתונים",
"Database name" : "שם מסד הנתונים",
"Database tablespace" : "מרחב הכתובות של מסד הנתונים",
"Database host" : "שרת בסיס נתונים",
+ "Performance warning" : "אזהרת ביצועים",
+ "SQLite will be used as database." : "יעשה שימוש ב- SQLite כמסד נתונים.",
+ "For larger installations we recommend to choose a different database backend." : "להתקנות נרחבות אנו ממליצים לבחור מסד נתונים אחר לצד השרת.",
+ "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "במיוחד כאשר משתמשים במחשב שולחני לסנכרון קבצים השימוש ב SQLite אינו מומלץ.",
"Finish setup" : "סיום התקנה",
+ "Finishing …" : "מסיים...",
+ "Need help?" : "עזרה נזקקת?",
+ "See the documentation" : "יש לצפות במסמכי התיעוד",
+ "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "הי לך,<br><br>כדאי לך לדעת ש- %s משתף/פת <strong>%s</strong> אתך.<br><a href=\"%s\">לצפייה!</a><br><br>",
+ "This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "יישום זה דורש JavaScript לפעולה נכונה. יש {linkstart}לאפשר JavaScript{linkend} ולטעון את העמוד מחדש.",
"Log out" : "התנתקות",
"Search" : "חיפוש",
+ "Server side authentication failed!" : "אימות לצד שרת נכשל!",
+ "Please contact your administrator." : "יש ליצור קשר עם המנהל.",
+ "An internal error occured." : "שגיאה פנימית אירעה.",
+ "Please try again or contact your administrator." : "יש לנסות שוב ליצור קשר עם המנהל שלך.",
"Log in" : "כניסה",
- "Alternative Logins" : "כניסות אלטרנטיביות"
+ "Wrong password. Reset it?" : "סיסמא שגוייה. האם לאפס אותה?",
+ "Wrong password." : "סיסמא שגוייה.",
+ "Stay logged in" : "השאר מחובר",
+ "Alternative Logins" : "כניסות אלטרנטיביות",
+ "Use the following link to reset your password: {link}" : "יש להשתמש בקישור הבא כדי לאפס את הססמה שלך: {link}",
+ "New password" : "ססמה חדשה",
+ "New Password" : "סיסמא חדשה",
+ "Reset password" : "איפוס ססמה",
+ "This ownCloud instance is currently in single user mode." : "הפעלת ownCloud זו עובדת כרגע במצב של משתמש יחיד.",
+ "This means only administrators can use the instance." : "לפיכך רק מנהלים יכולים להשתמש בהפעלה זו.",
+ "Contact your system administrator if this message persists or appeared unexpectedly." : "יש ליצור קשר עם מנהל המערכת אם הודעה שו נמשכת או מופיעה באופן בלתי צפוי. ",
+ "Thank you for your patience." : "תודה על הסבלנות.",
+ "You are accessing the server from an untrusted domain." : "נכנסת לשרת משם מתחם / דומיין שאינו מהימן.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "יש ליצור קשר עם המנהל שלך. אם הנך המנהל של הפעלה זו, יש להגדיר את הגדרות ה- \"trusted_domains\" של config/config.php. דוגמת תצורה ניתן לראות ב- config/config.sample.php.",
+ "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "בהתאם לתצורה שלך, כמנהל יתכן ותוכל להשתמש בכפתור מטה להפיכת שם המתחם / דומיין למהימן.",
+ "Add \"%s\" as trusted domain" : "הוספת \"%s\" כשם מתחם / דומיין מהימן",
+ "App update required" : "נדרש עדכון יישום",
+ "%s will be updated to version %s" : "%s יעודכן לגרסה %s",
+ "These apps will be updated:" : "יישומים אלו יעודכנו:",
+ "These incompatible apps will be disabled:" : "יישומים לא תואמים ינוטרלו:",
+ "The theme %s has been disabled." : "ערכת הנושא %s נוטרלה.",
+ "Please make sure that the database, the config folder and the data folder have been backed up before proceeding." : "יש לוודא שמסד הנתונים, תיקיית config ותיקיית data גובו לפני ההמשך.",
+ "Start update" : "התחלת עדכון",
+ "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "למניעת פסקי זמן בהתקנות גדולות, ניתן במקום להריץ את הפקודה הבאה בתיקיית ההתקנה שלך:",
+ "This %s instance is currently in maintenance mode, which may take a while." : "הפעלה %s זו כרגע במצב אחזקה, שתמשך זמן מה.",
+ "This page will refresh itself when the %s instance is available again." : "עמוד זה ירענן את עצמו כשהפעלת %s תהיה זמינה שוב."
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/he.json b/core/l10n/he.json
index 02c333c21d1..9e25f9895d1 100644
--- a/core/l10n/he.json
+++ b/core/l10n/he.json
@@ -1,4 +1,44 @@
{ "translations": {
+ "Couldn't send mail to following users: %s " : "לא ניתן היה לשלוח דואר אלקטרוני למשתמשים הבאים %s ",
+ "Preparing update" : "מכין עדכון",
+ "Turned on maintenance mode" : "הפעלת מצב אחזקה",
+ "Turned off maintenance mode" : "כיבוי מצב אחזקה",
+ "Maintenance mode is kept active" : "מצב אחזקה נשמר פעיל",
+ "Updating database schema" : "עדכון סכימת מסד נתונים",
+ "Updated database" : "עדכון מסד נתונים",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "בודק אם סכימת מסד הנתונים ניתנת לעדכון (פעולה זו יכולה להמשך זמן רב תלוי בגודל מסד הנתונים)",
+ "Checked database schema update" : "עדכון סכימת מסד נתונים נבדק",
+ "Checking updates of apps" : "בדיקת עדכוני יישומים",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "בודק אם סכימת מסד הנתונים עבור %s ניתנת לעדכון (פעולה זו יכולה להמשך זמן רב תלוי בגודל מסד הנתונים)",
+ "Checked database schema update for apps" : "עדכון סכימת מסד נתונים ליישומים נבדק",
+ "Updated \"%s\" to %s" : "מעדכן \"%s\" ל- %s",
+ "Repair warning: " : "אזהרת תיקון:",
+ "Repair error: " : "שגיאת תיקון:",
+ "Set log level to debug" : "קביעת רמת דיווח לתהליך ניפוי בשגיאות",
+ "Reset log level" : "קביעה מחדש לרמת דיווח",
+ "Starting code integrity check" : "התחלת בדיקת תקינות קוד",
+ "Finished code integrity check" : "סיום בדיקת תקינות קוד",
+ "%s (3rdparty)" : "%s (צד שלישי)",
+ "%s (incompatible)" : "%s (לא תואם)",
+ "Following apps have been disabled: %s" : "היישומים הבאים נוטרלו: %s",
+ "Already up to date" : "כבר עדכני",
+ "Please select a file." : "יש לבחור קובץ.",
+ "File is too big" : "הקובץ גדול מדי",
+ "Invalid file provided" : "סופק קובץ לא חוקי",
+ "No image or file provided" : "לא סופקו תמונה או קובץ",
+ "Unknown filetype" : "סוג קובץ לא מוכר",
+ "Invalid image" : "תמונה לא חוקית",
+ "An error occurred. Please contact your admin." : "אירעה שגיאה. יש ליצור קשר עם המנהל שלך.",
+ "No temporary profile picture available, try again" : "לא קיימת תמונת פרופיל זמנית, יש לנסות שוב",
+ "No crop data provided" : "לא סופק מידע קיטום",
+ "No valid crop data provided" : "לא סופק מידע קיטום חוקי",
+ "Crop is not square" : "הקיטום אינו מרובע",
+ "Couldn't reset password because the token is invalid" : "לא ניתן לאפס סיסמא כיוון שמחרוזת האימות אינה חוקית",
+ "Couldn't reset password because the token is expired" : "לא ניתן לאפס סיסמא כיוון שמחרוזת האימות פגה תוקף",
+ "Couldn't send reset email. Please make sure your username is correct." : "לא ניתן היה לשלוח דואר אלקטרוני לאיפוס. יש לוודא ששם המשתמש נכון.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "לא ניתן היה לשלוח דואר אלקטרוני כיוון שלא מוגדר דואר אלקטרוני למשתמש זה. יש ליצור קשר עם מנהל.",
+ "%s password reset" : "%s הסיסמא אופסה",
+ "Couldn't send reset email. Please contact your administrator." : "לא ניתן היה לשלוח דואר אלקטרוני לאיפוס. יש לפנות למנהל שלך.",
"Sunday" : "יום ראשון",
"Monday" : "יום שני",
"Tuesday" : "יום שלישי",
@@ -13,6 +53,13 @@
"Thu." : "חמישי",
"Fri." : "שישי",
"Sat." : "שבת",
+ "Su" : "א",
+ "Mo" : "ב",
+ "Tu" : "ג",
+ "We" : "ד",
+ "Th" : "ה",
+ "Fr" : "ו",
+ "Sa" : "ש",
"January" : "ינואר",
"February" : "פברואר",
"March" : "מרץ",
@@ -37,70 +84,214 @@
"Oct." : "אוק׳",
"Nov." : "נוב׳",
"Dec." : "דצמ׳",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">קיימות בעיות עם בדיקת תקינות קוד. למידע נוסף…</a>",
"Settings" : "הגדרות",
"Saving..." : "שמירה…",
"seconds ago" : "שניות",
+ "The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "הקישור לאיפוס הסיסמא שלך נשלח אליך בדואר אלקטרוני. אם לא קיבלת את הקישור תוך זמן סביר, מוטב לבדוק את תיבת דואר הזבל/ספאם שלך.<br>אם ההודעה אינה שם, יש לשאול את המנהל המקומי שלך .",
+ "Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "הקבצים שלך מוצפנים. אם לא הפעלת את מפתח השחזור, לא תהיה דרך לקבל את המידע מחדש אחרי שהסיסמא תאופס.<br />אם אין לך מושג מה לעשות what to do, מוטב לפנות למנהל שלך לפני ההמשך. <br />האם באמת ברצונך להמשיך?",
+ "I know what I'm doing" : "אני יודע/ת מה אני עושה",
+ "Password can not be changed. Please contact your administrator." : "לא ניתן לשנות את הסיסמא. יש לפנות למנהל שלך.",
"No" : "לא",
"Yes" : "כן",
"Choose" : "בחירה",
+ "Error loading file picker template: {error}" : "שגיאה בטעינת תבנית בחירת הקבצים: {error}",
"Ok" : "בסדר",
+ "Error loading message template: {error}" : "שגיאה בטעינת תבנית ההודעות: {error}",
+ "read-only" : "לקריאה בלבד",
+ "_{count} file conflict_::_{count} file conflicts_" : ["{count} הנגשות קובץ","{count} התנגשויות קבצים"],
+ "One file conflict" : "התנגשות קובץ אחת",
"New Files" : "קבצים חדשים",
+ "Already existing files" : "קבצים קיימים כבר",
+ "Which files do you want to keep?" : "אילו קבצים ברצונך לשמור?",
+ "If you select both versions, the copied file will have a number added to its name." : "אם תבחר האפשרות לשמור את שתי הגרסאות, לשם קובץ המועתק יתווסף מספר.",
"Cancel" : "ביטול",
+ "Continue" : "המשך",
+ "(all selected)" : "(הכול נבחר)",
+ "({count} selected)" : "({count} נבחרו)",
+ "Error loading file exists template" : "שגיאה בטעינת קובץ תבנית קיימים",
+ "Very weak password" : "סיסמא מאוד חלשה",
+ "Weak password" : "סיסמא חלשה",
+ "So-so password" : "סיסמא ככה-ככה",
+ "Good password" : "סיסמא טובה",
+ "Strong password" : "סיסמא חזקה",
+ "Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "שרת האינטרנט שלך אינו מוגדר כהלכה לאפשר סנכרון כיוון שממשק ה־WebDAV כנראה שבור.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "שרת האינטרנט שלך לא מוגדר כהלכה לפתור \"{url}\". מידע נוסף קיים <a target=\"_blank\" href=\"{docLink}\">במסמכים</a> שלנו.",
+ "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "לשרת זה אין חיבור אינטרנט פעיל. לפיכך חלק מהתכונות כגון עגינת אחסון חיצוני, הודעות על עדכונים או התקנת יישומי צד שלישי לא יעבדו. ייתכן ולא יעבדו גם כניסה לקבצים מבחוץ ושליחת הודעות דואר אלקטרוני. אנו ממליצים לאפשר חיבור אינטרנט לשרת זה אם ברצונך שיהיו לך את כל התכונות.",
+ "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "כנראה וניתן לגשת אל תיקיית data והקבצים שלך מהאינטרנט. קובץ .htaccess אינו עובד. אנו ממליצים בכל תוקף שתגדיר את השרת בצורה כזאת שלא ניתן יהיה לגשת לתיקיית ה- data או להעביר את תיקיית ה- dta מחוץ לנתיב המסמכים של שרת האינטרנט.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "לא הוגדר memory cache. על מנת לשפר את הביצועים יש להגדיר memcache אם קיים. מידע נוסף ניתן לצפות ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom אינו ניתן לקריאה על ידי PHP אשר אינו מומלץ בשל סיבות אבטחה. מידע נוסף ניתן לראות ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "גרסת ה- PHP שלך ({version}) אינה <a target=\"_blank\" href=\"{phpLink}\">נתמכת כבר על ידי PHP</a>. אנו ממליצים לשדרג את גרסת ה- PHP ולהנות מהיתרון של עדכוני האבטחה והביצועים שמספק ה- PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "תצורת כותרות פרוקסי ההפוכה אינה נכונה, או שהגישה ל- ownCloud מתבצעת מ- proxy אמין. אם הגישה ל- ownCloud אינה מ- proxy אמין, מדובר בבעיית אבטחה שמאפשרת לתוקף לזיין את כתובת ה- IP כגלויה ל- ownCloud. מידע נוסף ניתן למצוא ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a> שלנו.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached מוגדר כמטמון מופץ, אבל מותקן מודול PHP לא נכון \"memcache\". רק \\OC\\Memcache\\Memcached תומך ב- \"memcached\" אבל לא ב- \"memcache\". ניתן לצפות ב- <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki בנושא שני המודולים</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "חלק מהקבצים לא עברו את בדיקת התקינות. מידע נוסף איך לפתור את הבעיה ניתן למצוא ב- to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a> שלנו. (<a href=\"{codeIntegrityDownloadEndpoint}\">רשימה של קבצים לא תקינים…</a> / <a href=\"{rescanEndpoint}\">סריקה מחדש…</a>)",
+ "Error occurred while checking server setup" : "שגיאה אירעה בזמן בדיקת התקנת השרת",
+ "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "כותרת ה- HTTP \"{header}\" אינה מוגדרת להיות שווה ל- \"{expected}\". הדבר מהווה פוטנציאל סיכון אבטחה או פגיעה בפרטיות ואנו ממליצים לתקן את הגדרה זו.",
+ "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "כותרת HTTP \"Strict-Transport-Security\" אינה מוגדרת לפחות \"{seconds}\" שניות. להגברת האבטחה אנו ממליצים לאפשר HSTS כפי שמוסבר ב- <a href=\"{docUrl}\">טיפים לאבטחה</a> שלנו.",
+ "You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "הנך נכנס לאתר באמצעות פרוטוקול HTTP. אנו ממליצים מאוד להגדיר את השרת לעבוד עם פרוטוקול HTTPS במקום כפי שמוסבר ב- <a href=\"{docUrl}\">טיפים לאבטחה</a> שלנו.",
"Shared" : "שותף",
+ "Shared with {recipients}" : "שיתוף עם {recipients}",
"Error" : "שגיאה",
"Error while sharing" : "שגיאה במהלך השיתוף",
"Error while unsharing" : "שגיאה במהלך ביטול השיתוף",
- "Error while changing permissions" : "שגיאה במהלך שינוי ההגדרות",
"Error setting expiration date" : "אירעה שגיאה בעת הגדרת תאריך התפוגה",
+ "The public link will expire no later than {days} days after it is created" : "הקישור הציבורי יפוג עד {days} ימים לאחר שנוצר",
"Set expiration date" : "הגדרת תאריך תפוגה",
+ "Expiration" : "תפוגה",
"Expiration date" : "תאריך התפוגה",
+ "Choose a password for the public link" : "בחירת סיסמא לקישור ציבורי",
"Sending ..." : "מתבצעת שליחה ...",
"Email sent" : "הודעת הדוא״ל נשלחה",
"Resharing is not allowed" : "אסור לעשות שיתוף מחדש",
"Share link" : "קישור לשיתוף",
+ "Link" : "קישור",
"Password protect" : "הגנה בססמה",
"Password" : "סיסמא",
+ "Allow editing" : "אישור עריכה",
"Email link to person" : "שליחת קישור בדוא״ל למשתמש",
"Send" : "שליחה",
"Shared with you and the group {group} by {owner}" : "שותף אתך ועם הקבוצה {group} שבבעלות {owner}",
"Shared with you by {owner}" : "שותף אתך על ידי {owner}",
- "Shared in {item} with {user}" : "שותף תחת {item} עם {user}",
"group" : "קבוצה",
+ "remote" : "נשלט מרחוק",
+ "notify by email" : "קבלת הודעה בדואר אלקטרוני",
"Unshare" : "הסר שיתוף",
"can share" : "ניתן לשתף",
"can edit" : "ניתן לערוך",
"create" : "יצירה",
+ "change" : "שינוי",
"delete" : "מחיקה",
"access control" : "בקרת גישה",
+ "Could not unshare" : "לא ניתן לבטל שיתוף",
+ "Share details could not be loaded for this item." : "לא ניתן היה לטעון מידע שיתוף לפריט זה",
+ "An error occured. Please try again" : "אירעה שגיאה. יש לנסות בבקשה שוב",
"Share" : "שתף",
+ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "ניתן לשתף עם אנשים אחרים המשתמשים ב- ownClouds בעזרת הפורמט הבא username@example.com/owncloud",
+ "Share with users or groups …" : "שיתוף עם משתמשים או קבוצות...",
+ "Share with users, groups or remote users …" : "שיתוף עם משתמשים, קבוצות או משתמשים חצוניים...",
+ "Error removing share" : "שגיאה בזמן הסרת שיתוף",
"Warning" : "אזהרה",
- "The object type is not specified." : "סוג הפריט לא צוין.",
+ "Error while sending notification" : "שגיאה בזמן שליחת הודעה",
+ "Non-existing tag #{tag}" : "תגית לא קיימת #{tag}",
+ "not assignable" : "לא ניתן להקצאה",
+ "invisible" : "בלתי גלוי",
+ "({scope})" : "({scope})",
"Delete" : "מחיקה",
+ "Rename" : "שינוי שם",
+ "Global tags" : "תגיות גלובליות",
+ "The object type is not specified." : "סוג הפריט לא צוין.",
+ "Enter new" : "הכנסת חדש",
"Add" : "הוספה",
+ "Edit tags" : "עריכת תגים",
+ "Error loading dialog template: {error}" : "שגיאה בזמן טעינת תבנית דיאלוג: {error}",
+ "No tags selected for deletion." : "לא סומנו תגים למחיקה.",
+ "unknown text" : "מלל לא מוכר",
+ "Hello world!" : "שלום עולם!",
+ "sunny" : "שמשי",
+ "Hello {name}, the weather is {weather}" : "שלום {name}, מזג האוויר הנו {weather}",
+ "Hello {name}" : "שלום {name}",
+ "_download %n file_::_download %n files_" : ["הורד %n קובץ","הורדו %n קבצים"],
+ "{version} is available. Get more information on how to update." : "{version} זמינה. ניתן לקבל מידע נוסף על איך לעדכן.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "מתבצע עכשיו שדרוג, מעבר מדף זה עלול לפגוע בתהליך בסביבות הפעלה מסויימות.",
+ "Updating {productName} to version {version}, this may take a while." : "מעדכן {productName} לגרסה {version}, זה יקח זמן מה.",
+ "An error occurred." : "אירעה שגיאה.",
+ "Please reload the page." : "יש להעלות מחדש דף זה.",
+ "The update was unsuccessful. " : "העדכון בוצע בהצלחה.",
+ "The update was successful. There were warnings." : "העדכון בוצע בהצלחה. היו הזהרות.",
"The update was successful. Redirecting you to ownCloud now." : "תהליך העדכון הסתיים בהצלחה. עכשיו מנתב אותך אל ownCloud.",
- "Use the following link to reset your password: {link}" : "יש להשתמש בקישור הבא כדי לאפס את הססמה שלך: {link}",
- "New password" : "ססמה חדשה",
- "Reset password" : "איפוס ססמה",
+ "Searching other places" : "מחפש במקומות אחרים",
+ "No search results in other folders" : "אין תוצאות חיפוש בתיקיות אחרות",
+ "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} תוצאת חיפוש בתיקייה אחרות","{count} תוצאות חיפוש בתיקיות אחרות"],
"Personal" : "אישי",
"Users" : "משתמשים",
"Apps" : "יישומים",
"Admin" : "מנהל",
"Help" : "עזרה",
+ "Error loading tags" : "שגיאה בטעינת תגיות",
+ "Tag already exists" : "תגית כבר קיימת",
+ "Error deleting tag(s)" : "שגיאה במחיקת תגית(יות)",
+ "Error tagging" : "שגיאה בביצוע תגיות",
+ "Error untagging" : "שגיאה בהסרת תגיות",
+ "Error favoriting" : "שגיאה בקביעת מועדפים",
+ "Error unfavoriting" : "שגיאה בהסרת מועדפים",
"Access forbidden" : "הגישה נחסמה",
+ "File not found" : "קובץ לא נמצא",
+ "The specified document has not been found on the server." : "המסמך המבוקש לא נמצא על השרת.",
+ "You can click here to return to %s." : "ניתן ללחוץ כאן לחזרה אל %s.",
+ "Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\n" : "שלום רב,\n\nרצינו לעדכן אותך ש- %s שיתף/שיתפה %s איתך.\nניתן לצפות בשיתוף כאן: %s\n\n",
+ "The share will expire on %s." : "השיתוף יפוג תוקף ב- %s.",
+ "Cheers!" : "לחיים!",
+ "Internal Server Error" : "שגיאה פנימית בשרת",
+ "The server encountered an internal error and was unable to complete your request." : "השרת נתקל בשגיאה פנימית ולא הצליח לסיים את הבקשה שלך.",
+ "Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "יש ליצור קשר עם מנהל השרת אם שגיאה זו חוזרת מספר פעמים, יש לצרף לדיווח את הפרטים הטכניים למטה.",
+ "More details can be found in the server log." : "פרטים נוספים ניתן למצוא בלוג של הרשת.",
+ "Technical details" : "פרטים טכנים",
+ "Remote Address: %s" : "כתובת מרוחקת: %s",
+ "Request ID: %s" : "מספר זיהוי מבוקש: %s",
+ "Type: %s" : "סוג: %s",
+ "Code: %s" : "קוד: %s",
+ "Message: %s" : "הודעה: %s",
+ "File: %s" : "קובץ: %s",
+ "Line: %s" : "שורה: %s",
+ "Trace" : "עקבות",
+ "Security warning" : "אזהרת אבטחה",
"Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "תיקיית וקבצי המידע שלך כנראה נגישים מהאינטרנט מכיוון שקובץ ה.htaccess לא עובד.",
+ "For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "למידע איך להגדיר את השרת שלך, ניתן לראות ב- <a href=\"%s\" target=\"_blank\">מסמכי התיעוד</a>.",
"Create an <strong>admin account</strong>" : "יצירת <strong>חשבון מנהל</strong>",
"Username" : "שם משתמש",
+ "Storage & database" : "אחסון ומסד נתונים",
"Data folder" : "תיקיית נתונים",
"Configure the database" : "הגדרת מסד הנתונים",
+ "Only %s is available." : "רק %s זמין.",
+ "Install and activate additional PHP modules to choose other database types." : "לבחירת סוגים אחרים של מסדי נתונים יש להתקין ולהפעיל מודולי PHP נוספים.",
+ "For more details check out the documentation." : "למידע נוסף יש לבדוק במסמכי התיעוד.",
"Database user" : "שם משתמש במסד הנתונים",
"Database password" : "ססמת מסד הנתונים",
"Database name" : "שם מסד הנתונים",
"Database tablespace" : "מרחב הכתובות של מסד הנתונים",
"Database host" : "שרת בסיס נתונים",
+ "Performance warning" : "אזהרת ביצועים",
+ "SQLite will be used as database." : "יעשה שימוש ב- SQLite כמסד נתונים.",
+ "For larger installations we recommend to choose a different database backend." : "להתקנות נרחבות אנו ממליצים לבחור מסד נתונים אחר לצד השרת.",
+ "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "במיוחד כאשר משתמשים במחשב שולחני לסנכרון קבצים השימוש ב SQLite אינו מומלץ.",
"Finish setup" : "סיום התקנה",
+ "Finishing …" : "מסיים...",
+ "Need help?" : "עזרה נזקקת?",
+ "See the documentation" : "יש לצפות במסמכי התיעוד",
+ "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "הי לך,<br><br>כדאי לך לדעת ש- %s משתף/פת <strong>%s</strong> אתך.<br><a href=\"%s\">לצפייה!</a><br><br>",
+ "This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "יישום זה דורש JavaScript לפעולה נכונה. יש {linkstart}לאפשר JavaScript{linkend} ולטעון את העמוד מחדש.",
"Log out" : "התנתקות",
"Search" : "חיפוש",
+ "Server side authentication failed!" : "אימות לצד שרת נכשל!",
+ "Please contact your administrator." : "יש ליצור קשר עם המנהל.",
+ "An internal error occured." : "שגיאה פנימית אירעה.",
+ "Please try again or contact your administrator." : "יש לנסות שוב ליצור קשר עם המנהל שלך.",
"Log in" : "כניסה",
- "Alternative Logins" : "כניסות אלטרנטיביות"
+ "Wrong password. Reset it?" : "סיסמא שגוייה. האם לאפס אותה?",
+ "Wrong password." : "סיסמא שגוייה.",
+ "Stay logged in" : "השאר מחובר",
+ "Alternative Logins" : "כניסות אלטרנטיביות",
+ "Use the following link to reset your password: {link}" : "יש להשתמש בקישור הבא כדי לאפס את הססמה שלך: {link}",
+ "New password" : "ססמה חדשה",
+ "New Password" : "סיסמא חדשה",
+ "Reset password" : "איפוס ססמה",
+ "This ownCloud instance is currently in single user mode." : "הפעלת ownCloud זו עובדת כרגע במצב של משתמש יחיד.",
+ "This means only administrators can use the instance." : "לפיכך רק מנהלים יכולים להשתמש בהפעלה זו.",
+ "Contact your system administrator if this message persists or appeared unexpectedly." : "יש ליצור קשר עם מנהל המערכת אם הודעה שו נמשכת או מופיעה באופן בלתי צפוי. ",
+ "Thank you for your patience." : "תודה על הסבלנות.",
+ "You are accessing the server from an untrusted domain." : "נכנסת לשרת משם מתחם / דומיין שאינו מהימן.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "יש ליצור קשר עם המנהל שלך. אם הנך המנהל של הפעלה זו, יש להגדיר את הגדרות ה- \"trusted_domains\" של config/config.php. דוגמת תצורה ניתן לראות ב- config/config.sample.php.",
+ "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "בהתאם לתצורה שלך, כמנהל יתכן ותוכל להשתמש בכפתור מטה להפיכת שם המתחם / דומיין למהימן.",
+ "Add \"%s\" as trusted domain" : "הוספת \"%s\" כשם מתחם / דומיין מהימן",
+ "App update required" : "נדרש עדכון יישום",
+ "%s will be updated to version %s" : "%s יעודכן לגרסה %s",
+ "These apps will be updated:" : "יישומים אלו יעודכנו:",
+ "These incompatible apps will be disabled:" : "יישומים לא תואמים ינוטרלו:",
+ "The theme %s has been disabled." : "ערכת הנושא %s נוטרלה.",
+ "Please make sure that the database, the config folder and the data folder have been backed up before proceeding." : "יש לוודא שמסד הנתונים, תיקיית config ותיקיית data גובו לפני ההמשך.",
+ "Start update" : "התחלת עדכון",
+ "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "למניעת פסקי זמן בהתקנות גדולות, ניתן במקום להריץ את הפקודה הבאה בתיקיית ההתקנה שלך:",
+ "This %s instance is currently in maintenance mode, which may take a while." : "הפעלה %s זו כרגע במצב אחזקה, שתמשך זמן מה.",
+ "This page will refresh itself when the %s instance is available again." : "עמוד זה ירענן את עצמו כשהפעלת %s תהיה זמינה שוב."
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/hi.js b/core/l10n/hi.js
index b6106eaf867..df717fd1ac5 100644
--- a/core/l10n/hi.js
+++ b/core/l10n/hi.js
@@ -31,8 +31,6 @@ OC.L10N.register(
"Share" : "साझा करें",
"Warning" : "चेतावनी ",
"Add" : "डाले",
- "Use the following link to reset your password: {link}" : "आगे दिये गये लिंक का उपयोग पासवर्ड बदलने के लिये किजीये: {link}",
- "New password" : "नया पासवर्ड",
"Personal" : "यक्तिगत",
"Users" : "उपयोगकर्ता",
"Apps" : "Apps",
@@ -45,6 +43,8 @@ OC.L10N.register(
"Database password" : "डेटाबेस पासवर्ड",
"Database name" : "डेटाबेस का नाम",
"Finish setup" : "सेटअप समाप्त करे",
- "Log out" : "लोग आउट"
+ "Log out" : "लोग आउट",
+ "Use the following link to reset your password: {link}" : "आगे दिये गये लिंक का उपयोग पासवर्ड बदलने के लिये किजीये: {link}",
+ "New password" : "नया पासवर्ड"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/hi.json b/core/l10n/hi.json
index 206baee03e9..877b65381a7 100644
--- a/core/l10n/hi.json
+++ b/core/l10n/hi.json
@@ -29,8 +29,6 @@
"Share" : "साझा करें",
"Warning" : "चेतावनी ",
"Add" : "डाले",
- "Use the following link to reset your password: {link}" : "आगे दिये गये लिंक का उपयोग पासवर्ड बदलने के लिये किजीये: {link}",
- "New password" : "नया पासवर्ड",
"Personal" : "यक्तिगत",
"Users" : "उपयोगकर्ता",
"Apps" : "Apps",
@@ -43,6 +41,8 @@
"Database password" : "डेटाबेस पासवर्ड",
"Database name" : "डेटाबेस का नाम",
"Finish setup" : "सेटअप समाप्त करे",
- "Log out" : "लोग आउट"
+ "Log out" : "लोग आउट",
+ "Use the following link to reset your password: {link}" : "आगे दिये गये लिंक का उपयोग पासवर्ड बदलने के लिये किजीये: {link}",
+ "New password" : "नया पासवर्ड"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/hr.js b/core/l10n/hr.js
index 6bb9356a76b..789b9ff8745 100644
--- a/core/l10n/hr.js
+++ b/core/l10n/hr.js
@@ -13,6 +13,10 @@ OC.L10N.register(
"Invalid image" : "Slika neispravna",
"No temporary profile picture available, try again" : "Slike privremenih profila nisu dostupne, pokušajte ponovno",
"No crop data provided" : "Nema podataka o obrezivanju",
+ "Couldn't reset password because the token is invalid" : "Resetiranje lozinke nije moguće jer je token neispravan.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Resetiranu e-poštu nije moguće poslati.Molimo provjerite ispravnost svoga korisničkog imena.",
+ "%s password reset" : "%s lozinka resetirana",
+ "Couldn't send reset email. Please contact your administrator." : "Nije mogće poslati resetiranu poštu. MOlimo kontaktirajte svog administratora.",
"Sunday" : "Nedjelja",
"Monday" : "Ponedjeljak",
"Tuesday" : "Utorak",
@@ -54,7 +58,6 @@ OC.L10N.register(
"Settings" : "Postavke",
"Saving..." : "Spremanje...",
"seconds ago" : "prije par sekundi",
- "Couldn't send reset email. Please contact your administrator." : "Nije mogće poslati resetiranu poštu. MOlimo kontaktirajte svog administratora.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Veza za resetiranje vaše lozinke poslana je na vašu adresu e-pošte. Ako je ne primite unekom razumnom vremenskom roku, provjerite svoje spam/junk mape. <br> Ako nije tamo, kontaktirajtesvoga lokalnog administratora.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vaše datoteke su šifrirane. Ako niste aktivirali ključ oporavka,svoje podatke nećete moći dohvatitinakon što vaša lozinka bude resetirana.<br />Ako ne znate što učiniti, prije nego linastavite, molimo kontaktirajte svog administratora. <br />Želite li doista nastaviti?",
"I know what I'm doing" : "Znam što radim",
@@ -88,7 +91,6 @@ OC.L10N.register(
"Error" : "Pogreška",
"Error while sharing" : "Pogreška pri dijeljenju",
"Error while unsharing" : "Pogreška pri prestanku dijeljenja",
- "Error while changing permissions" : "POgreška pri mijenjanju dozvola",
"Error setting expiration date" : "Pogrešno učitavanje postavke datuma isteka",
"The public link will expire no later than {days} days after it is created" : " Javna veza ističe najkasnije {days} dana nakon što je kreirana",
"Set expiration date" : "Odredite datum isteka",
@@ -107,7 +109,6 @@ OC.L10N.register(
"Send" : "Pošaljite",
"Shared with you and the group {group} by {owner}" : "Dijeljeno s vama i grupom {group} vlasnika {owner}",
"Shared with you by {owner}" : "S vama podijelio {owner}",
- "Shared in {item} with {user}" : "Podijeljeno u {item} sa {user}",
"group" : "Grupa",
"remote" : "na daljinu",
"notify by email" : "Obavijestite e-poštom",
@@ -124,9 +125,10 @@ OC.L10N.register(
"Share with users or groups …" : "Podijeli sa korisnicima ili grupama ...",
"Share with users, groups or remote users …" : "Podijeli sa korisnicima, grupama ili udaljenim korisnicima ...",
"Warning" : "Upozorenje",
+ "Delete" : "Izbrišite",
+ "Rename" : "Preimenujte",
"The object type is not specified." : "Vrsta objekta nije specificirana.",
"Enter new" : "Unesite novi",
- "Delete" : "Izbrišite",
"Add" : "Dodajte",
"Edit tags" : "Uredite oznake",
"Error loading dialog template: {error}" : "Pogrešno učitavanje predloška dijaloga: {error}",
@@ -141,14 +143,6 @@ OC.L10N.register(
"Please reload the page." : "Molimo, ponovno učitajte stranicu",
"The update was unsuccessful. " : "Usklađivanje je bilo neuspješno.",
"The update was successful. Redirecting you to ownCloud now." : "Ažuriranje je uspjelo. Upravo ste preusmjeravani na ownCloud.",
- "Couldn't reset password because the token is invalid" : "Resetiranje lozinke nije moguće jer je token neispravan.",
- "Couldn't send reset email. Please make sure your username is correct." : "Resetiranu e-poštu nije moguće poslati.Molimo provjerite ispravnost svoga korisničkog imena.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Resetiranu e-poštu nije moguće poslati jer za ovo korisničko ime ne postoji adresa.Molimo, kontaktirajte svog administratora.",
- "%s password reset" : "%s lozinka resetirana",
- "Use the following link to reset your password: {link}" : "Za resetiranje svoje lozinke koristite sljedeću vezu: {link}",
- "New password" : "Nova lozinka",
- "New Password" : "Nova lozinka",
- "Reset password" : "Resetirajte lozinku",
"Searching other places" : "Pretraživanje drugih lokacija",
"Personal" : "Osobno",
"Users" : "Korisnici",
@@ -203,6 +197,10 @@ OC.L10N.register(
"Please contact your administrator." : "Molimo kontaktirajte svog administratora.",
"Log in" : "Prijavite se",
"Alternative Logins" : "Alternativne prijave",
+ "Use the following link to reset your password: {link}" : "Za resetiranje svoje lozinke koristite sljedeću vezu: {link}",
+ "New password" : "Nova lozinka",
+ "New Password" : "Nova lozinka",
+ "Reset password" : "Resetirajte lozinku",
"This ownCloud instance is currently in single user mode." : "Ova ownCloud instanca je trenutno u načinu rada za jednog korisnika.",
"This means only administrators can use the instance." : "To znači da tu instancu mogu koristiti samo administratori.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktirajte svog administratora sustava ako se ova poruka ponavlja ili sepojavila neočekivano.",
diff --git a/core/l10n/hr.json b/core/l10n/hr.json
index 3e64259428c..d3a2ce6a0a4 100644
--- a/core/l10n/hr.json
+++ b/core/l10n/hr.json
@@ -11,6 +11,10 @@
"Invalid image" : "Slika neispravna",
"No temporary profile picture available, try again" : "Slike privremenih profila nisu dostupne, pokušajte ponovno",
"No crop data provided" : "Nema podataka o obrezivanju",
+ "Couldn't reset password because the token is invalid" : "Resetiranje lozinke nije moguće jer je token neispravan.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Resetiranu e-poštu nije moguće poslati.Molimo provjerite ispravnost svoga korisničkog imena.",
+ "%s password reset" : "%s lozinka resetirana",
+ "Couldn't send reset email. Please contact your administrator." : "Nije mogće poslati resetiranu poštu. MOlimo kontaktirajte svog administratora.",
"Sunday" : "Nedjelja",
"Monday" : "Ponedjeljak",
"Tuesday" : "Utorak",
@@ -52,7 +56,6 @@
"Settings" : "Postavke",
"Saving..." : "Spremanje...",
"seconds ago" : "prije par sekundi",
- "Couldn't send reset email. Please contact your administrator." : "Nije mogće poslati resetiranu poštu. MOlimo kontaktirajte svog administratora.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Veza za resetiranje vaše lozinke poslana je na vašu adresu e-pošte. Ako je ne primite unekom razumnom vremenskom roku, provjerite svoje spam/junk mape. <br> Ako nije tamo, kontaktirajtesvoga lokalnog administratora.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vaše datoteke su šifrirane. Ako niste aktivirali ključ oporavka,svoje podatke nećete moći dohvatitinakon što vaša lozinka bude resetirana.<br />Ako ne znate što učiniti, prije nego linastavite, molimo kontaktirajte svog administratora. <br />Želite li doista nastaviti?",
"I know what I'm doing" : "Znam što radim",
@@ -86,7 +89,6 @@
"Error" : "Pogreška",
"Error while sharing" : "Pogreška pri dijeljenju",
"Error while unsharing" : "Pogreška pri prestanku dijeljenja",
- "Error while changing permissions" : "POgreška pri mijenjanju dozvola",
"Error setting expiration date" : "Pogrešno učitavanje postavke datuma isteka",
"The public link will expire no later than {days} days after it is created" : " Javna veza ističe najkasnije {days} dana nakon što je kreirana",
"Set expiration date" : "Odredite datum isteka",
@@ -105,7 +107,6 @@
"Send" : "Pošaljite",
"Shared with you and the group {group} by {owner}" : "Dijeljeno s vama i grupom {group} vlasnika {owner}",
"Shared with you by {owner}" : "S vama podijelio {owner}",
- "Shared in {item} with {user}" : "Podijeljeno u {item} sa {user}",
"group" : "Grupa",
"remote" : "na daljinu",
"notify by email" : "Obavijestite e-poštom",
@@ -122,9 +123,10 @@
"Share with users or groups …" : "Podijeli sa korisnicima ili grupama ...",
"Share with users, groups or remote users …" : "Podijeli sa korisnicima, grupama ili udaljenim korisnicima ...",
"Warning" : "Upozorenje",
+ "Delete" : "Izbrišite",
+ "Rename" : "Preimenujte",
"The object type is not specified." : "Vrsta objekta nije specificirana.",
"Enter new" : "Unesite novi",
- "Delete" : "Izbrišite",
"Add" : "Dodajte",
"Edit tags" : "Uredite oznake",
"Error loading dialog template: {error}" : "Pogrešno učitavanje predloška dijaloga: {error}",
@@ -139,14 +141,6 @@
"Please reload the page." : "Molimo, ponovno učitajte stranicu",
"The update was unsuccessful. " : "Usklađivanje je bilo neuspješno.",
"The update was successful. Redirecting you to ownCloud now." : "Ažuriranje je uspjelo. Upravo ste preusmjeravani na ownCloud.",
- "Couldn't reset password because the token is invalid" : "Resetiranje lozinke nije moguće jer je token neispravan.",
- "Couldn't send reset email. Please make sure your username is correct." : "Resetiranu e-poštu nije moguće poslati.Molimo provjerite ispravnost svoga korisničkog imena.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Resetiranu e-poštu nije moguće poslati jer za ovo korisničko ime ne postoji adresa.Molimo, kontaktirajte svog administratora.",
- "%s password reset" : "%s lozinka resetirana",
- "Use the following link to reset your password: {link}" : "Za resetiranje svoje lozinke koristite sljedeću vezu: {link}",
- "New password" : "Nova lozinka",
- "New Password" : "Nova lozinka",
- "Reset password" : "Resetirajte lozinku",
"Searching other places" : "Pretraživanje drugih lokacija",
"Personal" : "Osobno",
"Users" : "Korisnici",
@@ -201,6 +195,10 @@
"Please contact your administrator." : "Molimo kontaktirajte svog administratora.",
"Log in" : "Prijavite se",
"Alternative Logins" : "Alternativne prijave",
+ "Use the following link to reset your password: {link}" : "Za resetiranje svoje lozinke koristite sljedeću vezu: {link}",
+ "New password" : "Nova lozinka",
+ "New Password" : "Nova lozinka",
+ "Reset password" : "Resetirajte lozinku",
"This ownCloud instance is currently in single user mode." : "Ova ownCloud instanca je trenutno u načinu rada za jednog korisnika.",
"This means only administrators can use the instance." : "To znači da tu instancu mogu koristiti samo administratori.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktirajte svog administratora sustava ako se ova poruka ponavlja ili sepojavila neočekivano.",
diff --git a/core/l10n/hu_HU.js b/core/l10n/hu_HU.js
index 0feea423eb6..5142d6cb2eb 100644
--- a/core/l10n/hu_HU.js
+++ b/core/l10n/hu_HU.js
@@ -16,8 +16,6 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Frissítettük \"%s\"-t erre: %s",
"Repair warning: " : "Javítás figyelmeztetés:",
"Repair error: " : "Javítás hiba:",
- "Set log level to debug - current level: \"%s\"" : "Hibakeresési naplózási szint beállítása - jelenlegi szint: \"%s\"",
- "Reset log level to \"%s\"" : "Naplózási szint visszaállítása \"%s\"-re",
"%s (3rdparty)" : "%s (harmadik fél által)",
"%s (incompatible)" : "%s (nem kompatibilis)",
"Following apps have been disabled: %s" : "A következő applikációk lettek tiltva: %s",
@@ -32,6 +30,12 @@ OC.L10N.register(
"No crop data provided" : "Vágáshoz nincs adat megadva",
"No valid crop data provided" : "Nem lett valós levágási adat megadva",
"Crop is not square" : "Levágás nem négyzet alakú",
+ "Couldn't reset password because the token is invalid" : "Nem lehet a jelszót törölni, mert a token érvénytelen.",
+ "Couldn't reset password because the token is expired" : "Nem lehet a jelszót törölni, mert a token lejárt.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Visszaállítási e-mail nem küldhető. Kérjük, lépjen kapcsolatba a rendszergazdával. ",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Nem tudtunk visszaállítási e-mailt küldeni, mert ehhez a felhasználóhoz nem tartozik e-mail cím. Kérjük, vedd fel a kapcsolatot a rendszergazdáddal!",
+ "%s password reset" : "%s jelszó visszaállítás",
+ "Couldn't send reset email. Please contact your administrator." : "Visszaállítási e-mail nem küldhető. Kérjük, lépjen kapcsolatba a rendszergazdával.",
"Sunday" : "vasárnap",
"Monday" : "hétfő",
"Tuesday" : "kedd",
@@ -80,7 +84,6 @@ OC.L10N.register(
"Settings" : "Beállítások",
"Saving..." : "Mentés...",
"seconds ago" : "pár másodperce",
- "Couldn't send reset email. Please contact your administrator." : "Visszaállítási e-mail nem küldhető. Kérjük, lépjen kapcsolatba a rendszergazdával.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "A jelszó felülírásához a linket e-mailben elküldtük. Ha a levél elfogadható időn belül nem érkezik meg, ellenőrizze a spam/levélszemét mappát.<br>Ha nincs ott, kérdezze meg a helyi rendszergazdát.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Az Ön állományai titkosítva vannak. Ha nem engedélyezte korábban az adatok visszanyeréséhez szükséges kulcs használatát, akkor a jelszó megváltoztatását követően nem fog hozzáférni az adataihoz. Ha nem biztos abban, hogy mit kellene tennie, akkor kérdezze meg a rendszergazdát, mielőtt továbbmenne. Biztos, hogy folytatni kívánja?",
"I know what I'm doing" : "Tudom mit csinálok.",
@@ -111,11 +114,8 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "A webszerver nincs megfelelően beállítva a fájl szinkronizációhoz, mert a WebDAV interfész nem működik.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Ennek a szervernek nincs működő internet kapcsolata. Ez azt jelenti, hogy néhány tulajdonság, mint pl. külső tárolók felcsatolása, frissítési értesítések, vagy egyéb applikációk nem működnek. A fájlok távoli elérése és az email értesítések is lehet, hogy nem működnek. Ajánlott az internet kapcsolat engedélyezése a szerveren, ha minden tulajdonságot használni akar.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Az adat könyvtára és a fáljai valószínűleg elérhetőek az internetről. A .htaccess fájl nem működik. Erősen ajánlott, hogy úgy állítsa be a webszerverét, hogy az adatkönyvtár ne legyen elérhető az internetről, vagy mogassa ki az adatokat a webszerver gyökérkönyvtárából.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nem lett gyorsítótár memória beállítva. A teljesítmény növeléséhez kérem állítson be gyorsítótárat, ha lehetséges. További információ található az alábbi <a href=\"{docLink}\">dokumentációban</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "a /dev/urandom eszköz nem elérhető PHP-ből, ami nagyon nagy biztonsági problémát jelent. További információ található az alábbi <a href=\"{docLink}\">dokumentációban</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A PHP verziód ({version}) már nem <a href=\"{phpLink}\">támogatott a PHP által</a>. Javasoljuk, hogy frissítsd a PHP verziót, hogy kihasználd a teljesítménybeli és biztonsági javításokat.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "A fordított proxy fejlécek konfigurációs beállításai helytelenek, vagy egy megbízható proxy-ból próbálja az ownCloud-ot elérni. Ha nem megbízható proxy-ból próbálja elérni az ownCloud-ot, akkor ez egy biztonsági probléma, a támadó az ownCloud számára látható IP cím csalást tud végrehajtani. További információ található a <a href=\"{docLink}\">dokumentációban</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached be van konfigurálva gyorsítótárnak, de rossz \"memcache\" PHP modul van telepítve. \\OC\\Memcache\\Memcached csak a \"memcached\"-t támogatja, és nem a \"memcache\"-t. Kérjük, nézd meg a <a href=\"{wikiLink}\">memcached wiki oldalt a modulokkal kapcsolatban</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom nem olvasható a PHP számára, mely nagy biztonsági probléma. Bővebb információt találhatsz a <a target=\"_blank\" href=\"{docLink}\">dokumentációban</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A PHP verziód ({version}) többé nem támogatott a <a target=\"_blank\" href=\"{phpLink}\">PHP által</a>. Azt javasoljuk, hogy frissítsd a PHP verziód, hogy kitud használni a teljesítménybeli és biztonsági javításokat.",
"Error occurred while checking server setup" : "Hiba történt a szerver beállítások ellenőrzése közben",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "A \"{header}\" HTTP fejléc nincs beállítva, hogy megegyezzen az elvárttal \"{expected}\". Ez egy potenciális biztonsági kockázat és kérjük, hogy változtassa meg a beállításokat.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "A \"Strict-Transport-Security\" HTTP fejléc nincs beállítva hogy \"{seconds}\" másodpercig tartson. Biztonsági okokból ajánljuk, hogy engedélyezze a HSTS, ahogyan ezt részletezzük a <a href=\"{docUrl}\">biztonsági tippek</a> dokumentációban.",
@@ -125,7 +125,6 @@ OC.L10N.register(
"Error" : "Hiba",
"Error while sharing" : "Nem sikerült létrehozni a megosztást",
"Error while unsharing" : "Nem sikerült visszavonni a megosztást",
- "Error while changing permissions" : "Nem sikerült módosítani a jogosultságokat",
"Error setting expiration date" : "Nem sikerült a lejárati időt beállítani",
"The public link will expire no later than {days} days after it is created" : "A nyilvános hivatkozás érvényessége legkorábban {days} nappal a létrehozása után jár csak le",
"Set expiration date" : "Legyen lejárati idő",
@@ -144,7 +143,6 @@ OC.L10N.register(
"Send" : "Küldjük el",
"Shared with you and the group {group} by {owner}" : "Megosztotta Önnel és a(z) {group} csoporttal: {owner}",
"Shared with you by {owner}" : "Megosztotta Önnel: {owner}",
- "Shared in {item} with {user}" : "Megosztva {item}-ben {user}-rel",
"group" : "csoport",
"remote" : "távoli",
"notify by email" : "e-mail értesítés",
@@ -163,9 +161,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Megosztás felhasználókkal, csoportokkal vagy távoli felhasználókkal ...",
"Warning" : "Figyelmeztetés",
"Error while sending notification" : "Hiba történt az értesítő küldése közben",
+ "Delete" : "Törlés",
+ "Rename" : "Átnevezés",
"The object type is not specified." : "Az objektum típusa nincs megadva.",
"Enter new" : "Új beírása",
- "Delete" : "Törlés",
"Add" : "Hozzáadás",
"Edit tags" : "Címkék szerkesztése",
"Error loading dialog template: {error}" : "Hiba a párbeszédpanel-sablon betöltésekor: {error}",
@@ -184,15 +183,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "A frissítés nem sikerült.",
"The update was successful. There were warnings." : "A frissítés sikerült. Figyelmeztetések találhatók.",
"The update was successful. Redirecting you to ownCloud now." : "A frissítés sikeres volt. Visszairányítjuk az ownCloud szolgáltatáshoz.",
- "Couldn't reset password because the token is invalid" : "Nem lehet a jelszót törölni, mert a token érvénytelen.",
- "Couldn't reset password because the token is expired" : "Nem lehet a jelszót törölni, mert a token lejárt.",
- "Couldn't send reset email. Please make sure your username is correct." : "Visszaállítási e-mail nem küldhető. Kérjük, lépjen kapcsolatba a rendszergazdával. ",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Visszaállítási e-mail nem küldhető, mert nem tartozik e-mail cím ehhez a felhasználóhoz. Kérjük, lépjen kapcsolatba a rendszergazdával.",
- "%s password reset" : "%s jelszó visszaállítás",
- "Use the following link to reset your password: {link}" : "Használja ezt a linket a jelszó ismételt beállításához: {link}",
- "New password" : "Az új jelszó",
- "New Password" : "Új jelszó",
- "Reset password" : "Jelszó-visszaállítás",
"Searching other places" : "Keresés más helyeken",
"No search results in other folders" : "Nincs keresési eredmény a másik könyvtárakban",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} keresési eredmény egy másik könyvtárban","{count} keresési eredmény más könyvtárakban"],
@@ -262,13 +252,19 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Kérem próbálja újra, vagy vegye fel a kapcsolatot a rendszergazdával.",
"Log in" : "Bejelentkezés",
"Wrong password. Reset it?" : "Hibás jelszó. Visszaállítja?",
+ "Wrong password." : "Rossz jelszó.",
"Stay logged in" : "Maradjon bejelentkezve",
"Alternative Logins" : "Alternatív bejelentkezés",
+ "Use the following link to reset your password: {link}" : "Használja ezt a linket a jelszó ismételt beállításához: {link}",
+ "New password" : "Az új jelszó",
+ "New Password" : "Új jelszó",
+ "Reset password" : "Jelszó-visszaállítás",
"This ownCloud instance is currently in single user mode." : "Ez az ownCloud szolgáltatás jelenleg egyfelhasználós üzemmódban működik.",
"This means only administrators can use the instance." : "Ez azt jelenti, hogy csak az adminisztrátor használhatja ezt a példányt",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Ha ez az üzenet ismételten vagy indokolatlanul megjelenik, akkor keresse a rendszergazda segítségét!",
"Thank you for your patience." : "Köszönjük a türelmét.",
"You are accessing the server from an untrusted domain." : "A kiszolgálót nem megbízható tartományból éri el.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Kérjük keresse fel a rendszergazdát! Ha ennek a telepítésnek Ön a rendszergazdája, akkor állítsa be a config/config.php állományban a \"trusted_domain\" paramétert! A config/config.sample.php állományban talál példát a beállításra.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "A beállításoktól függően, rendszergazdaként lehetséges, hogy az alábbi gombot is használhatja a tartomány megbízhatóvá tételéhez.",
"Add \"%s\" as trusted domain" : "Adjuk hozzá \"%s\"-t a megbízható tartományokhoz!",
"App update required" : "Alkalmazás frissítés szükséges",
diff --git a/core/l10n/hu_HU.json b/core/l10n/hu_HU.json
index 313be232295..8034ea197f4 100644
--- a/core/l10n/hu_HU.json
+++ b/core/l10n/hu_HU.json
@@ -14,8 +14,6 @@
"Updated \"%s\" to %s" : "Frissítettük \"%s\"-t erre: %s",
"Repair warning: " : "Javítás figyelmeztetés:",
"Repair error: " : "Javítás hiba:",
- "Set log level to debug - current level: \"%s\"" : "Hibakeresési naplózási szint beállítása - jelenlegi szint: \"%s\"",
- "Reset log level to \"%s\"" : "Naplózási szint visszaállítása \"%s\"-re",
"%s (3rdparty)" : "%s (harmadik fél által)",
"%s (incompatible)" : "%s (nem kompatibilis)",
"Following apps have been disabled: %s" : "A következő applikációk lettek tiltva: %s",
@@ -30,6 +28,12 @@
"No crop data provided" : "Vágáshoz nincs adat megadva",
"No valid crop data provided" : "Nem lett valós levágási adat megadva",
"Crop is not square" : "Levágás nem négyzet alakú",
+ "Couldn't reset password because the token is invalid" : "Nem lehet a jelszót törölni, mert a token érvénytelen.",
+ "Couldn't reset password because the token is expired" : "Nem lehet a jelszót törölni, mert a token lejárt.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Visszaállítási e-mail nem küldhető. Kérjük, lépjen kapcsolatba a rendszergazdával. ",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Nem tudtunk visszaállítási e-mailt küldeni, mert ehhez a felhasználóhoz nem tartozik e-mail cím. Kérjük, vedd fel a kapcsolatot a rendszergazdáddal!",
+ "%s password reset" : "%s jelszó visszaállítás",
+ "Couldn't send reset email. Please contact your administrator." : "Visszaállítási e-mail nem küldhető. Kérjük, lépjen kapcsolatba a rendszergazdával.",
"Sunday" : "vasárnap",
"Monday" : "hétfő",
"Tuesday" : "kedd",
@@ -78,7 +82,6 @@
"Settings" : "Beállítások",
"Saving..." : "Mentés...",
"seconds ago" : "pár másodperce",
- "Couldn't send reset email. Please contact your administrator." : "Visszaállítási e-mail nem küldhető. Kérjük, lépjen kapcsolatba a rendszergazdával.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "A jelszó felülírásához a linket e-mailben elküldtük. Ha a levél elfogadható időn belül nem érkezik meg, ellenőrizze a spam/levélszemét mappát.<br>Ha nincs ott, kérdezze meg a helyi rendszergazdát.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Az Ön állományai titkosítva vannak. Ha nem engedélyezte korábban az adatok visszanyeréséhez szükséges kulcs használatát, akkor a jelszó megváltoztatását követően nem fog hozzáférni az adataihoz. Ha nem biztos abban, hogy mit kellene tennie, akkor kérdezze meg a rendszergazdát, mielőtt továbbmenne. Biztos, hogy folytatni kívánja?",
"I know what I'm doing" : "Tudom mit csinálok.",
@@ -109,11 +112,8 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "A webszerver nincs megfelelően beállítva a fájl szinkronizációhoz, mert a WebDAV interfész nem működik.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Ennek a szervernek nincs működő internet kapcsolata. Ez azt jelenti, hogy néhány tulajdonság, mint pl. külső tárolók felcsatolása, frissítési értesítések, vagy egyéb applikációk nem működnek. A fájlok távoli elérése és az email értesítések is lehet, hogy nem működnek. Ajánlott az internet kapcsolat engedélyezése a szerveren, ha minden tulajdonságot használni akar.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Az adat könyvtára és a fáljai valószínűleg elérhetőek az internetről. A .htaccess fájl nem működik. Erősen ajánlott, hogy úgy állítsa be a webszerverét, hogy az adatkönyvtár ne legyen elérhető az internetről, vagy mogassa ki az adatokat a webszerver gyökérkönyvtárából.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nem lett gyorsítótár memória beállítva. A teljesítmény növeléséhez kérem állítson be gyorsítótárat, ha lehetséges. További információ található az alábbi <a href=\"{docLink}\">dokumentációban</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "a /dev/urandom eszköz nem elérhető PHP-ből, ami nagyon nagy biztonsági problémát jelent. További információ található az alábbi <a href=\"{docLink}\">dokumentációban</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A PHP verziód ({version}) már nem <a href=\"{phpLink}\">támogatott a PHP által</a>. Javasoljuk, hogy frissítsd a PHP verziót, hogy kihasználd a teljesítménybeli és biztonsági javításokat.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "A fordított proxy fejlécek konfigurációs beállításai helytelenek, vagy egy megbízható proxy-ból próbálja az ownCloud-ot elérni. Ha nem megbízható proxy-ból próbálja elérni az ownCloud-ot, akkor ez egy biztonsági probléma, a támadó az ownCloud számára látható IP cím csalást tud végrehajtani. További információ található a <a href=\"{docLink}\">dokumentációban</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached be van konfigurálva gyorsítótárnak, de rossz \"memcache\" PHP modul van telepítve. \\OC\\Memcache\\Memcached csak a \"memcached\"-t támogatja, és nem a \"memcache\"-t. Kérjük, nézd meg a <a href=\"{wikiLink}\">memcached wiki oldalt a modulokkal kapcsolatban</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom nem olvasható a PHP számára, mely nagy biztonsági probléma. Bővebb információt találhatsz a <a target=\"_blank\" href=\"{docLink}\">dokumentációban</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A PHP verziód ({version}) többé nem támogatott a <a target=\"_blank\" href=\"{phpLink}\">PHP által</a>. Azt javasoljuk, hogy frissítsd a PHP verziód, hogy kitud használni a teljesítménybeli és biztonsági javításokat.",
"Error occurred while checking server setup" : "Hiba történt a szerver beállítások ellenőrzése közben",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "A \"{header}\" HTTP fejléc nincs beállítva, hogy megegyezzen az elvárttal \"{expected}\". Ez egy potenciális biztonsági kockázat és kérjük, hogy változtassa meg a beállításokat.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "A \"Strict-Transport-Security\" HTTP fejléc nincs beállítva hogy \"{seconds}\" másodpercig tartson. Biztonsági okokból ajánljuk, hogy engedélyezze a HSTS, ahogyan ezt részletezzük a <a href=\"{docUrl}\">biztonsági tippek</a> dokumentációban.",
@@ -123,7 +123,6 @@
"Error" : "Hiba",
"Error while sharing" : "Nem sikerült létrehozni a megosztást",
"Error while unsharing" : "Nem sikerült visszavonni a megosztást",
- "Error while changing permissions" : "Nem sikerült módosítani a jogosultságokat",
"Error setting expiration date" : "Nem sikerült a lejárati időt beállítani",
"The public link will expire no later than {days} days after it is created" : "A nyilvános hivatkozás érvényessége legkorábban {days} nappal a létrehozása után jár csak le",
"Set expiration date" : "Legyen lejárati idő",
@@ -142,7 +141,6 @@
"Send" : "Küldjük el",
"Shared with you and the group {group} by {owner}" : "Megosztotta Önnel és a(z) {group} csoporttal: {owner}",
"Shared with you by {owner}" : "Megosztotta Önnel: {owner}",
- "Shared in {item} with {user}" : "Megosztva {item}-ben {user}-rel",
"group" : "csoport",
"remote" : "távoli",
"notify by email" : "e-mail értesítés",
@@ -161,9 +159,10 @@
"Share with users, groups or remote users …" : "Megosztás felhasználókkal, csoportokkal vagy távoli felhasználókkal ...",
"Warning" : "Figyelmeztetés",
"Error while sending notification" : "Hiba történt az értesítő küldése közben",
+ "Delete" : "Törlés",
+ "Rename" : "Átnevezés",
"The object type is not specified." : "Az objektum típusa nincs megadva.",
"Enter new" : "Új beírása",
- "Delete" : "Törlés",
"Add" : "Hozzáadás",
"Edit tags" : "Címkék szerkesztése",
"Error loading dialog template: {error}" : "Hiba a párbeszédpanel-sablon betöltésekor: {error}",
@@ -182,15 +181,6 @@
"The update was unsuccessful. " : "A frissítés nem sikerült.",
"The update was successful. There were warnings." : "A frissítés sikerült. Figyelmeztetések találhatók.",
"The update was successful. Redirecting you to ownCloud now." : "A frissítés sikeres volt. Visszairányítjuk az ownCloud szolgáltatáshoz.",
- "Couldn't reset password because the token is invalid" : "Nem lehet a jelszót törölni, mert a token érvénytelen.",
- "Couldn't reset password because the token is expired" : "Nem lehet a jelszót törölni, mert a token lejárt.",
- "Couldn't send reset email. Please make sure your username is correct." : "Visszaállítási e-mail nem küldhető. Kérjük, lépjen kapcsolatba a rendszergazdával. ",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Visszaállítási e-mail nem küldhető, mert nem tartozik e-mail cím ehhez a felhasználóhoz. Kérjük, lépjen kapcsolatba a rendszergazdával.",
- "%s password reset" : "%s jelszó visszaállítás",
- "Use the following link to reset your password: {link}" : "Használja ezt a linket a jelszó ismételt beállításához: {link}",
- "New password" : "Az új jelszó",
- "New Password" : "Új jelszó",
- "Reset password" : "Jelszó-visszaállítás",
"Searching other places" : "Keresés más helyeken",
"No search results in other folders" : "Nincs keresési eredmény a másik könyvtárakban",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} keresési eredmény egy másik könyvtárban","{count} keresési eredmény más könyvtárakban"],
@@ -260,13 +250,19 @@
"Please try again or contact your administrator." : "Kérem próbálja újra, vagy vegye fel a kapcsolatot a rendszergazdával.",
"Log in" : "Bejelentkezés",
"Wrong password. Reset it?" : "Hibás jelszó. Visszaállítja?",
+ "Wrong password." : "Rossz jelszó.",
"Stay logged in" : "Maradjon bejelentkezve",
"Alternative Logins" : "Alternatív bejelentkezés",
+ "Use the following link to reset your password: {link}" : "Használja ezt a linket a jelszó ismételt beállításához: {link}",
+ "New password" : "Az új jelszó",
+ "New Password" : "Új jelszó",
+ "Reset password" : "Jelszó-visszaállítás",
"This ownCloud instance is currently in single user mode." : "Ez az ownCloud szolgáltatás jelenleg egyfelhasználós üzemmódban működik.",
"This means only administrators can use the instance." : "Ez azt jelenti, hogy csak az adminisztrátor használhatja ezt a példányt",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Ha ez az üzenet ismételten vagy indokolatlanul megjelenik, akkor keresse a rendszergazda segítségét!",
"Thank you for your patience." : "Köszönjük a türelmét.",
"You are accessing the server from an untrusted domain." : "A kiszolgálót nem megbízható tartományból éri el.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Kérjük keresse fel a rendszergazdát! Ha ennek a telepítésnek Ön a rendszergazdája, akkor állítsa be a config/config.php állományban a \"trusted_domain\" paramétert! A config/config.sample.php állományban talál példát a beállításra.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "A beállításoktól függően, rendszergazdaként lehetséges, hogy az alábbi gombot is használhatja a tartomány megbízhatóvá tételéhez.",
"Add \"%s\" as trusted domain" : "Adjuk hozzá \"%s\"-t a megbízható tartományokhoz!",
"App update required" : "Alkalmazás frissítés szükséges",
diff --git a/core/l10n/hy.js b/core/l10n/hy.js
index 841c9a0d4e7..1899f4d7eeb 100644
--- a/core/l10n/hy.js
+++ b/core/l10n/hy.js
@@ -46,6 +46,7 @@ OC.L10N.register(
"Very weak password" : "Շատ թույլ գաղտնաբառ",
"Weak password" : "Թույլ գաղտնաբառ",
"Good password" : "Լավ գաղտնաբառ",
+ "Error" : "Սխալ",
"Share link" : "Կիսվել հղմամբ",
"Link" : "Հղում",
"Password" : "Գաղտնաբառ",
@@ -55,8 +56,10 @@ OC.L10N.register(
"Share" : "Կիսվել",
"Warning" : "Զգուշացում",
"Delete" : "Ջնջել",
+ "Rename" : "Վերանվանել",
"Add" : "Ավելացնել",
- "New password" : "Նոր գաղտնաբառ",
- "Personal" : "Անձնական"
+ "Personal" : "Անձնական",
+ "Username" : "Օգտանուն",
+ "New password" : "Նոր գաղտնաբառ"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/hy.json b/core/l10n/hy.json
index 722975e72e3..23d99811203 100644
--- a/core/l10n/hy.json
+++ b/core/l10n/hy.json
@@ -44,6 +44,7 @@
"Very weak password" : "Շատ թույլ գաղտնաբառ",
"Weak password" : "Թույլ գաղտնաբառ",
"Good password" : "Լավ գաղտնաբառ",
+ "Error" : "Սխալ",
"Share link" : "Կիսվել հղմամբ",
"Link" : "Հղում",
"Password" : "Գաղտնաբառ",
@@ -53,8 +54,10 @@
"Share" : "Կիսվել",
"Warning" : "Զգուշացում",
"Delete" : "Ջնջել",
+ "Rename" : "Վերանվանել",
"Add" : "Ավելացնել",
- "New password" : "Նոր գաղտնաբառ",
- "Personal" : "Անձնական"
+ "Personal" : "Անձնական",
+ "Username" : "Օգտանուն",
+ "New password" : "Նոր գաղտնաբառ"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/ia.js b/core/l10n/ia.js
index 254699c5fd2..e6ee2d05141 100644
--- a/core/l10n/ia.js
+++ b/core/l10n/ia.js
@@ -12,6 +12,8 @@ OC.L10N.register(
"Unknown filetype" : "Typo de file incognite",
"Invalid image" : "Imagine invalide",
"No temporary profile picture available, try again" : "Necun photo de profilo temporanee disponibile, essaya novemente",
+ "%s password reset" : "%s contrasigno re-fixate",
+ "Couldn't send reset email. Please contact your administrator." : "On non pote inviar message de configurar ex novo. Pro favor continge tu administrator.",
"Sunday" : "Dominica",
"Monday" : "Lunedi",
"Tuesday" : "Martedi",
@@ -53,7 +55,6 @@ OC.L10N.register(
"Settings" : "Configurationes",
"Saving..." : "Salveguardante...",
"seconds ago" : "secundas passate",
- "Couldn't send reset email. Please contact your administrator." : "On non pote inviar message de configurar ex novo. Pro favor continge tu administrator.",
"I know what I'm doing" : "Io sape lo que io es facente",
"Password can not be changed. Please contact your administrator." : "Contrasigno non pote esser modificate. Pro favor continge tu administrator.",
"No" : "No",
@@ -79,7 +80,6 @@ OC.L10N.register(
"Error" : "Error",
"Error while sharing" : "Error quando on compartiva",
"Error while unsharing" : "Error quando on levava le compartir",
- "Error while changing permissions" : "Error quando on modificava permissiones",
"Error setting expiration date" : "Error quando on fixava le data de expiration",
"Set expiration date" : "Fixa data de expiration",
"Expiration date" : "Data de expiration",
@@ -94,7 +94,6 @@ OC.L10N.register(
"Send" : "Invia",
"Shared with you and the group {group} by {owner}" : "Compartite con te e le gruppo {group} per {owner}",
"Shared with you by {owner}" : "Compartite con te per {owner} ",
- "Shared in {item} with {user}" : "Compartite in {item} con {user}",
"group" : "gruppo",
"notify by email" : "notificar per message de e-posta",
"Unshare" : "Leva compartir",
@@ -105,18 +104,13 @@ OC.L10N.register(
"access control" : "controlo de accesso",
"Share" : "Compartir",
"Warning" : "Aviso",
+ "Delete" : "Deler",
"The object type is not specified." : "Le typo de objecto non es specificate",
"Enter new" : "Inserta nove",
- "Delete" : "Deler",
"Add" : "Adder",
"Edit tags" : "Modifica etiquettas",
"Please reload the page." : "Pro favor recarga le pagina.",
"The update was successful. Redirecting you to ownCloud now." : "Le actualisation terminava con successo. On redirige nunc a tu ownCloud.",
- "%s password reset" : "%s contrasigno re-fixate",
- "Use the following link to reset your password: {link}" : "Usa le ligamine sequente pro re-fixar tu contrasigno: {link}",
- "New password" : "Nove contrasigno",
- "New Password" : "Nove contrasigno",
- "Reset password" : "Reinitialisar contrasigno",
"Personal" : "Personal",
"Users" : "Usatores",
"Apps" : "Applicationes",
@@ -156,6 +150,10 @@ OC.L10N.register(
"Please contact your administrator." : "Pro favor continge tu administrator.",
"Log in" : "Aperir session",
"Alternative Logins" : "Accessos de autorisation alternative",
+ "Use the following link to reset your password: {link}" : "Usa le ligamine sequente pro re-fixar tu contrasigno: {link}",
+ "New password" : "Nove contrasigno",
+ "New Password" : "Nove contrasigno",
+ "Reset password" : "Reinitialisar contrasigno",
"Thank you for your patience." : "Gratias pro tu patientia.",
"Start update" : "Initia actualisation"
},
diff --git a/core/l10n/ia.json b/core/l10n/ia.json
index f3173a9dd35..2afceccdf50 100644
--- a/core/l10n/ia.json
+++ b/core/l10n/ia.json
@@ -10,6 +10,8 @@
"Unknown filetype" : "Typo de file incognite",
"Invalid image" : "Imagine invalide",
"No temporary profile picture available, try again" : "Necun photo de profilo temporanee disponibile, essaya novemente",
+ "%s password reset" : "%s contrasigno re-fixate",
+ "Couldn't send reset email. Please contact your administrator." : "On non pote inviar message de configurar ex novo. Pro favor continge tu administrator.",
"Sunday" : "Dominica",
"Monday" : "Lunedi",
"Tuesday" : "Martedi",
@@ -51,7 +53,6 @@
"Settings" : "Configurationes",
"Saving..." : "Salveguardante...",
"seconds ago" : "secundas passate",
- "Couldn't send reset email. Please contact your administrator." : "On non pote inviar message de configurar ex novo. Pro favor continge tu administrator.",
"I know what I'm doing" : "Io sape lo que io es facente",
"Password can not be changed. Please contact your administrator." : "Contrasigno non pote esser modificate. Pro favor continge tu administrator.",
"No" : "No",
@@ -77,7 +78,6 @@
"Error" : "Error",
"Error while sharing" : "Error quando on compartiva",
"Error while unsharing" : "Error quando on levava le compartir",
- "Error while changing permissions" : "Error quando on modificava permissiones",
"Error setting expiration date" : "Error quando on fixava le data de expiration",
"Set expiration date" : "Fixa data de expiration",
"Expiration date" : "Data de expiration",
@@ -92,7 +92,6 @@
"Send" : "Invia",
"Shared with you and the group {group} by {owner}" : "Compartite con te e le gruppo {group} per {owner}",
"Shared with you by {owner}" : "Compartite con te per {owner} ",
- "Shared in {item} with {user}" : "Compartite in {item} con {user}",
"group" : "gruppo",
"notify by email" : "notificar per message de e-posta",
"Unshare" : "Leva compartir",
@@ -103,18 +102,13 @@
"access control" : "controlo de accesso",
"Share" : "Compartir",
"Warning" : "Aviso",
+ "Delete" : "Deler",
"The object type is not specified." : "Le typo de objecto non es specificate",
"Enter new" : "Inserta nove",
- "Delete" : "Deler",
"Add" : "Adder",
"Edit tags" : "Modifica etiquettas",
"Please reload the page." : "Pro favor recarga le pagina.",
"The update was successful. Redirecting you to ownCloud now." : "Le actualisation terminava con successo. On redirige nunc a tu ownCloud.",
- "%s password reset" : "%s contrasigno re-fixate",
- "Use the following link to reset your password: {link}" : "Usa le ligamine sequente pro re-fixar tu contrasigno: {link}",
- "New password" : "Nove contrasigno",
- "New Password" : "Nove contrasigno",
- "Reset password" : "Reinitialisar contrasigno",
"Personal" : "Personal",
"Users" : "Usatores",
"Apps" : "Applicationes",
@@ -154,6 +148,10 @@
"Please contact your administrator." : "Pro favor continge tu administrator.",
"Log in" : "Aperir session",
"Alternative Logins" : "Accessos de autorisation alternative",
+ "Use the following link to reset your password: {link}" : "Usa le ligamine sequente pro re-fixar tu contrasigno: {link}",
+ "New password" : "Nove contrasigno",
+ "New Password" : "Nove contrasigno",
+ "Reset password" : "Reinitialisar contrasigno",
"Thank you for your patience." : "Gratias pro tu patientia.",
"Start update" : "Initia actualisation"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/core/l10n/id.js b/core/l10n/id.js
index 6306d0682e0..a8f7816be46 100644
--- a/core/l10n/id.js
+++ b/core/l10n/id.js
@@ -16,8 +16,6 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Terbaru \"%s\" sampai %s",
"Repair warning: " : "Peringatan perbaikan:",
"Repair error: " : "Kesalahan perbaikan:",
- "Set log level to debug - current level: \"%s\"" : "Atur level log untuk debug - level saat ini: \"%s\"",
- "Reset log level to \"%s\"" : "Atur ulang level log menjadi \"%s\"",
"%s (3rdparty)" : "%s (pihak ke-3)",
"%s (incompatible)" : "%s (tidak kompatibel)",
"Following apps have been disabled: %s" : "Aplikasi berikut telah dinonaktifkan: %s",
@@ -32,6 +30,11 @@ OC.L10N.register(
"No crop data provided" : "Tidak ada data krop tersedia",
"No valid crop data provided" : "Tidak ada data valid untuk dipangkas",
"Crop is not square" : "Pangkas ini tidak persegi",
+ "Couldn't reset password because the token is invalid" : "Tidak dapat menyetel ulang sandi karena token tidak sah",
+ "Couldn't reset password because the token is expired" : "Tidak dapat menyetel ulang sandi karena token telah kadaluarsa",
+ "Couldn't send reset email. Please make sure your username is correct." : "Tidak dapat menyetel ulang email. Mohon pastikan nama pengguna Anda benar.",
+ "%s password reset" : "%s sandi disetel ulang",
+ "Couldn't send reset email. Please contact your administrator." : "Tidak dapat mengirim email setel ulang. Silakan hubungi administrator Anda.",
"Sunday" : "Minggu",
"Monday" : "Senin",
"Tuesday" : "Selasa",
@@ -80,7 +83,6 @@ OC.L10N.register(
"Settings" : "Pengaturan",
"Saving..." : "Menyimpan...",
"seconds ago" : "beberapa detik yang lalu",
- "Couldn't send reset email. Please contact your administrator." : "Tidak dapat mengirim email setel ulang. Silakan hubungi administrator Anda.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Sebuah tautan untuk setel ulang sandi Anda telah dikirim ke email Anda. Jika Anda tidak menerima dalam jangka waktu yang wajar, periksa folder spam/sampah Anda.<br>Jika tidak ada, tanyakan pada administrator Anda.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Berkas-berkas Anda terenkripsi. Jika Anda tidak mengaktifkan kunci pemulihan, tidak ada cara lain untuk mendapatkan data Anda kembali setelah sandi di setel ulang.<br />Jika Anda tidak yakin dengan apa yang akan Anda dilakukan, mohon hubungi administrator Anda sebelum melanjutkan. <br />Apakah Anda yakin ingin melanjutkan?",
"I know what I'm doing" : "Saya tahu apa yang saya lakukan",
@@ -111,11 +113,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Server web Anda belum diatur dengan benar untuk mengizinkan sinkronisasi berkas karena antarmuka WebDAV nampaknya rusak.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Server ini tidak tersambung ke internet. Ini berarti beberapa fitur seperti me-mount penyimpanan eksternal, notifikasi pembaruan atau instalasi aplikasi pihak ketiga tidak akan bekerja. Mengakses berkas secara remote dan mengirim notifikasi email juga tidak bekerja. Kami menyarankan untuk mengaktifkan koneksi internet untuk server ini jika Anda ingin memiliki fitur ini.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Direktori data dan berkas Anda kemungkinan dapat diakses dari Internet. Berkas .htaccess tidak bekerja. Kami sangat menyarankan Anda untuk mengkonfigurasi server web agar direktori data tidak lagi dapat diakses atau pindahkan direktori data Anda di luar root dokumen server web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Tembolok memori tidak dikonfigurasi. Untuk meningkatkan kinerja, mohon konfigurasi memcache jika tersedia. Informasi lebih lanjut dapat ditemukan di <a href=\"{docLink}\">dokumentasi</a> kami.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom tidak terbaca oleh PHP sangat disarankan untuk alasan keamanan. Informasi lebih lanjut dapat ditemukan di <a href=\"{docLink}\">dokumentasi</a> kami.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Versi PHP Anda ({version}) tidak lagi <a href=\"{phpLink}\">didukung oleh PHP</a>. Kami menyarankan Anda untuk meningkatkan versi PHP Anda agar mendapatkan keuntungan pembaruan kinerja dan keamanan yang disediakan oleh PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Konfigurasi header reverse proxy tidak benar atau Anda mengakses ownCloud dari proxy yang tidak terpercaya. Jika Anda tidak mengakses ownCloud dari proxy yang terpercaya, ini merupakan masalah keamanan dan memungkinkan peretas dapat memalsukan alamat IP mereka yang terlihat pada ownCloud. Informasi lebih lanjut dapat ditemukan pada <a href=\"{docLink}\">dokumentasi</a> kami.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached diatur sebagai cache terdistribusi, namun modul PHP \"memcache\" yang dipasang salah. \\OC\\Memcache\\Memcached hanya mendukung \"memcached\" bukan \"memcache\". Lihat <a href=\"{wikiLink}\">wiki memcached tentang kedua modul</a>.",
"Error occurred while checking server setup" : "Kesalahan tidak terduga saat memeriksa setelan server",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Header HTTP \"{header}\" tidak dikonfigurasi sama dengan \"{expected}\". Hal ini berpotensi pada resiko keamanan dan privasi. Kami sarankan untuk menyesuaikan pengaturan ini.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP header \"Strict-Transport-Security\" tidak diatur kurang dari \"{seconds}\" detik. Untuk peningkatan keamanan, kami menyarankan untuk mengaktifkan HSTS seperti yang dijelaskan di <a href=\"{docUrl}\">tips keamanan</a>.",
@@ -125,7 +122,6 @@ OC.L10N.register(
"Error" : "Kesalahan",
"Error while sharing" : "Kesalahan saat membagikan",
"Error while unsharing" : "Kesalahan saat membatalkan pembagian",
- "Error while changing permissions" : "Kesalahan saat mengubah izin",
"Error setting expiration date" : "Kesalahan saat mengatur tanggal kedaluwarsa",
"The public link will expire no later than {days} days after it is created" : "Tautan publik akan kadaluarsa tidak lebih dari {days} hari setelah ini dibuat",
"Set expiration date" : "Atur tanggal kedaluwarsa",
@@ -144,7 +140,6 @@ OC.L10N.register(
"Send" : "Kirim",
"Shared with you and the group {group} by {owner}" : "Dibagikan dengan anda dan grup {group} oleh {owner}",
"Shared with you by {owner}" : "Dibagikan dengan anda oleh {owner}",
- "Shared in {item} with {user}" : "Dibagikan dalam {item} dengan {user}",
"group" : "grup",
"remote" : "remote",
"notify by email" : "notifikasi via email",
@@ -163,9 +158,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Bagikan dengan pengguna, grup atau pengguna remote ...",
"Warning" : "Peringatan",
"Error while sending notification" : "Kesalahan ketika mengirim notifikasi",
+ "Delete" : "Hapus",
+ "Rename" : "Ubah nama",
"The object type is not specified." : "Tipe objek tidak ditentukan.",
"Enter new" : "Masukkan baru",
- "Delete" : "Hapus",
"Add" : "Tambah",
"Edit tags" : "Sunting label",
"Error loading dialog template: {error}" : "Kesalahan saat memuat templat dialog: {error}",
@@ -184,15 +180,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Pembaruan tidak berhasil.",
"The update was successful. There were warnings." : "Pembaruan telah berhasil. Terdapat peringatan.",
"The update was successful. Redirecting you to ownCloud now." : "Pembaruan sukses. Anda akan diarahkan ulang ke ownCloud.",
- "Couldn't reset password because the token is invalid" : "Tidak dapat menyetel ulang sandi karena token tidak sah",
- "Couldn't reset password because the token is expired" : "Tidak dapat menyetel ulang sandi karena token telah kadaluarsa",
- "Couldn't send reset email. Please make sure your username is correct." : "Tidak dapat menyetel ulang email. Mohon pastikan nama pengguna Anda benar.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Tidak dapat menyetel ulang email karena tidak ada alamat email untuk nama pengguna ini. Silakan hubungi Administrator Anda.",
- "%s password reset" : "%s sandi disetel ulang",
- "Use the following link to reset your password: {link}" : "Gunakan tautan berikut untuk menyetel ulang sandi Anda: {link}",
- "New password" : "Sandi baru",
- "New Password" : "Sandi Baru",
- "Reset password" : "Setel ulang sandi",
"Searching other places" : "Mencari tempat lainnya",
"No search results in other folders" : "Tidak ada hasil penelusuran didalam folder yang lain",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} hasil pencarian di folder lain"],
@@ -264,6 +251,10 @@ OC.L10N.register(
"Wrong password. Reset it?" : "Sandi salah. Atur ulang?",
"Stay logged in" : "Tetap masuk",
"Alternative Logins" : "Cara Alternatif untuk Masuk",
+ "Use the following link to reset your password: {link}" : "Gunakan tautan berikut untuk menyetel ulang sandi Anda: {link}",
+ "New password" : "Sandi baru",
+ "New Password" : "Sandi Baru",
+ "Reset password" : "Setel ulang sandi",
"This ownCloud instance is currently in single user mode." : "ownCloud ini sedang dalam mode pengguna tunggal.",
"This means only administrators can use the instance." : "Ini berarti hanya administrator yang dapat menggunakan ownCloud.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Hubungi administrator sistem anda jika pesan ini terus muncul atau muncul tiba-tiba.",
diff --git a/core/l10n/id.json b/core/l10n/id.json
index 80eebfdaab4..fd16d67b1e1 100644
--- a/core/l10n/id.json
+++ b/core/l10n/id.json
@@ -14,8 +14,6 @@
"Updated \"%s\" to %s" : "Terbaru \"%s\" sampai %s",
"Repair warning: " : "Peringatan perbaikan:",
"Repair error: " : "Kesalahan perbaikan:",
- "Set log level to debug - current level: \"%s\"" : "Atur level log untuk debug - level saat ini: \"%s\"",
- "Reset log level to \"%s\"" : "Atur ulang level log menjadi \"%s\"",
"%s (3rdparty)" : "%s (pihak ke-3)",
"%s (incompatible)" : "%s (tidak kompatibel)",
"Following apps have been disabled: %s" : "Aplikasi berikut telah dinonaktifkan: %s",
@@ -30,6 +28,11 @@
"No crop data provided" : "Tidak ada data krop tersedia",
"No valid crop data provided" : "Tidak ada data valid untuk dipangkas",
"Crop is not square" : "Pangkas ini tidak persegi",
+ "Couldn't reset password because the token is invalid" : "Tidak dapat menyetel ulang sandi karena token tidak sah",
+ "Couldn't reset password because the token is expired" : "Tidak dapat menyetel ulang sandi karena token telah kadaluarsa",
+ "Couldn't send reset email. Please make sure your username is correct." : "Tidak dapat menyetel ulang email. Mohon pastikan nama pengguna Anda benar.",
+ "%s password reset" : "%s sandi disetel ulang",
+ "Couldn't send reset email. Please contact your administrator." : "Tidak dapat mengirim email setel ulang. Silakan hubungi administrator Anda.",
"Sunday" : "Minggu",
"Monday" : "Senin",
"Tuesday" : "Selasa",
@@ -78,7 +81,6 @@
"Settings" : "Pengaturan",
"Saving..." : "Menyimpan...",
"seconds ago" : "beberapa detik yang lalu",
- "Couldn't send reset email. Please contact your administrator." : "Tidak dapat mengirim email setel ulang. Silakan hubungi administrator Anda.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Sebuah tautan untuk setel ulang sandi Anda telah dikirim ke email Anda. Jika Anda tidak menerima dalam jangka waktu yang wajar, periksa folder spam/sampah Anda.<br>Jika tidak ada, tanyakan pada administrator Anda.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Berkas-berkas Anda terenkripsi. Jika Anda tidak mengaktifkan kunci pemulihan, tidak ada cara lain untuk mendapatkan data Anda kembali setelah sandi di setel ulang.<br />Jika Anda tidak yakin dengan apa yang akan Anda dilakukan, mohon hubungi administrator Anda sebelum melanjutkan. <br />Apakah Anda yakin ingin melanjutkan?",
"I know what I'm doing" : "Saya tahu apa yang saya lakukan",
@@ -109,11 +111,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Server web Anda belum diatur dengan benar untuk mengizinkan sinkronisasi berkas karena antarmuka WebDAV nampaknya rusak.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Server ini tidak tersambung ke internet. Ini berarti beberapa fitur seperti me-mount penyimpanan eksternal, notifikasi pembaruan atau instalasi aplikasi pihak ketiga tidak akan bekerja. Mengakses berkas secara remote dan mengirim notifikasi email juga tidak bekerja. Kami menyarankan untuk mengaktifkan koneksi internet untuk server ini jika Anda ingin memiliki fitur ini.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Direktori data dan berkas Anda kemungkinan dapat diakses dari Internet. Berkas .htaccess tidak bekerja. Kami sangat menyarankan Anda untuk mengkonfigurasi server web agar direktori data tidak lagi dapat diakses atau pindahkan direktori data Anda di luar root dokumen server web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Tembolok memori tidak dikonfigurasi. Untuk meningkatkan kinerja, mohon konfigurasi memcache jika tersedia. Informasi lebih lanjut dapat ditemukan di <a href=\"{docLink}\">dokumentasi</a> kami.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom tidak terbaca oleh PHP sangat disarankan untuk alasan keamanan. Informasi lebih lanjut dapat ditemukan di <a href=\"{docLink}\">dokumentasi</a> kami.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Versi PHP Anda ({version}) tidak lagi <a href=\"{phpLink}\">didukung oleh PHP</a>. Kami menyarankan Anda untuk meningkatkan versi PHP Anda agar mendapatkan keuntungan pembaruan kinerja dan keamanan yang disediakan oleh PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Konfigurasi header reverse proxy tidak benar atau Anda mengakses ownCloud dari proxy yang tidak terpercaya. Jika Anda tidak mengakses ownCloud dari proxy yang terpercaya, ini merupakan masalah keamanan dan memungkinkan peretas dapat memalsukan alamat IP mereka yang terlihat pada ownCloud. Informasi lebih lanjut dapat ditemukan pada <a href=\"{docLink}\">dokumentasi</a> kami.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached diatur sebagai cache terdistribusi, namun modul PHP \"memcache\" yang dipasang salah. \\OC\\Memcache\\Memcached hanya mendukung \"memcached\" bukan \"memcache\". Lihat <a href=\"{wikiLink}\">wiki memcached tentang kedua modul</a>.",
"Error occurred while checking server setup" : "Kesalahan tidak terduga saat memeriksa setelan server",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Header HTTP \"{header}\" tidak dikonfigurasi sama dengan \"{expected}\". Hal ini berpotensi pada resiko keamanan dan privasi. Kami sarankan untuk menyesuaikan pengaturan ini.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP header \"Strict-Transport-Security\" tidak diatur kurang dari \"{seconds}\" detik. Untuk peningkatan keamanan, kami menyarankan untuk mengaktifkan HSTS seperti yang dijelaskan di <a href=\"{docUrl}\">tips keamanan</a>.",
@@ -123,7 +120,6 @@
"Error" : "Kesalahan",
"Error while sharing" : "Kesalahan saat membagikan",
"Error while unsharing" : "Kesalahan saat membatalkan pembagian",
- "Error while changing permissions" : "Kesalahan saat mengubah izin",
"Error setting expiration date" : "Kesalahan saat mengatur tanggal kedaluwarsa",
"The public link will expire no later than {days} days after it is created" : "Tautan publik akan kadaluarsa tidak lebih dari {days} hari setelah ini dibuat",
"Set expiration date" : "Atur tanggal kedaluwarsa",
@@ -142,7 +138,6 @@
"Send" : "Kirim",
"Shared with you and the group {group} by {owner}" : "Dibagikan dengan anda dan grup {group} oleh {owner}",
"Shared with you by {owner}" : "Dibagikan dengan anda oleh {owner}",
- "Shared in {item} with {user}" : "Dibagikan dalam {item} dengan {user}",
"group" : "grup",
"remote" : "remote",
"notify by email" : "notifikasi via email",
@@ -161,9 +156,10 @@
"Share with users, groups or remote users …" : "Bagikan dengan pengguna, grup atau pengguna remote ...",
"Warning" : "Peringatan",
"Error while sending notification" : "Kesalahan ketika mengirim notifikasi",
+ "Delete" : "Hapus",
+ "Rename" : "Ubah nama",
"The object type is not specified." : "Tipe objek tidak ditentukan.",
"Enter new" : "Masukkan baru",
- "Delete" : "Hapus",
"Add" : "Tambah",
"Edit tags" : "Sunting label",
"Error loading dialog template: {error}" : "Kesalahan saat memuat templat dialog: {error}",
@@ -182,15 +178,6 @@
"The update was unsuccessful. " : "Pembaruan tidak berhasil.",
"The update was successful. There were warnings." : "Pembaruan telah berhasil. Terdapat peringatan.",
"The update was successful. Redirecting you to ownCloud now." : "Pembaruan sukses. Anda akan diarahkan ulang ke ownCloud.",
- "Couldn't reset password because the token is invalid" : "Tidak dapat menyetel ulang sandi karena token tidak sah",
- "Couldn't reset password because the token is expired" : "Tidak dapat menyetel ulang sandi karena token telah kadaluarsa",
- "Couldn't send reset email. Please make sure your username is correct." : "Tidak dapat menyetel ulang email. Mohon pastikan nama pengguna Anda benar.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Tidak dapat menyetel ulang email karena tidak ada alamat email untuk nama pengguna ini. Silakan hubungi Administrator Anda.",
- "%s password reset" : "%s sandi disetel ulang",
- "Use the following link to reset your password: {link}" : "Gunakan tautan berikut untuk menyetel ulang sandi Anda: {link}",
- "New password" : "Sandi baru",
- "New Password" : "Sandi Baru",
- "Reset password" : "Setel ulang sandi",
"Searching other places" : "Mencari tempat lainnya",
"No search results in other folders" : "Tidak ada hasil penelusuran didalam folder yang lain",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} hasil pencarian di folder lain"],
@@ -262,6 +249,10 @@
"Wrong password. Reset it?" : "Sandi salah. Atur ulang?",
"Stay logged in" : "Tetap masuk",
"Alternative Logins" : "Cara Alternatif untuk Masuk",
+ "Use the following link to reset your password: {link}" : "Gunakan tautan berikut untuk menyetel ulang sandi Anda: {link}",
+ "New password" : "Sandi baru",
+ "New Password" : "Sandi Baru",
+ "Reset password" : "Setel ulang sandi",
"This ownCloud instance is currently in single user mode." : "ownCloud ini sedang dalam mode pengguna tunggal.",
"This means only administrators can use the instance." : "Ini berarti hanya administrator yang dapat menggunakan ownCloud.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Hubungi administrator sistem anda jika pesan ini terus muncul atau muncul tiba-tiba.",
diff --git a/core/l10n/is.js b/core/l10n/is.js
index a4f17b74f55..d079011931f 100644
--- a/core/l10n/is.js
+++ b/core/l10n/is.js
@@ -23,6 +23,11 @@ OC.L10N.register(
"No crop data provided" : "Enginn klippi gögn veit",
"No valid crop data provided" : "Ógild klippi gögn veit",
"Crop is not square" : "Skurður er ekki ferhyrntur",
+ "Couldn't reset password because the token is invalid" : "Gat ekki endurstillt lykilorðið vegna þess að tóki ógilt",
+ "Couldn't reset password because the token is expired" : "Gat ekki endurstillt lykilorðið vegna þess að tóki er útrunnið",
+ "Couldn't send reset email. Please make sure your username is correct." : "Gat ekki sent endurstillingu í tölvupóst. Vinsamlegast gakktu úr skugga um að notandanafn þitt sé rétt.",
+ "%s password reset" : "%s lykilorð endurstillt",
+ "Couldn't send reset email. Please contact your administrator." : "Gat ekki sent endursetningar tölvupóst. Vinsamlegast hafðu samband við kerfisstjóra.",
"Sunday" : "Sunnudagur",
"Monday" : "Mánudagur",
"Tuesday" : "Þriðjudagur",
@@ -71,7 +76,6 @@ OC.L10N.register(
"Settings" : "Stillingar",
"Saving..." : "Er að vista ...",
"seconds ago" : "sek.",
- "Couldn't send reset email. Please contact your administrator." : "Gat ekki sent endursetningar tölvupóst. Vinsamlegast hafðu samband við kerfisstjóra.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Hlekkurinn til að endurstilla lykilorðið þitt hefur verið sent á netfangið þitt. Ef þú færð ekki póstinn innan hæfilegs tíma, athugaðu þá í ruslpóst möppu.<br>Ef það er ekki þar spurðu þá kerfisstjórann þinn.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Skrárnar þínar eru dulkóðaðar. Ef þú hefur ekki kveikt á vara lykill, það verður engin leið til að fá þinn gögn til baka eftir lykilorðið þitt er endurstillt.<br />Ef þú ert ekki viss hvað á að gera, skaltu hafa samband við kerfisstjórann áður en þú heldur áfram. <br />Viltu halda áfram?",
"I know what I'm doing" : "Ég veit hvað ég er að gera",
@@ -102,10 +106,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Vefþjónninn er ekki enn sett upp á réttan hátt til að leyfa skráar samstillingu því WebDAV viðmótið virðist vera brotinn.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Þessi miðlari hefur ekki virka nettengingu. Þetta þýðir að sumir eginleikar eins og virkja ytri gagnageymslu, tilkynningar um uppfærslur eða uppsetningu á foritum þriðja aðila mun ekki virka. Fjar aðgangur af skrám og senda tilkynningar í tölvupósti vika líklega ekki heldur. Við leggjum til að virkja internet tengingu fyrir þennan vefþjóni ef þú vilt hafa alla eiginleika.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Gagnamappa og skrá eru líklega aðgengilegar af internetinu vegna þess að .htaccess skrá er ekki virk. Við mælum eindregið með að þú stillir vefþjón þinn á þann hátt að gagnamappa er ekki lengur aðgengileg eða þú færir gagnamöppu út fyrir rót vefþjóns.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Ekkert skyndiminni hefur verið stillt. Til að auka afköst skaltu stilla skyndiminni ef í boði. Nánari upplýsingar má finna á <a href=\\\"{docLink}\\\">documentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom er ekki læsileg af PHP, Sterklega er mælt með því að leyfa PHP að lesa /dev/urandom af öryggisástæðum. Nánari upplýsingar má finna á <a href=\\\"{docLink}\\\">documentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "PHP útgáfan þín ({version}) er ekki lengur <a href=\\\"{phpLink}\\\">supported by PHP</a>. Við hvetjum þig til að uppfæra PHP útgáfuna til að nýta afkasta og öryggis nýjungar hjá PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Gagnstæður proxy haus stilling er röng, eða þú ert að tengjast ownCloud frá traustum proxy. Ef þú ert ekki að tengjast ownCloud frá traustum proxy, þetta er öryggismál og getur leyft árásir að skopstæling IP tölu þeirra sem sýnilega ownCloud. Nánari upplýsingar má finna á <a href=\\\"{docLink}\\\">documentation</a>.",
"Error occurred while checking server setup" : "Villa kom upp við athugun á uppsetingu miðlara",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\\\"{header}\\\" HTTP haus er ekki stilltur til jafns við \\\"{expected}\\\". Þetta er mögulegur öryggis eða næðis áhætta, við mælum með því að aðlaga þessa stillingu.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\\\"Strangt-Transport-Security\\\" HTTP haus er ekki stilltur á minst \\\"{seconds}\\\" sekúndur. Fyrir aukið öryggi mælum við með því að virkja HSTS eins og lýst er í <a href=\\\"{docUrl}\\\">security tips</a>.",
@@ -115,7 +115,6 @@ OC.L10N.register(
"Error" : "Villa",
"Error while sharing" : "Villa við deilingu",
"Error while unsharing" : "Villa við að hætta deilingu",
- "Error while changing permissions" : "Villa við að breyta aðgangsheimildum",
"Error setting expiration date" : "Villa við að setja gildistíma",
"The public link will expire no later than {days} days after it is created" : "Almennings hlekkur rennur út eigi síðar en {days} daga eftir að hann er búinn til",
"Set expiration date" : "Setja gildistíma",
@@ -134,7 +133,6 @@ OC.L10N.register(
"Send" : "Senda",
"Shared with you and the group {group} by {owner}" : "Deilt með þér og hópnum {group} af {owner}",
"Shared with you by {owner}" : "Deilt með þér af {owner}",
- "Shared in {item} with {user}" : "Deilt með {item} ásamt {user}",
"group" : "hópur",
"remote" : "fjarlægur",
"notify by email" : "tilkynna með tölvupósti",
@@ -153,9 +151,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Deila með notendum, hópa eða ytri notendum ...",
"Warning" : "Aðvörun",
"Error while sending notification" : "Villa við að senda tilkynningu",
+ "Delete" : "Eyða",
+ "Rename" : "Endurnefna",
"The object type is not specified." : "Tegund ekki tilgreind",
"Enter new" : "Sláðu inn nýtt",
- "Delete" : "Eyða",
"Add" : "Bæta við",
"Edit tags" : "Breyta tögum",
"Error loading dialog template: {error}" : "Villa við að hlaða valmynd sniðmátið: {error}",
@@ -172,15 +171,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Uppfærslan tókst ekki.",
"The update was successful. There were warnings." : "Uppfærslan tókst. Það voru viðvaranir.",
"The update was successful. Redirecting you to ownCloud now." : "Uppfærslan heppnaðist. Beini þér til ownCloud nú.",
- "Couldn't reset password because the token is invalid" : "Gat ekki endurstillt lykilorðið vegna þess að tóki ógilt",
- "Couldn't reset password because the token is expired" : "Gat ekki endurstillt lykilorðið vegna þess að tóki er útrunnið",
- "Couldn't send reset email. Please make sure your username is correct." : "Gat ekki sent endurstillingu í tölvupóst. Vinsamlegast gakktu úr skugga um að notandanafn þitt sé rétt.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Gat ekki sent endurstillingu í tölvupóst vegna þess að það er ekkert netfang fyrir þetta notandanafn. Vinsamlegast hafðu samband við kerfisstjóra.",
- "%s password reset" : "%s lykilorð endurstillt",
- "Use the following link to reset your password: {link}" : "Notað eftirfarandi veftengil til að endursetja lykilorðið þitt: {link}",
- "New password" : "Nýtt lykilorð",
- "New Password" : "Nýtt Lykilorð",
- "Reset password" : "Endursetja lykilorð",
"Searching other places" : "Leitað á öðrum stöðum",
"Personal" : "Um mig",
"Users" : "Notendur",
@@ -249,6 +239,10 @@ OC.L10N.register(
"Log in" : "Skrá inn",
"Wrong password. Reset it?" : "Rangt lykilorð. Endursetja?",
"Alternative Logins" : "Aðrar Innskráningar",
+ "Use the following link to reset your password: {link}" : "Notað eftirfarandi veftengil til að endursetja lykilorðið þitt: {link}",
+ "New password" : "Nýtt lykilorð",
+ "New Password" : "Nýtt Lykilorð",
+ "Reset password" : "Endursetja lykilorð",
"This ownCloud instance is currently in single user mode." : "Þetta ownCloud eintak er nú í einnar notandaham.",
"This means only administrators can use the instance." : "Þetta þýðir aðeins stjórnendur geta notað eintak.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Hafðu samband við kerfisstjóra ef þessi skilaboð eru viðvarandi eða birtist óvænt.",
diff --git a/core/l10n/is.json b/core/l10n/is.json
index aebd0c756d2..bee7653fc55 100644
--- a/core/l10n/is.json
+++ b/core/l10n/is.json
@@ -21,6 +21,11 @@
"No crop data provided" : "Enginn klippi gögn veit",
"No valid crop data provided" : "Ógild klippi gögn veit",
"Crop is not square" : "Skurður er ekki ferhyrntur",
+ "Couldn't reset password because the token is invalid" : "Gat ekki endurstillt lykilorðið vegna þess að tóki ógilt",
+ "Couldn't reset password because the token is expired" : "Gat ekki endurstillt lykilorðið vegna þess að tóki er útrunnið",
+ "Couldn't send reset email. Please make sure your username is correct." : "Gat ekki sent endurstillingu í tölvupóst. Vinsamlegast gakktu úr skugga um að notandanafn þitt sé rétt.",
+ "%s password reset" : "%s lykilorð endurstillt",
+ "Couldn't send reset email. Please contact your administrator." : "Gat ekki sent endursetningar tölvupóst. Vinsamlegast hafðu samband við kerfisstjóra.",
"Sunday" : "Sunnudagur",
"Monday" : "Mánudagur",
"Tuesday" : "Þriðjudagur",
@@ -69,7 +74,6 @@
"Settings" : "Stillingar",
"Saving..." : "Er að vista ...",
"seconds ago" : "sek.",
- "Couldn't send reset email. Please contact your administrator." : "Gat ekki sent endursetningar tölvupóst. Vinsamlegast hafðu samband við kerfisstjóra.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Hlekkurinn til að endurstilla lykilorðið þitt hefur verið sent á netfangið þitt. Ef þú færð ekki póstinn innan hæfilegs tíma, athugaðu þá í ruslpóst möppu.<br>Ef það er ekki þar spurðu þá kerfisstjórann þinn.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Skrárnar þínar eru dulkóðaðar. Ef þú hefur ekki kveikt á vara lykill, það verður engin leið til að fá þinn gögn til baka eftir lykilorðið þitt er endurstillt.<br />Ef þú ert ekki viss hvað á að gera, skaltu hafa samband við kerfisstjórann áður en þú heldur áfram. <br />Viltu halda áfram?",
"I know what I'm doing" : "Ég veit hvað ég er að gera",
@@ -100,10 +104,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Vefþjónninn er ekki enn sett upp á réttan hátt til að leyfa skráar samstillingu því WebDAV viðmótið virðist vera brotinn.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Þessi miðlari hefur ekki virka nettengingu. Þetta þýðir að sumir eginleikar eins og virkja ytri gagnageymslu, tilkynningar um uppfærslur eða uppsetningu á foritum þriðja aðila mun ekki virka. Fjar aðgangur af skrám og senda tilkynningar í tölvupósti vika líklega ekki heldur. Við leggjum til að virkja internet tengingu fyrir þennan vefþjóni ef þú vilt hafa alla eiginleika.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Gagnamappa og skrá eru líklega aðgengilegar af internetinu vegna þess að .htaccess skrá er ekki virk. Við mælum eindregið með að þú stillir vefþjón þinn á þann hátt að gagnamappa er ekki lengur aðgengileg eða þú færir gagnamöppu út fyrir rót vefþjóns.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Ekkert skyndiminni hefur verið stillt. Til að auka afköst skaltu stilla skyndiminni ef í boði. Nánari upplýsingar má finna á <a href=\\\"{docLink}\\\">documentation</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom er ekki læsileg af PHP, Sterklega er mælt með því að leyfa PHP að lesa /dev/urandom af öryggisástæðum. Nánari upplýsingar má finna á <a href=\\\"{docLink}\\\">documentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "PHP útgáfan þín ({version}) er ekki lengur <a href=\\\"{phpLink}\\\">supported by PHP</a>. Við hvetjum þig til að uppfæra PHP útgáfuna til að nýta afkasta og öryggis nýjungar hjá PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Gagnstæður proxy haus stilling er röng, eða þú ert að tengjast ownCloud frá traustum proxy. Ef þú ert ekki að tengjast ownCloud frá traustum proxy, þetta er öryggismál og getur leyft árásir að skopstæling IP tölu þeirra sem sýnilega ownCloud. Nánari upplýsingar má finna á <a href=\\\"{docLink}\\\">documentation</a>.",
"Error occurred while checking server setup" : "Villa kom upp við athugun á uppsetingu miðlara",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\\\"{header}\\\" HTTP haus er ekki stilltur til jafns við \\\"{expected}\\\". Þetta er mögulegur öryggis eða næðis áhætta, við mælum með því að aðlaga þessa stillingu.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\\\"Strangt-Transport-Security\\\" HTTP haus er ekki stilltur á minst \\\"{seconds}\\\" sekúndur. Fyrir aukið öryggi mælum við með því að virkja HSTS eins og lýst er í <a href=\\\"{docUrl}\\\">security tips</a>.",
@@ -113,7 +113,6 @@
"Error" : "Villa",
"Error while sharing" : "Villa við deilingu",
"Error while unsharing" : "Villa við að hætta deilingu",
- "Error while changing permissions" : "Villa við að breyta aðgangsheimildum",
"Error setting expiration date" : "Villa við að setja gildistíma",
"The public link will expire no later than {days} days after it is created" : "Almennings hlekkur rennur út eigi síðar en {days} daga eftir að hann er búinn til",
"Set expiration date" : "Setja gildistíma",
@@ -132,7 +131,6 @@
"Send" : "Senda",
"Shared with you and the group {group} by {owner}" : "Deilt með þér og hópnum {group} af {owner}",
"Shared with you by {owner}" : "Deilt með þér af {owner}",
- "Shared in {item} with {user}" : "Deilt með {item} ásamt {user}",
"group" : "hópur",
"remote" : "fjarlægur",
"notify by email" : "tilkynna með tölvupósti",
@@ -151,9 +149,10 @@
"Share with users, groups or remote users …" : "Deila með notendum, hópa eða ytri notendum ...",
"Warning" : "Aðvörun",
"Error while sending notification" : "Villa við að senda tilkynningu",
+ "Delete" : "Eyða",
+ "Rename" : "Endurnefna",
"The object type is not specified." : "Tegund ekki tilgreind",
"Enter new" : "Sláðu inn nýtt",
- "Delete" : "Eyða",
"Add" : "Bæta við",
"Edit tags" : "Breyta tögum",
"Error loading dialog template: {error}" : "Villa við að hlaða valmynd sniðmátið: {error}",
@@ -170,15 +169,6 @@
"The update was unsuccessful. " : "Uppfærslan tókst ekki.",
"The update was successful. There were warnings." : "Uppfærslan tókst. Það voru viðvaranir.",
"The update was successful. Redirecting you to ownCloud now." : "Uppfærslan heppnaðist. Beini þér til ownCloud nú.",
- "Couldn't reset password because the token is invalid" : "Gat ekki endurstillt lykilorðið vegna þess að tóki ógilt",
- "Couldn't reset password because the token is expired" : "Gat ekki endurstillt lykilorðið vegna þess að tóki er útrunnið",
- "Couldn't send reset email. Please make sure your username is correct." : "Gat ekki sent endurstillingu í tölvupóst. Vinsamlegast gakktu úr skugga um að notandanafn þitt sé rétt.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Gat ekki sent endurstillingu í tölvupóst vegna þess að það er ekkert netfang fyrir þetta notandanafn. Vinsamlegast hafðu samband við kerfisstjóra.",
- "%s password reset" : "%s lykilorð endurstillt",
- "Use the following link to reset your password: {link}" : "Notað eftirfarandi veftengil til að endursetja lykilorðið þitt: {link}",
- "New password" : "Nýtt lykilorð",
- "New Password" : "Nýtt Lykilorð",
- "Reset password" : "Endursetja lykilorð",
"Searching other places" : "Leitað á öðrum stöðum",
"Personal" : "Um mig",
"Users" : "Notendur",
@@ -247,6 +237,10 @@
"Log in" : "Skrá inn",
"Wrong password. Reset it?" : "Rangt lykilorð. Endursetja?",
"Alternative Logins" : "Aðrar Innskráningar",
+ "Use the following link to reset your password: {link}" : "Notað eftirfarandi veftengil til að endursetja lykilorðið þitt: {link}",
+ "New password" : "Nýtt lykilorð",
+ "New Password" : "Nýtt Lykilorð",
+ "Reset password" : "Endursetja lykilorð",
"This ownCloud instance is currently in single user mode." : "Þetta ownCloud eintak er nú í einnar notandaham.",
"This means only administrators can use the instance." : "Þetta þýðir aðeins stjórnendur geta notað eintak.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Hafðu samband við kerfisstjóra ef þessi skilaboð eru viðvarandi eða birtist óvænt.",
diff --git a/core/l10n/it.js b/core/l10n/it.js
index 873c8fb4fea..d23609d57ec 100644
--- a/core/l10n/it.js
+++ b/core/l10n/it.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Aggiornato \"%s\" a %s",
"Repair warning: " : "Avviso di riparazione",
"Repair error: " : "Errore di riparazione:",
- "Set log level to debug - current level: \"%s\"" : "Imposta il livello del log a debug - livello attuale: \"%s\"",
- "Reset log level to \"%s\"" : "Ripristina il livello del log a \"%s\"",
+ "Set log level to debug" : "Imposta il livello del log a debug",
+ "Reset log level" : "Ripristina il livello del log",
+ "Starting code integrity check" : "Avvio del controllo di integrità del codice",
+ "Finished code integrity check" : "Controllo di integrità del codice terminato",
"%s (3rdparty)" : "%s (Terze parti)",
"%s (incompatible)" : "%s (incompatibile)",
"Following apps have been disabled: %s" : "Le seguenti applicazioni sono state disabilitate: %s",
"Already up to date" : "Già aggiornato",
+ "Please select a file." : "Seleziona un file.",
"File is too big" : "Il file è troppo grande",
"Invalid file provided" : "File non valido fornito",
"No image or file provided" : "Non è stata fornita alcun immagine o file",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "Non sono stati forniti dati di ritaglio",
"No valid crop data provided" : "Non sono stati forniti dati di ritaglio validi",
"Crop is not square" : "Il ritaglio non è quadrato",
+ "Couldn't reset password because the token is invalid" : "Impossibile reimpostare la password poiché il token non è valido",
+ "Couldn't reset password because the token is expired" : "Impossibile reimpostare la password poiché il token è scaduto",
+ "Couldn't send reset email. Please make sure your username is correct." : "Impossibile inviare l'email di reimpostazione. Assicurati che il nome utente sia corretto.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossibile inviare l'email di reimpostazione poiché non è presente un indirizzo email per questo nome utente. Contatta il tuo amministratore.",
+ "%s password reset" : "Ripristino password di %s",
+ "Couldn't send reset email. Please contact your administrator." : "Impossibile inviare l'email di reimpostazione. Contatta il tuo amministratore.",
"Sunday" : "Domenica",
"Monday" : "Lunedì",
"Tuesday" : "Martedì",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "Ott.",
"Nov." : "Nov.",
"Dec." : "Dic.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Si sono verificati errori con il controllo di integrità del codice. Ulteriori informazioni…</a>",
"Settings" : "Impostazioni",
"Saving..." : "Salvataggio in corso...",
"seconds ago" : "secondi fa",
- "Couldn't send reset email. Please contact your administrator." : "Impossibile inviare l'email di reimpostazione. Contatta il tuo amministratore.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Il collegamento per reimpostare la password è stato inviato al tuo indirizzo di posta. Se non lo ricevi in tempi ragionevoli, controlla le cartelle della posta indesiderata.<br>Se non dovesse essere nemmeno lì, contatta il tuo amministratore locale.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "I tuoi file sono cifrati. Se non hai precedentemente abilitato la chiave di ripristino, non sarà più possibile ritrovare i tuoi dati una volta che la password sarà reimpostata.<br />Se non sei sicuro, contatta l'amministratore prima di proseguire.<br />Vuoi davvero continuare?",
"I know what I'm doing" : "So cosa sto facendo",
@@ -109,13 +118,15 @@ OC.L10N.register(
"Good password" : "Password buona",
"Strong password" : "Password forte",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Il tuo server web non è configurato correttamente per consentire la sincronizzazione dei file poiché l'interfaccia WebDAV sembra essere danneggiata.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Il tuo server web non è configurato correttamente per risolvere \"{url}\". Ulteriori informazioni sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Questo server non ha una connessione a Internet funzionante. Ciò significa che alcune delle funzionalità come il montaggio di archivi esterni, le notifiche degli aggiornamenti o l'installazione di applicazioni di terze parti non funzioneranno. L'accesso remoto ai file e l'invio di email di notifica potrebbero non funzionare. Ti suggeriamo di abilitare la connessione a Internet del server se desideri disporre di tutte le funzionalità.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "La cartella dei dati e i tuoi file sono probabilmente accessibili da Internet.\nIl file .htaccess non funziona. Ti consigliamo vivamente di configurare il server web in modo che la cartella dei dati non sia più accessibile o di spostare la cartella fuori dalla radice del server web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Non è stata configurata alcuna cache di memoria. Per migliorare le prestazioni configura memcache, se disponibile. Ulteriori informazioni sono disponibili nella nostra <a href=\"{docLink}\">documentazione</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom non è leggibile da PHP e ciò è vivamente sconsigliato per motivi di sicurezza. Ulteriori informazioni sono disponibili nella nostra <a href=\"{docLink}\">documentazione</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La tua versione ({version}) di PHP non è più <a href=\"{phpLink}\">supportata da PHP</a>. Ti esortiamo ad aggiornare la versione di PHP per trarre vantaggio dagli aggiornamenti in termini di prestazioni e sicurezza forniti da PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La configurazione delle intestazioni del proxy inverso non è corretta, o stai effettuando l'accesso a ownCloud da un proxy affidabile. Se non stai effettuando l'accesso da un proxy affidabile, questo è un problema di sicurezza e può consentire a un attaccante di falsificare il suo indirizzo IP, rendendo visibile a ownCloud. Ulteriori informazioni sono disponibili nella nostra <a href=\"{docLink}\">documentazione</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached è configurato come cache distribuita, ma è installato il modulo \"memcache\" errato. \\OC\\Memcache\\Memcached supporta solo \"memcached\" e non \"memcache\". Vedi il <a href=\"{wikiLink}\">wiki di memcached per informazioni su entrambi i moduli</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Non è stata configurata alcuna cache di memoria. Per migliorare le prestazioni, configura memcache, se disponibile. Ulteriori informazioni sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom non è leggibile da PHP e ciò è vivamente sconsigliato per motivi di sicurezza. Ulteriori informazioni sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La tua versione ({version}) di PHP non è più <a target=\"_blank\" href=\"{phpLink}\">supportata da PHP</a>. Ti consigliamo di aggiornare la versione di PHP per trarre vantaggio dagli aggiornamenti in termini di prestazioni e sicurezza forniti da PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La configurazione delle intestazioni del proxy inverso non è corretta, o stai effettuando l'accesso a ownCloud da un proxy affidabile. Se non stai effettuando l'accesso da un proxy affidabile, questo è un problema di sicurezza e può consentire a un attaccante di falsificare il suo indirizzo IP, rendendo visibile a ownCloud. Ulteriori informazioni sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached è configurato come cache distribuita, ma è installato il modulo \"memcache\" errato. \\OC\\Memcache\\Memcached supporta solo \"memcached\" e non \"memcache\". Vedi il <a target=\"_blank\" href=\"{wikiLink}\">wiki di memcached per informazioni su entrambi i moduli</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Alcuni file non hanno superato il controllo di integrità. Ulteriori informazioni su come risolvere questo problema sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Elenco dei file non validi…</a> / <a href=\"{rescanEndpoint}\">Nuova scansione…</a>)",
"Error occurred while checking server setup" : "Si è verificato un errore durante il controllo della configurazione del server",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "L'intestazione HTTP \"{header}\" non è configurata come \"{expected}\". \nQuesto è un potenziale rischio di sicurezza o di riservatezza dei dati e noi consigliamo di modificare questa impostazione.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "L'intestazione HTTP \"Strict-Transport-Security\" non è configurata con un valore almeno di \"{seconds}\" secondi. Per migliorare la sicurezza, consigliamo di abilitare HSTS come descritto nei nostri <a href=\"{docUrl}\">consigli sulla sicurezza</a>.",
@@ -125,7 +136,6 @@ OC.L10N.register(
"Error" : "Errore",
"Error while sharing" : "Errore durante la condivisione",
"Error while unsharing" : "Errore durante la rimozione della condivisione",
- "Error while changing permissions" : "Errore durante la modifica dei permessi",
"Error setting expiration date" : "Errore durante l'impostazione della data di scadenza",
"The public link will expire no later than {days} days after it is created" : "Il collegamento pubblico scadrà non più tardi di {days} giorni dopo la sua creazione",
"Set expiration date" : "Imposta data di scadenza",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "Invia",
"Shared with you and the group {group} by {owner}" : "Condiviso con te e con il gruppo {group} da {owner}",
"Shared with you by {owner}" : "Condiviso con te da {owner}",
- "Shared in {item} with {user}" : "Condiviso in {item} con {user}",
"group" : "gruppo",
"remote" : "remota",
"notify by email" : "notifica tramite email",
@@ -155,17 +164,25 @@ OC.L10N.register(
"change" : "cambia",
"delete" : "elimina",
"access control" : "controllo d'accesso",
+ "Could not unshare" : "Impossibile rimuovere la condivisione",
"Share details could not be loaded for this item." : "I dettagli della condivisione non possono essere caricati per questo elemento.",
"An error occured. Please try again" : "Si è verificato un errore. Prova ancora",
"Share" : "Condividi",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Condividi con persone su altri ownCloud utilizzando la sintassi nomeutente@esempio.com/owncloud",
"Share with users or groups …" : "Condividi con utenti o gruppi...",
"Share with users, groups or remote users …" : "Condividi con utenti, gruppi o utenti remoti...",
+ "Error removing share" : "Errore durante la rimozione della condivisione",
"Warning" : "Avviso",
"Error while sending notification" : "Errore durante l'invio della notifica",
+ "Non-existing tag #{tag}" : "Tag #{tag} inesistente",
+ "not assignable" : "non assegnabile",
+ "invisible" : "invisibile",
+ "({scope})" : "({scope})",
+ "Delete" : "Elimina",
+ "Rename" : "Rinomina",
+ "Global tags" : "Tag globali",
"The object type is not specified." : "Il tipo di oggetto non è specificato.",
"Enter new" : "Inserisci nuovo",
- "Delete" : "Elimina",
"Add" : "Aggiungi",
"Edit tags" : "Modifica etichette",
"Error loading dialog template: {error}" : "Errore durante il caricamento del modello di finestra: {error}",
@@ -184,15 +201,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "L'aggiornamento non è riuscito.",
"The update was successful. There were warnings." : "L'aggiornamento è stato effettuato correttamente. Ci sono degli avvisi.",
"The update was successful. Redirecting you to ownCloud now." : "L'aggiornamento è stato effettuato correttamente. Stai per essere reindirizzato a ownCloud.",
- "Couldn't reset password because the token is invalid" : "Impossibile reimpostare la password poiché il token non è valido",
- "Couldn't reset password because the token is expired" : "Impossibile reimpostare la password poiché il token è scaduto",
- "Couldn't send reset email. Please make sure your username is correct." : "Impossibile inviare l'email di reimpostazione. Assicurati che il nome utente sia corretto.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Impossibile inviare l'email di reimpostazione poiché non è presente un indirizzo email per questo nome utente. Contatta il tuo amministratore.",
- "%s password reset" : "Ripristino password di %s",
- "Use the following link to reset your password: {link}" : "Usa il collegamento seguente per ripristinare la password: {link}",
- "New password" : "Nuova password",
- "New Password" : "Nuova password",
- "Reset password" : "Ripristina la password",
"Searching other places" : "Ricerca in altre posizioni",
"No search results in other folders" : "Nessun risultato di ricerca in altre cartelle",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} risultato di ricerca in altre cartelle","{count} risultati di ricerca in altre cartelle"],
@@ -262,8 +270,13 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Prova ancora o contatta il tuo amministratore.",
"Log in" : "Accedi",
"Wrong password. Reset it?" : "Password errata. Vuoi reimpostarla?",
+ "Wrong password." : "Password errata.",
"Stay logged in" : "Rimani collegato",
"Alternative Logins" : "Accessi alternativi",
+ "Use the following link to reset your password: {link}" : "Usa il collegamento seguente per ripristinare la password: {link}",
+ "New password" : "Nuova password",
+ "New Password" : "Nuova password",
+ "Reset password" : "Ripristina la password",
"This ownCloud instance is currently in single user mode." : "Questa istanza di ownCloud è in modalità utente singolo.",
"This means only administrators can use the instance." : "Ciò significa che solo gli amministratori possono utilizzare l'istanza.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contatta il tuo amministratore di sistema se questo messaggio persiste o appare inaspettatamente.",
diff --git a/core/l10n/it.json b/core/l10n/it.json
index 8dffade7400..966d0f58125 100644
--- a/core/l10n/it.json
+++ b/core/l10n/it.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "Aggiornato \"%s\" a %s",
"Repair warning: " : "Avviso di riparazione",
"Repair error: " : "Errore di riparazione:",
- "Set log level to debug - current level: \"%s\"" : "Imposta il livello del log a debug - livello attuale: \"%s\"",
- "Reset log level to \"%s\"" : "Ripristina il livello del log a \"%s\"",
+ "Set log level to debug" : "Imposta il livello del log a debug",
+ "Reset log level" : "Ripristina il livello del log",
+ "Starting code integrity check" : "Avvio del controllo di integrità del codice",
+ "Finished code integrity check" : "Controllo di integrità del codice terminato",
"%s (3rdparty)" : "%s (Terze parti)",
"%s (incompatible)" : "%s (incompatibile)",
"Following apps have been disabled: %s" : "Le seguenti applicazioni sono state disabilitate: %s",
"Already up to date" : "Già aggiornato",
+ "Please select a file." : "Seleziona un file.",
"File is too big" : "Il file è troppo grande",
"Invalid file provided" : "File non valido fornito",
"No image or file provided" : "Non è stata fornita alcun immagine o file",
@@ -30,6 +33,12 @@
"No crop data provided" : "Non sono stati forniti dati di ritaglio",
"No valid crop data provided" : "Non sono stati forniti dati di ritaglio validi",
"Crop is not square" : "Il ritaglio non è quadrato",
+ "Couldn't reset password because the token is invalid" : "Impossibile reimpostare la password poiché il token non è valido",
+ "Couldn't reset password because the token is expired" : "Impossibile reimpostare la password poiché il token è scaduto",
+ "Couldn't send reset email. Please make sure your username is correct." : "Impossibile inviare l'email di reimpostazione. Assicurati che il nome utente sia corretto.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossibile inviare l'email di reimpostazione poiché non è presente un indirizzo email per questo nome utente. Contatta il tuo amministratore.",
+ "%s password reset" : "Ripristino password di %s",
+ "Couldn't send reset email. Please contact your administrator." : "Impossibile inviare l'email di reimpostazione. Contatta il tuo amministratore.",
"Sunday" : "Domenica",
"Monday" : "Lunedì",
"Tuesday" : "Martedì",
@@ -75,10 +84,10 @@
"Oct." : "Ott.",
"Nov." : "Nov.",
"Dec." : "Dic.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Si sono verificati errori con il controllo di integrità del codice. Ulteriori informazioni…</a>",
"Settings" : "Impostazioni",
"Saving..." : "Salvataggio in corso...",
"seconds ago" : "secondi fa",
- "Couldn't send reset email. Please contact your administrator." : "Impossibile inviare l'email di reimpostazione. Contatta il tuo amministratore.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Il collegamento per reimpostare la password è stato inviato al tuo indirizzo di posta. Se non lo ricevi in tempi ragionevoli, controlla le cartelle della posta indesiderata.<br>Se non dovesse essere nemmeno lì, contatta il tuo amministratore locale.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "I tuoi file sono cifrati. Se non hai precedentemente abilitato la chiave di ripristino, non sarà più possibile ritrovare i tuoi dati una volta che la password sarà reimpostata.<br />Se non sei sicuro, contatta l'amministratore prima di proseguire.<br />Vuoi davvero continuare?",
"I know what I'm doing" : "So cosa sto facendo",
@@ -107,13 +116,15 @@
"Good password" : "Password buona",
"Strong password" : "Password forte",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Il tuo server web non è configurato correttamente per consentire la sincronizzazione dei file poiché l'interfaccia WebDAV sembra essere danneggiata.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Il tuo server web non è configurato correttamente per risolvere \"{url}\". Ulteriori informazioni sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Questo server non ha una connessione a Internet funzionante. Ciò significa che alcune delle funzionalità come il montaggio di archivi esterni, le notifiche degli aggiornamenti o l'installazione di applicazioni di terze parti non funzioneranno. L'accesso remoto ai file e l'invio di email di notifica potrebbero non funzionare. Ti suggeriamo di abilitare la connessione a Internet del server se desideri disporre di tutte le funzionalità.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "La cartella dei dati e i tuoi file sono probabilmente accessibili da Internet.\nIl file .htaccess non funziona. Ti consigliamo vivamente di configurare il server web in modo che la cartella dei dati non sia più accessibile o di spostare la cartella fuori dalla radice del server web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Non è stata configurata alcuna cache di memoria. Per migliorare le prestazioni configura memcache, se disponibile. Ulteriori informazioni sono disponibili nella nostra <a href=\"{docLink}\">documentazione</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom non è leggibile da PHP e ciò è vivamente sconsigliato per motivi di sicurezza. Ulteriori informazioni sono disponibili nella nostra <a href=\"{docLink}\">documentazione</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La tua versione ({version}) di PHP non è più <a href=\"{phpLink}\">supportata da PHP</a>. Ti esortiamo ad aggiornare la versione di PHP per trarre vantaggio dagli aggiornamenti in termini di prestazioni e sicurezza forniti da PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La configurazione delle intestazioni del proxy inverso non è corretta, o stai effettuando l'accesso a ownCloud da un proxy affidabile. Se non stai effettuando l'accesso da un proxy affidabile, questo è un problema di sicurezza e può consentire a un attaccante di falsificare il suo indirizzo IP, rendendo visibile a ownCloud. Ulteriori informazioni sono disponibili nella nostra <a href=\"{docLink}\">documentazione</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached è configurato come cache distribuita, ma è installato il modulo \"memcache\" errato. \\OC\\Memcache\\Memcached supporta solo \"memcached\" e non \"memcache\". Vedi il <a href=\"{wikiLink}\">wiki di memcached per informazioni su entrambi i moduli</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Non è stata configurata alcuna cache di memoria. Per migliorare le prestazioni, configura memcache, se disponibile. Ulteriori informazioni sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom non è leggibile da PHP e ciò è vivamente sconsigliato per motivi di sicurezza. Ulteriori informazioni sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La tua versione ({version}) di PHP non è più <a target=\"_blank\" href=\"{phpLink}\">supportata da PHP</a>. Ti consigliamo di aggiornare la versione di PHP per trarre vantaggio dagli aggiornamenti in termini di prestazioni e sicurezza forniti da PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "La configurazione delle intestazioni del proxy inverso non è corretta, o stai effettuando l'accesso a ownCloud da un proxy affidabile. Se non stai effettuando l'accesso da un proxy affidabile, questo è un problema di sicurezza e può consentire a un attaccante di falsificare il suo indirizzo IP, rendendo visibile a ownCloud. Ulteriori informazioni sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached è configurato come cache distribuita, ma è installato il modulo \"memcache\" errato. \\OC\\Memcache\\Memcached supporta solo \"memcached\" e non \"memcache\". Vedi il <a target=\"_blank\" href=\"{wikiLink}\">wiki di memcached per informazioni su entrambi i moduli</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Alcuni file non hanno superato il controllo di integrità. Ulteriori informazioni su come risolvere questo problema sono disponibili nella nostra <a target=\"_blank\" href=\"{docLink}\">documentazione</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Elenco dei file non validi…</a> / <a href=\"{rescanEndpoint}\">Nuova scansione…</a>)",
"Error occurred while checking server setup" : "Si è verificato un errore durante il controllo della configurazione del server",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "L'intestazione HTTP \"{header}\" non è configurata come \"{expected}\". \nQuesto è un potenziale rischio di sicurezza o di riservatezza dei dati e noi consigliamo di modificare questa impostazione.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "L'intestazione HTTP \"Strict-Transport-Security\" non è configurata con un valore almeno di \"{seconds}\" secondi. Per migliorare la sicurezza, consigliamo di abilitare HSTS come descritto nei nostri <a href=\"{docUrl}\">consigli sulla sicurezza</a>.",
@@ -123,7 +134,6 @@
"Error" : "Errore",
"Error while sharing" : "Errore durante la condivisione",
"Error while unsharing" : "Errore durante la rimozione della condivisione",
- "Error while changing permissions" : "Errore durante la modifica dei permessi",
"Error setting expiration date" : "Errore durante l'impostazione della data di scadenza",
"The public link will expire no later than {days} days after it is created" : "Il collegamento pubblico scadrà non più tardi di {days} giorni dopo la sua creazione",
"Set expiration date" : "Imposta data di scadenza",
@@ -142,7 +152,6 @@
"Send" : "Invia",
"Shared with you and the group {group} by {owner}" : "Condiviso con te e con il gruppo {group} da {owner}",
"Shared with you by {owner}" : "Condiviso con te da {owner}",
- "Shared in {item} with {user}" : "Condiviso in {item} con {user}",
"group" : "gruppo",
"remote" : "remota",
"notify by email" : "notifica tramite email",
@@ -153,17 +162,25 @@
"change" : "cambia",
"delete" : "elimina",
"access control" : "controllo d'accesso",
+ "Could not unshare" : "Impossibile rimuovere la condivisione",
"Share details could not be loaded for this item." : "I dettagli della condivisione non possono essere caricati per questo elemento.",
"An error occured. Please try again" : "Si è verificato un errore. Prova ancora",
"Share" : "Condividi",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Condividi con persone su altri ownCloud utilizzando la sintassi nomeutente@esempio.com/owncloud",
"Share with users or groups …" : "Condividi con utenti o gruppi...",
"Share with users, groups or remote users …" : "Condividi con utenti, gruppi o utenti remoti...",
+ "Error removing share" : "Errore durante la rimozione della condivisione",
"Warning" : "Avviso",
"Error while sending notification" : "Errore durante l'invio della notifica",
+ "Non-existing tag #{tag}" : "Tag #{tag} inesistente",
+ "not assignable" : "non assegnabile",
+ "invisible" : "invisibile",
+ "({scope})" : "({scope})",
+ "Delete" : "Elimina",
+ "Rename" : "Rinomina",
+ "Global tags" : "Tag globali",
"The object type is not specified." : "Il tipo di oggetto non è specificato.",
"Enter new" : "Inserisci nuovo",
- "Delete" : "Elimina",
"Add" : "Aggiungi",
"Edit tags" : "Modifica etichette",
"Error loading dialog template: {error}" : "Errore durante il caricamento del modello di finestra: {error}",
@@ -182,15 +199,6 @@
"The update was unsuccessful. " : "L'aggiornamento non è riuscito.",
"The update was successful. There were warnings." : "L'aggiornamento è stato effettuato correttamente. Ci sono degli avvisi.",
"The update was successful. Redirecting you to ownCloud now." : "L'aggiornamento è stato effettuato correttamente. Stai per essere reindirizzato a ownCloud.",
- "Couldn't reset password because the token is invalid" : "Impossibile reimpostare la password poiché il token non è valido",
- "Couldn't reset password because the token is expired" : "Impossibile reimpostare la password poiché il token è scaduto",
- "Couldn't send reset email. Please make sure your username is correct." : "Impossibile inviare l'email di reimpostazione. Assicurati che il nome utente sia corretto.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Impossibile inviare l'email di reimpostazione poiché non è presente un indirizzo email per questo nome utente. Contatta il tuo amministratore.",
- "%s password reset" : "Ripristino password di %s",
- "Use the following link to reset your password: {link}" : "Usa il collegamento seguente per ripristinare la password: {link}",
- "New password" : "Nuova password",
- "New Password" : "Nuova password",
- "Reset password" : "Ripristina la password",
"Searching other places" : "Ricerca in altre posizioni",
"No search results in other folders" : "Nessun risultato di ricerca in altre cartelle",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} risultato di ricerca in altre cartelle","{count} risultati di ricerca in altre cartelle"],
@@ -260,8 +268,13 @@
"Please try again or contact your administrator." : "Prova ancora o contatta il tuo amministratore.",
"Log in" : "Accedi",
"Wrong password. Reset it?" : "Password errata. Vuoi reimpostarla?",
+ "Wrong password." : "Password errata.",
"Stay logged in" : "Rimani collegato",
"Alternative Logins" : "Accessi alternativi",
+ "Use the following link to reset your password: {link}" : "Usa il collegamento seguente per ripristinare la password: {link}",
+ "New password" : "Nuova password",
+ "New Password" : "Nuova password",
+ "Reset password" : "Ripristina la password",
"This ownCloud instance is currently in single user mode." : "Questa istanza di ownCloud è in modalità utente singolo.",
"This means only administrators can use the instance." : "Ciò significa che solo gli amministratori possono utilizzare l'istanza.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contatta il tuo amministratore di sistema se questo messaggio persiste o appare inaspettatamente.",
diff --git a/core/l10n/ja.js b/core/l10n/ja.js
index 225948366f6..1b368469f43 100644
--- a/core/l10n/ja.js
+++ b/core/l10n/ja.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "\"%s\" を %s にアップデートしました。",
"Repair warning: " : "修復警告:",
"Repair error: " : "修復エラー:",
- "Set log level to debug - current level: \"%s\"" : "ログレベルをデバッグにセットします - 現在のレベル: \"%s\"",
- "Reset log level to \"%s\"" : "ログレベルを \"%s\" にリセットします。",
+ "Set log level to debug" : "ログをデバッグレベルに設定",
+ "Reset log level" : "ログレベルをリセット",
+ "Starting code integrity check" : "コード整合性の確認を開始",
+ "Finished code integrity check" : "コード整合性の確認が終了",
"%s (3rdparty)" : "%s (サードパーティー)",
"%s (incompatible)" : "%s (非互換)",
"Following apps have been disabled: %s" : "以下のアプリが無効にされています: %s",
- "Already up to date" : "全て更新済",
+ "Already up to date" : "すべて更新済",
+ "Please select a file." : "ファイルを選択してください。",
"File is too big" : "ファイルが大きすぎます",
"Invalid file provided" : "無効なファイルが提供されました",
"No image or file provided" : "画像もしくはファイルが提供されていません",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "クロップデータは提供されません",
"No valid crop data provided" : "有効なクロップデータは提供されません",
"Crop is not square" : "クロップが正方形ではありません",
+ "Couldn't reset password because the token is invalid" : "トークンが無効なため、パスワードをリセットできませんでした",
+ "Couldn't reset password because the token is expired" : "トークンが期限切れのため、パスワードをリセットできませんでした",
+ "Couldn't send reset email. Please make sure your username is correct." : "リセットメールを送信できませんでした。ユーザー名が正しいことを確認してください。",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "このユーザー名に紐付けられたメールアドレスがないため、リセットメールを送信できませんでした。管理者に問い合わせてください。",
+ "%s password reset" : "%s パスワードリセット",
+ "Couldn't send reset email. Please contact your administrator." : "リセットメールを送信できませんでした。管理者に問い合わせてください。",
"Sunday" : "日",
"Monday" : "月",
"Tuesday" : "火",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "10月",
"Nov." : "11月",
"Dec." : "12月",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">コード整合性の確認で問題が発生しました。詳しくはこちら…</a>",
"Settings" : "設定",
"Saving..." : "保存中...",
"seconds ago" : "数秒前",
- "Couldn't send reset email. Please contact your administrator." : "リセットメールを送信できませんでした。管理者に問い合わせてください。",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "パスワードをリセットするリンクをクリックしたので、メールを送信しました。しばらくたってもメールが届かなかった場合は、スパム/ジャンクフォルダーを確認してください。<br>それでも見つからなかった場合は、管理者に問合わせてください。",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "ファイルが暗号化されています。リカバリーキーが有効でない場合は、パスワードをリセットした後にあなたのデータを元に戻す方法はありません。<br />どういうことか分からない場合は、操作を継続する前に管理者に問い合わせてください。<br />続けてよろしいでしょうか?",
"I know what I'm doing" : "どういう操作をしているか理解しています",
@@ -111,11 +120,12 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "WebDAVインターフェースが動作していないようです。Webサーバーは、ファイルの同期を許可するよう適切に設定されていません。",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "このサーバーはインターネットに接続していません。この場合、外部ストレージのマウント、更新の通知やサードパーティ製のアプリ、といった一部の機能が利用できません。また、リモート接続でのファイルアクセス、通知メールの送信のような機能も利用できないことがあります。すべての機能を利用するには、このサーバーのインターネット接続を有効にすることをお勧めします。",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "データディレクトリとファイルがインターネットからアクセス可能になっている可能性があります。.htaccessファイルが機能していません。データディレクトリがアクセスされないようにWebサーバーを設定するか、Webサーバーのドキュメントルートからデータディレクトリを移動するように強くお勧めします。",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "メモリキャッシュが設定されていません。パフォーマンスを向上するために、可能であれば memcache を設定してください。 より詳しい情報については、<a href=\"{docLink}\">documentation</a> を参照してください。",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom は PHP から読み取ることができず、この状態はセキュリティの観点からおすすめできません。より詳しい情報については、<a href=\"{docLink}\">documentation</a> を参照ください。",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "ご利用のPHPのバージョン ({version}) は、<a href=\"{phpLink}\">PHPでサポート</a> されていません。 我々は、PHPから提供されている新しいバージョンにアップグレードし、それによるセキュリティの確保とパフォーマンスのメリットを受けられることを強くお勧めします。",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "リバースプロキシーのヘッダー設定が間違っているか、または信頼されたプロキシーからownCloudにアクセスしていません。もし、信頼されたプロキシーからアクセスしているのでないなら、セキュリティに問題があり、ownCloudを詐称したIPアドレスから攻撃者に対して見えるよう許可していることになります。詳細な情報は、<a href=\"{docLink}\">ドキュメント</a>を確認してください。",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached は分散キャッシュとして設定されていますが、間違った\"memcache\"のPHPモジュールがインストールされています。 \\OC\\Memcache\\Memcached は、\"memcached\" のみをサポートしていますが、\"memcache\" ではありません。<a href=\"{wikiLink}\">memcached wiki で両方のモジュール</a> を見てください。",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "メモリキャッシュが設定されていません。パフォーマンスを向上するために、可能であれば memcache を設定してください。 より詳しい情報については、<a target=\"_blank\" href=\"{docLink}\">ドキュメント</a> を参照してください。",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom は PHP から読み取ることができず、この状態はセキュリティの観点からおすすめできません。より詳しい情報については、<a target=\"_blank\" href=\"{docLink}\">ドキュメント</a> を参照ください。",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "ご利用のPHPのバージョン ({version}) は、<a target=\"_blank\" href=\"{phpLink}\">PHPでサポート</a> されていません。セキュリティ確保とパフォーマンス向上のために、PHPから提供されている新しいバージョンにアップグレードすることを強くお勧めします。",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "リバースプロキシのヘッダー設定が間違っているか、または信頼されたプロキシからownCloudにアクセスしていません。もし、信頼されたプロキシからアクセスしているのでないなら、セキュリティに問題があり、ownCloudを詐称したIPアドレスから攻撃者に対して見えるよう許可していることになります。詳細な情報は、 <a target=\"_blank\" href=\"{docLink}\">ドキュメント</a>を確認してください。",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached は分散キャッシュとして設定されています。しかし、PHPモジュール \"memcache\"が間違ってインストールされています。 \\OC\\Memcache\\Memcached は、\"memcached\" のみをサポートしています。\"memcache\" ではありません。<a target=\"_blank\" href=\"{wikiLink}\">memcached wiki で両方のモジュール</a> について確認してください。",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "いくつかのファイルで整合性の確認に失敗しました。この問題を解決するための詳細情報は<a target=\"_blank\" href=\"{docLink}\">ドキュメント</a>にあります。 (<a href=\"{codeIntegrityDownloadEndpoint}\">不適正なファイルのリスト…</a> / <a href=\"{rescanEndpoint}\">再スキャン…</a>)",
"Error occurred while checking server setup" : "サーバー設定のチェック中にエラーが発生しました",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP ヘッダは \"{expected}\" に設定されていません。これは潜在的なセキュリティリスクもしくはプライバシーリスクとなる可能性があるため、この設定を見直すことをおすすめします。",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"Strict-Transport-Security\" HTTP ヘッダが最小値の \"{seconds}\" 秒に設定されていません。 セキュリティを強化するため、<a href=\"{docUrl}\">security tips</a>を参照して、HSTS を有効にすることをおすすめします。",
@@ -125,7 +135,6 @@ OC.L10N.register(
"Error" : "エラー",
"Error while sharing" : "共有でエラー発生",
"Error while unsharing" : "共有解除でエラー発生",
- "Error while changing permissions" : "権限変更でエラー発生",
"Error setting expiration date" : "有効期限の設定でエラー発生",
"The public link will expire no later than {days} days after it is created" : "URLによる共有は、作成してから {days} 日以内に有効期限切れになります",
"Set expiration date" : "有効期限を設定",
@@ -144,7 +153,6 @@ OC.L10N.register(
"Send" : "送信",
"Shared with you and the group {group} by {owner}" : "あなたと {owner} のグループ {group} で共有中",
"Shared with you by {owner}" : "{owner} と共有中",
- "Shared in {item} with {user}" : "{item} 内で {user} と共有中",
"group" : "グループ",
"remote" : "リモート",
"notify by email" : "メールで通知",
@@ -155,17 +163,23 @@ OC.L10N.register(
"change" : "更新",
"delete" : "削除",
"access control" : "アクセス権限",
+ "Could not unshare" : "共有の解除ができませんでした",
"Share details could not be loaded for this item." : "共有の詳細はこのアイテムによりロードできませんでした。",
"An error occured. Please try again" : "エラーが発生しました。もう一度トライしてください。",
"Share" : "共有",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "次の形式で指定して他のownCloudのユーザーと、共有",
"Share with users or groups …" : "ユーザーもしくはグループと共有 ...",
"Share with users, groups or remote users …" : "ユーザー、グループもしくはリモートユーザーと共有 ...",
+ "Error removing share" : "共有の削除エラー",
"Warning" : "警告",
"Error while sending notification" : "通知送信中にエラーが発生",
+ "Non-existing tag #{tag}" : "存在しないタグ#{tag}",
+ "not assignable" : "割り当てできない",
+ "Delete" : "削除",
+ "Rename" : "名前の変更",
+ "Global tags" : "グローバルタグ",
"The object type is not specified." : "オブジェクトタイプが指定されていません。",
"Enter new" : "新規に入力",
- "Delete" : "削除",
"Add" : "追加",
"Edit tags" : "タグを編集",
"Error loading dialog template: {error}" : "メッセージテンプレートの読み込みエラー: {error}",
@@ -184,15 +198,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "アップデートに失敗しました。",
"The update was successful. There were warnings." : "アップデートは成功しました。警告がありました。",
"The update was successful. Redirecting you to ownCloud now." : "アップデートに成功しました。今すぐownCloudにリダイレクトします。",
- "Couldn't reset password because the token is invalid" : "トークンが無効なため、パスワードをリセットできませんでした",
- "Couldn't reset password because the token is expired" : "トークンが期限切れのため、パスワードをリセットできませんでした",
- "Couldn't send reset email. Please make sure your username is correct." : "リセットメールを送信できませんでした。ユーザー名が正しいことを確認してください。",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "このユーザー名に紐付けられたメールアドレスがないため、リセットメールを送信できませんでした。管理者に問い合わせてください。",
- "%s password reset" : "%s パスワードリセット",
- "Use the following link to reset your password: {link}" : "パスワードをリセットするには次のリンクをクリックしてください: {link}",
- "New password" : "新しいパスワードを入力",
- "New Password" : "新しいパスワード",
- "Reset password" : "パスワードをリセット",
"Searching other places" : "他の場所の検索",
"No search results in other folders" : "他のフォルダーの検索結果はありません",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["他のフォルダーの検索件数 {count}"],
@@ -262,8 +267,13 @@ OC.L10N.register(
"Please try again or contact your administrator." : "もう一度試してみるか、管理者に問い合わせてください。",
"Log in" : "ログイン",
"Wrong password. Reset it?" : "パスワードが間違っています。リセットしますか?",
+ "Wrong password." : "パスワードが間違っています。",
"Stay logged in" : "ログインしたままにする",
"Alternative Logins" : "代替ログイン",
+ "Use the following link to reset your password: {link}" : "パスワードをリセットするには次のリンクをクリックしてください: {link}",
+ "New password" : "新しいパスワードを入力",
+ "New Password" : "新しいパスワード",
+ "Reset password" : "パスワードをリセット",
"This ownCloud instance is currently in single user mode." : "このownCloudインスタンスは、現在シングルユーザーモードです。",
"This means only administrators can use the instance." : "これは、管理者のみがインスタンスを利用できることを意味しています。",
"Contact your system administrator if this message persists or appeared unexpectedly." : "このメッセージが引き続きもしくは予期せず現れる場合は、システム管理者に問い合わせてください。",
diff --git a/core/l10n/ja.json b/core/l10n/ja.json
index 21cd77dacbb..4dbcaac6a08 100644
--- a/core/l10n/ja.json
+++ b/core/l10n/ja.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "\"%s\" を %s にアップデートしました。",
"Repair warning: " : "修復警告:",
"Repair error: " : "修復エラー:",
- "Set log level to debug - current level: \"%s\"" : "ログレベルをデバッグにセットします - 現在のレベル: \"%s\"",
- "Reset log level to \"%s\"" : "ログレベルを \"%s\" にリセットします。",
+ "Set log level to debug" : "ログをデバッグレベルに設定",
+ "Reset log level" : "ログレベルをリセット",
+ "Starting code integrity check" : "コード整合性の確認を開始",
+ "Finished code integrity check" : "コード整合性の確認が終了",
"%s (3rdparty)" : "%s (サードパーティー)",
"%s (incompatible)" : "%s (非互換)",
"Following apps have been disabled: %s" : "以下のアプリが無効にされています: %s",
- "Already up to date" : "全て更新済",
+ "Already up to date" : "すべて更新済",
+ "Please select a file." : "ファイルを選択してください。",
"File is too big" : "ファイルが大きすぎます",
"Invalid file provided" : "無効なファイルが提供されました",
"No image or file provided" : "画像もしくはファイルが提供されていません",
@@ -30,6 +33,12 @@
"No crop data provided" : "クロップデータは提供されません",
"No valid crop data provided" : "有効なクロップデータは提供されません",
"Crop is not square" : "クロップが正方形ではありません",
+ "Couldn't reset password because the token is invalid" : "トークンが無効なため、パスワードをリセットできませんでした",
+ "Couldn't reset password because the token is expired" : "トークンが期限切れのため、パスワードをリセットできませんでした",
+ "Couldn't send reset email. Please make sure your username is correct." : "リセットメールを送信できませんでした。ユーザー名が正しいことを確認してください。",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "このユーザー名に紐付けられたメールアドレスがないため、リセットメールを送信できませんでした。管理者に問い合わせてください。",
+ "%s password reset" : "%s パスワードリセット",
+ "Couldn't send reset email. Please contact your administrator." : "リセットメールを送信できませんでした。管理者に問い合わせてください。",
"Sunday" : "日",
"Monday" : "月",
"Tuesday" : "火",
@@ -75,10 +84,10 @@
"Oct." : "10月",
"Nov." : "11月",
"Dec." : "12月",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">コード整合性の確認で問題が発生しました。詳しくはこちら…</a>",
"Settings" : "設定",
"Saving..." : "保存中...",
"seconds ago" : "数秒前",
- "Couldn't send reset email. Please contact your administrator." : "リセットメールを送信できませんでした。管理者に問い合わせてください。",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "パスワードをリセットするリンクをクリックしたので、メールを送信しました。しばらくたってもメールが届かなかった場合は、スパム/ジャンクフォルダーを確認してください。<br>それでも見つからなかった場合は、管理者に問合わせてください。",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "ファイルが暗号化されています。リカバリーキーが有効でない場合は、パスワードをリセットした後にあなたのデータを元に戻す方法はありません。<br />どういうことか分からない場合は、操作を継続する前に管理者に問い合わせてください。<br />続けてよろしいでしょうか?",
"I know what I'm doing" : "どういう操作をしているか理解しています",
@@ -109,11 +118,12 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "WebDAVインターフェースが動作していないようです。Webサーバーは、ファイルの同期を許可するよう適切に設定されていません。",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "このサーバーはインターネットに接続していません。この場合、外部ストレージのマウント、更新の通知やサードパーティ製のアプリ、といった一部の機能が利用できません。また、リモート接続でのファイルアクセス、通知メールの送信のような機能も利用できないことがあります。すべての機能を利用するには、このサーバーのインターネット接続を有効にすることをお勧めします。",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "データディレクトリとファイルがインターネットからアクセス可能になっている可能性があります。.htaccessファイルが機能していません。データディレクトリがアクセスされないようにWebサーバーを設定するか、Webサーバーのドキュメントルートからデータディレクトリを移動するように強くお勧めします。",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "メモリキャッシュが設定されていません。パフォーマンスを向上するために、可能であれば memcache を設定してください。 より詳しい情報については、<a href=\"{docLink}\">documentation</a> を参照してください。",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom は PHP から読み取ることができず、この状態はセキュリティの観点からおすすめできません。より詳しい情報については、<a href=\"{docLink}\">documentation</a> を参照ください。",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "ご利用のPHPのバージョン ({version}) は、<a href=\"{phpLink}\">PHPでサポート</a> されていません。 我々は、PHPから提供されている新しいバージョンにアップグレードし、それによるセキュリティの確保とパフォーマンスのメリットを受けられることを強くお勧めします。",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "リバースプロキシーのヘッダー設定が間違っているか、または信頼されたプロキシーからownCloudにアクセスしていません。もし、信頼されたプロキシーからアクセスしているのでないなら、セキュリティに問題があり、ownCloudを詐称したIPアドレスから攻撃者に対して見えるよう許可していることになります。詳細な情報は、<a href=\"{docLink}\">ドキュメント</a>を確認してください。",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached は分散キャッシュとして設定されていますが、間違った\"memcache\"のPHPモジュールがインストールされています。 \\OC\\Memcache\\Memcached は、\"memcached\" のみをサポートしていますが、\"memcache\" ではありません。<a href=\"{wikiLink}\">memcached wiki で両方のモジュール</a> を見てください。",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "メモリキャッシュが設定されていません。パフォーマンスを向上するために、可能であれば memcache を設定してください。 より詳しい情報については、<a target=\"_blank\" href=\"{docLink}\">ドキュメント</a> を参照してください。",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom は PHP から読み取ることができず、この状態はセキュリティの観点からおすすめできません。より詳しい情報については、<a target=\"_blank\" href=\"{docLink}\">ドキュメント</a> を参照ください。",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "ご利用のPHPのバージョン ({version}) は、<a target=\"_blank\" href=\"{phpLink}\">PHPでサポート</a> されていません。セキュリティ確保とパフォーマンス向上のために、PHPから提供されている新しいバージョンにアップグレードすることを強くお勧めします。",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "リバースプロキシのヘッダー設定が間違っているか、または信頼されたプロキシからownCloudにアクセスしていません。もし、信頼されたプロキシからアクセスしているのでないなら、セキュリティに問題があり、ownCloudを詐称したIPアドレスから攻撃者に対して見えるよう許可していることになります。詳細な情報は、 <a target=\"_blank\" href=\"{docLink}\">ドキュメント</a>を確認してください。",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached は分散キャッシュとして設定されています。しかし、PHPモジュール \"memcache\"が間違ってインストールされています。 \\OC\\Memcache\\Memcached は、\"memcached\" のみをサポートしています。\"memcache\" ではありません。<a target=\"_blank\" href=\"{wikiLink}\">memcached wiki で両方のモジュール</a> について確認してください。",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "いくつかのファイルで整合性の確認に失敗しました。この問題を解決するための詳細情報は<a target=\"_blank\" href=\"{docLink}\">ドキュメント</a>にあります。 (<a href=\"{codeIntegrityDownloadEndpoint}\">不適正なファイルのリスト…</a> / <a href=\"{rescanEndpoint}\">再スキャン…</a>)",
"Error occurred while checking server setup" : "サーバー設定のチェック中にエラーが発生しました",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP ヘッダは \"{expected}\" に設定されていません。これは潜在的なセキュリティリスクもしくはプライバシーリスクとなる可能性があるため、この設定を見直すことをおすすめします。",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"Strict-Transport-Security\" HTTP ヘッダが最小値の \"{seconds}\" 秒に設定されていません。 セキュリティを強化するため、<a href=\"{docUrl}\">security tips</a>を参照して、HSTS を有効にすることをおすすめします。",
@@ -123,7 +133,6 @@
"Error" : "エラー",
"Error while sharing" : "共有でエラー発生",
"Error while unsharing" : "共有解除でエラー発生",
- "Error while changing permissions" : "権限変更でエラー発生",
"Error setting expiration date" : "有効期限の設定でエラー発生",
"The public link will expire no later than {days} days after it is created" : "URLによる共有は、作成してから {days} 日以内に有効期限切れになります",
"Set expiration date" : "有効期限を設定",
@@ -142,7 +151,6 @@
"Send" : "送信",
"Shared with you and the group {group} by {owner}" : "あなたと {owner} のグループ {group} で共有中",
"Shared with you by {owner}" : "{owner} と共有中",
- "Shared in {item} with {user}" : "{item} 内で {user} と共有中",
"group" : "グループ",
"remote" : "リモート",
"notify by email" : "メールで通知",
@@ -153,17 +161,23 @@
"change" : "更新",
"delete" : "削除",
"access control" : "アクセス権限",
+ "Could not unshare" : "共有の解除ができませんでした",
"Share details could not be loaded for this item." : "共有の詳細はこのアイテムによりロードできませんでした。",
"An error occured. Please try again" : "エラーが発生しました。もう一度トライしてください。",
"Share" : "共有",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "次の形式で指定して他のownCloudのユーザーと、共有",
"Share with users or groups …" : "ユーザーもしくはグループと共有 ...",
"Share with users, groups or remote users …" : "ユーザー、グループもしくはリモートユーザーと共有 ...",
+ "Error removing share" : "共有の削除エラー",
"Warning" : "警告",
"Error while sending notification" : "通知送信中にエラーが発生",
+ "Non-existing tag #{tag}" : "存在しないタグ#{tag}",
+ "not assignable" : "割り当てできない",
+ "Delete" : "削除",
+ "Rename" : "名前の変更",
+ "Global tags" : "グローバルタグ",
"The object type is not specified." : "オブジェクトタイプが指定されていません。",
"Enter new" : "新規に入力",
- "Delete" : "削除",
"Add" : "追加",
"Edit tags" : "タグを編集",
"Error loading dialog template: {error}" : "メッセージテンプレートの読み込みエラー: {error}",
@@ -182,15 +196,6 @@
"The update was unsuccessful. " : "アップデートに失敗しました。",
"The update was successful. There were warnings." : "アップデートは成功しました。警告がありました。",
"The update was successful. Redirecting you to ownCloud now." : "アップデートに成功しました。今すぐownCloudにリダイレクトします。",
- "Couldn't reset password because the token is invalid" : "トークンが無効なため、パスワードをリセットできませんでした",
- "Couldn't reset password because the token is expired" : "トークンが期限切れのため、パスワードをリセットできませんでした",
- "Couldn't send reset email. Please make sure your username is correct." : "リセットメールを送信できませんでした。ユーザー名が正しいことを確認してください。",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "このユーザー名に紐付けられたメールアドレスがないため、リセットメールを送信できませんでした。管理者に問い合わせてください。",
- "%s password reset" : "%s パスワードリセット",
- "Use the following link to reset your password: {link}" : "パスワードをリセットするには次のリンクをクリックしてください: {link}",
- "New password" : "新しいパスワードを入力",
- "New Password" : "新しいパスワード",
- "Reset password" : "パスワードをリセット",
"Searching other places" : "他の場所の検索",
"No search results in other folders" : "他のフォルダーの検索結果はありません",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["他のフォルダーの検索件数 {count}"],
@@ -260,8 +265,13 @@
"Please try again or contact your administrator." : "もう一度試してみるか、管理者に問い合わせてください。",
"Log in" : "ログイン",
"Wrong password. Reset it?" : "パスワードが間違っています。リセットしますか?",
+ "Wrong password." : "パスワードが間違っています。",
"Stay logged in" : "ログインしたままにする",
"Alternative Logins" : "代替ログイン",
+ "Use the following link to reset your password: {link}" : "パスワードをリセットするには次のリンクをクリックしてください: {link}",
+ "New password" : "新しいパスワードを入力",
+ "New Password" : "新しいパスワード",
+ "Reset password" : "パスワードをリセット",
"This ownCloud instance is currently in single user mode." : "このownCloudインスタンスは、現在シングルユーザーモードです。",
"This means only administrators can use the instance." : "これは、管理者のみがインスタンスを利用できることを意味しています。",
"Contact your system administrator if this message persists or appeared unexpectedly." : "このメッセージが引き続きもしくは予期せず現れる場合は、システム管理者に問い合わせてください。",
diff --git a/core/l10n/ka_GE.js b/core/l10n/ka_GE.js
index d70352ee92c..a8c5cbd4c85 100644
--- a/core/l10n/ka_GE.js
+++ b/core/l10n/ka_GE.js
@@ -52,7 +52,6 @@ OC.L10N.register(
"Error" : "შეცდომა",
"Error while sharing" : "შეცდომა გაზიარების დროს",
"Error while unsharing" : "შეცდომა გაზიარების გაუქმების დროს",
- "Error while changing permissions" : "შეცდომა დაშვების ცვლილების დროს",
"Error setting expiration date" : "შეცდომა ვადის გასვლის მითითების დროს",
"Set expiration date" : "მიუთითე ვადის გასვლის დრო",
"Expiration" : "ვადის გასვლის დრო",
@@ -66,7 +65,6 @@ OC.L10N.register(
"Send" : "გაგზავნა",
"Shared with you and the group {group} by {owner}" : "გაზიარდა თქვენთვის და ჯგუფისთვის {group}, {owner}–ის მიერ",
"Shared with you by {owner}" : "გაზიარდა თქვენთვის {owner}–ის მიერ",
- "Shared in {item} with {user}" : "გაზიარდა {item}–ში {user}–ის მიერ",
"group" : "ჯგუფი",
"Unshare" : "გაუზიარებადი",
"can edit" : "შეგიძლია შეცვლა",
@@ -75,13 +73,11 @@ OC.L10N.register(
"access control" : "დაშვების კონტროლი",
"Share" : "გაზიარება",
"Warning" : "გაფრთხილება",
- "The object type is not specified." : "ობიექტის ტიპი არ არის მითითებული.",
"Delete" : "წაშლა",
+ "Rename" : "გადარქმევა",
+ "The object type is not specified." : "ობიექტის ტიპი არ არის მითითებული.",
"Add" : "დამატება",
"The update was successful. Redirecting you to ownCloud now." : "განახლება ვერ განხორციელდა. გადამისამართება თქვენს ownCloud–ზე.",
- "Use the following link to reset your password: {link}" : "გამოიყენე შემდეგი ლინკი პაროლის შესაცვლელად: {link}",
- "New password" : "ახალი პაროლი",
- "Reset password" : "პაროლის შეცვლა",
"Personal" : "პირადი",
"Users" : "მომხმარებელი",
"Apps" : "აპლიკაციები",
@@ -102,6 +98,9 @@ OC.L10N.register(
"Log out" : "გამოსვლა",
"Search" : "ძებნა",
"Log in" : "შესვლა",
- "Alternative Logins" : "ალტერნატიული Login–ი"
+ "Alternative Logins" : "ალტერნატიული Login–ი",
+ "Use the following link to reset your password: {link}" : "გამოიყენე შემდეგი ლინკი პაროლის შესაცვლელად: {link}",
+ "New password" : "ახალი პაროლი",
+ "Reset password" : "პაროლის შეცვლა"
},
"nplurals=1; plural=0;");
diff --git a/core/l10n/ka_GE.json b/core/l10n/ka_GE.json
index fb6adcf7e77..ce66a7a4566 100644
--- a/core/l10n/ka_GE.json
+++ b/core/l10n/ka_GE.json
@@ -50,7 +50,6 @@
"Error" : "შეცდომა",
"Error while sharing" : "შეცდომა გაზიარების დროს",
"Error while unsharing" : "შეცდომა გაზიარების გაუქმების დროს",
- "Error while changing permissions" : "შეცდომა დაშვების ცვლილების დროს",
"Error setting expiration date" : "შეცდომა ვადის გასვლის მითითების დროს",
"Set expiration date" : "მიუთითე ვადის გასვლის დრო",
"Expiration" : "ვადის გასვლის დრო",
@@ -64,7 +63,6 @@
"Send" : "გაგზავნა",
"Shared with you and the group {group} by {owner}" : "გაზიარდა თქვენთვის და ჯგუფისთვის {group}, {owner}–ის მიერ",
"Shared with you by {owner}" : "გაზიარდა თქვენთვის {owner}–ის მიერ",
- "Shared in {item} with {user}" : "გაზიარდა {item}–ში {user}–ის მიერ",
"group" : "ჯგუფი",
"Unshare" : "გაუზიარებადი",
"can edit" : "შეგიძლია შეცვლა",
@@ -73,13 +71,11 @@
"access control" : "დაშვების კონტროლი",
"Share" : "გაზიარება",
"Warning" : "გაფრთხილება",
- "The object type is not specified." : "ობიექტის ტიპი არ არის მითითებული.",
"Delete" : "წაშლა",
+ "Rename" : "გადარქმევა",
+ "The object type is not specified." : "ობიექტის ტიპი არ არის მითითებული.",
"Add" : "დამატება",
"The update was successful. Redirecting you to ownCloud now." : "განახლება ვერ განხორციელდა. გადამისამართება თქვენს ownCloud–ზე.",
- "Use the following link to reset your password: {link}" : "გამოიყენე შემდეგი ლინკი პაროლის შესაცვლელად: {link}",
- "New password" : "ახალი პაროლი",
- "Reset password" : "პაროლის შეცვლა",
"Personal" : "პირადი",
"Users" : "მომხმარებელი",
"Apps" : "აპლიკაციები",
@@ -100,6 +96,9 @@
"Log out" : "გამოსვლა",
"Search" : "ძებნა",
"Log in" : "შესვლა",
- "Alternative Logins" : "ალტერნატიული Login–ი"
+ "Alternative Logins" : "ალტერნატიული Login–ი",
+ "Use the following link to reset your password: {link}" : "გამოიყენე შემდეგი ლინკი პაროლის შესაცვლელად: {link}",
+ "New password" : "ახალი პაროლი",
+ "Reset password" : "პაროლის შეცვლა"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/core/l10n/km.js b/core/l10n/km.js
index c84f02018d3..de686fb77f1 100644
--- a/core/l10n/km.js
+++ b/core/l10n/km.js
@@ -63,7 +63,6 @@ OC.L10N.register(
"Error" : "កំហុស",
"Error while sharing" : "កំហុស​ពេល​ចែក​រំលែក",
"Error while unsharing" : "កំពុង​ពេល​លែង​ចែក​រំលែក",
- "Error while changing permissions" : "មាន​កំហុស​នៅ​ពេល​ប្ដូរ​សិទ្ធិ",
"Set expiration date" : "កំណត់​ពេល​ផុត​កំណត់",
"Expiration date" : "ពេល​ផុត​កំណត់",
"Sending ..." : "កំពុង​ផ្ញើ ...",
@@ -74,7 +73,6 @@ OC.L10N.register(
"Send" : "ផ្ញើ",
"Shared with you and the group {group} by {owner}" : "បាន​ចែក​រំលែក​ជាមួយ​អ្នក និង​ក្រុម {group} ដោយ {owner}",
"Shared with you by {owner}" : "បាន​ចែក​រំលែក​ជាមួយ​អ្នក​ដោយ {owner}",
- "Shared in {item} with {user}" : "បាន​ចែក​រំលែក​ក្នុង {item} ជាមួយ {user}",
"group" : "ក្រុម",
"Unshare" : "លែង​ចែក​រំលែក",
"can share" : "អាច​ចែក​រំលែក",
@@ -84,12 +82,11 @@ OC.L10N.register(
"access control" : "សិទ្ធិ​បញ្ជា",
"Share" : "ចែក​រំលែក",
"Warning" : "បម្រាម",
- "The object type is not specified." : "មិន​បាន​កំណត់​ប្រភេទ​វត្ថុ។",
"Delete" : "លុប",
+ "Rename" : "ប្ដូរ​ឈ្មោះ",
+ "The object type is not specified." : "មិន​បាន​កំណត់​ប្រភេទ​វត្ថុ។",
"Add" : "បញ្ចូល",
"Please reload the page." : "សូម​ផ្ទុក​ទំព័រ​នេះ​ឡើង​វិញ។",
- "New password" : "ពាក្យ​សម្ងាត់​ថ្មី",
- "Reset password" : "កំណត់​ពាក្យ​សម្ងាត់​ម្ដង​ទៀត",
"Personal" : "ផ្ទាល់​ខ្លួន",
"Users" : "អ្នកប្រើ",
"Apps" : "កម្មវិធី",
@@ -110,6 +107,8 @@ OC.L10N.register(
"Log out" : "ចាក​ចេញ",
"Search" : "ស្វែង​រក",
"Log in" : "ចូល",
- "Alternative Logins" : "ការ​ចូល​ជំនួស"
+ "Alternative Logins" : "ការ​ចូល​ជំនួស",
+ "New password" : "ពាក្យ​សម្ងាត់​ថ្មី",
+ "Reset password" : "កំណត់​ពាក្យ​សម្ងាត់​ម្ដង​ទៀត"
},
"nplurals=1; plural=0;");
diff --git a/core/l10n/km.json b/core/l10n/km.json
index 480b6bb7b77..4c8a72f6864 100644
--- a/core/l10n/km.json
+++ b/core/l10n/km.json
@@ -61,7 +61,6 @@
"Error" : "កំហុស",
"Error while sharing" : "កំហុស​ពេល​ចែក​រំលែក",
"Error while unsharing" : "កំពុង​ពេល​លែង​ចែក​រំលែក",
- "Error while changing permissions" : "មាន​កំហុស​នៅ​ពេល​ប្ដូរ​សិទ្ធិ",
"Set expiration date" : "កំណត់​ពេល​ផុត​កំណត់",
"Expiration date" : "ពេល​ផុត​កំណត់",
"Sending ..." : "កំពុង​ផ្ញើ ...",
@@ -72,7 +71,6 @@
"Send" : "ផ្ញើ",
"Shared with you and the group {group} by {owner}" : "បាន​ចែក​រំលែក​ជាមួយ​អ្នក និង​ក្រុម {group} ដោយ {owner}",
"Shared with you by {owner}" : "បាន​ចែក​រំលែក​ជាមួយ​អ្នក​ដោយ {owner}",
- "Shared in {item} with {user}" : "បាន​ចែក​រំលែក​ក្នុង {item} ជាមួយ {user}",
"group" : "ក្រុម",
"Unshare" : "លែង​ចែក​រំលែក",
"can share" : "អាច​ចែក​រំលែក",
@@ -82,12 +80,11 @@
"access control" : "សិទ្ធិ​បញ្ជា",
"Share" : "ចែក​រំលែក",
"Warning" : "បម្រាម",
- "The object type is not specified." : "មិន​បាន​កំណត់​ប្រភេទ​វត្ថុ។",
"Delete" : "លុប",
+ "Rename" : "ប្ដូរ​ឈ្មោះ",
+ "The object type is not specified." : "មិន​បាន​កំណត់​ប្រភេទ​វត្ថុ។",
"Add" : "បញ្ចូល",
"Please reload the page." : "សូម​ផ្ទុក​ទំព័រ​នេះ​ឡើង​វិញ។",
- "New password" : "ពាក្យ​សម្ងាត់​ថ្មី",
- "Reset password" : "កំណត់​ពាក្យ​សម្ងាត់​ម្ដង​ទៀត",
"Personal" : "ផ្ទាល់​ខ្លួន",
"Users" : "អ្នកប្រើ",
"Apps" : "កម្មវិធី",
@@ -108,6 +105,8 @@
"Log out" : "ចាក​ចេញ",
"Search" : "ស្វែង​រក",
"Log in" : "ចូល",
- "Alternative Logins" : "ការ​ចូល​ជំនួស"
+ "Alternative Logins" : "ការ​ចូល​ជំនួស",
+ "New password" : "ពាក្យ​សម្ងាត់​ថ្មី",
+ "Reset password" : "កំណត់​ពាក្យ​សម្ងាត់​ម្ដង​ទៀត"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/core/l10n/kn.js b/core/l10n/kn.js
index cf16300c759..3f45d4ab4c8 100644
--- a/core/l10n/kn.js
+++ b/core/l10n/kn.js
@@ -13,6 +13,10 @@ OC.L10N.register(
"Invalid image" : "ಅಸಾಮರ್ಥ್ಯ ಚಿತ್ರ",
"No temporary profile picture available, try again" : "ಯಾವುದೇ ತಾತ್ಕಾಲಿಕ ವ್ಯಕ್ತಿ ಚಿತ್ರ ದೊರಕುತ್ತಿಲ್ಲ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ",
"No crop data provided" : "ಸುಕ್ಕು ಒದಗಿಸಿದ ಮಾಹಿತಿ ",
+ "Couldn't reset password because the token is invalid" : "ಚಿಹ್ನೆ ಅಮಾನ್ಯವಾಗಿದೆ, ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
+ "Couldn't send reset email. Please make sure your username is correct." : "ಬದಲಾವಣೆಯ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ನಿಮ್ಮ ಬಳಕೆದಾರ ಹೆಸರು ಸರಿಯಾಗಿದೆ ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.",
+ "%s password reset" : "%s ಗುಪ್ತ ಪದವನ್ನು ಮರುಹೊಂದಿಸಿ",
+ "Couldn't send reset email. Please contact your administrator." : "ರೀಸೆಟ್ ಇಮೇಲ್ ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.",
"Sunday" : "ಭಾನುವಾರ",
"Monday" : "ಸೋಮವಾರ",
"Tuesday" : "ಮಂಗಳವಾರ",
@@ -34,7 +38,6 @@ OC.L10N.register(
"December" : "ಡಿಸೆಂಬರ್",
"Settings" : "ಆಯ್ಕೆಗಳು",
"Saving..." : "ಉಳಿಸಲಾಗುತ್ತಿದೆ ...",
- "Couldn't send reset email. Please contact your administrator." : "ರೀಸೆಟ್ ಇಮೇಲ್ ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "ನಿಮ್ಮ ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಅಂತ್ರಜಾಲ ಕೊಂಡಿಯನ್ನು ನಿಮ್ಮ ಇ-ಅಂಚೆ ಪೆಟ್ಟಿಗೆಗೆ ಕಳುಹಿಸಲಾಗಿದೆ. ಇದನ್ನು ನಿರ್ದಿಷ್ಟ ಸಮಯದಲ್ಲಿ ಇ-ಅಂಚೆ ಪೆಟ್ಟಿಗೆಯ ಮುಖ್ಯ ಕೂಶದಲ್ಲಿ ಪಡೆಯದಿದ್ದಲ್ಲಿ, ಇತರೇ ಕೂಶಗಳನ್ನು ಪರಿಶೀಲಿಸಿ. <br> ಇದು ಇನ್ನು ಬಾರದೆ ಇದ್ದರೆ, ನಿಮ್ಮ ಸ್ಥಳೀಯ ಸಂಕೀರ್ಣ ವ್ಯವಸ್ಥೆಯ ನಿರ್ವಾಹಕರ ಸಹಾಯ ಕೇಳಿ.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "ನಿಮ್ಮ ಕಡತಗಳನ್ನು ಎನ್ಕ್ರಿಪ್ಟ್. ನೀವು ಚೇತರಿಕೆ ಕೀ ಸಶಕ್ತ ಇದ್ದರೆ, ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ ರೀಸೆಟ್ ಮತ್ತೆ ನಂತರ ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಪಡೆಯಲು ಯಾವುದೇ ದಾರಿ ಇರುತ್ತದೆ. <br /> ನೀವು ಏನು ಖಚಿತವಾಗಿ ಇದ್ದರೆ ನೀವು ಮುಂದುವರೆಯಲು ಮೊದಲು, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ. <br /> ನೀವು ನಿಜವಾಗಿಯೂ ಮುಂದುವರಿಸಲು ಬಯಸುತ್ತೀರಾ?",
"I know what I'm doing" : "ಏನು ಮಾಡುತ್ತಿರುವೆ ಎಂದು ನನಗೆ ತಿಳಿದಿದೆ",
@@ -64,7 +67,6 @@ OC.L10N.register(
"Error" : "ತಪ್ಪಾಗಿದೆ",
"Error while sharing" : "ಹಂಚುವಾಗ ಏನೊ ಲೋಪವಾಗಿದೆ",
"Error while unsharing" : " ಹಂಚಿಕೆಯನ್ನು ಹಿಂದೆರುಗಿಸು ಸಂದರ್ಭದಲ್ಲಿ ಲೋಪವಾಗಿದೆ",
- "Error while changing permissions" : "ಅನುಮತಿಗಳನ್ನು ಬದಲಾವಣೆ ಮಾಡುವಾಗ ದೋಷವಾಗಿದೆ",
"Error setting expiration date" : "ಮುಕ್ತಾಯ ದಿನಾಂಕವನ್ನು ನಿರ್ದರಿಸುವಲ್ಲಿ ದೋಷ",
"The public link will expire no later than {days} days after it is created" : "ರಚನೆಯಾದ {days} ದಿನಗಳ ನಂತರ ಈ ಸಾರ್ವಜನಿಕ ಸಂಪರ್ಕ ಕೊಂಡಿ ಅಂತ್ಯಗೊಳ್ಳಲಿದೆ",
"Set expiration date" : "ಮುಕ್ತಾಯ ದಿನಾಂಕವನ್ನು ನಿರ್ದರಿಸಿ",
@@ -83,7 +85,6 @@ OC.L10N.register(
"Send" : "ಕಳುಹಿಸಿ",
"Shared with you and the group {group} by {owner}" : "ನಿಮಗೆ ಮತ್ತು {group} ಗುಂಪಿನೂಂದಿಗೆ {owner} ಹಂಚಿಕೊಂಡಿದ್ದಾರೆ",
"Shared with you by {owner}" : "ನಿಮ್ಮೊಂದಿಗೆ {owner} ಹಂಚಿಕೊಂಡಿದ್ದಾರೆ",
- "Shared in {item} with {user}" : "{user} ಜೊತೆ {item} ಹಂಚಿಕೊಳ್ಳಲಾಗಿದೆ",
"group" : "ಗುಂಪು",
"remote" : "ಆಚೆಯ",
"notify by email" : "ಇ-ಅಂಚೆ ಮೂಲಕ ತಿಳಿಸಲು",
@@ -96,9 +97,10 @@ OC.L10N.register(
"access control" : "ಪ್ರವೇಶ ನಿಯಂತ್ರಣ",
"Share" : "ಹಂಚಿಕೊಳ್ಳಿ",
"Warning" : "ಎಚ್ಚರಿಕೆ",
+ "Delete" : "ಅಳಿಸಿ",
+ "Rename" : "ಮರುಹೆಸರಿಸು",
"The object type is not specified." : "ವಸ್ತು ಮಾದರಿ ನಿರ್ದಿಷ್ಟಪಡಿಸಲಾಗಿಲ್ಲ.",
"Enter new" : "ಹೊಸ ನಮೂದನೆ",
- "Delete" : "ಅಳಿಸಿ",
"Add" : "ಸೇರಿಸಿ",
"Edit tags" : "ಕಿರು-ಪದ ಗಳನ್ನು ಸಂಪಾದಿಸು",
"No tags selected for deletion." : "ಯಾವುದೇ ಕಿರು ಪದಗಳನ್ನ ಅಳಿಸಲು ಆಯ್ಕೆ ಇಲ್ಲ.",
@@ -109,14 +111,6 @@ OC.L10N.register(
"_download %n file_::_download %n files_" : ["%n ಕಡತಗಳನ್ನು ಸ್ಥಳೀಯ ಪ್ರತಿಯಾಗಿಸಿ"],
"Please reload the page." : "ಪುಟವನ್ನು ಪುನಃ ನವೀಕರಿಸಿ.",
"The update was unsuccessful. " : "ಆಧುನೀಕರಿಣೆ ಯಶಸ್ವಿಯಾಗಿಲ್ಲ.",
- "Couldn't reset password because the token is invalid" : "ಚಿಹ್ನೆ ಅಮಾನ್ಯವಾಗಿದೆ, ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
- "Couldn't send reset email. Please make sure your username is correct." : "ಬದಲಾವಣೆಯ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ನಿಮ್ಮ ಬಳಕೆದಾರ ಹೆಸರು ಸರಿಯಾಗಿದೆ ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "ಈ ಬಳಕೆದಾರನ ಹೆಸರಿನ್ನಲ್ಲಿ ಯಾವುದೇ ಇ-ಅಂಚೆ ವಿಳಾಸ ಇಲ್ಲದರಿರುವುದರಿಂದ ಬದಲಾವಣೆಯ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.",
- "%s password reset" : "%s ಗುಪ್ತ ಪದವನ್ನು ಮರುಹೊಂದಿಸಿ",
- "Use the following link to reset your password: {link}" : "ನಿಮ್ಮ ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಕೆಳಗಿನ ಅಂತ್ರಜಾಲ ಕೊಂಡಿಯನ್ನು ಬಳಸಿ : {link}",
- "New password" : "ಹೊಸ ಗುಪ್ತಪದ",
- "New Password" : "ಹೊಸ ಗುಪ್ತಪದ",
- "Reset password" : "ಗುಪ್ತ ಪದವನ್ನು ಮರುಹೊಂದಿಸಿ",
"Personal" : "ವೈಯಕ್ತಿಕ",
"Users" : "ಬಳಕೆದಾರರು",
"Apps" : "ಕಾರ್ಯಕ್ರಮಗಳು",
@@ -157,6 +151,10 @@ OC.L10N.register(
"Log out" : "ಈ ಆವೃತ್ತಿ ಇಂದ ನಿರ್ಗಮಿಸಿ",
"Search" : "ಹುಡುಕು",
"Please contact your administrator." : "ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಲು ಕೋರಲಾಗಿದೆ.",
+ "Use the following link to reset your password: {link}" : "ನಿಮ್ಮ ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಕೆಳಗಿನ ಅಂತ್ರಜಾಲ ಕೊಂಡಿಯನ್ನು ಬಳಸಿ : {link}",
+ "New password" : "ಹೊಸ ಗುಪ್ತಪದ",
+ "New Password" : "ಹೊಸ ಗುಪ್ತಪದ",
+ "Reset password" : "ಗುಪ್ತ ಪದವನ್ನು ಮರುಹೊಂದಿಸಿ",
"This ownCloud instance is currently in single user mode." : "ಪ್ರಸ್ತುತ ಕ್ರಮದಲ್ಲಿ, ಈ OwnCloud ನ್ನು ಕೇವಲ ಒಬ್ಬನೇ ಬಳಕೆದಾರ ಮಾತ್ರ ಬಳಸಬಹುದಾಗಿದೆ.",
"This means only administrators can use the instance." : "ಇದರ ಅರ್ಥ, ಸದ್ಯದ ನಿದರ್ಶನದಲ್ಲಿ ನಿರ್ವಾಹಕರು ಮಾತ್ರ ಬಳಸಬಹುದಾಗಿದೆ.",
"Thank you for your patience." : "ನಿಮ್ಮ ತಾಳ್ಮೆಗೆ ಧನ್ಯವಾದಗಳು.",
diff --git a/core/l10n/kn.json b/core/l10n/kn.json
index a7ea1bba098..316e48955ac 100644
--- a/core/l10n/kn.json
+++ b/core/l10n/kn.json
@@ -11,6 +11,10 @@
"Invalid image" : "ಅಸಾಮರ್ಥ್ಯ ಚಿತ್ರ",
"No temporary profile picture available, try again" : "ಯಾವುದೇ ತಾತ್ಕಾಲಿಕ ವ್ಯಕ್ತಿ ಚಿತ್ರ ದೊರಕುತ್ತಿಲ್ಲ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ",
"No crop data provided" : "ಸುಕ್ಕು ಒದಗಿಸಿದ ಮಾಹಿತಿ ",
+ "Couldn't reset password because the token is invalid" : "ಚಿಹ್ನೆ ಅಮಾನ್ಯವಾಗಿದೆ, ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
+ "Couldn't send reset email. Please make sure your username is correct." : "ಬದಲಾವಣೆಯ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ನಿಮ್ಮ ಬಳಕೆದಾರ ಹೆಸರು ಸರಿಯಾಗಿದೆ ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.",
+ "%s password reset" : "%s ಗುಪ್ತ ಪದವನ್ನು ಮರುಹೊಂದಿಸಿ",
+ "Couldn't send reset email. Please contact your administrator." : "ರೀಸೆಟ್ ಇಮೇಲ್ ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.",
"Sunday" : "ಭಾನುವಾರ",
"Monday" : "ಸೋಮವಾರ",
"Tuesday" : "ಮಂಗಳವಾರ",
@@ -32,7 +36,6 @@
"December" : "ಡಿಸೆಂಬರ್",
"Settings" : "ಆಯ್ಕೆಗಳು",
"Saving..." : "ಉಳಿಸಲಾಗುತ್ತಿದೆ ...",
- "Couldn't send reset email. Please contact your administrator." : "ರೀಸೆಟ್ ಇಮೇಲ್ ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "ನಿಮ್ಮ ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಅಂತ್ರಜಾಲ ಕೊಂಡಿಯನ್ನು ನಿಮ್ಮ ಇ-ಅಂಚೆ ಪೆಟ್ಟಿಗೆಗೆ ಕಳುಹಿಸಲಾಗಿದೆ. ಇದನ್ನು ನಿರ್ದಿಷ್ಟ ಸಮಯದಲ್ಲಿ ಇ-ಅಂಚೆ ಪೆಟ್ಟಿಗೆಯ ಮುಖ್ಯ ಕೂಶದಲ್ಲಿ ಪಡೆಯದಿದ್ದಲ್ಲಿ, ಇತರೇ ಕೂಶಗಳನ್ನು ಪರಿಶೀಲಿಸಿ. <br> ಇದು ಇನ್ನು ಬಾರದೆ ಇದ್ದರೆ, ನಿಮ್ಮ ಸ್ಥಳೀಯ ಸಂಕೀರ್ಣ ವ್ಯವಸ್ಥೆಯ ನಿರ್ವಾಹಕರ ಸಹಾಯ ಕೇಳಿ.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "ನಿಮ್ಮ ಕಡತಗಳನ್ನು ಎನ್ಕ್ರಿಪ್ಟ್. ನೀವು ಚೇತರಿಕೆ ಕೀ ಸಶಕ್ತ ಇದ್ದರೆ, ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ ರೀಸೆಟ್ ಮತ್ತೆ ನಂತರ ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಪಡೆಯಲು ಯಾವುದೇ ದಾರಿ ಇರುತ್ತದೆ. <br /> ನೀವು ಏನು ಖಚಿತವಾಗಿ ಇದ್ದರೆ ನೀವು ಮುಂದುವರೆಯಲು ಮೊದಲು, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ. <br /> ನೀವು ನಿಜವಾಗಿಯೂ ಮುಂದುವರಿಸಲು ಬಯಸುತ್ತೀರಾ?",
"I know what I'm doing" : "ಏನು ಮಾಡುತ್ತಿರುವೆ ಎಂದು ನನಗೆ ತಿಳಿದಿದೆ",
@@ -62,7 +65,6 @@
"Error" : "ತಪ್ಪಾಗಿದೆ",
"Error while sharing" : "ಹಂಚುವಾಗ ಏನೊ ಲೋಪವಾಗಿದೆ",
"Error while unsharing" : " ಹಂಚಿಕೆಯನ್ನು ಹಿಂದೆರುಗಿಸು ಸಂದರ್ಭದಲ್ಲಿ ಲೋಪವಾಗಿದೆ",
- "Error while changing permissions" : "ಅನುಮತಿಗಳನ್ನು ಬದಲಾವಣೆ ಮಾಡುವಾಗ ದೋಷವಾಗಿದೆ",
"Error setting expiration date" : "ಮುಕ್ತಾಯ ದಿನಾಂಕವನ್ನು ನಿರ್ದರಿಸುವಲ್ಲಿ ದೋಷ",
"The public link will expire no later than {days} days after it is created" : "ರಚನೆಯಾದ {days} ದಿನಗಳ ನಂತರ ಈ ಸಾರ್ವಜನಿಕ ಸಂಪರ್ಕ ಕೊಂಡಿ ಅಂತ್ಯಗೊಳ್ಳಲಿದೆ",
"Set expiration date" : "ಮುಕ್ತಾಯ ದಿನಾಂಕವನ್ನು ನಿರ್ದರಿಸಿ",
@@ -81,7 +83,6 @@
"Send" : "ಕಳುಹಿಸಿ",
"Shared with you and the group {group} by {owner}" : "ನಿಮಗೆ ಮತ್ತು {group} ಗುಂಪಿನೂಂದಿಗೆ {owner} ಹಂಚಿಕೊಂಡಿದ್ದಾರೆ",
"Shared with you by {owner}" : "ನಿಮ್ಮೊಂದಿಗೆ {owner} ಹಂಚಿಕೊಂಡಿದ್ದಾರೆ",
- "Shared in {item} with {user}" : "{user} ಜೊತೆ {item} ಹಂಚಿಕೊಳ್ಳಲಾಗಿದೆ",
"group" : "ಗುಂಪು",
"remote" : "ಆಚೆಯ",
"notify by email" : "ಇ-ಅಂಚೆ ಮೂಲಕ ತಿಳಿಸಲು",
@@ -94,9 +95,10 @@
"access control" : "ಪ್ರವೇಶ ನಿಯಂತ್ರಣ",
"Share" : "ಹಂಚಿಕೊಳ್ಳಿ",
"Warning" : "ಎಚ್ಚರಿಕೆ",
+ "Delete" : "ಅಳಿಸಿ",
+ "Rename" : "ಮರುಹೆಸರಿಸು",
"The object type is not specified." : "ವಸ್ತು ಮಾದರಿ ನಿರ್ದಿಷ್ಟಪಡಿಸಲಾಗಿಲ್ಲ.",
"Enter new" : "ಹೊಸ ನಮೂದನೆ",
- "Delete" : "ಅಳಿಸಿ",
"Add" : "ಸೇರಿಸಿ",
"Edit tags" : "ಕಿರು-ಪದ ಗಳನ್ನು ಸಂಪಾದಿಸು",
"No tags selected for deletion." : "ಯಾವುದೇ ಕಿರು ಪದಗಳನ್ನ ಅಳಿಸಲು ಆಯ್ಕೆ ಇಲ್ಲ.",
@@ -107,14 +109,6 @@
"_download %n file_::_download %n files_" : ["%n ಕಡತಗಳನ್ನು ಸ್ಥಳೀಯ ಪ್ರತಿಯಾಗಿಸಿ"],
"Please reload the page." : "ಪುಟವನ್ನು ಪುನಃ ನವೀಕರಿಸಿ.",
"The update was unsuccessful. " : "ಆಧುನೀಕರಿಣೆ ಯಶಸ್ವಿಯಾಗಿಲ್ಲ.",
- "Couldn't reset password because the token is invalid" : "ಚಿಹ್ನೆ ಅಮಾನ್ಯವಾಗಿದೆ, ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
- "Couldn't send reset email. Please make sure your username is correct." : "ಬದಲಾವಣೆಯ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ನಿಮ್ಮ ಬಳಕೆದಾರ ಹೆಸರು ಸರಿಯಾಗಿದೆ ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "ಈ ಬಳಕೆದಾರನ ಹೆಸರಿನ್ನಲ್ಲಿ ಯಾವುದೇ ಇ-ಅಂಚೆ ವಿಳಾಸ ಇಲ್ಲದರಿರುವುದರಿಂದ ಬದಲಾವಣೆಯ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.",
- "%s password reset" : "%s ಗುಪ್ತ ಪದವನ್ನು ಮರುಹೊಂದಿಸಿ",
- "Use the following link to reset your password: {link}" : "ನಿಮ್ಮ ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಕೆಳಗಿನ ಅಂತ್ರಜಾಲ ಕೊಂಡಿಯನ್ನು ಬಳಸಿ : {link}",
- "New password" : "ಹೊಸ ಗುಪ್ತಪದ",
- "New Password" : "ಹೊಸ ಗುಪ್ತಪದ",
- "Reset password" : "ಗುಪ್ತ ಪದವನ್ನು ಮರುಹೊಂದಿಸಿ",
"Personal" : "ವೈಯಕ್ತಿಕ",
"Users" : "ಬಳಕೆದಾರರು",
"Apps" : "ಕಾರ್ಯಕ್ರಮಗಳು",
@@ -155,6 +149,10 @@
"Log out" : "ಈ ಆವೃತ್ತಿ ಇಂದ ನಿರ್ಗಮಿಸಿ",
"Search" : "ಹುಡುಕು",
"Please contact your administrator." : "ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಲು ಕೋರಲಾಗಿದೆ.",
+ "Use the following link to reset your password: {link}" : "ನಿಮ್ಮ ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಲು ಕೆಳಗಿನ ಅಂತ್ರಜಾಲ ಕೊಂಡಿಯನ್ನು ಬಳಸಿ : {link}",
+ "New password" : "ಹೊಸ ಗುಪ್ತಪದ",
+ "New Password" : "ಹೊಸ ಗುಪ್ತಪದ",
+ "Reset password" : "ಗುಪ್ತ ಪದವನ್ನು ಮರುಹೊಂದಿಸಿ",
"This ownCloud instance is currently in single user mode." : "ಪ್ರಸ್ತುತ ಕ್ರಮದಲ್ಲಿ, ಈ OwnCloud ನ್ನು ಕೇವಲ ಒಬ್ಬನೇ ಬಳಕೆದಾರ ಮಾತ್ರ ಬಳಸಬಹುದಾಗಿದೆ.",
"This means only administrators can use the instance." : "ಇದರ ಅರ್ಥ, ಸದ್ಯದ ನಿದರ್ಶನದಲ್ಲಿ ನಿರ್ವಾಹಕರು ಮಾತ್ರ ಬಳಸಬಹುದಾಗಿದೆ.",
"Thank you for your patience." : "ನಿಮ್ಮ ತಾಳ್ಮೆಗೆ ಧನ್ಯವಾದಗಳು.",
diff --git a/core/l10n/ko.js b/core/l10n/ko.js
index 97c6d5dcdec..ea6019900b4 100644
--- a/core/l10n/ko.js
+++ b/core/l10n/ko.js
@@ -16,8 +16,6 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "\"%s\"을(를) %s(으)로 업데이트함",
"Repair warning: " : "수리 경고:",
"Repair error: " : "수리 오류:",
- "Set log level to debug - current level: \"%s\"" : "로그 단계를 디버그로 설정함 - 현재 단계: \"%s\"",
- "Reset log level to \"%s\"" : "로그 단계를 \"%s\"(으)로 초기화",
"%s (3rdparty)" : "%s(제 3사)",
"%s (incompatible)" : "%s(호환 불가)",
"Following apps have been disabled: %s" : "다음 앱이 비활성화되었습니다: %s",
@@ -32,6 +30,11 @@ OC.L10N.register(
"No crop data provided" : "선택된 데이터가 없습니다.",
"No valid crop data provided" : "올바른 잘라내기 데이터가 지정되지 않음",
"Crop is not square" : "잘라내는 영역이 사각형이 아님",
+ "Couldn't reset password because the token is invalid" : "토큰이 잘못되었기 때문에 암호를 초기화할 수 없습니다",
+ "Couldn't reset password because the token is expired" : "토큰이 만료되어 암호를 초기화할 수 없습니다",
+ "Couldn't send reset email. Please make sure your username is correct." : "재설정 메일을 보낼 수 없습니다. 사용자 이름이 올바른지 확인하십시오.",
+ "%s password reset" : "%s 암호 재설정",
+ "Couldn't send reset email. Please contact your administrator." : "재설정 메일을 보낼수 없습니다. 관리자에게 문의하십시오.",
"Sunday" : "일요일",
"Monday" : "월요일",
"Tuesday" : "화요일",
@@ -80,7 +83,6 @@ OC.L10N.register(
"Settings" : "설정",
"Saving..." : "저장 중...",
"seconds ago" : "초 지남",
- "Couldn't send reset email. Please contact your administrator." : "재설정 메일을 보낼수 없습니다. 관리자에게 문의하십시오.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "암호 재설정 링크를 포함하고 있는 이메일을 보냈습니다. 이메일이 도착하지 않은 경우 스팸함을 확인해 보십시오.<br>스팸함에도 없는 경우 로컬 관리자에게 문의하십시오.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "파일이 암호화되어 있습니다. 복구 키를 활성화하지 않았다면 암호를 초기화한 후 데이터를 복구할 수 없습니다.<br />무엇을 해야 할 지 잘 모르겠으면 계속하기 전에 관리자에게 연락하십시오.<br />그래도 계속 진행하시겠습니까?",
"I know what I'm doing" : "지금 하려는 것을 알고 있습니다",
@@ -111,11 +113,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "WebDAV 서비스가 올바르게 작동하지 않아서 웹 서버에서 파일 동기화를 사용할 수 없습니다.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "서버에서 인터넷 연결을 사용할 수 없습니다. 외부 저장소 마운트, 업데이트 알림, 제 3자 앱 설치 등 기능을 사용할 수 없습니다. 원격에서 파일에 접근하거나, 알림 이메일을 보내지 못할 수도 있습니다. 모든 기능을 사용하려면 인터넷에 연결하는 것을 추천합니다.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "인터넷에서 데이터 디렉터리와 파일에 접근할 수 있습니다. .htaccess 파일이 작동하지 않습니다. 웹 서버 설정을 변경하여 데이터 디렉터리에 직접 접근할 수 없도록 하거나, 데이터 디렉터리를 웹 서버 문서 경로 바깥에 두십시오.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "메모리 캐시가 설정되지 않았습니다. 성능을 향상시키려면 사용 가능한 경우 메모리 캐시를 설정하십시오. 더 많은 정보를 보려면 <a href=\"{docLink}\">문서</a>를 참고하십시오.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP에서 /dev/urandom을 읽을 수 없으며, 보안상의 이유로 권장되지 않습니다. 더 많은 정보를 보려면 <a href=\"{docLink}\">문서</a>를 참고하십시오.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "사용하고 있는 PHP 버전({version})은 더 이상 <a href=\"{phpLink}\">PHP에서 지원하지 않습니다.</a> PHP를 업그레이드하여 성능 및 보안 개선을 누리십시오.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "역방향 프록시 헤더 설정이 잘못되었거나, 신뢰할 수 있는 프록시에서 ownCloud에 접근하고 있습니다. 신뢰할 수 있는 프록시에서 ownCloud에 접근하는 것이 아니라면, 이 상황은 보안 문제이며 공격자가 ownCloud에 접근하는 IP 주소를 속일 수 있습니다. 더 많은 정보를 보려면 <a href=\"{docLink}\">문서</a>를 참고하십시오.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "분산 캐시로 Memcached가 설정되었으나, 잘못된 PHP 모듈 \"memcache\"가 설치되어 있습니다. \\OC\\Memcache\\Memcached는 \"memcached\"를 지원하며, \"memcache\"를 지원하지 않습니다. <a href=\"{wikiLink}\">memcached 위키의 두 모듈에 관한 정보</a>를 참조하십시오.",
"Error occurred while checking server setup" : "서버 설정을 확인하는 중 오류 발생",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP 헤더가 \"{expected}\"와(과) 같이 설정되지 않았습니다. 잠재적인 보안 위협이 될 수 있으므로 설정을 변경하는 것을 추천합니다.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP 헤더 \"Strict-Transport-Security\"가 최소한 \"{seconds}\"초 이상으로 설정되어야 합니다. 강화된 보안을 위해서 <a href=\"{docUrl}\">보안 팁</a>에 나타난 것처럼 HSTS를 활성화하는 것을 추천합니다.",
@@ -125,7 +122,6 @@ OC.L10N.register(
"Error" : "오류",
"Error while sharing" : "공유하는 중 오류 발생",
"Error while unsharing" : "공유 해제하는 중 오류 발생",
- "Error while changing permissions" : "권한 변경하는 중 오류 발생",
"Error setting expiration date" : "만료 날짜 설정 오류",
"The public link will expire no later than {days} days after it is created" : "공개 링크를 만든 후 최대 {days}일까지 유지됩니다",
"Set expiration date" : "만료 날짜 설정",
@@ -144,7 +140,6 @@ OC.L10N.register(
"Send" : "전송",
"Shared with you and the group {group} by {owner}" : "{owner} 님이 여러분 및 그룹 {group}와(과) 공유 중",
"Shared with you by {owner}" : "{owner} 님이 공유 중",
- "Shared in {item} with {user}" : "{user} 님과 {item}에서 공유 중",
"group" : "그룹",
"remote" : "원격",
"notify by email" : "이메일로 알림",
@@ -163,9 +158,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "사용자, 그룹 및 원격 사용자와 공유...",
"Warning" : "경고",
"Error while sending notification" : "알림을 보내는 중 오류 발생",
+ "Delete" : "삭제",
+ "Rename" : "이름 바꾸기",
"The object type is not specified." : "객체 유형이 지정되지 않았습니다.",
"Enter new" : "새로운 값 입력",
- "Delete" : "삭제",
"Add" : "추가",
"Edit tags" : "태그 편집",
"Error loading dialog template: {error}" : "대화 상자 템플릿을 불러오는 중 오류 발생: {error}",
@@ -184,15 +180,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "업데이트가 실패했습니다. ",
"The update was successful. There were warnings." : "업데이트가 성공했습니다. 일부 경고가 있습니다.",
"The update was successful. Redirecting you to ownCloud now." : "업데이트가 성공했습니다. ownCloud로 돌아갑니다.",
- "Couldn't reset password because the token is invalid" : "토큰이 잘못되었기 때문에 암호를 초기화할 수 없습니다",
- "Couldn't reset password because the token is expired" : "토큰이 만료되어 암호를 초기화할 수 없습니다",
- "Couldn't send reset email. Please make sure your username is correct." : "재설정 메일을 보낼 수 없습니다. 사용자 이름이 올바른지 확인하십시오.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "해당 사용자 이름에 등록된 이메일 주소가 없어서 재설정 메일을 보낼 수 없습니다. 관리자에게 문의하십시오.",
- "%s password reset" : "%s 암호 재설정",
- "Use the following link to reset your password: {link}" : "다음 링크를 사용하여 암호를 재설정할 수 있습니다: {link}",
- "New password" : "새 암호",
- "New Password" : "새 암호",
- "Reset password" : "암호 재설정",
"Searching other places" : "다른 장소 찾는 중",
"No search results in other folders" : "다른 폴더에 검색 결과 없음",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["다른 폴더의 검색 결과 {count}개"],
@@ -264,6 +251,10 @@ OC.L10N.register(
"Wrong password. Reset it?" : "암호가 잘못되었습니다. 다시 설정하시겠습니까?",
"Stay logged in" : "로그인 유지",
"Alternative Logins" : "대체 로그인",
+ "Use the following link to reset your password: {link}" : "다음 링크를 사용하여 암호를 재설정할 수 있습니다: {link}",
+ "New password" : "새 암호",
+ "New Password" : "새 암호",
+ "Reset password" : "암호 재설정",
"This ownCloud instance is currently in single user mode." : "ownCloud 인스턴스가 현재 단일 사용자 모드로 동작 중입니다.",
"This means only administrators can use the instance." : "현재 시스템 관리자만 인스턴스를 사용할 수 있습니다.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "이 메시지가 계속 표시되거나, 예상하지 못하였을 때 표시된다면 시스템 관리자에게 연락하십시오",
diff --git a/core/l10n/ko.json b/core/l10n/ko.json
index 293242a2f62..8ce1b2b5632 100644
--- a/core/l10n/ko.json
+++ b/core/l10n/ko.json
@@ -14,8 +14,6 @@
"Updated \"%s\" to %s" : "\"%s\"을(를) %s(으)로 업데이트함",
"Repair warning: " : "수리 경고:",
"Repair error: " : "수리 오류:",
- "Set log level to debug - current level: \"%s\"" : "로그 단계를 디버그로 설정함 - 현재 단계: \"%s\"",
- "Reset log level to \"%s\"" : "로그 단계를 \"%s\"(으)로 초기화",
"%s (3rdparty)" : "%s(제 3사)",
"%s (incompatible)" : "%s(호환 불가)",
"Following apps have been disabled: %s" : "다음 앱이 비활성화되었습니다: %s",
@@ -30,6 +28,11 @@
"No crop data provided" : "선택된 데이터가 없습니다.",
"No valid crop data provided" : "올바른 잘라내기 데이터가 지정되지 않음",
"Crop is not square" : "잘라내는 영역이 사각형이 아님",
+ "Couldn't reset password because the token is invalid" : "토큰이 잘못되었기 때문에 암호를 초기화할 수 없습니다",
+ "Couldn't reset password because the token is expired" : "토큰이 만료되어 암호를 초기화할 수 없습니다",
+ "Couldn't send reset email. Please make sure your username is correct." : "재설정 메일을 보낼 수 없습니다. 사용자 이름이 올바른지 확인하십시오.",
+ "%s password reset" : "%s 암호 재설정",
+ "Couldn't send reset email. Please contact your administrator." : "재설정 메일을 보낼수 없습니다. 관리자에게 문의하십시오.",
"Sunday" : "일요일",
"Monday" : "월요일",
"Tuesday" : "화요일",
@@ -78,7 +81,6 @@
"Settings" : "설정",
"Saving..." : "저장 중...",
"seconds ago" : "초 지남",
- "Couldn't send reset email. Please contact your administrator." : "재설정 메일을 보낼수 없습니다. 관리자에게 문의하십시오.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "암호 재설정 링크를 포함하고 있는 이메일을 보냈습니다. 이메일이 도착하지 않은 경우 스팸함을 확인해 보십시오.<br>스팸함에도 없는 경우 로컬 관리자에게 문의하십시오.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "파일이 암호화되어 있습니다. 복구 키를 활성화하지 않았다면 암호를 초기화한 후 데이터를 복구할 수 없습니다.<br />무엇을 해야 할 지 잘 모르겠으면 계속하기 전에 관리자에게 연락하십시오.<br />그래도 계속 진행하시겠습니까?",
"I know what I'm doing" : "지금 하려는 것을 알고 있습니다",
@@ -109,11 +111,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "WebDAV 서비스가 올바르게 작동하지 않아서 웹 서버에서 파일 동기화를 사용할 수 없습니다.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "서버에서 인터넷 연결을 사용할 수 없습니다. 외부 저장소 마운트, 업데이트 알림, 제 3자 앱 설치 등 기능을 사용할 수 없습니다. 원격에서 파일에 접근하거나, 알림 이메일을 보내지 못할 수도 있습니다. 모든 기능을 사용하려면 인터넷에 연결하는 것을 추천합니다.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "인터넷에서 데이터 디렉터리와 파일에 접근할 수 있습니다. .htaccess 파일이 작동하지 않습니다. 웹 서버 설정을 변경하여 데이터 디렉터리에 직접 접근할 수 없도록 하거나, 데이터 디렉터리를 웹 서버 문서 경로 바깥에 두십시오.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "메모리 캐시가 설정되지 않았습니다. 성능을 향상시키려면 사용 가능한 경우 메모리 캐시를 설정하십시오. 더 많은 정보를 보려면 <a href=\"{docLink}\">문서</a>를 참고하십시오.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP에서 /dev/urandom을 읽을 수 없으며, 보안상의 이유로 권장되지 않습니다. 더 많은 정보를 보려면 <a href=\"{docLink}\">문서</a>를 참고하십시오.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "사용하고 있는 PHP 버전({version})은 더 이상 <a href=\"{phpLink}\">PHP에서 지원하지 않습니다.</a> PHP를 업그레이드하여 성능 및 보안 개선을 누리십시오.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "역방향 프록시 헤더 설정이 잘못되었거나, 신뢰할 수 있는 프록시에서 ownCloud에 접근하고 있습니다. 신뢰할 수 있는 프록시에서 ownCloud에 접근하는 것이 아니라면, 이 상황은 보안 문제이며 공격자가 ownCloud에 접근하는 IP 주소를 속일 수 있습니다. 더 많은 정보를 보려면 <a href=\"{docLink}\">문서</a>를 참고하십시오.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "분산 캐시로 Memcached가 설정되었으나, 잘못된 PHP 모듈 \"memcache\"가 설치되어 있습니다. \\OC\\Memcache\\Memcached는 \"memcached\"를 지원하며, \"memcache\"를 지원하지 않습니다. <a href=\"{wikiLink}\">memcached 위키의 두 모듈에 관한 정보</a>를 참조하십시오.",
"Error occurred while checking server setup" : "서버 설정을 확인하는 중 오류 발생",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP 헤더가 \"{expected}\"와(과) 같이 설정되지 않았습니다. 잠재적인 보안 위협이 될 수 있으므로 설정을 변경하는 것을 추천합니다.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP 헤더 \"Strict-Transport-Security\"가 최소한 \"{seconds}\"초 이상으로 설정되어야 합니다. 강화된 보안을 위해서 <a href=\"{docUrl}\">보안 팁</a>에 나타난 것처럼 HSTS를 활성화하는 것을 추천합니다.",
@@ -123,7 +120,6 @@
"Error" : "오류",
"Error while sharing" : "공유하는 중 오류 발생",
"Error while unsharing" : "공유 해제하는 중 오류 발생",
- "Error while changing permissions" : "권한 변경하는 중 오류 발생",
"Error setting expiration date" : "만료 날짜 설정 오류",
"The public link will expire no later than {days} days after it is created" : "공개 링크를 만든 후 최대 {days}일까지 유지됩니다",
"Set expiration date" : "만료 날짜 설정",
@@ -142,7 +138,6 @@
"Send" : "전송",
"Shared with you and the group {group} by {owner}" : "{owner} 님이 여러분 및 그룹 {group}와(과) 공유 중",
"Shared with you by {owner}" : "{owner} 님이 공유 중",
- "Shared in {item} with {user}" : "{user} 님과 {item}에서 공유 중",
"group" : "그룹",
"remote" : "원격",
"notify by email" : "이메일로 알림",
@@ -161,9 +156,10 @@
"Share with users, groups or remote users …" : "사용자, 그룹 및 원격 사용자와 공유...",
"Warning" : "경고",
"Error while sending notification" : "알림을 보내는 중 오류 발생",
+ "Delete" : "삭제",
+ "Rename" : "이름 바꾸기",
"The object type is not specified." : "객체 유형이 지정되지 않았습니다.",
"Enter new" : "새로운 값 입력",
- "Delete" : "삭제",
"Add" : "추가",
"Edit tags" : "태그 편집",
"Error loading dialog template: {error}" : "대화 상자 템플릿을 불러오는 중 오류 발생: {error}",
@@ -182,15 +178,6 @@
"The update was unsuccessful. " : "업데이트가 실패했습니다. ",
"The update was successful. There were warnings." : "업데이트가 성공했습니다. 일부 경고가 있습니다.",
"The update was successful. Redirecting you to ownCloud now." : "업데이트가 성공했습니다. ownCloud로 돌아갑니다.",
- "Couldn't reset password because the token is invalid" : "토큰이 잘못되었기 때문에 암호를 초기화할 수 없습니다",
- "Couldn't reset password because the token is expired" : "토큰이 만료되어 암호를 초기화할 수 없습니다",
- "Couldn't send reset email. Please make sure your username is correct." : "재설정 메일을 보낼 수 없습니다. 사용자 이름이 올바른지 확인하십시오.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "해당 사용자 이름에 등록된 이메일 주소가 없어서 재설정 메일을 보낼 수 없습니다. 관리자에게 문의하십시오.",
- "%s password reset" : "%s 암호 재설정",
- "Use the following link to reset your password: {link}" : "다음 링크를 사용하여 암호를 재설정할 수 있습니다: {link}",
- "New password" : "새 암호",
- "New Password" : "새 암호",
- "Reset password" : "암호 재설정",
"Searching other places" : "다른 장소 찾는 중",
"No search results in other folders" : "다른 폴더에 검색 결과 없음",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["다른 폴더의 검색 결과 {count}개"],
@@ -262,6 +249,10 @@
"Wrong password. Reset it?" : "암호가 잘못되었습니다. 다시 설정하시겠습니까?",
"Stay logged in" : "로그인 유지",
"Alternative Logins" : "대체 로그인",
+ "Use the following link to reset your password: {link}" : "다음 링크를 사용하여 암호를 재설정할 수 있습니다: {link}",
+ "New password" : "새 암호",
+ "New Password" : "새 암호",
+ "Reset password" : "암호 재설정",
"This ownCloud instance is currently in single user mode." : "ownCloud 인스턴스가 현재 단일 사용자 모드로 동작 중입니다.",
"This means only administrators can use the instance." : "현재 시스템 관리자만 인스턴스를 사용할 수 있습니다.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "이 메시지가 계속 표시되거나, 예상하지 못하였을 때 표시된다면 시스템 관리자에게 연락하십시오",
diff --git a/core/l10n/ku_IQ.js b/core/l10n/ku_IQ.js
index 066e7c365bc..82faa80db05 100644
--- a/core/l10n/ku_IQ.js
+++ b/core/l10n/ku_IQ.js
@@ -12,8 +12,6 @@ OC.L10N.register(
"Share" : "هاوبەشی کردن",
"Warning" : "ئاگاداری",
"Add" : "زیادکردن",
- "New password" : "وشەی نهێنی نوێ",
- "Reset password" : "دووباره‌ كردنه‌وه‌ی وشه‌ی نهێنی",
"Users" : "به‌كارهێنه‌ر",
"Apps" : "به‌رنامه‌كان",
"Admin" : "به‌ڕێوه‌به‌ری سه‌ره‌كی",
@@ -26,6 +24,8 @@ OC.L10N.register(
"Database host" : "هۆستی داتابه‌یس",
"Finish setup" : "كۆتایی هات ده‌ستكاریه‌كان",
"Log out" : "چوونەدەرەوە",
- "Search" : "بگەڕێ"
+ "Search" : "بگەڕێ",
+ "New password" : "وشەی نهێنی نوێ",
+ "Reset password" : "دووباره‌ كردنه‌وه‌ی وشه‌ی نهێنی"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/ku_IQ.json b/core/l10n/ku_IQ.json
index 601ad30d303..bc105c06e4e 100644
--- a/core/l10n/ku_IQ.json
+++ b/core/l10n/ku_IQ.json
@@ -10,8 +10,6 @@
"Share" : "هاوبەشی کردن",
"Warning" : "ئاگاداری",
"Add" : "زیادکردن",
- "New password" : "وشەی نهێنی نوێ",
- "Reset password" : "دووباره‌ كردنه‌وه‌ی وشه‌ی نهێنی",
"Users" : "به‌كارهێنه‌ر",
"Apps" : "به‌رنامه‌كان",
"Admin" : "به‌ڕێوه‌به‌ری سه‌ره‌كی",
@@ -24,6 +22,8 @@
"Database host" : "هۆستی داتابه‌یس",
"Finish setup" : "كۆتایی هات ده‌ستكاریه‌كان",
"Log out" : "چوونەدەرەوە",
- "Search" : "بگەڕێ"
+ "Search" : "بگەڕێ",
+ "New password" : "وشەی نهێنی نوێ",
+ "Reset password" : "دووباره‌ كردنه‌وه‌ی وشه‌ی نهێنی"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/lb.js b/core/l10n/lb.js
index 0d900dcfd69..956d75da53b 100644
--- a/core/l10n/lb.js
+++ b/core/l10n/lb.js
@@ -7,6 +7,7 @@ OC.L10N.register(
"No image or file provided" : "Kee Bild oder Fichier uginn",
"Unknown filetype" : "Onbekannten Fichier Typ",
"Invalid image" : "Ongülteg d'Bild",
+ "%s password reset" : "%s Passwuert ass nei gesat",
"Sunday" : "Sonndeg",
"Monday" : "Méindeg",
"Tuesday" : "Dënschdeg",
@@ -61,7 +62,6 @@ OC.L10N.register(
"Error" : "Feeler",
"Error while sharing" : "Feeler beim Deelen",
"Error while unsharing" : "Feeler beim Annuléiere vum Deelen",
- "Error while changing permissions" : "Feeler beim Ännere vun de Rechter",
"Error setting expiration date" : "Feeler beim Setze vum Verfallsdatum",
"Set expiration date" : "Verfallsdatum setzen",
"Expiration date" : "Verfallsdatum",
@@ -75,7 +75,6 @@ OC.L10N.register(
"Send" : "Schécken",
"Shared with you and the group {group} by {owner}" : "Gedeelt mat dir an der Grupp {group} vum {owner}",
"Shared with you by {owner}" : "Gedeelt mat dir vum {owner}",
- "Shared in {item} with {user}" : "Gedeelt an {item} mat {user}",
"group" : "Grupp",
"notify by email" : "via e-mail Bescheed ginn",
"Unshare" : "Net méi deelen",
@@ -86,16 +85,13 @@ OC.L10N.register(
"access control" : "Zougrëffskontroll",
"Share" : "Deelen",
"Warning" : "Warnung",
+ "Delete" : "Läschen",
+ "Rename" : "Ëmbenennen",
"The object type is not specified." : "Den Typ vum Object ass net uginn.",
"Enter new" : "Gëff nei an",
- "Delete" : "Läschen",
"Add" : "Dobäisetzen",
"Edit tags" : "Tags editéieren",
"The update was successful. Redirecting you to ownCloud now." : "Den Update war erfollegräich. Du gëss elo bei d'ownCloud ëmgeleet.",
- "%s password reset" : "%s Passwuert ass nei gesat",
- "Use the following link to reset your password: {link}" : "Benotz folgende Link fir däi Passwuert zréckzesetzen: {link}",
- "New password" : "Neit Passwuert",
- "Reset password" : "Passwuert zréck setzen",
"Personal" : "Perséinlech",
"Users" : "Benotzer",
"Apps" : "Applikatiounen",
@@ -121,6 +117,9 @@ OC.L10N.register(
"Search" : "Sichen",
"Log in" : "Umellen",
"Alternative Logins" : "Alternativ Umeldungen",
+ "Use the following link to reset your password: {link}" : "Benotz folgende Link fir däi Passwuert zréckzesetzen: {link}",
+ "New password" : "Neit Passwuert",
+ "Reset password" : "Passwuert zréck setzen",
"Thank you for your patience." : "Merci fir deng Gedold."
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/lb.json b/core/l10n/lb.json
index c43c22990dc..39d913782fb 100644
--- a/core/l10n/lb.json
+++ b/core/l10n/lb.json
@@ -5,6 +5,7 @@
"No image or file provided" : "Kee Bild oder Fichier uginn",
"Unknown filetype" : "Onbekannten Fichier Typ",
"Invalid image" : "Ongülteg d'Bild",
+ "%s password reset" : "%s Passwuert ass nei gesat",
"Sunday" : "Sonndeg",
"Monday" : "Méindeg",
"Tuesday" : "Dënschdeg",
@@ -59,7 +60,6 @@
"Error" : "Feeler",
"Error while sharing" : "Feeler beim Deelen",
"Error while unsharing" : "Feeler beim Annuléiere vum Deelen",
- "Error while changing permissions" : "Feeler beim Ännere vun de Rechter",
"Error setting expiration date" : "Feeler beim Setze vum Verfallsdatum",
"Set expiration date" : "Verfallsdatum setzen",
"Expiration date" : "Verfallsdatum",
@@ -73,7 +73,6 @@
"Send" : "Schécken",
"Shared with you and the group {group} by {owner}" : "Gedeelt mat dir an der Grupp {group} vum {owner}",
"Shared with you by {owner}" : "Gedeelt mat dir vum {owner}",
- "Shared in {item} with {user}" : "Gedeelt an {item} mat {user}",
"group" : "Grupp",
"notify by email" : "via e-mail Bescheed ginn",
"Unshare" : "Net méi deelen",
@@ -84,16 +83,13 @@
"access control" : "Zougrëffskontroll",
"Share" : "Deelen",
"Warning" : "Warnung",
+ "Delete" : "Läschen",
+ "Rename" : "Ëmbenennen",
"The object type is not specified." : "Den Typ vum Object ass net uginn.",
"Enter new" : "Gëff nei an",
- "Delete" : "Läschen",
"Add" : "Dobäisetzen",
"Edit tags" : "Tags editéieren",
"The update was successful. Redirecting you to ownCloud now." : "Den Update war erfollegräich. Du gëss elo bei d'ownCloud ëmgeleet.",
- "%s password reset" : "%s Passwuert ass nei gesat",
- "Use the following link to reset your password: {link}" : "Benotz folgende Link fir däi Passwuert zréckzesetzen: {link}",
- "New password" : "Neit Passwuert",
- "Reset password" : "Passwuert zréck setzen",
"Personal" : "Perséinlech",
"Users" : "Benotzer",
"Apps" : "Applikatiounen",
@@ -119,6 +115,9 @@
"Search" : "Sichen",
"Log in" : "Umellen",
"Alternative Logins" : "Alternativ Umeldungen",
+ "Use the following link to reset your password: {link}" : "Benotz folgende Link fir däi Passwuert zréckzesetzen: {link}",
+ "New password" : "Neit Passwuert",
+ "Reset password" : "Passwuert zréck setzen",
"Thank you for your patience." : "Merci fir deng Gedold."
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/lt_LT.js b/core/l10n/lt_LT.js
index 1b9d4842913..756fff5139d 100644
--- a/core/l10n/lt_LT.js
+++ b/core/l10n/lt_LT.js
@@ -6,14 +6,13 @@ OC.L10N.register(
"Turned on maintenance mode" : "Įjungta priežiūros veiksena",
"Turned off maintenance mode" : "Išjungta priežiūros veiksena",
"Maintenance mode is kept active" : "Priežiūros veiksena yra aktyvi",
+ "Updating database schema" : "Atnaujinama duomenų bazės struktūra",
"Updated database" : "Atnaujinta duomenų bazė",
"Checked database schema update" : "Tikrinama duomenų bazės struktūra",
"Checked database schema update for apps" : "Tikrinama duomenų bazės struktūra įskiepiams",
"Updated \"%s\" to %s" : "Atnaujinta \"%s\" į %s",
"Repair warning: " : "Taisymo perspėjimas:",
"Repair error: " : "Taisymo klaida:",
- "Set log level to debug - current level: \"%s\"" : "Nustatykite žurnalų lygį į derinimas - dabar \"%s\"",
- "Reset log level to \"%s\"" : "Atkurkite žurnalų lygį į \"%s\"",
"Following apps have been disabled: %s" : "Išjungti įskiepiai: %s",
"Already up to date" : "Jau naujausia",
"File is too big" : "Per didelis failas",
@@ -23,6 +22,8 @@ OC.L10N.register(
"Invalid image" : "Netinkamas paveikslėlis",
"No temporary profile picture available, try again" : "Nėra laikino profilio paveikslėlio, bandykite dar kartą",
"No crop data provided" : "Nenurodyti apkirpimo duomenys",
+ "%s password reset" : "%s slaptažodžio atnaujinimas",
+ "Couldn't send reset email. Please contact your administrator." : "Nepavyko išsiųsti atkūrimo laiško, susisiekite su administratoriumi.",
"Sunday" : "Sekmadienis",
"Monday" : "Pirmadienis",
"Tuesday" : "Antradienis",
@@ -71,7 +72,6 @@ OC.L10N.register(
"Settings" : "Nustatymai",
"Saving..." : "Saugoma...",
"seconds ago" : "prieš sekundę",
- "Couldn't send reset email. Please contact your administrator." : "Nepavyko išsiųsti atkūrimo laiško, susisiekite su administratoriumi.",
"I know what I'm doing" : "Aš žinau ką darau",
"Password can not be changed. Please contact your administrator." : "Slaptažodis negali būti pakeistas, susisiekite su administratoriumi.",
"No" : "Ne",
@@ -101,7 +101,6 @@ OC.L10N.register(
"Error" : "Klaida",
"Error while sharing" : "Klaida, dalijimosi metu",
"Error while unsharing" : "Klaida, kai atšaukiamas dalijimasis",
- "Error while changing permissions" : "Klaida, keičiant privilegijas",
"Error setting expiration date" : "Klaida nustatant galiojimo laiką",
"The public link will expire no later than {days} days after it is created" : "Vieša nuoroda galios ne mažiau kaip {days} dienas nuo sukūrimo",
"Set expiration date" : "Nustatykite galiojimo laiką",
@@ -120,7 +119,6 @@ OC.L10N.register(
"Send" : "Siųsti",
"Shared with you and the group {group} by {owner}" : "Pasidalino su Jumis ir {group} grupe {owner}",
"Shared with you by {owner}" : "Pasidalino su Jumis {owner}",
- "Shared in {item} with {user}" : "Pasidalino {item} su {user}",
"group" : "grupė",
"remote" : "nutolęs",
"notify by email" : "pranešti el. paštu",
@@ -137,9 +135,10 @@ OC.L10N.register(
"Share with users or groups …" : "Dalintis su vartotoju ar grupe",
"Share with users, groups or remote users …" : "Dalintis su vartotoju, grupe, ar nutolusiu vartotoju...",
"Warning" : "Įspėjimas",
+ "Delete" : "Ištrinti",
+ "Rename" : "Pervadinti",
"The object type is not specified." : "Objekto tipas nenurodytas.",
"Enter new" : "Įveskite naują",
- "Delete" : "Ištrinti",
"Add" : "Pridėti",
"Edit tags" : "Redaguoti žymes",
"Error loading dialog template: {error}" : "Klaida įkeliant dialogo ruošinį: {error}",
@@ -148,11 +147,6 @@ OC.L10N.register(
"sunny" : "saulėta",
"Please reload the page." : "Prašome perkrauti puslapį.",
"The update was successful. Redirecting you to ownCloud now." : "Atnaujinimas buvo sėkmingas. Nukreipiame į jūsų ownCloud.",
- "%s password reset" : "%s slaptažodžio atnaujinimas",
- "Use the following link to reset your password: {link}" : "Slaptažodio atkūrimui naudokite šią nuorodą: {link}",
- "New password" : "Naujas slaptažodis",
- "New Password" : "Naujas slaptažodis",
- "Reset password" : "Atkurti slaptažodį",
"Personal" : "Asmeniniai",
"Users" : "Vartotojai",
"Apps" : "Programos",
@@ -193,6 +187,10 @@ OC.L10N.register(
"Please contact your administrator." : "Kreipkitės į savo sistemos administratorių.",
"Log in" : "Prisijungti",
"Alternative Logins" : "Alternatyvūs prisijungimai",
+ "Use the following link to reset your password: {link}" : "Slaptažodio atkūrimui naudokite šią nuorodą: {link}",
+ "New password" : "Naujas slaptažodis",
+ "New Password" : "Naujas slaptažodis",
+ "Reset password" : "Atkurti slaptažodį",
"This ownCloud instance is currently in single user mode." : "Ši ownCloud sistema yra vieno naudotojo veiksenoje.",
"This means only administrators can use the instance." : "Tai reiškia, kad tik administratorius gali naudotis sistema.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Susisiekite su savo sistemos administratoriumi jei šis pranešimas nedingsta arba jei jis pasirodė netikėtai.",
diff --git a/core/l10n/lt_LT.json b/core/l10n/lt_LT.json
index 8df5dc1ff48..541761aa35f 100644
--- a/core/l10n/lt_LT.json
+++ b/core/l10n/lt_LT.json
@@ -4,14 +4,13 @@
"Turned on maintenance mode" : "Įjungta priežiūros veiksena",
"Turned off maintenance mode" : "Išjungta priežiūros veiksena",
"Maintenance mode is kept active" : "Priežiūros veiksena yra aktyvi",
+ "Updating database schema" : "Atnaujinama duomenų bazės struktūra",
"Updated database" : "Atnaujinta duomenų bazė",
"Checked database schema update" : "Tikrinama duomenų bazės struktūra",
"Checked database schema update for apps" : "Tikrinama duomenų bazės struktūra įskiepiams",
"Updated \"%s\" to %s" : "Atnaujinta \"%s\" į %s",
"Repair warning: " : "Taisymo perspėjimas:",
"Repair error: " : "Taisymo klaida:",
- "Set log level to debug - current level: \"%s\"" : "Nustatykite žurnalų lygį į derinimas - dabar \"%s\"",
- "Reset log level to \"%s\"" : "Atkurkite žurnalų lygį į \"%s\"",
"Following apps have been disabled: %s" : "Išjungti įskiepiai: %s",
"Already up to date" : "Jau naujausia",
"File is too big" : "Per didelis failas",
@@ -21,6 +20,8 @@
"Invalid image" : "Netinkamas paveikslėlis",
"No temporary profile picture available, try again" : "Nėra laikino profilio paveikslėlio, bandykite dar kartą",
"No crop data provided" : "Nenurodyti apkirpimo duomenys",
+ "%s password reset" : "%s slaptažodžio atnaujinimas",
+ "Couldn't send reset email. Please contact your administrator." : "Nepavyko išsiųsti atkūrimo laiško, susisiekite su administratoriumi.",
"Sunday" : "Sekmadienis",
"Monday" : "Pirmadienis",
"Tuesday" : "Antradienis",
@@ -69,7 +70,6 @@
"Settings" : "Nustatymai",
"Saving..." : "Saugoma...",
"seconds ago" : "prieš sekundę",
- "Couldn't send reset email. Please contact your administrator." : "Nepavyko išsiųsti atkūrimo laiško, susisiekite su administratoriumi.",
"I know what I'm doing" : "Aš žinau ką darau",
"Password can not be changed. Please contact your administrator." : "Slaptažodis negali būti pakeistas, susisiekite su administratoriumi.",
"No" : "Ne",
@@ -99,7 +99,6 @@
"Error" : "Klaida",
"Error while sharing" : "Klaida, dalijimosi metu",
"Error while unsharing" : "Klaida, kai atšaukiamas dalijimasis",
- "Error while changing permissions" : "Klaida, keičiant privilegijas",
"Error setting expiration date" : "Klaida nustatant galiojimo laiką",
"The public link will expire no later than {days} days after it is created" : "Vieša nuoroda galios ne mažiau kaip {days} dienas nuo sukūrimo",
"Set expiration date" : "Nustatykite galiojimo laiką",
@@ -118,7 +117,6 @@
"Send" : "Siųsti",
"Shared with you and the group {group} by {owner}" : "Pasidalino su Jumis ir {group} grupe {owner}",
"Shared with you by {owner}" : "Pasidalino su Jumis {owner}",
- "Shared in {item} with {user}" : "Pasidalino {item} su {user}",
"group" : "grupė",
"remote" : "nutolęs",
"notify by email" : "pranešti el. paštu",
@@ -135,9 +133,10 @@
"Share with users or groups …" : "Dalintis su vartotoju ar grupe",
"Share with users, groups or remote users …" : "Dalintis su vartotoju, grupe, ar nutolusiu vartotoju...",
"Warning" : "Įspėjimas",
+ "Delete" : "Ištrinti",
+ "Rename" : "Pervadinti",
"The object type is not specified." : "Objekto tipas nenurodytas.",
"Enter new" : "Įveskite naują",
- "Delete" : "Ištrinti",
"Add" : "Pridėti",
"Edit tags" : "Redaguoti žymes",
"Error loading dialog template: {error}" : "Klaida įkeliant dialogo ruošinį: {error}",
@@ -146,11 +145,6 @@
"sunny" : "saulėta",
"Please reload the page." : "Prašome perkrauti puslapį.",
"The update was successful. Redirecting you to ownCloud now." : "Atnaujinimas buvo sėkmingas. Nukreipiame į jūsų ownCloud.",
- "%s password reset" : "%s slaptažodžio atnaujinimas",
- "Use the following link to reset your password: {link}" : "Slaptažodio atkūrimui naudokite šią nuorodą: {link}",
- "New password" : "Naujas slaptažodis",
- "New Password" : "Naujas slaptažodis",
- "Reset password" : "Atkurti slaptažodį",
"Personal" : "Asmeniniai",
"Users" : "Vartotojai",
"Apps" : "Programos",
@@ -191,6 +185,10 @@
"Please contact your administrator." : "Kreipkitės į savo sistemos administratorių.",
"Log in" : "Prisijungti",
"Alternative Logins" : "Alternatyvūs prisijungimai",
+ "Use the following link to reset your password: {link}" : "Slaptažodio atkūrimui naudokite šią nuorodą: {link}",
+ "New password" : "Naujas slaptažodis",
+ "New Password" : "Naujas slaptažodis",
+ "Reset password" : "Atkurti slaptažodį",
"This ownCloud instance is currently in single user mode." : "Ši ownCloud sistema yra vieno naudotojo veiksenoje.",
"This means only administrators can use the instance." : "Tai reiškia, kad tik administratorius gali naudotis sistema.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Susisiekite su savo sistemos administratoriumi jei šis pranešimas nedingsta arba jei jis pasirodė netikėtai.",
diff --git a/core/l10n/lv.js b/core/l10n/lv.js
index 95bc2a62165..fb79f8faf4c 100644
--- a/core/l10n/lv.js
+++ b/core/l10n/lv.js
@@ -7,6 +7,7 @@ OC.L10N.register(
"Updated database" : "Atjaunota datu bāze",
"Unknown filetype" : "Nezināms datnes tips",
"Invalid image" : "Nederīgs attēls",
+ "%s password reset" : "%s paroles maiņa",
"Sunday" : "Svētdiena",
"Monday" : "Pirmdiena",
"Tuesday" : "Otrdiena",
@@ -67,7 +68,6 @@ OC.L10N.register(
"Error" : "Kļūda",
"Error while sharing" : "Kļūda, daloties",
"Error while unsharing" : "Kļūda, beidzot dalīties",
- "Error while changing permissions" : "Kļūda, mainot atļaujas",
"Error setting expiration date" : "Kļūda, iestatot termiņa datumu",
"Set expiration date" : "Iestaties termiņa datumu",
"Expiration date" : "Termiņa datums",
@@ -81,7 +81,6 @@ OC.L10N.register(
"Send" : "Sūtīt",
"Shared with you and the group {group} by {owner}" : "{owner} dalījās ar jums un grupu {group}",
"Shared with you by {owner}" : "{owner} dalījās ar jums",
- "Shared in {item} with {user}" : "Dalījās ar {item} ar {user}",
"group" : "grupa",
"Unshare" : "Pārtraukt dalīšanos",
"can share" : "Var dalīties",
@@ -91,14 +90,11 @@ OC.L10N.register(
"access control" : "piekļuves vadība",
"Share" : "Dalīties",
"Warning" : "Brīdinājums",
- "The object type is not specified." : "Nav norādīts objekta tips.",
"Delete" : "Dzēst",
+ "Rename" : "Pārsaukt",
+ "The object type is not specified." : "Nav norādīts objekta tips.",
"Add" : "Pievienot",
"The update was successful. Redirecting you to ownCloud now." : "Atjaunināšana beidzās sekmīgi. Tagad pārsūta jūs uz ownCloud.",
- "%s password reset" : "%s paroles maiņa",
- "Use the following link to reset your password: {link}" : "Izmantojiet šo saiti, lai mainītu paroli: {link}",
- "New password" : "Jauna parole",
- "Reset password" : "Mainīt paroli",
"Personal" : "Personīgi",
"Users" : "Lietotāji",
"Apps" : "Lietotnes",
@@ -120,6 +116,9 @@ OC.L10N.register(
"Log out" : "Izrakstīties",
"Search" : "Meklēt",
"Log in" : "Ierakstīties",
- "Alternative Logins" : "Alternatīvās pieteikšanās"
+ "Alternative Logins" : "Alternatīvās pieteikšanās",
+ "Use the following link to reset your password: {link}" : "Izmantojiet šo saiti, lai mainītu paroli: {link}",
+ "New password" : "Jauna parole",
+ "Reset password" : "Mainīt paroli"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);");
diff --git a/core/l10n/lv.json b/core/l10n/lv.json
index 05dbd6b588e..6ffb0e194e7 100644
--- a/core/l10n/lv.json
+++ b/core/l10n/lv.json
@@ -5,6 +5,7 @@
"Updated database" : "Atjaunota datu bāze",
"Unknown filetype" : "Nezināms datnes tips",
"Invalid image" : "Nederīgs attēls",
+ "%s password reset" : "%s paroles maiņa",
"Sunday" : "Svētdiena",
"Monday" : "Pirmdiena",
"Tuesday" : "Otrdiena",
@@ -65,7 +66,6 @@
"Error" : "Kļūda",
"Error while sharing" : "Kļūda, daloties",
"Error while unsharing" : "Kļūda, beidzot dalīties",
- "Error while changing permissions" : "Kļūda, mainot atļaujas",
"Error setting expiration date" : "Kļūda, iestatot termiņa datumu",
"Set expiration date" : "Iestaties termiņa datumu",
"Expiration date" : "Termiņa datums",
@@ -79,7 +79,6 @@
"Send" : "Sūtīt",
"Shared with you and the group {group} by {owner}" : "{owner} dalījās ar jums un grupu {group}",
"Shared with you by {owner}" : "{owner} dalījās ar jums",
- "Shared in {item} with {user}" : "Dalījās ar {item} ar {user}",
"group" : "grupa",
"Unshare" : "Pārtraukt dalīšanos",
"can share" : "Var dalīties",
@@ -89,14 +88,11 @@
"access control" : "piekļuves vadība",
"Share" : "Dalīties",
"Warning" : "Brīdinājums",
- "The object type is not specified." : "Nav norādīts objekta tips.",
"Delete" : "Dzēst",
+ "Rename" : "Pārsaukt",
+ "The object type is not specified." : "Nav norādīts objekta tips.",
"Add" : "Pievienot",
"The update was successful. Redirecting you to ownCloud now." : "Atjaunināšana beidzās sekmīgi. Tagad pārsūta jūs uz ownCloud.",
- "%s password reset" : "%s paroles maiņa",
- "Use the following link to reset your password: {link}" : "Izmantojiet šo saiti, lai mainītu paroli: {link}",
- "New password" : "Jauna parole",
- "Reset password" : "Mainīt paroli",
"Personal" : "Personīgi",
"Users" : "Lietotāji",
"Apps" : "Lietotnes",
@@ -118,6 +114,9 @@
"Log out" : "Izrakstīties",
"Search" : "Meklēt",
"Log in" : "Ierakstīties",
- "Alternative Logins" : "Alternatīvās pieteikšanās"
+ "Alternative Logins" : "Alternatīvās pieteikšanās",
+ "Use the following link to reset your password: {link}" : "Izmantojiet šo saiti, lai mainītu paroli: {link}",
+ "New password" : "Jauna parole",
+ "Reset password" : "Mainīt paroli"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"
} \ No newline at end of file
diff --git a/core/l10n/mk.js b/core/l10n/mk.js
index e09dd51f6b8..07e25191b51 100644
--- a/core/l10n/mk.js
+++ b/core/l10n/mk.js
@@ -2,14 +2,21 @@ OC.L10N.register(
"core",
{
"Couldn't send mail to following users: %s " : "Не можев да пратам порака на следниве корисници: %s",
+ "Preparing update" : "Ја подготвувам надградбата",
"Turned on maintenance mode" : "Вклучен е модот за одржување",
"Turned off maintenance mode" : "Ислкучен е модот за одржување",
+ "Maintenance mode is kept active" : "Модот за одржување е уште активен",
+ "Updating database schema" : "Ја надградувам шемата на базата на податоци",
"Updated database" : "Базата е надградена",
"Checked database schema update" : "Проверена е шемата за ажурурање на базата на податоци",
"Checked database schema update for apps" : "Проверена е шемата за ажурурање на базата на податоци за апликации",
"Updated \"%s\" to %s" : "Ажурирано е \"%s\" во %s",
"Repair warning: " : "Предупредувања при поправка:",
"Repair error: " : "Грешка при поправка:",
+ "%s (3rdparty)" : "%s (3-та страна)",
+ "%s (incompatible)" : "%s (некомпатибилен)",
+ "Already up to date" : "Веќе ажурирано",
+ "File is too big" : "Датотеката е пре голема",
"Invalid file provided" : "Дадена е невалидна датотека",
"No image or file provided" : "Не е доставена фотографија или датотека",
"Unknown filetype" : "Непознат тип на датотека",
@@ -18,6 +25,8 @@ OC.L10N.register(
"No crop data provided" : "Не се доставени податоци за сечење",
"No valid crop data provided" : "Нема валидни податоци за сечење",
"Crop is not square" : "Сечењето не е правоаголно",
+ "%s password reset" : "%s ресетирање на лозинката",
+ "Couldn't send reset email. Please contact your administrator." : "Не можам да истпратам порака за ресетирање. Ве молам контактирајте го вашиот администратор.",
"Sunday" : "Недела",
"Monday" : "Понеделник",
"Tuesday" : "Вторник",
@@ -32,6 +41,13 @@ OC.L10N.register(
"Thu." : "Чет.",
"Fri." : "Пет.",
"Sat." : "Саб.",
+ "Su" : "Не",
+ "Mo" : "По",
+ "Tu" : "Вт",
+ "We" : "Ср",
+ "Th" : "Че",
+ "Fr" : "Пе",
+ "Sa" : "Са",
"January" : "Јануари",
"February" : "Февруари",
"March" : "Март",
@@ -59,7 +75,6 @@ OC.L10N.register(
"Settings" : "Подесувања",
"Saving..." : "Снимам...",
"seconds ago" : "пред секунди",
- "Couldn't send reset email. Please contact your administrator." : "Не можам да истпратам порака за ресетирање. Ве молам контактирајте го вашиот администратор.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Врската за ресетирање на вашата лозинка е испратена на вашата е-адреса. Ако не ја добиете во разумно време, проверете ги вашите папки за спам/ѓубре.<br>Ако не е таму прашајте го вашиот локален администратор.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Вашите датотеки се шифрирани. Ако не сте го овозможиле клучот за враќање, нема да можете да ги повратите вашите податоци откога вашата лозинка ќе биде ресетирана.<br>Ако не сте сигурни што да правите, ве молам контактирајте го вашиот локален администратор пред да продолжите.<br/>Дали навистина сакате да продолжите?",
"I know what I'm doing" : "Знам што правам",
@@ -89,7 +104,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Вашиот веб опслужувач сеуште не е точно подесен да овозможува синхронизација на датотеки бидејќи интерфејсот за WebDAV изгледа дека е расипан. ",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Овој опслужувач нема работна Интернет врска. Ова значи дека некои опции како што е монтирање на надворешни складишта, известувања за ажурирање или инсталации на апликации од 3-ти лица нема да работат. Пристапот на датотеки од далечина и праќање на пораки за известувања може исто така да не работат. Ви советуваме да овозможите Интернет врска за овој опслужувач ако сакате да ги имате сите опции. ",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Вашата папка за податоци и вашите датотеки се најверојатно достапни од интернет. Датотеката .htaccess не работи. Строго ви препорачуваме да го подесите вашиот веб опслужувач на начин на кој вашата папка за податоци не е веќе достапна од интернет или да ја преместите папката за податоци надвор од коренот на веб опслужувачот.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Не еконфигуриран кеш за меморијата. За да ги подобрите перформансите ве молам конфигурирајте memcache ако е достапно. Дополнителни информации можат да се најдат во нашата <a href=\"{docLink}\">документација</a>.",
"Error occurred while checking server setup" : "Се случи грешка при проверката на подесувањата на опслужувачот",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP заглавието \"{header}\" не е конфигурирано да биде еднакво на \"{expected}\". Ова е потенцијално сигурносен ризик и препорачуваме да прилагодат подесувањата.",
"Shared" : "Споделен",
@@ -97,45 +111,51 @@ OC.L10N.register(
"Error" : "Грешка",
"Error while sharing" : "Грешка при споделување",
"Error while unsharing" : "Грешка при прекин на споделување",
- "Error while changing permissions" : "Грешка при промена на привилегии",
"Error setting expiration date" : "Грешка при поставување на рок на траење",
"Set expiration date" : "Постави рок на траење",
"Expiration" : "Истекување",
"Expiration date" : "Рок на траење",
+ "Choose a password for the public link" : "Одбери лозинка за јавниот линк",
"Sending ..." : "Праќање...",
"Email sent" : "Е-порака пратена",
"Resharing is not allowed" : "Повторно споделување не е дозволено",
"Share link" : "Сподели ја врската",
+ "Link" : "Линк",
"Password protect" : "Заштити со лозинка",
"Password" : "Лозинка",
+ "Allow editing" : "Овозможи уредување",
"Email link to person" : "Прати врска по е-пошта на личност",
"Send" : "Прати",
"Shared with you and the group {group} by {owner}" : "Споделено со Вас и групата {group} од {owner}",
"Shared with you by {owner}" : "Споделено со Вас од {owner}",
- "Shared in {item} with {user}" : "Споделено во {item} со {user}",
"group" : "група",
+ "remote" : "далечински",
"notify by email" : "извести преку електронска пошта",
"Unshare" : "Не споделувај",
"can share" : "може да споделува",
"can edit" : "може да се измени",
"create" : "креирај",
+ "change" : "промени",
"delete" : "избриши",
"access control" : "контрола на пристап",
+ "An error occured. Please try again" : "Се случи грешка. Обиди се повторно",
"Share" : "Сподели",
"Share with users or groups …" : "Сподели со корисници или групи ...",
"Share with users, groups or remote users …" : "Споделено со корисници, групи или оддалечени корисници ...",
"Warning" : "Предупредување",
+ "Delete" : "Избриши",
+ "Rename" : "Преименувај",
"The object type is not specified." : "Не е специфициран типот на објект.",
"Enter new" : "Внеси нов",
- "Delete" : "Избриши",
"Add" : "Додади",
"Edit tags" : "Уреди ги таговите",
"No tags selected for deletion." : "Не се селектирани тагови за бришење.",
+ "unknown text" : "непознат текст",
+ "Hello world!" : "Здраво свету!",
+ "sunny" : "сончево",
+ "Hello {name}" : "Здраво {name}",
+ "An error occurred." : "Се случи грешка",
"The update was successful. Redirecting you to ownCloud now." : "Надградбата беше успешна. Веднаш ве префрлам на вашиот ownCloud.",
- "%s password reset" : "%s ресетирање на лозинката",
- "Use the following link to reset your password: {link}" : "Користете ја следната врска да ја ресетирате Вашата лозинка: {link}",
- "New password" : "Нова лозинка",
- "Reset password" : "Ресетирај лозинка",
"Personal" : "Лично",
"Users" : "Корисници",
"Apps" : "Аппликации",
@@ -148,8 +168,11 @@ OC.L10N.register(
"Error untagging" : "Грешка при отстранување на таговите",
"Error favoriting" : "Грешка при ",
"Access forbidden" : "Забранет пристап",
+ "File not found" : "Датотеката не е пронајдена",
"Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\n" : "Здраво,\n\nСамо да ве известам дека %s shared %s with you.\nView it: %s\n\n",
"Cheers!" : "Поздрав!",
+ "Internal Server Error" : "Интерна серверска грешка",
+ "Technical details" : "Технички детали",
"Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Вашиот директориум со податоци и датотеки се веројатно достапни преку интенернт поради што .htaccess датотеката не функционира.",
"Create an <strong>admin account</strong>" : "Направете <strong>администраторска сметка</strong>",
"Username" : "Корисничко име",
@@ -160,15 +183,28 @@ OC.L10N.register(
"Database name" : "Име на база",
"Database tablespace" : "Табела во базата на податоци",
"Database host" : "Сервер со база",
+ "Performance warning" : "Предупредување за перформансите",
+ "SQLite will be used as database." : "SQLite ќе се користи како база на податоци.",
"Finish setup" : "Заврши го подесувањето",
"Finishing …" : "Завршувам ...",
+ "Need help?" : "Ви треба помош?",
+ "See the documentation" : "Види ја документацијата",
"Log out" : "Одјава",
"Search" : "Барај",
"Server side authentication failed!" : "Автентификацијата на серверската страна е неуспешна!",
"Please contact your administrator." : "Ве молиме контактирајте го вашиот администратор.",
+ "An internal error occured." : "Се случи интерна грешка",
"Log in" : "Најава",
+ "Wrong password. Reset it?" : "Погрешна лозинка. Да ја ресетирам?",
+ "Wrong password." : "Погрешна лозинка.",
+ "Stay logged in" : "Остани најаваен",
"Alternative Logins" : "Алтернативни најавувања",
+ "Use the following link to reset your password: {link}" : "Користете ја следната врска да ја ресетирате Вашата лозинка: {link}",
+ "New password" : "Нова лозинка",
+ "New Password" : "Нова лозинка",
+ "Reset password" : "Ресетирај лозинка",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Контактирајте го вашиот систем администратор до колку оваа порака продолжи да се појавува или пак се појавува ненадејно.",
- "Thank you for your patience." : "Благодариме на вашето трпение."
+ "Thank you for your patience." : "Благодариме на вашето трпение.",
+ "These apps will be updated:" : "Следните апликации чќе бидат надградени:"
},
"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;");
diff --git a/core/l10n/mk.json b/core/l10n/mk.json
index d5002b8ffe9..1ec66dcb648 100644
--- a/core/l10n/mk.json
+++ b/core/l10n/mk.json
@@ -1,13 +1,20 @@
{ "translations": {
"Couldn't send mail to following users: %s " : "Не можев да пратам порака на следниве корисници: %s",
+ "Preparing update" : "Ја подготвувам надградбата",
"Turned on maintenance mode" : "Вклучен е модот за одржување",
"Turned off maintenance mode" : "Ислкучен е модот за одржување",
+ "Maintenance mode is kept active" : "Модот за одржување е уште активен",
+ "Updating database schema" : "Ја надградувам шемата на базата на податоци",
"Updated database" : "Базата е надградена",
"Checked database schema update" : "Проверена е шемата за ажурурање на базата на податоци",
"Checked database schema update for apps" : "Проверена е шемата за ажурурање на базата на податоци за апликации",
"Updated \"%s\" to %s" : "Ажурирано е \"%s\" во %s",
"Repair warning: " : "Предупредувања при поправка:",
"Repair error: " : "Грешка при поправка:",
+ "%s (3rdparty)" : "%s (3-та страна)",
+ "%s (incompatible)" : "%s (некомпатибилен)",
+ "Already up to date" : "Веќе ажурирано",
+ "File is too big" : "Датотеката е пре голема",
"Invalid file provided" : "Дадена е невалидна датотека",
"No image or file provided" : "Не е доставена фотографија или датотека",
"Unknown filetype" : "Непознат тип на датотека",
@@ -16,6 +23,8 @@
"No crop data provided" : "Не се доставени податоци за сечење",
"No valid crop data provided" : "Нема валидни податоци за сечење",
"Crop is not square" : "Сечењето не е правоаголно",
+ "%s password reset" : "%s ресетирање на лозинката",
+ "Couldn't send reset email. Please contact your administrator." : "Не можам да истпратам порака за ресетирање. Ве молам контактирајте го вашиот администратор.",
"Sunday" : "Недела",
"Monday" : "Понеделник",
"Tuesday" : "Вторник",
@@ -30,6 +39,13 @@
"Thu." : "Чет.",
"Fri." : "Пет.",
"Sat." : "Саб.",
+ "Su" : "Не",
+ "Mo" : "По",
+ "Tu" : "Вт",
+ "We" : "Ср",
+ "Th" : "Че",
+ "Fr" : "Пе",
+ "Sa" : "Са",
"January" : "Јануари",
"February" : "Февруари",
"March" : "Март",
@@ -57,7 +73,6 @@
"Settings" : "Подесувања",
"Saving..." : "Снимам...",
"seconds ago" : "пред секунди",
- "Couldn't send reset email. Please contact your administrator." : "Не можам да истпратам порака за ресетирање. Ве молам контактирајте го вашиот администратор.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Врската за ресетирање на вашата лозинка е испратена на вашата е-адреса. Ако не ја добиете во разумно време, проверете ги вашите папки за спам/ѓубре.<br>Ако не е таму прашајте го вашиот локален администратор.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Вашите датотеки се шифрирани. Ако не сте го овозможиле клучот за враќање, нема да можете да ги повратите вашите податоци откога вашата лозинка ќе биде ресетирана.<br>Ако не сте сигурни што да правите, ве молам контактирајте го вашиот локален администратор пред да продолжите.<br/>Дали навистина сакате да продолжите?",
"I know what I'm doing" : "Знам што правам",
@@ -87,7 +102,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Вашиот веб опслужувач сеуште не е точно подесен да овозможува синхронизација на датотеки бидејќи интерфејсот за WebDAV изгледа дека е расипан. ",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Овој опслужувач нема работна Интернет врска. Ова значи дека некои опции како што е монтирање на надворешни складишта, известувања за ажурирање или инсталации на апликации од 3-ти лица нема да работат. Пристапот на датотеки од далечина и праќање на пораки за известувања може исто така да не работат. Ви советуваме да овозможите Интернет врска за овој опслужувач ако сакате да ги имате сите опции. ",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Вашата папка за податоци и вашите датотеки се најверојатно достапни од интернет. Датотеката .htaccess не работи. Строго ви препорачуваме да го подесите вашиот веб опслужувач на начин на кој вашата папка за податоци не е веќе достапна од интернет или да ја преместите папката за податоци надвор од коренот на веб опслужувачот.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Не еконфигуриран кеш за меморијата. За да ги подобрите перформансите ве молам конфигурирајте memcache ако е достапно. Дополнителни информации можат да се најдат во нашата <a href=\"{docLink}\">документација</a>.",
"Error occurred while checking server setup" : "Се случи грешка при проверката на подесувањата на опслужувачот",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP заглавието \"{header}\" не е конфигурирано да биде еднакво на \"{expected}\". Ова е потенцијално сигурносен ризик и препорачуваме да прилагодат подесувањата.",
"Shared" : "Споделен",
@@ -95,45 +109,51 @@
"Error" : "Грешка",
"Error while sharing" : "Грешка при споделување",
"Error while unsharing" : "Грешка при прекин на споделување",
- "Error while changing permissions" : "Грешка при промена на привилегии",
"Error setting expiration date" : "Грешка при поставување на рок на траење",
"Set expiration date" : "Постави рок на траење",
"Expiration" : "Истекување",
"Expiration date" : "Рок на траење",
+ "Choose a password for the public link" : "Одбери лозинка за јавниот линк",
"Sending ..." : "Праќање...",
"Email sent" : "Е-порака пратена",
"Resharing is not allowed" : "Повторно споделување не е дозволено",
"Share link" : "Сподели ја врската",
+ "Link" : "Линк",
"Password protect" : "Заштити со лозинка",
"Password" : "Лозинка",
+ "Allow editing" : "Овозможи уредување",
"Email link to person" : "Прати врска по е-пошта на личност",
"Send" : "Прати",
"Shared with you and the group {group} by {owner}" : "Споделено со Вас и групата {group} од {owner}",
"Shared with you by {owner}" : "Споделено со Вас од {owner}",
- "Shared in {item} with {user}" : "Споделено во {item} со {user}",
"group" : "група",
+ "remote" : "далечински",
"notify by email" : "извести преку електронска пошта",
"Unshare" : "Не споделувај",
"can share" : "може да споделува",
"can edit" : "може да се измени",
"create" : "креирај",
+ "change" : "промени",
"delete" : "избриши",
"access control" : "контрола на пристап",
+ "An error occured. Please try again" : "Се случи грешка. Обиди се повторно",
"Share" : "Сподели",
"Share with users or groups …" : "Сподели со корисници или групи ...",
"Share with users, groups or remote users …" : "Споделено со корисници, групи или оддалечени корисници ...",
"Warning" : "Предупредување",
+ "Delete" : "Избриши",
+ "Rename" : "Преименувај",
"The object type is not specified." : "Не е специфициран типот на објект.",
"Enter new" : "Внеси нов",
- "Delete" : "Избриши",
"Add" : "Додади",
"Edit tags" : "Уреди ги таговите",
"No tags selected for deletion." : "Не се селектирани тагови за бришење.",
+ "unknown text" : "непознат текст",
+ "Hello world!" : "Здраво свету!",
+ "sunny" : "сончево",
+ "Hello {name}" : "Здраво {name}",
+ "An error occurred." : "Се случи грешка",
"The update was successful. Redirecting you to ownCloud now." : "Надградбата беше успешна. Веднаш ве префрлам на вашиот ownCloud.",
- "%s password reset" : "%s ресетирање на лозинката",
- "Use the following link to reset your password: {link}" : "Користете ја следната врска да ја ресетирате Вашата лозинка: {link}",
- "New password" : "Нова лозинка",
- "Reset password" : "Ресетирај лозинка",
"Personal" : "Лично",
"Users" : "Корисници",
"Apps" : "Аппликации",
@@ -146,8 +166,11 @@
"Error untagging" : "Грешка при отстранување на таговите",
"Error favoriting" : "Грешка при ",
"Access forbidden" : "Забранет пристап",
+ "File not found" : "Датотеката не е пронајдена",
"Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\n" : "Здраво,\n\nСамо да ве известам дека %s shared %s with you.\nView it: %s\n\n",
"Cheers!" : "Поздрав!",
+ "Internal Server Error" : "Интерна серверска грешка",
+ "Technical details" : "Технички детали",
"Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Вашиот директориум со податоци и датотеки се веројатно достапни преку интенернт поради што .htaccess датотеката не функционира.",
"Create an <strong>admin account</strong>" : "Направете <strong>администраторска сметка</strong>",
"Username" : "Корисничко име",
@@ -158,15 +181,28 @@
"Database name" : "Име на база",
"Database tablespace" : "Табела во базата на податоци",
"Database host" : "Сервер со база",
+ "Performance warning" : "Предупредување за перформансите",
+ "SQLite will be used as database." : "SQLite ќе се користи како база на податоци.",
"Finish setup" : "Заврши го подесувањето",
"Finishing …" : "Завршувам ...",
+ "Need help?" : "Ви треба помош?",
+ "See the documentation" : "Види ја документацијата",
"Log out" : "Одјава",
"Search" : "Барај",
"Server side authentication failed!" : "Автентификацијата на серверската страна е неуспешна!",
"Please contact your administrator." : "Ве молиме контактирајте го вашиот администратор.",
+ "An internal error occured." : "Се случи интерна грешка",
"Log in" : "Најава",
+ "Wrong password. Reset it?" : "Погрешна лозинка. Да ја ресетирам?",
+ "Wrong password." : "Погрешна лозинка.",
+ "Stay logged in" : "Остани најаваен",
"Alternative Logins" : "Алтернативни најавувања",
+ "Use the following link to reset your password: {link}" : "Користете ја следната врска да ја ресетирате Вашата лозинка: {link}",
+ "New password" : "Нова лозинка",
+ "New Password" : "Нова лозинка",
+ "Reset password" : "Ресетирај лозинка",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Контактирајте го вашиот систем администратор до колку оваа порака продолжи да се појавува или пак се појавува ненадејно.",
- "Thank you for your patience." : "Благодариме на вашето трпение."
+ "Thank you for your patience." : "Благодариме на вашето трпение.",
+ "These apps will be updated:" : "Следните апликации чќе бидат надградени:"
},"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"
} \ No newline at end of file
diff --git a/core/l10n/ms_MY.js b/core/l10n/ms_MY.js
index 262119dd07a..9f724442b3f 100644
--- a/core/l10n/ms_MY.js
+++ b/core/l10n/ms_MY.js
@@ -54,10 +54,8 @@ OC.L10N.register(
"Share" : "Kongsi",
"Warning" : "Amaran",
"Delete" : "Padam",
+ "Rename" : "Namakan",
"Add" : "Tambah",
- "Use the following link to reset your password: {link}" : "Guna pautan berikut untuk menetapkan semula kata laluan anda: {link}",
- "New password" : "Kata laluan baru",
- "Reset password" : "Penetapan semula kata laluan",
"Personal" : "Peribadi",
"Users" : "Pengguna",
"Apps" : "Aplikasi",
@@ -75,6 +73,9 @@ OC.L10N.register(
"Finish setup" : "Setup selesai",
"Log out" : "Log keluar",
"Search" : "Cari",
- "Log in" : "Log masuk"
+ "Log in" : "Log masuk",
+ "Use the following link to reset your password: {link}" : "Guna pautan berikut untuk menetapkan semula kata laluan anda: {link}",
+ "New password" : "Kata laluan baru",
+ "Reset password" : "Penetapan semula kata laluan"
},
"nplurals=1; plural=0;");
diff --git a/core/l10n/ms_MY.json b/core/l10n/ms_MY.json
index b2a8f0c4ff3..e39399056b9 100644
--- a/core/l10n/ms_MY.json
+++ b/core/l10n/ms_MY.json
@@ -52,10 +52,8 @@
"Share" : "Kongsi",
"Warning" : "Amaran",
"Delete" : "Padam",
+ "Rename" : "Namakan",
"Add" : "Tambah",
- "Use the following link to reset your password: {link}" : "Guna pautan berikut untuk menetapkan semula kata laluan anda: {link}",
- "New password" : "Kata laluan baru",
- "Reset password" : "Penetapan semula kata laluan",
"Personal" : "Peribadi",
"Users" : "Pengguna",
"Apps" : "Aplikasi",
@@ -73,6 +71,9 @@
"Finish setup" : "Setup selesai",
"Log out" : "Log keluar",
"Search" : "Cari",
- "Log in" : "Log masuk"
+ "Log in" : "Log masuk",
+ "Use the following link to reset your password: {link}" : "Guna pautan berikut untuk menetapkan semula kata laluan anda: {link}",
+ "New password" : "Kata laluan baru",
+ "Reset password" : "Penetapan semula kata laluan"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/core/l10n/my_MM.js b/core/l10n/my_MM.js
index 52165a6caed..70492ac63fa 100644
--- a/core/l10n/my_MM.js
+++ b/core/l10n/my_MM.js
@@ -27,7 +27,6 @@ OC.L10N.register(
"create" : "ဖန်တီးမည်",
"delete" : "ဖျက်မည်",
"Add" : "ပေါင်းထည့်",
- "New password" : "စကားဝှက်အသစ်",
"Users" : "သုံးစွဲသူ",
"Apps" : "Apps",
"Admin" : "အက်ဒမင်",
@@ -39,6 +38,7 @@ OC.L10N.register(
"Database password" : "Database စကားဝှက်",
"Database name" : "Database အမည်",
"Finish setup" : "တပ်ဆင်ခြင်းပြီးပါပြီ။",
- "Log in" : "ဝင်ရောက်ရန်"
+ "Log in" : "ဝင်ရောက်ရန်",
+ "New password" : "စကားဝှက်အသစ်"
},
"nplurals=1; plural=0;");
diff --git a/core/l10n/my_MM.json b/core/l10n/my_MM.json
index 7dfaa1fe6b1..126318a1a73 100644
--- a/core/l10n/my_MM.json
+++ b/core/l10n/my_MM.json
@@ -25,7 +25,6 @@
"create" : "ဖန်တီးမည်",
"delete" : "ဖျက်မည်",
"Add" : "ပေါင်းထည့်",
- "New password" : "စကားဝှက်အသစ်",
"Users" : "သုံးစွဲသူ",
"Apps" : "Apps",
"Admin" : "အက်ဒမင်",
@@ -37,6 +36,7 @@
"Database password" : "Database စကားဝှက်",
"Database name" : "Database အမည်",
"Finish setup" : "တပ်ဆင်ခြင်းပြီးပါပြီ။",
- "Log in" : "ဝင်ရောက်ရန်"
+ "Log in" : "ဝင်ရောက်ရန်",
+ "New password" : "စကားဝှက်အသစ်"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/core/l10n/nb_NO.js b/core/l10n/nb_NO.js
index b21e5d6b17c..aef4964a4a0 100644
--- a/core/l10n/nb_NO.js
+++ b/core/l10n/nb_NO.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Oppdaterte \"%s\" til %s",
"Repair warning: " : "Advarsel fra reparering: ",
"Repair error: " : "Feil ved reparering: ",
- "Set log level to debug - current level: \"%s\"" : "Sett loggnivå til feilsøking - nåværende nivå: \"%s\"",
- "Reset log level to \"%s\"" : "Tilbakestilt logg-nivå til \"%s\"",
+ "Set log level to debug" : "Sett loggnivå til feilsøking",
+ "Reset log level" : "Nullstill loggnivå",
+ "Starting code integrity check" : "Starter sjekk av kode-integritet",
+ "Finished code integrity check" : "Ferdig med sjekk av kode-integritet",
"%s (3rdparty)" : "%s (3dje-part)",
"%s (incompatible)" : "%s (ikke kompatibel)",
"Following apps have been disabled: %s" : "Følgende apper har blitt deaktivert: %s",
"Already up to date" : "Allerede oppdatert",
+ "Please select a file." : "Vennligst velg en fil.",
"File is too big" : "Filen er for stor",
"Invalid file provided" : "Ugyldig fil oppgitt",
"No image or file provided" : "Bilde eller fil ikke angitt",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "Ingen beskjæringsinformasjon angitt",
"No valid crop data provided" : "Ingen gyldige beskjæringsdata oppgitt",
"Crop is not square" : "Beskjæringen er ikke kvadratisk",
+ "Couldn't reset password because the token is invalid" : "Klarte ikke å tilbakestille passordet fordi token er ugyldig.",
+ "Couldn't reset password because the token is expired" : "Klarte ikke å tilbakestille passordet fordi token er utløpt.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Klarte ikke å sende e-post for tilbakestilling av passord. Sjekk at brukernavnet ditt er korrekt.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Klarte ikke å sende e-post for tilbakestilling av passord fordi det ikke finnes noen e-postadresse for dette brukernavnet. Kontakt administratoren din.",
+ "%s password reset" : "%s tilbakestilling av passord",
+ "Couldn't send reset email. Please contact your administrator." : "Klarte ikke å sende e-post for tilbakestilling. Kontakt administratoren.",
"Sunday" : "Søndag",
"Monday" : "Mandag",
"Tuesday" : "Tirsdag",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "Okt.",
"Nov." : "Nov.",
"Dec." : "Des.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Det var problemer med sjekk av kode-integritet. Mer informasjon…</a>",
"Settings" : "Innstillinger",
"Saving..." : "Lagrer...",
"seconds ago" : "for få sekunder siden",
- "Couldn't send reset email. Please contact your administrator." : "Klarte ikke å sende e-post for tilbakestilling. Kontakt administratoren.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Lenken for tilbakestilling av passordet ditt er sendt til din e-postadresse. Hvis du ikke mottar den innen rimelig tid, sjekk mappen for søppelpost.<br>Hvis du ikke finner den der, kontakt din lokale administrator.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Filene dine er kryptert. Hvis du ikke har aktivert gjenopprettingsnøkkelen, vil det være helt umulig å få tilbake dataene dine etter at pasordet ditt er tilbakestilt.<br />Hvis du er usikker på hva du skal gjøre, kontakt administratoren din før du fortsetter. <br />Vil du virkelig fortsette?",
"I know what I'm doing" : "Jeg vet hva jeg gjør",
@@ -109,13 +118,15 @@ OC.L10N.register(
"Good password" : "Bra passord",
"Strong password" : "Sterkt passord",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Web-serveren din er ikke satt opp til å tillate synkronisering av filer ennå, fordi WebDAV-grensesnittet ikke ser ut til å virke.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Web-serveren er ikke satt opp riktig for å oppløse \"{url}\". Mer informasjon finnes i <a target=\"_blank\" href=\"{docLink}\">dokumentasjonen</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Denne serveren har ingen fungerende internett-forbindelse. Dette betyr at noen funksjoner, som tilknytning av eksterne lagre, varslinger om oppdateringer eller installering av tredjeparts apper ikke vil virke. Fjerntilgang til filer og utsending av varsler på e-post vil kanskje ikke virke heller. Vi anbefaler å aktivere en internett-forbindelse for denne serveren hvis du vil ha full funksjonalitet.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Datamappen og filene dine er sannsynligvis tilgjengelige fra Internett. .htaccess-filen fungerer ikke. Vi anbefaler sterkt at du konfigurerer web-serveren slik at datamappen ikke kan aksesseres eller at du flytter datamappen ut av web-serverens dokumentrot.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Intet minne-cache er konfigurert. For å forbedre ytelsen, installer et minne-cache hvis tilgjengelig. Mer informasjon finnes i <a href=\"{docLink}\">dokumentasjonen</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom kan ikke leses av PHP, noe som er sterkt frarådet av sikkerhetshensyn. Mer informasjon finnes i <a href=\"{docLink}\">dokumentasjonen</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Din PHP-versjon ({version}) er ikke <a href=\"{phpLink}\">støttet av PHP</a> lenger. Vi oppfordrer deg til å oppgradere din PHP-versjon for å nyte fordel av ytelses- og sikkerhetsoppdateringer som tilbys av PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Konfigurasjon av reverse proxy-headers er ikke korrekt, eller du aksesserer ownCloud fra en \"trusted proxy\". Hvis du ikke aksesserer ownCloud fra en \"trusted proxy\", er dette en sikkerhetsrisiko som kan la en angriper forfalske IP-addressen sin slik den oppfattes av ownCloud. Mer informasjon i <a href=\"{docLink}\">dokumentasjonen</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached er konfigurert som distribuert cache, men feil PHP-module \"memcache\" er installert. \\OC\\Memcache\\Memcached støtter bare \"memcached\" og ikke \"memcache\". Se <a href=\"{wikiLink}\">memcached wiki om begge modulene</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Intet minne-cache er konfigurert. For å forbedre ytelsen, installer et minne-cache hvis tilgjengelig. Mer informasjon finnes i <a target=\"_blank\" href=\"{docLink}\">dokumentasjonen</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom kan ikke leses av PHP, noe som er sterkt frarådet av sikkerhetshensyn. Mer informasjon finnes i <a target=\"_blank\" href=\"{docLink}\">dokumentasjonen</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Din PHP-versjon ({version}) er ikke <a target=\"_blank\" href=\"{phpLink}\">støttet av PHP</a> lenger. Vi oppfordrer deg til å oppgradere din PHP-versjon for å nyte fordel av ytelses- og sikkerhetsoppdateringer som tilbys av PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Konfigurasjon av reverse proxy-headers er ikke korrekt, eller du aksesserer ownCloud fra en \"trusted proxy\". Hvis du ikke aksesserer ownCloud fra en \"trusted proxy\", er dette en sikkerhetsrisiko som kan la en angriper forfalske IP-addressen sin slik den oppfattes av ownCloud. Mer informasjon i <a target=\"_blank\" href=\"{docLink}\">dokumentasjonen</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached er konfigurert som distribuert cache, men feil PHP-module \"memcache\" er installert. \\OC\\Memcache\\Memcached støtter bare \"memcached\" og ikke \"memcache\". Se <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki om begge modulene</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Noen filer feilet integritets-sjekken. Informasjon for å løse situasjonen finnes i <a target=\"_blank\" href=\"{docLink}\">documentasjonen</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Liste med ugyldige filer…</a> / <a href=\"{rescanEndpoint}\">Skann på nytt…</a>)",
"Error occurred while checking server setup" : "Feil oppstod ved sjekking av server-oppsett",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP-header \"{header}\" er ikke konfigurert lik \"{expected}\". Dette kan være en sikkerhetsrisiko og vi anbefaler at denne innstillingen endres.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP header \"Strict-Transport-Security\" er ikke konfigurert til minst \"{seconds}\" sekunder. For beste sikkerhet anbefaler vi at HSTS aktiveres som beskrevet i <a href=\"{docUrl}\">sikkerhetstips</a>.",
@@ -125,7 +136,6 @@ OC.L10N.register(
"Error" : "Feil",
"Error while sharing" : "Feil under deling",
"Error while unsharing" : "Feil ved oppheving av deling",
- "Error while changing permissions" : "Feil ved endring av tillatelser",
"Error setting expiration date" : "Kan ikke sette utløpsdato",
"The public link will expire no later than {days} days after it is created" : "Den offentlige lenken vil utløpe senest {days} dager etter at den lages",
"Set expiration date" : "Sett utløpsdato",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "Send",
"Shared with you and the group {group} by {owner}" : "Delt med deg og gruppen {group} av {owner}",
"Shared with you by {owner}" : "Delt med deg av {owner}",
- "Shared in {item} with {user}" : "Delt i {item} med {user}",
"group" : "gruppe",
"remote" : "ekstern",
"notify by email" : "Varsle på email",
@@ -163,9 +172,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Del med brukere, grupper eller eksterne brukere ...",
"Warning" : "Advarsel",
"Error while sending notification" : "Feil ved sending av varsling",
+ "Delete" : "Slett",
+ "Rename" : "Gi nytt navn",
"The object type is not specified." : "Objekttypen er ikke spesifisert.",
"Enter new" : "Oppgi ny",
- "Delete" : "Slett",
"Add" : "Legg til",
"Edit tags" : "Rediger merkelapper",
"Error loading dialog template: {error}" : "Feil ved lasting av dialogmal: {error}",
@@ -184,15 +194,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Oppdateringen var mislykket.",
"The update was successful. There were warnings." : "Oppdateringen var vellykket. Det oppstod advarsler.",
"The update was successful. Redirecting you to ownCloud now." : "Oppdateringen var vellykket. Du omdirigeres nå til ownCloud.",
- "Couldn't reset password because the token is invalid" : "Klarte ikke å tilbakestille passordet fordi token er ugyldig.",
- "Couldn't reset password because the token is expired" : "Klarte ikke å tilbakestille passordet fordi token er utløpt.",
- "Couldn't send reset email. Please make sure your username is correct." : "Klarte ikke å sende e-post for tilbakestilling av passord. Sjekk at brukernavnet ditt er korrekt.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Klarte ikke å sende e-post for tilbakestilling av passord fordi det ikke finnes noen e-postadresse for dette brukernavnet. Kontakt administratoren din.",
- "%s password reset" : "%s tilbakestilling av passord",
- "Use the following link to reset your password: {link}" : "Bruk følgende lenke for å tilbakestille passordet ditt: {link}",
- "New password" : "Nytt passord",
- "New Password" : "Nytt passord",
- "Reset password" : "Tilbakestill passord",
"Searching other places" : "Søker andre steder",
"No search results in other folders" : "Ingen søkeresultater i andre mapper",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} søkeresultat i en annen mappe","{count} søkeresultater i andre mapper"],
@@ -262,13 +263,19 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Prøv igjen eller kontakt en administrator.",
"Log in" : "Logg inn",
"Wrong password. Reset it?" : "Feil passord. Nullstille det?",
+ "Wrong password." : "Feil passord.",
"Stay logged in" : "Forbli innlogget",
"Alternative Logins" : "Alternative innlogginger",
+ "Use the following link to reset your password: {link}" : "Bruk følgende lenke for å tilbakestille passordet ditt: {link}",
+ "New password" : "Nytt passord",
+ "New Password" : "Nytt passord",
+ "Reset password" : "Tilbakestill passord",
"This ownCloud instance is currently in single user mode." : "Denne ownCloud-instansen er for øyeblikket i enbrukermodus.",
"This means only administrators can use the instance." : "Dette betyr at kun administratorer kan bruke instansen.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontakt systemadministratoren hvis denne meldingen var uventet eller ikke forsvinner.",
"Thank you for your patience." : "Takk for din tålmodighet.",
"You are accessing the server from an untrusted domain." : "Du aksesserer serveren fra et ikke tiltrodd domene.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Vennligst kontakt administratoren. Hvis du er administrator for denne instansen, konfigurer innstillingen \"trusted_domains\" i config/config.php. Et eksempel på konfigurasjon er gitt i config/config.sample.php.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Avhengig av konfigurasjonen kan du, som administrator, kanskje også bruke kanppen nedenfor til å stole på dette domenet.",
"Add \"%s\" as trusted domain" : "Legg til \"%s\" som et tiltrodd domene",
"App update required" : "App-oppdatering kreves",
diff --git a/core/l10n/nb_NO.json b/core/l10n/nb_NO.json
index cb67534cd01..b9cda317839 100644
--- a/core/l10n/nb_NO.json
+++ b/core/l10n/nb_NO.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "Oppdaterte \"%s\" til %s",
"Repair warning: " : "Advarsel fra reparering: ",
"Repair error: " : "Feil ved reparering: ",
- "Set log level to debug - current level: \"%s\"" : "Sett loggnivå til feilsøking - nåværende nivå: \"%s\"",
- "Reset log level to \"%s\"" : "Tilbakestilt logg-nivå til \"%s\"",
+ "Set log level to debug" : "Sett loggnivå til feilsøking",
+ "Reset log level" : "Nullstill loggnivå",
+ "Starting code integrity check" : "Starter sjekk av kode-integritet",
+ "Finished code integrity check" : "Ferdig med sjekk av kode-integritet",
"%s (3rdparty)" : "%s (3dje-part)",
"%s (incompatible)" : "%s (ikke kompatibel)",
"Following apps have been disabled: %s" : "Følgende apper har blitt deaktivert: %s",
"Already up to date" : "Allerede oppdatert",
+ "Please select a file." : "Vennligst velg en fil.",
"File is too big" : "Filen er for stor",
"Invalid file provided" : "Ugyldig fil oppgitt",
"No image or file provided" : "Bilde eller fil ikke angitt",
@@ -30,6 +33,12 @@
"No crop data provided" : "Ingen beskjæringsinformasjon angitt",
"No valid crop data provided" : "Ingen gyldige beskjæringsdata oppgitt",
"Crop is not square" : "Beskjæringen er ikke kvadratisk",
+ "Couldn't reset password because the token is invalid" : "Klarte ikke å tilbakestille passordet fordi token er ugyldig.",
+ "Couldn't reset password because the token is expired" : "Klarte ikke å tilbakestille passordet fordi token er utløpt.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Klarte ikke å sende e-post for tilbakestilling av passord. Sjekk at brukernavnet ditt er korrekt.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Klarte ikke å sende e-post for tilbakestilling av passord fordi det ikke finnes noen e-postadresse for dette brukernavnet. Kontakt administratoren din.",
+ "%s password reset" : "%s tilbakestilling av passord",
+ "Couldn't send reset email. Please contact your administrator." : "Klarte ikke å sende e-post for tilbakestilling. Kontakt administratoren.",
"Sunday" : "Søndag",
"Monday" : "Mandag",
"Tuesday" : "Tirsdag",
@@ -75,10 +84,10 @@
"Oct." : "Okt.",
"Nov." : "Nov.",
"Dec." : "Des.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Det var problemer med sjekk av kode-integritet. Mer informasjon…</a>",
"Settings" : "Innstillinger",
"Saving..." : "Lagrer...",
"seconds ago" : "for få sekunder siden",
- "Couldn't send reset email. Please contact your administrator." : "Klarte ikke å sende e-post for tilbakestilling. Kontakt administratoren.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Lenken for tilbakestilling av passordet ditt er sendt til din e-postadresse. Hvis du ikke mottar den innen rimelig tid, sjekk mappen for søppelpost.<br>Hvis du ikke finner den der, kontakt din lokale administrator.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Filene dine er kryptert. Hvis du ikke har aktivert gjenopprettingsnøkkelen, vil det være helt umulig å få tilbake dataene dine etter at pasordet ditt er tilbakestilt.<br />Hvis du er usikker på hva du skal gjøre, kontakt administratoren din før du fortsetter. <br />Vil du virkelig fortsette?",
"I know what I'm doing" : "Jeg vet hva jeg gjør",
@@ -107,13 +116,15 @@
"Good password" : "Bra passord",
"Strong password" : "Sterkt passord",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Web-serveren din er ikke satt opp til å tillate synkronisering av filer ennå, fordi WebDAV-grensesnittet ikke ser ut til å virke.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Web-serveren er ikke satt opp riktig for å oppløse \"{url}\". Mer informasjon finnes i <a target=\"_blank\" href=\"{docLink}\">dokumentasjonen</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Denne serveren har ingen fungerende internett-forbindelse. Dette betyr at noen funksjoner, som tilknytning av eksterne lagre, varslinger om oppdateringer eller installering av tredjeparts apper ikke vil virke. Fjerntilgang til filer og utsending av varsler på e-post vil kanskje ikke virke heller. Vi anbefaler å aktivere en internett-forbindelse for denne serveren hvis du vil ha full funksjonalitet.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Datamappen og filene dine er sannsynligvis tilgjengelige fra Internett. .htaccess-filen fungerer ikke. Vi anbefaler sterkt at du konfigurerer web-serveren slik at datamappen ikke kan aksesseres eller at du flytter datamappen ut av web-serverens dokumentrot.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Intet minne-cache er konfigurert. For å forbedre ytelsen, installer et minne-cache hvis tilgjengelig. Mer informasjon finnes i <a href=\"{docLink}\">dokumentasjonen</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom kan ikke leses av PHP, noe som er sterkt frarådet av sikkerhetshensyn. Mer informasjon finnes i <a href=\"{docLink}\">dokumentasjonen</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Din PHP-versjon ({version}) er ikke <a href=\"{phpLink}\">støttet av PHP</a> lenger. Vi oppfordrer deg til å oppgradere din PHP-versjon for å nyte fordel av ytelses- og sikkerhetsoppdateringer som tilbys av PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Konfigurasjon av reverse proxy-headers er ikke korrekt, eller du aksesserer ownCloud fra en \"trusted proxy\". Hvis du ikke aksesserer ownCloud fra en \"trusted proxy\", er dette en sikkerhetsrisiko som kan la en angriper forfalske IP-addressen sin slik den oppfattes av ownCloud. Mer informasjon i <a href=\"{docLink}\">dokumentasjonen</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached er konfigurert som distribuert cache, men feil PHP-module \"memcache\" er installert. \\OC\\Memcache\\Memcached støtter bare \"memcached\" og ikke \"memcache\". Se <a href=\"{wikiLink}\">memcached wiki om begge modulene</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Intet minne-cache er konfigurert. For å forbedre ytelsen, installer et minne-cache hvis tilgjengelig. Mer informasjon finnes i <a target=\"_blank\" href=\"{docLink}\">dokumentasjonen</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom kan ikke leses av PHP, noe som er sterkt frarådet av sikkerhetshensyn. Mer informasjon finnes i <a target=\"_blank\" href=\"{docLink}\">dokumentasjonen</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Din PHP-versjon ({version}) er ikke <a target=\"_blank\" href=\"{phpLink}\">støttet av PHP</a> lenger. Vi oppfordrer deg til å oppgradere din PHP-versjon for å nyte fordel av ytelses- og sikkerhetsoppdateringer som tilbys av PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Konfigurasjon av reverse proxy-headers er ikke korrekt, eller du aksesserer ownCloud fra en \"trusted proxy\". Hvis du ikke aksesserer ownCloud fra en \"trusted proxy\", er dette en sikkerhetsrisiko som kan la en angriper forfalske IP-addressen sin slik den oppfattes av ownCloud. Mer informasjon i <a target=\"_blank\" href=\"{docLink}\">dokumentasjonen</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached er konfigurert som distribuert cache, men feil PHP-module \"memcache\" er installert. \\OC\\Memcache\\Memcached støtter bare \"memcached\" og ikke \"memcache\". Se <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki om begge modulene</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Noen filer feilet integritets-sjekken. Informasjon for å løse situasjonen finnes i <a target=\"_blank\" href=\"{docLink}\">documentasjonen</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Liste med ugyldige filer…</a> / <a href=\"{rescanEndpoint}\">Skann på nytt…</a>)",
"Error occurred while checking server setup" : "Feil oppstod ved sjekking av server-oppsett",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP-header \"{header}\" er ikke konfigurert lik \"{expected}\". Dette kan være en sikkerhetsrisiko og vi anbefaler at denne innstillingen endres.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP header \"Strict-Transport-Security\" er ikke konfigurert til minst \"{seconds}\" sekunder. For beste sikkerhet anbefaler vi at HSTS aktiveres som beskrevet i <a href=\"{docUrl}\">sikkerhetstips</a>.",
@@ -123,7 +134,6 @@
"Error" : "Feil",
"Error while sharing" : "Feil under deling",
"Error while unsharing" : "Feil ved oppheving av deling",
- "Error while changing permissions" : "Feil ved endring av tillatelser",
"Error setting expiration date" : "Kan ikke sette utløpsdato",
"The public link will expire no later than {days} days after it is created" : "Den offentlige lenken vil utløpe senest {days} dager etter at den lages",
"Set expiration date" : "Sett utløpsdato",
@@ -142,7 +152,6 @@
"Send" : "Send",
"Shared with you and the group {group} by {owner}" : "Delt med deg og gruppen {group} av {owner}",
"Shared with you by {owner}" : "Delt med deg av {owner}",
- "Shared in {item} with {user}" : "Delt i {item} med {user}",
"group" : "gruppe",
"remote" : "ekstern",
"notify by email" : "Varsle på email",
@@ -161,9 +170,10 @@
"Share with users, groups or remote users …" : "Del med brukere, grupper eller eksterne brukere ...",
"Warning" : "Advarsel",
"Error while sending notification" : "Feil ved sending av varsling",
+ "Delete" : "Slett",
+ "Rename" : "Gi nytt navn",
"The object type is not specified." : "Objekttypen er ikke spesifisert.",
"Enter new" : "Oppgi ny",
- "Delete" : "Slett",
"Add" : "Legg til",
"Edit tags" : "Rediger merkelapper",
"Error loading dialog template: {error}" : "Feil ved lasting av dialogmal: {error}",
@@ -182,15 +192,6 @@
"The update was unsuccessful. " : "Oppdateringen var mislykket.",
"The update was successful. There were warnings." : "Oppdateringen var vellykket. Det oppstod advarsler.",
"The update was successful. Redirecting you to ownCloud now." : "Oppdateringen var vellykket. Du omdirigeres nå til ownCloud.",
- "Couldn't reset password because the token is invalid" : "Klarte ikke å tilbakestille passordet fordi token er ugyldig.",
- "Couldn't reset password because the token is expired" : "Klarte ikke å tilbakestille passordet fordi token er utløpt.",
- "Couldn't send reset email. Please make sure your username is correct." : "Klarte ikke å sende e-post for tilbakestilling av passord. Sjekk at brukernavnet ditt er korrekt.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Klarte ikke å sende e-post for tilbakestilling av passord fordi det ikke finnes noen e-postadresse for dette brukernavnet. Kontakt administratoren din.",
- "%s password reset" : "%s tilbakestilling av passord",
- "Use the following link to reset your password: {link}" : "Bruk følgende lenke for å tilbakestille passordet ditt: {link}",
- "New password" : "Nytt passord",
- "New Password" : "Nytt passord",
- "Reset password" : "Tilbakestill passord",
"Searching other places" : "Søker andre steder",
"No search results in other folders" : "Ingen søkeresultater i andre mapper",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} søkeresultat i en annen mappe","{count} søkeresultater i andre mapper"],
@@ -260,13 +261,19 @@
"Please try again or contact your administrator." : "Prøv igjen eller kontakt en administrator.",
"Log in" : "Logg inn",
"Wrong password. Reset it?" : "Feil passord. Nullstille det?",
+ "Wrong password." : "Feil passord.",
"Stay logged in" : "Forbli innlogget",
"Alternative Logins" : "Alternative innlogginger",
+ "Use the following link to reset your password: {link}" : "Bruk følgende lenke for å tilbakestille passordet ditt: {link}",
+ "New password" : "Nytt passord",
+ "New Password" : "Nytt passord",
+ "Reset password" : "Tilbakestill passord",
"This ownCloud instance is currently in single user mode." : "Denne ownCloud-instansen er for øyeblikket i enbrukermodus.",
"This means only administrators can use the instance." : "Dette betyr at kun administratorer kan bruke instansen.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontakt systemadministratoren hvis denne meldingen var uventet eller ikke forsvinner.",
"Thank you for your patience." : "Takk for din tålmodighet.",
"You are accessing the server from an untrusted domain." : "Du aksesserer serveren fra et ikke tiltrodd domene.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Vennligst kontakt administratoren. Hvis du er administrator for denne instansen, konfigurer innstillingen \"trusted_domains\" i config/config.php. Et eksempel på konfigurasjon er gitt i config/config.sample.php.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Avhengig av konfigurasjonen kan du, som administrator, kanskje også bruke kanppen nedenfor til å stole på dette domenet.",
"Add \"%s\" as trusted domain" : "Legg til \"%s\" som et tiltrodd domene",
"App update required" : "App-oppdatering kreves",
diff --git a/core/l10n/nds.js b/core/l10n/nds.js
index ed29474b797..71bdf00fdcf 100644
--- a/core/l10n/nds.js
+++ b/core/l10n/nds.js
@@ -12,8 +12,6 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "\"%s\" auf %s aktualisiert",
"Repair warning: " : "Reparaturwarnung",
"Repair error: " : "Reparaturfehler",
- "Set log level to debug - current level: \"%s\"" : "Protokollierungsstufe auf Debug gesetzt - Aktuelle Stufe: \"%s\"",
- "Reset log level to \"%s\"" : "Protokollierungsstufe auf \"%s\" zurückgesetzt",
"Following apps have been disabled: %s" : "Folgende Apps wurden deaktiviert: %s",
"Already up to date" : "Bereits aktuell",
"File is too big" : "Datei ist zu groß",
@@ -25,6 +23,7 @@ OC.L10N.register(
"No crop data provided" : "Keine Angaben zum Zuschneiden geliefert",
"No valid crop data provided" : "Keine gültigen Angaben zum Zuschnitt geliefert",
"Crop is not square" : "Zuschnitt ist nicht quadratisch",
+ "Couldn't send reset email. Please contact your administrator." : "E-Mail zum Zurücksetzen konnte nicht gesendet werden. Bitte wende Dich an Deinem Administrator.",
"Sunday" : "Sonntag",
"Monday" : "Montag",
"Tuesday" : "Dienstag",
@@ -73,7 +72,6 @@ OC.L10N.register(
"Settings" : "Einstellungen",
"Saving..." : "Speichern...",
"seconds ago" : "vor wenigen Sekunden",
- "Couldn't send reset email. Please contact your administrator." : "E-Mail zum Zurücksetzen konnte nicht gesendet werden. Bitte wende Dich an Deinem Administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Der Link zum Zurücksetzen deines Passworts wurde an Deine E-Mailadresse geschickt. Wenn Du diesen in einer angemessenen Zeit nicht erhältst, prüfe bitte deine Spam/Junk Ordner.<br> Wenn die E-Mail dort nicht ist, wende Dich an Deinen lokalen Administrator.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Deine Dateien sind verschlüsselt. Wenn Dein Wiederherstellungsschlüssel nicht aktiviert ist, gibt es keine Möglichkeit die Daten wiederherzustellen, nachdem Dein Passwort zurückgesetzt wurde.<br /> Wenn Du nicht sicher weißt was zu tun ist, wende Dich bitte an deinen Adminstrator bevor du fortfährst.<br />Willst du wirklich fortfahren?",
"I know what I'm doing" : "Ich weiß was ich tue",
@@ -104,7 +102,11 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Dein Webserver ist für die Dateisynchronisierung noch nicht ordentlich eingerichtet, da die WebDAV-Schnittstelle fehlerhaft scheint. ",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Dieser Server ist nicht mit dem Internet verbunden. Das bedeutet, dass manche Funktionen, wie das Einbinden von externen Speichern, Benachrichtigungen über Aktualisierungen oder die Installation von Drittanbieter Apps nicht zur Verfügung stehen. Auch der Fernzugriff auf Dateien und das Senden von Hinweis-E-Mails könnte nicht funktionieren. Wir empfehlen die Internetverbindung dieses Servers zu aktivieren, wenn Du diese Funktionen nutzen möchtest.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Der Zugriff auf Dein Datenverzeichnis und Deine Dateien ist über das Internet vermutlich möglich. Die .htaccess-Datei greift nicht. Wir empfehlen dringend den Webserver derart zu konfigurieren, dass das Datenverzeichnis nicht mehr zugreifbar ist oder das Datenverzeichnis nach außerhalb des Dokumentenwurzelverzeichnisses des Webservers zu verschieben.",
+ "Error" : "Fehler",
"Password" : "Passwort",
+ "Send" : "Senden",
+ "can share" : "kann teilen",
+ "can edit" : "kann editieren",
"Share" : "Teilen",
"Delete" : "Löschen",
"Personal" : "Persönlich",
diff --git a/core/l10n/nds.json b/core/l10n/nds.json
index bc8f8d2510c..753a6bea64d 100644
--- a/core/l10n/nds.json
+++ b/core/l10n/nds.json
@@ -10,8 +10,6 @@
"Updated \"%s\" to %s" : "\"%s\" auf %s aktualisiert",
"Repair warning: " : "Reparaturwarnung",
"Repair error: " : "Reparaturfehler",
- "Set log level to debug - current level: \"%s\"" : "Protokollierungsstufe auf Debug gesetzt - Aktuelle Stufe: \"%s\"",
- "Reset log level to \"%s\"" : "Protokollierungsstufe auf \"%s\" zurückgesetzt",
"Following apps have been disabled: %s" : "Folgende Apps wurden deaktiviert: %s",
"Already up to date" : "Bereits aktuell",
"File is too big" : "Datei ist zu groß",
@@ -23,6 +21,7 @@
"No crop data provided" : "Keine Angaben zum Zuschneiden geliefert",
"No valid crop data provided" : "Keine gültigen Angaben zum Zuschnitt geliefert",
"Crop is not square" : "Zuschnitt ist nicht quadratisch",
+ "Couldn't send reset email. Please contact your administrator." : "E-Mail zum Zurücksetzen konnte nicht gesendet werden. Bitte wende Dich an Deinem Administrator.",
"Sunday" : "Sonntag",
"Monday" : "Montag",
"Tuesday" : "Dienstag",
@@ -71,7 +70,6 @@
"Settings" : "Einstellungen",
"Saving..." : "Speichern...",
"seconds ago" : "vor wenigen Sekunden",
- "Couldn't send reset email. Please contact your administrator." : "E-Mail zum Zurücksetzen konnte nicht gesendet werden. Bitte wende Dich an Deinem Administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Der Link zum Zurücksetzen deines Passworts wurde an Deine E-Mailadresse geschickt. Wenn Du diesen in einer angemessenen Zeit nicht erhältst, prüfe bitte deine Spam/Junk Ordner.<br> Wenn die E-Mail dort nicht ist, wende Dich an Deinen lokalen Administrator.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Deine Dateien sind verschlüsselt. Wenn Dein Wiederherstellungsschlüssel nicht aktiviert ist, gibt es keine Möglichkeit die Daten wiederherzustellen, nachdem Dein Passwort zurückgesetzt wurde.<br /> Wenn Du nicht sicher weißt was zu tun ist, wende Dich bitte an deinen Adminstrator bevor du fortfährst.<br />Willst du wirklich fortfahren?",
"I know what I'm doing" : "Ich weiß was ich tue",
@@ -102,7 +100,11 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Dein Webserver ist für die Dateisynchronisierung noch nicht ordentlich eingerichtet, da die WebDAV-Schnittstelle fehlerhaft scheint. ",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Dieser Server ist nicht mit dem Internet verbunden. Das bedeutet, dass manche Funktionen, wie das Einbinden von externen Speichern, Benachrichtigungen über Aktualisierungen oder die Installation von Drittanbieter Apps nicht zur Verfügung stehen. Auch der Fernzugriff auf Dateien und das Senden von Hinweis-E-Mails könnte nicht funktionieren. Wir empfehlen die Internetverbindung dieses Servers zu aktivieren, wenn Du diese Funktionen nutzen möchtest.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Der Zugriff auf Dein Datenverzeichnis und Deine Dateien ist über das Internet vermutlich möglich. Die .htaccess-Datei greift nicht. Wir empfehlen dringend den Webserver derart zu konfigurieren, dass das Datenverzeichnis nicht mehr zugreifbar ist oder das Datenverzeichnis nach außerhalb des Dokumentenwurzelverzeichnisses des Webservers zu verschieben.",
+ "Error" : "Fehler",
"Password" : "Passwort",
+ "Send" : "Senden",
+ "can share" : "kann teilen",
+ "can edit" : "kann editieren",
"Share" : "Teilen",
"Delete" : "Löschen",
"Personal" : "Persönlich",
diff --git a/core/l10n/nl.js b/core/l10n/nl.js
index f4702077004..560cdbcebbc 100644
--- a/core/l10n/nl.js
+++ b/core/l10n/nl.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Bijgewerkt \"%s\" naar %s",
"Repair warning: " : "Reparatiewaarschuwing:",
"Repair error: " : "Reparatiefout:",
- "Set log level to debug - current level: \"%s\"" : "Instellen logniveau op debug - huidige niveau: \"%s\"",
- "Reset log level to \"%s\"" : "Terugzetten logniveau op \"#%s\"",
+ "Set log level to debug" : "Logniveau instellen op debug",
+ "Reset log level" : "Terugzetten logniveau",
+ "Starting code integrity check" : "Starten code betrouwbaarheidscontrole",
+ "Finished code integrity check" : "Gereed met code betrouwbaarheidscontrole",
"%s (3rdparty)" : "%s (3rdparty)",
"%s (incompatible)" : "%s (incompatibel)",
"Following apps have been disabled: %s" : "De volgende apps zijn gedeactiveerd: %s",
"Already up to date" : "Al bijgewerkt",
+ "Please select a file." : "Selecteer een bestand.",
"File is too big" : "Bestand te groot",
"Invalid file provided" : "Ongeldig bestand opgegeven",
"No image or file provided" : "Geen afbeelding of bestand opgegeven",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "Geen bijsnijdingsgegevens opgegeven",
"No valid crop data provided" : "Geen geldige bijsnijdingsgegevens opgegeven",
"Crop is not square" : "Bijsnijding is niet vierkant",
+ "Couldn't reset password because the token is invalid" : "Kon het wachtwoord niet herstellen, omdat het token ongeldig is",
+ "Couldn't reset password because the token is expired" : "Kon het wachtwoord niet herstellen, omdat het token verlopen is",
+ "Couldn't send reset email. Please make sure your username is correct." : "Kon e-mail niet versturen. Verifieer of uw gebruikersnaam correct is.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Kon geen herstel e-mail versturen, omdat er geen e-mailadres bekend is bij deze gebruikersnaam. Neem contact op met uw beheerder.",
+ "%s password reset" : "%s wachtwoord reset",
+ "Couldn't send reset email. Please contact your administrator." : "Kon herstel e-mail niet versturen. Neem contact op met uw beheerder.",
"Sunday" : "zondag",
"Monday" : "maandag",
"Tuesday" : "dinsdag",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "Okt.",
"Nov." : "Nov.",
"Dec." : "Dec.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Er traden problemen op tijdens de code betrouwbaarheidscontrole. Meer informatie…</a>",
"Settings" : "Instellingen",
"Saving..." : "Opslaan",
"seconds ago" : "seconden geleden",
- "Couldn't send reset email. Please contact your administrator." : "Kon herstel e-mail niet versturen. Neem contact op met uw beheerder.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "De link om uw wachtwoord te herstellen is per e-mail naar u verstuurd. Als u dit bericht niet binnen redelijke tijd hebt ontvangen, controleer dan uw spammap. <br>Als het daar niet in zit, neem dan contact op met uw beheerder.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Uw bestanden zijn versleuteld. Als u de herstelsleutel niet hebt geactiveerd, is er geen mogelijk om uw gegevens terug te krijgen nadat uw wachtwoord is hersteld. <br>Als u niet weet wat u moet doen, neem dan eerst contact op met uw beheerder. <br>Wilt u echt verder gaan?",
"I know what I'm doing" : "Ik weet wat ik doe",
@@ -109,13 +118,15 @@ OC.L10N.register(
"Good password" : "Goed wachtwoord",
"Strong password" : "Sterk wachtwoord",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Uw webserver is nog niet goed ingesteld voor bestandssynchronisatie omdat de WebDAV interface verstoord lijkt.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Uw webserver is niet goed ingesteld om \"{url}\" te vinden. Meer informatie is te vinden in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Deze server heeft geen actieve internetverbinding. Dat betekent dat sommige functies, zoals aankoppelen van externe opslag, notificaties over updates of installatie van apps van 3e partijen niet werken. Ook het benaderen van bestanden vanaf een remote locatie en het versturen van notificatie emails kan mislukken. We adviseren om de internetverbinding voor deze server in te schakelen als u alle functies wilt gebruiken.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Uw data folder en uw bestanden zijn waarschijnlijk vanaf het internet bereikbaar. Het .htaccess-bestand werkt niet. We raden ten zeerste aan aan om uw webserver zodanig te configureren, dat de datadirectory niet bereikbaar is vanaf het internet of om uw datadirectory te verplaatsen naar een locatie buiten de document root van de webserver.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Er is geen geheugencache geconfigureerd. Om de prestaties te verhogen kunt u de memcache configureren als die beschikbaar is. Meer informatie vind u in onze <a href=\"{docLink}\">documentatie</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom is niet leesbaar door PHP, hetgeen wordt afgeraden wegens beveiligingsredenen. Meer informatie in onze <a href=\"{docLink}\">documentatie</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "UwPHP versie ({version}) wordt niet langer <a href=\"{phpLink}\">ondersteund door PHP</a>. We adviseren u om uw PHP versie te upgraden voor betere prestaties en security updates geleverd door PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "De reverse proxy headerconfiguratie is onjuist, of u hebt toegang tot ownCloud via een vertrouwde proxy. Als u ownCloud niet via een vertrouwde proxy benadert, dan levert dan een beveiligingsrisico op, waardoor een aanvaller het IP-adres dat ownCloud ziet kan spoofen. Meer informatie is te vinden in onze <a href=\"{docLink}\">documentatie</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached is geconfigureerd als gedistribueerde cache, maar de verkeerde PHP module \"memcache\" is geïnstalleerd. \\OC\\Memcache\\Memcached ondersteunt alleen \"memcached\" en niet \"memcache\". Zie de <a href=\"{wikiLink}\">memcached wiki over beide modules</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Er is geen geheugencache geconfigureerd. Om de prestaties te verhogen kunt u de memcache configureren als die beschikbaar is. Meer informatie vind u in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom is niet leesbaar door PHP, hetgeen wordt afgeraden wegens beveiligingsredenen. Meer informatie in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "UwPHP versie ({version}) wordt niet langer <a target=\"_blank\" href=\"{phpLink}\">ondersteund door PHP</a>. We adviseren u om uw PHP versie te upgraden voor betere prestaties en security updates geleverd door PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "De reverse proxy headerconfiguratie is onjuist, of u hebt toegang tot ownCloud via een vertrouwde proxy. Als u ownCloud niet via een vertrouwde proxy benadert, dan levert dan een beveiligingsrisico op, waardoor een aanvaller het IP-adres dat ownCloud ziet kan spoofen. Meer informatie is te vinden in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached is geconfigureerd als gedistribueerde cache, maar de verkeerde PHP module \"memcache\" is geïnstalleerd. \\OC\\Memcache\\Memcached ondersteunt alleen \"memcached\" en niet \"memcache\". Zie de <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki over beide modules</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Sommige bestanden kwamen niet door de code betrouwbaarheidscontrole. Meer informatie over het oplossen van dit probleem kan worden gevonden in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lijst met ongeldige bestanden…</a> / <a href=\"{rescanEndpoint}\">Opnieuw…</a>)",
"Error occurred while checking server setup" : "Een fout trad op bij checken serverconfiguratie",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "De \"{header}\" HTTP header is niet overeenkomstig met \"{expected}\" geconfigureerd. Dit is een potentieel security of privacy risico en we adviseren om deze instelling te wijzigen.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "De \"Strict-Transport-Security\" HTTP header is niet geconfigureerd als minimaal \"{seconds}\" seconden. Voor verbeterde beveiliging adviseren we HSTS in te schakelen zoals beschreven in onze <a href=\"{docUrl}\">security tips</a>.",
@@ -125,7 +136,6 @@ OC.L10N.register(
"Error" : "Fout",
"Error while sharing" : "Fout tijdens het delen",
"Error while unsharing" : "Fout tijdens het stoppen met delen",
- "Error while changing permissions" : "Fout tijdens het veranderen van permissies",
"Error setting expiration date" : "Fout tijdens het instellen van de vervaldatum",
"The public link will expire no later than {days} days after it is created" : "De openbare link vervalt niet eerder dan {days} dagen na het aanmaken",
"Set expiration date" : "Stel vervaldatum in",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "Versturen",
"Shared with you and the group {group} by {owner}" : "Gedeeld met u en de groep {group} door {owner}",
"Shared with you by {owner}" : "Gedeeld met u door {owner}",
- "Shared in {item} with {user}" : "Gedeeld in {item} met {user}",
"group" : "groep",
"remote" : "extern",
"notify by email" : "melden per e-mail",
@@ -155,17 +164,25 @@ OC.L10N.register(
"change" : "wijzig",
"delete" : "verwijderen",
"access control" : "toegangscontrole",
+ "Could not unshare" : "Kon delen niet ongedaan maken",
"Share details could not be loaded for this item." : "Details van shares voor dit object konden niet worden geladen.",
"An error occured. Please try again" : "Er trad een fout op. Probeer het opnieuw",
"Share" : "Delen",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Delen met mensen op andere ownClouds via de syntax gebruikersnaam@voorbeeld.org/owncloud",
"Share with users or groups …" : "Delen met gebruikers of groepen ...",
"Share with users, groups or remote users …" : "Delen met gebruikers, groepen of externe gebruikers ...",
+ "Error removing share" : "Fout bij verwijderen share",
"Warning" : "Waarschuwing",
"Error while sending notification" : "Fout bij versturen melding",
+ "Non-existing tag #{tag}" : "Niet bestaande tag #{tag}",
+ "not assignable" : "niet toewijsbaar",
+ "invisible" : "onzichtbaar",
+ "({scope})" : "({scope})",
+ "Delete" : "Verwijder",
+ "Rename" : "Naam wijzigen",
+ "Global tags" : "Globale tags",
"The object type is not specified." : "Het object type is niet gespecificeerd.",
"Enter new" : "Opgeven nieuw",
- "Delete" : "Verwijder",
"Add" : "Toevoegen",
"Edit tags" : "Bewerken tags",
"Error loading dialog template: {error}" : "Fout bij laden dialoog sjabloon: {error}",
@@ -184,15 +201,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "De update is niet geslaagd.",
"The update was successful. There were warnings." : "De update is geslaagd. Er zijn wel waarschuwingen.",
"The update was successful. Redirecting you to ownCloud now." : "De update is geslaagd. U wordt teruggeleid naar uw eigen ownCloud.",
- "Couldn't reset password because the token is invalid" : "Kon het wachtwoord niet herstellen, omdat het token ongeldig is",
- "Couldn't reset password because the token is expired" : "Kon het wachtwoord niet herstellen, omdat het token verlopen is",
- "Couldn't send reset email. Please make sure your username is correct." : "Kon e-mail niet versturen. Verifieer of uw gebruikersnaam correct is.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Kon geen herstel e-mail versturen, omdat er geen e-mailadres bekend is bij deze gebruikersnaam. Neem contact op met uw beheerder.",
- "%s password reset" : "%s wachtwoord reset",
- "Use the following link to reset your password: {link}" : "Gebruik de volgende link om uw wachtwoord te resetten: {link}",
- "New password" : "Nieuw wachtwoord",
- "New Password" : "Nieuw wachtwoord",
- "Reset password" : "Reset wachtwoord",
"Searching other places" : "Zoeken op andere plaatsen",
"No search results in other folders" : "Geen zoekresultaten in andere mappen",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} zoekresultaat in een andere map","{count} zoekresultaten in andere mappen"],
@@ -262,13 +270,19 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Probeer het opnieuw of neem contact op met uw beheerder.",
"Log in" : "Meld u aan",
"Wrong password. Reset it?" : "Onjuist wachtwoord. Resetten?",
+ "Wrong password." : "Onjuist wachtwoord.",
"Stay logged in" : "Ingelogd blijven",
"Alternative Logins" : "Alternatieve inlogs",
+ "Use the following link to reset your password: {link}" : "Gebruik de volgende link om uw wachtwoord te resetten: {link}",
+ "New password" : "Nieuw wachtwoord",
+ "New Password" : "Nieuw wachtwoord",
+ "Reset password" : "Reset wachtwoord",
"This ownCloud instance is currently in single user mode." : "Deze ownCloud werkt momenteel in enkele gebruiker modus.",
"This means only administrators can use the instance." : "Dat betekent dat alleen beheerders deze installatie kunnen gebruiken.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Neem contact op met uw systeembeheerder als deze melding aanhoudt of onverwacht verscheen.",
"Thank you for your patience." : "Bedankt voor uw geduld.",
"You are accessing the server from an untrusted domain." : "U benadert de server vanaf een niet vertrouwd domein.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Neem contact op met uw beheerder. Als u de beheerder van deze service bent, configureer dan de \"trusted_domains\" instelling in config/config.php. Een voorbeeldconfiguratie is gegeven in config/config.sample.php.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Afhankelijk van uw configuratie zou u als beheerder ook de onderstaande knop kunnen gebruiken om dit domein te vertrouwen.",
"Add \"%s\" as trusted domain" : "\"%s\" toevoegen als vertrouwd domein",
"App update required" : "Bijwerken App vereist",
diff --git a/core/l10n/nl.json b/core/l10n/nl.json
index a86bbe3d4af..f5eb1c59b41 100644
--- a/core/l10n/nl.json
+++ b/core/l10n/nl.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "Bijgewerkt \"%s\" naar %s",
"Repair warning: " : "Reparatiewaarschuwing:",
"Repair error: " : "Reparatiefout:",
- "Set log level to debug - current level: \"%s\"" : "Instellen logniveau op debug - huidige niveau: \"%s\"",
- "Reset log level to \"%s\"" : "Terugzetten logniveau op \"#%s\"",
+ "Set log level to debug" : "Logniveau instellen op debug",
+ "Reset log level" : "Terugzetten logniveau",
+ "Starting code integrity check" : "Starten code betrouwbaarheidscontrole",
+ "Finished code integrity check" : "Gereed met code betrouwbaarheidscontrole",
"%s (3rdparty)" : "%s (3rdparty)",
"%s (incompatible)" : "%s (incompatibel)",
"Following apps have been disabled: %s" : "De volgende apps zijn gedeactiveerd: %s",
"Already up to date" : "Al bijgewerkt",
+ "Please select a file." : "Selecteer een bestand.",
"File is too big" : "Bestand te groot",
"Invalid file provided" : "Ongeldig bestand opgegeven",
"No image or file provided" : "Geen afbeelding of bestand opgegeven",
@@ -30,6 +33,12 @@
"No crop data provided" : "Geen bijsnijdingsgegevens opgegeven",
"No valid crop data provided" : "Geen geldige bijsnijdingsgegevens opgegeven",
"Crop is not square" : "Bijsnijding is niet vierkant",
+ "Couldn't reset password because the token is invalid" : "Kon het wachtwoord niet herstellen, omdat het token ongeldig is",
+ "Couldn't reset password because the token is expired" : "Kon het wachtwoord niet herstellen, omdat het token verlopen is",
+ "Couldn't send reset email. Please make sure your username is correct." : "Kon e-mail niet versturen. Verifieer of uw gebruikersnaam correct is.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Kon geen herstel e-mail versturen, omdat er geen e-mailadres bekend is bij deze gebruikersnaam. Neem contact op met uw beheerder.",
+ "%s password reset" : "%s wachtwoord reset",
+ "Couldn't send reset email. Please contact your administrator." : "Kon herstel e-mail niet versturen. Neem contact op met uw beheerder.",
"Sunday" : "zondag",
"Monday" : "maandag",
"Tuesday" : "dinsdag",
@@ -75,10 +84,10 @@
"Oct." : "Okt.",
"Nov." : "Nov.",
"Dec." : "Dec.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Er traden problemen op tijdens de code betrouwbaarheidscontrole. Meer informatie…</a>",
"Settings" : "Instellingen",
"Saving..." : "Opslaan",
"seconds ago" : "seconden geleden",
- "Couldn't send reset email. Please contact your administrator." : "Kon herstel e-mail niet versturen. Neem contact op met uw beheerder.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "De link om uw wachtwoord te herstellen is per e-mail naar u verstuurd. Als u dit bericht niet binnen redelijke tijd hebt ontvangen, controleer dan uw spammap. <br>Als het daar niet in zit, neem dan contact op met uw beheerder.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Uw bestanden zijn versleuteld. Als u de herstelsleutel niet hebt geactiveerd, is er geen mogelijk om uw gegevens terug te krijgen nadat uw wachtwoord is hersteld. <br>Als u niet weet wat u moet doen, neem dan eerst contact op met uw beheerder. <br>Wilt u echt verder gaan?",
"I know what I'm doing" : "Ik weet wat ik doe",
@@ -107,13 +116,15 @@
"Good password" : "Goed wachtwoord",
"Strong password" : "Sterk wachtwoord",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Uw webserver is nog niet goed ingesteld voor bestandssynchronisatie omdat de WebDAV interface verstoord lijkt.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Uw webserver is niet goed ingesteld om \"{url}\" te vinden. Meer informatie is te vinden in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Deze server heeft geen actieve internetverbinding. Dat betekent dat sommige functies, zoals aankoppelen van externe opslag, notificaties over updates of installatie van apps van 3e partijen niet werken. Ook het benaderen van bestanden vanaf een remote locatie en het versturen van notificatie emails kan mislukken. We adviseren om de internetverbinding voor deze server in te schakelen als u alle functies wilt gebruiken.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Uw data folder en uw bestanden zijn waarschijnlijk vanaf het internet bereikbaar. Het .htaccess-bestand werkt niet. We raden ten zeerste aan aan om uw webserver zodanig te configureren, dat de datadirectory niet bereikbaar is vanaf het internet of om uw datadirectory te verplaatsen naar een locatie buiten de document root van de webserver.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Er is geen geheugencache geconfigureerd. Om de prestaties te verhogen kunt u de memcache configureren als die beschikbaar is. Meer informatie vind u in onze <a href=\"{docLink}\">documentatie</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom is niet leesbaar door PHP, hetgeen wordt afgeraden wegens beveiligingsredenen. Meer informatie in onze <a href=\"{docLink}\">documentatie</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "UwPHP versie ({version}) wordt niet langer <a href=\"{phpLink}\">ondersteund door PHP</a>. We adviseren u om uw PHP versie te upgraden voor betere prestaties en security updates geleverd door PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "De reverse proxy headerconfiguratie is onjuist, of u hebt toegang tot ownCloud via een vertrouwde proxy. Als u ownCloud niet via een vertrouwde proxy benadert, dan levert dan een beveiligingsrisico op, waardoor een aanvaller het IP-adres dat ownCloud ziet kan spoofen. Meer informatie is te vinden in onze <a href=\"{docLink}\">documentatie</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached is geconfigureerd als gedistribueerde cache, maar de verkeerde PHP module \"memcache\" is geïnstalleerd. \\OC\\Memcache\\Memcached ondersteunt alleen \"memcached\" en niet \"memcache\". Zie de <a href=\"{wikiLink}\">memcached wiki over beide modules</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Er is geen geheugencache geconfigureerd. Om de prestaties te verhogen kunt u de memcache configureren als die beschikbaar is. Meer informatie vind u in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom is niet leesbaar door PHP, hetgeen wordt afgeraden wegens beveiligingsredenen. Meer informatie in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "UwPHP versie ({version}) wordt niet langer <a target=\"_blank\" href=\"{phpLink}\">ondersteund door PHP</a>. We adviseren u om uw PHP versie te upgraden voor betere prestaties en security updates geleverd door PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "De reverse proxy headerconfiguratie is onjuist, of u hebt toegang tot ownCloud via een vertrouwde proxy. Als u ownCloud niet via een vertrouwde proxy benadert, dan levert dan een beveiligingsrisico op, waardoor een aanvaller het IP-adres dat ownCloud ziet kan spoofen. Meer informatie is te vinden in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached is geconfigureerd als gedistribueerde cache, maar de verkeerde PHP module \"memcache\" is geïnstalleerd. \\OC\\Memcache\\Memcached ondersteunt alleen \"memcached\" en niet \"memcache\". Zie de <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki over beide modules</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Sommige bestanden kwamen niet door de code betrouwbaarheidscontrole. Meer informatie over het oplossen van dit probleem kan worden gevonden in onze <a target=\"_blank\" href=\"{docLink}\">documentatie</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lijst met ongeldige bestanden…</a> / <a href=\"{rescanEndpoint}\">Opnieuw…</a>)",
"Error occurred while checking server setup" : "Een fout trad op bij checken serverconfiguratie",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "De \"{header}\" HTTP header is niet overeenkomstig met \"{expected}\" geconfigureerd. Dit is een potentieel security of privacy risico en we adviseren om deze instelling te wijzigen.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "De \"Strict-Transport-Security\" HTTP header is niet geconfigureerd als minimaal \"{seconds}\" seconden. Voor verbeterde beveiliging adviseren we HSTS in te schakelen zoals beschreven in onze <a href=\"{docUrl}\">security tips</a>.",
@@ -123,7 +134,6 @@
"Error" : "Fout",
"Error while sharing" : "Fout tijdens het delen",
"Error while unsharing" : "Fout tijdens het stoppen met delen",
- "Error while changing permissions" : "Fout tijdens het veranderen van permissies",
"Error setting expiration date" : "Fout tijdens het instellen van de vervaldatum",
"The public link will expire no later than {days} days after it is created" : "De openbare link vervalt niet eerder dan {days} dagen na het aanmaken",
"Set expiration date" : "Stel vervaldatum in",
@@ -142,7 +152,6 @@
"Send" : "Versturen",
"Shared with you and the group {group} by {owner}" : "Gedeeld met u en de groep {group} door {owner}",
"Shared with you by {owner}" : "Gedeeld met u door {owner}",
- "Shared in {item} with {user}" : "Gedeeld in {item} met {user}",
"group" : "groep",
"remote" : "extern",
"notify by email" : "melden per e-mail",
@@ -153,17 +162,25 @@
"change" : "wijzig",
"delete" : "verwijderen",
"access control" : "toegangscontrole",
+ "Could not unshare" : "Kon delen niet ongedaan maken",
"Share details could not be loaded for this item." : "Details van shares voor dit object konden niet worden geladen.",
"An error occured. Please try again" : "Er trad een fout op. Probeer het opnieuw",
"Share" : "Delen",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Delen met mensen op andere ownClouds via de syntax gebruikersnaam@voorbeeld.org/owncloud",
"Share with users or groups …" : "Delen met gebruikers of groepen ...",
"Share with users, groups or remote users …" : "Delen met gebruikers, groepen of externe gebruikers ...",
+ "Error removing share" : "Fout bij verwijderen share",
"Warning" : "Waarschuwing",
"Error while sending notification" : "Fout bij versturen melding",
+ "Non-existing tag #{tag}" : "Niet bestaande tag #{tag}",
+ "not assignable" : "niet toewijsbaar",
+ "invisible" : "onzichtbaar",
+ "({scope})" : "({scope})",
+ "Delete" : "Verwijder",
+ "Rename" : "Naam wijzigen",
+ "Global tags" : "Globale tags",
"The object type is not specified." : "Het object type is niet gespecificeerd.",
"Enter new" : "Opgeven nieuw",
- "Delete" : "Verwijder",
"Add" : "Toevoegen",
"Edit tags" : "Bewerken tags",
"Error loading dialog template: {error}" : "Fout bij laden dialoog sjabloon: {error}",
@@ -182,15 +199,6 @@
"The update was unsuccessful. " : "De update is niet geslaagd.",
"The update was successful. There were warnings." : "De update is geslaagd. Er zijn wel waarschuwingen.",
"The update was successful. Redirecting you to ownCloud now." : "De update is geslaagd. U wordt teruggeleid naar uw eigen ownCloud.",
- "Couldn't reset password because the token is invalid" : "Kon het wachtwoord niet herstellen, omdat het token ongeldig is",
- "Couldn't reset password because the token is expired" : "Kon het wachtwoord niet herstellen, omdat het token verlopen is",
- "Couldn't send reset email. Please make sure your username is correct." : "Kon e-mail niet versturen. Verifieer of uw gebruikersnaam correct is.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Kon geen herstel e-mail versturen, omdat er geen e-mailadres bekend is bij deze gebruikersnaam. Neem contact op met uw beheerder.",
- "%s password reset" : "%s wachtwoord reset",
- "Use the following link to reset your password: {link}" : "Gebruik de volgende link om uw wachtwoord te resetten: {link}",
- "New password" : "Nieuw wachtwoord",
- "New Password" : "Nieuw wachtwoord",
- "Reset password" : "Reset wachtwoord",
"Searching other places" : "Zoeken op andere plaatsen",
"No search results in other folders" : "Geen zoekresultaten in andere mappen",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} zoekresultaat in een andere map","{count} zoekresultaten in andere mappen"],
@@ -260,13 +268,19 @@
"Please try again or contact your administrator." : "Probeer het opnieuw of neem contact op met uw beheerder.",
"Log in" : "Meld u aan",
"Wrong password. Reset it?" : "Onjuist wachtwoord. Resetten?",
+ "Wrong password." : "Onjuist wachtwoord.",
"Stay logged in" : "Ingelogd blijven",
"Alternative Logins" : "Alternatieve inlogs",
+ "Use the following link to reset your password: {link}" : "Gebruik de volgende link om uw wachtwoord te resetten: {link}",
+ "New password" : "Nieuw wachtwoord",
+ "New Password" : "Nieuw wachtwoord",
+ "Reset password" : "Reset wachtwoord",
"This ownCloud instance is currently in single user mode." : "Deze ownCloud werkt momenteel in enkele gebruiker modus.",
"This means only administrators can use the instance." : "Dat betekent dat alleen beheerders deze installatie kunnen gebruiken.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Neem contact op met uw systeembeheerder als deze melding aanhoudt of onverwacht verscheen.",
"Thank you for your patience." : "Bedankt voor uw geduld.",
"You are accessing the server from an untrusted domain." : "U benadert de server vanaf een niet vertrouwd domein.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Neem contact op met uw beheerder. Als u de beheerder van deze service bent, configureer dan de \"trusted_domains\" instelling in config/config.php. Een voorbeeldconfiguratie is gegeven in config/config.sample.php.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Afhankelijk van uw configuratie zou u als beheerder ook de onderstaande knop kunnen gebruiken om dit domein te vertrouwen.",
"Add \"%s\" as trusted domain" : "\"%s\" toevoegen als vertrouwd domein",
"App update required" : "Bijwerken App vereist",
diff --git a/core/l10n/nn_NO.js b/core/l10n/nn_NO.js
index c16b1dc7887..82b4e5518fe 100644
--- a/core/l10n/nn_NO.js
+++ b/core/l10n/nn_NO.js
@@ -10,6 +10,7 @@ OC.L10N.register(
"Invalid image" : "Ugyldig bilete",
"No temporary profile picture available, try again" : "Inga midlertidig profilbilete tilgjengeleg, prøv igjen",
"No crop data provided" : "Ingen beskjeringsdata gjeve",
+ "%s password reset" : "%s passordnullstilling",
"Sunday" : "Søndag",
"Monday" : "Måndag",
"Tuesday" : "Tysdag",
@@ -73,7 +74,6 @@ OC.L10N.register(
"Error" : "Feil",
"Error while sharing" : "Feil ved deling",
"Error while unsharing" : "Feil ved udeling",
- "Error while changing permissions" : "Feil ved endring av tillatingar",
"Error setting expiration date" : "Klarte ikkje setja utløpsdato",
"Set expiration date" : "Set utløpsdato",
"Expiration date" : "Utløpsdato",
@@ -88,7 +88,6 @@ OC.L10N.register(
"Send" : "Send",
"Shared with you and the group {group} by {owner}" : "Delt med deg og gruppa {group} av {owner}",
"Shared with you by {owner}" : "Delt med deg av {owner}",
- "Shared in {item} with {user}" : "Delt i {item} med {brukar}",
"group" : "gruppe",
"Unshare" : "Udel",
"can share" : "kan dela",
@@ -98,14 +97,11 @@ OC.L10N.register(
"access control" : "tilgangskontroll",
"Share" : "Del",
"Warning" : "Åtvaring",
- "The object type is not specified." : "Objekttypen er ikkje spesifisert.",
"Delete" : "Slett",
+ "Rename" : "Endra namn",
+ "The object type is not specified." : "Objekttypen er ikkje spesifisert.",
"Add" : "Legg til",
"The update was successful. Redirecting you to ownCloud now." : "Oppdateringa er fullført. Sender deg vidare til ownCloud no.",
- "%s password reset" : "%s passordnullstilling",
- "Use the following link to reset your password: {link}" : "Klikk følgjande lenkje til å nullstilla passordet ditt: {link}",
- "New password" : "Nytt passord",
- "Reset password" : "Nullstill passord",
"Personal" : "Personleg",
"Users" : "Brukarar",
"Apps" : "Program",
@@ -127,6 +123,9 @@ OC.L10N.register(
"Log out" : "Logg ut",
"Search" : "Søk",
"Log in" : "Logg inn",
- "Alternative Logins" : "Alternative innloggingar"
+ "Alternative Logins" : "Alternative innloggingar",
+ "Use the following link to reset your password: {link}" : "Klikk følgjande lenkje til å nullstilla passordet ditt: {link}",
+ "New password" : "Nytt passord",
+ "Reset password" : "Nullstill passord"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/nn_NO.json b/core/l10n/nn_NO.json
index fd4fb2dd4a7..9e74f280d42 100644
--- a/core/l10n/nn_NO.json
+++ b/core/l10n/nn_NO.json
@@ -8,6 +8,7 @@
"Invalid image" : "Ugyldig bilete",
"No temporary profile picture available, try again" : "Inga midlertidig profilbilete tilgjengeleg, prøv igjen",
"No crop data provided" : "Ingen beskjeringsdata gjeve",
+ "%s password reset" : "%s passordnullstilling",
"Sunday" : "Søndag",
"Monday" : "Måndag",
"Tuesday" : "Tysdag",
@@ -71,7 +72,6 @@
"Error" : "Feil",
"Error while sharing" : "Feil ved deling",
"Error while unsharing" : "Feil ved udeling",
- "Error while changing permissions" : "Feil ved endring av tillatingar",
"Error setting expiration date" : "Klarte ikkje setja utløpsdato",
"Set expiration date" : "Set utløpsdato",
"Expiration date" : "Utløpsdato",
@@ -86,7 +86,6 @@
"Send" : "Send",
"Shared with you and the group {group} by {owner}" : "Delt med deg og gruppa {group} av {owner}",
"Shared with you by {owner}" : "Delt med deg av {owner}",
- "Shared in {item} with {user}" : "Delt i {item} med {brukar}",
"group" : "gruppe",
"Unshare" : "Udel",
"can share" : "kan dela",
@@ -96,14 +95,11 @@
"access control" : "tilgangskontroll",
"Share" : "Del",
"Warning" : "Åtvaring",
- "The object type is not specified." : "Objekttypen er ikkje spesifisert.",
"Delete" : "Slett",
+ "Rename" : "Endra namn",
+ "The object type is not specified." : "Objekttypen er ikkje spesifisert.",
"Add" : "Legg til",
"The update was successful. Redirecting you to ownCloud now." : "Oppdateringa er fullført. Sender deg vidare til ownCloud no.",
- "%s password reset" : "%s passordnullstilling",
- "Use the following link to reset your password: {link}" : "Klikk følgjande lenkje til å nullstilla passordet ditt: {link}",
- "New password" : "Nytt passord",
- "Reset password" : "Nullstill passord",
"Personal" : "Personleg",
"Users" : "Brukarar",
"Apps" : "Program",
@@ -125,6 +121,9 @@
"Log out" : "Logg ut",
"Search" : "Søk",
"Log in" : "Logg inn",
- "Alternative Logins" : "Alternative innloggingar"
+ "Alternative Logins" : "Alternative innloggingar",
+ "Use the following link to reset your password: {link}" : "Klikk følgjande lenkje til å nullstilla passordet ditt: {link}",
+ "New password" : "Nytt passord",
+ "Reset password" : "Nullstill passord"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/oc.js b/core/l10n/oc.js
index 6c27148b497..c72bd205dc9 100644
--- a/core/l10n/oc.js
+++ b/core/l10n/oc.js
@@ -16,8 +16,6 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Mesa a jorn de « %s » cap a %s",
"Repair warning: " : "Avertiment de reparacion :",
"Repair error: " : "Error de reparacion :",
- "Set log level to debug - current level: \"%s\"" : "Reglatge del nivèl de log de \"desbug\" - nivèl actual : \"%s\"",
- "Reset log level to \"%s\"" : "Reglatge del nivèl de log de \"desbug\" - nivèl actual : \"%s\"",
"%s (3rdparty)" : "%s (origina tèrça)",
"%s (incompatible)" : "%s (incompatible)",
"Following apps have been disabled: %s" : "Las aplicacions seguentas son estadas desactivadas : %s",
@@ -32,6 +30,11 @@ OC.L10N.register(
"No crop data provided" : "Cap de donada de requadratge pas provesida",
"No valid crop data provided" : "Donadas de requadratge invalidas",
"Crop is not square" : "Lo requadratge es pas carrat",
+ "Couldn't reset password because the token is invalid" : "Impossible de reïnicializar lo senhal perque lo geton es pas valable.",
+ "Couldn't reset password because the token is expired" : "Impossible de reïnicializar lo senhal perque lo geton a expirat.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Impossible de mandar lo corrièl de reïnicializacion. Verificatz que vòstre nom d'utilizaire es corrècte.",
+ "%s password reset" : "Reïnicializacion de vòstre senhal %s",
+ "Couldn't send reset email. Please contact your administrator." : "Impossible de mandar lo corrièl de reïnicializacion. Contactatz vòstre administrator.",
"Sunday" : "Dimenge",
"Monday" : "Diluns",
"Tuesday" : "Dimars",
@@ -80,7 +83,6 @@ OC.L10N.register(
"Settings" : "Paramètres",
"Saving..." : "Enregistrament…",
"seconds ago" : "i a qualques segondas",
- "Couldn't send reset email. Please contact your administrator." : "Impossible de mandar lo corrièl de reïnicializacion. Contactatz vòstre administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Lo ligam que permet de reïnicializar vòstre senhal ven d'èsser mandat a vòstra adreça de corrièl.<br>Se o recebètz pas dins un relambi rasonable, contactatz vòstre administrator.<br>Doblidetz pas de verificar dins vòstre dorsièr corrièr indesirable / spam!",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vòstres fichièrs son chifrats. Se avètz pas activat la clau de recuperacion, i aurà pas cap de mejan de recuperar vòstras donadas un còp lo senhal reïnicializat.<br />Se sètz pas segur(a) de çò que fasètz, contactatz vòstre administrator abans de contunhar. <br />Sètz segur que volètz contunhar ?",
"I know what I'm doing" : "Sabi çò que fau",
@@ -111,11 +113,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Vòstre servidor web es pas corrèctament configurat per la sincronizacion de fichièrs : sembla que l'interfàcia WebDAV fonciona pas.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Aqueste servidor se pòt pas connectar a internet. Aquò significa que certanas foncionalitats, talas coma lo montatge de supòrts d'emmagazinatge distants, las notificacions de mesas a jorn o l'installacion d'aplicacions tèrças foncionaràn pas. L'accès als fichièrs a distància, e tanben las notificacions per mail pòdon tanben èsser indisponiblas. Es recomandat d'activar la connexion internet per aqueste servidor se volètz dispausar de l'ensemble de las foncionalitats ofèrtas.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Vòstre dorsièr de donadas e vòstres fichièrs son probablament accessibles dempuèi internet. Lo fichièr .htaccess fonciona pas. Vos recomandam bravament de configurar vòstre servidor web de manièra qu'aqueste dorsièr de donadas siá pas mai accessible, o de lo desplaçar en defòra de la raiç del servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Cap d'escondedor de la memòria es pas configurat. Se possible, configuratz un \"memcache\" per aumentar las performàncias. Per mai d'information consultatz la <a href=\"{docLink}\">documentacion</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom es pas legible per PHP, aquò es bravament desconselhat per de rasons de seguretat. Mai d'informacions pòdon èsser trobadas dins nòstra <a href=\"{docLink}\">documentacion</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La version de PHP utilizada ({version}) <a href=\"{phpLink}\">es pas mai presa en carga pels creators de PHP</a>. Vos recomandam de metre a nivèl vòstra installacion de PHP per beneficiar de performàncias melhoras e de las mesas a jorn de seguretat provesidas per PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La configuracion dels headers del reverse proxy es incorrècta, o accedissètz a ownCloud dempuèi un proxy fisable. Se sètz pas a accedir a ownCloud dempuèi un proxy fisable, aquò es un problèma de seguretat que pòt permetre a un atacant d'amagar sa vertadièra adreça IP. <a href=\"{docLink}\">Mai d'info dins la documentacion.</a>",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "\"memcached\" es configurat coma escondedor distribuit, mas lo modul installat es \"memcache\". \\OC\\Memcache\\Memcached pren pas en carga que \"memcached\" e non pas \"memcache\". <a href=\"{wikiLink}\">Consultar lo wiki memcached que parla d'aquestes dos moduls.</a>",
"Error occurred while checking server setup" : "Una error s'es produsida al moment de la verificacion de la configuracion del servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "L'entèsta HTTP \"{header}\" es pas configurada per èsser egala a \"{expected}\" en creant potencialament un risc religat a la seguretat e a la vida privada. Es doncas recomandat d'ajustar aqueste paramètre.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "L'entèsta HTTP \"Strict-Transport-Security\" es pas configurada a \"{seconds}\" segondas. Per renforçar la seguretat, recomandam d'activar HSTS coma descrich dins nòstre <a href=\"{docUrl}\">Guida pel renfortiment e la seguretat</a>.",
@@ -125,7 +122,6 @@ OC.L10N.register(
"Error" : "Error",
"Error while sharing" : "Error al moment de la mesa en partiment",
"Error while unsharing" : "Error al moment de l'anullacion del partiment",
- "Error while changing permissions" : "Error al moment del cambiament de las permissions",
"Error setting expiration date" : "Error al moment de l'especificacion de la data d'expiracion",
"The public link will expire no later than {days} days after it is created" : "Aqueste ligam public expirarà al mai tard {days} jorns aprèp sa creacion.",
"Set expiration date" : "Especificar una data d'expiracion",
@@ -144,7 +140,6 @@ OC.L10N.register(
"Send" : "Mandar",
"Shared with you and the group {group} by {owner}" : "Partejat amb vos e lo grop {group} per {owner}",
"Shared with you by {owner}" : "Partejat amb vos per {owner}",
- "Shared in {item} with {user}" : "Partejat dins {item} amb {user}",
"group" : "grop",
"remote" : "distant",
"notify by email" : "notificar per corrièl",
@@ -163,9 +158,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Partejar amb d'utilizaires, gropes, o utilizaires distants",
"Warning" : "Atencion",
"Error while sending notification" : "Error al moment del mandadís de la notificacion",
+ "Delete" : "Suprimir",
+ "Rename" : "Renomenar",
"The object type is not specified." : "Lo tipe d'objècte es pas especificat.",
"Enter new" : "Picar un novèl",
- "Delete" : "Suprimir",
"Add" : "Apondre",
"Edit tags" : "Modificar las etiquetas",
"Error loading dialog template: {error}" : "Error al moment del cargament del modèl de dialòg : {error}",
@@ -184,15 +180,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "La mesa a jorn a fracassat.",
"The update was successful. There were warnings." : "La mesa a jorn a capitat, mas i a agut d'avertiments",
"The update was successful. Redirecting you to ownCloud now." : "La mesa a jorn a capitat. Ara sètz redirigit cap a ownCloud.",
- "Couldn't reset password because the token is invalid" : "Impossible de reïnicializar lo senhal perque lo geton es pas valable.",
- "Couldn't reset password because the token is expired" : "Impossible de reïnicializar lo senhal perque lo geton a expirat.",
- "Couldn't send reset email. Please make sure your username is correct." : "Impossible de mandar lo corrièl de reïnicializacion. Verificatz que vòstre nom d'utilizaire es corrècte.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Impossible de mandar lo corrièl de reïnicializacion perque i a pas cap d'adreça de corrièl per aqueste utilizaire. Contactatz vòstre administrator.",
- "%s password reset" : "Reïnicializacion de vòstre senhal %s",
- "Use the following link to reset your password: {link}" : "Utilizatz lo ligam seguent per reïnicializar vòstre senhal : {link}",
- "New password" : "Senhal novèl",
- "New Password" : "Senhal novèl",
- "Reset password" : "Reïnicializar lo senhal",
"Searching other places" : "Recèrca en cors dins d'autres emplaçaments",
"No search results in other folders" : "Pas cap de resultat dins d'autres dorsièrs",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} resultat dins un autre dorsièr","{count} resultats dins d'autres dorsièrs"],
@@ -264,6 +251,10 @@ OC.L10N.register(
"Wrong password. Reset it?" : "Senhal incorrècte. Reïnicializar ?",
"Stay logged in" : "Demorar connectat",
"Alternative Logins" : "Identificants alternatius",
+ "Use the following link to reset your password: {link}" : "Utilizatz lo ligam seguent per reïnicializar vòstre senhal : {link}",
+ "New password" : "Senhal novèl",
+ "New Password" : "Senhal novèl",
+ "Reset password" : "Reïnicializar lo senhal",
"This ownCloud instance is currently in single user mode." : "Aquesta instància de ownCloud es actualament en mòde utilizaire unic.",
"This means only administrators can use the instance." : "Aquò significa que sols los administrators pòdon utilizar l'instància.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contactatz vòstre administrator sistèma se aqueste messatge persistís o apareis de faiçon imprevista.",
diff --git a/core/l10n/oc.json b/core/l10n/oc.json
index c73667e6f1c..455290a2940 100644
--- a/core/l10n/oc.json
+++ b/core/l10n/oc.json
@@ -14,8 +14,6 @@
"Updated \"%s\" to %s" : "Mesa a jorn de « %s » cap a %s",
"Repair warning: " : "Avertiment de reparacion :",
"Repair error: " : "Error de reparacion :",
- "Set log level to debug - current level: \"%s\"" : "Reglatge del nivèl de log de \"desbug\" - nivèl actual : \"%s\"",
- "Reset log level to \"%s\"" : "Reglatge del nivèl de log de \"desbug\" - nivèl actual : \"%s\"",
"%s (3rdparty)" : "%s (origina tèrça)",
"%s (incompatible)" : "%s (incompatible)",
"Following apps have been disabled: %s" : "Las aplicacions seguentas son estadas desactivadas : %s",
@@ -30,6 +28,11 @@
"No crop data provided" : "Cap de donada de requadratge pas provesida",
"No valid crop data provided" : "Donadas de requadratge invalidas",
"Crop is not square" : "Lo requadratge es pas carrat",
+ "Couldn't reset password because the token is invalid" : "Impossible de reïnicializar lo senhal perque lo geton es pas valable.",
+ "Couldn't reset password because the token is expired" : "Impossible de reïnicializar lo senhal perque lo geton a expirat.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Impossible de mandar lo corrièl de reïnicializacion. Verificatz que vòstre nom d'utilizaire es corrècte.",
+ "%s password reset" : "Reïnicializacion de vòstre senhal %s",
+ "Couldn't send reset email. Please contact your administrator." : "Impossible de mandar lo corrièl de reïnicializacion. Contactatz vòstre administrator.",
"Sunday" : "Dimenge",
"Monday" : "Diluns",
"Tuesday" : "Dimars",
@@ -78,7 +81,6 @@
"Settings" : "Paramètres",
"Saving..." : "Enregistrament…",
"seconds ago" : "i a qualques segondas",
- "Couldn't send reset email. Please contact your administrator." : "Impossible de mandar lo corrièl de reïnicializacion. Contactatz vòstre administrator.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Lo ligam que permet de reïnicializar vòstre senhal ven d'èsser mandat a vòstra adreça de corrièl.<br>Se o recebètz pas dins un relambi rasonable, contactatz vòstre administrator.<br>Doblidetz pas de verificar dins vòstre dorsièr corrièr indesirable / spam!",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vòstres fichièrs son chifrats. Se avètz pas activat la clau de recuperacion, i aurà pas cap de mejan de recuperar vòstras donadas un còp lo senhal reïnicializat.<br />Se sètz pas segur(a) de çò que fasètz, contactatz vòstre administrator abans de contunhar. <br />Sètz segur que volètz contunhar ?",
"I know what I'm doing" : "Sabi çò que fau",
@@ -109,11 +111,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Vòstre servidor web es pas corrèctament configurat per la sincronizacion de fichièrs : sembla que l'interfàcia WebDAV fonciona pas.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Aqueste servidor se pòt pas connectar a internet. Aquò significa que certanas foncionalitats, talas coma lo montatge de supòrts d'emmagazinatge distants, las notificacions de mesas a jorn o l'installacion d'aplicacions tèrças foncionaràn pas. L'accès als fichièrs a distància, e tanben las notificacions per mail pòdon tanben èsser indisponiblas. Es recomandat d'activar la connexion internet per aqueste servidor se volètz dispausar de l'ensemble de las foncionalitats ofèrtas.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Vòstre dorsièr de donadas e vòstres fichièrs son probablament accessibles dempuèi internet. Lo fichièr .htaccess fonciona pas. Vos recomandam bravament de configurar vòstre servidor web de manièra qu'aqueste dorsièr de donadas siá pas mai accessible, o de lo desplaçar en defòra de la raiç del servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Cap d'escondedor de la memòria es pas configurat. Se possible, configuratz un \"memcache\" per aumentar las performàncias. Per mai d'information consultatz la <a href=\"{docLink}\">documentacion</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom es pas legible per PHP, aquò es bravament desconselhat per de rasons de seguretat. Mai d'informacions pòdon èsser trobadas dins nòstra <a href=\"{docLink}\">documentacion</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "La version de PHP utilizada ({version}) <a href=\"{phpLink}\">es pas mai presa en carga pels creators de PHP</a>. Vos recomandam de metre a nivèl vòstra installacion de PHP per beneficiar de performàncias melhoras e de las mesas a jorn de seguretat provesidas per PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "La configuracion dels headers del reverse proxy es incorrècta, o accedissètz a ownCloud dempuèi un proxy fisable. Se sètz pas a accedir a ownCloud dempuèi un proxy fisable, aquò es un problèma de seguretat que pòt permetre a un atacant d'amagar sa vertadièra adreça IP. <a href=\"{docLink}\">Mai d'info dins la documentacion.</a>",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "\"memcached\" es configurat coma escondedor distribuit, mas lo modul installat es \"memcache\". \\OC\\Memcache\\Memcached pren pas en carga que \"memcached\" e non pas \"memcache\". <a href=\"{wikiLink}\">Consultar lo wiki memcached que parla d'aquestes dos moduls.</a>",
"Error occurred while checking server setup" : "Una error s'es produsida al moment de la verificacion de la configuracion del servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "L'entèsta HTTP \"{header}\" es pas configurada per èsser egala a \"{expected}\" en creant potencialament un risc religat a la seguretat e a la vida privada. Es doncas recomandat d'ajustar aqueste paramètre.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "L'entèsta HTTP \"Strict-Transport-Security\" es pas configurada a \"{seconds}\" segondas. Per renforçar la seguretat, recomandam d'activar HSTS coma descrich dins nòstre <a href=\"{docUrl}\">Guida pel renfortiment e la seguretat</a>.",
@@ -123,7 +120,6 @@
"Error" : "Error",
"Error while sharing" : "Error al moment de la mesa en partiment",
"Error while unsharing" : "Error al moment de l'anullacion del partiment",
- "Error while changing permissions" : "Error al moment del cambiament de las permissions",
"Error setting expiration date" : "Error al moment de l'especificacion de la data d'expiracion",
"The public link will expire no later than {days} days after it is created" : "Aqueste ligam public expirarà al mai tard {days} jorns aprèp sa creacion.",
"Set expiration date" : "Especificar una data d'expiracion",
@@ -142,7 +138,6 @@
"Send" : "Mandar",
"Shared with you and the group {group} by {owner}" : "Partejat amb vos e lo grop {group} per {owner}",
"Shared with you by {owner}" : "Partejat amb vos per {owner}",
- "Shared in {item} with {user}" : "Partejat dins {item} amb {user}",
"group" : "grop",
"remote" : "distant",
"notify by email" : "notificar per corrièl",
@@ -161,9 +156,10 @@
"Share with users, groups or remote users …" : "Partejar amb d'utilizaires, gropes, o utilizaires distants",
"Warning" : "Atencion",
"Error while sending notification" : "Error al moment del mandadís de la notificacion",
+ "Delete" : "Suprimir",
+ "Rename" : "Renomenar",
"The object type is not specified." : "Lo tipe d'objècte es pas especificat.",
"Enter new" : "Picar un novèl",
- "Delete" : "Suprimir",
"Add" : "Apondre",
"Edit tags" : "Modificar las etiquetas",
"Error loading dialog template: {error}" : "Error al moment del cargament del modèl de dialòg : {error}",
@@ -182,15 +178,6 @@
"The update was unsuccessful. " : "La mesa a jorn a fracassat.",
"The update was successful. There were warnings." : "La mesa a jorn a capitat, mas i a agut d'avertiments",
"The update was successful. Redirecting you to ownCloud now." : "La mesa a jorn a capitat. Ara sètz redirigit cap a ownCloud.",
- "Couldn't reset password because the token is invalid" : "Impossible de reïnicializar lo senhal perque lo geton es pas valable.",
- "Couldn't reset password because the token is expired" : "Impossible de reïnicializar lo senhal perque lo geton a expirat.",
- "Couldn't send reset email. Please make sure your username is correct." : "Impossible de mandar lo corrièl de reïnicializacion. Verificatz que vòstre nom d'utilizaire es corrècte.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Impossible de mandar lo corrièl de reïnicializacion perque i a pas cap d'adreça de corrièl per aqueste utilizaire. Contactatz vòstre administrator.",
- "%s password reset" : "Reïnicializacion de vòstre senhal %s",
- "Use the following link to reset your password: {link}" : "Utilizatz lo ligam seguent per reïnicializar vòstre senhal : {link}",
- "New password" : "Senhal novèl",
- "New Password" : "Senhal novèl",
- "Reset password" : "Reïnicializar lo senhal",
"Searching other places" : "Recèrca en cors dins d'autres emplaçaments",
"No search results in other folders" : "Pas cap de resultat dins d'autres dorsièrs",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} resultat dins un autre dorsièr","{count} resultats dins d'autres dorsièrs"],
@@ -262,6 +249,10 @@
"Wrong password. Reset it?" : "Senhal incorrècte. Reïnicializar ?",
"Stay logged in" : "Demorar connectat",
"Alternative Logins" : "Identificants alternatius",
+ "Use the following link to reset your password: {link}" : "Utilizatz lo ligam seguent per reïnicializar vòstre senhal : {link}",
+ "New password" : "Senhal novèl",
+ "New Password" : "Senhal novèl",
+ "Reset password" : "Reïnicializar lo senhal",
"This ownCloud instance is currently in single user mode." : "Aquesta instància de ownCloud es actualament en mòde utilizaire unic.",
"This means only administrators can use the instance." : "Aquò significa que sols los administrators pòdon utilizar l'instància.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contactatz vòstre administrator sistèma se aqueste messatge persistís o apareis de faiçon imprevista.",
diff --git a/core/l10n/pa.js b/core/l10n/pa.js
index 2ab5eb0faff..6756021358d 100644
--- a/core/l10n/pa.js
+++ b/core/l10n/pa.js
@@ -34,6 +34,7 @@ OC.L10N.register(
"Share" : "ਸਾਂਝਾ ਕਰੋ",
"Warning" : "ਚੇਤਾਵਨੀ",
"Delete" : "ਹਟਾਓ",
+ "Rename" : "ਨਾਂ ਬਦਲੋ",
"Username" : "ਯੂਜ਼ਰ-ਨਾਂ",
"Search" : "ਖੋਜ"
},
diff --git a/core/l10n/pa.json b/core/l10n/pa.json
index 8a8d992589b..a222d9cecd7 100644
--- a/core/l10n/pa.json
+++ b/core/l10n/pa.json
@@ -32,6 +32,7 @@
"Share" : "ਸਾਂਝਾ ਕਰੋ",
"Warning" : "ਚੇਤਾਵਨੀ",
"Delete" : "ਹਟਾਓ",
+ "Rename" : "ਨਾਂ ਬਦਲੋ",
"Username" : "ਯੂਜ਼ਰ-ਨਾਂ",
"Search" : "ਖੋਜ"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/core/l10n/pl.js b/core/l10n/pl.js
index 972506283e9..f51edaca565 100644
--- a/core/l10n/pl.js
+++ b/core/l10n/pl.js
@@ -16,6 +16,10 @@ OC.L10N.register(
"Invalid image" : "Nieprawidłowe zdjęcie",
"No temporary profile picture available, try again" : "Brak obrazka profilu tymczasowego, spróbuj ponownie",
"No crop data provided" : "Brak danych do przycięcia",
+ "Couldn't reset password because the token is invalid" : "Nie można zresetować hasła, ponieważ token jest niepoprawny",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nie mogę wysłać maila resetującego. Sprawdź czy nazwa użytkownika jest poprawna.",
+ "%s password reset" : "%s reset hasła",
+ "Couldn't send reset email. Please contact your administrator." : "Nie mogę wysłać maila resetującego. Skontaktuj się z administratorem.",
"Sunday" : "Niedziela",
"Monday" : "Poniedziałek",
"Tuesday" : "Wtorek",
@@ -57,7 +61,6 @@ OC.L10N.register(
"Settings" : "Ustawienia",
"Saving..." : "Zapisywanie...",
"seconds ago" : "sekund temu",
- "Couldn't send reset email. Please contact your administrator." : "Nie mogę wysłać maila resetującego. Skontaktuj się z administratorem.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Link do zresetowanego hasła, został wysłany na twój adres e-mail. Jeśli nie dostałeś wiadomości w rozsądnym czasie, sprawdź folder ze spamem.<br> Jeśli nie ma wiadomości w tym folderze, skontaktuj się ze swoim administratorem.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Twoje pliki są zaszyfrowane. Jeśli nie włączyłeś klucza odzyskiwania, nie będzie możliwości odszyfrowania tych plików po zresetowaniu hasła.<br>Jeśli nie jesteś pewien co zrobić, skontaktuj się ze swoim administratorem, zanim bedziesz kontynuował. <br/> Czy chcesz kontynuować?\n ",
"I know what I'm doing" : "Wiem co robię",
@@ -91,7 +94,6 @@ OC.L10N.register(
"Error" : "Błąd",
"Error while sharing" : "Błąd podczas współdzielenia",
"Error while unsharing" : "Błąd podczas zatrzymywania współdzielenia",
- "Error while changing permissions" : "Błąd przy zmianie uprawnień",
"Error setting expiration date" : "Błąd podczas ustawiania daty wygaśnięcia",
"The public link will expire no later than {days} days after it is created" : "Link publiczny wygaśnie nie później niż po {days} dniach od utworzenia",
"Set expiration date" : "Ustaw datę wygaśnięcia",
@@ -110,7 +112,6 @@ OC.L10N.register(
"Send" : "Wyślij",
"Shared with you and the group {group} by {owner}" : "Udostępnione tobie i grupie {group} przez {owner}",
"Shared with you by {owner}" : "Udostępnione tobie przez {owner}",
- "Shared in {item} with {user}" : "Współdzielone w {item} z {user}",
"group" : "grupa",
"remote" : "zdalny",
"notify by email" : "powiadom przez emaila",
@@ -124,9 +125,10 @@ OC.L10N.register(
"Share" : "Udostępnij",
"Share with users or groups …" : "Współdziel z użytkownikami lub grupami",
"Warning" : "Ostrzeżenie",
+ "Delete" : "Usuń",
+ "Rename" : "Zmień nazwę",
"The object type is not specified." : "Nie określono typu obiektu.",
"Enter new" : "Wpisz nowy",
- "Delete" : "Usuń",
"Add" : "Dodaj",
"Edit tags" : "Edytuj tagi",
"Error loading dialog template: {error}" : "Błąd podczas ładowania szablonu dialogu: {error}",
@@ -141,14 +143,6 @@ OC.L10N.register(
"Please reload the page." : "Proszę przeładować stronę",
"The update was unsuccessful. " : "Aktualizowanie zakończyło się niepowodzeniem.",
"The update was successful. Redirecting you to ownCloud now." : "Aktualizacji zakończyła się powodzeniem. Przekierowuję do ownCloud.",
- "Couldn't reset password because the token is invalid" : "Nie można zresetować hasła, ponieważ token jest niepoprawny",
- "Couldn't send reset email. Please make sure your username is correct." : "Nie mogę wysłać maila resetującego. Sprawdź czy nazwa użytkownika jest poprawna.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nie mogę wysłać maila resetującego. Sprawdź czy nazwa użytkownika lub adres email jest poprawny. Skontaktuj się z administratorem.",
- "%s password reset" : "%s reset hasła",
- "Use the following link to reset your password: {link}" : "Użyj tego odnośnika by zresetować hasło: {link}",
- "New password" : "Nowe hasło",
- "New Password" : "Nowe hasło",
- "Reset password" : "Zresetuj hasło",
"Searching other places" : "Przeszukaj inne miejsca",
"Personal" : "Osobiste",
"Users" : "Użytkownicy",
@@ -206,6 +200,10 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Spróbuj ponownie lub skontaktuj się z administratorem.",
"Log in" : "Zaloguj",
"Alternative Logins" : "Alternatywne loginy",
+ "Use the following link to reset your password: {link}" : "Użyj tego odnośnika by zresetować hasło: {link}",
+ "New password" : "Nowe hasło",
+ "New Password" : "Nowe hasło",
+ "Reset password" : "Zresetuj hasło",
"This ownCloud instance is currently in single user mode." : "Ta instalacja ownCloud działa obecnie w trybie pojedynczego użytkownika.",
"This means only administrators can use the instance." : "To oznacza, że tylko administratorzy mogą w tej chwili używać aplikacji.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Skontaktuj się z administratorem, jeśli ten komunikat pojawił się nieoczekiwanie lub wyświetla się ciągle.",
diff --git a/core/l10n/pl.json b/core/l10n/pl.json
index 05c38bdcc0f..05a3f25f70d 100644
--- a/core/l10n/pl.json
+++ b/core/l10n/pl.json
@@ -14,6 +14,10 @@
"Invalid image" : "Nieprawidłowe zdjęcie",
"No temporary profile picture available, try again" : "Brak obrazka profilu tymczasowego, spróbuj ponownie",
"No crop data provided" : "Brak danych do przycięcia",
+ "Couldn't reset password because the token is invalid" : "Nie można zresetować hasła, ponieważ token jest niepoprawny",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nie mogę wysłać maila resetującego. Sprawdź czy nazwa użytkownika jest poprawna.",
+ "%s password reset" : "%s reset hasła",
+ "Couldn't send reset email. Please contact your administrator." : "Nie mogę wysłać maila resetującego. Skontaktuj się z administratorem.",
"Sunday" : "Niedziela",
"Monday" : "Poniedziałek",
"Tuesday" : "Wtorek",
@@ -55,7 +59,6 @@
"Settings" : "Ustawienia",
"Saving..." : "Zapisywanie...",
"seconds ago" : "sekund temu",
- "Couldn't send reset email. Please contact your administrator." : "Nie mogę wysłać maila resetującego. Skontaktuj się z administratorem.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Link do zresetowanego hasła, został wysłany na twój adres e-mail. Jeśli nie dostałeś wiadomości w rozsądnym czasie, sprawdź folder ze spamem.<br> Jeśli nie ma wiadomości w tym folderze, skontaktuj się ze swoim administratorem.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Twoje pliki są zaszyfrowane. Jeśli nie włączyłeś klucza odzyskiwania, nie będzie możliwości odszyfrowania tych plików po zresetowaniu hasła.<br>Jeśli nie jesteś pewien co zrobić, skontaktuj się ze swoim administratorem, zanim bedziesz kontynuował. <br/> Czy chcesz kontynuować?\n ",
"I know what I'm doing" : "Wiem co robię",
@@ -89,7 +92,6 @@
"Error" : "Błąd",
"Error while sharing" : "Błąd podczas współdzielenia",
"Error while unsharing" : "Błąd podczas zatrzymywania współdzielenia",
- "Error while changing permissions" : "Błąd przy zmianie uprawnień",
"Error setting expiration date" : "Błąd podczas ustawiania daty wygaśnięcia",
"The public link will expire no later than {days} days after it is created" : "Link publiczny wygaśnie nie później niż po {days} dniach od utworzenia",
"Set expiration date" : "Ustaw datę wygaśnięcia",
@@ -108,7 +110,6 @@
"Send" : "Wyślij",
"Shared with you and the group {group} by {owner}" : "Udostępnione tobie i grupie {group} przez {owner}",
"Shared with you by {owner}" : "Udostępnione tobie przez {owner}",
- "Shared in {item} with {user}" : "Współdzielone w {item} z {user}",
"group" : "grupa",
"remote" : "zdalny",
"notify by email" : "powiadom przez emaila",
@@ -122,9 +123,10 @@
"Share" : "Udostępnij",
"Share with users or groups …" : "Współdziel z użytkownikami lub grupami",
"Warning" : "Ostrzeżenie",
+ "Delete" : "Usuń",
+ "Rename" : "Zmień nazwę",
"The object type is not specified." : "Nie określono typu obiektu.",
"Enter new" : "Wpisz nowy",
- "Delete" : "Usuń",
"Add" : "Dodaj",
"Edit tags" : "Edytuj tagi",
"Error loading dialog template: {error}" : "Błąd podczas ładowania szablonu dialogu: {error}",
@@ -139,14 +141,6 @@
"Please reload the page." : "Proszę przeładować stronę",
"The update was unsuccessful. " : "Aktualizowanie zakończyło się niepowodzeniem.",
"The update was successful. Redirecting you to ownCloud now." : "Aktualizacji zakończyła się powodzeniem. Przekierowuję do ownCloud.",
- "Couldn't reset password because the token is invalid" : "Nie można zresetować hasła, ponieważ token jest niepoprawny",
- "Couldn't send reset email. Please make sure your username is correct." : "Nie mogę wysłać maila resetującego. Sprawdź czy nazwa użytkownika jest poprawna.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nie mogę wysłać maila resetującego. Sprawdź czy nazwa użytkownika lub adres email jest poprawny. Skontaktuj się z administratorem.",
- "%s password reset" : "%s reset hasła",
- "Use the following link to reset your password: {link}" : "Użyj tego odnośnika by zresetować hasło: {link}",
- "New password" : "Nowe hasło",
- "New Password" : "Nowe hasło",
- "Reset password" : "Zresetuj hasło",
"Searching other places" : "Przeszukaj inne miejsca",
"Personal" : "Osobiste",
"Users" : "Użytkownicy",
@@ -204,6 +198,10 @@
"Please try again or contact your administrator." : "Spróbuj ponownie lub skontaktuj się z administratorem.",
"Log in" : "Zaloguj",
"Alternative Logins" : "Alternatywne loginy",
+ "Use the following link to reset your password: {link}" : "Użyj tego odnośnika by zresetować hasło: {link}",
+ "New password" : "Nowe hasło",
+ "New Password" : "Nowe hasło",
+ "Reset password" : "Zresetuj hasło",
"This ownCloud instance is currently in single user mode." : "Ta instalacja ownCloud działa obecnie w trybie pojedynczego użytkownika.",
"This means only administrators can use the instance." : "To oznacza, że tylko administratorzy mogą w tej chwili używać aplikacji.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Skontaktuj się z administratorem, jeśli ten komunikat pojawił się nieoczekiwanie lub wyświetla się ciągle.",
diff --git a/core/l10n/pt_BR.js b/core/l10n/pt_BR.js
index 4c5528163ec..3d4e236bac2 100644
--- a/core/l10n/pt_BR.js
+++ b/core/l10n/pt_BR.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Atualizado \"%s\" para %s",
"Repair warning: " : "Aviso de reparação:",
"Repair error: " : "Reparação de erro:",
- "Set log level to debug - current level: \"%s\"" : "Configure o nível de log para debug - nível corrente: \"%s\"",
- "Reset log level to \"%s\"" : "Reconfigurar o nível de log para \"%s\"",
+ "Set log level to debug" : "Definir o nível de log para debug",
+ "Reset log level" : "Redefinição do nível do log",
+ "Starting code integrity check" : "Inicializando verificação da integridade do código",
+ "Finished code integrity check" : "Finalizada a verificação de integridade do código",
"%s (3rdparty)" : "%s (3ºterceiros)",
"%s (incompatible)" : "%s (incompatível)",
"Following apps have been disabled: %s" : "Os seguintes aplicativos foram desabilitados: %s",
"Already up to date" : "Já está atualizado",
+ "Please select a file." : "Por favor selecione um arquivo.",
"File is too big" : "O arquivo é muito grande",
"Invalid file provided" : "Arquivo fornecido inválido",
"No image or file provided" : "Nenhuma imagem ou arquivo fornecido",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "Nenhum dado para coleta foi fornecido",
"No valid crop data provided" : "Nenhum dado recortado válido",
"Crop is not square" : "Recorte não é quadrado",
+ "Couldn't reset password because the token is invalid" : "Não foi possível redefinir a senha porque o token é inválido",
+ "Couldn't reset password because the token is expired" : "Não foi possível redefinir a senha porque o token expirou",
+ "Couldn't send reset email. Please make sure your username is correct." : "Não foi possível enviar e-mail de redefinição. Verifique se o seu nome de usuário está correto.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Não foi possível enviar email de redefinição porque não há nenhum endereço de e-mail para este nome de usuário. Entre em contato com o administrador.",
+ "%s password reset" : "%s redefinir senha",
+ "Couldn't send reset email. Please contact your administrator." : "Não foi possível enviar e-mail de redefinição. Por favor, contate o administrador.",
"Sunday" : "Domingo",
"Monday" : "Segunda-feira",
"Tuesday" : "Terça-feira",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "Out.",
"Nov." : "Nov.",
"Dec." : "Dez.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Houve problemas com a verificação de integridade do código. Mais informações…</a>",
"Settings" : "Configurações",
"Saving..." : "Salvando...",
"seconds ago" : "segundos atrás",
- "Couldn't send reset email. Please contact your administrator." : "Não foi possível enviar e-mail de redefinição. Por favor, contate o administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "O link para redefinir sua senha foi enviada para o seu e-mail. Se você não recebê-lo dentro de um período razoável de tempo, verifique suas pastas de spam/lixo. <br> Se ele não estiver lá, pergunte ao administrador do local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Seus arquivos são criptografados. Se você não ativou a chave de recuperação, não haverá maneira de obter seus dados de volta após a sua senha ser redefinida. <br/> Se você não tem certeza do que fazer, por favor, contate o administrador antes de continuar. <br/> Você realmente deseja continuar?",
"I know what I'm doing" : "Eu sei o que estou fazendo",
@@ -109,23 +118,24 @@ OC.L10N.register(
"Good password" : "Boa senha",
"Strong password" : "Senha forte",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Seu servidor web ainda não está configurado corretamente para permitir a sincronização de arquivos, pois a interface WebDAV parece ser desconfigurada.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "O seu servidor web não está configurado corretamente para resolver \"{url}\". Mais informações podem ser encontradas em nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Este servidor não tem nenhuma conexão com a Internet. Isto significa que algumas das características como a montagem de armazenamento externo, notificações sobre atualizações ou instalação de aplicativos de terceiros não vai funcionar. Acessar arquivos remotamente e envio de e-mails de notificação pode não funcionar, também. Sugerimos permitir conexão com a Internet para este servidor, se você quer ter todas as funcionalidades.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "O seu diretório de dados e os arquivos estão, provavelmente, acessíveis a partir da Internet. O arquivo .htaccess não está funcionando. Nós sugerimos que você configure o servidor web de uma forma que o diretório de dados não seja acessível ou mova o diretório de dados para fora do diretório raiz de documentos do servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nenhum cache de memória foi configurado. Para melhorar o seu desempenho, por favor configurar um cache de memória, se disponível. Mais informações podem ser encontradas em nossa <a href=\"{docLink}\"> documentação </a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom não pode ser lido por PHP o que é altamente desencorajado por razões de segurança. Mais informações podem ser encontradas em nossa <a href=\"{docLink}\">documentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A sua versão do PHP ({version}) não é <a href=\"{phpLink}\">suportada pela PHP</a>. Nós o incentivamos a atualizar sua versão do PHP para tirar proveito de atualizações de desempenho e de segurança fornecidos pela PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "A configuração de cabeçalhos do proxy reverso está incorreta, ou você está acessando ownCloud de um proxy confiável. Se você não está acessando ownCloud de um proxy confiável, esta é uma questão de segurança e pode permitir a um invasor falsificar seu endereço IP como visível para ownCloud. Mais informações podem ser encontradas em nossa <a href=\"{docLink}\">documentação</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached está configurado como cache distribuído, mas o módulo PHP errado \"memcache\" está instalado. \\OC\\Memcache\\Memcached somente suporta \"memcached\" e não \"memcache\". Veja o <a href=\"{wikiLink}\">memcached wiki sobre esse módulo</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Nenhuma memória cache foi configurada. Para melhorar o seu desempenho, por favor configure um cache de memória, se disponível. Mais informação podem ser encontradas em nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom não pode ser lido pelo PHP o que é altamente desencorajado por razões de segurança. Mais informações podem ser encontradas na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A sua versão do PHP ({version}) não é mais <a target=\"_blank\" href=\"{phpLink}\">suportada pelo PHP</a>. Nós o incentivamos a atualizar sua versão do PHP para tirar proveito de atualizações de desempenho e de segurança fornecidas pelo PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "A configuração de cabeçalhos do proxy reverso está incorreta, ou você está acessando ownCloud de um proxy confiável. Se você não está acessando ownCloud de um proxy confiável, esta é uma questão de segurança e pode permitir a um invasor falsificar seu endereço IP como visível para ownCloud. Mais informação pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached está configurado como cache distribuído, mas o módulo PHP \"memcache\" errado está instalado. \\OC\\Memcache\\Memcached suporta apenas \"memcached\" e não \"memcache\". Veja a <a target=\"_blank\" href=\"{wikiLink}\">o wiki sobre memcached sobre ambos os módulos</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Alguns arquivos não passaram na verificação de integridade. Mais informações sobre como resolver este problema podem ser encontradas na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lista de arquivos inválidos…</a> / <a href=\"{rescanEndpoint}\">Reexaminar…</a>)",
"Error occurred while checking server setup" : "Erro ao verificar a configuração do servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "O \"{header}\" cabeçalho HTTP não está configurado igual ao \"{expected}\". Este é um risco potencial para a segurança e recomendamos ajustar essa configuração.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "O cabeçalho \"Transporte-de-Segurança-Restrita\"HTTP não está configurada para menos de \"{seconds}\" segundos. Para uma maior segurança recomendamos a ativação HSTS conforme descrito em nossas <a href=\"{docUrl}\">dicas de segurança</a>.",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Você está acessando este site via HTTP. Nós fortemente sugerimos que você ao invéz, configure o servidor para exigir o uso de HTTPS como descrito em nossas <a href=\"{docUrl}\">dicas de segurança</a>.",
- "Shared" : "Compartilhados",
+ "Shared" : "Compartilhado",
"Shared with {recipients}" : "Compartilhado com {recipients}",
"Error" : "Erro",
"Error while sharing" : "Erro ao compartilhar",
"Error while unsharing" : "Erro ao descompartilhar",
- "Error while changing permissions" : "Erro ao mudar permissões",
"Error setting expiration date" : "Erro ao definir data de expiração",
"The public link will expire no later than {days} days after it is created" : "O link público irá expirar não antes de {days} depois de ser criado",
"Set expiration date" : "Definir data de expiração",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Compartilhado com você e com o grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartilhado com você por {owner}",
- "Shared in {item} with {user}" : "Compartilhado em {item} com {user}",
"group" : "grupo",
"remote" : "remoto",
"notify by email" : "notificar por e-mail",
@@ -155,17 +164,25 @@ OC.L10N.register(
"change" : "mudança",
"delete" : "remover",
"access control" : "controle de acesso",
+ "Could not unshare" : "Não foi possível descompartilhar",
"Share details could not be loaded for this item." : "Detalhes de compartilhamento não puderam ser carregados para este item.",
"An error occured. Please try again" : "Ocorreu um erro. Por favor tente novamente",
"Share" : "Compartilhar",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Compartilhar com usuários em outros ownClouds usando a sintaxe username@example.com/owncloud",
"Share with users or groups …" : "Compartilhar com usuários ou grupos ...",
"Share with users, groups or remote users …" : "Compartilhar com usuários, grupos ou usuários remoto ...",
+ "Error removing share" : "Erro na remoção do compartilhamento",
"Warning" : "Aviso",
"Error while sending notification" : "Erro ao enviar notificação",
+ "Non-existing tag #{tag}" : "Etiqueta não existente #{tag}",
+ "not assignable" : "não atribuível",
+ "invisible" : "invisível",
+ "({scope})" : "({scope})",
+ "Delete" : "Eliminar",
+ "Rename" : "Renomear",
+ "Global tags" : "Etiquetas Globais",
"The object type is not specified." : "O tipo de objeto não foi especificado.",
"Enter new" : "Entrar uma nova",
- "Delete" : "Eliminar",
"Add" : "Adicionar",
"Edit tags" : "Editar etiqueta",
"Error loading dialog template: {error}" : "Erro carregando diálogo de formatação: {error}",
@@ -184,15 +201,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "A atualização não foi bem sucedida.",
"The update was successful. There were warnings." : "A atualização foi bem sucedida. Havia advertências.",
"The update was successful. Redirecting you to ownCloud now." : "A atualização teve êxito. Você será redirecionado ao ownCloud agora.",
- "Couldn't reset password because the token is invalid" : "Não foi possível redefinir a senha porque o token é inválido",
- "Couldn't reset password because the token is expired" : "Não foi possível redefinir a senha porque o token expirou",
- "Couldn't send reset email. Please make sure your username is correct." : "Não foi possível enviar e-mail de redefinição. Verifique se o seu nome de usuário está correto.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Não foi possível enviar e-mail de redefinição, porque não há nenhum endereço de e-mail para este nome de usuário. Por favor, contate o administrador.",
- "%s password reset" : "%s redefinir senha",
- "Use the following link to reset your password: {link}" : "Use o seguinte link para redefinir sua senha: {link}",
- "New password" : "Nova senha",
- "New Password" : "Nova Senha",
- "Reset password" : "Redefinir senha",
"Searching other places" : "Pesquisando em outros lugares",
"No search results in other folders" : "Nenhum resultado de pesquisa em outras pastas",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} resultado da pesquisa em outras pastas","{count} resultados da pesquisa em outras pastas"],
@@ -214,7 +222,7 @@ OC.L10N.register(
"You can click here to return to %s." : "Você pode clicar aqui para retornar para %s.",
"Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\n" : "Olá,\n\ngostaria que você soubesse que %s compartilhou %s com você.\nVeja isto: %s\n\n",
"The share will expire on %s." : "O compartilhamento irá expirar em %s.",
- "Cheers!" : "Saúde!",
+ "Cheers!" : "Saudações!",
"Internal Server Error" : "Erro Interno do Servidor",
"The server encountered an internal error and was unable to complete your request." : "O servidor encontrou um erro interno e não conseguiu concluir o seu pedido.",
"Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "Entre em contato com o administrador do servidor se este erro reaparece várias vezes, por favor, inclua os detalhes técnicos abaixo em seu relatório.",
@@ -252,7 +260,7 @@ OC.L10N.register(
"Finishing …" : "Finalizando ...",
"Need help?" : "Precisa de ajuda?",
"See the documentation" : "Veja a documentação",
- "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Olá,<br><br>só para seu conhecimento que %s compartilhou <strong>%s</strong> com você. <br><a href=\"%s\">Verificar!</a><br><br> ",
+ "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Olá,<br><br>só para seu conhecimento que %s compartilhou <strong>%s</strong> com você. <br><a href=\"%s\">Visualize-o!</a><br><br> ",
"This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Esta aplicação requer JavaScript para sua correta operação. Por favor {linkstart}habilite JavaScript{linkend} e recerregue a página.",
"Log out" : "Sair",
"Search" : "Perquisar",
@@ -262,8 +270,13 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Por favor tente novamente ou faça contato com o seu administrador.",
"Log in" : "Entrar",
"Wrong password. Reset it?" : "Senha incorreta. Redefini-la?",
+ "Wrong password." : "Senha errada",
"Stay logged in" : "Permaneça logado",
"Alternative Logins" : "Logins Alternativos",
+ "Use the following link to reset your password: {link}" : "Use o seguinte link para redefinir sua senha: {link}",
+ "New password" : "Nova senha",
+ "New Password" : "Nova Senha",
+ "Reset password" : "Redefinir senha",
"This ownCloud instance is currently in single user mode." : "Nesta instância ownCloud está em modo de usuário único.",
"This means only administrators can use the instance." : "Isso significa que apenas os administradores podem usar esta instância.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte o seu administrador do sistema se esta mensagem persistir ou aparecer inesperadamente.",
diff --git a/core/l10n/pt_BR.json b/core/l10n/pt_BR.json
index 023119c0fb1..f2289975685 100644
--- a/core/l10n/pt_BR.json
+++ b/core/l10n/pt_BR.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "Atualizado \"%s\" para %s",
"Repair warning: " : "Aviso de reparação:",
"Repair error: " : "Reparação de erro:",
- "Set log level to debug - current level: \"%s\"" : "Configure o nível de log para debug - nível corrente: \"%s\"",
- "Reset log level to \"%s\"" : "Reconfigurar o nível de log para \"%s\"",
+ "Set log level to debug" : "Definir o nível de log para debug",
+ "Reset log level" : "Redefinição do nível do log",
+ "Starting code integrity check" : "Inicializando verificação da integridade do código",
+ "Finished code integrity check" : "Finalizada a verificação de integridade do código",
"%s (3rdparty)" : "%s (3ºterceiros)",
"%s (incompatible)" : "%s (incompatível)",
"Following apps have been disabled: %s" : "Os seguintes aplicativos foram desabilitados: %s",
"Already up to date" : "Já está atualizado",
+ "Please select a file." : "Por favor selecione um arquivo.",
"File is too big" : "O arquivo é muito grande",
"Invalid file provided" : "Arquivo fornecido inválido",
"No image or file provided" : "Nenhuma imagem ou arquivo fornecido",
@@ -30,6 +33,12 @@
"No crop data provided" : "Nenhum dado para coleta foi fornecido",
"No valid crop data provided" : "Nenhum dado recortado válido",
"Crop is not square" : "Recorte não é quadrado",
+ "Couldn't reset password because the token is invalid" : "Não foi possível redefinir a senha porque o token é inválido",
+ "Couldn't reset password because the token is expired" : "Não foi possível redefinir a senha porque o token expirou",
+ "Couldn't send reset email. Please make sure your username is correct." : "Não foi possível enviar e-mail de redefinição. Verifique se o seu nome de usuário está correto.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Não foi possível enviar email de redefinição porque não há nenhum endereço de e-mail para este nome de usuário. Entre em contato com o administrador.",
+ "%s password reset" : "%s redefinir senha",
+ "Couldn't send reset email. Please contact your administrator." : "Não foi possível enviar e-mail de redefinição. Por favor, contate o administrador.",
"Sunday" : "Domingo",
"Monday" : "Segunda-feira",
"Tuesday" : "Terça-feira",
@@ -75,10 +84,10 @@
"Oct." : "Out.",
"Nov." : "Nov.",
"Dec." : "Dez.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Houve problemas com a verificação de integridade do código. Mais informações…</a>",
"Settings" : "Configurações",
"Saving..." : "Salvando...",
"seconds ago" : "segundos atrás",
- "Couldn't send reset email. Please contact your administrator." : "Não foi possível enviar e-mail de redefinição. Por favor, contate o administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "O link para redefinir sua senha foi enviada para o seu e-mail. Se você não recebê-lo dentro de um período razoável de tempo, verifique suas pastas de spam/lixo. <br> Se ele não estiver lá, pergunte ao administrador do local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Seus arquivos são criptografados. Se você não ativou a chave de recuperação, não haverá maneira de obter seus dados de volta após a sua senha ser redefinida. <br/> Se você não tem certeza do que fazer, por favor, contate o administrador antes de continuar. <br/> Você realmente deseja continuar?",
"I know what I'm doing" : "Eu sei o que estou fazendo",
@@ -107,23 +116,24 @@
"Good password" : "Boa senha",
"Strong password" : "Senha forte",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Seu servidor web ainda não está configurado corretamente para permitir a sincronização de arquivos, pois a interface WebDAV parece ser desconfigurada.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "O seu servidor web não está configurado corretamente para resolver \"{url}\". Mais informações podem ser encontradas em nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Este servidor não tem nenhuma conexão com a Internet. Isto significa que algumas das características como a montagem de armazenamento externo, notificações sobre atualizações ou instalação de aplicativos de terceiros não vai funcionar. Acessar arquivos remotamente e envio de e-mails de notificação pode não funcionar, também. Sugerimos permitir conexão com a Internet para este servidor, se você quer ter todas as funcionalidades.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "O seu diretório de dados e os arquivos estão, provavelmente, acessíveis a partir da Internet. O arquivo .htaccess não está funcionando. Nós sugerimos que você configure o servidor web de uma forma que o diretório de dados não seja acessível ou mova o diretório de dados para fora do diretório raiz de documentos do servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nenhum cache de memória foi configurado. Para melhorar o seu desempenho, por favor configurar um cache de memória, se disponível. Mais informações podem ser encontradas em nossa <a href=\"{docLink}\"> documentação </a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom não pode ser lido por PHP o que é altamente desencorajado por razões de segurança. Mais informações podem ser encontradas em nossa <a href=\"{docLink}\">documentation</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A sua versão do PHP ({version}) não é <a href=\"{phpLink}\">suportada pela PHP</a>. Nós o incentivamos a atualizar sua versão do PHP para tirar proveito de atualizações de desempenho e de segurança fornecidos pela PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "A configuração de cabeçalhos do proxy reverso está incorreta, ou você está acessando ownCloud de um proxy confiável. Se você não está acessando ownCloud de um proxy confiável, esta é uma questão de segurança e pode permitir a um invasor falsificar seu endereço IP como visível para ownCloud. Mais informações podem ser encontradas em nossa <a href=\"{docLink}\">documentação</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached está configurado como cache distribuído, mas o módulo PHP errado \"memcache\" está instalado. \\OC\\Memcache\\Memcached somente suporta \"memcached\" e não \"memcache\". Veja o <a href=\"{wikiLink}\">memcached wiki sobre esse módulo</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Nenhuma memória cache foi configurada. Para melhorar o seu desempenho, por favor configure um cache de memória, se disponível. Mais informação podem ser encontradas em nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom não pode ser lido pelo PHP o que é altamente desencorajado por razões de segurança. Mais informações podem ser encontradas na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A sua versão do PHP ({version}) não é mais <a target=\"_blank\" href=\"{phpLink}\">suportada pelo PHP</a>. Nós o incentivamos a atualizar sua versão do PHP para tirar proveito de atualizações de desempenho e de segurança fornecidas pelo PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "A configuração de cabeçalhos do proxy reverso está incorreta, ou você está acessando ownCloud de um proxy confiável. Se você não está acessando ownCloud de um proxy confiável, esta é uma questão de segurança e pode permitir a um invasor falsificar seu endereço IP como visível para ownCloud. Mais informação pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached está configurado como cache distribuído, mas o módulo PHP \"memcache\" errado está instalado. \\OC\\Memcache\\Memcached suporta apenas \"memcached\" e não \"memcache\". Veja a <a target=\"_blank\" href=\"{wikiLink}\">o wiki sobre memcached sobre ambos os módulos</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Alguns arquivos não passaram na verificação de integridade. Mais informações sobre como resolver este problema podem ser encontradas na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lista de arquivos inválidos…</a> / <a href=\"{rescanEndpoint}\">Reexaminar…</a>)",
"Error occurred while checking server setup" : "Erro ao verificar a configuração do servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "O \"{header}\" cabeçalho HTTP não está configurado igual ao \"{expected}\". Este é um risco potencial para a segurança e recomendamos ajustar essa configuração.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "O cabeçalho \"Transporte-de-Segurança-Restrita\"HTTP não está configurada para menos de \"{seconds}\" segundos. Para uma maior segurança recomendamos a ativação HSTS conforme descrito em nossas <a href=\"{docUrl}\">dicas de segurança</a>.",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Você está acessando este site via HTTP. Nós fortemente sugerimos que você ao invéz, configure o servidor para exigir o uso de HTTPS como descrito em nossas <a href=\"{docUrl}\">dicas de segurança</a>.",
- "Shared" : "Compartilhados",
+ "Shared" : "Compartilhado",
"Shared with {recipients}" : "Compartilhado com {recipients}",
"Error" : "Erro",
"Error while sharing" : "Erro ao compartilhar",
"Error while unsharing" : "Erro ao descompartilhar",
- "Error while changing permissions" : "Erro ao mudar permissões",
"Error setting expiration date" : "Erro ao definir data de expiração",
"The public link will expire no later than {days} days after it is created" : "O link público irá expirar não antes de {days} depois de ser criado",
"Set expiration date" : "Definir data de expiração",
@@ -142,7 +152,6 @@
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Compartilhado com você e com o grupo {group} por {owner}",
"Shared with you by {owner}" : "Compartilhado com você por {owner}",
- "Shared in {item} with {user}" : "Compartilhado em {item} com {user}",
"group" : "grupo",
"remote" : "remoto",
"notify by email" : "notificar por e-mail",
@@ -153,17 +162,25 @@
"change" : "mudança",
"delete" : "remover",
"access control" : "controle de acesso",
+ "Could not unshare" : "Não foi possível descompartilhar",
"Share details could not be loaded for this item." : "Detalhes de compartilhamento não puderam ser carregados para este item.",
"An error occured. Please try again" : "Ocorreu um erro. Por favor tente novamente",
"Share" : "Compartilhar",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Compartilhar com usuários em outros ownClouds usando a sintaxe username@example.com/owncloud",
"Share with users or groups …" : "Compartilhar com usuários ou grupos ...",
"Share with users, groups or remote users …" : "Compartilhar com usuários, grupos ou usuários remoto ...",
+ "Error removing share" : "Erro na remoção do compartilhamento",
"Warning" : "Aviso",
"Error while sending notification" : "Erro ao enviar notificação",
+ "Non-existing tag #{tag}" : "Etiqueta não existente #{tag}",
+ "not assignable" : "não atribuível",
+ "invisible" : "invisível",
+ "({scope})" : "({scope})",
+ "Delete" : "Eliminar",
+ "Rename" : "Renomear",
+ "Global tags" : "Etiquetas Globais",
"The object type is not specified." : "O tipo de objeto não foi especificado.",
"Enter new" : "Entrar uma nova",
- "Delete" : "Eliminar",
"Add" : "Adicionar",
"Edit tags" : "Editar etiqueta",
"Error loading dialog template: {error}" : "Erro carregando diálogo de formatação: {error}",
@@ -182,15 +199,6 @@
"The update was unsuccessful. " : "A atualização não foi bem sucedida.",
"The update was successful. There were warnings." : "A atualização foi bem sucedida. Havia advertências.",
"The update was successful. Redirecting you to ownCloud now." : "A atualização teve êxito. Você será redirecionado ao ownCloud agora.",
- "Couldn't reset password because the token is invalid" : "Não foi possível redefinir a senha porque o token é inválido",
- "Couldn't reset password because the token is expired" : "Não foi possível redefinir a senha porque o token expirou",
- "Couldn't send reset email. Please make sure your username is correct." : "Não foi possível enviar e-mail de redefinição. Verifique se o seu nome de usuário está correto.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Não foi possível enviar e-mail de redefinição, porque não há nenhum endereço de e-mail para este nome de usuário. Por favor, contate o administrador.",
- "%s password reset" : "%s redefinir senha",
- "Use the following link to reset your password: {link}" : "Use o seguinte link para redefinir sua senha: {link}",
- "New password" : "Nova senha",
- "New Password" : "Nova Senha",
- "Reset password" : "Redefinir senha",
"Searching other places" : "Pesquisando em outros lugares",
"No search results in other folders" : "Nenhum resultado de pesquisa em outras pastas",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} resultado da pesquisa em outras pastas","{count} resultados da pesquisa em outras pastas"],
@@ -212,7 +220,7 @@
"You can click here to return to %s." : "Você pode clicar aqui para retornar para %s.",
"Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\n" : "Olá,\n\ngostaria que você soubesse que %s compartilhou %s com você.\nVeja isto: %s\n\n",
"The share will expire on %s." : "O compartilhamento irá expirar em %s.",
- "Cheers!" : "Saúde!",
+ "Cheers!" : "Saudações!",
"Internal Server Error" : "Erro Interno do Servidor",
"The server encountered an internal error and was unable to complete your request." : "O servidor encontrou um erro interno e não conseguiu concluir o seu pedido.",
"Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "Entre em contato com o administrador do servidor se este erro reaparece várias vezes, por favor, inclua os detalhes técnicos abaixo em seu relatório.",
@@ -250,7 +258,7 @@
"Finishing …" : "Finalizando ...",
"Need help?" : "Precisa de ajuda?",
"See the documentation" : "Veja a documentação",
- "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Olá,<br><br>só para seu conhecimento que %s compartilhou <strong>%s</strong> com você. <br><a href=\"%s\">Verificar!</a><br><br> ",
+ "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Olá,<br><br>só para seu conhecimento que %s compartilhou <strong>%s</strong> com você. <br><a href=\"%s\">Visualize-o!</a><br><br> ",
"This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Esta aplicação requer JavaScript para sua correta operação. Por favor {linkstart}habilite JavaScript{linkend} e recerregue a página.",
"Log out" : "Sair",
"Search" : "Perquisar",
@@ -260,8 +268,13 @@
"Please try again or contact your administrator." : "Por favor tente novamente ou faça contato com o seu administrador.",
"Log in" : "Entrar",
"Wrong password. Reset it?" : "Senha incorreta. Redefini-la?",
+ "Wrong password." : "Senha errada",
"Stay logged in" : "Permaneça logado",
"Alternative Logins" : "Logins Alternativos",
+ "Use the following link to reset your password: {link}" : "Use o seguinte link para redefinir sua senha: {link}",
+ "New password" : "Nova senha",
+ "New Password" : "Nova Senha",
+ "Reset password" : "Redefinir senha",
"This ownCloud instance is currently in single user mode." : "Nesta instância ownCloud está em modo de usuário único.",
"This means only administrators can use the instance." : "Isso significa que apenas os administradores podem usar esta instância.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte o seu administrador do sistema se esta mensagem persistir ou aparecer inesperadamente.",
diff --git a/core/l10n/pt_PT.js b/core/l10n/pt_PT.js
index 53b9ab0bf77..653ec6ec8b5 100644
--- a/core/l10n/pt_PT.js
+++ b/core/l10n/pt_PT.js
@@ -6,18 +6,25 @@ OC.L10N.register(
"Turned on maintenance mode" : "Ativado o modo de manutenção",
"Turned off maintenance mode" : "Desativado o modo de manutenção",
"Maintenance mode is kept active" : "O modo de manutenção é mantido ativo",
+ "Updating database schema" : "A actualizar o esquema da base de dados",
"Updated database" : "Base de dados atualizada",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "A verificar se o esquema da base de dados pode ser atualizado (isto pode demorar algum tempo dependendo do tamanho da base de dados)",
"Checked database schema update" : "Atualização do esquema da base de dados verificada.",
"Checking updates of apps" : "A procurar por atualizações das apps",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "A verificar se o esquema da base de dados para %s pode ser atualizado (isto pode demorar algum tempo dependendo do tamanho da base de dados)",
"Checked database schema update for apps" : "Atualização do esquema da base de dados verificada.",
"Updated \"%s\" to %s" : "Atualizado \"%s\" para %s",
"Repair warning: " : "Aviso de reparação:",
"Repair error: " : "Corrija o erro:",
- "Reset log level to \"%s\"" : "Reiniciar o nível de registo para \"%s\"",
+ "Set log level to debug" : "Definir o nível de log para debug",
+ "Reset log level" : "Reiniciar nível de registo",
+ "Starting code integrity check" : "A iniciar verificação de integridade do código",
+ "Finished code integrity check" : "Terminada a verificação de integridade do código",
"%s (3rdparty)" : "%s (terceiros)",
"%s (incompatible)" : "%s (incompatível)",
"Following apps have been disabled: %s" : "As seguintes apps foram desativadas: %s",
"Already up to date" : "Já está atualizado",
+ "Please select a file." : "Por favor, selecione um ficheiro.",
"File is too big" : "O ficheiro é muito grande",
"Invalid file provided" : "Ficheiro indicado inválido",
"No image or file provided" : "Não foi fornecido nenhum ficheiro ou imagem",
@@ -28,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "Não foram fornecidos dados de recorte",
"No valid crop data provided" : "Não foram indicados dados de recorte válidos",
"Crop is not square" : "O recorte não é quadrado",
+ "Couldn't reset password because the token is invalid" : "Não foi possível repor a palavra-passe porque a senha é inválida",
+ "Couldn't reset password because the token is expired" : "Não foi possível repor a palavra-passe porque a senha expirou",
+ "Couldn't send reset email. Please make sure your username is correct." : "Ocorreu um problema com o envio do e-mail, por favor confirme o seu utilizador.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Não foi possível enviar o email de reposição porque não existe nenhum email associado a este utilizador. Por favor contacte o administrador.",
+ "%s password reset" : "%s reposição da palavra-passe",
+ "Couldn't send reset email. Please contact your administrator." : "Não foi possível enviar o e-mail de reposição. Por favor, contacte o administrador.",
"Sunday" : "Domingo",
"Monday" : "Segunda",
"Tuesday" : "Terça",
@@ -73,10 +86,10 @@ OC.L10N.register(
"Oct." : "Out.",
"Nov." : "Nov.",
"Dec." : "Dez.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Existiram alguns problemas com a verificação de integridade do código. Mais informação…</a>",
"Settings" : "Definições",
"Saving..." : "A guardar ...",
"seconds ago" : "segundos atrás",
- "Couldn't send reset email. Please contact your administrator." : "Não foi possível enviar o e-mail de reposição. Por favor, contacte o administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "A hiperligação para reiniciar a sua senha foi enviada para o seu correio eletrónico. Se não a receber dentro de um tempo aceitável, verifique as suas pastas de span/lixo.<br> Se não a encontrar, pergunte ao seu administrador local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Os seus ficheiros estão encriptados. Se não ativou a chave de recuperação, não terá nenhum modo para voltar obter os seus dados depois de reiniciar a sua senha. <br />Se não tem a certeza do que fazer, por favor, contacte o seu administrador antes de continuar.<br /> Tem a certeza que quer continuar?",
"I know what I'm doing" : "Eu sei o que eu estou a fazer",
@@ -105,20 +118,24 @@ OC.L10N.register(
"Good password" : "Palavra-passe boa",
"Strong password" : "Palavra-passe forte",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "O seu servidor da Web não está configurado corretamente para permitir a sincronização de ficheiro, porque a interface WebDAV parece estar com problemas.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "O seu servidor web não está configurado corretamente para resolver \"{url}\". Mais informação pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Este servidor ownCloud não tem uma ligação de Internet a funcionar. Isto significa que algumas funcionalidades como o acesso a locais externos, notificações sobre actualizações, ou a instalação de aplicações de terceiros não irá funcionar. Aceder aos ficheiros remotamente e enviar notificações de email poderão não funcionar também. Sugerimos que active uma ligação à Internet se pretende obter todas as funcionalidades do ownCloud.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "A sua pasta com os dados e os seus ficheiros estão provavelmente acessíveis a partir das internet. O seu ficheiro .htaccess não está a funcionar corretamente. Sugerimos veementemente que configure o seu servidor web de maneira a que a pasta com os dados deixe de ficar acessível, ou mova a pasta com os dados para fora da raiz de documentos do servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nenhuma memória de cache foi configurada. Se possível configure-a de forma a optimizar o desempenho. Mais informações podem ser encontradas na <a href=\"{docLink}\">documentação</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom não é legível pelo PHP, o que é altamente desanimador por motivos de segurança. Pode ser encontrada mais informação na <a href=\"{docLink}\">documentação</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A sua versão ({version}) do PHP já não é <a href=\"{phpLink}\">suportada pelo PHP</a>. Nós encorajamos-lo a atualizar a sua versão do PHP para aproveitar o desempenho e as atualizações de segurança fornecidas pelo PHP.´«",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Nenhuma memória cache foi configurada. Para melhorar o seu desempenho, por favor configure a memcache, se disponível. Mais informação pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom não é legível pelo PHP, o que é altamente desanimador por motivos de segurança. Pode ser encontrada mais informação na <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A sua versão ({version}) do PHP já não é <a target=\"_blank\" href=\"{phpLink}\">suportada pelo PHP</a>. Nós encorajamos-lhe a atualizar a sua versão do PHP para aproveitar o desempenho e as atualizações de segurança fornecidas pelo PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "A configuração dos proxy headers reversos está incorreta, ou então está a aceder ao ownCloud através de um proxy de confiança. Se não está a aceder ao ownCloud através de um proxy de confiança, isto é um problema de segurança e poderá permitir a um invasor falsificar o seu endereço IP como visível para o ownCloud. Mais informação pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached está configurada como cache distribuída, mas o módulo \"memcache\" PHP errado está instalado. \\OC\\Memcache\\Memcached apenas suporta \"memcached\" e não \"memcache\". Leia a <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki sobre ambos os módulos</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Alguns ficheiros não passaram na verificação de integridade. Mais informação sobre este assunto pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lists de ficheiros inválidos…</a> / <a href=\"{rescanEndpoint}\">Reverificar…</a>)",
"Error occurred while checking server setup" : "Ocorreu um erro durante a verificação da configuração do servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "O cabeçalho HTTP \"{header}\" não está configurado para igualar \"{expected}\". Isto é um potencial risco de segurança ou privacidade e recomendamos que o corrija.",
+ "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "O cabeçalho HTTP \"Strict-Transport-Security\" não está configurado para um mínimo de \"{seconds}\" segundos. Para uma segurança melhorada recomendados a ativação do HSTS como descrito nas nossas <a href=\"{docUrl}\">dicas de segurança</a>.",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Está a aceder a este site via HTTP. Nós recomendamos vivamente que configure o seu servidor para requerer a utilização de HTTPS, em vez do que está descrito nas nossas <a href=\"{docUrl}\">dicas de segurança</a>.",
"Shared" : "Partilhado",
"Shared with {recipients}" : "Partilhado com {recipients}",
"Error" : "Erro",
"Error while sharing" : "Erro ao partilhar",
"Error while unsharing" : "Erro ao remover a partilha",
- "Error while changing permissions" : "Erro ao mudar permissões",
"Error setting expiration date" : "Erro ao aplicar a data de expiração",
"The public link will expire no later than {days} days after it is created" : "O link público expira, o mais tardar {days} dias após sua criação",
"Set expiration date" : "Definir a data de expiração",
@@ -137,7 +154,6 @@ OC.L10N.register(
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Partilhado consigo e com o grupo {group} por {owner}",
"Shared with you by {owner}" : "Partilhado consigo por {owner}",
- "Shared in {item} with {user}" : "Partilhado em {item} com {user}",
"group" : "grupo",
"remote" : "remoto",
"notify by email" : "Notificar por correio eletrónico",
@@ -148,17 +164,25 @@ OC.L10N.register(
"change" : "alterar",
"delete" : "apagar",
"access control" : "controlo de acesso",
+ "Could not unshare" : "Não foi possível cancelar a partilha",
"Share details could not be loaded for this item." : "Não foi possível carregar os detalhes de partilha para este item.",
"An error occured. Please try again" : "Ocorreu um erro. Por favor, tente de novo",
"Share" : "Compartilhar",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Compartilhe com as pessoas nas outras ownClouds utilizando a sintaxe username@example.com/owncloud",
"Share with users or groups …" : "Partilhar com utilizadores ou grupos...",
"Share with users, groups or remote users …" : "Partilhar com utilizadores, grupos ou utilizadores remotos...",
+ "Error removing share" : "Erro ao remover partilha",
"Warning" : "Aviso",
"Error while sending notification" : "Erro enquanto estava a enviar a notificação",
+ "Non-existing tag #{tag}" : "Etiqueta não existente #{tag}",
+ "not assignable" : "não atribuível",
+ "invisible" : "invisível",
+ "({scope})" : "({scope})",
+ "Delete" : "Apagar",
+ "Rename" : "Renomear",
+ "Global tags" : "Etiquetas gerais",
"The object type is not specified." : "O tipo de objeto não está especificado.",
"Enter new" : "Introduza novo",
- "Delete" : "Apagar",
"Add" : "Adicionar",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Ocorreu um erro ao carregar o modelo de janela: {error}",
@@ -170,23 +194,16 @@ OC.L10N.register(
"Hello {name}" : "Olá {name}",
"_download %n file_::_download %n files_" : ["transferir %n ficheiro","transferir %n ficheiros"],
"{version} is available. Get more information on how to update." : "{version} está disponível. Obtenha mais informação sobre como atualizar.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "A atualização está em curso. Deixar esta página agora poderá interromper o processo nalguns ambientes.",
"Updating {productName} to version {version}, this may take a while." : "A atualizar {productName} para a versão {version}, isto poderá demorar algum tempo.",
"An error occurred." : "Ocorreu um erro.",
"Please reload the page." : "Por favor, recarregue a página.",
"The update was unsuccessful. " : "Não foi possível atualizar.",
"The update was successful. There were warnings." : "A atualização foi bem sucedida. Tem alguns avisos.",
"The update was successful. Redirecting you to ownCloud now." : "A actualização foi concluída com sucesso. Vai ser redireccionado para o ownCloud agora.",
- "Couldn't reset password because the token is invalid" : "Não foi possível repor a palavra-passe porque a senha é inválida",
- "Couldn't reset password because the token is expired" : "Não foi possível repor a palavra-passe porque a senha expirou",
- "Couldn't send reset email. Please make sure your username is correct." : "Ocorreu um problema com o envio do e-mail, por favor confirme o seu utilizador.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Ocorreu um problema com o envio do e-mail, por favor contacte o administrador.",
- "%s password reset" : "%s reposição da palavra-passe",
- "Use the following link to reset your password: {link}" : "Utilize a seguinte hiperligação para repor a sua palavra-passe: {link}",
- "New password" : "Nova palavra-chave",
- "New Password" : "Nova palavra-passe",
- "Reset password" : "Repor palavra-passe",
"Searching other places" : "A pesquisar noutros lugares",
"No search results in other folders" : "Sem resultados de procura nas outras pastas",
+ "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} resultado de pesquisa noutra pasta","{count} resultados de pesquisa noutras pastas"],
"Personal" : "Pessoal",
"Users" : "Utilizadores",
"Apps" : "Apps",
@@ -253,13 +270,19 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Por favor tente de novo ou contacte o administrador.",
"Log in" : "Iniciar Sessão",
"Wrong password. Reset it?" : "Senha errada. Repô-la?",
+ "Wrong password." : "Palavra-passe errada.",
"Stay logged in" : "Manter sessão iniciada",
"Alternative Logins" : "Contas de acesso alternativas",
+ "Use the following link to reset your password: {link}" : "Utilize a seguinte hiperligação para repor a sua palavra-passe: {link}",
+ "New password" : "Nova palavra-chave",
+ "New Password" : "Nova palavra-passe",
+ "Reset password" : "Repor palavra-passe",
"This ownCloud instance is currently in single user mode." : "Esta instância do ownCloud está actualmente configurada no modo de utilizador único.",
"This means only administrators can use the instance." : "Isto significa que apenas os administradores podem usar a instância.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte o seu administrador de sistema se esta mensagem continuar a aparecer ou apareceu inesperadamente.",
"Thank you for your patience." : "Obrigado pela sua paciência.",
"You are accessing the server from an untrusted domain." : "Está a aceder ao servidor a partir de um domínio que não é de confiança.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Por favor contacte o seu administrador. Se é um administrador desta instância, configure as definições \"trusted_domains\" em config/config.php. Um exemplo de configuração é fornecido em config/config.sample.php.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Dependendo da configuração, como administrador, você também pode ser capaz de usar o botão abaixo para confiar neste domínio.",
"Add \"%s\" as trusted domain" : "Adicionar \"%s\" como um domínio de confiança",
"App update required" : "É necessário atualizar a app",
diff --git a/core/l10n/pt_PT.json b/core/l10n/pt_PT.json
index 8b7d483f270..af02e2bf081 100644
--- a/core/l10n/pt_PT.json
+++ b/core/l10n/pt_PT.json
@@ -4,18 +4,25 @@
"Turned on maintenance mode" : "Ativado o modo de manutenção",
"Turned off maintenance mode" : "Desativado o modo de manutenção",
"Maintenance mode is kept active" : "O modo de manutenção é mantido ativo",
+ "Updating database schema" : "A actualizar o esquema da base de dados",
"Updated database" : "Base de dados atualizada",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "A verificar se o esquema da base de dados pode ser atualizado (isto pode demorar algum tempo dependendo do tamanho da base de dados)",
"Checked database schema update" : "Atualização do esquema da base de dados verificada.",
"Checking updates of apps" : "A procurar por atualizações das apps",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "A verificar se o esquema da base de dados para %s pode ser atualizado (isto pode demorar algum tempo dependendo do tamanho da base de dados)",
"Checked database schema update for apps" : "Atualização do esquema da base de dados verificada.",
"Updated \"%s\" to %s" : "Atualizado \"%s\" para %s",
"Repair warning: " : "Aviso de reparação:",
"Repair error: " : "Corrija o erro:",
- "Reset log level to \"%s\"" : "Reiniciar o nível de registo para \"%s\"",
+ "Set log level to debug" : "Definir o nível de log para debug",
+ "Reset log level" : "Reiniciar nível de registo",
+ "Starting code integrity check" : "A iniciar verificação de integridade do código",
+ "Finished code integrity check" : "Terminada a verificação de integridade do código",
"%s (3rdparty)" : "%s (terceiros)",
"%s (incompatible)" : "%s (incompatível)",
"Following apps have been disabled: %s" : "As seguintes apps foram desativadas: %s",
"Already up to date" : "Já está atualizado",
+ "Please select a file." : "Por favor, selecione um ficheiro.",
"File is too big" : "O ficheiro é muito grande",
"Invalid file provided" : "Ficheiro indicado inválido",
"No image or file provided" : "Não foi fornecido nenhum ficheiro ou imagem",
@@ -26,6 +33,12 @@
"No crop data provided" : "Não foram fornecidos dados de recorte",
"No valid crop data provided" : "Não foram indicados dados de recorte válidos",
"Crop is not square" : "O recorte não é quadrado",
+ "Couldn't reset password because the token is invalid" : "Não foi possível repor a palavra-passe porque a senha é inválida",
+ "Couldn't reset password because the token is expired" : "Não foi possível repor a palavra-passe porque a senha expirou",
+ "Couldn't send reset email. Please make sure your username is correct." : "Ocorreu um problema com o envio do e-mail, por favor confirme o seu utilizador.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Não foi possível enviar o email de reposição porque não existe nenhum email associado a este utilizador. Por favor contacte o administrador.",
+ "%s password reset" : "%s reposição da palavra-passe",
+ "Couldn't send reset email. Please contact your administrator." : "Não foi possível enviar o e-mail de reposição. Por favor, contacte o administrador.",
"Sunday" : "Domingo",
"Monday" : "Segunda",
"Tuesday" : "Terça",
@@ -71,10 +84,10 @@
"Oct." : "Out.",
"Nov." : "Nov.",
"Dec." : "Dez.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Existiram alguns problemas com a verificação de integridade do código. Mais informação…</a>",
"Settings" : "Definições",
"Saving..." : "A guardar ...",
"seconds ago" : "segundos atrás",
- "Couldn't send reset email. Please contact your administrator." : "Não foi possível enviar o e-mail de reposição. Por favor, contacte o administrador.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "A hiperligação para reiniciar a sua senha foi enviada para o seu correio eletrónico. Se não a receber dentro de um tempo aceitável, verifique as suas pastas de span/lixo.<br> Se não a encontrar, pergunte ao seu administrador local.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Os seus ficheiros estão encriptados. Se não ativou a chave de recuperação, não terá nenhum modo para voltar obter os seus dados depois de reiniciar a sua senha. <br />Se não tem a certeza do que fazer, por favor, contacte o seu administrador antes de continuar.<br /> Tem a certeza que quer continuar?",
"I know what I'm doing" : "Eu sei o que eu estou a fazer",
@@ -103,20 +116,24 @@
"Good password" : "Palavra-passe boa",
"Strong password" : "Palavra-passe forte",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "O seu servidor da Web não está configurado corretamente para permitir a sincronização de ficheiro, porque a interface WebDAV parece estar com problemas.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "O seu servidor web não está configurado corretamente para resolver \"{url}\". Mais informação pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Este servidor ownCloud não tem uma ligação de Internet a funcionar. Isto significa que algumas funcionalidades como o acesso a locais externos, notificações sobre actualizações, ou a instalação de aplicações de terceiros não irá funcionar. Aceder aos ficheiros remotamente e enviar notificações de email poderão não funcionar também. Sugerimos que active uma ligação à Internet se pretende obter todas as funcionalidades do ownCloud.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "A sua pasta com os dados e os seus ficheiros estão provavelmente acessíveis a partir das internet. O seu ficheiro .htaccess não está a funcionar corretamente. Sugerimos veementemente que configure o seu servidor web de maneira a que a pasta com os dados deixe de ficar acessível, ou mova a pasta com os dados para fora da raiz de documentos do servidor web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nenhuma memória de cache foi configurada. Se possível configure-a de forma a optimizar o desempenho. Mais informações podem ser encontradas na <a href=\"{docLink}\">documentação</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom não é legível pelo PHP, o que é altamente desanimador por motivos de segurança. Pode ser encontrada mais informação na <a href=\"{docLink}\">documentação</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A sua versão ({version}) do PHP já não é <a href=\"{phpLink}\">suportada pelo PHP</a>. Nós encorajamos-lo a atualizar a sua versão do PHP para aproveitar o desempenho e as atualizações de segurança fornecidas pelo PHP.´«",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Nenhuma memória cache foi configurada. Para melhorar o seu desempenho, por favor configure a memcache, se disponível. Mais informação pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom não é legível pelo PHP, o que é altamente desanimador por motivos de segurança. Pode ser encontrada mais informação na <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "A sua versão ({version}) do PHP já não é <a target=\"_blank\" href=\"{phpLink}\">suportada pelo PHP</a>. Nós encorajamos-lhe a atualizar a sua versão do PHP para aproveitar o desempenho e as atualizações de segurança fornecidas pelo PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "A configuração dos proxy headers reversos está incorreta, ou então está a aceder ao ownCloud através de um proxy de confiança. Se não está a aceder ao ownCloud através de um proxy de confiança, isto é um problema de segurança e poderá permitir a um invasor falsificar o seu endereço IP como visível para o ownCloud. Mais informação pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached está configurada como cache distribuída, mas o módulo \"memcache\" PHP errado está instalado. \\OC\\Memcache\\Memcached apenas suporta \"memcached\" e não \"memcache\". Leia a <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki sobre ambos os módulos</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Alguns ficheiros não passaram na verificação de integridade. Mais informação sobre este assunto pode ser encontrada na nossa <a target=\"_blank\" href=\"{docLink}\">documentação</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Lists de ficheiros inválidos…</a> / <a href=\"{rescanEndpoint}\">Reverificar…</a>)",
"Error occurred while checking server setup" : "Ocorreu um erro durante a verificação da configuração do servidor",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "O cabeçalho HTTP \"{header}\" não está configurado para igualar \"{expected}\". Isto é um potencial risco de segurança ou privacidade e recomendamos que o corrija.",
+ "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "O cabeçalho HTTP \"Strict-Transport-Security\" não está configurado para um mínimo de \"{seconds}\" segundos. Para uma segurança melhorada recomendados a ativação do HSTS como descrito nas nossas <a href=\"{docUrl}\">dicas de segurança</a>.",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Está a aceder a este site via HTTP. Nós recomendamos vivamente que configure o seu servidor para requerer a utilização de HTTPS, em vez do que está descrito nas nossas <a href=\"{docUrl}\">dicas de segurança</a>.",
"Shared" : "Partilhado",
"Shared with {recipients}" : "Partilhado com {recipients}",
"Error" : "Erro",
"Error while sharing" : "Erro ao partilhar",
"Error while unsharing" : "Erro ao remover a partilha",
- "Error while changing permissions" : "Erro ao mudar permissões",
"Error setting expiration date" : "Erro ao aplicar a data de expiração",
"The public link will expire no later than {days} days after it is created" : "O link público expira, o mais tardar {days} dias após sua criação",
"Set expiration date" : "Definir a data de expiração",
@@ -135,7 +152,6 @@
"Send" : "Enviar",
"Shared with you and the group {group} by {owner}" : "Partilhado consigo e com o grupo {group} por {owner}",
"Shared with you by {owner}" : "Partilhado consigo por {owner}",
- "Shared in {item} with {user}" : "Partilhado em {item} com {user}",
"group" : "grupo",
"remote" : "remoto",
"notify by email" : "Notificar por correio eletrónico",
@@ -146,17 +162,25 @@
"change" : "alterar",
"delete" : "apagar",
"access control" : "controlo de acesso",
+ "Could not unshare" : "Não foi possível cancelar a partilha",
"Share details could not be loaded for this item." : "Não foi possível carregar os detalhes de partilha para este item.",
"An error occured. Please try again" : "Ocorreu um erro. Por favor, tente de novo",
"Share" : "Compartilhar",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Compartilhe com as pessoas nas outras ownClouds utilizando a sintaxe username@example.com/owncloud",
"Share with users or groups …" : "Partilhar com utilizadores ou grupos...",
"Share with users, groups or remote users …" : "Partilhar com utilizadores, grupos ou utilizadores remotos...",
+ "Error removing share" : "Erro ao remover partilha",
"Warning" : "Aviso",
"Error while sending notification" : "Erro enquanto estava a enviar a notificação",
+ "Non-existing tag #{tag}" : "Etiqueta não existente #{tag}",
+ "not assignable" : "não atribuível",
+ "invisible" : "invisível",
+ "({scope})" : "({scope})",
+ "Delete" : "Apagar",
+ "Rename" : "Renomear",
+ "Global tags" : "Etiquetas gerais",
"The object type is not specified." : "O tipo de objeto não está especificado.",
"Enter new" : "Introduza novo",
- "Delete" : "Apagar",
"Add" : "Adicionar",
"Edit tags" : "Editar etiquetas",
"Error loading dialog template: {error}" : "Ocorreu um erro ao carregar o modelo de janela: {error}",
@@ -168,23 +192,16 @@
"Hello {name}" : "Olá {name}",
"_download %n file_::_download %n files_" : ["transferir %n ficheiro","transferir %n ficheiros"],
"{version} is available. Get more information on how to update." : "{version} está disponível. Obtenha mais informação sobre como atualizar.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "A atualização está em curso. Deixar esta página agora poderá interromper o processo nalguns ambientes.",
"Updating {productName} to version {version}, this may take a while." : "A atualizar {productName} para a versão {version}, isto poderá demorar algum tempo.",
"An error occurred." : "Ocorreu um erro.",
"Please reload the page." : "Por favor, recarregue a página.",
"The update was unsuccessful. " : "Não foi possível atualizar.",
"The update was successful. There were warnings." : "A atualização foi bem sucedida. Tem alguns avisos.",
"The update was successful. Redirecting you to ownCloud now." : "A actualização foi concluída com sucesso. Vai ser redireccionado para o ownCloud agora.",
- "Couldn't reset password because the token is invalid" : "Não foi possível repor a palavra-passe porque a senha é inválida",
- "Couldn't reset password because the token is expired" : "Não foi possível repor a palavra-passe porque a senha expirou",
- "Couldn't send reset email. Please make sure your username is correct." : "Ocorreu um problema com o envio do e-mail, por favor confirme o seu utilizador.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Ocorreu um problema com o envio do e-mail, por favor contacte o administrador.",
- "%s password reset" : "%s reposição da palavra-passe",
- "Use the following link to reset your password: {link}" : "Utilize a seguinte hiperligação para repor a sua palavra-passe: {link}",
- "New password" : "Nova palavra-chave",
- "New Password" : "Nova palavra-passe",
- "Reset password" : "Repor palavra-passe",
"Searching other places" : "A pesquisar noutros lugares",
"No search results in other folders" : "Sem resultados de procura nas outras pastas",
+ "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} resultado de pesquisa noutra pasta","{count} resultados de pesquisa noutras pastas"],
"Personal" : "Pessoal",
"Users" : "Utilizadores",
"Apps" : "Apps",
@@ -251,13 +268,19 @@
"Please try again or contact your administrator." : "Por favor tente de novo ou contacte o administrador.",
"Log in" : "Iniciar Sessão",
"Wrong password. Reset it?" : "Senha errada. Repô-la?",
+ "Wrong password." : "Palavra-passe errada.",
"Stay logged in" : "Manter sessão iniciada",
"Alternative Logins" : "Contas de acesso alternativas",
+ "Use the following link to reset your password: {link}" : "Utilize a seguinte hiperligação para repor a sua palavra-passe: {link}",
+ "New password" : "Nova palavra-chave",
+ "New Password" : "Nova palavra-passe",
+ "Reset password" : "Repor palavra-passe",
"This ownCloud instance is currently in single user mode." : "Esta instância do ownCloud está actualmente configurada no modo de utilizador único.",
"This means only administrators can use the instance." : "Isto significa que apenas os administradores podem usar a instância.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Contacte o seu administrador de sistema se esta mensagem continuar a aparecer ou apareceu inesperadamente.",
"Thank you for your patience." : "Obrigado pela sua paciência.",
"You are accessing the server from an untrusted domain." : "Está a aceder ao servidor a partir de um domínio que não é de confiança.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Por favor contacte o seu administrador. Se é um administrador desta instância, configure as definições \"trusted_domains\" em config/config.php. Um exemplo de configuração é fornecido em config/config.sample.php.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Dependendo da configuração, como administrador, você também pode ser capaz de usar o botão abaixo para confiar neste domínio.",
"Add \"%s\" as trusted domain" : "Adicionar \"%s\" como um domínio de confiança",
"App update required" : "É necessário atualizar a app",
diff --git a/core/l10n/ro.js b/core/l10n/ro.js
index ac56a921da3..5089ce061be 100644
--- a/core/l10n/ro.js
+++ b/core/l10n/ro.js
@@ -11,6 +11,8 @@ OC.L10N.register(
"No image or file provided" : "Nu a fost furnizat vreo imagine sau fișier",
"Unknown filetype" : "Tip fișier necunoscut",
"Invalid image" : "Imagine invalidă",
+ "%s password reset" : "%s resetare parola",
+ "Couldn't send reset email. Please contact your administrator." : "Expedierea email-ului de resetare a eşuat. Vă rugăm să contactaţi administratorul dvs.",
"Sunday" : "Duminică",
"Monday" : "Luni",
"Tuesday" : "Marți",
@@ -52,7 +54,6 @@ OC.L10N.register(
"Settings" : "Setări",
"Saving..." : "Se salvează...",
"seconds ago" : "secunde în urmă",
- "Couldn't send reset email. Please contact your administrator." : "Expedierea email-ului de resetare a eşuat. Vă rugăm să contactaţi administratorul dvs.",
"I know what I'm doing" : "Eu știu ce fac",
"Password can not be changed. Please contact your administrator." : "Parola nu poate fi modificata. Vă rugăm să contactați administratorul dvs.",
"No" : "Nu",
@@ -80,7 +81,6 @@ OC.L10N.register(
"Error" : "Eroare",
"Error while sharing" : "Eroare la partajare",
"Error while unsharing" : "Eroare la anularea partajării",
- "Error while changing permissions" : "Eroare la modificarea permisiunilor",
"Error setting expiration date" : "Eroare la specificarea datei de expirare",
"The public link will expire no later than {days} days after it is created" : "Legătura publică va expira nu mai târziu de {days} zile de la ziua creării",
"Set expiration date" : "Specifică data expirării",
@@ -98,7 +98,6 @@ OC.L10N.register(
"Send" : "Expediază",
"Shared with you and the group {group} by {owner}" : "Distribuie cu tine si grupul {group} de {owner}",
"Shared with you by {owner}" : "Distribuie cu tine de {owner}",
- "Shared in {item} with {user}" : "Distribuie in {item} si {user}",
"group" : "grup",
"notify by email" : "notifică prin email",
"Unshare" : "Anulare partajare",
@@ -110,18 +109,14 @@ OC.L10N.register(
"access control" : "control acces",
"Share" : "Partajează",
"Warning" : "Atenție",
+ "Delete" : "Șterge",
+ "Rename" : "Redenumește",
"The object type is not specified." : "Tipul obiectului nu este specificat.",
"Enter new" : "Introducere nou",
- "Delete" : "Șterge",
"Add" : "Adaugă",
"Updating {productName} to version {version}, this may take a while." : "Se actualizează {productName} la versiunea {version}, poate dura câteva momente.",
"Please reload the page." : "Te rugăm să reîncarci pagina.",
"The update was successful. Redirecting you to ownCloud now." : "Actualizare reușită. Ești redirecționat către ownCloud.",
- "%s password reset" : "%s resetare parola",
- "Use the following link to reset your password: {link}" : "Folosește următorul link pentru a reseta parola: {link}",
- "New password" : "Noua parolă",
- "New Password" : "Noua parolă",
- "Reset password" : "Resetează parola",
"Personal" : "Personal",
"Users" : "Utilizatori",
"Apps" : "Aplicații",
@@ -148,6 +143,10 @@ OC.L10N.register(
"Search" : "Căutare",
"Log in" : "Autentificare",
"Alternative Logins" : "Conectări alternative",
+ "Use the following link to reset your password: {link}" : "Folosește următorul link pentru a reseta parola: {link}",
+ "New password" : "Noua parolă",
+ "New Password" : "Noua parolă",
+ "Reset password" : "Resetează parola",
"Thank you for your patience." : "Îți mulțumim pentru răbrade.",
"Start update" : "Începe actualizarea"
},
diff --git a/core/l10n/ro.json b/core/l10n/ro.json
index 701b991ba98..cdc76824c7e 100644
--- a/core/l10n/ro.json
+++ b/core/l10n/ro.json
@@ -9,6 +9,8 @@
"No image or file provided" : "Nu a fost furnizat vreo imagine sau fișier",
"Unknown filetype" : "Tip fișier necunoscut",
"Invalid image" : "Imagine invalidă",
+ "%s password reset" : "%s resetare parola",
+ "Couldn't send reset email. Please contact your administrator." : "Expedierea email-ului de resetare a eşuat. Vă rugăm să contactaţi administratorul dvs.",
"Sunday" : "Duminică",
"Monday" : "Luni",
"Tuesday" : "Marți",
@@ -50,7 +52,6 @@
"Settings" : "Setări",
"Saving..." : "Se salvează...",
"seconds ago" : "secunde în urmă",
- "Couldn't send reset email. Please contact your administrator." : "Expedierea email-ului de resetare a eşuat. Vă rugăm să contactaţi administratorul dvs.",
"I know what I'm doing" : "Eu știu ce fac",
"Password can not be changed. Please contact your administrator." : "Parola nu poate fi modificata. Vă rugăm să contactați administratorul dvs.",
"No" : "Nu",
@@ -78,7 +79,6 @@
"Error" : "Eroare",
"Error while sharing" : "Eroare la partajare",
"Error while unsharing" : "Eroare la anularea partajării",
- "Error while changing permissions" : "Eroare la modificarea permisiunilor",
"Error setting expiration date" : "Eroare la specificarea datei de expirare",
"The public link will expire no later than {days} days after it is created" : "Legătura publică va expira nu mai târziu de {days} zile de la ziua creării",
"Set expiration date" : "Specifică data expirării",
@@ -96,7 +96,6 @@
"Send" : "Expediază",
"Shared with you and the group {group} by {owner}" : "Distribuie cu tine si grupul {group} de {owner}",
"Shared with you by {owner}" : "Distribuie cu tine de {owner}",
- "Shared in {item} with {user}" : "Distribuie in {item} si {user}",
"group" : "grup",
"notify by email" : "notifică prin email",
"Unshare" : "Anulare partajare",
@@ -108,18 +107,14 @@
"access control" : "control acces",
"Share" : "Partajează",
"Warning" : "Atenție",
+ "Delete" : "Șterge",
+ "Rename" : "Redenumește",
"The object type is not specified." : "Tipul obiectului nu este specificat.",
"Enter new" : "Introducere nou",
- "Delete" : "Șterge",
"Add" : "Adaugă",
"Updating {productName} to version {version}, this may take a while." : "Se actualizează {productName} la versiunea {version}, poate dura câteva momente.",
"Please reload the page." : "Te rugăm să reîncarci pagina.",
"The update was successful. Redirecting you to ownCloud now." : "Actualizare reușită. Ești redirecționat către ownCloud.",
- "%s password reset" : "%s resetare parola",
- "Use the following link to reset your password: {link}" : "Folosește următorul link pentru a reseta parola: {link}",
- "New password" : "Noua parolă",
- "New Password" : "Noua parolă",
- "Reset password" : "Resetează parola",
"Personal" : "Personal",
"Users" : "Utilizatori",
"Apps" : "Aplicații",
@@ -146,6 +141,10 @@
"Search" : "Căutare",
"Log in" : "Autentificare",
"Alternative Logins" : "Conectări alternative",
+ "Use the following link to reset your password: {link}" : "Folosește următorul link pentru a reseta parola: {link}",
+ "New password" : "Noua parolă",
+ "New Password" : "Noua parolă",
+ "Reset password" : "Resetează parola",
"Thank you for your patience." : "Îți mulțumim pentru răbrade.",
"Start update" : "Începe actualizarea"
},"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"
diff --git a/core/l10n/ru.js b/core/l10n/ru.js
index 39302e9a18e..2b942444db1 100644
--- a/core/l10n/ru.js
+++ b/core/l10n/ru.js
@@ -16,13 +16,16 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Обновлено \"%s\" до %s",
"Repair warning: " : "Предупреждение восстановления:",
"Repair error: " : "Ошибка восстановления:",
- "Set log level to debug - current level: \"%s\"" : "Установить отладочное журналирование - текущий уровень: \"%s\"",
- "Reset log level to \"%s\"" : "Сбросить уровень журналирования в \"%s\"",
- "%s (3rdparty)" : "%s (3rdparty)",
+ "Set log level to debug" : "Установить журнал в режим отладки",
+ "Reset log level" : "Сбросить уровень журнала",
+ "Starting code integrity check" : "Начинается проверка целостности кода",
+ "Finished code integrity check" : "Проверка целостности кода завершина",
+ "%s (3rdparty)" : "%s (стороннее)",
"%s (incompatible)" : "%s (несовместим)",
"Following apps have been disabled: %s" : "Были отключены следующие приложения: %s",
"Already up to date" : "Не нуждается в обновлении",
- "File is too big" : "Файл слишком большой",
+ "Please select a file." : "Пожалуйста выберите файл.",
+ "File is too big" : "Файл слишком велик",
"Invalid file provided" : "Указан неправильный файл",
"No image or file provided" : "Не указано изображение или файл",
"Unknown filetype" : "Неизвестный тип файла",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "Не указана информация о кадрировании",
"No valid crop data provided" : "Не указаны корректные данные о кадрировании",
"Crop is not square" : "Кадр не является квадратом",
+ "Couldn't reset password because the token is invalid" : "Не удалось сбросить пароль из-за неверного токена",
+ "Couldn't reset password because the token is expired" : "Не удалось сбросить пароль, так как срок действия токена истек.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Не удалось отправить письмо для сброса пароля. Убедитесь, что имя пользователя указано верно.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Не удалось отправить письмо сброса так как у данного пользователя не задан адрес электронной почты. Пожалуйста, обратитесь к администратору.",
+ "%s password reset" : "Сброс пароля %s",
+ "Couldn't send reset email. Please contact your administrator." : "Не удалось отправить письмо для сброса пароля. Пожалуйста, свяжитесь с вашим администратором.",
"Sunday" : "Воскресенье",
"Monday" : "Понедельник",
"Tuesday" : "Вторник",
@@ -77,11 +86,11 @@ OC.L10N.register(
"Oct." : "Окт.",
"Nov." : "Ноя.",
"Dec." : "Дек.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\"> Были обнаружены проблемы с проверкой целостности кода. Подробнее ...",
"Settings" : "Настройки",
"Saving..." : "Сохранение...",
"seconds ago" : "несколько секунд назад",
- "Couldn't send reset email. Please contact your administrator." : "Не удалось отправить письмо для сброса пароля. Пожалуйста, свяжитесь с вашим администратором.",
- "The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Ссылка для сброса пароля была отправлена на ваш email. Если вы не получили письмо в течении разумного промежутка времени, проверьте папку спама.<br>Если его там нет, то обратитесь к вашему администратору.",
+ "The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Ссылка для сброса пароля была отправлена на ваш email. Если вы не получили письмо в течении разумного промежутка времени, проверьте папку со спамом.<br>Если его там нет, то обратитесь к вашему администратору.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Ваши файлы зашифрованы. Если вы не включили ключ восстановления, то ваши данные будут недоступны после сброса пароля.<br />Если вы не уверены что делать дальше - обратитесь к вашему администратору.<br />Вы действительно хотите продолжить?",
"I know what I'm doing" : "Я понимаю, что делаю",
"Password can not be changed. Please contact your administrator." : "Пароль не может быть изменён. Пожалуйста, свяжитесь с вашим администратором.",
@@ -108,24 +117,25 @@ OC.L10N.register(
"So-so password" : "Так себе пароль",
"Good password" : "Хороший пароль",
"Strong password" : "Устойчивый к взлому пароль",
- "Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ваш веб-сервер еще не настроен должным образом, чтобы позволить синхронизацию файлов, потому что интерфейс WebDAV, кажется, испорчен.",
- "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Этот сервер не имеет подключения к Интернету. Это означает, что некоторые из функций, таких как внешнее хранилище, уведомления об обновлениях и установки сторонних приложений не будут работать. Доступ к файлам удаленно и отправки уведомлений по почте могут не работать. Мы предлагаем включить подключение к Интернету для этого сервера, если вы хотите, чтобы все функции работали.",
- "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ваш каталог данных и ваши файлы возможно доступны из интернете. .htaccess файл не работает. Мы настоятельно рекомендуем вам настроить ваш веб сервер таким образом, что-бы каталог данных не был больше доступен или переместите каталог данных за пределы корня веб сервера.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Не настроена система кеширования. Для увеличения производительности сервера, по возможности, настройте memcache. Более подробную информацию, вы можете посмотреть в нашей <a href=\"{docLink}\">документации</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom не может быть прочитан PHP, что крайне нежелательно по причинам безопасности. Дополнительную информацию можно найти в a href=\"{docLink}\">документации</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Ваша версия PHP ({version}) более не <a href=\"{phpLink}\">поддерживается PHP</a>. Мы советуем Вам обновить Вашу версию PHP для получения обновлений производительности и безопасности, предоставляемых PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Конфигурация заголовков обратного прокси сервера некорректна, либо Вы заходите в ownCloud через доверенный прокси. Если Вы не заходите в ownCloud через доверенный прокси, это может быть небезопасно, так как злоумышленник может подменить видимые Owncloud IP-адреса. Более подробную информацию можно найти в нашей <a href=\"{docLink}\">документации</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached настроен на распределенный кеш, но установлен не поддерживаемый модуль PHP \"memcache\". \\OC\\Memcache\\Memcached поддерживает только модуль \"memcached\"! Информацию о модулях читайте на странице <a href=\"{wikiLink}\">memcached</a>.",
+ "Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ваш веб-сервер еще не настроен должным образом чтобы позволить синхронизацию файлов, потому что интерфейс WebDAV, кажется, испорчен.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Ваш сервер не настроен для правильного разрешения \"{url}\". За дополнительной информацией обратитесь к нашей <a target=\"_blank\" href=\"{docLink}\">документации</a>.",
+ "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Этот сервер не имеет подключения к Интернету. Это означает, что некоторые из функций, таких как внешнее хранилище, уведомления об обновлениях и установка сторонних приложений не будут работать. Доступ к файлам удаленно и отправки уведомлений по почте могут не работать. Рекомендуется разрешить данному серверу доступ в Интернет если хотите, чтобы все функции работали.",
+ "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ваш каталог данных и ваши файлы возможно доступны из Интернета. Файл .htaccess не работает. Мы настоятельно рекомендуем Вам настроить веб сервер таким образом, чтобы каталог данных не был больше доступен или переместить каталог данных за пределы корня веб сервера.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Кэш-памяти не настроено. Для повышения производительности, пожалуйста, настройте кэш-памяти (memcache) если есть такая возможность. Дополнительную информацию можно найти в нашей <a target=\"_blank\" href=\"{docLink}\"> документации </a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom не доступно чтение для PHP, что крайне нежелательно по соображениям безопасности. Дополнительную информацию можно найти в нашей <a target=\"_blank\" href=\"{docLink}\"> документации </a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Ваша версия PHP ({version}) больше не <a target=\"_blank\" href=\"{phpLink}\"> поддерживается разработчиками PHP</a>. Мы рекомендуем Вам обновить версию PHP, чтобы воспользоваться производительностью и безопасностью, предусмотренных в обновленной версии PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Конфигурация заголовков обратного прокси не верна, либо доступ к ownCloud осуществлён через доверенный прокси. Если ownCloud открыт не через доверенный прокси то это проблема безопасности, которая может позволить атакующему подделать IP адрес, который видит ownCloud. Дополнительная информация доступна в нашей <a target=\"_blank\" href=\"{docLink}\">документации</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "В качестве распределённого кеша настроен memcached, но установлен неверный модуль PHP \"memcache\". \\OC\\Memcache\\Memcached поддерживает только \"memcached\", но не \"memcache\". Изучите <a target=\"_blank\" href=\"{wikiLink}\">оба модуля в memcached wiki</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Некоторые файлы не прошли проверку целостности. Дополнительная информация о том, как устранить данную проблему доступна в нашей <a target=\"_blank\" href=\"{docLink}\">документации</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Список проблемных файлов…</a> / <a href=\"{rescanEndpoint}\">Сканировать ещё раз…</a>)",
"Error occurred while checking server setup" : "Произошла ошибка при проверке настроек сервера",
- "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Заголовок HTTP \"{header}\" не настроен на ожидаемый \"{expected}\". Это потенциальная проблема безопасности и мы рекомендуем изменить эти настройки.",
- "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Заголовок HTTP \"Strict-Transport-Security\" должен быть настроен хотя бы на \"{seconds}\" секунд. Для улучшения безопасности мы рекомендуем включить HSTS согласно нашим <a href=\"{docUrl}\">подсказкам по безопасности</a>.",
+ "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Заголовок HTTP \"{header}\" не настроен на значение \"{expected}\". Это потенциальная проблема безопасности и мы рекомендуем изменить эти настройки.",
+ "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Заголовок HTTP \"Strict-Transport-Security\" не настроен хотя бы на \"{seconds}\" секунд. Для улучшения безопасности мы рекомендуем включить HSTS согласно нашим <a href=\"{docUrl}\">подсказкам по безопасности</a>.",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Вы зашли на этот сайт через HTTP. Мы настоятельно рекомендуем настроить ваш сервер на использование HTTPS согласно нашим <a href=\"{docUrl}\">подсказкам по безопасности</a>.",
"Shared" : "Общий доступ",
"Shared with {recipients}" : "Вы поделились с {recipients}",
"Error" : "Ошибка",
"Error while sharing" : "При попытке поделиться произошла ошибка",
"Error while unsharing" : "При закрытии доступа произошла ошибка",
- "Error while changing permissions" : "При изменении прав доступа произошла ошибка",
"Error setting expiration date" : "Ошибка при установке срока доступа",
"The public link will expire no later than {days} days after it is created" : "Срок действия публичной ссылки истекает не позже чем через {days} дней после её создания",
"Set expiration date" : "Установить срок действия",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "Отправить",
"Shared with you and the group {group} by {owner}" : "{owner} поделился с вами и группой {group} ",
"Shared with you by {owner}" : "С вами поделился {owner} ",
- "Shared in {item} with {user}" : "Общий доступ в {item} для {user}",
"group" : "группа",
"remote" : "удаленный",
"notify by email" : "уведомить по почте",
@@ -155,17 +164,25 @@ OC.L10N.register(
"change" : "изменить",
"delete" : "удалить",
"access control" : "контроль доступа",
- "Share details could not be loaded for this item." : "Информация об общем доступе для этого элемента не может быть загружена.",
+ "Could not unshare" : "Не удается отменить доступ",
+ "Share details could not be loaded for this item." : "Не удалось загрузить информацию об общем доступе для этого элемента.",
"An error occured. Please try again" : "Произошла ошибка. Попробуйте ещё раз",
"Share" : "Поделиться",
- "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Поделиться с людьми на других серверах ownCloud используя синтакс username@example.com/owncloud",
+ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Поделиться с людьми на других серверах ownCloud используя формат username@example.com/owncloud",
"Share with users or groups …" : "Поделиться с пользователями или группами ...",
"Share with users, groups or remote users …" : "Поделиться с пользователями, группами или удаленными пользователями ...",
+ "Error removing share" : "Ошибка удаления общего доступа",
"Warning" : "Предупреждение",
- "Error while sending notification" : "Ошибка отправки уведомления",
+ "Error while sending notification" : "Ошибка при отправке уведомления",
+ "Non-existing tag #{tag}" : "Несуществующий тег #{tag}",
+ "not assignable" : "не назначаемый",
+ "invisible" : "невидимый",
+ "({scope})" : "({scope})",
+ "Delete" : "Удалить",
+ "Rename" : "Переименовать",
+ "Global tags" : "Глобальные теги",
"The object type is not specified." : "Тип объекта не указан",
"Enter new" : "Ввести новое",
- "Delete" : "Удалить",
"Add" : "Добавить",
"Edit tags" : "Изменить метки",
"Error loading dialog template: {error}" : "Ошибка загрузки шаблона диалога: {error}",
@@ -178,24 +195,15 @@ OC.L10N.register(
"_download %n file_::_download %n files_" : ["скачать %n файл","скачать %n файла","скачать %n файлов","скачать %n файлов"],
"{version} is available. Get more information on how to update." : "Доступна версия {version}. Получить дополнительную информацию о порядке обновления.",
"The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Идет обновление. Покидая эту страницу, вы можете прервать процесс обновления.",
- "Updating {productName} to version {version}, this may take a while." : "Идет обновление {productName} до версии {version}, пожалуйста, подождите.",
+ "Updating {productName} to version {version}, this may take a while." : "Идет обновление {productName} до версии {version}, это может занять некоторое время.",
"An error occurred." : "Произошла ошибка.",
- "Please reload the page." : "Обновите страницу.",
- "The update was unsuccessful. " : "Обновление не удалось.",
+ "Please reload the page." : "Пожалуйста, обновите страницу.",
+ "The update was unsuccessful. " : "Обновление окончилось неудачей.",
"The update was successful. There were warnings." : "Обновление прошло успешно. Были предупреждения.",
"The update was successful. Redirecting you to ownCloud now." : "Обновление прошло успешно. Перенаправляем в ownCloud.",
- "Couldn't reset password because the token is invalid" : "Невозможно сбросить пароль из-за неверного токена",
- "Couldn't reset password because the token is expired" : "Не удается сбросить пароль, так как токен истек.",
- "Couldn't send reset email. Please make sure your username is correct." : "Не удалось отправить письмо для сброса пароля. Убедитесь, что имя пользователя указано верно.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Невозможно отправить письмо для сброса пароля, для вашей учетной записи не указан адрес электронной почты. Пожалуйста, свяжитесь с администратором.",
- "%s password reset" : "Сброс пароля %s",
- "Use the following link to reset your password: {link}" : "Используйте следующую ссылку чтобы сбросить пароль: {link}",
- "New password" : "Новый пароль",
- "New Password" : "Новый пароль",
- "Reset password" : "Сбросить пароль",
"Searching other places" : "Идет поиск в других местах",
- "No search results in other folders" : "Нет результатов поиска в других папках",
- "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} результат в другой папке","{count} результата в другой папке","{count} результатов в другой папке","{count} результатов в другой папке"],
+ "No search results in other folders" : "В других папках ничего не найдено",
+ "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} результат в другой папке","{count} результата в другой папке","{count} результатов в другой папке","{count} результатов в других папках"],
"Personal" : "Личное",
"Users" : "Пользователи",
"Apps" : "Приложения",
@@ -217,7 +225,7 @@ OC.L10N.register(
"Cheers!" : "Всего наилучшего!",
"Internal Server Error" : "Внутренняя ошибка сервера",
"The server encountered an internal error and was unable to complete your request." : "Запрос не выполнен, на сервере произошла ошибка.",
- "Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "Пожалуйста, свяжитесь с администратором сервера, если эта ошибка будет повторяться, прикрепите технические детали к своему сообщению.",
+ "Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "Пожалуйста, свяжитесь с администратором сервера если эта ошибка будет повторяться. Прикрепите указанную ниже информацию к своему сообщению.",
"More details can be found in the server log." : "Больше деталей может быть найдено в журнале сервера.",
"Technical details" : "Технические детали",
"Remote Address: %s" : "Удаленный адрес: %s",
@@ -227,10 +235,10 @@ OC.L10N.register(
"Message: %s" : "Сообщение: %s",
"File: %s" : "Файл: %s",
"Line: %s" : "Линия: %s",
- "Trace" : "След",
+ "Trace" : "Трассировка",
"Security warning" : "Предупреждение безопасности",
- "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Правила файла .htaccess не выполняются, возможно, каталог данных и файлы свободно доступны из интернета.",
- "For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "Что-бы правильно настроить сервер, руководствуйтесь <a hrev=\"%s\"target=\"blank\">документацией</a>.",
+ "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Правила файла .htaccess не выполняются. Возможно, каталог данных и файлы свободно доступны из интернета.",
+ "For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "Что-бы правильно настроить сервер, воспользуйтесь <a hrev=\"%s\"target=\"blank\">документацией</a>.",
"Create an <strong>admin account</strong>" : "Создать <strong>учётную запись администратора</strong>",
"Username" : "Имя пользователя",
"Storage & database" : "Хранилище и база данных",
@@ -246,31 +254,36 @@ OC.L10N.register(
"Database host" : "Хост базы данных",
"Performance warning" : "Предупреждение о производительности",
"SQLite will be used as database." : "В качестве базы данных будет использована SQLite.",
- "For larger installations we recommend to choose a different database backend." : "Для крупных проектов мы советуем выбрать другую базу данных.",
- "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Особенно вызывает сомнение использование SQLite при синхронизации файлов с использование клиента для ПК.",
+ "For larger installations we recommend to choose a different database backend." : "Для крупных проектов мы советуем выбрать другой тип базы данных.",
+ "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "В частности не рекомендуется использовать SQLite при синхронизации файлов с использованием клиента для ПК.",
"Finish setup" : "Завершить установку",
"Finishing …" : "Завершение...",
"Need help?" : "Нужна помощь?",
"See the documentation" : "Посмотреть документацию",
"Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Здравствуйте,<br><br>%s поделился с вами <strong>%s</strong>.<br>Перейдите по <a href=\"%s\">ссылке</a>, чтобы посмотреть<br><br>",
- "This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Это приложение требует включённый JavaScript для корректной работы. Пожалуйста, <a href=\"http://enable-javascript.com/\" target=\"_blank\">включите JavaScript</a> и перезагрузите интерфейс.",
+ "This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Для корректной работы приложения требуется JavaScript. Пожалуйста, {linkstart}включите JavaScript{linkend} и обновите страницу.",
"Log out" : "Выйти",
"Search" : "Найти",
- "Server side authentication failed!" : "Неудачная аутентификация с сервером!",
- "Please contact your administrator." : "Пожалуйста, свяжитесь с вашим администратором.",
- "An internal error occured." : "Произошла внутренняя ошибка",
+ "Server side authentication failed!" : "Ошибка аутентификации на стороне сервера!",
+ "Please contact your administrator." : "Пожалуйста, обратитесь к администратору.",
+ "An internal error occured." : "Произошла внутренняя ошибка.",
"Please try again or contact your administrator." : "Пожалуйста попробуйте ещё раз или свяжитесь с вашим администратором",
"Log in" : "Войти",
"Wrong password. Reset it?" : "Неправильный пароль. Сбросить его?",
+ "Wrong password." : "Неправильный пароль.",
"Stay logged in" : "Оставаться в системе",
"Alternative Logins" : "Альтернативные имена пользователя",
+ "Use the following link to reset your password: {link}" : "Используйте следующую ссылку чтобы сбросить пароль: {link}",
+ "New password" : "Новый пароль",
+ "New Password" : "Новый пароль",
+ "Reset password" : "Сбросить пароль",
"This ownCloud instance is currently in single user mode." : "Сервер ownCloud в настоящее время работает в однопользовательском режиме.",
"This means only administrators can use the instance." : "Это значит, что только администраторы могут использовать сервер.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Обратитесь к вашему системному администратору если это сообщение не исчезает или появляется неожиданно.",
"Thank you for your patience." : "Спасибо за терпение.",
- "You are accessing the server from an untrusted domain." : "Вы пытаетесь получить доступ к серверу с неподтверждённого домена.",
- "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Пожалуйста, обратитесь к администратору. Если вы являетесь администратором этого экземпляра, настроить параметры \"trusted_domains\" можно в config/config.php. Пример настройки можно найти в config/config.sample.php.",
- "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "В зависимости от конфигурации, как администратор вы можете также внести домен в доверенные с помощью кнопки ниже.",
+ "You are accessing the server from an untrusted domain." : "Вы пытаетесь получить доступ к серверу с недоверенного домена.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Пожалуйста, обратитесь к администратору. Если вы являетесь администратором этого сервера, настройте параметры \"trusted_domains\" в файле config/config.php. Пример настройки можно найти в config/config.sample.php.",
+ "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "В зависимости от конфигурации, как администратор вы можете также внести домен в доверенные с помощью кнопки, расположенной ниже.",
"Add \"%s\" as trusted domain" : "Добавить \"%s\" как доверенный домен",
"App update required" : "Требуется обновление приложения",
"%s will be updated to version %s" : "%s будет обновлен до версии %s",
@@ -279,8 +292,8 @@ OC.L10N.register(
"The theme %s has been disabled." : "Тема %s была отключена.",
"Please make sure that the database, the config folder and the data folder have been backed up before proceeding." : "Перед продолжением убедитесь, что вы сделали резервную копию базы данных, каталога конфигурации и каталога с данными.",
"Start update" : "Запустить обновление",
- "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Чтобы избежать задержек в крупных установках, вы можете выполнить следующую команду в каталоге установки:",
- "This %s instance is currently in maintenance mode, which may take a while." : "Это %s находится в режиме технического обслуживания, которое может занять некоторое время.",
- "This page will refresh itself when the %s instance is available again." : "Эта страница обновится, когда экземпляр %s снова станет доступен."
+ "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Чтобы избежать тайм-аутов в крупных установках, вместо этого можно выполнить следующую команду в каталоге установки:",
+ "This %s instance is currently in maintenance mode, which may take a while." : "Этот сервер %s находится в режиме технического обслуживания, которое может занять некоторое время.",
+ "This page will refresh itself when the %s instance is available again." : "Эта страница автоматически обновится, когда сервер %s снова станет доступен."
},
"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/core/l10n/ru.json b/core/l10n/ru.json
index a24ee0831a0..d90e88b37ae 100644
--- a/core/l10n/ru.json
+++ b/core/l10n/ru.json
@@ -14,13 +14,16 @@
"Updated \"%s\" to %s" : "Обновлено \"%s\" до %s",
"Repair warning: " : "Предупреждение восстановления:",
"Repair error: " : "Ошибка восстановления:",
- "Set log level to debug - current level: \"%s\"" : "Установить отладочное журналирование - текущий уровень: \"%s\"",
- "Reset log level to \"%s\"" : "Сбросить уровень журналирования в \"%s\"",
- "%s (3rdparty)" : "%s (3rdparty)",
+ "Set log level to debug" : "Установить журнал в режим отладки",
+ "Reset log level" : "Сбросить уровень журнала",
+ "Starting code integrity check" : "Начинается проверка целостности кода",
+ "Finished code integrity check" : "Проверка целостности кода завершина",
+ "%s (3rdparty)" : "%s (стороннее)",
"%s (incompatible)" : "%s (несовместим)",
"Following apps have been disabled: %s" : "Были отключены следующие приложения: %s",
"Already up to date" : "Не нуждается в обновлении",
- "File is too big" : "Файл слишком большой",
+ "Please select a file." : "Пожалуйста выберите файл.",
+ "File is too big" : "Файл слишком велик",
"Invalid file provided" : "Указан неправильный файл",
"No image or file provided" : "Не указано изображение или файл",
"Unknown filetype" : "Неизвестный тип файла",
@@ -30,6 +33,12 @@
"No crop data provided" : "Не указана информация о кадрировании",
"No valid crop data provided" : "Не указаны корректные данные о кадрировании",
"Crop is not square" : "Кадр не является квадратом",
+ "Couldn't reset password because the token is invalid" : "Не удалось сбросить пароль из-за неверного токена",
+ "Couldn't reset password because the token is expired" : "Не удалось сбросить пароль, так как срок действия токена истек.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Не удалось отправить письмо для сброса пароля. Убедитесь, что имя пользователя указано верно.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Не удалось отправить письмо сброса так как у данного пользователя не задан адрес электронной почты. Пожалуйста, обратитесь к администратору.",
+ "%s password reset" : "Сброс пароля %s",
+ "Couldn't send reset email. Please contact your administrator." : "Не удалось отправить письмо для сброса пароля. Пожалуйста, свяжитесь с вашим администратором.",
"Sunday" : "Воскресенье",
"Monday" : "Понедельник",
"Tuesday" : "Вторник",
@@ -75,11 +84,11 @@
"Oct." : "Окт.",
"Nov." : "Ноя.",
"Dec." : "Дек.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\"> Были обнаружены проблемы с проверкой целостности кода. Подробнее ...",
"Settings" : "Настройки",
"Saving..." : "Сохранение...",
"seconds ago" : "несколько секунд назад",
- "Couldn't send reset email. Please contact your administrator." : "Не удалось отправить письмо для сброса пароля. Пожалуйста, свяжитесь с вашим администратором.",
- "The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Ссылка для сброса пароля была отправлена на ваш email. Если вы не получили письмо в течении разумного промежутка времени, проверьте папку спама.<br>Если его там нет, то обратитесь к вашему администратору.",
+ "The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Ссылка для сброса пароля была отправлена на ваш email. Если вы не получили письмо в течении разумного промежутка времени, проверьте папку со спамом.<br>Если его там нет, то обратитесь к вашему администратору.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Ваши файлы зашифрованы. Если вы не включили ключ восстановления, то ваши данные будут недоступны после сброса пароля.<br />Если вы не уверены что делать дальше - обратитесь к вашему администратору.<br />Вы действительно хотите продолжить?",
"I know what I'm doing" : "Я понимаю, что делаю",
"Password can not be changed. Please contact your administrator." : "Пароль не может быть изменён. Пожалуйста, свяжитесь с вашим администратором.",
@@ -106,24 +115,25 @@
"So-so password" : "Так себе пароль",
"Good password" : "Хороший пароль",
"Strong password" : "Устойчивый к взлому пароль",
- "Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ваш веб-сервер еще не настроен должным образом, чтобы позволить синхронизацию файлов, потому что интерфейс WebDAV, кажется, испорчен.",
- "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Этот сервер не имеет подключения к Интернету. Это означает, что некоторые из функций, таких как внешнее хранилище, уведомления об обновлениях и установки сторонних приложений не будут работать. Доступ к файлам удаленно и отправки уведомлений по почте могут не работать. Мы предлагаем включить подключение к Интернету для этого сервера, если вы хотите, чтобы все функции работали.",
- "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ваш каталог данных и ваши файлы возможно доступны из интернете. .htaccess файл не работает. Мы настоятельно рекомендуем вам настроить ваш веб сервер таким образом, что-бы каталог данных не был больше доступен или переместите каталог данных за пределы корня веб сервера.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Не настроена система кеширования. Для увеличения производительности сервера, по возможности, настройте memcache. Более подробную информацию, вы можете посмотреть в нашей <a href=\"{docLink}\">документации</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom не может быть прочитан PHP, что крайне нежелательно по причинам безопасности. Дополнительную информацию можно найти в a href=\"{docLink}\">документации</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Ваша версия PHP ({version}) более не <a href=\"{phpLink}\">поддерживается PHP</a>. Мы советуем Вам обновить Вашу версию PHP для получения обновлений производительности и безопасности, предоставляемых PHP.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Конфигурация заголовков обратного прокси сервера некорректна, либо Вы заходите в ownCloud через доверенный прокси. Если Вы не заходите в ownCloud через доверенный прокси, это может быть небезопасно, так как злоумышленник может подменить видимые Owncloud IP-адреса. Более подробную информацию можно найти в нашей <a href=\"{docLink}\">документации</a>.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached настроен на распределенный кеш, но установлен не поддерживаемый модуль PHP \"memcache\". \\OC\\Memcache\\Memcached поддерживает только модуль \"memcached\"! Информацию о модулях читайте на странице <a href=\"{wikiLink}\">memcached</a>.",
+ "Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ваш веб-сервер еще не настроен должным образом чтобы позволить синхронизацию файлов, потому что интерфейс WebDAV, кажется, испорчен.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Ваш сервер не настроен для правильного разрешения \"{url}\". За дополнительной информацией обратитесь к нашей <a target=\"_blank\" href=\"{docLink}\">документации</a>.",
+ "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Этот сервер не имеет подключения к Интернету. Это означает, что некоторые из функций, таких как внешнее хранилище, уведомления об обновлениях и установка сторонних приложений не будут работать. Доступ к файлам удаленно и отправки уведомлений по почте могут не работать. Рекомендуется разрешить данному серверу доступ в Интернет если хотите, чтобы все функции работали.",
+ "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ваш каталог данных и ваши файлы возможно доступны из Интернета. Файл .htaccess не работает. Мы настоятельно рекомендуем Вам настроить веб сервер таким образом, чтобы каталог данных не был больше доступен или переместить каталог данных за пределы корня веб сервера.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Кэш-памяти не настроено. Для повышения производительности, пожалуйста, настройте кэш-памяти (memcache) если есть такая возможность. Дополнительную информацию можно найти в нашей <a target=\"_blank\" href=\"{docLink}\"> документации </a>.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom не доступно чтение для PHP, что крайне нежелательно по соображениям безопасности. Дополнительную информацию можно найти в нашей <a target=\"_blank\" href=\"{docLink}\"> документации </a>.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Ваша версия PHP ({version}) больше не <a target=\"_blank\" href=\"{phpLink}\"> поддерживается разработчиками PHP</a>. Мы рекомендуем Вам обновить версию PHP, чтобы воспользоваться производительностью и безопасностью, предусмотренных в обновленной версии PHP.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Конфигурация заголовков обратного прокси не верна, либо доступ к ownCloud осуществлён через доверенный прокси. Если ownCloud открыт не через доверенный прокси то это проблема безопасности, которая может позволить атакующему подделать IP адрес, который видит ownCloud. Дополнительная информация доступна в нашей <a target=\"_blank\" href=\"{docLink}\">документации</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "В качестве распределённого кеша настроен memcached, но установлен неверный модуль PHP \"memcache\". \\OC\\Memcache\\Memcached поддерживает только \"memcached\", но не \"memcache\". Изучите <a target=\"_blank\" href=\"{wikiLink}\">оба модуля в memcached wiki</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Некоторые файлы не прошли проверку целостности. Дополнительная информация о том, как устранить данную проблему доступна в нашей <a target=\"_blank\" href=\"{docLink}\">документации</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Список проблемных файлов…</a> / <a href=\"{rescanEndpoint}\">Сканировать ещё раз…</a>)",
"Error occurred while checking server setup" : "Произошла ошибка при проверке настроек сервера",
- "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Заголовок HTTP \"{header}\" не настроен на ожидаемый \"{expected}\". Это потенциальная проблема безопасности и мы рекомендуем изменить эти настройки.",
- "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Заголовок HTTP \"Strict-Transport-Security\" должен быть настроен хотя бы на \"{seconds}\" секунд. Для улучшения безопасности мы рекомендуем включить HSTS согласно нашим <a href=\"{docUrl}\">подсказкам по безопасности</a>.",
+ "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Заголовок HTTP \"{header}\" не настроен на значение \"{expected}\". Это потенциальная проблема безопасности и мы рекомендуем изменить эти настройки.",
+ "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Заголовок HTTP \"Strict-Transport-Security\" не настроен хотя бы на \"{seconds}\" секунд. Для улучшения безопасности мы рекомендуем включить HSTS согласно нашим <a href=\"{docUrl}\">подсказкам по безопасности</a>.",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "Вы зашли на этот сайт через HTTP. Мы настоятельно рекомендуем настроить ваш сервер на использование HTTPS согласно нашим <a href=\"{docUrl}\">подсказкам по безопасности</a>.",
"Shared" : "Общий доступ",
"Shared with {recipients}" : "Вы поделились с {recipients}",
"Error" : "Ошибка",
"Error while sharing" : "При попытке поделиться произошла ошибка",
"Error while unsharing" : "При закрытии доступа произошла ошибка",
- "Error while changing permissions" : "При изменении прав доступа произошла ошибка",
"Error setting expiration date" : "Ошибка при установке срока доступа",
"The public link will expire no later than {days} days after it is created" : "Срок действия публичной ссылки истекает не позже чем через {days} дней после её создания",
"Set expiration date" : "Установить срок действия",
@@ -142,7 +152,6 @@
"Send" : "Отправить",
"Shared with you and the group {group} by {owner}" : "{owner} поделился с вами и группой {group} ",
"Shared with you by {owner}" : "С вами поделился {owner} ",
- "Shared in {item} with {user}" : "Общий доступ в {item} для {user}",
"group" : "группа",
"remote" : "удаленный",
"notify by email" : "уведомить по почте",
@@ -153,17 +162,25 @@
"change" : "изменить",
"delete" : "удалить",
"access control" : "контроль доступа",
- "Share details could not be loaded for this item." : "Информация об общем доступе для этого элемента не может быть загружена.",
+ "Could not unshare" : "Не удается отменить доступ",
+ "Share details could not be loaded for this item." : "Не удалось загрузить информацию об общем доступе для этого элемента.",
"An error occured. Please try again" : "Произошла ошибка. Попробуйте ещё раз",
"Share" : "Поделиться",
- "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Поделиться с людьми на других серверах ownCloud используя синтакс username@example.com/owncloud",
+ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Поделиться с людьми на других серверах ownCloud используя формат username@example.com/owncloud",
"Share with users or groups …" : "Поделиться с пользователями или группами ...",
"Share with users, groups or remote users …" : "Поделиться с пользователями, группами или удаленными пользователями ...",
+ "Error removing share" : "Ошибка удаления общего доступа",
"Warning" : "Предупреждение",
- "Error while sending notification" : "Ошибка отправки уведомления",
+ "Error while sending notification" : "Ошибка при отправке уведомления",
+ "Non-existing tag #{tag}" : "Несуществующий тег #{tag}",
+ "not assignable" : "не назначаемый",
+ "invisible" : "невидимый",
+ "({scope})" : "({scope})",
+ "Delete" : "Удалить",
+ "Rename" : "Переименовать",
+ "Global tags" : "Глобальные теги",
"The object type is not specified." : "Тип объекта не указан",
"Enter new" : "Ввести новое",
- "Delete" : "Удалить",
"Add" : "Добавить",
"Edit tags" : "Изменить метки",
"Error loading dialog template: {error}" : "Ошибка загрузки шаблона диалога: {error}",
@@ -176,24 +193,15 @@
"_download %n file_::_download %n files_" : ["скачать %n файл","скачать %n файла","скачать %n файлов","скачать %n файлов"],
"{version} is available. Get more information on how to update." : "Доступна версия {version}. Получить дополнительную информацию о порядке обновления.",
"The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Идет обновление. Покидая эту страницу, вы можете прервать процесс обновления.",
- "Updating {productName} to version {version}, this may take a while." : "Идет обновление {productName} до версии {version}, пожалуйста, подождите.",
+ "Updating {productName} to version {version}, this may take a while." : "Идет обновление {productName} до версии {version}, это может занять некоторое время.",
"An error occurred." : "Произошла ошибка.",
- "Please reload the page." : "Обновите страницу.",
- "The update was unsuccessful. " : "Обновление не удалось.",
+ "Please reload the page." : "Пожалуйста, обновите страницу.",
+ "The update was unsuccessful. " : "Обновление окончилось неудачей.",
"The update was successful. There were warnings." : "Обновление прошло успешно. Были предупреждения.",
"The update was successful. Redirecting you to ownCloud now." : "Обновление прошло успешно. Перенаправляем в ownCloud.",
- "Couldn't reset password because the token is invalid" : "Невозможно сбросить пароль из-за неверного токена",
- "Couldn't reset password because the token is expired" : "Не удается сбросить пароль, так как токен истек.",
- "Couldn't send reset email. Please make sure your username is correct." : "Не удалось отправить письмо для сброса пароля. Убедитесь, что имя пользователя указано верно.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Невозможно отправить письмо для сброса пароля, для вашей учетной записи не указан адрес электронной почты. Пожалуйста, свяжитесь с администратором.",
- "%s password reset" : "Сброс пароля %s",
- "Use the following link to reset your password: {link}" : "Используйте следующую ссылку чтобы сбросить пароль: {link}",
- "New password" : "Новый пароль",
- "New Password" : "Новый пароль",
- "Reset password" : "Сбросить пароль",
"Searching other places" : "Идет поиск в других местах",
- "No search results in other folders" : "Нет результатов поиска в других папках",
- "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} результат в другой папке","{count} результата в другой папке","{count} результатов в другой папке","{count} результатов в другой папке"],
+ "No search results in other folders" : "В других папках ничего не найдено",
+ "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} результат в другой папке","{count} результата в другой папке","{count} результатов в другой папке","{count} результатов в других папках"],
"Personal" : "Личное",
"Users" : "Пользователи",
"Apps" : "Приложения",
@@ -215,7 +223,7 @@
"Cheers!" : "Всего наилучшего!",
"Internal Server Error" : "Внутренняя ошибка сервера",
"The server encountered an internal error and was unable to complete your request." : "Запрос не выполнен, на сервере произошла ошибка.",
- "Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "Пожалуйста, свяжитесь с администратором сервера, если эта ошибка будет повторяться, прикрепите технические детали к своему сообщению.",
+ "Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "Пожалуйста, свяжитесь с администратором сервера если эта ошибка будет повторяться. Прикрепите указанную ниже информацию к своему сообщению.",
"More details can be found in the server log." : "Больше деталей может быть найдено в журнале сервера.",
"Technical details" : "Технические детали",
"Remote Address: %s" : "Удаленный адрес: %s",
@@ -225,10 +233,10 @@
"Message: %s" : "Сообщение: %s",
"File: %s" : "Файл: %s",
"Line: %s" : "Линия: %s",
- "Trace" : "След",
+ "Trace" : "Трассировка",
"Security warning" : "Предупреждение безопасности",
- "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Правила файла .htaccess не выполняются, возможно, каталог данных и файлы свободно доступны из интернета.",
- "For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "Что-бы правильно настроить сервер, руководствуйтесь <a hrev=\"%s\"target=\"blank\">документацией</a>.",
+ "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Правила файла .htaccess не выполняются. Возможно, каталог данных и файлы свободно доступны из интернета.",
+ "For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "Что-бы правильно настроить сервер, воспользуйтесь <a hrev=\"%s\"target=\"blank\">документацией</a>.",
"Create an <strong>admin account</strong>" : "Создать <strong>учётную запись администратора</strong>",
"Username" : "Имя пользователя",
"Storage & database" : "Хранилище и база данных",
@@ -244,31 +252,36 @@
"Database host" : "Хост базы данных",
"Performance warning" : "Предупреждение о производительности",
"SQLite will be used as database." : "В качестве базы данных будет использована SQLite.",
- "For larger installations we recommend to choose a different database backend." : "Для крупных проектов мы советуем выбрать другую базу данных.",
- "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Особенно вызывает сомнение использование SQLite при синхронизации файлов с использование клиента для ПК.",
+ "For larger installations we recommend to choose a different database backend." : "Для крупных проектов мы советуем выбрать другой тип базы данных.",
+ "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "В частности не рекомендуется использовать SQLite при синхронизации файлов с использованием клиента для ПК.",
"Finish setup" : "Завершить установку",
"Finishing …" : "Завершение...",
"Need help?" : "Нужна помощь?",
"See the documentation" : "Посмотреть документацию",
"Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Здравствуйте,<br><br>%s поделился с вами <strong>%s</strong>.<br>Перейдите по <a href=\"%s\">ссылке</a>, чтобы посмотреть<br><br>",
- "This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Это приложение требует включённый JavaScript для корректной работы. Пожалуйста, <a href=\"http://enable-javascript.com/\" target=\"_blank\">включите JavaScript</a> и перезагрузите интерфейс.",
+ "This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Для корректной работы приложения требуется JavaScript. Пожалуйста, {linkstart}включите JavaScript{linkend} и обновите страницу.",
"Log out" : "Выйти",
"Search" : "Найти",
- "Server side authentication failed!" : "Неудачная аутентификация с сервером!",
- "Please contact your administrator." : "Пожалуйста, свяжитесь с вашим администратором.",
- "An internal error occured." : "Произошла внутренняя ошибка",
+ "Server side authentication failed!" : "Ошибка аутентификации на стороне сервера!",
+ "Please contact your administrator." : "Пожалуйста, обратитесь к администратору.",
+ "An internal error occured." : "Произошла внутренняя ошибка.",
"Please try again or contact your administrator." : "Пожалуйста попробуйте ещё раз или свяжитесь с вашим администратором",
"Log in" : "Войти",
"Wrong password. Reset it?" : "Неправильный пароль. Сбросить его?",
+ "Wrong password." : "Неправильный пароль.",
"Stay logged in" : "Оставаться в системе",
"Alternative Logins" : "Альтернативные имена пользователя",
+ "Use the following link to reset your password: {link}" : "Используйте следующую ссылку чтобы сбросить пароль: {link}",
+ "New password" : "Новый пароль",
+ "New Password" : "Новый пароль",
+ "Reset password" : "Сбросить пароль",
"This ownCloud instance is currently in single user mode." : "Сервер ownCloud в настоящее время работает в однопользовательском режиме.",
"This means only administrators can use the instance." : "Это значит, что только администраторы могут использовать сервер.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Обратитесь к вашему системному администратору если это сообщение не исчезает или появляется неожиданно.",
"Thank you for your patience." : "Спасибо за терпение.",
- "You are accessing the server from an untrusted domain." : "Вы пытаетесь получить доступ к серверу с неподтверждённого домена.",
- "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Пожалуйста, обратитесь к администратору. Если вы являетесь администратором этого экземпляра, настроить параметры \"trusted_domains\" можно в config/config.php. Пример настройки можно найти в config/config.sample.php.",
- "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "В зависимости от конфигурации, как администратор вы можете также внести домен в доверенные с помощью кнопки ниже.",
+ "You are accessing the server from an untrusted domain." : "Вы пытаетесь получить доступ к серверу с недоверенного домена.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Пожалуйста, обратитесь к администратору. Если вы являетесь администратором этого сервера, настройте параметры \"trusted_domains\" в файле config/config.php. Пример настройки можно найти в config/config.sample.php.",
+ "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "В зависимости от конфигурации, как администратор вы можете также внести домен в доверенные с помощью кнопки, расположенной ниже.",
"Add \"%s\" as trusted domain" : "Добавить \"%s\" как доверенный домен",
"App update required" : "Требуется обновление приложения",
"%s will be updated to version %s" : "%s будет обновлен до версии %s",
@@ -277,8 +290,8 @@
"The theme %s has been disabled." : "Тема %s была отключена.",
"Please make sure that the database, the config folder and the data folder have been backed up before proceeding." : "Перед продолжением убедитесь, что вы сделали резервную копию базы данных, каталога конфигурации и каталога с данными.",
"Start update" : "Запустить обновление",
- "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Чтобы избежать задержек в крупных установках, вы можете выполнить следующую команду в каталоге установки:",
- "This %s instance is currently in maintenance mode, which may take a while." : "Это %s находится в режиме технического обслуживания, которое может занять некоторое время.",
- "This page will refresh itself when the %s instance is available again." : "Эта страница обновится, когда экземпляр %s снова станет доступен."
+ "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Чтобы избежать тайм-аутов в крупных установках, вместо этого можно выполнить следующую команду в каталоге установки:",
+ "This %s instance is currently in maintenance mode, which may take a while." : "Этот сервер %s находится в режиме технического обслуживания, которое может занять некоторое время.",
+ "This page will refresh itself when the %s instance is available again." : "Эта страница автоматически обновится, когда сервер %s снова станет доступен."
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
} \ No newline at end of file
diff --git a/core/l10n/si_LK.js b/core/l10n/si_LK.js
index ca5b4af1b9a..c142d17a6ca 100644
--- a/core/l10n/si_LK.js
+++ b/core/l10n/si_LK.js
@@ -62,9 +62,8 @@ OC.L10N.register(
"Share" : "බෙදා හදා ගන්න",
"Warning" : "අවවාදය",
"Delete" : "මකා දමන්න",
+ "Rename" : "නැවත නම් කරන්න",
"Add" : "එකතු කරන්න",
- "New password" : "නව මුරපදය",
- "Reset password" : "මුරපදය ප්‍රත්‍යාරම්භ කරන්න",
"Personal" : "පෞද්ගලික",
"Users" : "පරිශීලකයන්",
"Apps" : "යෙදුම්",
@@ -81,6 +80,8 @@ OC.L10N.register(
"Finish setup" : "ස්ථාපනය කිරීම අවසන් කරන්න",
"Log out" : "නික්මීම",
"Search" : "සොයන්න",
- "Log in" : "ප්‍රවේශවන්න"
+ "Log in" : "ප්‍රවේශවන්න",
+ "New password" : "නව මුරපදය",
+ "Reset password" : "මුරපදය ප්‍රත්‍යාරම්භ කරන්න"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/si_LK.json b/core/l10n/si_LK.json
index f28f0086eba..5c2529c9557 100644
--- a/core/l10n/si_LK.json
+++ b/core/l10n/si_LK.json
@@ -60,9 +60,8 @@
"Share" : "බෙදා හදා ගන්න",
"Warning" : "අවවාදය",
"Delete" : "මකා දමන්න",
+ "Rename" : "නැවත නම් කරන්න",
"Add" : "එකතු කරන්න",
- "New password" : "නව මුරපදය",
- "Reset password" : "මුරපදය ප්‍රත්‍යාරම්භ කරන්න",
"Personal" : "පෞද්ගලික",
"Users" : "පරිශීලකයන්",
"Apps" : "යෙදුම්",
@@ -79,6 +78,8 @@
"Finish setup" : "ස්ථාපනය කිරීම අවසන් කරන්න",
"Log out" : "නික්මීම",
"Search" : "සොයන්න",
- "Log in" : "ප්‍රවේශවන්න"
+ "Log in" : "ප්‍රවේශවන්න",
+ "New password" : "නව මුරපදය",
+ "Reset password" : "මුරපදය ප්‍රත්‍යාරම්භ කරන්න"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/sk_SK.js b/core/l10n/sk_SK.js
index 2968a570a25..0c68ac2fd6b 100644
--- a/core/l10n/sk_SK.js
+++ b/core/l10n/sk_SK.js
@@ -16,8 +16,6 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "Aktualizované \"%s\" na %s",
"Repair warning: " : "Oznámenie opravy:",
"Repair error: " : "Chyba opravy:",
- "Set log level to debug - current level: \"%s\"" : "Nastaviť úroveň záznamu na debug - aktuálna úroveň: \"%s\"",
- "Reset log level to \"%s\"" : "Vrátiť úroveň záznamu na „%s“",
"%s (3rdparty)" : "%s (od tretej strany)",
"%s (incompatible)" : "%s (nekompatibilná)",
"Following apps have been disabled: %s" : "Nasledovné aplikácie boli zakázané: %s",
@@ -32,6 +30,11 @@ OC.L10N.register(
"No crop data provided" : "Dáta pre orezanie neboli zadané",
"No valid crop data provided" : "Neplatné dáta pre orezanie neboli zadané",
"Crop is not square" : "Orezanie nie je štvorcové",
+ "Couldn't reset password because the token is invalid" : "Nemožno zmeniť heslo pre neplatnosť tokenu.",
+ "Couldn't reset password because the token is expired" : "Nepodarilo sa obnoviť heslo, pretože platnosť tokenu uplynula.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nemožno poslať email pre obnovu. Uistite sa, či vkladáte správne používateľské meno.",
+ "%s password reset" : "reset hesla %s",
+ "Couldn't send reset email. Please contact your administrator." : "Nemožno poslať email pre obnovu. Kontaktujte prosím vášho administrátora.",
"Sunday" : "Nedeľa",
"Monday" : "Pondelok",
"Tuesday" : "Utorok",
@@ -80,7 +83,6 @@ OC.L10N.register(
"Settings" : "Nastavenia",
"Saving..." : "Ukladám...",
"seconds ago" : "pred sekundami",
- "Couldn't send reset email. Please contact your administrator." : "Nemožno poslať email pre obnovu. Kontaktujte prosím vášho administrátora.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Odkaz na obnovu hesla bol odoslaný na váš email. Pokiaľ ho neobdržíte v primeranom čase, skontrolujte spam / priečinok nevyžiadanej pošty. <br> Ak tam nie je, kontaktujte svojho administrátora.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Súbory sú zašifrované. Ak ste nepovolili kľúč pre obnovenie, neexistuje žiadny spôsob, ako obnoviť vaše dáta po obnovení vášho hesla. <br /> Ak si nie ste istí čo urobiť, prosím skôr než budete pokračovať, obráťte sa na administrátora. <br /> Naozaj chcete pokračovať?",
"I know what I'm doing" : "Viem, čo robím",
@@ -111,14 +113,12 @@ OC.L10N.register(
"Your web server is not yet set up properly 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é.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Server nemá funkčné pripojenie k internetu. Niektoré moduly ako napr. externé úložisko, oznámenie o dostupných aktualizáciách alebo inštalácia aplikácií tretích strán nebudú fungovať. Vzdialený prístup k súborom a odosielanie oznamovacích emailov tiež nemusí fungovať. Ak chcete využívať všetky funkcie, odporúčame povoliť tomuto serveru pripojenie k internetu.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Váš priečinok s dátami aj vaše súbory sú pravdepodobne prístupné z internetu. Súbor .htaccess nefunguje. Dôrazne odporúčame nakonfigurovať webový server tak, aby priečinok s dátami nebol naďalej prístupný alebo presunúť priečinok s dátami mimo priestoru, ktorý webový server sprístupňuje.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP nedokáže čítať z /dev/urandom, čo sa z bezpečnostných dôvodov dôrazne neodporúča. Ďalšie informácie nájdete v našej <a href=\"{docLink}\">dokumentácii</a>.",
"Error occurred while checking server setup" : "Počas kontroly nastavenia serveru sa stala chyba",
"Shared" : "Zdieľané",
"Shared with {recipients}" : "Zdieľa s {recipients}",
"Error" : "Chyba",
"Error while sharing" : "Chyba počas zdieľania",
"Error while unsharing" : "Chyba počas ukončenia zdieľania",
- "Error while changing permissions" : "Chyba počas zmeny oprávnení",
"Error setting expiration date" : "Chyba pri nastavení dátumu expirácie",
"The public link will expire no later than {days} days after it is created" : "Verejný odkaz nevyprší skôr než za {days} dní po vytvorení",
"Set expiration date" : "Nastaviť dátum expirácie",
@@ -137,7 +137,6 @@ OC.L10N.register(
"Send" : "Odoslať",
"Shared with you and the group {group} by {owner}" : "Zdieľané s vami a so skupinou {group} používateľom {owner}",
"Shared with you by {owner}" : "Zdieľané s vami používateľom {owner}",
- "Shared in {item} with {user}" : "Zdieľané v {item} s {user}",
"group" : "skupina",
"remote" : "vzdialený",
"notify by email" : "informovať emailom",
@@ -156,9 +155,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Zdieľať s používateľmi, skupinami alebo vzdialenými používateľmi ...",
"Warning" : "Varovanie",
"Error while sending notification" : "Chyba pri posielaní oznámenia",
+ "Delete" : "Zmazať",
+ "Rename" : "Premenovať",
"The object type is not specified." : "Nešpecifikovaný typ objektu.",
"Enter new" : "Zadať nový",
- "Delete" : "Zmazať",
"Add" : "Pridať",
"Edit tags" : "Upraviť štítky",
"Error loading dialog template: {error}" : "Chyba pri načítaní šablóny dialógu: {error}",
@@ -177,15 +177,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Aktualizácia bola neúspešná.",
"The update was successful. There were warnings." : "Aktualizácia bola úspešná. Vyskytli sa upozornenia.",
"The update was successful. Redirecting you to ownCloud now." : "Aktualizácia bola úspešná. Presmerovávam vás na prihlasovaciu stránku.",
- "Couldn't reset password because the token is invalid" : "Nemožno zmeniť heslo pre neplatnosť tokenu.",
- "Couldn't reset password because the token is expired" : "Nepodarilo sa obnoviť heslo, pretože platnosť tokenu uplynula.",
- "Couldn't send reset email. Please make sure your username is correct." : "Nemožno poslať email pre obnovu. Uistite sa, či vkladáte správne používateľské meno.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nemožno poslať email pre obnovu hesla, pretože pre tohoto používateľa nie je uvedená žiadna emailová adresa. Prosím, obráťte sa na administrátora.",
- "%s password reset" : "reset hesla %s",
- "Use the following link to reset your password: {link}" : "Použite nasledujúci odkaz pre obnovenie vášho hesla: {link}",
- "New password" : "Nové heslo",
- "New Password" : "Nové heslo",
- "Reset password" : "Obnovenie hesla",
"Searching other places" : "Prehľadanie ostatných umiestnení",
"No search results in other folders" : "Žiadne výsledky vyhľadávania v ostatných priečinkoch",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} výsledok vyhľadávania v ostatných priečinkoch","{count} výsledky vyhľadávania v ostatných priečinkoch","{count} výsledkov vyhľadávania v ostatných priečinkoch"],
@@ -257,6 +248,10 @@ OC.L10N.register(
"Wrong password. Reset it?" : "Chybné heslo. Chcete ho obnoviť?",
"Stay logged in" : "Zostať prihlásený",
"Alternative Logins" : "Alternatívne prihlásenie",
+ "Use the following link to reset your password: {link}" : "Použite nasledujúci odkaz pre obnovenie vášho hesla: {link}",
+ "New password" : "Nové heslo",
+ "New Password" : "Nové heslo",
+ "Reset password" : "Obnovenie hesla",
"This ownCloud instance is currently in single user mode." : "Táto inštancia ownCloudu je teraz v jednopoužívateľskom móde.",
"This means only administrators can use the instance." : "Len správca systému môže používať túto inštanciu.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktujte prosím správcu systému, ak sa táto správa objavuje opakovane alebo neočakávane.",
diff --git a/core/l10n/sk_SK.json b/core/l10n/sk_SK.json
index 537985d28ed..c9a24cc78cb 100644
--- a/core/l10n/sk_SK.json
+++ b/core/l10n/sk_SK.json
@@ -14,8 +14,6 @@
"Updated \"%s\" to %s" : "Aktualizované \"%s\" na %s",
"Repair warning: " : "Oznámenie opravy:",
"Repair error: " : "Chyba opravy:",
- "Set log level to debug - current level: \"%s\"" : "Nastaviť úroveň záznamu na debug - aktuálna úroveň: \"%s\"",
- "Reset log level to \"%s\"" : "Vrátiť úroveň záznamu na „%s“",
"%s (3rdparty)" : "%s (od tretej strany)",
"%s (incompatible)" : "%s (nekompatibilná)",
"Following apps have been disabled: %s" : "Nasledovné aplikácie boli zakázané: %s",
@@ -30,6 +28,11 @@
"No crop data provided" : "Dáta pre orezanie neboli zadané",
"No valid crop data provided" : "Neplatné dáta pre orezanie neboli zadané",
"Crop is not square" : "Orezanie nie je štvorcové",
+ "Couldn't reset password because the token is invalid" : "Nemožno zmeniť heslo pre neplatnosť tokenu.",
+ "Couldn't reset password because the token is expired" : "Nepodarilo sa obnoviť heslo, pretože platnosť tokenu uplynula.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nemožno poslať email pre obnovu. Uistite sa, či vkladáte správne používateľské meno.",
+ "%s password reset" : "reset hesla %s",
+ "Couldn't send reset email. Please contact your administrator." : "Nemožno poslať email pre obnovu. Kontaktujte prosím vášho administrátora.",
"Sunday" : "Nedeľa",
"Monday" : "Pondelok",
"Tuesday" : "Utorok",
@@ -78,7 +81,6 @@
"Settings" : "Nastavenia",
"Saving..." : "Ukladám...",
"seconds ago" : "pred sekundami",
- "Couldn't send reset email. Please contact your administrator." : "Nemožno poslať email pre obnovu. Kontaktujte prosím vášho administrátora.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Odkaz na obnovu hesla bol odoslaný na váš email. Pokiaľ ho neobdržíte v primeranom čase, skontrolujte spam / priečinok nevyžiadanej pošty. <br> Ak tam nie je, kontaktujte svojho administrátora.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Súbory sú zašifrované. Ak ste nepovolili kľúč pre obnovenie, neexistuje žiadny spôsob, ako obnoviť vaše dáta po obnovení vášho hesla. <br /> Ak si nie ste istí čo urobiť, prosím skôr než budete pokračovať, obráťte sa na administrátora. <br /> Naozaj chcete pokračovať?",
"I know what I'm doing" : "Viem, čo robím",
@@ -109,14 +111,12 @@
"Your web server is not yet set up properly 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é.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Server nemá funkčné pripojenie k internetu. Niektoré moduly ako napr. externé úložisko, oznámenie o dostupných aktualizáciách alebo inštalácia aplikácií tretích strán nebudú fungovať. Vzdialený prístup k súborom a odosielanie oznamovacích emailov tiež nemusí fungovať. Ak chcete využívať všetky funkcie, odporúčame povoliť tomuto serveru pripojenie k internetu.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Váš priečinok s dátami aj vaše súbory sú pravdepodobne prístupné z internetu. Súbor .htaccess nefunguje. Dôrazne odporúčame nakonfigurovať webový server tak, aby priečinok s dátami nebol naďalej prístupný alebo presunúť priečinok s dátami mimo priestoru, ktorý webový server sprístupňuje.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP nedokáže čítať z /dev/urandom, čo sa z bezpečnostných dôvodov dôrazne neodporúča. Ďalšie informácie nájdete v našej <a href=\"{docLink}\">dokumentácii</a>.",
"Error occurred while checking server setup" : "Počas kontroly nastavenia serveru sa stala chyba",
"Shared" : "Zdieľané",
"Shared with {recipients}" : "Zdieľa s {recipients}",
"Error" : "Chyba",
"Error while sharing" : "Chyba počas zdieľania",
"Error while unsharing" : "Chyba počas ukončenia zdieľania",
- "Error while changing permissions" : "Chyba počas zmeny oprávnení",
"Error setting expiration date" : "Chyba pri nastavení dátumu expirácie",
"The public link will expire no later than {days} days after it is created" : "Verejný odkaz nevyprší skôr než za {days} dní po vytvorení",
"Set expiration date" : "Nastaviť dátum expirácie",
@@ -135,7 +135,6 @@
"Send" : "Odoslať",
"Shared with you and the group {group} by {owner}" : "Zdieľané s vami a so skupinou {group} používateľom {owner}",
"Shared with you by {owner}" : "Zdieľané s vami používateľom {owner}",
- "Shared in {item} with {user}" : "Zdieľané v {item} s {user}",
"group" : "skupina",
"remote" : "vzdialený",
"notify by email" : "informovať emailom",
@@ -154,9 +153,10 @@
"Share with users, groups or remote users …" : "Zdieľať s používateľmi, skupinami alebo vzdialenými používateľmi ...",
"Warning" : "Varovanie",
"Error while sending notification" : "Chyba pri posielaní oznámenia",
+ "Delete" : "Zmazať",
+ "Rename" : "Premenovať",
"The object type is not specified." : "Nešpecifikovaný typ objektu.",
"Enter new" : "Zadať nový",
- "Delete" : "Zmazať",
"Add" : "Pridať",
"Edit tags" : "Upraviť štítky",
"Error loading dialog template: {error}" : "Chyba pri načítaní šablóny dialógu: {error}",
@@ -175,15 +175,6 @@
"The update was unsuccessful. " : "Aktualizácia bola neúspešná.",
"The update was successful. There were warnings." : "Aktualizácia bola úspešná. Vyskytli sa upozornenia.",
"The update was successful. Redirecting you to ownCloud now." : "Aktualizácia bola úspešná. Presmerovávam vás na prihlasovaciu stránku.",
- "Couldn't reset password because the token is invalid" : "Nemožno zmeniť heslo pre neplatnosť tokenu.",
- "Couldn't reset password because the token is expired" : "Nepodarilo sa obnoviť heslo, pretože platnosť tokenu uplynula.",
- "Couldn't send reset email. Please make sure your username is correct." : "Nemožno poslať email pre obnovu. Uistite sa, či vkladáte správne používateľské meno.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nemožno poslať email pre obnovu hesla, pretože pre tohoto používateľa nie je uvedená žiadna emailová adresa. Prosím, obráťte sa na administrátora.",
- "%s password reset" : "reset hesla %s",
- "Use the following link to reset your password: {link}" : "Použite nasledujúci odkaz pre obnovenie vášho hesla: {link}",
- "New password" : "Nové heslo",
- "New Password" : "Nové heslo",
- "Reset password" : "Obnovenie hesla",
"Searching other places" : "Prehľadanie ostatných umiestnení",
"No search results in other folders" : "Žiadne výsledky vyhľadávania v ostatných priečinkoch",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} výsledok vyhľadávania v ostatných priečinkoch","{count} výsledky vyhľadávania v ostatných priečinkoch","{count} výsledkov vyhľadávania v ostatných priečinkoch"],
@@ -255,6 +246,10 @@
"Wrong password. Reset it?" : "Chybné heslo. Chcete ho obnoviť?",
"Stay logged in" : "Zostať prihlásený",
"Alternative Logins" : "Alternatívne prihlásenie",
+ "Use the following link to reset your password: {link}" : "Použite nasledujúci odkaz pre obnovenie vášho hesla: {link}",
+ "New password" : "Nové heslo",
+ "New Password" : "Nové heslo",
+ "Reset password" : "Obnovenie hesla",
"This ownCloud instance is currently in single user mode." : "Táto inštancia ownCloudu je teraz v jednopoužívateľskom móde.",
"This means only administrators can use the instance." : "Len správca systému môže používať túto inštanciu.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktujte prosím správcu systému, ak sa táto správa objavuje opakovane alebo neočakávane.",
diff --git a/core/l10n/sl.js b/core/l10n/sl.js
index 3398a9bd2ee..4ebac59a392 100644
--- a/core/l10n/sl.js
+++ b/core/l10n/sl.js
@@ -2,17 +2,42 @@ OC.L10N.register(
"core",
{
"Couldn't send mail to following users: %s " : "Ni mogoče poslati sporočila za: %s",
+ "Preparing update" : "Pripravljanje posodobitve",
"Turned on maintenance mode" : "Vzdrževalni način je omogočen",
"Turned off maintenance mode" : "Vzdrževalni način je onemogočen",
+ "Maintenance mode is kept active" : "Vzdrževalni način je še vedno dejaven",
+ "Updating database schema" : "Poteka posodabljanje sheme podatkovne zbirke",
"Updated database" : "Posodobljena podatkovna zbirka",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "Preverjam, ali lahko posodobim strukturo baze (lahko traja dlje zaradi velikosti baze)",
"Checked database schema update" : "Izbrana posodobitev sheme podatkovne zbirke",
+ "Checking updates of apps" : "Poteka preverjanje za posodobitve programov",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "Preverjam, ali lahko posodobim strukturo baze za %s (lahko traja dlje zaradi velikosti baze)",
"Checked database schema update for apps" : "Izbrana posodobitev sheme podatkovne zbirke za programe",
"Updated \"%s\" to %s" : "Datoteka \"%s\" je posodobljena na %s",
+ "Repair warning: " : "Opozorilo popravila:",
+ "Repair error: " : "Napaka popravila:",
+ "Set log level to debug" : "Nastavi raven beleženja za razhroščevanje",
+ "Reset log level" : "Počisti raven beleženja",
+ "%s (3rdparty)" : "%s (zunanje)",
+ "%s (incompatible)" : "%s (neskladno)",
+ "Following apps have been disabled: %s" : "Navedeni programi so onemogočeni: %s",
+ "Already up to date" : "Sistem je že posodobljen",
+ "Please select a file." : "Izberite datoteko",
+ "File is too big" : "Datoteka je prevelika",
+ "Invalid file provided" : "Predložena je neveljavna datoteka",
"No image or file provided" : "Ni podane datoteke ali slike",
"Unknown filetype" : "Neznana vrsta datoteke",
"Invalid image" : "Neveljavna slika",
+ "An error occurred. Please contact your admin." : "Prišlo je do napake. Stopite v stik s skrbnikom sistema.",
"No temporary profile picture available, try again" : "Na voljo ni nobene začasne slike za profil. Poskusite znova.",
"No crop data provided" : "Ni podanih podatkov obreza",
+ "No valid crop data provided" : "Napačni podatki za obrez slike",
+ "Crop is not square" : "Obrez ni pravokoten",
+ "Couldn't reset password because the token is invalid" : "Ni mogoče ponastaviti gesla zaradi neustreznega žetona.",
+ "Couldn't reset password because the token is expired" : "Ni mogoče ponastaviti gesla, ker je žeton potekel.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Ni mogoče poslati elektronskega sporočila. Prepričajte se, da je uporabniško ime pravilno.",
+ "%s password reset" : "Ponastavitev gesla %s",
+ "Couldn't send reset email. Please contact your administrator." : "Ni mogoče nastaviti elektronskega naslova za ponastavitev. Stopite v stik s skrbnikom sistema.",
"Sunday" : "nedelja",
"Monday" : "ponedeljek",
"Tuesday" : "torek",
@@ -27,6 +52,13 @@ OC.L10N.register(
"Thu." : "čet",
"Fri." : "pet",
"Sat." : "sob",
+ "Su" : "Ne",
+ "Mo" : "Po",
+ "Tu" : "To",
+ "We" : "Sr",
+ "Th" : "Če",
+ "Fr" : "Pe",
+ "Sa" : "So",
"January" : "januar",
"February" : "februar",
"March" : "marec",
@@ -54,7 +86,6 @@ OC.L10N.register(
"Settings" : "Nastavitve",
"Saving..." : "Poteka shranjevanje ...",
"seconds ago" : "pred nekaj sekundami",
- "Couldn't send reset email. Please contact your administrator." : "Ni mogoče nastaviti elektronskega naslova za ponastavitev. Stopite v stik s skrbnikom sistema.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Povezava za ponastavitev gesla je bila poslana na naveden elektronski naslov. V kolikor sporočila ne dobite v kratkem, preverite tudi mapo neželene pošte.<br> Če sporočila ni niti v tej mapi, stopite v stik s skrbnikom.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Datoteke so šifrirane. Če niste omogočili obnovitvenega ključa, po ponastavitvi gesla ne bo mogoč dostop do datotek.<br />V primeru, da niste prepričani, kaj storiti, stopite v stik s skrbnikom sistema.<br />Ali ste prepričani, da želite nadaljevati?",
"I know what I'm doing" : "Vem, kaj delam!",
@@ -88,7 +119,6 @@ OC.L10N.register(
"Error" : "Napaka",
"Error while sharing" : "Napaka med souporabo",
"Error while unsharing" : "Napaka med odstranjevanjem souporabe",
- "Error while changing permissions" : "Napaka med spreminjanjem dovoljenj",
"Error setting expiration date" : "Napaka nastavljanja datuma preteka",
"The public link will expire no later than {days} days after it is created" : "Javna povezava bo potekla {days} dni po ustvarjanju.",
"Set expiration date" : "Nastavi datum preteka",
@@ -107,7 +137,6 @@ OC.L10N.register(
"Send" : "Pošlji",
"Shared with you and the group {group} by {owner}" : "V souporabi z vami in skupino {group}. Lastnik je {owner}.",
"Shared with you by {owner}" : "V souporabi z vami. Lastnik je {owner}.",
- "Shared in {item} with {user}" : "V souporabi v {item} z uporabnikom {user}",
"group" : "skupina",
"remote" : "oddaljeno",
"notify by email" : "obvesti po elektronski pošti",
@@ -118,11 +147,18 @@ OC.L10N.register(
"change" : "sprememba",
"delete" : "izbriše",
"access control" : "nadzor dostopa",
+ "Share details could not be loaded for this item." : "Detajlov souporabe ne morem naložiti za ta element.",
+ "An error occured. Please try again" : "Prišlo je do napake. Poskusite znova.",
"Share" : "Souporaba",
+ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Soupraba z ljudmi v drugih ownCloud oblakih v formatu uporabnik@domena.si/owncloud",
+ "Share with users or groups …" : "Souporaba z uporabniki ali skupinami ...",
+ "Share with users, groups or remote users …" : "Souporaba z usporabniki, skupinami ali zunanjimi uporabniki ...",
"Warning" : "Opozorilo",
+ "Error while sending notification" : "Napaka med pošiljanjem obvestila",
+ "Delete" : "Izbriši",
+ "Rename" : "Preimenuj",
"The object type is not specified." : "Vrsta predmeta ni podana.",
"Enter new" : "Vnesite novo",
- "Delete" : "Izbriši",
"Add" : "Dodaj",
"Edit tags" : "Uredi oznake",
"Error loading dialog template: {error}" : "Napaka nalaganja predloge pogovornega okna: {error}",
@@ -133,19 +169,17 @@ OC.L10N.register(
"Hello {name}, the weather is {weather}" : "Pozdravljeni, {name}, vreme je {weather}",
"Hello {name}" : "Pozdravljeni, {name}",
"_download %n file_::_download %n files_" : ["prejmi %n datoteko","prejmi %n datoteki","prejmi %n datoteke","prejmi %n datotek"],
+ "{version} is available. Get more information on how to update." : "Na voljo je verzija {version}. Pridobite informacije, kako nadgraditi.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Posodobitev sistema je v teku. Če zapustite stran, lahko v nekaterih okoljih prekine ta proces.",
"Updating {productName} to version {version}, this may take a while." : "Poteka posodabljanje {productName} na različico {version}. Opravilo je lahko dolgotrajno.",
+ "An error occurred." : "Prišlo je do napake.",
"Please reload the page." : "Stran je treba ponovno naložiti",
"The update was unsuccessful. " : "Posodobitev je spodletela.",
+ "The update was successful. There were warnings." : "Posodobitev je uspela. Z nekaj opozorili.",
"The update was successful. Redirecting you to ownCloud now." : "Posodobitev je uspešno končana. Stran bo preusmerjena na oblak ownCloud.",
- "Couldn't reset password because the token is invalid" : "Ni mogoče ponastaviti gesla zaradi neustreznega žetona.",
- "Couldn't send reset email. Please make sure your username is correct." : "Ni mogoče poslati elektronskega sporočila. Prepričajte se, da je uporabniško ime pravilno.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Ni mogoče poslati elektronskega sporočila za ponastavitev gesla, ker ni navedenega elektronskega naslova. Stopite v stik s skrbnikom sistema.",
- "%s password reset" : "Ponastavitev gesla %s",
- "Use the following link to reset your password: {link}" : "Za ponastavitev gesla uporabite povezavo: {link}",
- "New password" : "Novo geslo",
- "New Password" : "Novo geslo",
- "Reset password" : "Ponastavi geslo",
"Searching other places" : "Iskanje drugih mest",
+ "No search results in other folders" : "Iskanje po drugih mapah ni vrnilo rezultata",
+ "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} rezultat v drugih mapah","{count} rezultata v drugih mapah","{count} rezultatov v drugih mapah","{count} rezultatov v drugih mapah"],
"Personal" : "Osebno",
"Users" : "Uporabniki",
"Apps" : "Programi",
@@ -172,11 +206,13 @@ OC.L10N.register(
"Technical details" : "Tehnične podrobnosti",
"Remote Address: %s" : "Oddaljen naslov: %s",
"Request ID: %s" : "ID zahteve: %s",
+ "Type: %s" : "Vrsta: %s",
"Code: %s" : "Koda: %s",
"Message: %s" : "Sporočilo: %s",
"File: %s" : "Datoteka: %s",
"Line: %s" : "Vrstica: %s",
"Trace" : "Sledenje povezav",
+ "Security warning" : "Varnostno opozorilo",
"Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Podatkovna mapa in datoteke so najverjetneje javno dostopni preko interneta, saj datoteka .htaccess ni ustrezno nastavljena.",
"For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "Za več informacij o pravilnem nastavljanju strežnika, kliknite na povezavo do <a href=\"%s\" target=\"_blank\">dokumentacije</a>.",
"Create an <strong>admin account</strong>" : "Ustvari <strong>skrbniški račun</strong>",
@@ -190,16 +226,28 @@ OC.L10N.register(
"Database name" : "Ime podatkovne zbirke",
"Database tablespace" : "Razpredelnica podatkovne zbirke",
"Database host" : "Gostitelj podatkovne zbirke",
+ "Performance warning" : "Opozorilo učinkovitosti delovanja",
"SQLite will be used as database." : "Kot podatkovna zbirka bo uporabljena zbirka SQLite",
"Finish setup" : "Končaj nastavitev",
"Finishing …" : "Poteka zaključevanje opravila ...",
+ "Need help?" : "Ali potrebujete pomoč?",
+ "See the documentation" : "Preverite dokumentacijo",
"Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Pozdravljeni,<br><br>uporabnik %s vam je omogočil souporabo <strong>%s</strong>.<br><a href=\"%s\">Oglejte si vsebino!</a><br><br>",
"Log out" : "Odjava",
"Search" : "Poišči",
"Server side authentication failed!" : "Overitev s strežnika je spodletela!",
"Please contact your administrator." : "Stopite v stik s skrbnikom sistema.",
+ "An internal error occured." : "Prišlo je do notranje napake.",
+ "Please try again or contact your administrator." : "Poskusite znova ali pa stopite v stik s skrbnikom sistema.",
"Log in" : "Prijava",
+ "Wrong password. Reset it?" : "Napačno gelo. Ponastavimo?",
+ "Wrong password." : "Napačno geslo!",
+ "Stay logged in" : "Ohrani prijavo",
"Alternative Logins" : "Druge prijavne možnosti",
+ "Use the following link to reset your password: {link}" : "Za ponastavitev gesla uporabite povezavo: {link}",
+ "New password" : "Novo geslo",
+ "New Password" : "Novo geslo",
+ "Reset password" : "Ponastavi geslo",
"This ownCloud instance is currently in single user mode." : "Ta seja oblaka ownCloud je trenutno v načinu enega sočasnega uporabnika.",
"This means only administrators can use the instance." : "To pomeni, da lahko oblak uporabljajo le osebe s skrbniškimi dovoljenji.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Stopite v stik s skrbnikom sistema, če se bo sporočilo še naprej nepričakovano prikazovalo.",
@@ -207,10 +255,15 @@ OC.L10N.register(
"You are accessing the server from an untrusted domain." : "Trenutno je vzpostavljena povezava s strežnikom preko ne-varne domene.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Glede na nastavitve bi lahko kot skrbnik uporabili spodnji gumb in domeno ročno določili kot varno.",
"Add \"%s\" as trusted domain" : "Dodaj \"%s\" kot varno domeno",
+ "App update required" : "Zahtevana je posodobitev programa",
+ "%s will be updated to version %s" : "%s bo posodbljena na verzijo %s",
+ "These apps will be updated:" : "Te aplikacije bodo posodbljene:",
+ "These incompatible apps will be disabled:" : "Te neskladne aplikacije bodo onemogočene:",
"The theme %s has been disabled." : "Tema %s je onemogočena za uporabo.",
"Please make sure that the database, the config folder and the data folder have been backed up before proceeding." : "Pred nadaljevanjem se prepričajte se, da je ustvarjena varnostna kopija podatkovne zbirke, nastavitvenih datotek in podatkovne mape.",
"Start update" : "Začni posodobitev",
"To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Za razreševanje časovnih zahtev večjih namestitev lahko uporabite ukaz iz namestitvene mape:",
+ "This %s instance is currently in maintenance mode, which may take a while." : "Ta %s strežnik je trenutno v načinu vzdrževanja, kar lahko traja dlje časa.",
"This page will refresh itself when the %s instance is available again." : "Stran bo osvežena ko bo %s spet na voljo."
},
"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);");
diff --git a/core/l10n/sl.json b/core/l10n/sl.json
index 866a6dca670..e79552dfbdd 100644
--- a/core/l10n/sl.json
+++ b/core/l10n/sl.json
@@ -1,16 +1,41 @@
{ "translations": {
"Couldn't send mail to following users: %s " : "Ni mogoče poslati sporočila za: %s",
+ "Preparing update" : "Pripravljanje posodobitve",
"Turned on maintenance mode" : "Vzdrževalni način je omogočen",
"Turned off maintenance mode" : "Vzdrževalni način je onemogočen",
+ "Maintenance mode is kept active" : "Vzdrževalni način je še vedno dejaven",
+ "Updating database schema" : "Poteka posodabljanje sheme podatkovne zbirke",
"Updated database" : "Posodobljena podatkovna zbirka",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "Preverjam, ali lahko posodobim strukturo baze (lahko traja dlje zaradi velikosti baze)",
"Checked database schema update" : "Izbrana posodobitev sheme podatkovne zbirke",
+ "Checking updates of apps" : "Poteka preverjanje za posodobitve programov",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "Preverjam, ali lahko posodobim strukturo baze za %s (lahko traja dlje zaradi velikosti baze)",
"Checked database schema update for apps" : "Izbrana posodobitev sheme podatkovne zbirke za programe",
"Updated \"%s\" to %s" : "Datoteka \"%s\" je posodobljena na %s",
+ "Repair warning: " : "Opozorilo popravila:",
+ "Repair error: " : "Napaka popravila:",
+ "Set log level to debug" : "Nastavi raven beleženja za razhroščevanje",
+ "Reset log level" : "Počisti raven beleženja",
+ "%s (3rdparty)" : "%s (zunanje)",
+ "%s (incompatible)" : "%s (neskladno)",
+ "Following apps have been disabled: %s" : "Navedeni programi so onemogočeni: %s",
+ "Already up to date" : "Sistem je že posodobljen",
+ "Please select a file." : "Izberite datoteko",
+ "File is too big" : "Datoteka je prevelika",
+ "Invalid file provided" : "Predložena je neveljavna datoteka",
"No image or file provided" : "Ni podane datoteke ali slike",
"Unknown filetype" : "Neznana vrsta datoteke",
"Invalid image" : "Neveljavna slika",
+ "An error occurred. Please contact your admin." : "Prišlo je do napake. Stopite v stik s skrbnikom sistema.",
"No temporary profile picture available, try again" : "Na voljo ni nobene začasne slike za profil. Poskusite znova.",
"No crop data provided" : "Ni podanih podatkov obreza",
+ "No valid crop data provided" : "Napačni podatki za obrez slike",
+ "Crop is not square" : "Obrez ni pravokoten",
+ "Couldn't reset password because the token is invalid" : "Ni mogoče ponastaviti gesla zaradi neustreznega žetona.",
+ "Couldn't reset password because the token is expired" : "Ni mogoče ponastaviti gesla, ker je žeton potekel.",
+ "Couldn't send reset email. Please make sure your username is correct." : "Ni mogoče poslati elektronskega sporočila. Prepričajte se, da je uporabniško ime pravilno.",
+ "%s password reset" : "Ponastavitev gesla %s",
+ "Couldn't send reset email. Please contact your administrator." : "Ni mogoče nastaviti elektronskega naslova za ponastavitev. Stopite v stik s skrbnikom sistema.",
"Sunday" : "nedelja",
"Monday" : "ponedeljek",
"Tuesday" : "torek",
@@ -25,6 +50,13 @@
"Thu." : "čet",
"Fri." : "pet",
"Sat." : "sob",
+ "Su" : "Ne",
+ "Mo" : "Po",
+ "Tu" : "To",
+ "We" : "Sr",
+ "Th" : "Če",
+ "Fr" : "Pe",
+ "Sa" : "So",
"January" : "januar",
"February" : "februar",
"March" : "marec",
@@ -52,7 +84,6 @@
"Settings" : "Nastavitve",
"Saving..." : "Poteka shranjevanje ...",
"seconds ago" : "pred nekaj sekundami",
- "Couldn't send reset email. Please contact your administrator." : "Ni mogoče nastaviti elektronskega naslova za ponastavitev. Stopite v stik s skrbnikom sistema.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Povezava za ponastavitev gesla je bila poslana na naveden elektronski naslov. V kolikor sporočila ne dobite v kratkem, preverite tudi mapo neželene pošte.<br> Če sporočila ni niti v tej mapi, stopite v stik s skrbnikom.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Datoteke so šifrirane. Če niste omogočili obnovitvenega ključa, po ponastavitvi gesla ne bo mogoč dostop do datotek.<br />V primeru, da niste prepričani, kaj storiti, stopite v stik s skrbnikom sistema.<br />Ali ste prepričani, da želite nadaljevati?",
"I know what I'm doing" : "Vem, kaj delam!",
@@ -86,7 +117,6 @@
"Error" : "Napaka",
"Error while sharing" : "Napaka med souporabo",
"Error while unsharing" : "Napaka med odstranjevanjem souporabe",
- "Error while changing permissions" : "Napaka med spreminjanjem dovoljenj",
"Error setting expiration date" : "Napaka nastavljanja datuma preteka",
"The public link will expire no later than {days} days after it is created" : "Javna povezava bo potekla {days} dni po ustvarjanju.",
"Set expiration date" : "Nastavi datum preteka",
@@ -105,7 +135,6 @@
"Send" : "Pošlji",
"Shared with you and the group {group} by {owner}" : "V souporabi z vami in skupino {group}. Lastnik je {owner}.",
"Shared with you by {owner}" : "V souporabi z vami. Lastnik je {owner}.",
- "Shared in {item} with {user}" : "V souporabi v {item} z uporabnikom {user}",
"group" : "skupina",
"remote" : "oddaljeno",
"notify by email" : "obvesti po elektronski pošti",
@@ -116,11 +145,18 @@
"change" : "sprememba",
"delete" : "izbriše",
"access control" : "nadzor dostopa",
+ "Share details could not be loaded for this item." : "Detajlov souporabe ne morem naložiti za ta element.",
+ "An error occured. Please try again" : "Prišlo je do napake. Poskusite znova.",
"Share" : "Souporaba",
+ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Soupraba z ljudmi v drugih ownCloud oblakih v formatu uporabnik@domena.si/owncloud",
+ "Share with users or groups …" : "Souporaba z uporabniki ali skupinami ...",
+ "Share with users, groups or remote users …" : "Souporaba z usporabniki, skupinami ali zunanjimi uporabniki ...",
"Warning" : "Opozorilo",
+ "Error while sending notification" : "Napaka med pošiljanjem obvestila",
+ "Delete" : "Izbriši",
+ "Rename" : "Preimenuj",
"The object type is not specified." : "Vrsta predmeta ni podana.",
"Enter new" : "Vnesite novo",
- "Delete" : "Izbriši",
"Add" : "Dodaj",
"Edit tags" : "Uredi oznake",
"Error loading dialog template: {error}" : "Napaka nalaganja predloge pogovornega okna: {error}",
@@ -131,19 +167,17 @@
"Hello {name}, the weather is {weather}" : "Pozdravljeni, {name}, vreme je {weather}",
"Hello {name}" : "Pozdravljeni, {name}",
"_download %n file_::_download %n files_" : ["prejmi %n datoteko","prejmi %n datoteki","prejmi %n datoteke","prejmi %n datotek"],
+ "{version} is available. Get more information on how to update." : "Na voljo je verzija {version}. Pridobite informacije, kako nadgraditi.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Posodobitev sistema je v teku. Če zapustite stran, lahko v nekaterih okoljih prekine ta proces.",
"Updating {productName} to version {version}, this may take a while." : "Poteka posodabljanje {productName} na različico {version}. Opravilo je lahko dolgotrajno.",
+ "An error occurred." : "Prišlo je do napake.",
"Please reload the page." : "Stran je treba ponovno naložiti",
"The update was unsuccessful. " : "Posodobitev je spodletela.",
+ "The update was successful. There were warnings." : "Posodobitev je uspela. Z nekaj opozorili.",
"The update was successful. Redirecting you to ownCloud now." : "Posodobitev je uspešno končana. Stran bo preusmerjena na oblak ownCloud.",
- "Couldn't reset password because the token is invalid" : "Ni mogoče ponastaviti gesla zaradi neustreznega žetona.",
- "Couldn't send reset email. Please make sure your username is correct." : "Ni mogoče poslati elektronskega sporočila. Prepričajte se, da je uporabniško ime pravilno.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Ni mogoče poslati elektronskega sporočila za ponastavitev gesla, ker ni navedenega elektronskega naslova. Stopite v stik s skrbnikom sistema.",
- "%s password reset" : "Ponastavitev gesla %s",
- "Use the following link to reset your password: {link}" : "Za ponastavitev gesla uporabite povezavo: {link}",
- "New password" : "Novo geslo",
- "New Password" : "Novo geslo",
- "Reset password" : "Ponastavi geslo",
"Searching other places" : "Iskanje drugih mest",
+ "No search results in other folders" : "Iskanje po drugih mapah ni vrnilo rezultata",
+ "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} rezultat v drugih mapah","{count} rezultata v drugih mapah","{count} rezultatov v drugih mapah","{count} rezultatov v drugih mapah"],
"Personal" : "Osebno",
"Users" : "Uporabniki",
"Apps" : "Programi",
@@ -170,11 +204,13 @@
"Technical details" : "Tehnične podrobnosti",
"Remote Address: %s" : "Oddaljen naslov: %s",
"Request ID: %s" : "ID zahteve: %s",
+ "Type: %s" : "Vrsta: %s",
"Code: %s" : "Koda: %s",
"Message: %s" : "Sporočilo: %s",
"File: %s" : "Datoteka: %s",
"Line: %s" : "Vrstica: %s",
"Trace" : "Sledenje povezav",
+ "Security warning" : "Varnostno opozorilo",
"Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "Podatkovna mapa in datoteke so najverjetneje javno dostopni preko interneta, saj datoteka .htaccess ni ustrezno nastavljena.",
"For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "Za več informacij o pravilnem nastavljanju strežnika, kliknite na povezavo do <a href=\"%s\" target=\"_blank\">dokumentacije</a>.",
"Create an <strong>admin account</strong>" : "Ustvari <strong>skrbniški račun</strong>",
@@ -188,16 +224,28 @@
"Database name" : "Ime podatkovne zbirke",
"Database tablespace" : "Razpredelnica podatkovne zbirke",
"Database host" : "Gostitelj podatkovne zbirke",
+ "Performance warning" : "Opozorilo učinkovitosti delovanja",
"SQLite will be used as database." : "Kot podatkovna zbirka bo uporabljena zbirka SQLite",
"Finish setup" : "Končaj nastavitev",
"Finishing …" : "Poteka zaključevanje opravila ...",
+ "Need help?" : "Ali potrebujete pomoč?",
+ "See the documentation" : "Preverite dokumentacijo",
"Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Pozdravljeni,<br><br>uporabnik %s vam je omogočil souporabo <strong>%s</strong>.<br><a href=\"%s\">Oglejte si vsebino!</a><br><br>",
"Log out" : "Odjava",
"Search" : "Poišči",
"Server side authentication failed!" : "Overitev s strežnika je spodletela!",
"Please contact your administrator." : "Stopite v stik s skrbnikom sistema.",
+ "An internal error occured." : "Prišlo je do notranje napake.",
+ "Please try again or contact your administrator." : "Poskusite znova ali pa stopite v stik s skrbnikom sistema.",
"Log in" : "Prijava",
+ "Wrong password. Reset it?" : "Napačno gelo. Ponastavimo?",
+ "Wrong password." : "Napačno geslo!",
+ "Stay logged in" : "Ohrani prijavo",
"Alternative Logins" : "Druge prijavne možnosti",
+ "Use the following link to reset your password: {link}" : "Za ponastavitev gesla uporabite povezavo: {link}",
+ "New password" : "Novo geslo",
+ "New Password" : "Novo geslo",
+ "Reset password" : "Ponastavi geslo",
"This ownCloud instance is currently in single user mode." : "Ta seja oblaka ownCloud je trenutno v načinu enega sočasnega uporabnika.",
"This means only administrators can use the instance." : "To pomeni, da lahko oblak uporabljajo le osebe s skrbniškimi dovoljenji.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Stopite v stik s skrbnikom sistema, če se bo sporočilo še naprej nepričakovano prikazovalo.",
@@ -205,10 +253,15 @@
"You are accessing the server from an untrusted domain." : "Trenutno je vzpostavljena povezava s strežnikom preko ne-varne domene.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Glede na nastavitve bi lahko kot skrbnik uporabili spodnji gumb in domeno ročno določili kot varno.",
"Add \"%s\" as trusted domain" : "Dodaj \"%s\" kot varno domeno",
+ "App update required" : "Zahtevana je posodobitev programa",
+ "%s will be updated to version %s" : "%s bo posodbljena na verzijo %s",
+ "These apps will be updated:" : "Te aplikacije bodo posodbljene:",
+ "These incompatible apps will be disabled:" : "Te neskladne aplikacije bodo onemogočene:",
"The theme %s has been disabled." : "Tema %s je onemogočena za uporabo.",
"Please make sure that the database, the config folder and the data folder have been backed up before proceeding." : "Pred nadaljevanjem se prepričajte se, da je ustvarjena varnostna kopija podatkovne zbirke, nastavitvenih datotek in podatkovne mape.",
"Start update" : "Začni posodobitev",
"To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "Za razreševanje časovnih zahtev večjih namestitev lahko uporabite ukaz iz namestitvene mape:",
+ "This %s instance is currently in maintenance mode, which may take a while." : "Ta %s strežnik je trenutno v načinu vzdrževanja, kar lahko traja dlje časa.",
"This page will refresh itself when the %s instance is available again." : "Stran bo osvežena ko bo %s spet na voljo."
},"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"
} \ No newline at end of file
diff --git a/core/l10n/sq.js b/core/l10n/sq.js
index a40e56b9907..bcdec3b9c73 100644
--- a/core/l10n/sq.js
+++ b/core/l10n/sq.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "U përditësua \"%s\" në %s",
"Repair warning: " : "Sinjalizim ndreqjeje: ",
"Repair error: " : "Gabim ndreqjeje: ",
- "Set log level to debug - current level: \"%s\"" : "Caktoni debug si nivel regjistri - niveli i tanishëm: \"%s\"",
- "Reset log level to \"%s\"" : "Riktheni nivel regjistri në \"%s\"",
+ "Set log level to debug" : "Caktoni shkallë regjistrimi për diagnostikimin",
+ "Reset log level" : "Rikthe te parazgjedhja shkallën e regjistrimit",
+ "Starting code integrity check" : "Po fillohet kontroll integriteti për kodin",
+ "Finished code integrity check" : "Përfundoi kontrolli i integritetit për kodin",
"%s (3rdparty)" : "%s (prej palësh të treta)",
"%s (incompatible)" : "%s (e papërputhshme)",
"Following apps have been disabled: %s" : "Janë çaktivizuar aplikacionet vijuese : %s",
"Already up to date" : "Tashmë e përditësuar",
+ "Please select a file." : "Ju lutemi, përzgjidhni një kartelë.",
"File is too big" : "Kartela është shumë e madhe",
"Invalid file provided" : "U dha kartelë e pavlefshme",
"No image or file provided" : "S’u dha figurë apo kartelë",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "S’u dhanë të dhëna qethjeje",
"No valid crop data provided" : "S’u dhanë të dhëna qethjeje të vlefshme",
"Crop is not square" : "Qethja s’është katrore",
+ "Couldn't reset password because the token is invalid" : "S’u ricaktua dot fjalëkalimi, ngaqë token-i është i pavlefshëm",
+ "Couldn't reset password because the token is expired" : "S’u ricaktua dot fjalëkalimi, ngaqë token-i ka skaduar",
+ "Couldn't send reset email. Please make sure your username is correct." : "S’u dërgua dot email ricaktimi. Ju lutemi, sigurohuni që emri juaj i përdoruesit është i saktë.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "S’u dërgua dot email ricaktimi, ngaqë s’ka adresë email për këtë përdoruesi. Ju lutemi, lidhuni me përgjegjësin tuaj.",
+ "%s password reset" : "U ricaktua fjalëkalimi për %s",
+ "Couldn't send reset email. Please contact your administrator." : "S’u dërgua dot email-i i ricaktimit. Ju lutemi, lidhuni me përgjegjësin tuaj.",
"Sunday" : "E dielë",
"Monday" : "E hënë",
"Tuesday" : "E martë",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "Tet.",
"Nov." : "Nën.",
"Dec." : "Dhj.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Pati probleme me kontrollin e integritetit të kodit. Më tepër të dhëna…</a>",
"Settings" : "Rregullime",
"Saving..." : "Po ruhet …",
"seconds ago" : "sekonda më parë",
- "Couldn't send reset email. Please contact your administrator." : "S’u dërgua dot email-i i ricaktimit. Ju lutemi, lidhuni me përgjegjësin tuaj.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Lidhja për ricaktimin e fjalëkalimi tuaj u dërgua tek email-i juaj. Nëse nuk e merrni brenda një kohe të arsyeshme, kontrolloni dosjet e postës së padëshirueshme/postës së pavlerë.<br>Nëse s’është as aty, pyetni përgjegjësin tuaj lokal.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Kartelat tuaja janë të fshehtëzuara. Nëse s’keni aktivizuar kyçin e rimarrjeve, nuk do të ketë ndonjë rrugë për të marrë sërish të dhënat tuaja pasi të jetë ricaktuar fjalëkalimi juaj.<br />Nëse s’jeni i sigurt se ç’duhet bërë, ju lutemi, përpara se të vazhdoni, lidhuni me përgjegjësin tuaj. <br />Doni vërtet të vazhdoni?",
"I know what I'm doing" : "E di se ç’bëj",
@@ -109,13 +118,15 @@ OC.L10N.register(
"Good password" : "Fjalëkalim i mirë",
"Strong password" : "Fjalëkalim i fortë",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Shërbyesi juaj web ende s’është rregulluar për të lejuar njëkohësim kartelash, ngaqë ndërfaqja WebDAV duket se është e dëmtuar.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Shërbyesi juaj s’është rregulluar si duhet për të kuptuar \"{url}\". Të dhëna të mëtejshme mund të gjenden te <a target=\"_blank\" href=\"{docLink}\">dokumentimi</a> ynë.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Ky shërbyes nuk ka lidhje Internet që funksionon. Kjo do të thotë që disa prej veçorive, të tilla si montimi i depozitave të jashtme, njoftimet mbi përditësime apo instalim aplikacionesh nga palë të treta, s’do të funksionojnë. Edhe hyrja në kartela së largëti, apo dërgimi i email-eve për njoftime mund të mos funksionojnë. Këshillojmë të aktivizoni për këtë shërbyes lidhjen në Internet, nëse doni t’i keni krejt këto veçori.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Drejtoria juaj e të dhënave dhe kartelat tuaja ka shumë mundësi të jenë të arritshme që nga interneti. Kartela .htaccess s’funksionon. Këshillojmë me forcë që ta formësoni shërbyesin tuaj web në një mënyrë që drejtoria e të dhënave të mos lejojë më hyrje, ose ta zhvendosni drejtorinë e të dhënave jashtë rrënjës së dokumenteve të shërbyesit web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "S’ka të formësuar fshehtinë kujtese. Që të shtoni suksesshmërinë e shërbyesit tuaj, ju lutemi, formësoni një memcache, në mundet. Të dhëna të mëtejshme mund të gjenden te <a href=\"{docLink}\">dokumentimi</a> ynë.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom s’është i lexueshëm nga PHP-ja, çka shkëshillohet me forcë, për arsye sigurie. Më tepër informacion mund të gjendet te <a href=\"{docLink}\">dokumentimi</a> ynë.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Versioni juaj i PHP -së ({version}) nuk <a href=\"{phpLink}\">mbulohet më nga PHP-ja</a>. Ju nxisim ta përmirësoni PHP-në me një version të ri që të përfitoni nga përditësimi i punimit dhe sigurisë të ofruara nga PHP-ja.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Formësimi për krye ndërmjetësi prapësor është i pasaktë, ose jeni duke hyrë në ownCloud prej një ndërmjetësi të besuar. Nëse s’jeni duke hyrë në ownCloud prej një ndërmjetësi të besuar, ky është një problem sigurie dhe mund t’i lejojë një agresori të maskojë adresën e vet IP si një të pranueshme nga ownCloud-i. Të dhëna të mëtejshme mund të gjeni te <a href=\"{docLink}\">dokumentimi</a> ynë.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached është formësuar si fshehtinë e shpërndarë, por është instaluar moduli i gabuar PHP \"memcache\". \\OC\\Memcache\\Memcached mbulon vetëm \"memcached\" dhe jo \"memcache\". Shihni <a href=\"{wikiLink}\">memcached wiki për të dy modulet</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "S’është formësuar ndonjë fshehtinë kujtese. Që të përmirësohet punimi juaj, ju lutemi, formësoni një fshehtinë kujtese, në pastë. Të dhëna të mëtejshme mund të gjenden te <a target=\"_blank\" href=\"{docLink}\">dokumentimi</a> ynë.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom s’është i lexueshëm nga PHP-ja, çka shkëshillohet me forcë, për arsye sigurie. Më tepër informacion mund të gjendet te <a target=\"_blank\" href=\"{docLink}\">dokumentimi</a> ynë.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Versioni juaj i PHP-së ({version}) nuk <a target=\"_blank\" href=\"{phpLink}\">mbulohet më nga PHP-ja</a>. Ju nxisim ta përmirësoni versionin tuaj të PHP-së që të përfitoni nga përditësimet e funksionimit dhe sigurisë të ofruara nga PHP-ja.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Formësimi për krye ndërmjetësi prapësor është i pasaktë, ose jeni duke hyrë në ownCloud prej një ndërmjetësi të besuar. Nëse s’jeni duke hyrë në ownCloud prej një ndërmjetësi të besuar, ky është një problem sigurie dhe mund t’i lejojë një agresori të maskojë adresën e vet IP si një të pranueshme nga ownCloud-i. Të dhëna të mëtejshme mund të gjeni te <a target=\"_blank\" href=\"{docLink}\">dokumentimi</a> ynë.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached është formësuar si fshehtinë e shpërndarë, por është instaluar moduli i gabuar PHP \"memcache\". \\OC\\Memcache\\Memcached mbulon vetëm \"memcached\" dhe jo \"memcache\". Shihni <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki për të dy modulet</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Disa prej kartelave s’e kaluan dot kontrollin e integritetit. Si si mund të zgjidhet ky problem mund ta shihni më në thellësi te <a target=\"_blank\" href=\"{docLink}\">dokumentimi ynë</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Listë e kartelave të pavlefshme…</a> / <a href=\"{rescanEndpoint}\">Rikontrolloji…</a>)",
"Error occurred while checking server setup" : "Ndodhi një gabim gjatë kontrollit të rregullimit të shërbyesit",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Kryet HTTP \"{header}\" s’është formësuar të jetë i njëjtë me \"{expected}\". Ky është një rrezik potencial sigurie dhe privatësie dhe këshillojmë të ndreqet ky rregullim.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Kryet HTTP \"Strict-Transport-Security\" s’është formësuar të paktën \"{seconds}\". Për siguri të thelluar këshillojmë aktivizimin e HSTS-së, siç përshkruhet te <a href=\"{docUrl}\">këshillat tona mbi sigurinë</a>.",
@@ -125,7 +136,6 @@ OC.L10N.register(
"Error" : "Gabim",
"Error while sharing" : "Gabim gjatë ndarjes",
"Error while unsharing" : "Gabim gjatë heqjes së ndarjes",
- "Error while changing permissions" : "Gabim gjatë ndryshimit të lejeve",
"Error setting expiration date" : "Gabim në caktimin e datës së skadimit",
"The public link will expire no later than {days} days after it is created" : "Lidhja publike do të skadojë jo më vonë se {days} ditë pas krijimit të saj",
"Set expiration date" : "Caktoni datë skadimi",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "Dërgoje",
"Shared with you and the group {group} by {owner}" : "Ndarë me ju dhe me grupin {group} nga {owner}",
"Shared with you by {owner}" : "Ndarë me ju nga {owner}",
- "Shared in {item} with {user}" : "Ndarë në {item} me {user}",
"group" : "grup",
"remote" : "i largët",
"notify by email" : "njofto me email",
@@ -155,17 +164,25 @@ OC.L10N.register(
"change" : "ndërroje",
"delete" : "fshije",
"access control" : "kontroll hyrjesh",
+ "Could not unshare" : "S’e shndau dot",
"Share details could not be loaded for this item." : "Për këtë objekt s’u ngarkuan dot hollësi ndarjeje.",
"An error occured. Please try again" : "Ndodhi një gabim. Ju lutemi, riprovoni",
"Share" : "Ndaje",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Ndajeni me persona në ownCloud-e të tjera duke përdorur sintaksën username@example.com/owncloud",
"Share with users or groups …" : "Ndajeni me përdorues ose grupe …",
"Share with users, groups or remote users …" : "Ndajeni me përdorues, grupe ose përdorues të largët …",
+ "Error removing share" : "Gabim në heqjen e ndarjes",
"Warning" : "Kujdes",
"Error while sending notification" : "Gabim gjatë dërgimit të njoftimit",
+ "Non-existing tag #{tag}" : "Etiketë #{tag} që s’ekziston",
+ "not assignable" : "e pacaktueshme",
+ "invisible" : "e padukshme",
+ "({scope})" : "({scope})",
+ "Delete" : "Fshije",
+ "Rename" : "Riemërtoje",
+ "Global tags" : "Etiketa globale",
"The object type is not specified." : "S’është specifikuar lloji i objektit.",
"Enter new" : "Jep të ri",
- "Delete" : "Fshije",
"Add" : "Shtoni",
"Edit tags" : "Përpunoni etiketa",
"Error loading dialog template: {error}" : "Gabim gjatë ngarkimit të gjedhes së dialogut: {error}",
@@ -184,15 +201,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Përditësimi qe i pasuksesshëm. ",
"The update was successful. There were warnings." : "Përditësimi qe i suksesshëm. Pati sinjalizime.",
"The update was successful. Redirecting you to ownCloud now." : "Përditësimi qe i suksesshëm. Po ridrejtoheni te ownCloud-i.",
- "Couldn't reset password because the token is invalid" : "S’u ricaktua dot fjalëkalimi, ngaqë token-i është i pavlefshëm",
- "Couldn't reset password because the token is expired" : "S’u ricaktua dot fjalëkalimi, ngaqë token-i ka skaduar",
- "Couldn't send reset email. Please make sure your username is correct." : "S’u dërgua dot email ricaktimi. Ju lutemi, sigurohuni që emri juaj i përdoruesit është i saktë.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "S’u dërgua dot email ricaktimi, ngaqë s’ka adresë email për këtë përdoruesi. Ju lutemi, lidhuni me përgjegjësin tuaj.",
- "%s password reset" : "U ricaktua fjalëkalimi për %s",
- "Use the following link to reset your password: {link}" : "Që të ricaktoni fjalëkalimin tuaj, përdorni lidhjen vijuese: {link}",
- "New password" : "Fjalëkalim i ri",
- "New Password" : "Fjalëkalim i Ri",
- "Reset password" : "Ricaktoni fjalëkalimin",
"Searching other places" : "Po kërkohet në vende të tjera",
"No search results in other folders" : "S’u gjetën përfundime në dosje të tjera",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} përfundim kërkimi në një tjetër dosje","{count} përfundime kërkimi në dosje të tjera"],
@@ -245,7 +253,7 @@ OC.L10N.register(
"Database tablespace" : "Tablespace-i i database-it",
"Database host" : "Strehë baze të dhënash",
"Performance warning" : "Sinjalizim funksionimi",
- "SQLite will be used as database." : "Si bazë të dhënash do të përdoret SQL-ja.",
+ "SQLite will be used as database." : "Si bazë të dhënash do të përdoret SQLite.",
"For larger installations we recommend to choose a different database backend." : "Për instalime më të mëdha këshillojmë të zgjidhni një tjetër program shërbyesi baze të dhënash.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Përdorimi i SQLite-it shkëshillohet veçanërisht, kur për njëkohësim kartelash përdoret klienti desktop.",
"Finish setup" : "Përfundoje rregullimin",
@@ -262,8 +270,13 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Ju lutemi, riprovoni ose lidhuni me përgjegjësin tuaj.",
"Log in" : "Hyni",
"Wrong password. Reset it?" : "Fjalëkalim i gabuar. Të ricaktohet?",
+ "Wrong password." : "Fjalëkalim i gabuar.",
"Stay logged in" : "Qëndro i futur",
"Alternative Logins" : "Hyrje Alternative",
+ "Use the following link to reset your password: {link}" : "Që të ricaktoni fjalëkalimin tuaj, përdorni lidhjen vijuese: {link}",
+ "New password" : "Fjalëkalim i ri",
+ "New Password" : "Fjalëkalim i Ri",
+ "Reset password" : "Ricaktoni fjalëkalimin",
"This ownCloud instance is currently in single user mode." : "Kjo instancë ownCloud është aktualisht në gjendje me përdorues të vetëm.",
"This means only administrators can use the instance." : "Kjo do të thotë që instancën mund ta përdorin vetëm administratorët.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Nëse ky mesazh shfaqet vazhdimisht ose u shfaq papritmas, lidhuni me përgjegjësin e sistemit.",
diff --git a/core/l10n/sq.json b/core/l10n/sq.json
index 4284bb9a40e..3fdd04bd429 100644
--- a/core/l10n/sq.json
+++ b/core/l10n/sq.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "U përditësua \"%s\" në %s",
"Repair warning: " : "Sinjalizim ndreqjeje: ",
"Repair error: " : "Gabim ndreqjeje: ",
- "Set log level to debug - current level: \"%s\"" : "Caktoni debug si nivel regjistri - niveli i tanishëm: \"%s\"",
- "Reset log level to \"%s\"" : "Riktheni nivel regjistri në \"%s\"",
+ "Set log level to debug" : "Caktoni shkallë regjistrimi për diagnostikimin",
+ "Reset log level" : "Rikthe te parazgjedhja shkallën e regjistrimit",
+ "Starting code integrity check" : "Po fillohet kontroll integriteti për kodin",
+ "Finished code integrity check" : "Përfundoi kontrolli i integritetit për kodin",
"%s (3rdparty)" : "%s (prej palësh të treta)",
"%s (incompatible)" : "%s (e papërputhshme)",
"Following apps have been disabled: %s" : "Janë çaktivizuar aplikacionet vijuese : %s",
"Already up to date" : "Tashmë e përditësuar",
+ "Please select a file." : "Ju lutemi, përzgjidhni një kartelë.",
"File is too big" : "Kartela është shumë e madhe",
"Invalid file provided" : "U dha kartelë e pavlefshme",
"No image or file provided" : "S’u dha figurë apo kartelë",
@@ -30,6 +33,12 @@
"No crop data provided" : "S’u dhanë të dhëna qethjeje",
"No valid crop data provided" : "S’u dhanë të dhëna qethjeje të vlefshme",
"Crop is not square" : "Qethja s’është katrore",
+ "Couldn't reset password because the token is invalid" : "S’u ricaktua dot fjalëkalimi, ngaqë token-i është i pavlefshëm",
+ "Couldn't reset password because the token is expired" : "S’u ricaktua dot fjalëkalimi, ngaqë token-i ka skaduar",
+ "Couldn't send reset email. Please make sure your username is correct." : "S’u dërgua dot email ricaktimi. Ju lutemi, sigurohuni që emri juaj i përdoruesit është i saktë.",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "S’u dërgua dot email ricaktimi, ngaqë s’ka adresë email për këtë përdoruesi. Ju lutemi, lidhuni me përgjegjësin tuaj.",
+ "%s password reset" : "U ricaktua fjalëkalimi për %s",
+ "Couldn't send reset email. Please contact your administrator." : "S’u dërgua dot email-i i ricaktimit. Ju lutemi, lidhuni me përgjegjësin tuaj.",
"Sunday" : "E dielë",
"Monday" : "E hënë",
"Tuesday" : "E martë",
@@ -75,10 +84,10 @@
"Oct." : "Tet.",
"Nov." : "Nën.",
"Dec." : "Dhj.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">Pati probleme me kontrollin e integritetit të kodit. Më tepër të dhëna…</a>",
"Settings" : "Rregullime",
"Saving..." : "Po ruhet …",
"seconds ago" : "sekonda më parë",
- "Couldn't send reset email. Please contact your administrator." : "S’u dërgua dot email-i i ricaktimit. Ju lutemi, lidhuni me përgjegjësin tuaj.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Lidhja për ricaktimin e fjalëkalimi tuaj u dërgua tek email-i juaj. Nëse nuk e merrni brenda një kohe të arsyeshme, kontrolloni dosjet e postës së padëshirueshme/postës së pavlerë.<br>Nëse s’është as aty, pyetni përgjegjësin tuaj lokal.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Kartelat tuaja janë të fshehtëzuara. Nëse s’keni aktivizuar kyçin e rimarrjeve, nuk do të ketë ndonjë rrugë për të marrë sërish të dhënat tuaja pasi të jetë ricaktuar fjalëkalimi juaj.<br />Nëse s’jeni i sigurt se ç’duhet bërë, ju lutemi, përpara se të vazhdoni, lidhuni me përgjegjësin tuaj. <br />Doni vërtet të vazhdoni?",
"I know what I'm doing" : "E di se ç’bëj",
@@ -107,13 +116,15 @@
"Good password" : "Fjalëkalim i mirë",
"Strong password" : "Fjalëkalim i fortë",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Shërbyesi juaj web ende s’është rregulluar për të lejuar njëkohësim kartelash, ngaqë ndërfaqja WebDAV duket se është e dëmtuar.",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Shërbyesi juaj s’është rregulluar si duhet për të kuptuar \"{url}\". Të dhëna të mëtejshme mund të gjenden te <a target=\"_blank\" href=\"{docLink}\">dokumentimi</a> ynë.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Ky shërbyes nuk ka lidhje Internet që funksionon. Kjo do të thotë që disa prej veçorive, të tilla si montimi i depozitave të jashtme, njoftimet mbi përditësime apo instalim aplikacionesh nga palë të treta, s’do të funksionojnë. Edhe hyrja në kartela së largëti, apo dërgimi i email-eve për njoftime mund të mos funksionojnë. Këshillojmë të aktivizoni për këtë shërbyes lidhjen në Internet, nëse doni t’i keni krejt këto veçori.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Drejtoria juaj e të dhënave dhe kartelat tuaja ka shumë mundësi të jenë të arritshme që nga interneti. Kartela .htaccess s’funksionon. Këshillojmë me forcë që ta formësoni shërbyesin tuaj web në një mënyrë që drejtoria e të dhënave të mos lejojë më hyrje, ose ta zhvendosni drejtorinë e të dhënave jashtë rrënjës së dokumenteve të shërbyesit web.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "S’ka të formësuar fshehtinë kujtese. Që të shtoni suksesshmërinë e shërbyesit tuaj, ju lutemi, formësoni një memcache, në mundet. Të dhëna të mëtejshme mund të gjenden te <a href=\"{docLink}\">dokumentimi</a> ynë.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom s’është i lexueshëm nga PHP-ja, çka shkëshillohet me forcë, për arsye sigurie. Më tepër informacion mund të gjendet te <a href=\"{docLink}\">dokumentimi</a> ynë.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Versioni juaj i PHP -së ({version}) nuk <a href=\"{phpLink}\">mbulohet më nga PHP-ja</a>. Ju nxisim ta përmirësoni PHP-në me një version të ri që të përfitoni nga përditësimi i punimit dhe sigurisë të ofruara nga PHP-ja.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Formësimi për krye ndërmjetësi prapësor është i pasaktë, ose jeni duke hyrë në ownCloud prej një ndërmjetësi të besuar. Nëse s’jeni duke hyrë në ownCloud prej një ndërmjetësi të besuar, ky është një problem sigurie dhe mund t’i lejojë një agresori të maskojë adresën e vet IP si një të pranueshme nga ownCloud-i. Të dhëna të mëtejshme mund të gjeni te <a href=\"{docLink}\">dokumentimi</a> ynë.",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached është formësuar si fshehtinë e shpërndarë, por është instaluar moduli i gabuar PHP \"memcache\". \\OC\\Memcache\\Memcached mbulon vetëm \"memcached\" dhe jo \"memcache\". Shihni <a href=\"{wikiLink}\">memcached wiki për të dy modulet</a>.",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "S’është formësuar ndonjë fshehtinë kujtese. Që të përmirësohet punimi juaj, ju lutemi, formësoni një fshehtinë kujtese, në pastë. Të dhëna të mëtejshme mund të gjenden te <a target=\"_blank\" href=\"{docLink}\">dokumentimi</a> ynë.",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom s’është i lexueshëm nga PHP-ja, çka shkëshillohet me forcë, për arsye sigurie. Më tepër informacion mund të gjendet te <a target=\"_blank\" href=\"{docLink}\">dokumentimi</a> ynë.",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Versioni juaj i PHP-së ({version}) nuk <a target=\"_blank\" href=\"{phpLink}\">mbulohet më nga PHP-ja</a>. Ju nxisim ta përmirësoni versionin tuaj të PHP-së që të përfitoni nga përditësimet e funksionimit dhe sigurisë të ofruara nga PHP-ja.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "Formësimi për krye ndërmjetësi prapësor është i pasaktë, ose jeni duke hyrë në ownCloud prej një ndërmjetësi të besuar. Nëse s’jeni duke hyrë në ownCloud prej një ndërmjetësi të besuar, ky është një problem sigurie dhe mund t’i lejojë një agresori të maskojë adresën e vet IP si një të pranueshme nga ownCloud-i. Të dhëna të mëtejshme mund të gjeni te <a target=\"_blank\" href=\"{docLink}\">dokumentimi</a> ynë.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached është formësuar si fshehtinë e shpërndarë, por është instaluar moduli i gabuar PHP \"memcache\". \\OC\\Memcache\\Memcached mbulon vetëm \"memcached\" dhe jo \"memcache\". Shihni <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki për të dy modulet</a>.",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "Disa prej kartelave s’e kaluan dot kontrollin e integritetit. Si si mund të zgjidhet ky problem mund ta shihni më në thellësi te <a target=\"_blank\" href=\"{docLink}\">dokumentimi ynë</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">Listë e kartelave të pavlefshme…</a> / <a href=\"{rescanEndpoint}\">Rikontrolloji…</a>)",
"Error occurred while checking server setup" : "Ndodhi një gabim gjatë kontrollit të rregullimit të shërbyesit",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "Kryet HTTP \"{header}\" s’është formësuar të jetë i njëjtë me \"{expected}\". Ky është një rrezik potencial sigurie dhe privatësie dhe këshillojmë të ndreqet ky rregullim.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "Kryet HTTP \"Strict-Transport-Security\" s’është formësuar të paktën \"{seconds}\". Për siguri të thelluar këshillojmë aktivizimin e HSTS-së, siç përshkruhet te <a href=\"{docUrl}\">këshillat tona mbi sigurinë</a>.",
@@ -123,7 +134,6 @@
"Error" : "Gabim",
"Error while sharing" : "Gabim gjatë ndarjes",
"Error while unsharing" : "Gabim gjatë heqjes së ndarjes",
- "Error while changing permissions" : "Gabim gjatë ndryshimit të lejeve",
"Error setting expiration date" : "Gabim në caktimin e datës së skadimit",
"The public link will expire no later than {days} days after it is created" : "Lidhja publike do të skadojë jo më vonë se {days} ditë pas krijimit të saj",
"Set expiration date" : "Caktoni datë skadimi",
@@ -142,7 +152,6 @@
"Send" : "Dërgoje",
"Shared with you and the group {group} by {owner}" : "Ndarë me ju dhe me grupin {group} nga {owner}",
"Shared with you by {owner}" : "Ndarë me ju nga {owner}",
- "Shared in {item} with {user}" : "Ndarë në {item} me {user}",
"group" : "grup",
"remote" : "i largët",
"notify by email" : "njofto me email",
@@ -153,17 +162,25 @@
"change" : "ndërroje",
"delete" : "fshije",
"access control" : "kontroll hyrjesh",
+ "Could not unshare" : "S’e shndau dot",
"Share details could not be loaded for this item." : "Për këtë objekt s’u ngarkuan dot hollësi ndarjeje.",
"An error occured. Please try again" : "Ndodhi një gabim. Ju lutemi, riprovoni",
"Share" : "Ndaje",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Ndajeni me persona në ownCloud-e të tjera duke përdorur sintaksën username@example.com/owncloud",
"Share with users or groups …" : "Ndajeni me përdorues ose grupe …",
"Share with users, groups or remote users …" : "Ndajeni me përdorues, grupe ose përdorues të largët …",
+ "Error removing share" : "Gabim në heqjen e ndarjes",
"Warning" : "Kujdes",
"Error while sending notification" : "Gabim gjatë dërgimit të njoftimit",
+ "Non-existing tag #{tag}" : "Etiketë #{tag} që s’ekziston",
+ "not assignable" : "e pacaktueshme",
+ "invisible" : "e padukshme",
+ "({scope})" : "({scope})",
+ "Delete" : "Fshije",
+ "Rename" : "Riemërtoje",
+ "Global tags" : "Etiketa globale",
"The object type is not specified." : "S’është specifikuar lloji i objektit.",
"Enter new" : "Jep të ri",
- "Delete" : "Fshije",
"Add" : "Shtoni",
"Edit tags" : "Përpunoni etiketa",
"Error loading dialog template: {error}" : "Gabim gjatë ngarkimit të gjedhes së dialogut: {error}",
@@ -182,15 +199,6 @@
"The update was unsuccessful. " : "Përditësimi qe i pasuksesshëm. ",
"The update was successful. There were warnings." : "Përditësimi qe i suksesshëm. Pati sinjalizime.",
"The update was successful. Redirecting you to ownCloud now." : "Përditësimi qe i suksesshëm. Po ridrejtoheni te ownCloud-i.",
- "Couldn't reset password because the token is invalid" : "S’u ricaktua dot fjalëkalimi, ngaqë token-i është i pavlefshëm",
- "Couldn't reset password because the token is expired" : "S’u ricaktua dot fjalëkalimi, ngaqë token-i ka skaduar",
- "Couldn't send reset email. Please make sure your username is correct." : "S’u dërgua dot email ricaktimi. Ju lutemi, sigurohuni që emri juaj i përdoruesit është i saktë.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "S’u dërgua dot email ricaktimi, ngaqë s’ka adresë email për këtë përdoruesi. Ju lutemi, lidhuni me përgjegjësin tuaj.",
- "%s password reset" : "U ricaktua fjalëkalimi për %s",
- "Use the following link to reset your password: {link}" : "Që të ricaktoni fjalëkalimin tuaj, përdorni lidhjen vijuese: {link}",
- "New password" : "Fjalëkalim i ri",
- "New Password" : "Fjalëkalim i Ri",
- "Reset password" : "Ricaktoni fjalëkalimin",
"Searching other places" : "Po kërkohet në vende të tjera",
"No search results in other folders" : "S’u gjetën përfundime në dosje të tjera",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} përfundim kërkimi në një tjetër dosje","{count} përfundime kërkimi në dosje të tjera"],
@@ -243,7 +251,7 @@
"Database tablespace" : "Tablespace-i i database-it",
"Database host" : "Strehë baze të dhënash",
"Performance warning" : "Sinjalizim funksionimi",
- "SQLite will be used as database." : "Si bazë të dhënash do të përdoret SQL-ja.",
+ "SQLite will be used as database." : "Si bazë të dhënash do të përdoret SQLite.",
"For larger installations we recommend to choose a different database backend." : "Për instalime më të mëdha këshillojmë të zgjidhni një tjetër program shërbyesi baze të dhënash.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Përdorimi i SQLite-it shkëshillohet veçanërisht, kur për njëkohësim kartelash përdoret klienti desktop.",
"Finish setup" : "Përfundoje rregullimin",
@@ -260,8 +268,13 @@
"Please try again or contact your administrator." : "Ju lutemi, riprovoni ose lidhuni me përgjegjësin tuaj.",
"Log in" : "Hyni",
"Wrong password. Reset it?" : "Fjalëkalim i gabuar. Të ricaktohet?",
+ "Wrong password." : "Fjalëkalim i gabuar.",
"Stay logged in" : "Qëndro i futur",
"Alternative Logins" : "Hyrje Alternative",
+ "Use the following link to reset your password: {link}" : "Që të ricaktoni fjalëkalimin tuaj, përdorni lidhjen vijuese: {link}",
+ "New password" : "Fjalëkalim i ri",
+ "New Password" : "Fjalëkalim i Ri",
+ "Reset password" : "Ricaktoni fjalëkalimin",
"This ownCloud instance is currently in single user mode." : "Kjo instancë ownCloud është aktualisht në gjendje me përdorues të vetëm.",
"This means only administrators can use the instance." : "Kjo do të thotë që instancën mund ta përdorin vetëm administratorët.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Nëse ky mesazh shfaqet vazhdimisht ose u shfaq papritmas, lidhuni me përgjegjësin e sistemit.",
diff --git a/core/l10n/sr.js b/core/l10n/sr.js
index aac106e61ad..83cdd2605f3 100644
--- a/core/l10n/sr.js
+++ b/core/l10n/sr.js
@@ -22,6 +22,10 @@ OC.L10N.register(
"No crop data provided" : "Нема података о опсецању",
"No valid crop data provided" : "Нема података о опсецању",
"Crop is not square" : "Опсецање није квадрат",
+ "Couldn't reset password because the token is invalid" : "Није могуће ресетовати лозинку јер je токен неважећи",
+ "Couldn't send reset email. Please make sure your username is correct." : "Не могу да пошаљем поруку за ресетовање лозинке. Проверите да ли је корисничко име исправно.",
+ "%s password reset" : "%s лозинка ресетована",
+ "Couldn't send reset email. Please contact your administrator." : "Не могу да пошаљем е-пошту за ресетовање лозинке. Контактирајте администратора.",
"Sunday" : "недеља",
"Monday" : "понедељак",
"Tuesday" : "уторак",
@@ -70,7 +74,6 @@ OC.L10N.register(
"Settings" : "Поставке",
"Saving..." : "Уписујем...",
"seconds ago" : "пре пар секунди",
- "Couldn't send reset email. Please contact your administrator." : "Не могу да пошаљем е-пошту за ресетовање лозинке. Контактирајте администратора.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Веза за ресетовање лозинке је послата на вашу е-адресу. Ако је не примите ускоро, проверите фасцикле за нежељену пошту.<br>Ако није ни тамо, контактирајте вашег администратора.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Фајлови су вам шифровани. Ако нисте укључили кључ за опоравак, нећете моћи да повратите податке након ресетовања лозинке.<br />Ако нисте сигурни шта да радите, контактирајте администратора пре него што наставите.<br />Да ли желите да наставите?",
"I know what I'm doing" : "Знам шта радим",
@@ -101,8 +104,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ваш сервер није правилно подешен да омогући синхронизацију фајлова. Изгледа да је ВебДАВ сучеље покварено.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Овај сервер нема везу са интернетом. То значи да неке могућности, попут монтирања спољашњег складишта, обавештења о ажурирању или инсталација апликација треће стране, неће радити. Даљински приступ и слање е-поште, такође неће радити. Предлажемо да омогућите интернет везу за овај сервер ако желите да имате све могућности.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ваш директоријум са подацима и ваши фајлови су вероватно доступни са интернета. Фајл .htaccess не ради. Предлажемо да подесите ваш веб сервер на начин да директоријум са подацима не буде доступан или га изместите изван кореног директоријума веб сервера.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Није подешен меморијски кеш. Да бисте побољшали перформансе подесите „memcache“ ако је доступан. Више информација можете наћи у <a href=\"{docLink}\">документацији</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ПХП не може да чита што није добро из безбедносних разлога. Информације о томе можете наћи у нашој <a href=\"{docLink}\">дукументацији</a>.",
"Error occurred while checking server setup" : "Дошло је до грешке при провери поставки сервера",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "ХТТП заглавље „{header}“ није подешено као „{expected}“. Ово потенцијално угрожава безбедност и приватност и препоручујемо да подесите ову поставку.",
"Shared" : "Дељено",
@@ -110,7 +111,6 @@ OC.L10N.register(
"Error" : "Грешка",
"Error while sharing" : "Грешка при дељењу",
"Error while unsharing" : "Грешка при укидању дељења",
- "Error while changing permissions" : "Грешка при измени дозвола",
"Error setting expiration date" : "Грешка при постављању датума истека",
"The public link will expire no later than {days} days after it is created" : "Јавна веза ће престати да важи {days} дана након стварања",
"Set expiration date" : "Постави датум истека",
@@ -129,7 +129,6 @@ OC.L10N.register(
"Send" : "Пошаљи",
"Shared with you and the group {group} by {owner}" : "{owner} дели са вама и са групом {group}.",
"Shared with you by {owner}" : "{owner} дели са вама",
- "Shared in {item} with {user}" : "Подељено унутар {item} са корисником {user}",
"group" : "група",
"remote" : "удаљени",
"notify by email" : "обавести е-поштом",
@@ -146,9 +145,10 @@ OC.L10N.register(
"Share with users or groups …" : "Дели са корисницима или групама...",
"Share with users, groups or remote users …" : "Дели са корисницима, групама или удаљеним корисницима...",
"Warning" : "Упозорење",
+ "Delete" : "Обриши",
+ "Rename" : "Преименуј",
"The object type is not specified." : "Тип објекта није наведен.",
"Enter new" : "Унесите нови",
- "Delete" : "Обриши",
"Add" : "Додај",
"Edit tags" : "Уреди ознаке",
"Error loading dialog template: {error}" : "Грешка при учитавању шаблона дијалога: {error}",
@@ -165,14 +165,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Ажурирање није успело.",
"The update was successful. There were warnings." : "Ажурирање је успело. Било је упозорења.",
"The update was successful. Redirecting you to ownCloud now." : "Ажурирање је успело. Преусмеравам вас на оунКлауд.",
- "Couldn't reset password because the token is invalid" : "Није могуће ресетовати лозинку јер je токен неважећи",
- "Couldn't send reset email. Please make sure your username is correct." : "Не могу да пошаљем поруку за ресетовање лозинке. Проверите да ли је корисничко име исправно.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Не могу да пошаљем поруку за ресетовање лозинке јер за ово корисничко име нема е-адресе. Контактирајте администратора.",
- "%s password reset" : "%s лозинка ресетована",
- "Use the following link to reset your password: {link}" : "Употребите следећу везу да ресетујете своју лозинку: {link}",
- "New password" : "Нова лозинка",
- "New Password" : "Нова лозинка",
- "Reset password" : "Ресетуј лозинку",
"Searching other places" : "Претражујем остала места",
"Personal" : "Лично",
"Users" : "Корисници",
@@ -240,6 +232,10 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Покушајте поново или контактирајте вашег администратора.",
"Log in" : "Пријава",
"Alternative Logins" : "Алтернативне пријаве",
+ "Use the following link to reset your password: {link}" : "Употребите следећу везу да ресетујете своју лозинку: {link}",
+ "New password" : "Нова лозинка",
+ "New Password" : "Нова лозинка",
+ "Reset password" : "Ресетуј лозинку",
"This ownCloud instance is currently in single user mode." : "Овај оунКлауд тренутно ради у режиму једног корисника.",
"This means only administrators can use the instance." : "То значи да га могу користити само администратори.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Контактирајте администратора ако се порука понавља или се неочекивано појавила.",
diff --git a/core/l10n/sr.json b/core/l10n/sr.json
index c3af2764d0b..ef5e9962968 100644
--- a/core/l10n/sr.json
+++ b/core/l10n/sr.json
@@ -20,6 +20,10 @@
"No crop data provided" : "Нема података о опсецању",
"No valid crop data provided" : "Нема података о опсецању",
"Crop is not square" : "Опсецање није квадрат",
+ "Couldn't reset password because the token is invalid" : "Није могуће ресетовати лозинку јер je токен неважећи",
+ "Couldn't send reset email. Please make sure your username is correct." : "Не могу да пошаљем поруку за ресетовање лозинке. Проверите да ли је корисничко име исправно.",
+ "%s password reset" : "%s лозинка ресетована",
+ "Couldn't send reset email. Please contact your administrator." : "Не могу да пошаљем е-пошту за ресетовање лозинке. Контактирајте администратора.",
"Sunday" : "недеља",
"Monday" : "понедељак",
"Tuesday" : "уторак",
@@ -68,7 +72,6 @@
"Settings" : "Поставке",
"Saving..." : "Уписујем...",
"seconds ago" : "пре пар секунди",
- "Couldn't send reset email. Please contact your administrator." : "Не могу да пошаљем е-пошту за ресетовање лозинке. Контактирајте администратора.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Веза за ресетовање лозинке је послата на вашу е-адресу. Ако је не примите ускоро, проверите фасцикле за нежељену пошту.<br>Ако није ни тамо, контактирајте вашег администратора.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Фајлови су вам шифровани. Ако нисте укључили кључ за опоравак, нећете моћи да повратите податке након ресетовања лозинке.<br />Ако нисте сигурни шта да радите, контактирајте администратора пре него што наставите.<br />Да ли желите да наставите?",
"I know what I'm doing" : "Знам шта радим",
@@ -99,8 +102,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ваш сервер није правилно подешен да омогући синхронизацију фајлова. Изгледа да је ВебДАВ сучеље покварено.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Овај сервер нема везу са интернетом. То значи да неке могућности, попут монтирања спољашњег складишта, обавештења о ажурирању или инсталација апликација треће стране, неће радити. Даљински приступ и слање е-поште, такође неће радити. Предлажемо да омогућите интернет везу за овај сервер ако желите да имате све могућности.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ваш директоријум са подацима и ваши фајлови су вероватно доступни са интернета. Фајл .htaccess не ради. Предлажемо да подесите ваш веб сервер на начин да директоријум са подацима не буде доступан или га изместите изван кореног директоријума веб сервера.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Није подешен меморијски кеш. Да бисте побољшали перформансе подесите „memcache“ ако је доступан. Више информација можете наћи у <a href=\"{docLink}\">документацији</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ПХП не може да чита што није добро из безбедносних разлога. Информације о томе можете наћи у нашој <a href=\"{docLink}\">дукументацији</a>.",
"Error occurred while checking server setup" : "Дошло је до грешке при провери поставки сервера",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "ХТТП заглавље „{header}“ није подешено као „{expected}“. Ово потенцијално угрожава безбедност и приватност и препоручујемо да подесите ову поставку.",
"Shared" : "Дељено",
@@ -108,7 +109,6 @@
"Error" : "Грешка",
"Error while sharing" : "Грешка при дељењу",
"Error while unsharing" : "Грешка при укидању дељења",
- "Error while changing permissions" : "Грешка при измени дозвола",
"Error setting expiration date" : "Грешка при постављању датума истека",
"The public link will expire no later than {days} days after it is created" : "Јавна веза ће престати да важи {days} дана након стварања",
"Set expiration date" : "Постави датум истека",
@@ -127,7 +127,6 @@
"Send" : "Пошаљи",
"Shared with you and the group {group} by {owner}" : "{owner} дели са вама и са групом {group}.",
"Shared with you by {owner}" : "{owner} дели са вама",
- "Shared in {item} with {user}" : "Подељено унутар {item} са корисником {user}",
"group" : "група",
"remote" : "удаљени",
"notify by email" : "обавести е-поштом",
@@ -144,9 +143,10 @@
"Share with users or groups …" : "Дели са корисницима или групама...",
"Share with users, groups or remote users …" : "Дели са корисницима, групама или удаљеним корисницима...",
"Warning" : "Упозорење",
+ "Delete" : "Обриши",
+ "Rename" : "Преименуј",
"The object type is not specified." : "Тип објекта није наведен.",
"Enter new" : "Унесите нови",
- "Delete" : "Обриши",
"Add" : "Додај",
"Edit tags" : "Уреди ознаке",
"Error loading dialog template: {error}" : "Грешка при учитавању шаблона дијалога: {error}",
@@ -163,14 +163,6 @@
"The update was unsuccessful. " : "Ажурирање није успело.",
"The update was successful. There were warnings." : "Ажурирање је успело. Било је упозорења.",
"The update was successful. Redirecting you to ownCloud now." : "Ажурирање је успело. Преусмеравам вас на оунКлауд.",
- "Couldn't reset password because the token is invalid" : "Није могуће ресетовати лозинку јер je токен неважећи",
- "Couldn't send reset email. Please make sure your username is correct." : "Не могу да пошаљем поруку за ресетовање лозинке. Проверите да ли је корисничко име исправно.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Не могу да пошаљем поруку за ресетовање лозинке јер за ово корисничко име нема е-адресе. Контактирајте администратора.",
- "%s password reset" : "%s лозинка ресетована",
- "Use the following link to reset your password: {link}" : "Употребите следећу везу да ресетујете своју лозинку: {link}",
- "New password" : "Нова лозинка",
- "New Password" : "Нова лозинка",
- "Reset password" : "Ресетуј лозинку",
"Searching other places" : "Претражујем остала места",
"Personal" : "Лично",
"Users" : "Корисници",
@@ -238,6 +230,10 @@
"Please try again or contact your administrator." : "Покушајте поново или контактирајте вашег администратора.",
"Log in" : "Пријава",
"Alternative Logins" : "Алтернативне пријаве",
+ "Use the following link to reset your password: {link}" : "Употребите следећу везу да ресетујете своју лозинку: {link}",
+ "New password" : "Нова лозинка",
+ "New Password" : "Нова лозинка",
+ "Reset password" : "Ресетуј лозинку",
"This ownCloud instance is currently in single user mode." : "Овај оунКлауд тренутно ради у режиму једног корисника.",
"This means only administrators can use the instance." : "То значи да га могу користити само администратори.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Контактирајте администратора ако се порука понавља или се неочекивано појавила.",
diff --git a/core/l10n/sr@latin.js b/core/l10n/sr@latin.js
index 18ab8513417..2755dde9ad1 100644
--- a/core/l10n/sr@latin.js
+++ b/core/l10n/sr@latin.js
@@ -13,6 +13,10 @@ OC.L10N.register(
"Invalid image" : "Neispravna slika",
"No temporary profile picture available, try again" : "Nije dostupna privremena slika profila, pokušajte ponovo",
"No crop data provided" : "Nisu dati podaci za sečenje slike",
+ "Couldn't reset password because the token is invalid" : "Nije bilo moguće ponovo postaviti lozinku zbog nevažećeg kontrolnog broja",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nije bilo moguće poslati Email za ponovno postavljanje. Molimo Vas da proverite da li je Vaše korisničko ime ispravno.",
+ "%s password reset" : "%s lozinka ponovo postavljena",
+ "Couldn't send reset email. Please contact your administrator." : "Nemoguće slanje e-mail-a za ponovno postavljanje lozinke. Molimo Vas kontaktirajte Vašeg administratora",
"Sunday" : "Nedelja",
"Monday" : "Ponedeljak",
"Tuesday" : "Utorak",
@@ -54,7 +58,6 @@ OC.L10N.register(
"Settings" : "Podešavanja",
"Saving..." : "Snimam...",
"seconds ago" : "Pre par sekundi",
- "Couldn't send reset email. Please contact your administrator." : "Nemoguće slanje e-mail-a za ponovno postavljanje lozinke. Molimo Vas kontaktirajte Vašeg administratora",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Link za ponovno postavljanje Vaše lozinke je poslat na Vašu e-mail adresu. Ako ga ne primite u razumnom roku, proverite fascikle za neželjenu poštu.<br>Ako ga nema ni tamo, kontaktirajte Vašeg lokalnog administratora.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vaši fajlovi su šifrovani. Ako nista omogućili ključ za povrat fajlova, neće biti načina da dobijete ponovo svoje podatke posle promene lozinke.<br />Ako niste sigurni šta da radite, molimo Vas da kontaktirate Vašeg administratora pre nego što nastavite.<br />Da li zaista želite da nastavite?",
"I know what I'm doing" : "Znam šta radim",
@@ -88,7 +91,6 @@ OC.L10N.register(
"Error" : "Greška",
"Error while sharing" : "Greška pri deljenju",
"Error while unsharing" : "Greška u uklanjanju deljenja",
- "Error while changing permissions" : "Greška u promeni dozvola",
"Error setting expiration date" : "Greška u postavljanju datuma isteka",
"The public link will expire no later than {days} days after it is created" : "Javna prečica će isteći ne kasnije od {days} dana pošto je kreirana",
"Set expiration date" : "Datum isteka",
@@ -107,7 +109,6 @@ OC.L10N.register(
"Send" : "Pošalji",
"Shared with you and the group {group} by {owner}" : "{owner} podelio sa Vama i grupom {group} ",
"Shared with you by {owner}" : "Sa vama podelio {owner}",
- "Shared in {item} with {user}" : "Deljeno u {item} sa {user}",
"group" : "grupa",
"remote" : "udaljeni",
"notify by email" : "obavesti Email-om",
@@ -120,9 +121,10 @@ OC.L10N.register(
"access control" : "kontrola pristupa",
"Share" : "Podeli",
"Warning" : "Upozorenje",
+ "Delete" : "Obriši",
+ "Rename" : "Preimenuj",
"The object type is not specified." : "Tip objekta nije zadan.",
"Enter new" : "Unesite novi",
- "Delete" : "Obriši",
"Add" : "Dodaj",
"Edit tags" : "Uredi oznake",
"Error loading dialog template: {error}" : "Greška pri učitavanju obrasca dijaloga: {error}",
@@ -136,14 +138,6 @@ OC.L10N.register(
"Please reload the page." : "Molimo, ponovo učitajte stranu.",
"The update was unsuccessful. " : "Osvežavanje je uspelo.",
"The update was successful. Redirecting you to ownCloud now." : "Ažuriranje je uspelo. Prosleđivanje na ownCloud.",
- "Couldn't reset password because the token is invalid" : "Nije bilo moguće ponovo postaviti lozinku zbog nevažećeg kontrolnog broja",
- "Couldn't send reset email. Please make sure your username is correct." : "Nije bilo moguće poslati Email za ponovno postavljanje. Molimo Vas da proverite da li je Vaše korisničko ime ispravno.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nije bilo moguće poslati Email za ponovno postavljanje lozinke jer nema Email adrese za ovo korisničko ime. Molimo Vas da kontaktirate Vašeg administratora.",
- "%s password reset" : "%s lozinka ponovo postavljena",
- "Use the following link to reset your password: {link}" : "Koristite sledeći link za reset lozinke: {link}",
- "New password" : "Nova lozinka",
- "New Password" : "Nova lozinka",
- "Reset password" : "Resetuj lozinku",
"Personal" : "Lično",
"Users" : "Korisnici",
"Apps" : "Programi",
@@ -197,6 +191,10 @@ OC.L10N.register(
"Please contact your administrator." : "Molimo Vas da kontaktirate Vašeg administratora.",
"Log in" : "Prijavi se",
"Alternative Logins" : "Alternativne prijave",
+ "Use the following link to reset your password: {link}" : "Koristite sledeći link za reset lozinke: {link}",
+ "New password" : "Nova lozinka",
+ "New Password" : "Nova lozinka",
+ "Reset password" : "Resetuj lozinku",
"This ownCloud instance is currently in single user mode." : "Ova instanca ownCloud-a je trenutno u režimu rada jednog korisnika.",
"This means only administrators can use the instance." : "Ovo znači da samo administratori mogu da koriste ovu instancu.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktirajte Vašeg sistem administratora ako se ova poruka često ili iznenada pojavljuje.",
diff --git a/core/l10n/sr@latin.json b/core/l10n/sr@latin.json
index 47b017d5a16..62bb03d0b27 100644
--- a/core/l10n/sr@latin.json
+++ b/core/l10n/sr@latin.json
@@ -11,6 +11,10 @@
"Invalid image" : "Neispravna slika",
"No temporary profile picture available, try again" : "Nije dostupna privremena slika profila, pokušajte ponovo",
"No crop data provided" : "Nisu dati podaci za sečenje slike",
+ "Couldn't reset password because the token is invalid" : "Nije bilo moguće ponovo postaviti lozinku zbog nevažećeg kontrolnog broja",
+ "Couldn't send reset email. Please make sure your username is correct." : "Nije bilo moguće poslati Email za ponovno postavljanje. Molimo Vas da proverite da li je Vaše korisničko ime ispravno.",
+ "%s password reset" : "%s lozinka ponovo postavljena",
+ "Couldn't send reset email. Please contact your administrator." : "Nemoguće slanje e-mail-a za ponovno postavljanje lozinke. Molimo Vas kontaktirajte Vašeg administratora",
"Sunday" : "Nedelja",
"Monday" : "Ponedeljak",
"Tuesday" : "Utorak",
@@ -52,7 +56,6 @@
"Settings" : "Podešavanja",
"Saving..." : "Snimam...",
"seconds ago" : "Pre par sekundi",
- "Couldn't send reset email. Please contact your administrator." : "Nemoguće slanje e-mail-a za ponovno postavljanje lozinke. Molimo Vas kontaktirajte Vašeg administratora",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Link za ponovno postavljanje Vaše lozinke je poslat na Vašu e-mail adresu. Ako ga ne primite u razumnom roku, proverite fascikle za neželjenu poštu.<br>Ako ga nema ni tamo, kontaktirajte Vašeg lokalnog administratora.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Vaši fajlovi su šifrovani. Ako nista omogućili ključ za povrat fajlova, neće biti načina da dobijete ponovo svoje podatke posle promene lozinke.<br />Ako niste sigurni šta da radite, molimo Vas da kontaktirate Vašeg administratora pre nego što nastavite.<br />Da li zaista želite da nastavite?",
"I know what I'm doing" : "Znam šta radim",
@@ -86,7 +89,6 @@
"Error" : "Greška",
"Error while sharing" : "Greška pri deljenju",
"Error while unsharing" : "Greška u uklanjanju deljenja",
- "Error while changing permissions" : "Greška u promeni dozvola",
"Error setting expiration date" : "Greška u postavljanju datuma isteka",
"The public link will expire no later than {days} days after it is created" : "Javna prečica će isteći ne kasnije od {days} dana pošto je kreirana",
"Set expiration date" : "Datum isteka",
@@ -105,7 +107,6 @@
"Send" : "Pošalji",
"Shared with you and the group {group} by {owner}" : "{owner} podelio sa Vama i grupom {group} ",
"Shared with you by {owner}" : "Sa vama podelio {owner}",
- "Shared in {item} with {user}" : "Deljeno u {item} sa {user}",
"group" : "grupa",
"remote" : "udaljeni",
"notify by email" : "obavesti Email-om",
@@ -118,9 +119,10 @@
"access control" : "kontrola pristupa",
"Share" : "Podeli",
"Warning" : "Upozorenje",
+ "Delete" : "Obriši",
+ "Rename" : "Preimenuj",
"The object type is not specified." : "Tip objekta nije zadan.",
"Enter new" : "Unesite novi",
- "Delete" : "Obriši",
"Add" : "Dodaj",
"Edit tags" : "Uredi oznake",
"Error loading dialog template: {error}" : "Greška pri učitavanju obrasca dijaloga: {error}",
@@ -134,14 +136,6 @@
"Please reload the page." : "Molimo, ponovo učitajte stranu.",
"The update was unsuccessful. " : "Osvežavanje je uspelo.",
"The update was successful. Redirecting you to ownCloud now." : "Ažuriranje je uspelo. Prosleđivanje na ownCloud.",
- "Couldn't reset password because the token is invalid" : "Nije bilo moguće ponovo postaviti lozinku zbog nevažećeg kontrolnog broja",
- "Couldn't send reset email. Please make sure your username is correct." : "Nije bilo moguće poslati Email za ponovno postavljanje. Molimo Vas da proverite da li je Vaše korisničko ime ispravno.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Nije bilo moguće poslati Email za ponovno postavljanje lozinke jer nema Email adrese za ovo korisničko ime. Molimo Vas da kontaktirate Vašeg administratora.",
- "%s password reset" : "%s lozinka ponovo postavljena",
- "Use the following link to reset your password: {link}" : "Koristite sledeći link za reset lozinke: {link}",
- "New password" : "Nova lozinka",
- "New Password" : "Nova lozinka",
- "Reset password" : "Resetuj lozinku",
"Personal" : "Lično",
"Users" : "Korisnici",
"Apps" : "Programi",
@@ -195,6 +189,10 @@
"Please contact your administrator." : "Molimo Vas da kontaktirate Vašeg administratora.",
"Log in" : "Prijavi se",
"Alternative Logins" : "Alternativne prijave",
+ "Use the following link to reset your password: {link}" : "Koristite sledeći link za reset lozinke: {link}",
+ "New password" : "Nova lozinka",
+ "New Password" : "Nova lozinka",
+ "Reset password" : "Resetuj lozinku",
"This ownCloud instance is currently in single user mode." : "Ova instanca ownCloud-a je trenutno u režimu rada jednog korisnika.",
"This means only administrators can use the instance." : "Ovo znači da samo administratori mogu da koriste ovu instancu.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Kontaktirajte Vašeg sistem administratora ako se ova poruka često ili iznenada pojavljuje.",
diff --git a/core/l10n/sv.js b/core/l10n/sv.js
index cde3ece247a..0f1b349bc26 100644
--- a/core/l10n/sv.js
+++ b/core/l10n/sv.js
@@ -13,6 +13,10 @@ OC.L10N.register(
"Invalid image" : "Ogiltig bild",
"No temporary profile picture available, try again" : "Ingen temporär profilbild finns tillgänglig, försök igen",
"No crop data provided" : "Ingen beskärdata har angivits",
+ "Couldn't reset password because the token is invalid" : "Kunde inte återställa lösenordet på grund av felaktig token",
+ "Couldn't send reset email. Please make sure your username is correct." : "Kunde inte skicka återställningsmail. Vänligen kontrollera att ditt användarnamn är korrekt.",
+ "%s password reset" : "%s återställ lösenord",
+ "Couldn't send reset email. Please contact your administrator." : "Kunde inte skicka återställningsmail. Vänligen kontakta din administratör.",
"Sunday" : "Söndag",
"Monday" : "Måndag",
"Tuesday" : "Tisdag",
@@ -54,7 +58,6 @@ OC.L10N.register(
"Settings" : "Inställningar",
"Saving..." : "Sparar...",
"seconds ago" : "sekunder sedan",
- "Couldn't send reset email. Please contact your administrator." : "Kunde inte skicka återställningsmail. Vänligen kontakta din administratör.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Länken för att återställa ditt lösenord har skickats till din e-mail. Om du inte mottar något inom kort, kontrollera spam/skräpkorgen.<br>Om det inte finns något där, vänligen kontakta din lokala administratör.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Dina filer är krypterade. Om du inte angett någon återställningsnyckel, kommer det att vara omöjligt att få tillbaka dina data efter att lösenordet är återställt..<br />Om du är osäker på vad du ska göra, vänligen kontakta din administratör innan du fortsätter.<br />Är du verkligen helt säker på att du vill fortsätta?",
"I know what I'm doing" : "Jag är säker på vad jag gör",
@@ -88,7 +91,6 @@ OC.L10N.register(
"Error" : "Fel",
"Error while sharing" : "Fel vid delning",
"Error while unsharing" : "Fel när delning skulle avslutas",
- "Error while changing permissions" : "Fel vid ändring av rättigheter",
"Error setting expiration date" : "Fel vid sättning av utgångsdatum",
"The public link will expire no later than {days} days after it is created" : "Den publika länken kommer sluta gälla inte senare än {days} dagar efter att den skapades",
"Set expiration date" : "Sätt utgångsdatum",
@@ -107,7 +109,6 @@ OC.L10N.register(
"Send" : "Skicka",
"Shared with you and the group {group} by {owner}" : "Delad med dig och gruppen {group} av {owner}",
"Shared with you by {owner}" : "Delad med dig av {owner}",
- "Shared in {item} with {user}" : "Delad i {item} med {user}",
"group" : "Grupp",
"remote" : "fjärr",
"notify by email" : "informera via e-post",
@@ -124,9 +125,10 @@ OC.L10N.register(
"Share with users or groups …" : "Dela med användare eller grupper ...",
"Share with users, groups or remote users …" : "Dela med användare, grupper eller fjärranvändare ...",
"Warning" : "Varning",
+ "Delete" : "Radera",
+ "Rename" : "Byt namn",
"The object type is not specified." : "Objekttypen är inte specificerad.",
"Enter new" : "Skriv nytt",
- "Delete" : "Radera",
"Add" : "Lägg till",
"Edit tags" : "Editera taggar",
"Error loading dialog template: {error}" : "Fel under laddning utav dialog mall: {fel}",
@@ -142,14 +144,6 @@ OC.L10N.register(
"Please reload the page." : "Vänligen ladda om sidan.",
"The update was unsuccessful. " : "Uppdateringen misslyckades.",
"The update was successful. Redirecting you to ownCloud now." : "Uppdateringen lyckades. Du omdirigeras nu till OwnCloud.",
- "Couldn't reset password because the token is invalid" : "Kunde inte återställa lösenordet på grund av felaktig token",
- "Couldn't send reset email. Please make sure your username is correct." : "Kunde inte skicka återställningsmail. Vänligen kontrollera att ditt användarnamn är korrekt.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Kunde inte skicka något återställningsmail därför att det inte finns någon e-mailadress kopplad till detta användarnamn. Vänligen kontakta din administratör.",
- "%s password reset" : "%s återställ lösenord",
- "Use the following link to reset your password: {link}" : "Använd följande länk för att återställa lösenordet: {link}",
- "New password" : "Nytt lösenord",
- "New Password" : "Nytt lösenord",
- "Reset password" : "Återställ lösenordet",
"Personal" : "Personligt",
"Users" : "Användare",
"Apps" : "Program",
@@ -205,6 +199,10 @@ OC.L10N.register(
"Please contact your administrator." : "Kontakta din administratör.",
"Log in" : "Logga in",
"Alternative Logins" : "Alternativa inloggningar",
+ "Use the following link to reset your password: {link}" : "Använd följande länk för att återställa lösenordet: {link}",
+ "New password" : "Nytt lösenord",
+ "New Password" : "Nytt lösenord",
+ "Reset password" : "Återställ lösenordet",
"This ownCloud instance is currently in single user mode." : "Denna ownCloud instans är för närvarande i enanvändarläge",
"This means only administrators can use the instance." : "Detta betyder att endast administartörer kan använda instansen.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Hör av dig till din system administratör ifall detta meddelande fortsätter eller visas oväntat.",
diff --git a/core/l10n/sv.json b/core/l10n/sv.json
index 5c0666c2011..978a1956a9e 100644
--- a/core/l10n/sv.json
+++ b/core/l10n/sv.json
@@ -11,6 +11,10 @@
"Invalid image" : "Ogiltig bild",
"No temporary profile picture available, try again" : "Ingen temporär profilbild finns tillgänglig, försök igen",
"No crop data provided" : "Ingen beskärdata har angivits",
+ "Couldn't reset password because the token is invalid" : "Kunde inte återställa lösenordet på grund av felaktig token",
+ "Couldn't send reset email. Please make sure your username is correct." : "Kunde inte skicka återställningsmail. Vänligen kontrollera att ditt användarnamn är korrekt.",
+ "%s password reset" : "%s återställ lösenord",
+ "Couldn't send reset email. Please contact your administrator." : "Kunde inte skicka återställningsmail. Vänligen kontakta din administratör.",
"Sunday" : "Söndag",
"Monday" : "Måndag",
"Tuesday" : "Tisdag",
@@ -52,7 +56,6 @@
"Settings" : "Inställningar",
"Saving..." : "Sparar...",
"seconds ago" : "sekunder sedan",
- "Couldn't send reset email. Please contact your administrator." : "Kunde inte skicka återställningsmail. Vänligen kontakta din administratör.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Länken för att återställa ditt lösenord har skickats till din e-mail. Om du inte mottar något inom kort, kontrollera spam/skräpkorgen.<br>Om det inte finns något där, vänligen kontakta din lokala administratör.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Dina filer är krypterade. Om du inte angett någon återställningsnyckel, kommer det att vara omöjligt att få tillbaka dina data efter att lösenordet är återställt..<br />Om du är osäker på vad du ska göra, vänligen kontakta din administratör innan du fortsätter.<br />Är du verkligen helt säker på att du vill fortsätta?",
"I know what I'm doing" : "Jag är säker på vad jag gör",
@@ -86,7 +89,6 @@
"Error" : "Fel",
"Error while sharing" : "Fel vid delning",
"Error while unsharing" : "Fel när delning skulle avslutas",
- "Error while changing permissions" : "Fel vid ändring av rättigheter",
"Error setting expiration date" : "Fel vid sättning av utgångsdatum",
"The public link will expire no later than {days} days after it is created" : "Den publika länken kommer sluta gälla inte senare än {days} dagar efter att den skapades",
"Set expiration date" : "Sätt utgångsdatum",
@@ -105,7 +107,6 @@
"Send" : "Skicka",
"Shared with you and the group {group} by {owner}" : "Delad med dig och gruppen {group} av {owner}",
"Shared with you by {owner}" : "Delad med dig av {owner}",
- "Shared in {item} with {user}" : "Delad i {item} med {user}",
"group" : "Grupp",
"remote" : "fjärr",
"notify by email" : "informera via e-post",
@@ -122,9 +123,10 @@
"Share with users or groups …" : "Dela med användare eller grupper ...",
"Share with users, groups or remote users …" : "Dela med användare, grupper eller fjärranvändare ...",
"Warning" : "Varning",
+ "Delete" : "Radera",
+ "Rename" : "Byt namn",
"The object type is not specified." : "Objekttypen är inte specificerad.",
"Enter new" : "Skriv nytt",
- "Delete" : "Radera",
"Add" : "Lägg till",
"Edit tags" : "Editera taggar",
"Error loading dialog template: {error}" : "Fel under laddning utav dialog mall: {fel}",
@@ -140,14 +142,6 @@
"Please reload the page." : "Vänligen ladda om sidan.",
"The update was unsuccessful. " : "Uppdateringen misslyckades.",
"The update was successful. Redirecting you to ownCloud now." : "Uppdateringen lyckades. Du omdirigeras nu till OwnCloud.",
- "Couldn't reset password because the token is invalid" : "Kunde inte återställa lösenordet på grund av felaktig token",
- "Couldn't send reset email. Please make sure your username is correct." : "Kunde inte skicka återställningsmail. Vänligen kontrollera att ditt användarnamn är korrekt.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Kunde inte skicka något återställningsmail därför att det inte finns någon e-mailadress kopplad till detta användarnamn. Vänligen kontakta din administratör.",
- "%s password reset" : "%s återställ lösenord",
- "Use the following link to reset your password: {link}" : "Använd följande länk för att återställa lösenordet: {link}",
- "New password" : "Nytt lösenord",
- "New Password" : "Nytt lösenord",
- "Reset password" : "Återställ lösenordet",
"Personal" : "Personligt",
"Users" : "Användare",
"Apps" : "Program",
@@ -203,6 +197,10 @@
"Please contact your administrator." : "Kontakta din administratör.",
"Log in" : "Logga in",
"Alternative Logins" : "Alternativa inloggningar",
+ "Use the following link to reset your password: {link}" : "Använd följande länk för att återställa lösenordet: {link}",
+ "New password" : "Nytt lösenord",
+ "New Password" : "Nytt lösenord",
+ "Reset password" : "Återställ lösenordet",
"This ownCloud instance is currently in single user mode." : "Denna ownCloud instans är för närvarande i enanvändarläge",
"This means only administrators can use the instance." : "Detta betyder att endast administartörer kan använda instansen.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Hör av dig till din system administratör ifall detta meddelande fortsätter eller visas oväntat.",
diff --git a/core/l10n/ta_LK.js b/core/l10n/ta_LK.js
index 47339a42287..c5f022d0813 100644
--- a/core/l10n/ta_LK.js
+++ b/core/l10n/ta_LK.js
@@ -50,7 +50,6 @@ OC.L10N.register(
"Error" : "வழு",
"Error while sharing" : "பகிரும் போதான வழு",
"Error while unsharing" : "பகிராமல் உள்ளப்போதான வழு",
- "Error while changing permissions" : "அனுமதிகள் மாறும்போதான வழு",
"Error setting expiration date" : "காலாவதியாகும் திகதியை குறிப்பிடுவதில் வழு",
"Set expiration date" : "காலாவதி தேதியை குறிப்பிடுக",
"Expiration date" : "காலவதியாகும் திகதி",
@@ -59,7 +58,6 @@ OC.L10N.register(
"Password" : "கடவுச்சொல்",
"Shared with you and the group {group} by {owner}" : "உங்களுடனும் குழுவுக்கிடையிலும் {குழு} பகிரப்பட்டுள்ளது {உரிமையாளர்}",
"Shared with you by {owner}" : "உங்களுடன் பகிரப்பட்டுள்ளது {உரிமையாளர்}",
- "Shared in {item} with {user}" : "{பயனாளர்} உடன் {உருப்படி} பகிரப்பட்டுள்ளது",
"group" : "குழு",
"Unshare" : "பகிரப்படாதது",
"can edit" : "தொகுக்க முடியும்",
@@ -68,12 +66,10 @@ OC.L10N.register(
"access control" : "கட்டுப்பாடான அணுகல்",
"Share" : "பகிர்வு",
"Warning" : "எச்சரிக்கை",
- "The object type is not specified." : "பொருள் வகை குறிப்பிடப்படவில்லை.",
"Delete" : "நீக்குக",
+ "Rename" : "பெயர்மாற்றம்",
+ "The object type is not specified." : "பொருள் வகை குறிப்பிடப்படவில்லை.",
"Add" : "சேர்க்க",
- "Use the following link to reset your password: {link}" : "உங்கள் கடவுச்சொல்லை மீளமைக்க பின்வரும் இணைப்பை பயன்படுத்தவும் : {இணைப்பு}",
- "New password" : "புதிய கடவுச்சொல்",
- "Reset password" : "மீளமைத்த கடவுச்சொல்",
"Personal" : "தனிப்பட்ட",
"Users" : "பயனாளர்",
"Apps" : "செயலிகள்",
@@ -92,6 +88,9 @@ OC.L10N.register(
"Finish setup" : "அமைப்பை முடிக்க",
"Log out" : "விடுபதிகை செய்க",
"Search" : "தேடுதல்",
- "Log in" : "புகுபதிகை"
+ "Log in" : "புகுபதிகை",
+ "Use the following link to reset your password: {link}" : "உங்கள் கடவுச்சொல்லை மீளமைக்க பின்வரும் இணைப்பை பயன்படுத்தவும் : {இணைப்பு}",
+ "New password" : "புதிய கடவுச்சொல்",
+ "Reset password" : "மீளமைத்த கடவுச்சொல்"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/ta_LK.json b/core/l10n/ta_LK.json
index cbe0c8b9df7..4d978c78712 100644
--- a/core/l10n/ta_LK.json
+++ b/core/l10n/ta_LK.json
@@ -48,7 +48,6 @@
"Error" : "வழு",
"Error while sharing" : "பகிரும் போதான வழு",
"Error while unsharing" : "பகிராமல் உள்ளப்போதான வழு",
- "Error while changing permissions" : "அனுமதிகள் மாறும்போதான வழு",
"Error setting expiration date" : "காலாவதியாகும் திகதியை குறிப்பிடுவதில் வழு",
"Set expiration date" : "காலாவதி தேதியை குறிப்பிடுக",
"Expiration date" : "காலவதியாகும் திகதி",
@@ -57,7 +56,6 @@
"Password" : "கடவுச்சொல்",
"Shared with you and the group {group} by {owner}" : "உங்களுடனும் குழுவுக்கிடையிலும் {குழு} பகிரப்பட்டுள்ளது {உரிமையாளர்}",
"Shared with you by {owner}" : "உங்களுடன் பகிரப்பட்டுள்ளது {உரிமையாளர்}",
- "Shared in {item} with {user}" : "{பயனாளர்} உடன் {உருப்படி} பகிரப்பட்டுள்ளது",
"group" : "குழு",
"Unshare" : "பகிரப்படாதது",
"can edit" : "தொகுக்க முடியும்",
@@ -66,12 +64,10 @@
"access control" : "கட்டுப்பாடான அணுகல்",
"Share" : "பகிர்வு",
"Warning" : "எச்சரிக்கை",
- "The object type is not specified." : "பொருள் வகை குறிப்பிடப்படவில்லை.",
"Delete" : "நீக்குக",
+ "Rename" : "பெயர்மாற்றம்",
+ "The object type is not specified." : "பொருள் வகை குறிப்பிடப்படவில்லை.",
"Add" : "சேர்க்க",
- "Use the following link to reset your password: {link}" : "உங்கள் கடவுச்சொல்லை மீளமைக்க பின்வரும் இணைப்பை பயன்படுத்தவும் : {இணைப்பு}",
- "New password" : "புதிய கடவுச்சொல்",
- "Reset password" : "மீளமைத்த கடவுச்சொல்",
"Personal" : "தனிப்பட்ட",
"Users" : "பயனாளர்",
"Apps" : "செயலிகள்",
@@ -90,6 +86,9 @@
"Finish setup" : "அமைப்பை முடிக்க",
"Log out" : "விடுபதிகை செய்க",
"Search" : "தேடுதல்",
- "Log in" : "புகுபதிகை"
+ "Log in" : "புகுபதிகை",
+ "Use the following link to reset your password: {link}" : "உங்கள் கடவுச்சொல்லை மீளமைக்க பின்வரும் இணைப்பை பயன்படுத்தவும் : {இணைப்பு}",
+ "New password" : "புதிய கடவுச்சொல்",
+ "Reset password" : "மீளமைத்த கடவுச்சொல்"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/te.js b/core/l10n/te.js
index f2be12f12da..6483cd82ee1 100644
--- a/core/l10n/te.js
+++ b/core/l10n/te.js
@@ -35,11 +35,11 @@ OC.L10N.register(
"Warning" : "హెచ్చరిక",
"Delete" : "తొలగించు",
"Add" : "చేర్చు",
- "New password" : "కొత్త సంకేతపదం",
"Personal" : "వ్యక్తిగతం",
"Users" : "వాడుకరులు",
"Help" : "సహాయం",
"Username" : "వాడుకరి పేరు",
- "Log out" : "నిష్క్రమించు"
+ "Log out" : "నిష్క్రమించు",
+ "New password" : "కొత్త సంకేతపదం"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/te.json b/core/l10n/te.json
index f165c3f457f..d0b93b5d059 100644
--- a/core/l10n/te.json
+++ b/core/l10n/te.json
@@ -33,11 +33,11 @@
"Warning" : "హెచ్చరిక",
"Delete" : "తొలగించు",
"Add" : "చేర్చు",
- "New password" : "కొత్త సంకేతపదం",
"Personal" : "వ్యక్తిగతం",
"Users" : "వాడుకరులు",
"Help" : "సహాయం",
"Username" : "వాడుకరి పేరు",
- "Log out" : "నిష్క్రమించు"
+ "Log out" : "నిష్క్రమించు",
+ "New password" : "కొత్త సంకేతపదం"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/th_TH.js b/core/l10n/th_TH.js
index fed963670ad..b8b191ae8a3 100644
--- a/core/l10n/th_TH.js
+++ b/core/l10n/th_TH.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "อัพเดท \"%s\" ไปยัง %s",
"Repair warning: " : "เตือนการซ่อมแซม:",
"Repair error: " : "เกิดข้อผิดพลาดในการซ่อมแซม:",
- "Set log level to debug - current level: \"%s\"" : "การตั้งค่าระดับของการบันทึกเพื่อแก้ปัญหา - ระดับปัจจุบันคือ: \"%s\"",
- "Reset log level to \"%s\"" : "รีเซ็ทระดับการบันทึกเป็น \"%s\"",
+ "Set log level to debug" : "ตั้งค่าระดับบันทึกเพื่อแก้ปัญหา",
+ "Reset log level" : "ตั้งค่าระดับบันทึกใหม่",
+ "Starting code integrity check" : "กำลังเริ่มต้นรหัสตรวจสอบความสมบูรณ์",
+ "Finished code integrity check" : "ตรวจสอบความสมบูรณ์ของรหัสเสร็จสิ้น",
"%s (3rdparty)" : "%s (บุคคลที่ 3)",
"%s (incompatible)" : "%s (เข้ากันไม่ได้)",
"Following apps have been disabled: %s" : "แอพฯดังต่อไปนี้ถูกปิดการใช้งาน: %s",
"Already up to date" : "มีอยู่แล้วถึงวันที่",
+ "Please select a file." : "กรุณาเลือกแฟ้ม",
"File is too big" : "ไฟล์มีขนาดใหญ่เกินไป",
"Invalid file provided" : "ระบุไฟล์ไม่ถูกต้อง",
"No image or file provided" : "ไม่มีรูปภาพหรือไฟล์ที่ระบุ",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "ไม่มีการครอบตัดข้อมูลที่ระบุ",
"No valid crop data provided" : "ไม่ได้ระบุข้อมูลการครอบตัดที่ถูกต้อง",
"Crop is not square" : "การครอบตัดไม่เป็นสี่เหลี่ยม",
+ "Couldn't reset password because the token is invalid" : "ไม่สามารถตั้งรหัสผ่านใหม่เพราะโทเค็นไม่ถูกต้อง",
+ "Couldn't reset password because the token is expired" : "ไม่สามารถตั้งค่ารหัสผ่านเพราะโทเค็นหมดอายุ",
+ "Couldn't send reset email. Please make sure your username is correct." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่ กรุณาตรวจสอบชื่อผู้ใช้ของคุณให้ถูกต้อง",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "ไม่ควร",
+ "%s password reset" : "%s ตั้งรหัสผ่านใหม่",
+ "Couldn't send reset email. Please contact your administrator." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่ กรุณาติดต่อผู้ดูแลระบบ",
"Sunday" : "วันอาทิตย์",
"Monday" : "วันจันทร์",
"Tuesday" : "วันอังคาร",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "ต.ค.",
"Nov." : "พ.ย.",
"Dec." : "ธ.ค.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">มีปัญหาเกี่ยวกับการตรวจสอบความสมบูรณ์ของรหัส รายละเอียดเพิ่มเติม...</a>",
"Settings" : "ตั้งค่า",
"Saving..." : "กำลังบันทึกข้อมูล...",
"seconds ago" : "วินาที ก่อนหน้านี้",
- "Couldn't send reset email. Please contact your administrator." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่ กรุณาติดต่อผู้ดูแลระบบ",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "ลิงค์ที่ใช้สำหรับตั้งค่ารหัสผ่านใหม่ ของคุณ ได้ถูกส่งไปยังอีเมลของคุณ หากคุณยังไม่ได้รับอีกเมล ลองไปดูที่โฟลเดอร์ สแปม/ถังขยะ ในอีเมลของคุณ <br>ทั้งนี้หากหาอีเมลไม่พบกรุณาติดต่อผู้ดูแลระบบ",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "ไฟล์ของคุณจะถูกเข้ารหัส หากคุณยังไม่ได้เปิดใช้งานรหัสการกู้คืน คุณจะได้รับข้อมูลของคุณกลับมาหลังจากที่รหัสผ่านของคุณถูกรีเซ็ต<br /> หากคุณไม่แน่ใจว่าควรทำอย่างไรโปรดติดต่อผู้ดูแลระบบของคุณก่อนที่คุณจะดำเนินการต่อไป <br /> คุณต้องการดำเนินการต่อ?",
"I know what I'm doing" : "ฉันรู้ว่าฉันกำลังทำอะไรอยู่",
@@ -109,14 +118,16 @@ OC.L10N.register(
"Good password" : "รหัสผ่านระดับดี",
"Strong password" : "รหัสผ่านระดับดีมาก",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "เว็บเซิร์ฟเวอร์ของคุณยังไม่ถูกติดตั้งอย่างถูกต้องเพื่ออนุญาตให้ประสานข้อมูลให้ตรงกัน เนื่องจากอินเตอร์เฟซ WebDAV อาจเสียหาย",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "เว็บเซิร์ฟเวอร์ของคุณไม่ได้ติดตั้งอย่างถูกต้องเพื่อที่จะแก้ไข \"{url}\" สามารถข้อมูลเพิ่มเติมได้ใน <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "เซิร์ฟเวอร์นี้ไม่มีการเชื่อมต่ออินเทอร์เน็ตซึ่งหมายความว่าบางส่วนของคุณสมบัติ เช่น การจัดเก็บข้อมูลภายนอก การแจ้งเตือนเกี่ยวกับการปรับปรุงหรือการติดตั้งแอพพลิเคชันของบุคคลที่สามจะไม่ทำงาน การเข้าถึงไฟล์จากระยะไกลและการส่งอีเมล์แจ้งเตือนอาจจะไม่ทำงาน เราขอแนะนำให้เปิดใช้งานการเชื่อมต่ออินเทอร์เน็ตสำหรับเซิร์ฟเวอร์นี้ถ้าคุณต้องการใช้งานคุณสมบัติทั้งหมด",
- "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "ข้อมูลไดเรกทอรีและไฟล์ของคุณอาจจะสามารถเข้าถึงได้จากอินเทอร์เน็ต ขณะที่ htaccess ไฟล์ไม่ทำงาน เราขอแนะนำให้คุณกำหนดค่าเว็บเซิร์ฟเวอร์ของคุณในทางที่ข้อมูลไดเรกทอรีไม่สามารถเข้าถึงได้หรือคุณย้ายข้อมูลไดเรกทอรีไปยังนอกเว็บเซิร์ฟเวอร์หรือเอกสาร",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "ไม่ได้ตั้งค่าหน่วยความจำแคช เพื่อเพิ่มประสิทธิภาพกรุณาตั้งค่า Memcache ของคุณ สามารถดูข้อมูลเพิ่มเติมได้ที่ <a href=\"{docLink}\">เอกสาร</a>",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ไม่สามารถอ่านโดย PHP ซึ่งมีผลด้านความปลอดภัยเป็นอย่างมาก สามารถดูข้อมูลเพิ่มเติมได้ที่ <a href=\"{docLink}\">เอกสาร</a>",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "PHP รุ่น ({version}) ของคุณ จะไม่ได้รับ <a href=\"{phpLink}\">การสนับสนุนโดย PHP</a> เราขอแนะนำให้คุณอัพเกรดรุ่นของ PHP เพื่อความปลอดภัย",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "การกำหนดค่าพร็อกซี่ไม่ถูกต้องหรือคุณกำลังเข้าถึง ownCloud จากพร็อกซี่ที่เชื่อถือได้ ถ้าคุณไม่ได้เข้าถึง ownCloud จากพร็อกซี่ที่เชื่อถือได้ นี้เป็นปัญหาด้านความปลอดภัย คุณอาจถูกโจมดีจากผู้ไม่หวังดี อ่านข้อมูลเพิ่มเติมได้ที่ <a href=\"{docLink}\">เอกสาร</a>",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached เป็นการกำหนดค่าแคช แต่มีโมดูล PHP ของ \"memcache\" ที่ผิดพลาดได้ถูกติดตั้ง \\OC\\Memcache\\Memcached สนับสนุนเฉพาะ \"memcached\" ไม่ใช่ \"memcache\" ดูได้ที่ <a href=\"{wikiLink}\">วิกิพีเดียเกี่ยวกับโมดูล Memcached</a>",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "ไม่ได้กำหนดค่าหน่วยความจำแคช เพื่อเพิ่มประสิทธิภาพของคุณโปรดกำหนดค่า memcache หากต้องการข้อมูลเพิ่มเติมสามารถอ่านได้ใน <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "ไม่สามารถอ่าน /dev/urandom โดย PHP ซึ่งมีผลอย่างมากสำหรับเหตุผลด้านความปลอดภัย สามารถข้อมูลเพิ่มเติมได้ใน <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "PHP ของคุณรุ่น ({version}) <a target=\"_blank\" href=\"{phpLink}\">ไม่สนับสนุน PHP</a> เราขอแนะนำให้อัพเกรดรุ่น PHP ของคุณ เพื่อปรับปรุงประสิทธิภาพการทำงานและเนื้อหาด้านความปลอดภัย",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "การกำหนดค่าส่วนหัวของรีเวิร์สพร็อกซี่ไม่ถูกต้องหรือคุณกำลังเข้าถึง ownCloud จากพร็อกซี่ที่เชื่อถือได้ ถ้าคุณไม่ได้เข้าถึง ownCloud จากพร็อกซี่ที่เชื่อถือได้นี้เป็นปัญหาด้านความปลอดภัยและมันจะอณุญาตทำให้แฮกเกอร์ปลอมที่อยู่ IP ของพวกเขา ข้อมูลเพิ่มเติมสามารถอ่านได้ใน <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "การกำหนดค่า memcach ผิดพลาดเนื่องจากมีโมดูล PHP ของ memcache ได้ถูกติดตั้งไปแล้ว มีการติดตั้ง \\OC\\Memcache\\Memcached สนับสนุนเฉพาะ \"memcached\" แต่ไม่สนับสนุน \"memcache\" คุณสามารถดู <a target=\"_blank\" href=\"{wikiLink}\">ข้อมูลเกี่ยวกับทั้ง 2 โมดูล</a>",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "บางไฟล์ยังไม่ผ่านการตรวจสอบความสมบูรณ์ ข้อมูลเพิ่มเติมเกี่ยวกับวิธีการแก้ไขปัญหาเหล่านี้สามารถอ่านได้จาก <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา (<a href=\"{codeIntegrityDownloadEndpoint}\">รายชื่อของไฟล์ที่ไม่ถูกต้อง…</a> / <a href=\"{rescanEndpoint}\">ค้นหาใหม่…</a>)",
"Error occurred while checking server setup" : "เกิดข้อผิดพลาดขณะที่ทำการตรวจสอบการติดตั้งเซิร์ฟเวอร์",
+ "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "ข้อมูลไดเรกทอรีและไฟล์ของคุณอาจจะสามารถเข้าถึงได้จากอินเทอร์เน็ต ขณะที่ htaccess ไฟล์ไม่ทำงาน เราขอแนะนำให้คุณกำหนดค่าเว็บเซิร์ฟเวอร์ของคุณในทางที่ข้อมูลไดเรกทอรีไม่สามารถเข้าถึงได้หรือคุณย้ายข้อมูลไดเรกทอรีไปยังนอกเว็บเซิร์ฟเวอร์หรือเอกสาร",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" ไม่ได้กำหนดค่าส่วนหัว Http ให้เท่ากับ \"{expected}\" นี่คือระบบการรักษาความปลอดภัยที่มีศักยภาพหรือลดความเสี่ยงที่จะเกิดขึ้นเราขอแนะนำให้ปรับการตั้งค่านี้",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"Strict-Transport-Security\" ส่วนหัว HTTP ไม่ได้กำหนดค่าให้น้อยกว่า \"{seconds}\" วินาที เพื่อความปลอดภัยที่เพิ่มขึ้นเราขอแนะนำให้เปิดใช้งาน HSTS ที่อธิบายไว้ใน <a href=\"{docUrl}\">เคล็ดลับการรักษาความปลอดภัย</a> ของเรา",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "คุณกำลังเข้าถึงเว็บไซต์นี้ผ่านทาง HTTP เราขอแนะนำให้คุณกำหนดค่าเซิร์ฟเวอร์ของคุณที่จะต้องใช้ HTTPS แทนตามที่อธิบายไว้ใน <a href=\"{docUrl}\">เคล็ดลับการรักษาความปลอดภัย</a> ของเรา",
@@ -125,7 +136,6 @@ OC.L10N.register(
"Error" : "ข้อผิดพลาด",
"Error while sharing" : "เกิดข้อผิดพลาดขณะกำลังแชร์ข้อมูล",
"Error while unsharing" : "เกิดข้อผิดพลาดขณะกำลังยกเลิกการแชร์ข้อมูล",
- "Error while changing permissions" : "เกิดข้อผิดพลาดขณะกำลังเปลี่ยนสิทธิ์การเข้าใช้งาน",
"Error setting expiration date" : "เกิดข้อผิดพลาดในการตั้งค่าวันที่หมดอายุ",
"The public link will expire no later than {days} days after it is created" : "ลิงค์สาธารณะจะหมดอายุภายใน {days} วัน หลังจากที่มันถูกสร้างขึ้น",
"Set expiration date" : "กำหนดวันที่หมดอายุ",
@@ -144,7 +154,6 @@ OC.L10N.register(
"Send" : "ส่ง",
"Shared with you and the group {group} by {owner}" : "ได้แชร์ให้กับคุณ และกลุ่ม {group} โดย {owner}",
"Shared with you by {owner}" : "ถูกแชร์ให้กับคุณโดย {owner}",
- "Shared in {item} with {user}" : "ได้แชร์ {item} ให้กับ {user}",
"group" : "กลุ่มผู้ใช้งาน",
"remote" : "ระยะไกล",
"notify by email" : "แจ้งเตือนทางอีเมล",
@@ -155,17 +164,25 @@ OC.L10N.register(
"change" : "เปลี่ยนแปลง",
"delete" : "ลบ",
"access control" : "ควบคุมการเข้าถึง",
+ "Could not unshare" : "ไม่สามารถยกเลิกการแชร์ได้",
"Share details could not be loaded for this item." : "รายละเอียดการแชร์ไม่สามารถโหลดสำหรับรายการนี้",
"An error occured. Please try again" : "เกิดข้อผิดพลาด กรุณาลองอีกครั้ง",
"Share" : "แชร์",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "แชร์กับคนใน ownClouds อื่นๆ ที่ใช้ไวยากรณ์ username@example.com/owncloud ",
"Share with users or groups …" : "แชร์กับผู้ใช้หรือกลุ่ม ...",
"Share with users, groups or remote users …" : "แชร์กับผู้ใช้กลุ่มหรือผู้ใช้ระยะไกล ...",
+ "Error removing share" : "พบข้อผิดพลาดในรายการที่แชร์ออก",
"Warning" : "คำเตือน",
"Error while sending notification" : "เกิดข้อผิดพลาดขณะกำลังส่งการแจ้งเตือน",
+ "Non-existing tag #{tag}" : "ไม่มีแท็กนี้อยู่ #{tag}",
+ "not assignable" : "ไม่ได้รับมอบหมาย",
+ "invisible" : "จะมองไม่เห็น",
+ "({scope})" : "({scope})",
+ "Delete" : "ลบ",
+ "Rename" : "เปลี่ยนชื่อ",
+ "Global tags" : "แท็กทั่วไป",
"The object type is not specified." : "ชนิดของวัตถุยังไม่ได้รับการระบุ",
"Enter new" : "ใส่ข้อมูลใหม่",
- "Delete" : "ลบ",
"Add" : "เพิ่ม",
"Edit tags" : "แก้ไขแท็ก",
"Error loading dialog template: {error}" : "เกิดข้อผิดพลาดขณะโหลดไดอะล็อกแม่แบบ: {error}",
@@ -184,15 +201,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "อัพเดทไม่สำเร็จ",
"The update was successful. There were warnings." : "การอัพเดทสำเร็จ แต่มีคำเตือนอยู่",
"The update was successful. Redirecting you to ownCloud now." : "การอัพเดทเสร็จเรียบร้อย กำลังเปลี่ยนเส้นทางไปที่ ownCloud อยู่ในขณะนี้",
- "Couldn't reset password because the token is invalid" : "ไม่สามารถตั้งรหัสผ่านใหม่เพราะโทเค็นไม่ถูกต้อง",
- "Couldn't reset password because the token is expired" : "ไม่สามารถตั้งค่ารหัสผ่านเพราะโทเค็นหมดอายุ",
- "Couldn't send reset email. Please make sure your username is correct." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่ กรุณาตรวจสอบชื่อผู้ใช้ของคุณให้ถูกต้อง",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่เพราะไม่มีที่อยู่อีเมลนี้ กรุณาติดต่อผู้ดูแลระบบ",
- "%s password reset" : "%s ตั้งรหัสผ่านใหม่",
- "Use the following link to reset your password: {link}" : "ใช้ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่านของคุณใหม่: {link}",
- "New password" : "รหัสผ่านใหม่",
- "New Password" : "รหัสผ่านใหม่",
- "Reset password" : "เปลี่ยนรหัสผ่านใหม่",
"Searching other places" : "กำลังค้นหาสถานที่อื่นๆ",
"No search results in other folders" : "ไม่พบผลลัพธ์การค้นหาในโฟลเดอร์อื่นๆ",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["ค้นหาพบ {count} ผลลัพธ์ในโฟลเดอร์อื่นๆ"],
@@ -262,13 +270,19 @@ OC.L10N.register(
"Please try again or contact your administrator." : "โปรดลองอีกครั้งหรือติดต่อผู้ดูแลระบบ",
"Log in" : "เข้าสู่ระบบ",
"Wrong password. Reset it?" : "รหัสผ่านผิด ตั้งค่าใหม่?",
+ "Wrong password." : "รหัสผ่านผิดพลาด",
"Stay logged in" : "กำลังอยู่ในระบบ",
"Alternative Logins" : "ทางเลือกการเข้าสู่ระบบ",
+ "Use the following link to reset your password: {link}" : "ใช้ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่านของคุณใหม่: {link}",
+ "New password" : "รหัสผ่านใหม่",
+ "New Password" : "รหัสผ่านใหม่",
+ "Reset password" : "เปลี่ยนรหัสผ่านใหม่",
"This ownCloud instance is currently in single user mode." : "ขณะนี้ ownCloud อยู่ในโหมดผู้ใช้คนเดียว",
"This means only administrators can use the instance." : "ซึ่งหมายความว่าผู้ดูแลระบบสามารถใช้อินสแตนซ์",
"Contact your system administrator if this message persists or appeared unexpectedly." : "ติดต่อผู้ดูแลระบบของคุณหากข้อความนี้ยังคงมีอยู่หรือปรากฏโดยไม่คาดคิด",
"Thank you for your patience." : "ขอบคุณสำหรับความอดทนของคุณ เราจะนำความคิดเห็นของท่านมาปรับปรุงระบบให้ดียิ่งขึ้น",
"You are accessing the server from an untrusted domain." : "คุณกำลังเข้าถึงเซิร์ฟเวอร์จากโดเมนที่ไม่น่าเชื่อถือ",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "กรุณาติดต่อผู้ดูแลระบบ หากคุณเป็นผู้ดูแลระบบ นี้ตัวอย่างการกำหนดค่า \"trusted_domains\" ใน\nconfig/config.php ตัวอย่างการกำหนดค่ามีอยู่ใน config/config.sample.php",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "ทั้งนี้ขึ้นอยู่กับการกำหนดค่าของคุณ ผู้ดูแลระบบอาจสามารถใช้ปุ่มด้านล่างเพื่อกำหนดให้โดเมนนี้มีความน่าเชื่อถือ",
"Add \"%s\" as trusted domain" : "ได้เพิ่ม \"%s\" เป็นโดเมนที่เชื่อถือ",
"App update required" : "จำเป้นต้องอัพเดทแอพฯ",
diff --git a/core/l10n/th_TH.json b/core/l10n/th_TH.json
index 70c774d4a9d..1a72dec0b22 100644
--- a/core/l10n/th_TH.json
+++ b/core/l10n/th_TH.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "อัพเดท \"%s\" ไปยัง %s",
"Repair warning: " : "เตือนการซ่อมแซม:",
"Repair error: " : "เกิดข้อผิดพลาดในการซ่อมแซม:",
- "Set log level to debug - current level: \"%s\"" : "การตั้งค่าระดับของการบันทึกเพื่อแก้ปัญหา - ระดับปัจจุบันคือ: \"%s\"",
- "Reset log level to \"%s\"" : "รีเซ็ทระดับการบันทึกเป็น \"%s\"",
+ "Set log level to debug" : "ตั้งค่าระดับบันทึกเพื่อแก้ปัญหา",
+ "Reset log level" : "ตั้งค่าระดับบันทึกใหม่",
+ "Starting code integrity check" : "กำลังเริ่มต้นรหัสตรวจสอบความสมบูรณ์",
+ "Finished code integrity check" : "ตรวจสอบความสมบูรณ์ของรหัสเสร็จสิ้น",
"%s (3rdparty)" : "%s (บุคคลที่ 3)",
"%s (incompatible)" : "%s (เข้ากันไม่ได้)",
"Following apps have been disabled: %s" : "แอพฯดังต่อไปนี้ถูกปิดการใช้งาน: %s",
"Already up to date" : "มีอยู่แล้วถึงวันที่",
+ "Please select a file." : "กรุณาเลือกแฟ้ม",
"File is too big" : "ไฟล์มีขนาดใหญ่เกินไป",
"Invalid file provided" : "ระบุไฟล์ไม่ถูกต้อง",
"No image or file provided" : "ไม่มีรูปภาพหรือไฟล์ที่ระบุ",
@@ -30,6 +33,12 @@
"No crop data provided" : "ไม่มีการครอบตัดข้อมูลที่ระบุ",
"No valid crop data provided" : "ไม่ได้ระบุข้อมูลการครอบตัดที่ถูกต้อง",
"Crop is not square" : "การครอบตัดไม่เป็นสี่เหลี่ยม",
+ "Couldn't reset password because the token is invalid" : "ไม่สามารถตั้งรหัสผ่านใหม่เพราะโทเค็นไม่ถูกต้อง",
+ "Couldn't reset password because the token is expired" : "ไม่สามารถตั้งค่ารหัสผ่านเพราะโทเค็นหมดอายุ",
+ "Couldn't send reset email. Please make sure your username is correct." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่ กรุณาตรวจสอบชื่อผู้ใช้ของคุณให้ถูกต้อง",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "ไม่ควร",
+ "%s password reset" : "%s ตั้งรหัสผ่านใหม่",
+ "Couldn't send reset email. Please contact your administrator." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่ กรุณาติดต่อผู้ดูแลระบบ",
"Sunday" : "วันอาทิตย์",
"Monday" : "วันจันทร์",
"Tuesday" : "วันอังคาร",
@@ -75,10 +84,10 @@
"Oct." : "ต.ค.",
"Nov." : "พ.ย.",
"Dec." : "ธ.ค.",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">มีปัญหาเกี่ยวกับการตรวจสอบความสมบูรณ์ของรหัส รายละเอียดเพิ่มเติม...</a>",
"Settings" : "ตั้งค่า",
"Saving..." : "กำลังบันทึกข้อมูล...",
"seconds ago" : "วินาที ก่อนหน้านี้",
- "Couldn't send reset email. Please contact your administrator." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่ กรุณาติดต่อผู้ดูแลระบบ",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "ลิงค์ที่ใช้สำหรับตั้งค่ารหัสผ่านใหม่ ของคุณ ได้ถูกส่งไปยังอีเมลของคุณ หากคุณยังไม่ได้รับอีกเมล ลองไปดูที่โฟลเดอร์ สแปม/ถังขยะ ในอีเมลของคุณ <br>ทั้งนี้หากหาอีเมลไม่พบกรุณาติดต่อผู้ดูแลระบบ",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "ไฟล์ของคุณจะถูกเข้ารหัส หากคุณยังไม่ได้เปิดใช้งานรหัสการกู้คืน คุณจะได้รับข้อมูลของคุณกลับมาหลังจากที่รหัสผ่านของคุณถูกรีเซ็ต<br /> หากคุณไม่แน่ใจว่าควรทำอย่างไรโปรดติดต่อผู้ดูแลระบบของคุณก่อนที่คุณจะดำเนินการต่อไป <br /> คุณต้องการดำเนินการต่อ?",
"I know what I'm doing" : "ฉันรู้ว่าฉันกำลังทำอะไรอยู่",
@@ -107,14 +116,16 @@
"Good password" : "รหัสผ่านระดับดี",
"Strong password" : "รหัสผ่านระดับดีมาก",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "เว็บเซิร์ฟเวอร์ของคุณยังไม่ถูกติดตั้งอย่างถูกต้องเพื่ออนุญาตให้ประสานข้อมูลให้ตรงกัน เนื่องจากอินเตอร์เฟซ WebDAV อาจเสียหาย",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "เว็บเซิร์ฟเวอร์ของคุณไม่ได้ติดตั้งอย่างถูกต้องเพื่อที่จะแก้ไข \"{url}\" สามารถข้อมูลเพิ่มเติมได้ใน <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "เซิร์ฟเวอร์นี้ไม่มีการเชื่อมต่ออินเทอร์เน็ตซึ่งหมายความว่าบางส่วนของคุณสมบัติ เช่น การจัดเก็บข้อมูลภายนอก การแจ้งเตือนเกี่ยวกับการปรับปรุงหรือการติดตั้งแอพพลิเคชันของบุคคลที่สามจะไม่ทำงาน การเข้าถึงไฟล์จากระยะไกลและการส่งอีเมล์แจ้งเตือนอาจจะไม่ทำงาน เราขอแนะนำให้เปิดใช้งานการเชื่อมต่ออินเทอร์เน็ตสำหรับเซิร์ฟเวอร์นี้ถ้าคุณต้องการใช้งานคุณสมบัติทั้งหมด",
- "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "ข้อมูลไดเรกทอรีและไฟล์ของคุณอาจจะสามารถเข้าถึงได้จากอินเทอร์เน็ต ขณะที่ htaccess ไฟล์ไม่ทำงาน เราขอแนะนำให้คุณกำหนดค่าเว็บเซิร์ฟเวอร์ของคุณในทางที่ข้อมูลไดเรกทอรีไม่สามารถเข้าถึงได้หรือคุณย้ายข้อมูลไดเรกทอรีไปยังนอกเว็บเซิร์ฟเวอร์หรือเอกสาร",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "ไม่ได้ตั้งค่าหน่วยความจำแคช เพื่อเพิ่มประสิทธิภาพกรุณาตั้งค่า Memcache ของคุณ สามารถดูข้อมูลเพิ่มเติมได้ที่ <a href=\"{docLink}\">เอกสาร</a>",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom ไม่สามารถอ่านโดย PHP ซึ่งมีผลด้านความปลอดภัยเป็นอย่างมาก สามารถดูข้อมูลเพิ่มเติมได้ที่ <a href=\"{docLink}\">เอกสาร</a>",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "PHP รุ่น ({version}) ของคุณ จะไม่ได้รับ <a href=\"{phpLink}\">การสนับสนุนโดย PHP</a> เราขอแนะนำให้คุณอัพเกรดรุ่นของ PHP เพื่อความปลอดภัย",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "การกำหนดค่าพร็อกซี่ไม่ถูกต้องหรือคุณกำลังเข้าถึง ownCloud จากพร็อกซี่ที่เชื่อถือได้ ถ้าคุณไม่ได้เข้าถึง ownCloud จากพร็อกซี่ที่เชื่อถือได้ นี้เป็นปัญหาด้านความปลอดภัย คุณอาจถูกโจมดีจากผู้ไม่หวังดี อ่านข้อมูลเพิ่มเติมได้ที่ <a href=\"{docLink}\">เอกสาร</a>",
- "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached เป็นการกำหนดค่าแคช แต่มีโมดูล PHP ของ \"memcache\" ที่ผิดพลาดได้ถูกติดตั้ง \\OC\\Memcache\\Memcached สนับสนุนเฉพาะ \"memcached\" ไม่ใช่ \"memcache\" ดูได้ที่ <a href=\"{wikiLink}\">วิกิพีเดียเกี่ยวกับโมดูล Memcached</a>",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "ไม่ได้กำหนดค่าหน่วยความจำแคช เพื่อเพิ่มประสิทธิภาพของคุณโปรดกำหนดค่า memcache หากต้องการข้อมูลเพิ่มเติมสามารถอ่านได้ใน <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "ไม่สามารถอ่าน /dev/urandom โดย PHP ซึ่งมีผลอย่างมากสำหรับเหตุผลด้านความปลอดภัย สามารถข้อมูลเพิ่มเติมได้ใน <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "PHP ของคุณรุ่น ({version}) <a target=\"_blank\" href=\"{phpLink}\">ไม่สนับสนุน PHP</a> เราขอแนะนำให้อัพเกรดรุ่น PHP ของคุณ เพื่อปรับปรุงประสิทธิภาพการทำงานและเนื้อหาด้านความปลอดภัย",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "การกำหนดค่าส่วนหัวของรีเวิร์สพร็อกซี่ไม่ถูกต้องหรือคุณกำลังเข้าถึง ownCloud จากพร็อกซี่ที่เชื่อถือได้ ถ้าคุณไม่ได้เข้าถึง ownCloud จากพร็อกซี่ที่เชื่อถือได้นี้เป็นปัญหาด้านความปลอดภัยและมันจะอณุญาตทำให้แฮกเกอร์ปลอมที่อยู่ IP ของพวกเขา ข้อมูลเพิ่มเติมสามารถอ่านได้ใน <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "การกำหนดค่า memcach ผิดพลาดเนื่องจากมีโมดูล PHP ของ memcache ได้ถูกติดตั้งไปแล้ว มีการติดตั้ง \\OC\\Memcache\\Memcached สนับสนุนเฉพาะ \"memcached\" แต่ไม่สนับสนุน \"memcache\" คุณสามารถดู <a target=\"_blank\" href=\"{wikiLink}\">ข้อมูลเกี่ยวกับทั้ง 2 โมดูล</a>",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "บางไฟล์ยังไม่ผ่านการตรวจสอบความสมบูรณ์ ข้อมูลเพิ่มเติมเกี่ยวกับวิธีการแก้ไขปัญหาเหล่านี้สามารถอ่านได้จาก <a target=\"_blank\" href=\"{docLink}\">เอกสาร</a> ของเรา (<a href=\"{codeIntegrityDownloadEndpoint}\">รายชื่อของไฟล์ที่ไม่ถูกต้อง…</a> / <a href=\"{rescanEndpoint}\">ค้นหาใหม่…</a>)",
"Error occurred while checking server setup" : "เกิดข้อผิดพลาดขณะที่ทำการตรวจสอบการติดตั้งเซิร์ฟเวอร์",
+ "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "ข้อมูลไดเรกทอรีและไฟล์ของคุณอาจจะสามารถเข้าถึงได้จากอินเทอร์เน็ต ขณะที่ htaccess ไฟล์ไม่ทำงาน เราขอแนะนำให้คุณกำหนดค่าเว็บเซิร์ฟเวอร์ของคุณในทางที่ข้อมูลไดเรกทอรีไม่สามารถเข้าถึงได้หรือคุณย้ายข้อมูลไดเรกทอรีไปยังนอกเว็บเซิร์ฟเวอร์หรือเอกสาร",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" ไม่ได้กำหนดค่าส่วนหัว Http ให้เท่ากับ \"{expected}\" นี่คือระบบการรักษาความปลอดภัยที่มีศักยภาพหรือลดความเสี่ยงที่จะเกิดขึ้นเราขอแนะนำให้ปรับการตั้งค่านี้",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"Strict-Transport-Security\" ส่วนหัว HTTP ไม่ได้กำหนดค่าให้น้อยกว่า \"{seconds}\" วินาที เพื่อความปลอดภัยที่เพิ่มขึ้นเราขอแนะนำให้เปิดใช้งาน HSTS ที่อธิบายไว้ใน <a href=\"{docUrl}\">เคล็ดลับการรักษาความปลอดภัย</a> ของเรา",
"You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "คุณกำลังเข้าถึงเว็บไซต์นี้ผ่านทาง HTTP เราขอแนะนำให้คุณกำหนดค่าเซิร์ฟเวอร์ของคุณที่จะต้องใช้ HTTPS แทนตามที่อธิบายไว้ใน <a href=\"{docUrl}\">เคล็ดลับการรักษาความปลอดภัย</a> ของเรา",
@@ -123,7 +134,6 @@
"Error" : "ข้อผิดพลาด",
"Error while sharing" : "เกิดข้อผิดพลาดขณะกำลังแชร์ข้อมูล",
"Error while unsharing" : "เกิดข้อผิดพลาดขณะกำลังยกเลิกการแชร์ข้อมูล",
- "Error while changing permissions" : "เกิดข้อผิดพลาดขณะกำลังเปลี่ยนสิทธิ์การเข้าใช้งาน",
"Error setting expiration date" : "เกิดข้อผิดพลาดในการตั้งค่าวันที่หมดอายุ",
"The public link will expire no later than {days} days after it is created" : "ลิงค์สาธารณะจะหมดอายุภายใน {days} วัน หลังจากที่มันถูกสร้างขึ้น",
"Set expiration date" : "กำหนดวันที่หมดอายุ",
@@ -142,7 +152,6 @@
"Send" : "ส่ง",
"Shared with you and the group {group} by {owner}" : "ได้แชร์ให้กับคุณ และกลุ่ม {group} โดย {owner}",
"Shared with you by {owner}" : "ถูกแชร์ให้กับคุณโดย {owner}",
- "Shared in {item} with {user}" : "ได้แชร์ {item} ให้กับ {user}",
"group" : "กลุ่มผู้ใช้งาน",
"remote" : "ระยะไกล",
"notify by email" : "แจ้งเตือนทางอีเมล",
@@ -153,17 +162,25 @@
"change" : "เปลี่ยนแปลง",
"delete" : "ลบ",
"access control" : "ควบคุมการเข้าถึง",
+ "Could not unshare" : "ไม่สามารถยกเลิกการแชร์ได้",
"Share details could not be loaded for this item." : "รายละเอียดการแชร์ไม่สามารถโหลดสำหรับรายการนี้",
"An error occured. Please try again" : "เกิดข้อผิดพลาด กรุณาลองอีกครั้ง",
"Share" : "แชร์",
"Share with people on other ownClouds using the syntax username@example.com/owncloud" : "แชร์กับคนใน ownClouds อื่นๆ ที่ใช้ไวยากรณ์ username@example.com/owncloud ",
"Share with users or groups …" : "แชร์กับผู้ใช้หรือกลุ่ม ...",
"Share with users, groups or remote users …" : "แชร์กับผู้ใช้กลุ่มหรือผู้ใช้ระยะไกล ...",
+ "Error removing share" : "พบข้อผิดพลาดในรายการที่แชร์ออก",
"Warning" : "คำเตือน",
"Error while sending notification" : "เกิดข้อผิดพลาดขณะกำลังส่งการแจ้งเตือน",
+ "Non-existing tag #{tag}" : "ไม่มีแท็กนี้อยู่ #{tag}",
+ "not assignable" : "ไม่ได้รับมอบหมาย",
+ "invisible" : "จะมองไม่เห็น",
+ "({scope})" : "({scope})",
+ "Delete" : "ลบ",
+ "Rename" : "เปลี่ยนชื่อ",
+ "Global tags" : "แท็กทั่วไป",
"The object type is not specified." : "ชนิดของวัตถุยังไม่ได้รับการระบุ",
"Enter new" : "ใส่ข้อมูลใหม่",
- "Delete" : "ลบ",
"Add" : "เพิ่ม",
"Edit tags" : "แก้ไขแท็ก",
"Error loading dialog template: {error}" : "เกิดข้อผิดพลาดขณะโหลดไดอะล็อกแม่แบบ: {error}",
@@ -182,15 +199,6 @@
"The update was unsuccessful. " : "อัพเดทไม่สำเร็จ",
"The update was successful. There were warnings." : "การอัพเดทสำเร็จ แต่มีคำเตือนอยู่",
"The update was successful. Redirecting you to ownCloud now." : "การอัพเดทเสร็จเรียบร้อย กำลังเปลี่ยนเส้นทางไปที่ ownCloud อยู่ในขณะนี้",
- "Couldn't reset password because the token is invalid" : "ไม่สามารถตั้งรหัสผ่านใหม่เพราะโทเค็นไม่ถูกต้อง",
- "Couldn't reset password because the token is expired" : "ไม่สามารถตั้งค่ารหัสผ่านเพราะโทเค็นหมดอายุ",
- "Couldn't send reset email. Please make sure your username is correct." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่ กรุณาตรวจสอบชื่อผู้ใช้ของคุณให้ถูกต้อง",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "ไม่สามารถส่งการตั้งค่าอีเมลใหม่เพราะไม่มีที่อยู่อีเมลนี้ กรุณาติดต่อผู้ดูแลระบบ",
- "%s password reset" : "%s ตั้งรหัสผ่านใหม่",
- "Use the following link to reset your password: {link}" : "ใช้ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่านของคุณใหม่: {link}",
- "New password" : "รหัสผ่านใหม่",
- "New Password" : "รหัสผ่านใหม่",
- "Reset password" : "เปลี่ยนรหัสผ่านใหม่",
"Searching other places" : "กำลังค้นหาสถานที่อื่นๆ",
"No search results in other folders" : "ไม่พบผลลัพธ์การค้นหาในโฟลเดอร์อื่นๆ",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["ค้นหาพบ {count} ผลลัพธ์ในโฟลเดอร์อื่นๆ"],
@@ -260,13 +268,19 @@
"Please try again or contact your administrator." : "โปรดลองอีกครั้งหรือติดต่อผู้ดูแลระบบ",
"Log in" : "เข้าสู่ระบบ",
"Wrong password. Reset it?" : "รหัสผ่านผิด ตั้งค่าใหม่?",
+ "Wrong password." : "รหัสผ่านผิดพลาด",
"Stay logged in" : "กำลังอยู่ในระบบ",
"Alternative Logins" : "ทางเลือกการเข้าสู่ระบบ",
+ "Use the following link to reset your password: {link}" : "ใช้ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่านของคุณใหม่: {link}",
+ "New password" : "รหัสผ่านใหม่",
+ "New Password" : "รหัสผ่านใหม่",
+ "Reset password" : "เปลี่ยนรหัสผ่านใหม่",
"This ownCloud instance is currently in single user mode." : "ขณะนี้ ownCloud อยู่ในโหมดผู้ใช้คนเดียว",
"This means only administrators can use the instance." : "ซึ่งหมายความว่าผู้ดูแลระบบสามารถใช้อินสแตนซ์",
"Contact your system administrator if this message persists or appeared unexpectedly." : "ติดต่อผู้ดูแลระบบของคุณหากข้อความนี้ยังคงมีอยู่หรือปรากฏโดยไม่คาดคิด",
"Thank you for your patience." : "ขอบคุณสำหรับความอดทนของคุณ เราจะนำความคิดเห็นของท่านมาปรับปรุงระบบให้ดียิ่งขึ้น",
"You are accessing the server from an untrusted domain." : "คุณกำลังเข้าถึงเซิร์ฟเวอร์จากโดเมนที่ไม่น่าเชื่อถือ",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "กรุณาติดต่อผู้ดูแลระบบ หากคุณเป็นผู้ดูแลระบบ นี้ตัวอย่างการกำหนดค่า \"trusted_domains\" ใน\nconfig/config.php ตัวอย่างการกำหนดค่ามีอยู่ใน config/config.sample.php",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "ทั้งนี้ขึ้นอยู่กับการกำหนดค่าของคุณ ผู้ดูแลระบบอาจสามารถใช้ปุ่มด้านล่างเพื่อกำหนดให้โดเมนนี้มีความน่าเชื่อถือ",
"Add \"%s\" as trusted domain" : "ได้เพิ่ม \"%s\" เป็นโดเมนที่เชื่อถือ",
"App update required" : "จำเป้นต้องอัพเดทแอพฯ",
diff --git a/core/l10n/tr.js b/core/l10n/tr.js
index 257550ecd4b..b8b7c91d4b8 100644
--- a/core/l10n/tr.js
+++ b/core/l10n/tr.js
@@ -6,16 +6,17 @@ OC.L10N.register(
"Turned on maintenance mode" : "Bakım kipi etkinleştirildi",
"Turned off maintenance mode" : "Bakım kipi kapatıldı",
"Maintenance mode is kept active" : "Bakım kipi etkin tutuldu",
+ "Updating database schema" : "Veritabanı şeması güncelleniyor",
"Updated database" : "Veritabanı güncellendi",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "Veritabanı şeması güncellenebilirliği denetleniyor (Veritabanının büyüklüğüne bağlı olarak uzun sürebilir)",
"Checked database schema update" : "Veritabanı şema güncellemesi denetlendi",
- "Checking updates of apps" : "Uygulamaların güncellemelerini kontrol et",
+ "Checking updates of apps" : "Uygulamaların güncellemeleri denetleniyor",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "%s için veritabanı güncellenebilirliği denetleniyor (Veritabanının büyüklüğüne bağlı olarak uzun sürebilir)",
"Checked database schema update for apps" : "Uygulamalar için veritabanı şema güncellemesi denetlendi",
"Updated \"%s\" to %s" : "\"%s\", %s sürümüne güncellendi",
"Repair warning: " : "Onarım uyarısı:",
"Repair error: " : "Onarım hatası:",
- "Set log level to debug - current level: \"%s\"" : "Günlük seviyesini hata ayıklamaya ayarla - geçerli seviye: \"%s\"",
- "Reset log level to \"%s\"" : "Günlük seviyesini \"%s\" olarak sıfırla",
- "%s (3rdparty)" : "%s (3.parti)",
+ "%s (3rdparty)" : "%s (3. parti)",
"%s (incompatible)" : "%s (uyumsuz)",
"Following apps have been disabled: %s" : "Aşağıdaki uygulamalar devre dışı bırakıldı: %s",
"Already up to date" : "Zaten güncel",
@@ -24,10 +25,16 @@ OC.L10N.register(
"No image or file provided" : "Resim veya dosya belirtilmedi",
"Unknown filetype" : "Bilinmeyen dosya türü",
"Invalid image" : "Geçersiz resim",
+ "An error occurred. Please contact your admin." : "Bir hata oluştu. Lütfen yöneticinize başvurun.",
"No temporary profile picture available, try again" : "Kullanılabilir geçici profil resmi yok, tekrar deneyin",
"No crop data provided" : "Kesme verisi sağlanmamış",
"No valid crop data provided" : "Geçerli kırpma verisi sağlanmadı",
"Crop is not square" : "Kırpma kare değil",
+ "Couldn't reset password because the token is invalid" : "Belirteç geçersiz olduğundan parola sıfırlanamadı",
+ "Couldn't reset password because the token is expired" : "Jeton zaman aşımına uğradığından parola sıfırlanamadı",
+ "Couldn't send reset email. Please make sure your username is correct." : "Sıfırlama e-postası gönderilemedi. Lütfen kullanıcı adınızın doğru olduğundan emin olun.",
+ "%s password reset" : "%s parola sıfırlama",
+ "Couldn't send reset email. Please contact your administrator." : "Sıfırlama e-postası gönderilemedi. Lütfen yöneticiniz ile iletişime geçin.",
"Sunday" : "Pazar",
"Monday" : "Pazartesi",
"Tuesday" : "Salı",
@@ -76,7 +83,6 @@ OC.L10N.register(
"Settings" : "Ayarlar",
"Saving..." : "Kaydediliyor...",
"seconds ago" : "saniyeler önce",
- "Couldn't send reset email. Please contact your administrator." : "Sıfırlama e-postası gönderilemedi. Lütfen yöneticiniz ile iletişime geçin.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Parolanızı değiştirme bağlantısı e-posta adresinize gönderildi. Makul bir süre içerisinde almadıysanız spam/gereksiz klasörlerini kontrol ediniz.<br>Bu konumlarda da yoksa yerel sistem yöneticinize sorunuz.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Dosyalarınız şifrelenmiş. Kurtarma anahtarını etkinleştirmemişseniz, parola sıfırlama işleminden sonra verilerinize erişmeniz imkansız olacak.<br />Ne yaptığınızdan emin değilseniz, devam etmeden önce sistem yöneticiniz ile iletişime geçin.<br />Gerçekten devam etmek istiyor musunuz?",
"I know what I'm doing" : "Ne yaptığımı biliyorum",
@@ -107,10 +113,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Web sunucunuz dosya transferi için düzgün bir şekilde yapılandırılmamış. WevDAV arabirimini sorunlu gözüküyor.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Bu sunucunun çalışan bir İnternet bağlantısı yok. Bu, harici depolama alanı bağlama, güncelleştirme bildirimleri veya üçüncü parti uygulama kurma gibi bazı özellikler çalışmayacak demektir. Uzak dosyalara erişim ve e-posta ile bildirim gönderme de çalışmayacaktır. Eğer bu özelliklerin tamamını kullanmak istiyorsanız, sunucu için İnternet bağlantısını etkinleştirmenizi öneriyoruz.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "data dizininiz ve dosyalarınız büyük ihtimalle İnternet üzerinden erişilebilir. .htaccess dosyası çalışmıyor. Web sunucunuzu yapılandırarak data dizinine erişimi kapatmanızı veya data dizinini web sunucu belge dizini dışına almanızı şiddetle tavsiye ederiz.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Hafıza önbelleği ayarlanmamış. Performansın artması için mümkünse lütfen bir memcache ayarlayın. Detaylı bilgiye <a href=\"{docLink}\">belgelendirmemizden</a> ulaşabilirsiniz.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Güvenlik sebepleri ile şiddetle kaçınılması gereken /dev/urandom PHP tarafından okunamıyor. Daha fazla bilgi <a href=\"{docLink}\">belgelendirmemizde</a> bulunabilir.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Kullandığınız PHP sürümü ({version}) artık <a href=\"{phpLink}\">PHP tarafından desteklenmiyor</a>. PHP tarafından sağlanan performans ve güvenlik güncellemelerinden faydalanmak için PHP sürümünüzü güncellemenizi öneririz.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Ters vekil sunucu başlık yapılandırması hatalı veya ownCloud'a güvenilen bir vekil sunucusundan erişiyorsunuz. ownCloud'a güvenilen bir vekil sunucusundan erişmiyorsanız bu bir güvenlik problemidir ve bir saldırganın IP adresinizi taklit etmesine izin verebilir. Ayrıntılı bilgiyi <a href=\"{docLink}\">belgelendirmemizde</a> bulabilirsiniz.",
"Error occurred while checking server setup" : "Sunucu yapılandırması denetlenirken hata oluştu",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP başlığı \"{expected}\" ile eşleşmek üzere yapılandırılmamış. Bu muhtemel bir güvenlik veya gizlilik riski olduğundan bu ayarı düzeltmenizi öneririz.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"Strict-Transport-Security\" HTTP başlığı en az \"{seconds}\" saniye olarak ayarlanmış. İyileştirilmiş güvenlik için <a href=\"{docUrl}\">güvenlik ipuçlarımızda</a> belirtilen HSTS etkinleştirmesini öneririz.",
@@ -120,7 +122,6 @@ OC.L10N.register(
"Error" : "Hata",
"Error while sharing" : "Paylaşım sırasında hata",
"Error while unsharing" : "Paylaşım iptal edilirken hata",
- "Error while changing permissions" : "İzinleri değiştirirken hata",
"Error setting expiration date" : "Son kullanma tarihi ayarlama hatası",
"The public link will expire no later than {days} days after it is created" : "Herkese açık bağlantı, oluşturulduktan en geç {days} gün sonra sona erecek",
"Set expiration date" : "Son kullanma tarihini ayarla",
@@ -139,7 +140,6 @@ OC.L10N.register(
"Send" : "Gönder",
"Shared with you and the group {group} by {owner}" : "{owner} tarafından sizinle ve {group} ile paylaştırılmış",
"Shared with you by {owner}" : "{owner} tarafından sizinle paylaşıldı",
- "Shared in {item} with {user}" : "{item} içinde {user} ile paylaşılanlar",
"group" : "grup",
"remote" : "uzak",
"notify by email" : "e-posta ile bildir",
@@ -158,9 +158,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Kullanıcılar, gruplar veya uzak kullanıcılarla paylaş ...",
"Warning" : "Uyarı",
"Error while sending notification" : "Bildirim gönderilirken hata",
+ "Delete" : "Sil",
+ "Rename" : "Yeniden adlandır",
"The object type is not specified." : "Nesne türü belirtilmemiş.",
"Enter new" : "Yeni girin",
- "Delete" : "Sil",
"Add" : "Ekle",
"Edit tags" : "Etiketleri düzenle",
"Error loading dialog template: {error}" : "İletişim şablonu yüklenirken hata: {error}",
@@ -172,20 +173,13 @@ OC.L10N.register(
"Hello {name}" : "Merhaba {name}",
"_download %n file_::_download %n files_" : ["%n dosya indir","%n dosya indir"],
"{version} is available. Get more information on how to update." : "Sürüm {version} hazır. Nasıl güncelleyeceğinizle ilgili daha fazla bilgi alın.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Güncelleme yapılıyor, sayfadan ayrılmak bazı işlemleri kesebilir.",
"Updating {productName} to version {version}, this may take a while." : "{productName}, {version} sürümüne güncelleniyor, bu biraz zaman alabilir.",
+ "An error occurred." : "Bir hata oluştu",
"Please reload the page." : "Lütfen sayfayı yeniden yükleyin.",
"The update was unsuccessful. " : "Güncelleştirme başarısız.",
"The update was successful. There were warnings." : "Güncelleme başarılı. Uyarılar mevcut.",
"The update was successful. Redirecting you to ownCloud now." : "Güncelleme başarılı. Şimdi ownCloud'a yönlendiriliyorsunuz.",
- "Couldn't reset password because the token is invalid" : "Belirteç geçersiz olduğundan parola sıfırlanamadı",
- "Couldn't reset password because the token is expired" : "Jeton zaman aşımına uğradığından parola sıfırlanamadı",
- "Couldn't send reset email. Please make sure your username is correct." : "Sıfırlama e-postası gönderilemedi. Lütfen kullanıcı adınızın doğru olduğundan emin olun.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Sıfırlama e-postası, bu kullanıcı için bir e-posta adresi olmadığından gönderilemedi. Lütfen yöneticiniz ile iletişime geçin.",
- "%s password reset" : "%s parola sıfırlama",
- "Use the following link to reset your password: {link}" : "Parolanızı sıfırlamak için bu bağlantıyı kullanın: {link}",
- "New password" : "Yeni parola",
- "New Password" : "Yeni Parola",
- "Reset password" : "Parolayı sıfırla",
"Searching other places" : "Diğer konumlarda aranıyor",
"No search results in other folders" : "Diğer klasörlerde arama sonucu yok",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["Diğer klasörlerde {count} arama sonucu","Diğer bir klasörde {count} arama sonucu"],
@@ -257,11 +251,16 @@ OC.L10N.register(
"Wrong password. Reset it?" : "Hatalı parola. Sıfırlansın mı?",
"Stay logged in" : "Bağlı kal",
"Alternative Logins" : "Alternatif Girişler",
+ "Use the following link to reset your password: {link}" : "Parolanızı sıfırlamak için bu bağlantıyı kullanın: {link}",
+ "New password" : "Yeni parola",
+ "New Password" : "Yeni Parola",
+ "Reset password" : "Parolayı sıfırla",
"This ownCloud instance is currently in single user mode." : "Bu ownCloud örneği şu anda tek kullanıcı kipinde.",
"This means only administrators can use the instance." : "Bu, örneği sadece yöneticiler kullanabilir demektir.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Eğer bu ileti görünmeye devam ederse veya beklenmedik şekilde ortaya çıkmışsa sistem yöneticinizle iletişime geçin.",
"Thank you for your patience." : "Sabrınız için teşekkür ederiz.",
"You are accessing the server from an untrusted domain." : "Sunucuya güvenilmeyen bir alan adından ulaşıyorsunuz.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Lütfen yöneticiniz ile iletişime geçin. Eğer bu örneğin bir yöneticisi iseniz, config/config.php dosyası içerisindeki \"trusted_domain\" ayarını yapılandırın. Bu yapılandırmanın bir örneği config/config.sample.php dosyasında verilmiştir.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Yapılandırmanıza bağlı olarak, bir yönetici olarak bu alan adına güvenmek için aşağıdaki düğmeyi de kullanabilirsiniz.",
"Add \"%s\" as trusted domain" : "\"%s\" alan adını güvenilir olarak ekle",
"App update required" : "Uygulama güncellemesi gerekli",
diff --git a/core/l10n/tr.json b/core/l10n/tr.json
index 66f3a83f7ed..e0adbe5ec58 100644
--- a/core/l10n/tr.json
+++ b/core/l10n/tr.json
@@ -4,16 +4,17 @@
"Turned on maintenance mode" : "Bakım kipi etkinleştirildi",
"Turned off maintenance mode" : "Bakım kipi kapatıldı",
"Maintenance mode is kept active" : "Bakım kipi etkin tutuldu",
+ "Updating database schema" : "Veritabanı şeması güncelleniyor",
"Updated database" : "Veritabanı güncellendi",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "Veritabanı şeması güncellenebilirliği denetleniyor (Veritabanının büyüklüğüne bağlı olarak uzun sürebilir)",
"Checked database schema update" : "Veritabanı şema güncellemesi denetlendi",
- "Checking updates of apps" : "Uygulamaların güncellemelerini kontrol et",
+ "Checking updates of apps" : "Uygulamaların güncellemeleri denetleniyor",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "%s için veritabanı güncellenebilirliği denetleniyor (Veritabanının büyüklüğüne bağlı olarak uzun sürebilir)",
"Checked database schema update for apps" : "Uygulamalar için veritabanı şema güncellemesi denetlendi",
"Updated \"%s\" to %s" : "\"%s\", %s sürümüne güncellendi",
"Repair warning: " : "Onarım uyarısı:",
"Repair error: " : "Onarım hatası:",
- "Set log level to debug - current level: \"%s\"" : "Günlük seviyesini hata ayıklamaya ayarla - geçerli seviye: \"%s\"",
- "Reset log level to \"%s\"" : "Günlük seviyesini \"%s\" olarak sıfırla",
- "%s (3rdparty)" : "%s (3.parti)",
+ "%s (3rdparty)" : "%s (3. parti)",
"%s (incompatible)" : "%s (uyumsuz)",
"Following apps have been disabled: %s" : "Aşağıdaki uygulamalar devre dışı bırakıldı: %s",
"Already up to date" : "Zaten güncel",
@@ -22,10 +23,16 @@
"No image or file provided" : "Resim veya dosya belirtilmedi",
"Unknown filetype" : "Bilinmeyen dosya türü",
"Invalid image" : "Geçersiz resim",
+ "An error occurred. Please contact your admin." : "Bir hata oluştu. Lütfen yöneticinize başvurun.",
"No temporary profile picture available, try again" : "Kullanılabilir geçici profil resmi yok, tekrar deneyin",
"No crop data provided" : "Kesme verisi sağlanmamış",
"No valid crop data provided" : "Geçerli kırpma verisi sağlanmadı",
"Crop is not square" : "Kırpma kare değil",
+ "Couldn't reset password because the token is invalid" : "Belirteç geçersiz olduğundan parola sıfırlanamadı",
+ "Couldn't reset password because the token is expired" : "Jeton zaman aşımına uğradığından parola sıfırlanamadı",
+ "Couldn't send reset email. Please make sure your username is correct." : "Sıfırlama e-postası gönderilemedi. Lütfen kullanıcı adınızın doğru olduğundan emin olun.",
+ "%s password reset" : "%s parola sıfırlama",
+ "Couldn't send reset email. Please contact your administrator." : "Sıfırlama e-postası gönderilemedi. Lütfen yöneticiniz ile iletişime geçin.",
"Sunday" : "Pazar",
"Monday" : "Pazartesi",
"Tuesday" : "Salı",
@@ -74,7 +81,6 @@
"Settings" : "Ayarlar",
"Saving..." : "Kaydediliyor...",
"seconds ago" : "saniyeler önce",
- "Couldn't send reset email. Please contact your administrator." : "Sıfırlama e-postası gönderilemedi. Lütfen yöneticiniz ile iletişime geçin.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Parolanızı değiştirme bağlantısı e-posta adresinize gönderildi. Makul bir süre içerisinde almadıysanız spam/gereksiz klasörlerini kontrol ediniz.<br>Bu konumlarda da yoksa yerel sistem yöneticinize sorunuz.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Dosyalarınız şifrelenmiş. Kurtarma anahtarını etkinleştirmemişseniz, parola sıfırlama işleminden sonra verilerinize erişmeniz imkansız olacak.<br />Ne yaptığınızdan emin değilseniz, devam etmeden önce sistem yöneticiniz ile iletişime geçin.<br />Gerçekten devam etmek istiyor musunuz?",
"I know what I'm doing" : "Ne yaptığımı biliyorum",
@@ -105,10 +111,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Web sunucunuz dosya transferi için düzgün bir şekilde yapılandırılmamış. WevDAV arabirimini sorunlu gözüküyor.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Bu sunucunun çalışan bir İnternet bağlantısı yok. Bu, harici depolama alanı bağlama, güncelleştirme bildirimleri veya üçüncü parti uygulama kurma gibi bazı özellikler çalışmayacak demektir. Uzak dosyalara erişim ve e-posta ile bildirim gönderme de çalışmayacaktır. Eğer bu özelliklerin tamamını kullanmak istiyorsanız, sunucu için İnternet bağlantısını etkinleştirmenizi öneriyoruz.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "data dizininiz ve dosyalarınız büyük ihtimalle İnternet üzerinden erişilebilir. .htaccess dosyası çalışmıyor. Web sunucunuzu yapılandırarak data dizinine erişimi kapatmanızı veya data dizinini web sunucu belge dizini dışına almanızı şiddetle tavsiye ederiz.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Hafıza önbelleği ayarlanmamış. Performansın artması için mümkünse lütfen bir memcache ayarlayın. Detaylı bilgiye <a href=\"{docLink}\">belgelendirmemizden</a> ulaşabilirsiniz.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Güvenlik sebepleri ile şiddetle kaçınılması gereken /dev/urandom PHP tarafından okunamıyor. Daha fazla bilgi <a href=\"{docLink}\">belgelendirmemizde</a> bulunabilir.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Kullandığınız PHP sürümü ({version}) artık <a href=\"{phpLink}\">PHP tarafından desteklenmiyor</a>. PHP tarafından sağlanan performans ve güvenlik güncellemelerinden faydalanmak için PHP sürümünüzü güncellemenizi öneririz.",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Ters vekil sunucu başlık yapılandırması hatalı veya ownCloud'a güvenilen bir vekil sunucusundan erişiyorsunuz. ownCloud'a güvenilen bir vekil sunucusundan erişmiyorsanız bu bir güvenlik problemidir ve bir saldırganın IP adresinizi taklit etmesine izin verebilir. Ayrıntılı bilgiyi <a href=\"{docLink}\">belgelendirmemizde</a> bulabilirsiniz.",
"Error occurred while checking server setup" : "Sunucu yapılandırması denetlenirken hata oluştu",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP başlığı \"{expected}\" ile eşleşmek üzere yapılandırılmamış. Bu muhtemel bir güvenlik veya gizlilik riski olduğundan bu ayarı düzeltmenizi öneririz.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"Strict-Transport-Security\" HTTP başlığı en az \"{seconds}\" saniye olarak ayarlanmış. İyileştirilmiş güvenlik için <a href=\"{docUrl}\">güvenlik ipuçlarımızda</a> belirtilen HSTS etkinleştirmesini öneririz.",
@@ -118,7 +120,6 @@
"Error" : "Hata",
"Error while sharing" : "Paylaşım sırasında hata",
"Error while unsharing" : "Paylaşım iptal edilirken hata",
- "Error while changing permissions" : "İzinleri değiştirirken hata",
"Error setting expiration date" : "Son kullanma tarihi ayarlama hatası",
"The public link will expire no later than {days} days after it is created" : "Herkese açık bağlantı, oluşturulduktan en geç {days} gün sonra sona erecek",
"Set expiration date" : "Son kullanma tarihini ayarla",
@@ -137,7 +138,6 @@
"Send" : "Gönder",
"Shared with you and the group {group} by {owner}" : "{owner} tarafından sizinle ve {group} ile paylaştırılmış",
"Shared with you by {owner}" : "{owner} tarafından sizinle paylaşıldı",
- "Shared in {item} with {user}" : "{item} içinde {user} ile paylaşılanlar",
"group" : "grup",
"remote" : "uzak",
"notify by email" : "e-posta ile bildir",
@@ -156,9 +156,10 @@
"Share with users, groups or remote users …" : "Kullanıcılar, gruplar veya uzak kullanıcılarla paylaş ...",
"Warning" : "Uyarı",
"Error while sending notification" : "Bildirim gönderilirken hata",
+ "Delete" : "Sil",
+ "Rename" : "Yeniden adlandır",
"The object type is not specified." : "Nesne türü belirtilmemiş.",
"Enter new" : "Yeni girin",
- "Delete" : "Sil",
"Add" : "Ekle",
"Edit tags" : "Etiketleri düzenle",
"Error loading dialog template: {error}" : "İletişim şablonu yüklenirken hata: {error}",
@@ -170,20 +171,13 @@
"Hello {name}" : "Merhaba {name}",
"_download %n file_::_download %n files_" : ["%n dosya indir","%n dosya indir"],
"{version} is available. Get more information on how to update." : "Sürüm {version} hazır. Nasıl güncelleyeceğinizle ilgili daha fazla bilgi alın.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "Güncelleme yapılıyor, sayfadan ayrılmak bazı işlemleri kesebilir.",
"Updating {productName} to version {version}, this may take a while." : "{productName}, {version} sürümüne güncelleniyor, bu biraz zaman alabilir.",
+ "An error occurred." : "Bir hata oluştu",
"Please reload the page." : "Lütfen sayfayı yeniden yükleyin.",
"The update was unsuccessful. " : "Güncelleştirme başarısız.",
"The update was successful. There were warnings." : "Güncelleme başarılı. Uyarılar mevcut.",
"The update was successful. Redirecting you to ownCloud now." : "Güncelleme başarılı. Şimdi ownCloud'a yönlendiriliyorsunuz.",
- "Couldn't reset password because the token is invalid" : "Belirteç geçersiz olduğundan parola sıfırlanamadı",
- "Couldn't reset password because the token is expired" : "Jeton zaman aşımına uğradığından parola sıfırlanamadı",
- "Couldn't send reset email. Please make sure your username is correct." : "Sıfırlama e-postası gönderilemedi. Lütfen kullanıcı adınızın doğru olduğundan emin olun.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Sıfırlama e-postası, bu kullanıcı için bir e-posta adresi olmadığından gönderilemedi. Lütfen yöneticiniz ile iletişime geçin.",
- "%s password reset" : "%s parola sıfırlama",
- "Use the following link to reset your password: {link}" : "Parolanızı sıfırlamak için bu bağlantıyı kullanın: {link}",
- "New password" : "Yeni parola",
- "New Password" : "Yeni Parola",
- "Reset password" : "Parolayı sıfırla",
"Searching other places" : "Diğer konumlarda aranıyor",
"No search results in other folders" : "Diğer klasörlerde arama sonucu yok",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["Diğer klasörlerde {count} arama sonucu","Diğer bir klasörde {count} arama sonucu"],
@@ -255,11 +249,16 @@
"Wrong password. Reset it?" : "Hatalı parola. Sıfırlansın mı?",
"Stay logged in" : "Bağlı kal",
"Alternative Logins" : "Alternatif Girişler",
+ "Use the following link to reset your password: {link}" : "Parolanızı sıfırlamak için bu bağlantıyı kullanın: {link}",
+ "New password" : "Yeni parola",
+ "New Password" : "Yeni Parola",
+ "Reset password" : "Parolayı sıfırla",
"This ownCloud instance is currently in single user mode." : "Bu ownCloud örneği şu anda tek kullanıcı kipinde.",
"This means only administrators can use the instance." : "Bu, örneği sadece yöneticiler kullanabilir demektir.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Eğer bu ileti görünmeye devam ederse veya beklenmedik şekilde ortaya çıkmışsa sistem yöneticinizle iletişime geçin.",
"Thank you for your patience." : "Sabrınız için teşekkür ederiz.",
"You are accessing the server from an untrusted domain." : "Sunucuya güvenilmeyen bir alan adından ulaşıyorsunuz.",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "Lütfen yöneticiniz ile iletişime geçin. Eğer bu örneğin bir yöneticisi iseniz, config/config.php dosyası içerisindeki \"trusted_domain\" ayarını yapılandırın. Bu yapılandırmanın bir örneği config/config.sample.php dosyasında verilmiştir.",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "Yapılandırmanıza bağlı olarak, bir yönetici olarak bu alan adına güvenmek için aşağıdaki düğmeyi de kullanabilirsiniz.",
"Add \"%s\" as trusted domain" : "\"%s\" alan adını güvenilir olarak ekle",
"App update required" : "Uygulama güncellemesi gerekli",
diff --git a/core/l10n/ug.js b/core/l10n/ug.js
index ae8b001ef37..ea8f6f23817 100644
--- a/core/l10n/ug.js
+++ b/core/l10n/ug.js
@@ -54,8 +54,8 @@ OC.L10N.register(
"Share" : "ھەمبەھىر",
"Warning" : "ئاگاھلاندۇرۇش",
"Delete" : "ئۆچۈر",
+ "Rename" : "ئات ئۆزگەرت",
"Add" : "قوش",
- "New password" : "يېڭى ئىم",
"Personal" : "شەخسىي",
"Users" : "ئىشلەتكۈچىلەر",
"Apps" : "ئەپلەر",
@@ -63,6 +63,7 @@ OC.L10N.register(
"Username" : "ئىشلەتكۈچى ئاتى",
"Finish setup" : "تەڭشەك تامام",
"Log out" : "تىزىمدىن چىق",
- "Search" : "ئىزدە"
+ "Search" : "ئىزدە",
+ "New password" : "يېڭى ئىم"
},
"nplurals=1; plural=0;");
diff --git a/core/l10n/ug.json b/core/l10n/ug.json
index f61d52d0d5a..f6eaf3fc047 100644
--- a/core/l10n/ug.json
+++ b/core/l10n/ug.json
@@ -52,8 +52,8 @@
"Share" : "ھەمبەھىر",
"Warning" : "ئاگاھلاندۇرۇش",
"Delete" : "ئۆچۈر",
+ "Rename" : "ئات ئۆزگەرت",
"Add" : "قوش",
- "New password" : "يېڭى ئىم",
"Personal" : "شەخسىي",
"Users" : "ئىشلەتكۈچىلەر",
"Apps" : "ئەپلەر",
@@ -61,6 +61,7 @@
"Username" : "ئىشلەتكۈچى ئاتى",
"Finish setup" : "تەڭشەك تامام",
"Log out" : "تىزىمدىن چىق",
- "Search" : "ئىزدە"
+ "Search" : "ئىزدە",
+ "New password" : "يېڭى ئىم"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/core/l10n/uk.js b/core/l10n/uk.js
index bd1c5f679e8..c2585f43c32 100644
--- a/core/l10n/uk.js
+++ b/core/l10n/uk.js
@@ -23,6 +23,11 @@ OC.L10N.register(
"No crop data provided" : "Не вказана інформація про кадрування",
"No valid crop data provided" : "Не вказані коректні дані про кадрування",
"Crop is not square" : "Кадр не є квадратом",
+ "Couldn't reset password because the token is invalid" : "Неможливо скинути пароль, бо маркер є недійсним",
+ "Couldn't reset password because the token is expired" : "Неможливо скинути пароль, бо маркер застарів",
+ "Couldn't send reset email. Please make sure your username is correct." : "Не вдалося відправити скидання паролю. Будь ласка, переконайтеся, що ваше ім'я користувача є правильним.",
+ "%s password reset" : "%s скидання паролю",
+ "Couldn't send reset email. Please contact your administrator." : "Не можу надіслати email для скидання. Будь ласка, зверніться до вашого адміністратора.",
"Sunday" : "Неділя",
"Monday" : "Понеділок",
"Tuesday" : "Вівторок",
@@ -71,7 +76,6 @@ OC.L10N.register(
"Settings" : "Налаштування",
"Saving..." : "Збереження...",
"seconds ago" : "секунди тому",
- "Couldn't send reset email. Please contact your administrator." : "Не можу надіслати email для скидання. Будь ласка, зверніться до вашого адміністратора.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Посилання для скидання вашого паролю було надіслано на ваш email. Якщо ви не отримали його найближчим часом, перевірте теку зі спамом.<br>Якщо і там немає, спитайте вашого місцевого адміністратора.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Ваші файли зашифровані. Якщо ви не зробили ключ відновлення, після скидання паролю відновити ваші дані буде неможливо.<br /> Якщо ви не знаєте, що робити, будь ласка, зверніться до адміністратора перед продовженням.<br /> Ви дійсно хочете продовжити?",
"I know what I'm doing" : "Я знаю що роблю",
@@ -102,9 +106,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ваш веб-сервер ще не налаштований належним чином, щоб дозволити синхронізацію файлів, тому що інтерфейс WebDAV, здається, зіпсований.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Цей сервер не має підключення до Інтернету. Це означає, що деякі з функцій, таких як зовнішнє сховище, повідомлення про оновлення та встановлення сторонніх додатків не будуть працювати. Доступ до файлів віддалено і надсилання повідомлень поштою можуть не працювати. Ми пропонуємо включити підключення до Інтернету для цього сервера, якщо ви хочете, щоб всі функції працювали.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ваш каталог даних і ваші файли можливо доступні з інтернету. .htaccess файл не працює. Ми наполегливо рекомендуємо вам налаштувати ваш веб сервер таким чином, щоб каталог даних більше не був доступний або перемістіть каталог даних за межі кореня веб сервера.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Кеш пам'яті не налаштований. Задля покращення продуктивності, будь ласка, налаштуйте memcache, якщо є можливість. Додаткову інформацію шукайте у нашій <a href=\"{docLink}\">документації</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom не доступний для читання PHP, що вкрай небажано з міркувань безпеки. Додаткову інформацію шукайте у нашій <a href=\"{docLink}\">документації</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Ваша версія PHP ({version}) більше <a href=\"{phpLink}\">не підтримується</a>. Ми рекомендуємо вам оновити версію PHP щоб отримати кращу продуктивність та оновлення безпеки.",
"Error occurred while checking server setup" : "При перевірці налаштувань серверу сталася помилка",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP заголовок \"{header}\" не налаштований як \"{expected}\". Це потенційний ризик для безпеки чи приватності і ми радимо виправити це налаштування.",
"Shared" : "Опубліковано",
@@ -112,7 +113,6 @@ OC.L10N.register(
"Error" : "Помилка",
"Error while sharing" : "Помилка під час публікації",
"Error while unsharing" : "Помилка під час відміни публікації",
- "Error while changing permissions" : "Помилка при зміні повноважень",
"Error setting expiration date" : "Помилка при встановленні терміну дії",
"The public link will expire no later than {days} days after it is created" : "Доступ до опублікованого посилання буде припинено не пізніше ніж через {days} днів з моменту створення",
"Set expiration date" : "Встановити термін дії",
@@ -131,7 +131,6 @@ OC.L10N.register(
"Send" : "Надіслати",
"Shared with you and the group {group} by {owner}" : " {owner} опублікував для Вас та для групи {group}",
"Shared with you by {owner}" : "{owner} опублікував для Вас",
- "Shared in {item} with {user}" : "Опубліковано {item} для {user}",
"group" : "група",
"remote" : "Віддалений",
"notify by email" : "повідомити по Email",
@@ -149,9 +148,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "Поширити серед локальних чи віддалених користувачів або груп ...",
"Warning" : "Попередження",
"Error while sending notification" : "Помилка при надсиланні повідомлення",
+ "Delete" : "Видалити",
+ "Rename" : "Перейменувати",
"The object type is not specified." : "Не визначено тип об'єкту.",
"Enter new" : "Введіть новий",
- "Delete" : "Видалити",
"Add" : "Додати",
"Edit tags" : "Редагувати мітки",
"Error loading dialog template: {error}" : "Помилка при завантаженні шаблону діалогу: {error}",
@@ -168,15 +168,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "Оновлення завершилось невдачею.",
"The update was successful. There were warnings." : "Оновлення виконалось успішно, але були попередження.",
"The update was successful. Redirecting you to ownCloud now." : "Оновлення виконалось успішно. Перенаправляємо вас на ownCloud.",
- "Couldn't reset password because the token is invalid" : "Неможливо скинути пароль, бо маркер є недійсним",
- "Couldn't reset password because the token is expired" : "Неможливо скинути пароль, бо маркер застарів",
- "Couldn't send reset email. Please make sure your username is correct." : "Не вдалося відправити скидання паролю. Будь ласка, переконайтеся, що ваше ім'я користувача є правильним.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Не вдалося відправити скидання паролю, тому що немає адреси електронної пошти для цього користувача. Будь ласка, зверніться до адміністратора.",
- "%s password reset" : "%s скидання паролю",
- "Use the following link to reset your password: {link}" : "Використовуйте наступне посилання для скидання пароля: {link}",
- "New password" : "Новий пароль",
- "New Password" : "Новий пароль",
- "Reset password" : "Скинути пароль",
"Searching other places" : "Йде пошук в інших місцях",
"No search results in other folders" : "В інших теках нічого не знайдено",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} результат пошуку в інших теках","{count} результатів пошуку в інших теках","{count} результатів пошуку в інших теках"],
@@ -247,6 +238,10 @@ OC.L10N.register(
"Log in" : "Увійти",
"Wrong password. Reset it?" : "Невірний пароль. Скинути його?",
"Alternative Logins" : "Альтернативні імена користувача",
+ "Use the following link to reset your password: {link}" : "Використовуйте наступне посилання для скидання пароля: {link}",
+ "New password" : "Новий пароль",
+ "New Password" : "Новий пароль",
+ "Reset password" : "Скинути пароль",
"This ownCloud instance is currently in single user mode." : "Сервер ownCloud в даний час працює в однокористувацькому режимі.",
"This means only administrators can use the instance." : "Це означає, що тільки адміністратори можуть використовувати сервер.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Зверніться до вашого системного адміністратора якщо це повідомлення не зникає або з'являється несподівано.",
diff --git a/core/l10n/uk.json b/core/l10n/uk.json
index 4b95c4a92cd..ac348537937 100644
--- a/core/l10n/uk.json
+++ b/core/l10n/uk.json
@@ -21,6 +21,11 @@
"No crop data provided" : "Не вказана інформація про кадрування",
"No valid crop data provided" : "Не вказані коректні дані про кадрування",
"Crop is not square" : "Кадр не є квадратом",
+ "Couldn't reset password because the token is invalid" : "Неможливо скинути пароль, бо маркер є недійсним",
+ "Couldn't reset password because the token is expired" : "Неможливо скинути пароль, бо маркер застарів",
+ "Couldn't send reset email. Please make sure your username is correct." : "Не вдалося відправити скидання паролю. Будь ласка, переконайтеся, що ваше ім'я користувача є правильним.",
+ "%s password reset" : "%s скидання паролю",
+ "Couldn't send reset email. Please contact your administrator." : "Не можу надіслати email для скидання. Будь ласка, зверніться до вашого адміністратора.",
"Sunday" : "Неділя",
"Monday" : "Понеділок",
"Tuesday" : "Вівторок",
@@ -69,7 +74,6 @@
"Settings" : "Налаштування",
"Saving..." : "Збереження...",
"seconds ago" : "секунди тому",
- "Couldn't send reset email. Please contact your administrator." : "Не можу надіслати email для скидання. Будь ласка, зверніться до вашого адміністратора.",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "Посилання для скидання вашого паролю було надіслано на ваш email. Якщо ви не отримали його найближчим часом, перевірте теку зі спамом.<br>Якщо і там немає, спитайте вашого місцевого адміністратора.",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "Ваші файли зашифровані. Якщо ви не зробили ключ відновлення, після скидання паролю відновити ваші дані буде неможливо.<br /> Якщо ви не знаєте, що робити, будь ласка, зверніться до адміністратора перед продовженням.<br /> Ви дійсно хочете продовжити?",
"I know what I'm doing" : "Я знаю що роблю",
@@ -100,9 +104,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "Ваш веб-сервер ще не налаштований належним чином, щоб дозволити синхронізацію файлів, тому що інтерфейс WebDAV, здається, зіпсований.",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "Цей сервер не має підключення до Інтернету. Це означає, що деякі з функцій, таких як зовнішнє сховище, повідомлення про оновлення та встановлення сторонніх додатків не будуть працювати. Доступ до файлів віддалено і надсилання повідомлень поштою можуть не працювати. Ми пропонуємо включити підключення до Інтернету для цього сервера, якщо ви хочете, щоб всі функції працювали.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "Ваш каталог даних і ваші файли можливо доступні з інтернету. .htaccess файл не працює. Ми наполегливо рекомендуємо вам налаштувати ваш веб сервер таким чином, щоб каталог даних більше не був доступний або перемістіть каталог даних за межі кореня веб сервера.",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Кеш пам'яті не налаштований. Задля покращення продуктивності, будь ласка, налаштуйте memcache, якщо є можливість. Додаткову інформацію шукайте у нашій <a href=\"{docLink}\">документації</a>.",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom не доступний для читання PHP, що вкрай небажано з міркувань безпеки. Додаткову інформацію шукайте у нашій <a href=\"{docLink}\">документації</a>.",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Ваша версія PHP ({version}) більше <a href=\"{phpLink}\">не підтримується</a>. Ми рекомендуємо вам оновити версію PHP щоб отримати кращу продуктивність та оновлення безпеки.",
"Error occurred while checking server setup" : "При перевірці налаштувань серверу сталася помилка",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP заголовок \"{header}\" не налаштований як \"{expected}\". Це потенційний ризик для безпеки чи приватності і ми радимо виправити це налаштування.",
"Shared" : "Опубліковано",
@@ -110,7 +111,6 @@
"Error" : "Помилка",
"Error while sharing" : "Помилка під час публікації",
"Error while unsharing" : "Помилка під час відміни публікації",
- "Error while changing permissions" : "Помилка при зміні повноважень",
"Error setting expiration date" : "Помилка при встановленні терміну дії",
"The public link will expire no later than {days} days after it is created" : "Доступ до опублікованого посилання буде припинено не пізніше ніж через {days} днів з моменту створення",
"Set expiration date" : "Встановити термін дії",
@@ -129,7 +129,6 @@
"Send" : "Надіслати",
"Shared with you and the group {group} by {owner}" : " {owner} опублікував для Вас та для групи {group}",
"Shared with you by {owner}" : "{owner} опублікував для Вас",
- "Shared in {item} with {user}" : "Опубліковано {item} для {user}",
"group" : "група",
"remote" : "Віддалений",
"notify by email" : "повідомити по Email",
@@ -147,9 +146,10 @@
"Share with users, groups or remote users …" : "Поширити серед локальних чи віддалених користувачів або груп ...",
"Warning" : "Попередження",
"Error while sending notification" : "Помилка при надсиланні повідомлення",
+ "Delete" : "Видалити",
+ "Rename" : "Перейменувати",
"The object type is not specified." : "Не визначено тип об'єкту.",
"Enter new" : "Введіть новий",
- "Delete" : "Видалити",
"Add" : "Додати",
"Edit tags" : "Редагувати мітки",
"Error loading dialog template: {error}" : "Помилка при завантаженні шаблону діалогу: {error}",
@@ -166,15 +166,6 @@
"The update was unsuccessful. " : "Оновлення завершилось невдачею.",
"The update was successful. There were warnings." : "Оновлення виконалось успішно, але були попередження.",
"The update was successful. Redirecting you to ownCloud now." : "Оновлення виконалось успішно. Перенаправляємо вас на ownCloud.",
- "Couldn't reset password because the token is invalid" : "Неможливо скинути пароль, бо маркер є недійсним",
- "Couldn't reset password because the token is expired" : "Неможливо скинути пароль, бо маркер застарів",
- "Couldn't send reset email. Please make sure your username is correct." : "Не вдалося відправити скидання паролю. Будь ласка, переконайтеся, що ваше ім'я користувача є правильним.",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "Не вдалося відправити скидання паролю, тому що немає адреси електронної пошти для цього користувача. Будь ласка, зверніться до адміністратора.",
- "%s password reset" : "%s скидання паролю",
- "Use the following link to reset your password: {link}" : "Використовуйте наступне посилання для скидання пароля: {link}",
- "New password" : "Новий пароль",
- "New Password" : "Новий пароль",
- "Reset password" : "Скинути пароль",
"Searching other places" : "Йде пошук в інших місцях",
"No search results in other folders" : "В інших теках нічого не знайдено",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} результат пошуку в інших теках","{count} результатів пошуку в інших теках","{count} результатів пошуку в інших теках"],
@@ -245,6 +236,10 @@
"Log in" : "Увійти",
"Wrong password. Reset it?" : "Невірний пароль. Скинути його?",
"Alternative Logins" : "Альтернативні імена користувача",
+ "Use the following link to reset your password: {link}" : "Використовуйте наступне посилання для скидання пароля: {link}",
+ "New password" : "Новий пароль",
+ "New Password" : "Новий пароль",
+ "Reset password" : "Скинути пароль",
"This ownCloud instance is currently in single user mode." : "Сервер ownCloud в даний час працює в однокористувацькому режимі.",
"This means only administrators can use the instance." : "Це означає, що тільки адміністратори можуть використовувати сервер.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Зверніться до вашого системного адміністратора якщо це повідомлення не зникає або з'являється несподівано.",
diff --git a/core/l10n/ur_PK.js b/core/l10n/ur_PK.js
index 487a197cf8b..508c9c6cfac 100644
--- a/core/l10n/ur_PK.js
+++ b/core/l10n/ur_PK.js
@@ -52,7 +52,6 @@ OC.L10N.register(
"Error" : "خرابی",
"Error while sharing" : "اشتراک کے دوران خرابی ",
"Error while unsharing" : "اشترک ختم کرنے کے دوران خرابی",
- "Error while changing permissions" : "اختیارات کو تبدیل کرنے کے دوران خرابی ",
"Error setting expiration date" : "خرابی تصحیح تاریخ معیاد",
"Set expiration date" : "تاریخ معیاد سیٹ کریں",
"Expiration date" : "تاریخ معیاد",
@@ -67,7 +66,6 @@ OC.L10N.register(
"Send" : "بھجیں",
"Shared with you and the group {group} by {owner}" : "آپ اور گروہ سے مشترق شدہ {گروہ } سے {مالک}",
"Shared with you by {owner}" : "اشتراک شدہ آپ سے{مالک}",
- "Shared in {item} with {user}" : "شراکت میں {آئٹم}اور {مستخدم}",
"group" : "مجموعہ",
"notify by email" : "ای میل کے ذریعے مطلع کریں",
"Unshare" : "شئیرنگ ختم کریں",
@@ -77,16 +75,13 @@ OC.L10N.register(
"access control" : "اسیس کنٹرول",
"Share" : "اشتراک",
"Warning" : "انتباہ",
+ "Delete" : "حذف کریں",
"The object type is not specified." : "اس چیز کی قسم کی وضاحت نہیں",
"Enter new" : "جدید درج کریں",
- "Delete" : "حذف کریں",
"Add" : "شامل کریں",
"Edit tags" : "ترمیم ٹیگز",
"Please reload the page." : "براہ مہربانی صفحہ دوبارہ لوڈ کریں.",
"The update was successful. Redirecting you to ownCloud now." : "اپ ڈیٹ کامیاب تھی۔ اپ کو اون کلوڈ سے منسلک کیا جا رہا ہے",
- "Use the following link to reset your password: {link}" : "اپنا پاسورڈ ری سیٹ کرنے کے لیے اس لنک پر کلک کریں۔ {link}",
- "New password" : "نیا پاسورڈ",
- "Reset password" : "ری سیٹ پاسورڈ",
"Personal" : "شخصی",
"Users" : "صارفین",
"Apps" : "ایپز",
@@ -111,6 +106,9 @@ OC.L10N.register(
"Search" : "تلاش",
"Log in" : "لاگ ان",
"Alternative Logins" : "متبادل لاگ ان ",
+ "Use the following link to reset your password: {link}" : "اپنا پاسورڈ ری سیٹ کرنے کے لیے اس لنک پر کلک کریں۔ {link}",
+ "New password" : "نیا پاسورڈ",
+ "Reset password" : "ری سیٹ پاسورڈ",
"Thank you for your patience." : "آپ کے صبر کا شکریہ"
},
"nplurals=2; plural=(n != 1);");
diff --git a/core/l10n/ur_PK.json b/core/l10n/ur_PK.json
index 7411d6cb71a..01653f74e54 100644
--- a/core/l10n/ur_PK.json
+++ b/core/l10n/ur_PK.json
@@ -50,7 +50,6 @@
"Error" : "خرابی",
"Error while sharing" : "اشتراک کے دوران خرابی ",
"Error while unsharing" : "اشترک ختم کرنے کے دوران خرابی",
- "Error while changing permissions" : "اختیارات کو تبدیل کرنے کے دوران خرابی ",
"Error setting expiration date" : "خرابی تصحیح تاریخ معیاد",
"Set expiration date" : "تاریخ معیاد سیٹ کریں",
"Expiration date" : "تاریخ معیاد",
@@ -65,7 +64,6 @@
"Send" : "بھجیں",
"Shared with you and the group {group} by {owner}" : "آپ اور گروہ سے مشترق شدہ {گروہ } سے {مالک}",
"Shared with you by {owner}" : "اشتراک شدہ آپ سے{مالک}",
- "Shared in {item} with {user}" : "شراکت میں {آئٹم}اور {مستخدم}",
"group" : "مجموعہ",
"notify by email" : "ای میل کے ذریعے مطلع کریں",
"Unshare" : "شئیرنگ ختم کریں",
@@ -75,16 +73,13 @@
"access control" : "اسیس کنٹرول",
"Share" : "اشتراک",
"Warning" : "انتباہ",
+ "Delete" : "حذف کریں",
"The object type is not specified." : "اس چیز کی قسم کی وضاحت نہیں",
"Enter new" : "جدید درج کریں",
- "Delete" : "حذف کریں",
"Add" : "شامل کریں",
"Edit tags" : "ترمیم ٹیگز",
"Please reload the page." : "براہ مہربانی صفحہ دوبارہ لوڈ کریں.",
"The update was successful. Redirecting you to ownCloud now." : "اپ ڈیٹ کامیاب تھی۔ اپ کو اون کلوڈ سے منسلک کیا جا رہا ہے",
- "Use the following link to reset your password: {link}" : "اپنا پاسورڈ ری سیٹ کرنے کے لیے اس لنک پر کلک کریں۔ {link}",
- "New password" : "نیا پاسورڈ",
- "Reset password" : "ری سیٹ پاسورڈ",
"Personal" : "شخصی",
"Users" : "صارفین",
"Apps" : "ایپز",
@@ -109,6 +104,9 @@
"Search" : "تلاش",
"Log in" : "لاگ ان",
"Alternative Logins" : "متبادل لاگ ان ",
+ "Use the following link to reset your password: {link}" : "اپنا پاسورڈ ری سیٹ کرنے کے لیے اس لنک پر کلک کریں۔ {link}",
+ "New password" : "نیا پاسورڈ",
+ "Reset password" : "ری سیٹ پاسورڈ",
"Thank you for your patience." : "آپ کے صبر کا شکریہ"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/core/l10n/vi.js b/core/l10n/vi.js
index 9cc2fe7d762..ca5937b0f4f 100644
--- a/core/l10n/vi.js
+++ b/core/l10n/vi.js
@@ -10,6 +10,7 @@ OC.L10N.register(
"Invalid image" : "Hình ảnh không hợp lệ",
"No temporary profile picture available, try again" : "Ảnh cá nhân tạm thời không có giá trị, hãy thử lại",
"No crop data provided" : "Không có dữ liệu nguồn được cung cấp",
+ "%s password reset" : "%s thiết lập lại mật khẩu",
"Sunday" : "Chủ nhật",
"Monday" : "Thứ 2",
"Tuesday" : "Thứ 3",
@@ -71,7 +72,6 @@ OC.L10N.register(
"Error" : "Lỗi",
"Error while sharing" : "Lỗi trong quá trình chia sẻ",
"Error while unsharing" : "Lỗi trong quá trình gỡ chia sẻ",
- "Error while changing permissions" : "Lỗi trong quá trình phân quyền",
"Error setting expiration date" : "Lỗi cấu hình ngày kết thúc",
"Set expiration date" : "Đặt ngày kết thúc",
"Expiration date" : "Ngày kết thúc",
@@ -85,7 +85,6 @@ OC.L10N.register(
"Send" : "Gởi",
"Shared with you and the group {group} by {owner}" : "Đã được chia sẽ với bạn và nhóm {group} bởi {owner}",
"Shared with you by {owner}" : "Đã được chia sẽ bởi {owner}",
- "Shared in {item} with {user}" : "Đã được chia sẽ trong {item} với {user}",
"group" : "nhóm",
"notify by email" : "Thông báo qua email",
"Unshare" : "Bỏ chia sẻ",
@@ -96,19 +95,16 @@ OC.L10N.register(
"access control" : "quản lý truy cập",
"Share" : "Chia sẻ",
"Warning" : "Cảnh báo",
+ "Delete" : "Xóa",
+ "Rename" : "Sửa tên",
"The object type is not specified." : "Loại đối tượng không được chỉ định.",
"Enter new" : "Nhập mới",
- "Delete" : "Xóa",
"Add" : "Thêm",
"Edit tags" : "Sửa thẻ",
"Error loading dialog template: {error}" : "Lỗi khi tải mẫu hội thoại: {error}",
"No tags selected for deletion." : "Không có thẻ nào được chọn để xóa",
"Please reload the page." : "Vui lòng tải lại trang.",
"The update was successful. Redirecting you to ownCloud now." : "Cập nhật thành công .Hệ thống sẽ đưa bạn tới ownCloud.",
- "%s password reset" : "%s thiết lập lại mật khẩu",
- "Use the following link to reset your password: {link}" : "Dùng đường dẫn sau để khôi phục lại mật khẩu : {link}",
- "New password" : "Mật khẩu mới",
- "Reset password" : "Khôi phục mật khẩu",
"Personal" : "Cá nhân",
"Users" : "Người dùng",
"Apps" : "Ứng dụng",
@@ -142,6 +138,9 @@ OC.L10N.register(
"Please contact your administrator." : "Vui lòng liên hệ với quản trị viên.",
"Log in" : "Đăng nhập",
"Alternative Logins" : "Đăng nhập khác",
+ "Use the following link to reset your password: {link}" : "Dùng đường dẫn sau để khôi phục lại mật khẩu : {link}",
+ "New password" : "Mật khẩu mới",
+ "Reset password" : "Khôi phục mật khẩu",
"This ownCloud instance is currently in single user mode." : "OwnCloud trong trường hợp này đang ở chế độ người dùng duy nhất.",
"This means only administrators can use the instance." : "Điều này có nghĩa chỉ có người quản trị có thể sử dụng trong trường hợp này.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Liên hệ với người quản trị nếu lỗi này vẫn tồn tại hoặc xuất hiện bất ngờ.",
diff --git a/core/l10n/vi.json b/core/l10n/vi.json
index f4118935fd1..b3837cb72f8 100644
--- a/core/l10n/vi.json
+++ b/core/l10n/vi.json
@@ -8,6 +8,7 @@
"Invalid image" : "Hình ảnh không hợp lệ",
"No temporary profile picture available, try again" : "Ảnh cá nhân tạm thời không có giá trị, hãy thử lại",
"No crop data provided" : "Không có dữ liệu nguồn được cung cấp",
+ "%s password reset" : "%s thiết lập lại mật khẩu",
"Sunday" : "Chủ nhật",
"Monday" : "Thứ 2",
"Tuesday" : "Thứ 3",
@@ -69,7 +70,6 @@
"Error" : "Lỗi",
"Error while sharing" : "Lỗi trong quá trình chia sẻ",
"Error while unsharing" : "Lỗi trong quá trình gỡ chia sẻ",
- "Error while changing permissions" : "Lỗi trong quá trình phân quyền",
"Error setting expiration date" : "Lỗi cấu hình ngày kết thúc",
"Set expiration date" : "Đặt ngày kết thúc",
"Expiration date" : "Ngày kết thúc",
@@ -83,7 +83,6 @@
"Send" : "Gởi",
"Shared with you and the group {group} by {owner}" : "Đã được chia sẽ với bạn và nhóm {group} bởi {owner}",
"Shared with you by {owner}" : "Đã được chia sẽ bởi {owner}",
- "Shared in {item} with {user}" : "Đã được chia sẽ trong {item} với {user}",
"group" : "nhóm",
"notify by email" : "Thông báo qua email",
"Unshare" : "Bỏ chia sẻ",
@@ -94,19 +93,16 @@
"access control" : "quản lý truy cập",
"Share" : "Chia sẻ",
"Warning" : "Cảnh báo",
+ "Delete" : "Xóa",
+ "Rename" : "Sửa tên",
"The object type is not specified." : "Loại đối tượng không được chỉ định.",
"Enter new" : "Nhập mới",
- "Delete" : "Xóa",
"Add" : "Thêm",
"Edit tags" : "Sửa thẻ",
"Error loading dialog template: {error}" : "Lỗi khi tải mẫu hội thoại: {error}",
"No tags selected for deletion." : "Không có thẻ nào được chọn để xóa",
"Please reload the page." : "Vui lòng tải lại trang.",
"The update was successful. Redirecting you to ownCloud now." : "Cập nhật thành công .Hệ thống sẽ đưa bạn tới ownCloud.",
- "%s password reset" : "%s thiết lập lại mật khẩu",
- "Use the following link to reset your password: {link}" : "Dùng đường dẫn sau để khôi phục lại mật khẩu : {link}",
- "New password" : "Mật khẩu mới",
- "Reset password" : "Khôi phục mật khẩu",
"Personal" : "Cá nhân",
"Users" : "Người dùng",
"Apps" : "Ứng dụng",
@@ -140,6 +136,9 @@
"Please contact your administrator." : "Vui lòng liên hệ với quản trị viên.",
"Log in" : "Đăng nhập",
"Alternative Logins" : "Đăng nhập khác",
+ "Use the following link to reset your password: {link}" : "Dùng đường dẫn sau để khôi phục lại mật khẩu : {link}",
+ "New password" : "Mật khẩu mới",
+ "Reset password" : "Khôi phục mật khẩu",
"This ownCloud instance is currently in single user mode." : "OwnCloud trong trường hợp này đang ở chế độ người dùng duy nhất.",
"This means only administrators can use the instance." : "Điều này có nghĩa chỉ có người quản trị có thể sử dụng trong trường hợp này.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Liên hệ với người quản trị nếu lỗi này vẫn tồn tại hoặc xuất hiện bất ngờ.",
diff --git a/core/l10n/zh_CN.js b/core/l10n/zh_CN.js
index d2f2b6cb33b..49e24e1412e 100644
--- a/core/l10n/zh_CN.js
+++ b/core/l10n/zh_CN.js
@@ -6,14 +6,18 @@ OC.L10N.register(
"Turned on maintenance mode" : "启用维护模式",
"Turned off maintenance mode" : "关闭维护模式",
"Maintenance mode is kept active" : "维护模式已被启用",
+ "Updating database schema" : "正在更新数据库架构",
"Updated database" : "数据库已更新",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "检查数据库架构是否可以更新 (这可能需要很长的时间,这取决于数据库大小)",
"Checked database schema update" : "已经检查数据库架构更新",
+ "Checking updates of apps" : "检查更新应用",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "检查 %s 的数据库架构是否可以更新 (这可能需要很长的时间,这取决于数据库大小)",
"Checked database schema update for apps" : "已经检查应用的数据库架构更新",
"Updated \"%s\" to %s" : "更新 \"%s\" 为 %s",
"Repair warning: " : "修复警告:",
"Repair error: " : "修复错误:",
- "Set log level to debug - current level: \"%s\"" : "设置日志级别为 调试 - 目前级别:%s",
- "Reset log level to \"%s\"" : "重设日志级别为 \"%s\"",
+ "%s (3rdparty)" : "%s (第三方)",
+ "%s (incompatible)" : "%s (不兼容)",
"Following apps have been disabled: %s" : "下列应用已经被禁用:%s",
"Already up to date" : "已经是最新",
"File is too big" : "文件太大",
@@ -21,10 +25,16 @@ OC.L10N.register(
"No image or file provided" : "没有提供图片或文件",
"Unknown filetype" : "未知的文件类型",
"Invalid image" : "无效的图像",
+ "An error occurred. Please contact your admin." : "发生了一个错误,请联系管理员。",
"No temporary profile picture available, try again" : "没有临时概览页图片可用,请重试",
"No crop data provided" : "没有提供相应数据",
"No valid crop data provided" : "没有提供有效的裁剪数据",
"Crop is not square" : "裁剪的不是正方形",
+ "Couldn't reset password because the token is invalid" : "令牌无效,无法重置密码",
+ "Couldn't reset password because the token is expired" : "无法重设密码,因为令牌已过期",
+ "Couldn't send reset email. Please make sure your username is correct." : "无法发送重置邮件,请检查您的用户名是否正确。",
+ "%s password reset" : "重置 %s 的密码",
+ "Couldn't send reset email. Please contact your administrator." : "未能成功发送重置邮件,请联系管理员。",
"Sunday" : "星期日",
"Monday" : "星期一",
"Tuesday" : "星期二",
@@ -73,7 +83,6 @@ OC.L10N.register(
"Settings" : "设置",
"Saving..." : "保存中...",
"seconds ago" : "几秒前",
- "Couldn't send reset email. Please contact your administrator." : "未能成功发送重置邮件,请联系管理员。",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "密码重置邮件已经发送到您的电子邮箱中。如果您长时间没能收到邮件,请检查您的垃圾/广告邮件箱。<br>如果未能收到邮件请联系管理员。",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "您的文件已被加密。如果您没有启用恢复密钥,密码重置后您将无法取回您的文件。<br />在继续之前,如果有疑问请联系您的管理员。<br />确认继续?",
"I know what I'm doing" : "我知道我在做什么",
@@ -104,10 +113,6 @@ OC.L10N.register(
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "由于 WebDAV 接口似乎被破坏,因此你的网页服务器没有正确地设置来允许文件同步。",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "此服务器上没有可用的因特网连接. 这意味着某些特性将无法工作,例如挂载外部存储器, 提醒更新或安装第三方应用等. 从远程访问文件和发送提醒电子邮件也可能无法工作. 如果你想要ownCloud的所有特性, 我们建议启用此服务器的因特网连接.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "你的数据目录和你的文件可能从互联网被访问到。.htaccess 文件不工作。我们强烈建议你配置你的网页服务器,使数据目录不再可访问,或者将数据目录移动到网页服务器根文档目录之外。",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "内存缓存未配置。如果可用,请配置 memcache 来增强性能。更多信息请查看我们的<a href=\"{docLink}\">文档</a> 。",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom 无法被 PHP 读取,处于安全原因,这是强烈不推荐的。请查看<a href=\"{docLink}\">文档</a>了解详情。",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "你的 PHP 版本 ({version}) 不再被 <a href=\"{phpLink}\"> PHP </a>支持。我们建议您升级您的PHP版本,以便获得 PHP 性能和安全提升。",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "反向代理头配置不正确,或者您正从一个受信任的代理访问ownCloud。如果你不是通过受信任的代理访问 ownCloud,这将引发一个安全问题,可能由于 ownCloud IP 地址可见导致欺骗攻击。更多信息可以查看我们的 <a href=\"{docLink}\">文档</a>。",
"Error occurred while checking server setup" : "当检查服务器启动时出错",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP 头部没有配置和 \"{expected}\" 的一样。这是一个潜在的安全或者隐私风险,我们调整这项设置。",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP 严格传输安全(Strict-Transport-Security)报头未配置到至少“{seconds}”秒。处于增强安全性考虑,我们推荐按照<a href=\"{docUrl}\">安全提示</a>启用 HSTS。",
@@ -117,7 +122,6 @@ OC.L10N.register(
"Error" : "错误",
"Error while sharing" : "共享时出错",
"Error while unsharing" : "取消共享时出错",
- "Error while changing permissions" : "修改权限时出错",
"Error setting expiration date" : "设置过期日期时出错",
"The public link will expire no later than {days} days after it is created" : "这个共享链接将在创建后 {days} 天失效",
"Set expiration date" : "设置过期日期",
@@ -136,7 +140,6 @@ OC.L10N.register(
"Send" : "发送",
"Shared with you and the group {group} by {owner}" : "{owner} 共享给您及 {group} 组",
"Shared with you by {owner}" : "{owner} 与您共享",
- "Shared in {item} with {user}" : "在 {item} 与 {user} 共享。",
"group" : "群组",
"remote" : "远程",
"notify by email" : "以邮件通知",
@@ -155,9 +158,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "分享给其他用户、组或远程用户 ...",
"Warning" : "警告",
"Error while sending notification" : "发送通知时出现错误",
+ "Delete" : "删除",
+ "Rename" : "重命名",
"The object type is not specified." : "未指定对象类型。",
"Enter new" : "输入新...",
- "Delete" : "删除",
"Add" : "增加",
"Edit tags" : "编辑标签",
"Error loading dialog template: {error}" : "加载对话框模板出错: {error}",
@@ -169,20 +173,13 @@ OC.L10N.register(
"Hello {name}" : "你好 {name}",
"_download %n file_::_download %n files_" : ["下载 %n 个文件"],
"{version} is available. Get more information on how to update." : "{version} 现在可用。获取更多升级相关信息。",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "升级正在进行,在某些环境中离开此网页可能中断该过程。",
"Updating {productName} to version {version}, this may take a while." : "更新 {productName} 到版本 {version},这可能需要一些时间。",
+ "An error occurred." : "发生了一个错误",
"Please reload the page." : "请重新加载页面。",
"The update was unsuccessful. " : "升级未成功",
"The update was successful. There were warnings." : "更新成功。有警告。",
"The update was successful. Redirecting you to ownCloud now." : "更新成功。正在重定向至 ownCloud。",
- "Couldn't reset password because the token is invalid" : "令牌无效,无法重置密码",
- "Couldn't reset password because the token is expired" : "无法重设密码,因为令牌已过期",
- "Couldn't send reset email. Please make sure your username is correct." : "无法发送重置邮件,请检查您的用户名是否正确。",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "此用户名的电子邮件地址不存在导致无法发送重置邮件,请联系管理员。",
- "%s password reset" : "重置 %s 的密码",
- "Use the following link to reset your password: {link}" : "使用以下链接重置您的密码:{link}",
- "New password" : "新密码",
- "New Password" : "新密码",
- "Reset password" : "重置密码",
"Searching other places" : "搜索其他地方",
"No search results in other folders" : "在其他文件夹中没有得到任何搜索结果",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["在其他文件夹中找到 {count} 条搜索结果"],
@@ -252,12 +249,18 @@ OC.L10N.register(
"Please try again or contact your administrator." : "请重试或联系管理员。",
"Log in" : "登录",
"Wrong password. Reset it?" : "密码错误。要重置么?",
+ "Stay logged in" : "保持登录",
"Alternative Logins" : "其他登录方式",
+ "Use the following link to reset your password: {link}" : "使用以下链接重置您的密码:{link}",
+ "New password" : "新密码",
+ "New Password" : "新密码",
+ "Reset password" : "重置密码",
"This ownCloud instance is currently in single user mode." : "当前ownCloud实例运行在单用户模式下。",
"This means only administrators can use the instance." : "这意味着只有管理员才能在实例上操作。",
"Contact your system administrator if this message persists or appeared unexpectedly." : "如果这个消息一直存在或不停出现,请联系你的系统管理员。",
"Thank you for your patience." : "感谢让你久等了。",
"You are accessing the server from an untrusted domain." : "您正在访问来自不信任域名的服务器。",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "请联系你的系统管理员。如果你是系统管理员,配置 config/config.php 文件中参数 \"trusted_domain\" 设置。可以在 config/config.sample.php 文件中找到例子。",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "基于你的配置,作为系统管理员,你可能还能点击下面的按钮来信任这个域。",
"Add \"%s\" as trusted domain" : "添加 \"%s\"为信任域",
"App update required" : "必须的应用更新",
diff --git a/core/l10n/zh_CN.json b/core/l10n/zh_CN.json
index 4d7cbb12d1f..0c3f8972b71 100644
--- a/core/l10n/zh_CN.json
+++ b/core/l10n/zh_CN.json
@@ -4,14 +4,18 @@
"Turned on maintenance mode" : "启用维护模式",
"Turned off maintenance mode" : "关闭维护模式",
"Maintenance mode is kept active" : "维护模式已被启用",
+ "Updating database schema" : "正在更新数据库架构",
"Updated database" : "数据库已更新",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "检查数据库架构是否可以更新 (这可能需要很长的时间,这取决于数据库大小)",
"Checked database schema update" : "已经检查数据库架构更新",
+ "Checking updates of apps" : "检查更新应用",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "检查 %s 的数据库架构是否可以更新 (这可能需要很长的时间,这取决于数据库大小)",
"Checked database schema update for apps" : "已经检查应用的数据库架构更新",
"Updated \"%s\" to %s" : "更新 \"%s\" 为 %s",
"Repair warning: " : "修复警告:",
"Repair error: " : "修复错误:",
- "Set log level to debug - current level: \"%s\"" : "设置日志级别为 调试 - 目前级别:%s",
- "Reset log level to \"%s\"" : "重设日志级别为 \"%s\"",
+ "%s (3rdparty)" : "%s (第三方)",
+ "%s (incompatible)" : "%s (不兼容)",
"Following apps have been disabled: %s" : "下列应用已经被禁用:%s",
"Already up to date" : "已经是最新",
"File is too big" : "文件太大",
@@ -19,10 +23,16 @@
"No image or file provided" : "没有提供图片或文件",
"Unknown filetype" : "未知的文件类型",
"Invalid image" : "无效的图像",
+ "An error occurred. Please contact your admin." : "发生了一个错误,请联系管理员。",
"No temporary profile picture available, try again" : "没有临时概览页图片可用,请重试",
"No crop data provided" : "没有提供相应数据",
"No valid crop data provided" : "没有提供有效的裁剪数据",
"Crop is not square" : "裁剪的不是正方形",
+ "Couldn't reset password because the token is invalid" : "令牌无效,无法重置密码",
+ "Couldn't reset password because the token is expired" : "无法重设密码,因为令牌已过期",
+ "Couldn't send reset email. Please make sure your username is correct." : "无法发送重置邮件,请检查您的用户名是否正确。",
+ "%s password reset" : "重置 %s 的密码",
+ "Couldn't send reset email. Please contact your administrator." : "未能成功发送重置邮件,请联系管理员。",
"Sunday" : "星期日",
"Monday" : "星期一",
"Tuesday" : "星期二",
@@ -71,7 +81,6 @@
"Settings" : "设置",
"Saving..." : "保存中...",
"seconds ago" : "几秒前",
- "Couldn't send reset email. Please contact your administrator." : "未能成功发送重置邮件,请联系管理员。",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "密码重置邮件已经发送到您的电子邮箱中。如果您长时间没能收到邮件,请检查您的垃圾/广告邮件箱。<br>如果未能收到邮件请联系管理员。",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "您的文件已被加密。如果您没有启用恢复密钥,密码重置后您将无法取回您的文件。<br />在继续之前,如果有疑问请联系您的管理员。<br />确认继续?",
"I know what I'm doing" : "我知道我在做什么",
@@ -102,10 +111,6 @@
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "由于 WebDAV 接口似乎被破坏,因此你的网页服务器没有正确地设置来允许文件同步。",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "此服务器上没有可用的因特网连接. 这意味着某些特性将无法工作,例如挂载外部存储器, 提醒更新或安装第三方应用等. 从远程访问文件和发送提醒电子邮件也可能无法工作. 如果你想要ownCloud的所有特性, 我们建议启用此服务器的因特网连接.",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "你的数据目录和你的文件可能从互联网被访问到。.htaccess 文件不工作。我们强烈建议你配置你的网页服务器,使数据目录不再可访问,或者将数据目录移动到网页服务器根文档目录之外。",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "内存缓存未配置。如果可用,请配置 memcache 来增强性能。更多信息请查看我们的<a href=\"{docLink}\">文档</a> 。",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "/dev/urandom 无法被 PHP 读取,处于安全原因,这是强烈不推荐的。请查看<a href=\"{docLink}\">文档</a>了解详情。",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "你的 PHP 版本 ({version}) 不再被 <a href=\"{phpLink}\"> PHP </a>支持。我们建议您升级您的PHP版本,以便获得 PHP 性能和安全提升。",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "反向代理头配置不正确,或者您正从一个受信任的代理访问ownCloud。如果你不是通过受信任的代理访问 ownCloud,这将引发一个安全问题,可能由于 ownCloud IP 地址可见导致欺骗攻击。更多信息可以查看我们的 <a href=\"{docLink}\">文档</a>。",
"Error occurred while checking server setup" : "当检查服务器启动时出错",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP 头部没有配置和 \"{expected}\" 的一样。这是一个潜在的安全或者隐私风险,我们调整这项设置。",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP 严格传输安全(Strict-Transport-Security)报头未配置到至少“{seconds}”秒。处于增强安全性考虑,我们推荐按照<a href=\"{docUrl}\">安全提示</a>启用 HSTS。",
@@ -115,7 +120,6 @@
"Error" : "错误",
"Error while sharing" : "共享时出错",
"Error while unsharing" : "取消共享时出错",
- "Error while changing permissions" : "修改权限时出错",
"Error setting expiration date" : "设置过期日期时出错",
"The public link will expire no later than {days} days after it is created" : "这个共享链接将在创建后 {days} 天失效",
"Set expiration date" : "设置过期日期",
@@ -134,7 +138,6 @@
"Send" : "发送",
"Shared with you and the group {group} by {owner}" : "{owner} 共享给您及 {group} 组",
"Shared with you by {owner}" : "{owner} 与您共享",
- "Shared in {item} with {user}" : "在 {item} 与 {user} 共享。",
"group" : "群组",
"remote" : "远程",
"notify by email" : "以邮件通知",
@@ -153,9 +156,10 @@
"Share with users, groups or remote users …" : "分享给其他用户、组或远程用户 ...",
"Warning" : "警告",
"Error while sending notification" : "发送通知时出现错误",
+ "Delete" : "删除",
+ "Rename" : "重命名",
"The object type is not specified." : "未指定对象类型。",
"Enter new" : "输入新...",
- "Delete" : "删除",
"Add" : "增加",
"Edit tags" : "编辑标签",
"Error loading dialog template: {error}" : "加载对话框模板出错: {error}",
@@ -167,20 +171,13 @@
"Hello {name}" : "你好 {name}",
"_download %n file_::_download %n files_" : ["下载 %n 个文件"],
"{version} is available. Get more information on how to update." : "{version} 现在可用。获取更多升级相关信息。",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "升级正在进行,在某些环境中离开此网页可能中断该过程。",
"Updating {productName} to version {version}, this may take a while." : "更新 {productName} 到版本 {version},这可能需要一些时间。",
+ "An error occurred." : "发生了一个错误",
"Please reload the page." : "请重新加载页面。",
"The update was unsuccessful. " : "升级未成功",
"The update was successful. There were warnings." : "更新成功。有警告。",
"The update was successful. Redirecting you to ownCloud now." : "更新成功。正在重定向至 ownCloud。",
- "Couldn't reset password because the token is invalid" : "令牌无效,无法重置密码",
- "Couldn't reset password because the token is expired" : "无法重设密码,因为令牌已过期",
- "Couldn't send reset email. Please make sure your username is correct." : "无法发送重置邮件,请检查您的用户名是否正确。",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "此用户名的电子邮件地址不存在导致无法发送重置邮件,请联系管理员。",
- "%s password reset" : "重置 %s 的密码",
- "Use the following link to reset your password: {link}" : "使用以下链接重置您的密码:{link}",
- "New password" : "新密码",
- "New Password" : "新密码",
- "Reset password" : "重置密码",
"Searching other places" : "搜索其他地方",
"No search results in other folders" : "在其他文件夹中没有得到任何搜索结果",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["在其他文件夹中找到 {count} 条搜索结果"],
@@ -250,12 +247,18 @@
"Please try again or contact your administrator." : "请重试或联系管理员。",
"Log in" : "登录",
"Wrong password. Reset it?" : "密码错误。要重置么?",
+ "Stay logged in" : "保持登录",
"Alternative Logins" : "其他登录方式",
+ "Use the following link to reset your password: {link}" : "使用以下链接重置您的密码:{link}",
+ "New password" : "新密码",
+ "New Password" : "新密码",
+ "Reset password" : "重置密码",
"This ownCloud instance is currently in single user mode." : "当前ownCloud实例运行在单用户模式下。",
"This means only administrators can use the instance." : "这意味着只有管理员才能在实例上操作。",
"Contact your system administrator if this message persists or appeared unexpectedly." : "如果这个消息一直存在或不停出现,请联系你的系统管理员。",
"Thank you for your patience." : "感谢让你久等了。",
"You are accessing the server from an untrusted domain." : "您正在访问来自不信任域名的服务器。",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "请联系你的系统管理员。如果你是系统管理员,配置 config/config.php 文件中参数 \"trusted_domain\" 设置。可以在 config/config.sample.php 文件中找到例子。",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "基于你的配置,作为系统管理员,你可能还能点击下面的按钮来信任这个域。",
"Add \"%s\" as trusted domain" : "添加 \"%s\"为信任域",
"App update required" : "必须的应用更新",
diff --git a/core/l10n/zh_HK.js b/core/l10n/zh_HK.js
index b9791794e65..1e03d908948 100644
--- a/core/l10n/zh_HK.js
+++ b/core/l10n/zh_HK.js
@@ -32,7 +32,6 @@ OC.L10N.register(
"Error" : "錯誤",
"Error while sharing" : "分享時發生錯誤",
"Error while unsharing" : "取消分享時發生錯誤",
- "Error while changing permissions" : "更改權限時發生錯誤",
"Set expiration date" : "設定分享期限",
"Expiration date" : "分享期限",
"Sending ..." : "發送中...",
@@ -49,12 +48,9 @@ OC.L10N.register(
"Share" : "分享",
"Warning" : "警告",
"Delete" : "刪除",
+ "Rename" : "重新命名",
"Add" : "加入",
"The update was successful. Redirecting you to ownCloud now." : "更新成功, 正",
- "Use the following link to reset your password: {link}" : "請用以下連結重設你的密碼: {link}",
- "New password" : "新密碼",
- "New Password" : "新密碼",
- "Reset password" : "重設密碼",
"Personal" : "個人",
"Users" : "用戶",
"Apps" : "軟件",
@@ -68,6 +64,10 @@ OC.L10N.register(
"Database name" : "資料庫名稱",
"Log out" : "登出",
"Search" : "尋找",
- "Log in" : "登入"
+ "Log in" : "登入",
+ "Use the following link to reset your password: {link}" : "請用以下連結重設你的密碼: {link}",
+ "New password" : "新密碼",
+ "New Password" : "新密碼",
+ "Reset password" : "重設密碼"
},
"nplurals=1; plural=0;");
diff --git a/core/l10n/zh_HK.json b/core/l10n/zh_HK.json
index 7cb0e9e001e..cbb721c6b4b 100644
--- a/core/l10n/zh_HK.json
+++ b/core/l10n/zh_HK.json
@@ -30,7 +30,6 @@
"Error" : "錯誤",
"Error while sharing" : "分享時發生錯誤",
"Error while unsharing" : "取消分享時發生錯誤",
- "Error while changing permissions" : "更改權限時發生錯誤",
"Set expiration date" : "設定分享期限",
"Expiration date" : "分享期限",
"Sending ..." : "發送中...",
@@ -47,12 +46,9 @@
"Share" : "分享",
"Warning" : "警告",
"Delete" : "刪除",
+ "Rename" : "重新命名",
"Add" : "加入",
"The update was successful. Redirecting you to ownCloud now." : "更新成功, 正",
- "Use the following link to reset your password: {link}" : "請用以下連結重設你的密碼: {link}",
- "New password" : "新密碼",
- "New Password" : "新密碼",
- "Reset password" : "重設密碼",
"Personal" : "個人",
"Users" : "用戶",
"Apps" : "軟件",
@@ -66,6 +62,10 @@
"Database name" : "資料庫名稱",
"Log out" : "登出",
"Search" : "尋找",
- "Log in" : "登入"
+ "Log in" : "登入",
+ "Use the following link to reset your password: {link}" : "請用以下連結重設你的密碼: {link}",
+ "New password" : "新密碼",
+ "New Password" : "新密碼",
+ "Reset password" : "重設密碼"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/core/l10n/zh_TW.js b/core/l10n/zh_TW.js
index bf83a8eb3db..e39cc2bdcc8 100644
--- a/core/l10n/zh_TW.js
+++ b/core/l10n/zh_TW.js
@@ -16,12 +16,15 @@ OC.L10N.register(
"Updated \"%s\" to %s" : "已更新 %s 到 %s",
"Repair warning: " : "修復警告:",
"Repair error: " : "修復錯誤",
- "Set log level to debug - current level: \"%s\"" : "設定除錯記錄層級 - 目前層級: \"%s\"",
- "Reset log level to \"%s\"" : "重設記錄層級為 \"%s\"",
+ "Set log level to debug" : "設定紀錄變成除錯層級",
+ "Reset log level" : "重設記錄層級",
+ "Starting code integrity check" : "開始檢查程式碼完整性",
+ "Finished code integrity check" : "完成程式碼完整性檢查",
"%s (3rdparty)" : "%s (第3方)",
"%s (incompatible)" : "%s (不相容的)",
"Following apps have been disabled: %s" : "以下應用程式已經被停用:%s",
"Already up to date" : "已經是最新版",
+ "Please select a file." : "請選擇一個檔案",
"File is too big" : "檔案太大",
"Invalid file provided" : "提供的檔案無效",
"No image or file provided" : "未提供圖片或檔案",
@@ -32,6 +35,12 @@ OC.L10N.register(
"No crop data provided" : "未設定剪裁",
"No valid crop data provided" : "未提供有效的剪裁設定",
"Crop is not square" : "剪裁設定不是正方形",
+ "Couldn't reset password because the token is invalid" : "無法重設密碼因為 token 無效",
+ "Couldn't reset password because the token is expired" : "無法重設密碼,因為 token 過期",
+ "Couldn't send reset email. Please make sure your username is correct." : "無法寄送重設 email ,請確認您的帳號輸入正確",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "無法寄送重設 email ,因為這個帳號沒有設定 email 地址,請聯絡您的系統管理員。",
+ "%s password reset" : "%s 密碼重設",
+ "Couldn't send reset email. Please contact your administrator." : "無法寄送重設 email ,請聯絡系統管理員",
"Sunday" : "週日",
"Monday" : "週一",
"Tuesday" : "週二",
@@ -77,10 +86,10 @@ OC.L10N.register(
"Oct." : "十月",
"Nov." : "十一月",
"Dec." : "十二月",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">執行程式碼完整性檢查時發生問題。更多資訊…</a>",
"Settings" : "設定",
"Saving..." : "儲存中...",
"seconds ago" : "幾秒前",
- "Couldn't send reset email. Please contact your administrator." : "無法寄送重設 email ,請聯絡系統管理員",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "重設密碼的連結已經 email 至你的信箱,如果你在一段時間內沒收到,請檢查垃圾郵件資料夾,如果還是找不到,請聯絡系統管理員。",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "您的檔案是加密的,如果您沒有啟用救援金鑰,當您重設密碼之後將無法存取您的資料。<br/>如果不確定該怎麼做,請聯絡您的系統管理員。<br/>您確定要繼續嗎?",
"I know what I'm doing" : "我知道我在幹嘛",
@@ -103,28 +112,30 @@ OC.L10N.register(
"(all selected)" : "(已全選)",
"({count} selected)" : "(已選 {count} 項)",
"Error loading file exists template" : "載入檔案存在樣板出錯",
- "Very weak password" : "非常弱的密碼",
- "Weak password" : "弱的密碼",
- "So-so password" : "普通的密碼",
- "Good password" : "好的密碼",
- "Strong password" : "很強的密碼",
+ "Very weak password" : "密碼強度非常弱",
+ "Weak password" : "密碼強度弱",
+ "So-so password" : "密碼強度普通",
+ "Good password" : "密碼強度佳",
+ "Strong password" : "密碼強度極佳",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "您的網頁伺服器無法提供檔案同步功能,因為 WebDAV 界面有問題",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "您的網路伺服器尚未妥善的設定\"{url}\"。更多資訊請參閱我們的 <a target=\"_blank\" href=\"{docLink}\">文件</a>。",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "伺服器沒有網際網路連線,有些功能,像是外部儲存、更新版通知將無法運作。從遠端存取資料或是寄送 email 通知可能也無法運作。建議您設定好網際網路連線以使用所有功能。",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "您的資料目錄和您的檔案可能從網路網路被存取,使.htaccess 檔案無法發揮效果,我們強烈建議您配置您的網頁伺服器讓資料目錄不再被訪問存取或者將您的資料目錄移出網頁伺服器根目錄。",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "記憶體快取目前尚未配置,如果可以,請配置memcache提升效能,更多訊息查看 <a href=\"{docLink}\">文件</a>。",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP目前無法讀取/dev/urandom,基於安全因素,強烈建議您改善,更多訊息查看 <a href=\"{docLink}\">文件</a>。",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "您的PHP版本 ({version}) 不再被<a href=\"{phpLink}\">PHP</a>支援,我們建議您升級您的PHP版本來提升效能以及安全性。",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "反向代理伺服器標頭配置不正確或者您正從一個受信任的代理伺服器訪問ownCloud,如果您不是從受信任的代理伺服器訪問ownCloud,表示這是一個安全性問題,攻擊者可利用IP詐騙存取ownCloud,更多訊息查看 <a href=\"{docLink}\">文件</a>。",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "沒有設定 memory cache,為了增加效能,可以設定一個 memory cache ,請到<a target=\"_blank\" href=\"{docLink}\">我們的文件</a>取得更多資訊",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom 無法被 PHP 讀取,將造成安全性風險,請到<a target=\"_blank\" href=\"{docLink}\">我們的文件</a>取得更多資訊",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "您的PHP版本 ({version}) 不再被<a href=\"{phpLink}\">PHP</a>支援,我們建議您升級您的PHP版本來提升效能以及安全性。",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "反向代理伺服器標頭配置不正確或者您正從一個受信任的代理伺服器訪問ownCloud,如果您不是從受信任的代理伺服器訪問ownCloud,表示這是一個安全性問題,攻擊者可利用IP詐騙存取ownCloud,更多訊息查看 <a href=\"{docLink}\">文件</a>。",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached 被設置成分散式緩存模式,但已經安裝了錯誤的PHP模組 \"memcache\"。\\OC\\Memcache\\Memcached 只支援 \"memcached\",並未支援\"memcache\"。請參閱<a target=\"_blank\" href=\"{wikiLink}\">關於這兩個模組的wiki</a>。",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "有些檔案並未通過程式碼完整性的檢查,更多有關如何解決上述問題的資訊請參閱我們的 <a target=\"_blank\" href=\"{docLink}\">文件</a>。(<a href=\"{codeIntegrityDownloadEndpoint}\">列出所有無效的檔案…</a> / <a href=\"{rescanEndpoint}\">重新掃描…</a>)",
"Error occurred while checking server setup" : "檢查伺服器設定時發生錯誤",
- "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP 標頭配置與 \"{expected}\"不一樣,這是一個潛在安全性或者隱私上的風險,因此我們建議您調整此設定。",
- "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"強制安全傳輸\" HTTP標頭尚未配置至少 \"{seconds}\" 秒會重新定義成HTTPS,如我們的<a href=\"{docUrl}\">安全性提示</a>所述,為了加強安全性,我們建議啟動 HTTP強制安全傳輸。",
- "You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "您正在藉由HTTP訪問此網站,如我們的<a href=\"{docUrl}\">安全性提示</a>所述,我們強烈建議您配置您的伺服器須要求使用HTTPS。",
+ "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP 標頭配置與 \"{expected}\"不一樣,這是一個潛在安全性或者隱私上的風險,因此我們建議您調整此設定",
+ "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"Strict-Transport-Security\" HTTP 標頭 (HSTS) 並非設定為至少 {seconds} 秒,如我們的<a href=\"{docUrl}\">安全性提示</a>所述,為了加強安全性,我們建議啟動 HSTS (HTTP 強制安全傳輸)",
+ "You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "您正在藉由 HTTP 訪問此網站,如我們的<a href=\"{docUrl}\">安全性提示</a>所述,我們強烈建議設定您的伺服器須要求使用 HTTPS",
"Shared" : "已分享",
"Shared with {recipients}" : "與 {recipients} 分享",
"Error" : "錯誤",
"Error while sharing" : "分享時發生錯誤",
"Error while unsharing" : "取消分享時發生錯誤",
- "Error while changing permissions" : "修改權限時發生錯誤",
"Error setting expiration date" : "設定到期日發生錯誤",
"The public link will expire no later than {days} days after it is created" : "這個公開連結會在 {days} 天內失效",
"Set expiration date" : "指定到期日",
@@ -143,7 +154,6 @@ OC.L10N.register(
"Send" : "寄出",
"Shared with you and the group {group} by {owner}" : "由 {owner} 分享給您和 {group}",
"Shared with you by {owner}" : "{owner} 已經和您分享",
- "Shared in {item} with {user}" : "已和 {user} 分享 {item}",
"group" : "群組",
"remote" : "遠端",
"notify by email" : "以 email 通知",
@@ -162,9 +172,10 @@ OC.L10N.register(
"Share with users, groups or remote users …" : "與用戶,群組或是遠端使用者分享 ...",
"Warning" : "警告",
"Error while sending notification" : "發送通知錯誤",
+ "Delete" : "刪除",
+ "Rename" : "重新命名",
"The object type is not specified." : "未指定物件類型",
"Enter new" : "輸入新的",
- "Delete" : "刪除",
"Add" : "增加",
"Edit tags" : "編輯標籤",
"Error loading dialog template: {error}" : "載入對話樣板出錯:{error}",
@@ -183,15 +194,6 @@ OC.L10N.register(
"The update was unsuccessful. " : "更新失敗",
"The update was successful. There were warnings." : "更新成功,有警告訊息",
"The update was successful. Redirecting you to ownCloud now." : "升級成功,正將您重新導向至 ownCloud 。",
- "Couldn't reset password because the token is invalid" : "無法重設密碼因為 token 無效",
- "Couldn't reset password because the token is expired" : "無法重設密碼,因為 token 過期",
- "Couldn't send reset email. Please make sure your username is correct." : "無法寄送重設 email ,請確認您的帳號輸入正確",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "無法寄送重設 email ,因為這個帳號沒有設定 email 地址,請聯絡您的系統管理員",
- "%s password reset" : "%s 密碼重設",
- "Use the following link to reset your password: {link}" : "請至以下連結重設您的密碼: {link}",
- "New password" : "新密碼",
- "New Password" : "新密碼",
- "Reset password" : "重設密碼",
"Searching other places" : "搜尋其他位置",
"No search results in other folders" : "在其他資料夾中沒有找到",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["在其他資料夾中有 {count} 比結果"],
@@ -256,18 +258,24 @@ OC.L10N.register(
"Log out" : "登出",
"Search" : "搜尋",
"Server side authentication failed!" : "伺服器端認證失敗!",
- "Please contact your administrator." : "請聯絡系統管理員。",
+ "Please contact your administrator." : "請聯絡系統管理員",
"An internal error occured." : "發生內部錯誤",
"Please try again or contact your administrator." : "請重試或聯絡系統管理員",
"Log in" : "登入",
"Wrong password. Reset it?" : "密碼錯誤,重設密碼?",
+ "Wrong password." : "密碼錯誤",
"Stay logged in" : "保持登入狀態",
"Alternative Logins" : "其他登入方法",
+ "Use the following link to reset your password: {link}" : "請至以下連結重設您的密碼: {link}",
+ "New password" : "新密碼",
+ "New Password" : "新密碼",
+ "Reset password" : "重設密碼",
"This ownCloud instance is currently in single user mode." : "這個 ownCloud 伺服器目前運作於單一使用者模式",
"This means only administrators can use the instance." : "這表示只有系統管理員能夠使用",
"Contact your system administrator if this message persists or appeared unexpectedly." : "若這個訊息持續出現,請聯絡系統管理員",
"Thank you for your patience." : "感謝您的耐心",
"You are accessing the server from an untrusted domain." : "你正在從一個未信任的網域存取伺服器",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "請聯絡您的系統管理員,如果您就是系統管理員,請設定 config/config.php 中的 \"trusted_domain\" 選項。範例設定提供於 config/config.sample.php。",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "依照設定而定,您身為系統管理員可能也可以使用底下的按鈕來信任這個網域",
"Add \"%s\" as trusted domain" : "將 %s 加入到信任的網域",
"App update required" : "需要更新應用程式",
diff --git a/core/l10n/zh_TW.json b/core/l10n/zh_TW.json
index 89ed5f0c086..95df2e2f841 100644
--- a/core/l10n/zh_TW.json
+++ b/core/l10n/zh_TW.json
@@ -14,12 +14,15 @@
"Updated \"%s\" to %s" : "已更新 %s 到 %s",
"Repair warning: " : "修復警告:",
"Repair error: " : "修復錯誤",
- "Set log level to debug - current level: \"%s\"" : "設定除錯記錄層級 - 目前層級: \"%s\"",
- "Reset log level to \"%s\"" : "重設記錄層級為 \"%s\"",
+ "Set log level to debug" : "設定紀錄變成除錯層級",
+ "Reset log level" : "重設記錄層級",
+ "Starting code integrity check" : "開始檢查程式碼完整性",
+ "Finished code integrity check" : "完成程式碼完整性檢查",
"%s (3rdparty)" : "%s (第3方)",
"%s (incompatible)" : "%s (不相容的)",
"Following apps have been disabled: %s" : "以下應用程式已經被停用:%s",
"Already up to date" : "已經是最新版",
+ "Please select a file." : "請選擇一個檔案",
"File is too big" : "檔案太大",
"Invalid file provided" : "提供的檔案無效",
"No image or file provided" : "未提供圖片或檔案",
@@ -30,6 +33,12 @@
"No crop data provided" : "未設定剪裁",
"No valid crop data provided" : "未提供有效的剪裁設定",
"Crop is not square" : "剪裁設定不是正方形",
+ "Couldn't reset password because the token is invalid" : "無法重設密碼因為 token 無效",
+ "Couldn't reset password because the token is expired" : "無法重設密碼,因為 token 過期",
+ "Couldn't send reset email. Please make sure your username is correct." : "無法寄送重設 email ,請確認您的帳號輸入正確",
+ "Could not send reset email because there is no email address for this username. Please contact your administrator." : "無法寄送重設 email ,因為這個帳號沒有設定 email 地址,請聯絡您的系統管理員。",
+ "%s password reset" : "%s 密碼重設",
+ "Couldn't send reset email. Please contact your administrator." : "無法寄送重設 email ,請聯絡系統管理員",
"Sunday" : "週日",
"Monday" : "週一",
"Tuesday" : "週二",
@@ -75,10 +84,10 @@
"Oct." : "十月",
"Nov." : "十一月",
"Dec." : "十二月",
+ "<a href=\"{docUrl}\">There were problems with the code integrity check. More information…</a>" : "<a href=\"{docUrl}\">執行程式碼完整性檢查時發生問題。更多資訊…</a>",
"Settings" : "設定",
"Saving..." : "儲存中...",
"seconds ago" : "幾秒前",
- "Couldn't send reset email. Please contact your administrator." : "無法寄送重設 email ,請聯絡系統管理員",
"The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.<br>If it is not there ask your local administrator." : "重設密碼的連結已經 email 至你的信箱,如果你在一段時間內沒收到,請檢查垃圾郵件資料夾,如果還是找不到,請聯絡系統管理員。",
"Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.<br />If you are not sure what to do, please contact your administrator before you continue. <br />Do you really want to continue?" : "您的檔案是加密的,如果您沒有啟用救援金鑰,當您重設密碼之後將無法存取您的資料。<br/>如果不確定該怎麼做,請聯絡您的系統管理員。<br/>您確定要繼續嗎?",
"I know what I'm doing" : "我知道我在幹嘛",
@@ -101,28 +110,30 @@
"(all selected)" : "(已全選)",
"({count} selected)" : "(已選 {count} 項)",
"Error loading file exists template" : "載入檔案存在樣板出錯",
- "Very weak password" : "非常弱的密碼",
- "Weak password" : "弱的密碼",
- "So-so password" : "普通的密碼",
- "Good password" : "好的密碼",
- "Strong password" : "很強的密碼",
+ "Very weak password" : "密碼強度非常弱",
+ "Weak password" : "密碼強度弱",
+ "So-so password" : "密碼強度普通",
+ "Good password" : "密碼強度佳",
+ "Strong password" : "密碼強度極佳",
"Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "您的網頁伺服器無法提供檔案同步功能,因為 WebDAV 界面有問題",
+ "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "您的網路伺服器尚未妥善的設定\"{url}\"。更多資訊請參閱我們的 <a target=\"_blank\" href=\"{docLink}\">文件</a>。",
"This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "伺服器沒有網際網路連線,有些功能,像是外部儲存、更新版通知將無法運作。從遠端存取資料或是寄送 email 通知可能也無法運作。建議您設定好網際網路連線以使用所有功能。",
"Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "您的資料目錄和您的檔案可能從網路網路被存取,使.htaccess 檔案無法發揮效果,我們強烈建議您配置您的網頁伺服器讓資料目錄不再被訪問存取或者將您的資料目錄移出網頁伺服器根目錄。",
- "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "記憶體快取目前尚未配置,如果可以,請配置memcache提升效能,更多訊息查看 <a href=\"{docLink}\">文件</a>。",
- "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP目前無法讀取/dev/urandom,基於安全因素,強烈建議您改善,更多訊息查看 <a href=\"{docLink}\">文件</a>。",
- "Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "您的PHP版本 ({version}) 不再被<a href=\"{phpLink}\">PHP</a>支援,我們建議您升級您的PHP版本來提升效能以及安全性。",
- "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "反向代理伺服器標頭配置不正確或者您正從一個受信任的代理伺服器訪問ownCloud,如果您不是從受信任的代理伺服器訪問ownCloud,表示這是一個安全性問題,攻擊者可利用IP詐騙存取ownCloud,更多訊息查看 <a href=\"{docLink}\">文件</a>。",
+ "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "沒有設定 memory cache,為了增加效能,可以設定一個 memory cache ,請到<a target=\"_blank\" href=\"{docLink}\">我們的文件</a>取得更多資訊",
+ "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom 無法被 PHP 讀取,將造成安全性風險,請到<a target=\"_blank\" href=\"{docLink}\">我們的文件</a>取得更多資訊",
+ "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "您的PHP版本 ({version}) 不再被<a href=\"{phpLink}\">PHP</a>支援,我們建議您升級您的PHP版本來提升效能以及安全性。",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "反向代理伺服器標頭配置不正確或者您正從一個受信任的代理伺服器訪問ownCloud,如果您不是從受信任的代理伺服器訪問ownCloud,表示這是一個安全性問題,攻擊者可利用IP詐騙存取ownCloud,更多訊息查看 <a href=\"{docLink}\">文件</a>。",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached 被設置成分散式緩存模式,但已經安裝了錯誤的PHP模組 \"memcache\"。\\OC\\Memcache\\Memcached 只支援 \"memcached\",並未支援\"memcache\"。請參閱<a target=\"_blank\" href=\"{wikiLink}\">關於這兩個模組的wiki</a>。",
+ "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "有些檔案並未通過程式碼完整性的檢查,更多有關如何解決上述問題的資訊請參閱我們的 <a target=\"_blank\" href=\"{docLink}\">文件</a>。(<a href=\"{codeIntegrityDownloadEndpoint}\">列出所有無效的檔案…</a> / <a href=\"{rescanEndpoint}\">重新掃描…</a>)",
"Error occurred while checking server setup" : "檢查伺服器設定時發生錯誤",
- "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP 標頭配置與 \"{expected}\"不一樣,這是一個潛在安全性或者隱私上的風險,因此我們建議您調整此設定。",
- "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"強制安全傳輸\" HTTP標頭尚未配置至少 \"{seconds}\" 秒會重新定義成HTTPS,如我們的<a href=\"{docUrl}\">安全性提示</a>所述,為了加強安全性,我們建議啟動 HTTP強制安全傳輸。",
- "You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "您正在藉由HTTP訪問此網站,如我們的<a href=\"{docUrl}\">安全性提示</a>所述,我們強烈建議您配置您的伺服器須要求使用HTTPS。",
+ "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "\"{header}\" HTTP 標頭配置與 \"{expected}\"不一樣,這是一個潛在安全性或者隱私上的風險,因此我們建議您調整此設定",
+ "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "\"Strict-Transport-Security\" HTTP 標頭 (HSTS) 並非設定為至少 {seconds} 秒,如我們的<a href=\"{docUrl}\">安全性提示</a>所述,為了加強安全性,我們建議啟動 HSTS (HTTP 強制安全傳輸)",
+ "You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "您正在藉由 HTTP 訪問此網站,如我們的<a href=\"{docUrl}\">安全性提示</a>所述,我們強烈建議設定您的伺服器須要求使用 HTTPS",
"Shared" : "已分享",
"Shared with {recipients}" : "與 {recipients} 分享",
"Error" : "錯誤",
"Error while sharing" : "分享時發生錯誤",
"Error while unsharing" : "取消分享時發生錯誤",
- "Error while changing permissions" : "修改權限時發生錯誤",
"Error setting expiration date" : "設定到期日發生錯誤",
"The public link will expire no later than {days} days after it is created" : "這個公開連結會在 {days} 天內失效",
"Set expiration date" : "指定到期日",
@@ -141,7 +152,6 @@
"Send" : "寄出",
"Shared with you and the group {group} by {owner}" : "由 {owner} 分享給您和 {group}",
"Shared with you by {owner}" : "{owner} 已經和您分享",
- "Shared in {item} with {user}" : "已和 {user} 分享 {item}",
"group" : "群組",
"remote" : "遠端",
"notify by email" : "以 email 通知",
@@ -160,9 +170,10 @@
"Share with users, groups or remote users …" : "與用戶,群組或是遠端使用者分享 ...",
"Warning" : "警告",
"Error while sending notification" : "發送通知錯誤",
+ "Delete" : "刪除",
+ "Rename" : "重新命名",
"The object type is not specified." : "未指定物件類型",
"Enter new" : "輸入新的",
- "Delete" : "刪除",
"Add" : "增加",
"Edit tags" : "編輯標籤",
"Error loading dialog template: {error}" : "載入對話樣板出錯:{error}",
@@ -181,15 +192,6 @@
"The update was unsuccessful. " : "更新失敗",
"The update was successful. There were warnings." : "更新成功,有警告訊息",
"The update was successful. Redirecting you to ownCloud now." : "升級成功,正將您重新導向至 ownCloud 。",
- "Couldn't reset password because the token is invalid" : "無法重設密碼因為 token 無效",
- "Couldn't reset password because the token is expired" : "無法重設密碼,因為 token 過期",
- "Couldn't send reset email. Please make sure your username is correct." : "無法寄送重設 email ,請確認您的帳號輸入正確",
- "Couldn't send reset email because there is no email address for this username. Please contact your administrator." : "無法寄送重設 email ,因為這個帳號沒有設定 email 地址,請聯絡您的系統管理員",
- "%s password reset" : "%s 密碼重設",
- "Use the following link to reset your password: {link}" : "請至以下連結重設您的密碼: {link}",
- "New password" : "新密碼",
- "New Password" : "新密碼",
- "Reset password" : "重設密碼",
"Searching other places" : "搜尋其他位置",
"No search results in other folders" : "在其他資料夾中沒有找到",
"_{count} search result in another folder_::_{count} search results in other folders_" : ["在其他資料夾中有 {count} 比結果"],
@@ -254,18 +256,24 @@
"Log out" : "登出",
"Search" : "搜尋",
"Server side authentication failed!" : "伺服器端認證失敗!",
- "Please contact your administrator." : "請聯絡系統管理員。",
+ "Please contact your administrator." : "請聯絡系統管理員",
"An internal error occured." : "發生內部錯誤",
"Please try again or contact your administrator." : "請重試或聯絡系統管理員",
"Log in" : "登入",
"Wrong password. Reset it?" : "密碼錯誤,重設密碼?",
+ "Wrong password." : "密碼錯誤",
"Stay logged in" : "保持登入狀態",
"Alternative Logins" : "其他登入方法",
+ "Use the following link to reset your password: {link}" : "請至以下連結重設您的密碼: {link}",
+ "New password" : "新密碼",
+ "New Password" : "新密碼",
+ "Reset password" : "重設密碼",
"This ownCloud instance is currently in single user mode." : "這個 ownCloud 伺服器目前運作於單一使用者模式",
"This means only administrators can use the instance." : "這表示只有系統管理員能夠使用",
"Contact your system administrator if this message persists or appeared unexpectedly." : "若這個訊息持續出現,請聯絡系統管理員",
"Thank you for your patience." : "感謝您的耐心",
"You are accessing the server from an untrusted domain." : "你正在從一個未信任的網域存取伺服器",
+ "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "請聯絡您的系統管理員,如果您就是系統管理員,請設定 config/config.php 中的 \"trusted_domain\" 選項。範例設定提供於 config/config.sample.php。",
"Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "依照設定而定,您身為系統管理員可能也可以使用底下的按鈕來信任這個網域",
"Add \"%s\" as trusted domain" : "將 %s 加入到信任的網域",
"App update required" : "需要更新應用程式",
diff --git a/core/lostpassword/css/lostpassword.css b/core/lostpassword/css/lostpassword.css
deleted file mode 100644
index b7f7023648d..00000000000
--- a/core/lostpassword/css/lostpassword.css
+++ /dev/null
@@ -1,31 +0,0 @@
-#body-login
-input[type="text"]#user{
- padding-right: 20px;
- padding-left: 41px;
-}
-
-#body-login
-input[type="submit"] {
- text-align: center;
- width: 170px;
- height: 45px;
- padding-top: 7px;
- padding-bottom: 7px;
-}
-
-#body-login input[type="submit"]#submit {
- width: 280px;
-}
-
-#body-login .update {
- text-align: left;
-}
-
-#body-login .update,
-#body-login .error {
- margin: 10px 0 5px 0;
-}
-
-#user {
- width: 226px !important;
-}
diff --git a/core/register_command.php b/core/register_command.php
index 4044d2d200c..5f9a2675873 100644
--- a/core/register_command.php
+++ b/core/register_command.php
@@ -4,12 +4,14 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Christian Kampka <christian@kampka.net>
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,11 +34,21 @@ $application->add(new OC\Core\Command\Check(\OC::$server->getConfig()));
$infoParser = new \OC\App\InfoParser(\OC::$server->getHTTPHelper(), \OC::$server->getURLGenerator());
$application->add(new OC\Core\Command\App\CheckCode($infoParser));
$application->add(new OC\Core\Command\L10n\CreateJs());
+$application->add(new \OC\Core\Command\Integrity\SignApp(
+ \OC::$server->getIntegrityCodeChecker(),
+ new \OC\IntegrityCheck\Helpers\FileAccessHelper(),
+ \OC::$server->getURLGenerator()
+));
+$application->add(new \OC\Core\Command\Integrity\SignCore(
+ \OC::$server->getIntegrityCodeChecker(),
+ new \OC\IntegrityCheck\Helpers\FileAccessHelper()
+));
if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
- $application->add(new OC\Core\Command\App\Disable());
- $application->add(new OC\Core\Command\App\Enable());
- $application->add(new OC\Core\Command\App\ListApps());
+ $application->add(new OC\Core\Command\App\Disable(\OC::$server->getAppManager()));
+ $application->add(new OC\Core\Command\App\Enable(\OC::$server->getAppManager()));
+ $application->add(new OC\Core\Command\App\GetPath());
+ $application->add(new OC\Core\Command\App\ListApps(\OC::$server->getAppManager()));
$application->add(new OC\Core\Command\Background\Cron(\OC::$server->getConfig()));
$application->add(new OC\Core\Command\Background\WebCron(\OC::$server->getConfig()));
@@ -101,6 +113,10 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
$application->add(new OC\Core\Command\User\LastSeen(\OC::$server->getUserManager()));
$application->add(new OC\Core\Command\User\Report(\OC::$server->getUserManager()));
$application->add(new OC\Core\Command\User\ResetPassword(\OC::$server->getUserManager()));
+
+ $application->add(new OC\Core\Command\Security\ListCertificates(\OC::$server->getCertificateManager(null), \OC::$server->getL10N('core')));
+ $application->add(new OC\Core\Command\Security\ImportCertificate(\OC::$server->getCertificateManager(null)));
+ $application->add(new OC\Core\Command\Security\RemoveCertificate(\OC::$server->getCertificateManager(null)));
} else {
$application->add(new OC\Core\Command\Maintenance\Install(\OC::$server->getConfig()));
}
diff --git a/core/routes.php b/core/routes.php
index 0eb013aae85..8981eb618f3 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -11,7 +11,7 @@
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/search/ajax/search.php b/core/search/ajax/search.php
index 1b025088f08..6c5e0237362 100644
--- a/core/search/ajax/search.php
+++ b/core/search/ajax/search.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/search/js/search.js b/core/search/js/search.js
index 4e83a070170..ef99cf7e961 100644
--- a/core/search/js/search.js
+++ b/core/search/js/search.js
@@ -343,6 +343,18 @@
}
});
+ $(document).keydown(function(event) {
+ if ((event.ctrlKey || event.metaKey) && // Ctrl or Command (OSX)
+ !event.shiftKey &&
+ event.keyCode === 70 && // F
+ self.hasFilter(getCurrentApp()) && // Search is enabled
+ !$searchBox.is(':focus') // if searchbox is already focused do nothing (fallback to browser default)
+ ) {
+ $searchBox.focus();
+ event.preventDefault();
+ }
+ });
+
$searchResults.on('click', 'tr.result', function (event) {
var $row = $(this);
var item = $row.data('result');
diff --git a/core/shipped.json b/core/shipped.json
index cd1fca4d9fe..069bb210ba7 100644
--- a/core/shipped.json
+++ b/core/shipped.json
@@ -3,15 +3,16 @@
"activity",
"admin_audit",
"encryption",
+ "comments",
"dav",
"enterprise_key",
"external",
+ "federation",
"files",
"files_antivirus",
"files_drop",
"files_external",
"files_ldap_home",
- "files_locking",
"files_pdfviewer",
"files_sharing",
"files_sharing_log",
@@ -24,15 +25,17 @@
"gallery",
"notifications",
"objectstore",
+ "password_policy",
"provisioning_api",
"sharepoint",
+ "systemtags",
"templateeditor",
"updater",
"user_external",
"user_ldap",
"user_shibboleth",
"windows_network_drive",
- "password_policy"
+ "workflow"
],
"alwaysEnabled": [
"files",
diff --git a/core/strings.php b/core/strings.php
index e89228844d8..4936866377a 100644
--- a/core/strings.php
+++ b/core/strings.php
@@ -3,7 +3,7 @@
* @author Jan-Christoph Borchardt <hey@jancborchardt.net>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/tags/controller.php b/core/tags/controller.php
index e06a343f2b3..9798a59d56f 100644
--- a/core/tags/controller.php
+++ b/core/tags/controller.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/templates/404.php b/core/templates/404.php
index c8d16e3e8f7..2b12b12cff7 100644
--- a/core/templates/404.php
+++ b/core/templates/404.php
@@ -16,7 +16,7 @@ if(!isset($_)) {//also provide standalone error page
<li class="error">
<?php p($l->t('File not found')); ?><br>
<p class="hint"><?php p($l->t('The specified document has not been found on the server.')); ?></p>
- <p class="hint"><a href="<?php p(OC_Helper::linkTo('', 'index.php')) ?>"><?php p($l->t('You can click here to return to %s.', array($theme->getName()))); ?></a></p>
+ <p class="hint"><a href="<?php p(\OC::$server->getURLGenerator()->linkTo('', 'index.php')) ?>"><?php p($l->t('You can click here to return to %s.', array($theme->getName()))); ?></a></p>
</li>
</ul>
<?php endif; ?>
diff --git a/core/templates/internalmail.php b/core/templates/internalmail.php
index 0e73a601857..c2d84184d38 100644
--- a/core/templates/internalmail.php
+++ b/core/templates/internalmail.php
@@ -4,7 +4,7 @@
<tr>
<td bgcolor="<?php p($theme->getMailHeaderColor());?>" width="20px">&nbsp;</td>
<td bgcolor="<?php p($theme->getMailHeaderColor());?>">
-<img src="<?php p(OC_Helper::makeURLAbsolute(image_path('', 'logo-mail.gif'))); ?>" alt="<?php p($theme->getName()); ?>"/>
+<img src="<?php p(\OC::$server->getURLGenerator()->getAbsoluteURL(image_path('', 'logo-mail.gif'))); ?>" alt="<?php p($theme->getName()); ?>"/>
</td>
</tr>
<tr><td colspan="2">&nbsp;</td></tr>
diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php
index 5e13d9329f3..7905f5b7f3a 100644
--- a/core/templates/layout.user.php
+++ b/core/templates/layout.user.php
@@ -2,9 +2,9 @@
<!--[if lte IE 8]><html class="ng-csp ie ie8 lte9 lte8" data-placeholder-focus="false" lang="<?php p($_['language']); ?>" ><![endif]-->
<!--[if IE 9]><html class="ng-csp ie ie9 lte9" data-placeholder-focus="false" lang="<?php p($_['language']); ?>" ><![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--><html class="ng-csp" data-placeholder-focus="false" lang="<?php p($_['language']); ?>" ><!--<![endif]-->
- <head data-user="<?php p($_['user_uid']); ?>" data-requesttoken="<?php p($_['requesttoken']); ?>"
+ <head data-user="<?php p($_['user_uid']); ?>" data-user-displayname="<?php p($_['user_displayname']); ?>" data-requesttoken="<?php p($_['requesttoken']); ?>"
<?php if ($_['updateAvailable']): ?>
- data-update-version="<?php print($_['updateVersion']); ?>" data-update-link="<?php print_unescaped($_['updateLink']); ?>"
+ data-update-version="<?php p($_['updateVersion']); ?>" data-update-link="<?php p($_['updateLink']); ?>"
<?php endif; ?>
>
<meta charset="utf-8">
@@ -131,7 +131,7 @@
<li id="apps-management">
<a href="<?php print_unescaped(\OC::$server->getURLGenerator()->linkToRoute('settings.AppSettings.viewApps')); ?>" tabindex="4"
<?php if( $_['appsmanagement_active'] ): ?> class="active"<?php endif; ?>>
- <img class="app-icon svg" alt="" src="<?php print_unescaped(OC_Helper::imagePath('settings', 'apps.svg')); ?>">
+ <img class="app-icon svg" alt="" src="<?php print_unescaped(image_path('settings', 'apps.svg')); ?>">
<div class="icon-loading-dark" style="display:none;"></div>
<span>
<?php p($l->t('Apps')); ?>
diff --git a/core/templates/login.php b/core/templates/login.php
index 03be6258fdf..e87b871c67e 100644
--- a/core/templates/login.php
+++ b/core/templates/login.php
@@ -12,7 +12,7 @@ script('core', [
<form method="post" name="login">
<fieldset>
<?php if (!empty($_['redirect_url'])) {
- print_unescaped('<input type="hidden" name="redirect_url" value="' . OC_Util::sanitizeHTML($_['redirect_url']) . '">');
+ print_unescaped('<input type="hidden" name="redirect_url" value="' . \OCP\Util::sanitizeHTML($_['redirect_url']) . '">');
} ?>
<?php if (isset($_['apacheauthfailed']) && ($_['apacheauthfailed'])): ?>
<div class="warning">
@@ -56,11 +56,15 @@ script('core', [
<input type="submit" id="submit" class="login primary icon-confirm svg" title="<?php p($l->t('Log in')); ?>" value="" disabled="disabled"/>
</p>
- <?php if (isset($_['invalidpassword']) && ($_['invalidpassword'])): ?>
+ <?php if (!empty($_['invalidpassword']) && !empty($_['canResetPassword'])) { ?>
<a id="lost-password" class="warning" href="">
<?php p($l->t('Wrong password. Reset it?')); ?>
</a>
- <?php endif; ?>
+ <?php } else if (!empty($_['invalidpassword'])) { ?>
+ <p class="warning">
+ <?php p($l->t('Wrong password.')); ?>
+ </p>
+ <?php } ?>
<?php if ($_['rememberLoginAllowed'] === true) : ?>
<div class="remember-login-container">
<input type="checkbox" name="remember_login" value="1" id="remember_login" class="checkbox checkbox--white">
diff --git a/core/lostpassword/templates/email.php b/core/templates/lostpassword/email.php
index 618ac5dcd5c..3ca424d5294 100644
--- a/core/lostpassword/templates/email.php
+++ b/core/templates/lostpassword/email.php
@@ -2,7 +2,7 @@
/**
* @author Christopher Schäpers <kondou@ts.unde.re>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/core/lostpassword/templates/resetpassword.php b/core/templates/lostpassword/resetpassword.php
index c17ec652473..49ced424648 100644
--- a/core/lostpassword/templates/resetpassword.php
+++ b/core/templates/lostpassword/resetpassword.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,7 +22,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-style('lostpassword', 'resetpassword');
+style('core', 'lostpassword/resetpassword');
script('core', 'lostpassword');
?>
diff --git a/core/templates/mail.php b/core/templates/mail.php
index 0e73a601857..c2d84184d38 100644
--- a/core/templates/mail.php
+++ b/core/templates/mail.php
@@ -4,7 +4,7 @@
<tr>
<td bgcolor="<?php p($theme->getMailHeaderColor());?>" width="20px">&nbsp;</td>
<td bgcolor="<?php p($theme->getMailHeaderColor());?>">
-<img src="<?php p(OC_Helper::makeURLAbsolute(image_path('', 'logo-mail.gif'))); ?>" alt="<?php p($theme->getName()); ?>"/>
+<img src="<?php p(\OC::$server->getURLGenerator()->getAbsoluteURL(image_path('', 'logo-mail.gif'))); ?>" alt="<?php p($theme->getName()); ?>"/>
</td>
</tr>
<tr><td colspan="2">&nbsp;</td></tr>
diff --git a/core/templates/untrustedDomain.php b/core/templates/untrustedDomain.php
index 361495636cd..46bad216822 100644
--- a/core/templates/untrustedDomain.php
+++ b/core/templates/untrustedDomain.php
@@ -10,7 +10,7 @@
<?php p($l->t('Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain.')); ?>
<br><br>
<p style="text-align:center;">
- <a href="<?php print_unescaped(OC_Helper::makeURLAbsolute(\OCP\Util::linkToRoute('settings_admin'))); ?>?trustDomain=<?php p($_['domain']); ?>" class="button">
+ <a href="<?php print_unescaped(\OC::$server->getURLGenerator()->getAbsoluteURL(\OCP\Util::linkToRoute('settings_admin'))); ?>?trustDomain=<?php p($_['domain']); ?>" class="button">
<?php p($l->t('Add "%s" as trusted domain', array($_['domain']))); ?>
</a>
</p>
diff --git a/core/templates/update.admin.php b/core/templates/update.admin.php
index ae88350bdc5..75815de84bc 100644
--- a/core/templates/update.admin.php
+++ b/core/templates/update.admin.php
@@ -8,7 +8,7 @@
<?php } ?>
<?php if (!empty($_['appsToUpgrade'])) { ?>
<div class="infogroup">
- <span class="bold"><?php p($l->t('These apps will be updated:')); ?></span>
+ <span><?php p($l->t('These apps will be updated:')); ?></span>
<ul class="content appList">
<?php foreach ($_['appsToUpgrade'] as $appInfo) { ?>
<li><?php p($appInfo['name']) ?> (<?php p($appInfo['id']) ?>)</li>
@@ -18,7 +18,7 @@
<?php } ?>
<?php if (!empty($_['incompatibleAppsList'])) { ?>
<div class="infogroup">
- <span class="bold"><?php p($l->t('These incompatible apps will be disabled:')) ?></span>
+ <span><?php p($l->t('These incompatible apps will be disabled:')) ?></span>
<ul class="content appList">
<?php foreach ($_['incompatibleAppsList'] as $appInfo) { ?>
<li><?php p($appInfo['name']) ?> (<?php p($appInfo['id']) ?>)</li>
@@ -27,7 +27,7 @@
</div>
<?php } ?>
<?php if (!empty($_['oldTheme'])) { ?>
- <div class="infogroup bold">
+ <div class="infogroup">
<?php p($l->t('The theme %s has been disabled.', array($_['oldTheme']))) ?>
</div>
<?php } ?>
diff --git a/core/vendor/.gitignore b/core/vendor/.gitignore
index bcbb59b6f24..3560e8c8668 100644
--- a/core/vendor/.gitignore
+++ b/core/vendor/.gitignore
@@ -122,3 +122,16 @@ bootstrap/js/*
# backbone
backbone/backbone-min*
+
+# davclient.js
+davclient.js/**
+!davclient.js/lib/*
+!davclient.js/LICENSE
+
+# es6-promise
+es6-promise/**
+!es6-promise/LICENSE
+!es6-promise/dist/es6-promise.js
+
+# base64
+base64/*min.js
diff --git a/core/vendor/backbone/.bower.json b/core/vendor/backbone/.bower.json
index 578c8ffb669..38a9c03af75 100644
--- a/core/vendor/backbone/.bower.json
+++ b/core/vendor/backbone/.bower.json
@@ -1,6 +1,5 @@
{
"name": "backbone",
- "version": "1.2.1",
"main": "backbone.js",
"dependencies": {
"underscore": ">=1.7.0"
@@ -20,14 +19,14 @@
"package.json"
],
"homepage": "https://github.com/jashkenas/backbone",
- "_release": "1.2.1",
+ "version": "1.2.3",
+ "_release": "1.2.3",
"_resolution": {
"type": "version",
- "tag": "1.2.1",
- "commit": "938a8ff934fd4de4f0009f68d43f500f5920b490"
+ "tag": "1.2.3",
+ "commit": "05fde9e201f7e2137796663081105cd6dad12a98"
},
"_source": "git://github.com/jashkenas/backbone.git",
- "_target": "~1.2.1",
- "_originalSource": "backbone",
- "_direct": true
+ "_target": "~1.2.3",
+ "_originalSource": "backbone"
} \ No newline at end of file
diff --git a/core/vendor/backbone/backbone.js b/core/vendor/backbone/backbone.js
index 58800425c70..c9249656218 100644
--- a/core/vendor/backbone/backbone.js
+++ b/core/vendor/backbone/backbone.js
@@ -1,4 +1,4 @@
-// Backbone.js 1.2.1
+// Backbone.js 1.2.3
// (c) 2010-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Backbone may be freely distributed under the MIT license.
@@ -41,10 +41,10 @@
var previousBackbone = root.Backbone;
// Create a local reference to a common array method we'll want to use later.
- var slice = [].slice;
+ var slice = Array.prototype.slice;
// Current version of the library. Keep in sync with `package.json`.
- Backbone.VERSION = '1.2.1';
+ Backbone.VERSION = '1.2.3';
// For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
// the `$` variable.
@@ -68,8 +68,13 @@
// form param named `model`.
Backbone.emulateJSON = false;
- // Proxy Underscore methods to a Backbone class' prototype using a
- // particular attribute as the data argument
+ // Proxy Backbone class methods to Underscore functions, wrapping the model's
+ // `attributes` object or collection's `models` array behind the scenes.
+ //
+ // collection.filter(function(model) { return model.get('age') > 10 });
+ // collection.each(this.addView);
+ //
+ // `Function#apply` can be slow so we use the method's arg count, if we know it.
var addMethod = function(length, method, attribute) {
switch (length) {
case 1: return function() {
@@ -79,10 +84,10 @@
return _[method](this[attribute], value);
};
case 3: return function(iteratee, context) {
- return _[method](this[attribute], iteratee, context);
+ return _[method](this[attribute], cb(iteratee, this), context);
};
case 4: return function(iteratee, defaultVal, context) {
- return _[method](this[attribute], iteratee, defaultVal, context);
+ return _[method](this[attribute], cb(iteratee, this), defaultVal, context);
};
default: return function() {
var args = slice.call(arguments);
@@ -97,12 +102,26 @@
});
};
+ // Support `collection.sortBy('attr')` and `collection.findWhere({id: 1})`.
+ var cb = function(iteratee, instance) {
+ if (_.isFunction(iteratee)) return iteratee;
+ if (_.isObject(iteratee) && !instance._isModel(iteratee)) return modelMatcher(iteratee);
+ if (_.isString(iteratee)) return function(model) { return model.get(iteratee); };
+ return iteratee;
+ };
+ var modelMatcher = function(attrs) {
+ var matcher = _.matches(attrs);
+ return function(model) {
+ return matcher(model.attributes);
+ };
+ };
+
// Backbone.Events
// ---------------
// A module that can be mixed in to *any object* in order to provide it with
- // custom events. You may bind with `on` or remove with `off` callback
- // functions to an event; `trigger`-ing an event fires all callbacks in
+ // a custom event channel. You may bind a callback to an event with `on` or
+ // remove with `off`; `trigger`-ing an event fires all callbacks in
// succession.
//
// var object = {};
@@ -117,26 +136,25 @@
// Iterates over the standard `event, callback` (as well as the fancy multiple
// space-separated events `"change blur", callback` and jQuery-style event
- // maps `{event: callback}`), reducing them by manipulating `memo`.
- // Passes a normalized single event name and callback, as well as any
- // optional `opts`.
- var eventsApi = function(iteratee, memo, name, callback, opts) {
+ // maps `{event: callback}`).
+ var eventsApi = function(iteratee, events, name, callback, opts) {
var i = 0, names;
if (name && typeof name === 'object') {
// Handle event maps.
if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
for (names = _.keys(name); i < names.length ; i++) {
- memo = iteratee(memo, names[i], name[names[i]], opts);
+ events = eventsApi(iteratee, events, names[i], name[names[i]], opts);
}
} else if (name && eventSplitter.test(name)) {
- // Handle space separated event names.
+ // Handle space separated event names by delegating them individually.
for (names = name.split(eventSplitter); i < names.length; i++) {
- memo = iteratee(memo, names[i], callback, opts);
+ events = iteratee(events, names[i], callback, opts);
}
} else {
- memo = iteratee(memo, name, callback, opts);
+ // Finally, standard events.
+ events = iteratee(events, name, callback, opts);
}
- return memo;
+ return events;
};
// Bind an event to a `callback` function. Passing `"all"` will bind
@@ -145,8 +163,7 @@
return internalOn(this, name, callback, context);
};
- // An internal use `on` function, used to guard the `listening` argument from
- // the public API.
+ // Guard the `listening` argument from the public API.
var internalOn = function(obj, name, callback, context, listening) {
obj._events = eventsApi(onApi, obj._events || {}, name, callback, {
context: context,
@@ -163,7 +180,8 @@
};
// Inversion-of-control versions of `on`. Tell *this* object to listen to
- // an event in another object... keeping track of what it's listening to.
+ // an event in another object... keeping track of what it's listening to
+ // for easier unbinding later.
Events.listenTo = function(obj, name, callback) {
if (!obj) return this;
var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
@@ -231,7 +249,6 @@
// The reducing API that removes a callback from the `events` object.
var offApi = function(events, name, callback, options) {
- // No events to consider.
if (!events) return;
var i = 0, listening;
@@ -286,9 +303,9 @@
};
// Bind an event to only be triggered a single time. After the first time
- // the callback is invoked, it will be removed. When multiple events are
- // passed in using the space-separated syntax, the event will fire once for every
- // event you passed in, not once for a combination of all events
+ // the callback is invoked, its listener will be removed. If multiple events
+ // are passed in using the space-separated syntax, the handler will fire
+ // once for each event, not once for a combination of all events.
Events.once = function(name, callback, context) {
// Map the event into a `{event: once}` object.
var events = eventsApi(onceMap, {}, name, callback, _.bind(this.off, this));
@@ -476,9 +493,6 @@
var changed = this.changed;
var prev = this._previousAttributes;
- // Check for changes of `id`.
- if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
-
// For each `set` attribute, update or delete the current value.
for (var attr in attrs) {
val = attrs[attr];
@@ -491,6 +505,9 @@
unset ? delete current[attr] : current[attr] = val;
}
+ // Update the `id`.
+ this.id = this.get(this.idAttribute);
+
// Trigger all relevant attribute changes.
if (!silent) {
if (changes.length) this._pending = options;
@@ -713,7 +730,8 @@
});
- // Underscore methods that we want to implement on the Model.
+ // Underscore methods that we want to implement on the Model, mapped to the
+ // number of arguments they take.
var modelMethods = { keys: 1, values: 1, pairs: 1, invert: 1, pick: 0,
omit: 0, chain: 1, isEmpty: 1 };
@@ -746,6 +764,16 @@
var setOptions = {add: true, remove: true, merge: true};
var addOptions = {add: true, remove: false};
+ // Splices `insert` into `array` at index `at`.
+ var splice = function(array, insert, at) {
+ at = Math.min(Math.max(at, 0), array.length);
+ var tail = Array(array.length - at);
+ var length = insert.length;
+ for (var i = 0; i < tail.length; i++) tail[i] = array[i + at];
+ for (i = 0; i < length; i++) array[i + at] = insert[i];
+ for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i];
+ };
+
// Define the Collection's inheritable methods.
_.extend(Collection.prototype, Events, {
@@ -768,7 +796,9 @@
return Backbone.sync.apply(this, arguments);
},
- // Add a model, or list of models to the set.
+ // Add a model, or list of models to the set. `models` may be Backbone
+ // Models or raw JavaScript objects to be converted to Models, or any
+ // combination of the two.
add: function(models, options) {
return this.set(models, _.extend({merge: false}, options, addOptions));
},
@@ -788,83 +818,88 @@
// already exist in the collection, as necessary. Similar to **Model#set**,
// the core operation for updating the data contained by the collection.
set: function(models, options) {
+ if (models == null) return;
+
options = _.defaults({}, options, setOptions);
if (options.parse && !this._isModel(models)) models = this.parse(models, options);
+
var singular = !_.isArray(models);
- models = singular ? (models ? [models] : []) : models.slice();
- var id, model, attrs, existing, sort;
+ models = singular ? [models] : models.slice();
+
var at = options.at;
if (at != null) at = +at;
if (at < 0) at += this.length + 1;
+
+ var set = [];
+ var toAdd = [];
+ var toRemove = [];
+ var modelMap = {};
+
+ var add = options.add;
+ var merge = options.merge;
+ var remove = options.remove;
+
+ var sort = false;
var sortable = this.comparator && (at == null) && options.sort !== false;
var sortAttr = _.isString(this.comparator) ? this.comparator : null;
- var toAdd = [], toRemove = [], modelMap = {};
- var add = options.add, merge = options.merge, remove = options.remove;
- var order = !sortable && add && remove ? [] : false;
- var orderChanged = false;
// Turn bare objects into model references, and prevent invalid models
// from being added.
+ var model;
for (var i = 0; i < models.length; i++) {
- attrs = models[i];
+ model = models[i];
// If a duplicate is found, prevent it from being added and
// optionally merge it into the existing model.
- if (existing = this.get(attrs)) {
- if (remove) modelMap[existing.cid] = true;
- if (merge && attrs !== existing) {
- attrs = this._isModel(attrs) ? attrs.attributes : attrs;
+ var existing = this.get(model);
+ if (existing) {
+ if (merge && model !== existing) {
+ var attrs = this._isModel(model) ? model.attributes : model;
if (options.parse) attrs = existing.parse(attrs, options);
existing.set(attrs, options);
- if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
+ if (sortable && !sort) sort = existing.hasChanged(sortAttr);
+ }
+ if (!modelMap[existing.cid]) {
+ modelMap[existing.cid] = true;
+ set.push(existing);
}
models[i] = existing;
// If this is a new, valid model, push it to the `toAdd` list.
} else if (add) {
- model = models[i] = this._prepareModel(attrs, options);
- if (!model) continue;
- toAdd.push(model);
- this._addReference(model, options);
- }
-
- // Do not add multiple models with the same `id`.
- model = existing || model;
- if (!model) continue;
- id = this.modelId(model.attributes);
- if (order && (model.isNew() || !modelMap[id])) {
- order.push(model);
-
- // Check to see if this is actually a new model at this index.
- orderChanged = orderChanged || !this.models[i] || model.cid !== this.models[i].cid;
+ model = models[i] = this._prepareModel(model, options);
+ if (model) {
+ toAdd.push(model);
+ this._addReference(model, options);
+ modelMap[model.cid] = true;
+ set.push(model);
+ }
}
-
- modelMap[id] = true;
}
- // Remove nonexistent models if appropriate.
+ // Remove stale models.
if (remove) {
- for (var i = 0; i < this.length; i++) {
- if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
+ for (i = 0; i < this.length; i++) {
+ model = this.models[i];
+ if (!modelMap[model.cid]) toRemove.push(model);
}
if (toRemove.length) this._removeModels(toRemove, options);
}
// See if sorting is needed, update `length` and splice in new models.
- if (toAdd.length || orderChanged) {
+ var orderChanged = false;
+ var replace = !sortable && add && remove;
+ if (set.length && replace) {
+ orderChanged = this.length != set.length || _.some(this.models, function(model, index) {
+ return model !== set[index];
+ });
+ this.models.length = 0;
+ splice(this.models, set, 0);
+ this.length = this.models.length;
+ } else if (toAdd.length) {
if (sortable) sort = true;
- this.length += toAdd.length;
- if (at != null) {
- for (var i = 0; i < toAdd.length; i++) {
- this.models.splice(at + i, 0, toAdd[i]);
- }
- } else {
- if (order) this.models.length = 0;
- var orderedModels = order || toAdd;
- for (var i = 0; i < orderedModels.length; i++) {
- this.models.push(orderedModels[i]);
- }
- }
+ splice(this.models, toAdd, at == null ? this.length : at);
+ this.length = this.models.length;
}
// Silently sort the collection if appropriate.
@@ -872,10 +907,10 @@
// Unless silenced, it's time to fire all appropriate add/sort events.
if (!options.silent) {
- var addOpts = at != null ? _.clone(options) : options;
- for (var i = 0; i < toAdd.length; i++) {
- if (at != null) addOpts.index = at + i;
- (model = toAdd[i]).trigger('add', model, this, addOpts);
+ for (i = 0; i < toAdd.length; i++) {
+ if (at != null) options.index = at + i;
+ model = toAdd[i];
+ model.trigger('add', model, this, options);
}
if (sort || orderChanged) this.trigger('sort', this, options);
if (toAdd.length || toRemove.length) this.trigger('update', this, options);
@@ -944,10 +979,7 @@
// Return models with matching attributes. Useful for simple cases of
// `filter`.
where: function(attrs, first) {
- var matches = _.matches(attrs);
- return this[first ? 'find' : 'filter'](function(model) {
- return matches(model.attributes);
- });
+ return this[first ? 'find' : 'filter'](attrs);
},
// Return the first model with matching attributes. Useful for simple cases
@@ -960,16 +992,19 @@
// normal circumstances, as the set will maintain sort order as each item
// is added.
sort: function(options) {
- if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
+ var comparator = this.comparator;
+ if (!comparator) throw new Error('Cannot sort a set without a comparator');
options || (options = {});
+ var length = comparator.length;
+ if (_.isFunction(comparator)) comparator = _.bind(comparator, this);
+
// Run sort based on type of `comparator`.
- if (_.isString(this.comparator) || this.comparator.length === 1) {
- this.models = this.sortBy(this.comparator, this);
+ if (length === 1 || _.isString(comparator)) {
+ this.models = this.sortBy(comparator);
} else {
- this.models.sort(_.bind(this.comparator, this));
+ this.models.sort(comparator);
}
-
if (!options.silent) this.trigger('sort', this, options);
return this;
},
@@ -1058,7 +1093,6 @@
},
// Internal method called by both remove and set.
- // Returns removed models, or false if nothing is removed.
_removeModels: function(models, options) {
var removed = [];
for (var i = 0; i < models.length; i++) {
@@ -1128,29 +1162,16 @@
// right here:
var collectionMethods = { forEach: 3, each: 3, map: 3, collect: 3, reduce: 4,
foldl: 4, inject: 4, reduceRight: 4, foldr: 4, find: 3, detect: 3, filter: 3,
- select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 2,
- contains: 2, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3,
+ select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 3, includes: 3,
+ contains: 3, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3,
head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3,
without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3,
- isEmpty: 1, chain: 1, sample: 3, partition: 3 };
+ isEmpty: 1, chain: 1, sample: 3, partition: 3, groupBy: 3, countBy: 3,
+ sortBy: 3, indexBy: 3};
// Mix in each Underscore method as a proxy to `Collection#models`.
addUnderscoreMethods(Collection, collectionMethods, 'models');
- // Underscore methods that take a property name as an argument.
- var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];
-
- // Use attributes instead of properties.
- _.each(attributeMethods, function(method) {
- if (!_[method]) return;
- Collection.prototype[method] = function(value, context) {
- var iterator = _.isFunction(value) ? value : function(model) {
- return model.get(value);
- };
- return _[method](this.models, iterator, context);
- };
- });
-
// Backbone.View
// -------------
@@ -1174,7 +1195,7 @@
// Cached regex to split keys for `delegate`.
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
- // List of view options to be merged as properties.
+ // List of view options to be set as properties.
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
// Set up all inheritable **Backbone.View** properties and methods.
@@ -1518,7 +1539,7 @@
// falls back to polling.
var History = Backbone.History = function() {
this.handlers = [];
- _.bindAll(this, 'checkUrl');
+ this.checkUrl = _.bind(this.checkUrl, this);
// Ensure that `History` can be used outside of the browser.
if (typeof window !== 'undefined') {
@@ -1611,7 +1632,7 @@
this.options = _.extend({root: '/'}, this.options, options);
this.root = this.options.root;
this._wantsHashChange = this.options.hashChange !== false;
- this._hasHashChange = 'onhashchange' in window;
+ this._hasHashChange = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7);
this._useHashChange = this._wantsHashChange && this._hasHashChange;
this._wantsPushState = !!this.options.pushState;
this._hasPushState = !!(this.history && this.history.pushState);
@@ -1730,7 +1751,7 @@
// If the root doesn't match, no routes can match either.
if (!this.matchRoot()) return false;
fragment = this.fragment = this.getFragment(fragment);
- return _.any(this.handlers, function(handler) {
+ return _.some(this.handlers, function(handler) {
if (handler.route.test(fragment)) {
handler.callback(fragment);
return true;
diff --git a/core/vendor/base64/.bower.json b/core/vendor/base64/.bower.json
new file mode 100644
index 00000000000..43a7299706b
--- /dev/null
+++ b/core/vendor/base64/.bower.json
@@ -0,0 +1,29 @@
+{
+ "name": "base64",
+ "version": "0.3.0",
+ "description": "Base64 encoding and decoding",
+ "main": "./base64.js",
+ "license": "WTFPL",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/davidchambers/Base64.js.git"
+ },
+ "ignore": [
+ "**/.*",
+ "Makefile",
+ "coverage/",
+ "scripts/",
+ "test/"
+ ],
+ "homepage": "https://github.com/davidchambers/Base64.js",
+ "_release": "0.3.0",
+ "_resolution": {
+ "type": "version",
+ "tag": "0.3.0",
+ "commit": "772df096a5ffe983f40202684ad45eed1e0e2d59"
+ },
+ "_source": "git://github.com/davidchambers/Base64.js.git",
+ "_target": "~0.3.0",
+ "_originalSource": "base64",
+ "_direct": true
+} \ No newline at end of file
diff --git a/core/vendor/base64/LICENSE b/core/vendor/base64/LICENSE
new file mode 100644
index 00000000000..483276716db
--- /dev/null
+++ b/core/vendor/base64/LICENSE
@@ -0,0 +1,14 @@
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (c) 2011..2012 David Chambers <dc@hashify.me>
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
diff --git a/core/vendor/base64/base64.js b/core/vendor/base64/base64.js
new file mode 100644
index 00000000000..b82dded62c2
--- /dev/null
+++ b/core/vendor/base64/base64.js
@@ -0,0 +1,61 @@
+;(function () {
+
+ var object = typeof exports != 'undefined' ? exports : this; // #8: web workers
+ var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+
+ function InvalidCharacterError(message) {
+ this.message = message;
+ }
+ InvalidCharacterError.prototype = new Error;
+ InvalidCharacterError.prototype.name = 'InvalidCharacterError';
+
+ // encoder
+ // [https://gist.github.com/999166] by [https://github.com/nignag]
+ object.btoa || (
+ object.btoa = function (input) {
+ var str = String(input);
+ for (
+ // initialize result and counter
+ var block, charCode, idx = 0, map = chars, output = '';
+ // if the next str index does not exist:
+ // change the mapping table to "="
+ // check if d has no fractional digits
+ str.charAt(idx | 0) || (map = '=', idx % 1);
+ // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
+ output += map.charAt(63 & block >> 8 - idx % 1 * 8)
+ ) {
+ charCode = str.charCodeAt(idx += 3/4);
+ if (charCode > 0xFF) {
+ throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
+ }
+ block = block << 8 | charCode;
+ }
+ return output;
+ });
+
+ // decoder
+ // [https://gist.github.com/1020396] by [https://github.com/atk]
+ object.atob || (
+ object.atob = function (input) {
+ var str = String(input).replace(/=+$/, '');
+ if (str.length % 4 == 1) {
+ throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
+ }
+ for (
+ // initialize result and counters
+ var bc = 0, bs, buffer, idx = 0, output = '';
+ // get next character
+ buffer = str.charAt(idx++);
+ // character found in table? initialize bit storage and add its ascii value;
+ ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
+ // and if not first of each 4 characters,
+ // convert the first 8 bits to one ascii character
+ bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
+ ) {
+ // try to find character in table (0-63, not found => -1)
+ buffer = chars.indexOf(buffer);
+ }
+ return output;
+ });
+
+}());
diff --git a/core/vendor/bootstrap/js/tooltip.js b/core/vendor/bootstrap/js/tooltip.js
index c3fe4b06ca2..7094b34dce7 100644
--- a/core/vendor/bootstrap/js/tooltip.js
+++ b/core/vendor/bootstrap/js/tooltip.js
@@ -1,5 +1,5 @@
/* ========================================================================
- * Bootstrap: tooltip.js v3.3.5
+ * Bootstrap: tooltip.js v3.3.6
* http://getbootstrap.com/javascript/#tooltip
* Inspired by the original jQuery.tipsy by Jason Frame
* ========================================================================
@@ -26,7 +26,7 @@
this.init('tooltip', element, options)
}
- Tooltip.VERSION = '3.3.5'
+ Tooltip.VERSION = '3.3.6'
Tooltip.TRANSITION_DURATION = 150
diff --git a/core/vendor/davclient.js/LICENSE b/core/vendor/davclient.js/LICENSE
new file mode 100644
index 00000000000..fd7293e8f32
--- /dev/null
+++ b/core/vendor/davclient.js/LICENSE
@@ -0,0 +1,27 @@
+Copyright (C) 2013-2014 fruux GmbH (https://fruux.com/)
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name Sabre nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
diff --git a/core/vendor/davclient.js/lib/client.js b/core/vendor/davclient.js/lib/client.js
new file mode 100644
index 00000000000..89c11516a38
--- /dev/null
+++ b/core/vendor/davclient.js/lib/client.js
@@ -0,0 +1,389 @@
+if (typeof dav == 'undefined') { dav = {}; };
+
+dav._XML_CHAR_MAP = {
+ '<': '&lt;',
+ '>': '&gt;',
+ '&': '&amp;',
+ '"': '&quot;',
+ "'": '&apos;'
+};
+
+dav._escapeXml = function(s) {
+ return s.replace(/[<>&"']/g, function (ch) {
+ return dav._XML_CHAR_MAP[ch];
+ });
+};
+
+dav.Client = function(options) {
+ var i;
+ for(i in options) {
+ this[i] = options[i];
+ }
+
+};
+
+dav.Client.prototype = {
+
+ baseUrl : null,
+
+ userName : null,
+
+ password : null,
+
+
+ xmlNamespaces : {
+ 'DAV:' : 'd'
+ },
+
+ /**
+ * Generates a propFind request.
+ *
+ * @param {string} url Url to do the propfind request on
+ * @param {Array} properties List of properties to retrieve.
+ * @return {Promise}
+ */
+ propFind : function(url, properties, depth) {
+
+ if(typeof depth == "undefined") {
+ depth = 0;
+ }
+
+ var headers = {
+ Depth : depth,
+ 'Content-Type' : 'application/xml; charset=utf-8'
+ };
+
+ var body =
+ '<?xml version="1.0"?>\n' +
+ '<d:propfind ';
+ var namespace;
+ for (namespace in this.xmlNamespaces) {
+ body += ' xmlns:' + this.xmlNamespaces[namespace] + '="' + namespace + '"';
+ }
+ body += '>\n' +
+ ' <d:prop>\n';
+
+ for(var ii in properties) {
+
+ var property = this.parseClarkNotation(properties[ii]);
+ if (this.xmlNamespaces[property.namespace]) {
+ body+=' <' + this.xmlNamespaces[property.namespace] + ':' + property.name + ' />\n';
+ } else {
+ body+=' <x:' + property.name + ' xmlns:x="' + property.namespace + '" />\n';
+ }
+
+ }
+ body+=' </d:prop>\n';
+ body+='</d:propfind>';
+
+ return this.request('PROPFIND', url, headers, body).then(
+ function(result) {
+
+ if (depth===0) {
+ return {
+ status: result.status,
+ body: result.body[0],
+ xhr: result.xhr
+ };
+ } else {
+ return {
+ status: result.status,
+ body: result.body,
+ xhr: result.xhr
+ };
+ }
+
+ }.bind(this)
+ );
+
+ },
+
+ /**
+ * Generates a propPatch request.
+ *
+ * @param {string} url Url to do the proppatch request on
+ * @param {Array} properties List of properties to store.
+ * @return {Promise}
+ */
+ propPatch : function(url, properties, headers) {
+ headers = headers || {};
+
+ headers['Content-Type'] = 'application/xml; charset=utf-8';
+
+ var body =
+ '<?xml version="1.0"?>\n' +
+ '<d:propertyupdate ';
+ var namespace;
+ for (namespace in this.xmlNamespaces) {
+ body += ' xmlns:' + this.xmlNamespaces[namespace] + '="' + namespace + '"';
+ }
+ body += '>\n' +
+ ' <d:set>\n' +
+ ' <d:prop>\n';
+
+ for(var ii in properties) {
+
+ var property = this.parseClarkNotation(ii);
+ var propName;
+ var propValue = properties[ii];
+ if (this.xmlNamespaces[property.namespace]) {
+ propName = this.xmlNamespaces[property.namespace] + ':' + property.name;
+ } else {
+ propName = 'x:' + property.name + ' xmlns:x="' + property.namespace + '"';
+ }
+ body += ' <' + propName + '>' + dav._escapeXml(propValue) + '</' + propName + '>\n';
+ }
+ body+=' </d:prop>\n';
+ body+=' </d:set>\n';
+ body+='</d:propertyupdate>';
+
+ return this.request('PROPPATCH', url, headers, body).then(
+ function(result) {
+ return {
+ status: result.status,
+ body: result.body,
+ xhr: result.xhr
+ };
+ }.bind(this)
+ );
+
+ },
+
+ /**
+ * Performs a HTTP request, and returns a Promise
+ *
+ * @param {string} method HTTP method
+ * @param {string} url Relative or absolute url
+ * @param {Object} headers HTTP headers as an object.
+ * @param {string} body HTTP request body.
+ * @return {Promise}
+ */
+ request : function(method, url, headers, body) {
+
+ var self = this;
+ var xhr = this.xhrProvider();
+
+ if (this.userName) {
+ headers['Authorization'] = 'Basic ' + btoa(this.userName + ':' + this.password);
+ // xhr.open(method, this.resolveUrl(url), true, this.userName, this.password);
+ }
+ xhr.open(method, this.resolveUrl(url), true);
+ var ii;
+ for(ii in headers) {
+ xhr.setRequestHeader(ii, headers[ii]);
+ }
+ xhr.send(body);
+
+ return new Promise(function(fulfill, reject) {
+
+ xhr.onreadystatechange = function() {
+
+ if (xhr.readyState !== 4) {
+ return;
+ }
+
+ var resultBody = xhr.response;
+ if (xhr.status === 207) {
+ resultBody = self.parseMultiStatus(xhr.response);
+ }
+
+ fulfill({
+ body: resultBody,
+ status: xhr.status,
+ xhr: xhr
+ });
+
+ };
+
+ xhr.ontimeout = function() {
+
+ reject(new Error('Timeout exceeded'));
+
+ };
+
+ });
+
+ },
+
+ /**
+ * Returns an XMLHttpRequest object.
+ *
+ * This is in its own method, so it can be easily overridden.
+ *
+ * @return {XMLHttpRequest}
+ */
+ xhrProvider : function() {
+
+ return new XMLHttpRequest();
+
+ },
+
+ /**
+ * Parses a property node.
+ *
+ * Either returns a string if the node only contains text, or returns an
+ * array of non-text subnodes.
+ *
+ * @param {Object} propNode node to parse
+ * @return {string|Array} text content as string or array of subnodes, excluding text nodes
+ */
+ _parsePropNode: function(propNode) {
+ var content = null;
+ if (propNode.childNodes && propNode.childNodes.length > 0) {
+ var subNodes = [];
+ // filter out text nodes
+ for (var j = 0; j < propNode.childNodes.length; j++) {
+ var node = propNode.childNodes[j];
+ if (node.nodeType === 1) {
+ subNodes.push(node);
+ }
+ }
+ if (subNodes.length) {
+ content = subNodes;
+ }
+ }
+
+ return content || propNode.textContent || propNode.text || '';
+ },
+
+ /**
+ * Parses a multi-status response body.
+ *
+ * @param {string} xmlBody
+ * @param {Array}
+ */
+ parseMultiStatus : function(xmlBody) {
+
+ var parser = new DOMParser();
+ var doc = parser.parseFromString(xmlBody, "application/xml");
+
+ var resolver = function(foo) {
+ var ii;
+ for(ii in this.xmlNamespaces) {
+ if (this.xmlNamespaces[ii] === foo) {
+ return ii;
+ }
+ }
+ }.bind(this);
+
+ var responseIterator = doc.evaluate('/d:multistatus/d:response', doc, resolver, XPathResult.ANY_TYPE, null);
+
+ var result = [];
+ var responseNode = responseIterator.iterateNext();
+
+ while(responseNode) {
+
+ var response = {
+ href : null,
+ propStat : []
+ };
+
+ response.href = doc.evaluate('string(d:href)', responseNode, resolver, XPathResult.ANY_TYPE, null).stringValue;
+
+ var propStatIterator = doc.evaluate('d:propstat', responseNode, resolver, XPathResult.ANY_TYPE, null);
+ var propStatNode = propStatIterator.iterateNext();
+
+ while(propStatNode) {
+
+ var propStat = {
+ status : doc.evaluate('string(d:status)', propStatNode, resolver, XPathResult.ANY_TYPE, null).stringValue,
+ properties : [],
+ };
+
+ var propIterator = doc.evaluate('d:prop/*', propStatNode, resolver, XPathResult.ANY_TYPE, null);
+
+ var propNode = propIterator.iterateNext();
+ while(propNode) {
+ var content = this._parsePropNode(propNode);
+ propStat.properties['{' + propNode.namespaceURI + '}' + propNode.localName] = content;
+ propNode = propIterator.iterateNext();
+
+ }
+ response.propStat.push(propStat);
+ propStatNode = propStatIterator.iterateNext();
+
+
+ }
+
+ result.push(response);
+ responseNode = responseIterator.iterateNext();
+
+ }
+
+ return result;
+
+ },
+
+ /**
+ * Takes a relative url, and maps it to an absolute url, using the baseUrl
+ *
+ * @param {string} url
+ * @return {string}
+ */
+ resolveUrl : function(url) {
+
+ // Note: this is rudamentary.. not sure yet if it handles every case.
+ if (/^https?:\/\//i.test(url)) {
+ // absolute
+ return url;
+ }
+
+ var baseParts = this.parseUrl(this.baseUrl);
+ if (url.charAt('/')) {
+ // Url starts with a slash
+ return baseParts.root + url;
+ }
+
+ // Url does not start with a slash, we need grab the base url right up until the last slash.
+ var newUrl = baseParts.root + '/';
+ if (baseParts.path.lastIndexOf('/')!==-1) {
+ newUrl = newUrl = baseParts.path.subString(0, baseParts.path.lastIndexOf('/')) + '/';
+ }
+ newUrl+=url;
+ return url;
+
+ },
+
+ /**
+ * Parses a url and returns its individual components.
+ *
+ * @param {String} url
+ * @return {Object}
+ */
+ parseUrl : function(url) {
+
+ var parts = url.match(/^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/);
+ var result = {
+ url : parts[0],
+ scheme : parts[1],
+ host : parts[3],
+ port : parts[4],
+ path : parts[5],
+ query : parts[6],
+ fragment : parts[7],
+ };
+ result.root =
+ result.scheme + '://' +
+ result.host +
+ (result.port ? ':' + result.port : '');
+
+ return result;
+
+ },
+
+ parseClarkNotation : function(propertyName) {
+
+ var result = propertyName.match(/^{([^}]+)}(.*)$/);
+ if (!result) {
+ return;
+ }
+
+ return {
+ name : result[2],
+ namespace : result[1]
+ };
+
+ }
+
+};
+
diff --git a/core/vendor/es6-promise/.bower.json b/core/vendor/es6-promise/.bower.json
new file mode 100644
index 00000000000..f8c28b04e53
--- /dev/null
+++ b/core/vendor/es6-promise/.bower.json
@@ -0,0 +1,40 @@
+{
+ "name": "es6-promise",
+ "namespace": "Promise",
+ "version": "2.3.0",
+ "description": "A polyfill for ES6-style Promises, tracking rsvp",
+ "authors": [
+ "Stefan Penner <stefan.penner@gmail.com>"
+ ],
+ "main": "dist/es6-promise.js",
+ "keywords": [
+ "promise"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/jakearchibald/ES6-Promises.git"
+ },
+ "bugs": {
+ "url": "https://github.com/jakearchibald/ES6-Promises/issues"
+ },
+ "license": "MIT",
+ "ignore": [
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests",
+ "vendor",
+ "tasks"
+ ],
+ "homepage": "https://github.com/jakearchibald/es6-promise",
+ "_release": "2.3.0",
+ "_resolution": {
+ "type": "version",
+ "tag": "2.3.0",
+ "commit": "fcbab11a1a981eb2290bfff89017cb764335a2a5"
+ },
+ "_source": "https://github.com/jakearchibald/es6-promise.git",
+ "_target": "~2.3.0",
+ "_originalSource": "https://github.com/jakearchibald/es6-promise.git",
+ "_direct": true
+} \ No newline at end of file
diff --git a/core/vendor/es6-promise/.npmignore b/core/vendor/es6-promise/.npmignore
new file mode 100644
index 00000000000..7a758111e9e
--- /dev/null
+++ b/core/vendor/es6-promise/.npmignore
@@ -0,0 +1,11 @@
+/node_modules/
+/tmp
+/tasks
+/test
+/vendor
+/.jshintrc
+/.npmignore
+/.travis.yml
+/Gruntfile.js
+/component.json
+/index.html
diff --git a/core/vendor/es6-promise/.release.json b/core/vendor/es6-promise/.release.json
new file mode 100644
index 00000000000..dee8cbc5d92
--- /dev/null
+++ b/core/vendor/es6-promise/.release.json
@@ -0,0 +1,17 @@
+{
+ "non-interactive": true,
+ "dry-run": false,
+ "verbose": false,
+ "force": false,
+ "pkgFiles": ["package.json", "bower.json"],
+ "increment": "patch",
+ "commitMessage": "Release %s",
+ "tagName": "%s",
+ "tagAnnotation": "Release %s",
+ "buildCommand": "npm run-script build-all",
+ "distRepo": "git@github.com:components/rsvp.js.git",
+ "distStageDir": "tmp/stage",
+ "distBase": "dist",
+ "distFiles": ["**/*", "../package.json", "../bower.json"],
+ "publish": false
+}
diff --git a/core/vendor/es6-promise/.spmignore b/core/vendor/es6-promise/.spmignore
new file mode 100644
index 00000000000..7a758111e9e
--- /dev/null
+++ b/core/vendor/es6-promise/.spmignore
@@ -0,0 +1,11 @@
+/node_modules/
+/tmp
+/tasks
+/test
+/vendor
+/.jshintrc
+/.npmignore
+/.travis.yml
+/Gruntfile.js
+/component.json
+/index.html
diff --git a/core/vendor/es6-promise/LICENSE b/core/vendor/es6-promise/LICENSE
new file mode 100644
index 00000000000..954ec5992df
--- /dev/null
+++ b/core/vendor/es6-promise/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/core/vendor/es6-promise/dist/es6-promise.js b/core/vendor/es6-promise/dist/es6-promise.js
new file mode 100644
index 00000000000..aff0482ee5e
--- /dev/null
+++ b/core/vendor/es6-promise/dist/es6-promise.js
@@ -0,0 +1,972 @@
+/*!
+ * @overview es6-promise - a tiny implementation of Promises/A+.
+ * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
+ * @license Licensed under MIT license
+ * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
+ * @version 2.3.0
+ */
+
+(function() {
+ "use strict";
+ function lib$es6$promise$utils$$objectOrFunction(x) {
+ return typeof x === 'function' || (typeof x === 'object' && x !== null);
+ }
+
+ function lib$es6$promise$utils$$isFunction(x) {
+ return typeof x === 'function';
+ }
+
+ function lib$es6$promise$utils$$isMaybeThenable(x) {
+ return typeof x === 'object' && x !== null;
+ }
+
+ var lib$es6$promise$utils$$_isArray;
+ if (!Array.isArray) {
+ lib$es6$promise$utils$$_isArray = function (x) {
+ return Object.prototype.toString.call(x) === '[object Array]';
+ };
+ } else {
+ lib$es6$promise$utils$$_isArray = Array.isArray;
+ }
+
+ var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray;
+ var lib$es6$promise$asap$$len = 0;
+ var lib$es6$promise$asap$$toString = {}.toString;
+ var lib$es6$promise$asap$$vertxNext;
+ var lib$es6$promise$asap$$customSchedulerFn;
+
+ var lib$es6$promise$asap$$asap = function asap(callback, arg) {
+ lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback;
+ lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg;
+ lib$es6$promise$asap$$len += 2;
+ if (lib$es6$promise$asap$$len === 2) {
+ // If len is 2, that means that we need to schedule an async flush.
+ // If additional callbacks are queued before the queue is flushed, they
+ // will be processed by this flush that we are scheduling.
+ if (lib$es6$promise$asap$$customSchedulerFn) {
+ lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush);
+ } else {
+ lib$es6$promise$asap$$scheduleFlush();
+ }
+ }
+ }
+
+ function lib$es6$promise$asap$$setScheduler(scheduleFn) {
+ lib$es6$promise$asap$$customSchedulerFn = scheduleFn;
+ }
+
+ function lib$es6$promise$asap$$setAsap(asapFn) {
+ lib$es6$promise$asap$$asap = asapFn;
+ }
+
+ var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined;
+ var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {};
+ var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver;
+ var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
+
+ // test for web worker but not in IE10
+ var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
+ typeof importScripts !== 'undefined' &&
+ typeof MessageChannel !== 'undefined';
+
+ // node
+ function lib$es6$promise$asap$$useNextTick() {
+ var nextTick = process.nextTick;
+ // node version 0.10.x displays a deprecation warning when nextTick is used recursively
+ // setImmediate should be used instead instead
+ var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/);
+ if (Array.isArray(version) && version[1] === '0' && version[2] === '10') {
+ nextTick = setImmediate;
+ }
+ return function() {
+ nextTick(lib$es6$promise$asap$$flush);
+ };
+ }
+
+ // vertx
+ function lib$es6$promise$asap$$useVertxTimer() {
+ return function() {
+ lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush);
+ };
+ }
+
+ function lib$es6$promise$asap$$useMutationObserver() {
+ var iterations = 0;
+ var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush);
+ var node = document.createTextNode('');
+ observer.observe(node, { characterData: true });
+
+ return function() {
+ node.data = (iterations = ++iterations % 2);
+ };
+ }
+
+ // web worker
+ function lib$es6$promise$asap$$useMessageChannel() {
+ var channel = new MessageChannel();
+ channel.port1.onmessage = lib$es6$promise$asap$$flush;
+ return function () {
+ channel.port2.postMessage(0);
+ };
+ }
+
+ function lib$es6$promise$asap$$useSetTimeout() {
+ return function() {
+ setTimeout(lib$es6$promise$asap$$flush, 1);
+ };
+ }
+
+ var lib$es6$promise$asap$$queue = new Array(1000);
+ function lib$es6$promise$asap$$flush() {
+ for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) {
+ var callback = lib$es6$promise$asap$$queue[i];
+ var arg = lib$es6$promise$asap$$queue[i+1];
+
+ callback(arg);
+
+ lib$es6$promise$asap$$queue[i] = undefined;
+ lib$es6$promise$asap$$queue[i+1] = undefined;
+ }
+
+ lib$es6$promise$asap$$len = 0;
+ }
+
+ function lib$es6$promise$asap$$attemptVertex() {
+ try {
+ var r = require;
+ var vertx = r('vertx');
+ lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext;
+ return lib$es6$promise$asap$$useVertxTimer();
+ } catch(e) {
+ return lib$es6$promise$asap$$useSetTimeout();
+ }
+ }
+
+ var lib$es6$promise$asap$$scheduleFlush;
+ // Decide what async method to use to triggering processing of queued callbacks:
+ if (lib$es6$promise$asap$$isNode) {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick();
+ } else if (lib$es6$promise$asap$$BrowserMutationObserver) {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver();
+ } else if (lib$es6$promise$asap$$isWorker) {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel();
+ } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertex();
+ } else {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout();
+ }
+
+ function lib$es6$promise$$internal$$noop() {}
+
+ var lib$es6$promise$$internal$$PENDING = void 0;
+ var lib$es6$promise$$internal$$FULFILLED = 1;
+ var lib$es6$promise$$internal$$REJECTED = 2;
+
+ var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject();
+
+ function lib$es6$promise$$internal$$selfFullfillment() {
+ return new TypeError("You cannot resolve a promise with itself");
+ }
+
+ function lib$es6$promise$$internal$$cannotReturnOwn() {
+ return new TypeError('A promises callback cannot return that same promise.');
+ }
+
+ function lib$es6$promise$$internal$$getThen(promise) {
+ try {
+ return promise.then;
+ } catch(error) {
+ lib$es6$promise$$internal$$GET_THEN_ERROR.error = error;
+ return lib$es6$promise$$internal$$GET_THEN_ERROR;
+ }
+ }
+
+ function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
+ try {
+ then.call(value, fulfillmentHandler, rejectionHandler);
+ } catch(e) {
+ return e;
+ }
+ }
+
+ function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) {
+ lib$es6$promise$asap$$asap(function(promise) {
+ var sealed = false;
+ var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) {
+ if (sealed) { return; }
+ sealed = true;
+ if (thenable !== value) {
+ lib$es6$promise$$internal$$resolve(promise, value);
+ } else {
+ lib$es6$promise$$internal$$fulfill(promise, value);
+ }
+ }, function(reason) {
+ if (sealed) { return; }
+ sealed = true;
+
+ lib$es6$promise$$internal$$reject(promise, reason);
+ }, 'Settle: ' + (promise._label || ' unknown promise'));
+
+ if (!sealed && error) {
+ sealed = true;
+ lib$es6$promise$$internal$$reject(promise, error);
+ }
+ }, promise);
+ }
+
+ function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) {
+ if (thenable._state === lib$es6$promise$$internal$$FULFILLED) {
+ lib$es6$promise$$internal$$fulfill(promise, thenable._result);
+ } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) {
+ lib$es6$promise$$internal$$reject(promise, thenable._result);
+ } else {
+ lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) {
+ lib$es6$promise$$internal$$resolve(promise, value);
+ }, function(reason) {
+ lib$es6$promise$$internal$$reject(promise, reason);
+ });
+ }
+ }
+
+ function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) {
+ if (maybeThenable.constructor === promise.constructor) {
+ lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable);
+ } else {
+ var then = lib$es6$promise$$internal$$getThen(maybeThenable);
+
+ if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) {
+ lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error);
+ } else if (then === undefined) {
+ lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
+ } else if (lib$es6$promise$utils$$isFunction(then)) {
+ lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then);
+ } else {
+ lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
+ }
+ }
+ }
+
+ function lib$es6$promise$$internal$$resolve(promise, value) {
+ if (promise === value) {
+ lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFullfillment());
+ } else if (lib$es6$promise$utils$$objectOrFunction(value)) {
+ lib$es6$promise$$internal$$handleMaybeThenable(promise, value);
+ } else {
+ lib$es6$promise$$internal$$fulfill(promise, value);
+ }
+ }
+
+ function lib$es6$promise$$internal$$publishRejection(promise) {
+ if (promise._onerror) {
+ promise._onerror(promise._result);
+ }
+
+ lib$es6$promise$$internal$$publish(promise);
+ }
+
+ function lib$es6$promise$$internal$$fulfill(promise, value) {
+ if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }
+
+ promise._result = value;
+ promise._state = lib$es6$promise$$internal$$FULFILLED;
+
+ if (promise._subscribers.length !== 0) {
+ lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, promise);
+ }
+ }
+
+ function lib$es6$promise$$internal$$reject(promise, reason) {
+ if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }
+ promise._state = lib$es6$promise$$internal$$REJECTED;
+ promise._result = reason;
+
+ lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection, promise);
+ }
+
+ function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
+ var subscribers = parent._subscribers;
+ var length = subscribers.length;
+
+ parent._onerror = null;
+
+ subscribers[length] = child;
+ subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment;
+ subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection;
+
+ if (length === 0 && parent._state) {
+ lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, parent);
+ }
+ }
+
+ function lib$es6$promise$$internal$$publish(promise) {
+ var subscribers = promise._subscribers;
+ var settled = promise._state;
+
+ if (subscribers.length === 0) { return; }
+
+ var child, callback, detail = promise._result;
+
+ for (var i = 0; i < subscribers.length; i += 3) {
+ child = subscribers[i];
+ callback = subscribers[i + settled];
+
+ if (child) {
+ lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail);
+ } else {
+ callback(detail);
+ }
+ }
+
+ promise._subscribers.length = 0;
+ }
+
+ function lib$es6$promise$$internal$$ErrorObject() {
+ this.error = null;
+ }
+
+ var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject();
+
+ function lib$es6$promise$$internal$$tryCatch(callback, detail) {
+ try {
+ return callback(detail);
+ } catch(e) {
+ lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e;
+ return lib$es6$promise$$internal$$TRY_CATCH_ERROR;
+ }
+ }
+
+ function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) {
+ var hasCallback = lib$es6$promise$utils$$isFunction(callback),
+ value, error, succeeded, failed;
+
+ if (hasCallback) {
+ value = lib$es6$promise$$internal$$tryCatch(callback, detail);
+
+ if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) {
+ failed = true;
+ error = value.error;
+ value = null;
+ } else {
+ succeeded = true;
+ }
+
+ if (promise === value) {
+ lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn());
+ return;
+ }
+
+ } else {
+ value = detail;
+ succeeded = true;
+ }
+
+ if (promise._state !== lib$es6$promise$$internal$$PENDING) {
+ // noop
+ } else if (hasCallback && succeeded) {
+ lib$es6$promise$$internal$$resolve(promise, value);
+ } else if (failed) {
+ lib$es6$promise$$internal$$reject(promise, error);
+ } else if (settled === lib$es6$promise$$internal$$FULFILLED) {
+ lib$es6$promise$$internal$$fulfill(promise, value);
+ } else if (settled === lib$es6$promise$$internal$$REJECTED) {
+ lib$es6$promise$$internal$$reject(promise, value);
+ }
+ }
+
+ function lib$es6$promise$$internal$$initializePromise(promise, resolver) {
+ try {
+ resolver(function resolvePromise(value){
+ lib$es6$promise$$internal$$resolve(promise, value);
+ }, function rejectPromise(reason) {
+ lib$es6$promise$$internal$$reject(promise, reason);
+ });
+ } catch(e) {
+ lib$es6$promise$$internal$$reject(promise, e);
+ }
+ }
+
+ function lib$es6$promise$enumerator$$Enumerator(Constructor, input) {
+ var enumerator = this;
+
+ enumerator._instanceConstructor = Constructor;
+ enumerator.promise = new Constructor(lib$es6$promise$$internal$$noop);
+
+ if (enumerator._validateInput(input)) {
+ enumerator._input = input;
+ enumerator.length = input.length;
+ enumerator._remaining = input.length;
+
+ enumerator._init();
+
+ if (enumerator.length === 0) {
+ lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result);
+ } else {
+ enumerator.length = enumerator.length || 0;
+ enumerator._enumerate();
+ if (enumerator._remaining === 0) {
+ lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result);
+ }
+ }
+ } else {
+ lib$es6$promise$$internal$$reject(enumerator.promise, enumerator._validationError());
+ }
+ }
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function(input) {
+ return lib$es6$promise$utils$$isArray(input);
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function() {
+ return new Error('Array Methods must be provided an Array');
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._init = function() {
+ this._result = new Array(this.length);
+ };
+
+ var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator;
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() {
+ var enumerator = this;
+
+ var length = enumerator.length;
+ var promise = enumerator.promise;
+ var input = enumerator._input;
+
+ for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) {
+ enumerator._eachEntry(input[i], i);
+ }
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
+ var enumerator = this;
+ var c = enumerator._instanceConstructor;
+
+ if (lib$es6$promise$utils$$isMaybeThenable(entry)) {
+ if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) {
+ entry._onerror = null;
+ enumerator._settledAt(entry._state, i, entry._result);
+ } else {
+ enumerator._willSettleAt(c.resolve(entry), i);
+ }
+ } else {
+ enumerator._remaining--;
+ enumerator._result[i] = entry;
+ }
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
+ var enumerator = this;
+ var promise = enumerator.promise;
+
+ if (promise._state === lib$es6$promise$$internal$$PENDING) {
+ enumerator._remaining--;
+
+ if (state === lib$es6$promise$$internal$$REJECTED) {
+ lib$es6$promise$$internal$$reject(promise, value);
+ } else {
+ enumerator._result[i] = value;
+ }
+ }
+
+ if (enumerator._remaining === 0) {
+ lib$es6$promise$$internal$$fulfill(promise, enumerator._result);
+ }
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
+ var enumerator = this;
+
+ lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) {
+ enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value);
+ }, function(reason) {
+ enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason);
+ });
+ };
+ function lib$es6$promise$promise$all$$all(entries) {
+ return new lib$es6$promise$enumerator$$default(this, entries).promise;
+ }
+ var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all;
+ function lib$es6$promise$promise$race$$race(entries) {
+ /*jshint validthis:true */
+ var Constructor = this;
+
+ var promise = new Constructor(lib$es6$promise$$internal$$noop);
+
+ if (!lib$es6$promise$utils$$isArray(entries)) {
+ lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.'));
+ return promise;
+ }
+
+ var length = entries.length;
+
+ function onFulfillment(value) {
+ lib$es6$promise$$internal$$resolve(promise, value);
+ }
+
+ function onRejection(reason) {
+ lib$es6$promise$$internal$$reject(promise, reason);
+ }
+
+ for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) {
+ lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection);
+ }
+
+ return promise;
+ }
+ var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race;
+ function lib$es6$promise$promise$resolve$$resolve(object) {
+ /*jshint validthis:true */
+ var Constructor = this;
+
+ if (object && typeof object === 'object' && object.constructor === Constructor) {
+ return object;
+ }
+
+ var promise = new Constructor(lib$es6$promise$$internal$$noop);
+ lib$es6$promise$$internal$$resolve(promise, object);
+ return promise;
+ }
+ var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve;
+ function lib$es6$promise$promise$reject$$reject(reason) {
+ /*jshint validthis:true */
+ var Constructor = this;
+ var promise = new Constructor(lib$es6$promise$$internal$$noop);
+ lib$es6$promise$$internal$$reject(promise, reason);
+ return promise;
+ }
+ var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject;
+
+ var lib$es6$promise$promise$$counter = 0;
+
+ function lib$es6$promise$promise$$needsResolver() {
+ throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
+ }
+
+ function lib$es6$promise$promise$$needsNew() {
+ throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
+ }
+
+ var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise;
+ /**
+ Promise objects represent the eventual result of an asynchronous operation. The
+ primary way of interacting with a promise is through its `then` method, which
+ registers callbacks to receive either a promise's eventual value or the reason
+ why the promise cannot be fulfilled.
+
+ Terminology
+ -----------
+
+ - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
+ - `thenable` is an object or function that defines a `then` method.
+ - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
+ - `exception` is a value that is thrown using the throw statement.
+ - `reason` is a value that indicates why a promise was rejected.
+ - `settled` the final resting state of a promise, fulfilled or rejected.
+
+ A promise can be in one of three states: pending, fulfilled, or rejected.
+
+ Promises that are fulfilled have a fulfillment value and are in the fulfilled
+ state. Promises that are rejected have a rejection reason and are in the
+ rejected state. A fulfillment value is never a thenable.
+
+ Promises can also be said to *resolve* a value. If this value is also a
+ promise, then the original promise's settled state will match the value's
+ settled state. So a promise that *resolves* a promise that rejects will
+ itself reject, and a promise that *resolves* a promise that fulfills will
+ itself fulfill.
+
+
+ Basic Usage:
+ ------------
+
+ ```js
+ var promise = new Promise(function(resolve, reject) {
+ // on success
+ resolve(value);
+
+ // on failure
+ reject(reason);
+ });
+
+ promise.then(function(value) {
+ // on fulfillment
+ }, function(reason) {
+ // on rejection
+ });
+ ```
+
+ Advanced Usage:
+ ---------------
+
+ Promises shine when abstracting away asynchronous interactions such as
+ `XMLHttpRequest`s.
+
+ ```js
+ function getJSON(url) {
+ return new Promise(function(resolve, reject){
+ var xhr = new XMLHttpRequest();
+
+ xhr.open('GET', url);
+ xhr.onreadystatechange = handler;
+ xhr.responseType = 'json';
+ xhr.setRequestHeader('Accept', 'application/json');
+ xhr.send();
+
+ function handler() {
+ if (this.readyState === this.DONE) {
+ if (this.status === 200) {
+ resolve(this.response);
+ } else {
+ reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
+ }
+ }
+ };
+ });
+ }
+
+ getJSON('/posts.json').then(function(json) {
+ // on fulfillment
+ }, function(reason) {
+ // on rejection
+ });
+ ```
+
+ Unlike callbacks, promises are great composable primitives.
+
+ ```js
+ Promise.all([
+ getJSON('/posts'),
+ getJSON('/comments')
+ ]).then(function(values){
+ values[0] // => postsJSON
+ values[1] // => commentsJSON
+
+ return values;
+ });
+ ```
+
+ @class Promise
+ @param {function} resolver
+ Useful for tooling.
+ @constructor
+ */
+ function lib$es6$promise$promise$$Promise(resolver) {
+ this._id = lib$es6$promise$promise$$counter++;
+ this._state = undefined;
+ this._result = undefined;
+ this._subscribers = [];
+
+ if (lib$es6$promise$$internal$$noop !== resolver) {
+ if (!lib$es6$promise$utils$$isFunction(resolver)) {
+ lib$es6$promise$promise$$needsResolver();
+ }
+
+ if (!(this instanceof lib$es6$promise$promise$$Promise)) {
+ lib$es6$promise$promise$$needsNew();
+ }
+
+ lib$es6$promise$$internal$$initializePromise(this, resolver);
+ }
+ }
+
+ lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default;
+ lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default;
+ lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default;
+ lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default;
+ lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler;
+ lib$es6$promise$promise$$Promise._setAsap = lib$es6$promise$asap$$setAsap;
+ lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$asap;
+
+ lib$es6$promise$promise$$Promise.prototype = {
+ constructor: lib$es6$promise$promise$$Promise,
+
+ /**
+ The primary way of interacting with a promise is through its `then` method,
+ which registers callbacks to receive either a promise's eventual value or the
+ reason why the promise cannot be fulfilled.
+
+ ```js
+ findUser().then(function(user){
+ // user is available
+ }, function(reason){
+ // user is unavailable, and you are given the reason why
+ });
+ ```
+
+ Chaining
+ --------
+
+ The return value of `then` is itself a promise. This second, 'downstream'
+ promise is resolved with the return value of the first promise's fulfillment
+ or rejection handler, or rejected if the handler throws an exception.
+
+ ```js
+ findUser().then(function (user) {
+ return user.name;
+ }, function (reason) {
+ return 'default name';
+ }).then(function (userName) {
+ // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
+ // will be `'default name'`
+ });
+
+ findUser().then(function (user) {
+ throw new Error('Found user, but still unhappy');
+ }, function (reason) {
+ throw new Error('`findUser` rejected and we're unhappy');
+ }).then(function (value) {
+ // never reached
+ }, function (reason) {
+ // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
+ // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
+ });
+ ```
+ If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
+
+ ```js
+ findUser().then(function (user) {
+ throw new PedagogicalException('Upstream error');
+ }).then(function (value) {
+ // never reached
+ }).then(function (value) {
+ // never reached
+ }, function (reason) {
+ // The `PedgagocialException` is propagated all the way down to here
+ });
+ ```
+
+ Assimilation
+ ------------
+
+ Sometimes the value you want to propagate to a downstream promise can only be
+ retrieved asynchronously. This can be achieved by returning a promise in the
+ fulfillment or rejection handler. The downstream promise will then be pending
+ until the returned promise is settled. This is called *assimilation*.
+
+ ```js
+ findUser().then(function (user) {
+ return findCommentsByAuthor(user);
+ }).then(function (comments) {
+ // The user's comments are now available
+ });
+ ```
+
+ If the assimliated promise rejects, then the downstream promise will also reject.
+
+ ```js
+ findUser().then(function (user) {
+ return findCommentsByAuthor(user);
+ }).then(function (comments) {
+ // If `findCommentsByAuthor` fulfills, we'll have the value here
+ }, function (reason) {
+ // If `findCommentsByAuthor` rejects, we'll have the reason here
+ });
+ ```
+
+ Simple Example
+ --------------
+
+ Synchronous Example
+
+ ```javascript
+ var result;
+
+ try {
+ result = findResult();
+ // success
+ } catch(reason) {
+ // failure
+ }
+ ```
+
+ Errback Example
+
+ ```js
+ findResult(function(result, err){
+ if (err) {
+ // failure
+ } else {
+ // success
+ }
+ });
+ ```
+
+ Promise Example;
+
+ ```javascript
+ findResult().then(function(result){
+ // success
+ }, function(reason){
+ // failure
+ });
+ ```
+
+ Advanced Example
+ --------------
+
+ Synchronous Example
+
+ ```javascript
+ var author, books;
+
+ try {
+ author = findAuthor();
+ books = findBooksByAuthor(author);
+ // success
+ } catch(reason) {
+ // failure
+ }
+ ```
+
+ Errback Example
+
+ ```js
+
+ function foundBooks(books) {
+
+ }
+
+ function failure(reason) {
+
+ }
+
+ findAuthor(function(author, err){
+ if (err) {
+ failure(err);
+ // failure
+ } else {
+ try {
+ findBoooksByAuthor(author, function(books, err) {
+ if (err) {
+ failure(err);
+ } else {
+ try {
+ foundBooks(books);
+ } catch(reason) {
+ failure(reason);
+ }
+ }
+ });
+ } catch(error) {
+ failure(err);
+ }
+ // success
+ }
+ });
+ ```
+
+ Promise Example;
+
+ ```javascript
+ findAuthor().
+ then(findBooksByAuthor).
+ then(function(books){
+ // found books
+ }).catch(function(reason){
+ // something went wrong
+ });
+ ```
+
+ @method then
+ @param {Function} onFulfilled
+ @param {Function} onRejected
+ Useful for tooling.
+ @return {Promise}
+ */
+ then: function(onFulfillment, onRejection) {
+ var parent = this;
+ var state = parent._state;
+
+ if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) {
+ return this;
+ }
+
+ var child = new this.constructor(lib$es6$promise$$internal$$noop);
+ var result = parent._result;
+
+ if (state) {
+ var callback = arguments[state - 1];
+ lib$es6$promise$asap$$asap(function(){
+ lib$es6$promise$$internal$$invokeCallback(state, child, callback, result);
+ });
+ } else {
+ lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection);
+ }
+
+ return child;
+ },
+
+ /**
+ `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
+ as the catch block of a try/catch statement.
+
+ ```js
+ function findAuthor(){
+ throw new Error('couldn't find that author');
+ }
+
+ // synchronous
+ try {
+ findAuthor();
+ } catch(reason) {
+ // something went wrong
+ }
+
+ // async with promises
+ findAuthor().catch(function(reason){
+ // something went wrong
+ });
+ ```
+
+ @method catch
+ @param {Function} onRejection
+ Useful for tooling.
+ @return {Promise}
+ */
+ 'catch': function(onRejection) {
+ return this.then(null, onRejection);
+ }
+ };
+ function lib$es6$promise$polyfill$$polyfill() {
+ var local;
+
+ if (typeof global !== 'undefined') {
+ local = global;
+ } else if (typeof self !== 'undefined') {
+ local = self;
+ } else {
+ try {
+ local = Function('return this')();
+ } catch (e) {
+ throw new Error('polyfill failed because global object is unavailable in this environment');
+ }
+ }
+
+ var P = local.Promise;
+
+ if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) {
+ return;
+ }
+
+ local.Promise = lib$es6$promise$promise$$default;
+ }
+ var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill;
+
+ var lib$es6$promise$umd$$ES6Promise = {
+ 'Promise': lib$es6$promise$promise$$default,
+ 'polyfill': lib$es6$promise$polyfill$$default
+ };
+
+ /* global define:true module:true window: true */
+ if (typeof define === 'function' && define['amd']) {
+ define(function() { return lib$es6$promise$umd$$ES6Promise; });
+ } else if (typeof module !== 'undefined' && module['exports']) {
+ module['exports'] = lib$es6$promise$umd$$ES6Promise;
+ } else if (typeof this !== 'undefined') {
+ this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise;
+ }
+
+ lib$es6$promise$polyfill$$default();
+}).call(this);
+
diff --git a/cron.php b/cron.php
index 008a02b6d3e..73f233e1350 100644
--- a/cron.php
+++ b/cron.php
@@ -13,7 +13,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -130,11 +130,20 @@ try {
// Work
$jobList = \OC::$server->getJobList();
- $jobs = $jobList->getAll();
- foreach ($jobs as $job) {
+
+ $executedJobs = [];
+ while ($job = $jobList->getNext()) {
+ if (isset($executedJobs[$job->getId()])) {
+ break;
+ }
+
$logger->debug('Run job with ID ' . $job->getId(), ['app' => 'cron']);
$job->execute($jobList, $logger);
$logger->debug('Finished job with ID ' . $job->getId(), ['app' => 'cron']);
+
+ $jobList->setLastJob($job);
+ $executedJobs[$job->getId()] = true;
+ unset($job);
}
// unlock the file
diff --git a/db_structure.xml b/db_structure.xml
index 8135746233e..dbbfa8c7a4d 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -127,6 +127,93 @@
</table>
+ <!-- a list of all mounted storage per user, populated on filesystem setup -->
+ <table>
+
+ <name>*dbprefix*mounts</name>
+
+ <declaration>
+
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>storage_id</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ </field>
+
+ <!-- fileid of the root of the mount, foreign key: oc_filecache.fileid -->
+ <field>
+ <name>root_id</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ </field>
+
+ <field>
+ <name>user_id</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>mount_point</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>4000</length>
+ </field>
+
+ <index>
+ <name>mounts_user_index</name>
+ <unique>false</unique>
+ <field>
+ <name>user_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ <index>
+ <name>mounts_storage_index</name>
+ <unique>false</unique>
+ <field>
+ <name>storage_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ <index>
+ <name>mounts_root_index</name>
+ <unique>false</unique>
+ <field>
+ <name>root_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ <index>
+ <name>mounts_user_root_index</name>
+ <unique>true</unique>
+ <field>
+ <name>user_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>root_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ </declaration>
+
+ </table>
+
<table>
<!--
@@ -310,6 +397,14 @@
<length>4</length>
</field>
+ <field>
+ <name>checksum</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+
<index>
<name>fs_storage_path_hash</name>
@@ -684,6 +779,8 @@
</field>
<!-- Foreign Key users::uid -->
+ <!-- This is the owner of the share
+ which does not have to be the initiator of the share -->
<field>
<name>uid_owner</name>
<type>text</type>
@@ -692,6 +789,18 @@
<length>64</length>
</field>
+ <!-- Foreign Key users::uid -->
+ <!-- This is the initiator of the share -->
+ <field>
+ <name>uid_initiator</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>64</length>
+ </field>
+
+
+
<!-- Foreign Key share::id or NULL -->
<field>
<name>parent</name>
@@ -1064,6 +1173,130 @@
</table>
<table>
+ <!--
+ List of system-wide tags
+ -->
+ <name>*dbprefix*systemtag</name>
+
+ <declaration>
+
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <!-- Tag name -->
+ <field>
+ <name>name</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ <!-- Visibility: 0 user-not-visible, 1 user-visible -->
+ <field>
+ <name>visibility</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <length>1</length>
+ </field>
+
+ <!-- Editable: 0 user-not-editable, 1 user-editable -->
+ <field>
+ <name>editable</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <length>1</length>
+ </field>
+
+ <index>
+ <name>tag_ident</name>
+ <unique>true</unique>
+ <field>
+ <name>name</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>visibility</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>editable</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ </declaration>
+ </table>
+
+ <table>
+
+ <!--
+ System tag to object associations per object type.
+ -->
+ <name>*dbprefix*systemtag_object_mapping</name>
+
+ <declaration>
+
+ <!-- object id (ex: file id for files)-->
+ <field>
+ <name>objectid</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <!-- object type (ex: "files")-->
+ <field>
+ <name>objecttype</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ <!-- Foreign Key systemtag::id -->
+ <field>
+ <name>systemtagid</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <index>
+ <unique>true</unique>
+ <name>mapping</name>
+ <field>
+ <name>objecttype</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>objectid</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>systemtagid</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ </declaration>
+
+ </table>
+
+ <table>
<!--
Namespaced Key-Value Store for arbitrary data.
@@ -1204,5 +1437,254 @@
</table>
+ <table>
+ <!--
+ default place to store comment data
+ -->
+ <name>*dbprefix*comments</name>
+
+ <declaration>
+
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ <autoincrement>1</autoincrement>
+ </field>
+
+ <field>
+ <name>parent_id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>topmost_parent_id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>children_count</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
+ <field>
+ <name>actor_type</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>actor_id</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>message</name>
+ <type>clob</type>
+ <default></default>
+ <notnull>false</notnull>
+ </field>
+
+ <field>
+ <name>verb</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>creation_timestamp</name>
+ <type>timestamp</type>
+ <default></default>
+ <notnull>false</notnull>
+ </field>
+
+ <field>
+ <name>latest_child_timestamp</name>
+ <type>timestamp</type>
+ <default></default>
+ <notnull>false</notnull>
+ </field>
+
+ <field>
+ <name>object_type</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>object_id</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+<!--
+ TODO: finalize indexes when all queries are done
+ <index>
+ <name>comments_parent_id_index</name>
+ <unique>false</unique>
+ <field>
+ <name>parent_id</name>
+ <sorting>descending</sorting>
+ </field>
+ </index>
+
+ <index>
+ <name>comments_actor_index</name>
+ <unique>false</unique>
+ <field>
+ <name>actor_type</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>actor_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ <index>
+ <name>comments_object_index</name>
+ <unique>false</unique>
+ <field>
+ <name>object_type</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>object_id</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>creation_timestamp</name>
+ <sorting>descending</sorting>
+ </field>
+ </index>
+-->
+
+ </declaration>
+
+ </table>
+
+ <table>
+ <!--
+ default place to store per user and object read markers
+ -->
+ <name>*dbprefix*comments_read_markers</name>
+
+ <declaration>
+
+ <field>
+ <name>user_id</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>marker_datetime</name>
+ <type>timestamp</type>
+ <default></default>
+ <notnull>false</notnull>
+ </field>
+
+ <field>
+ <name>object_type</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>object_id</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ </declaration>
+
+ </table>
+
+ <table>
+ <!--
+ Encrypted credentials storage
+ -->
+ <name>*dbprefix*credentials</name>
+
+ <declaration>
+
+ <field>
+ <name>user</name>
+ <type>text</type>
+ <default></default>
+ <notnull>false</notnull>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>identifier</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+
+ <field>
+ <name>credentials</name>
+ <type>clob</type>
+ <notnull>false</notnull>
+ </field>
+
+ <index>
+ <name>credentials_user_id</name>
+ <primary>true</primary>
+ <unique>true</unique>
+ <field>
+ <name>user</name>
+ <sorting>ascending</sorting>
+ </field>
+ <field>
+ <name>identifier</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ <index>
+ <name>credentials_user</name>
+ <unique>false</unique>
+ <field>
+ <name>user</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ </declaration>
+
+ </table>
</database>
diff --git a/index.php b/index.php
index 5c376dcf285..f3bf699f3c1 100644
--- a/index.php
+++ b/index.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/issue_template.md b/issue_template.md
index 3859ea1c414..424f6c062a9 100644
--- a/issue_template.md
+++ b/issue_template.md
@@ -22,6 +22,14 @@ Tell us what happens instead
**Updated from an older ownCloud or fresh install:**
+**Signing status (ownCloud 9.0 and above):**
+
+```
+Login as admin user into your ownCloud and access
+http://example.com/index.php/settings/integrity/failed
+paste the results here.
+```
+
**List of activated apps:**
```
@@ -34,7 +42,7 @@ from within your ownCloud installation folder
```
If you have access to your command line run e.g.:
-sudo -u www-data php occ config:list system --public
+sudo -u www-data php occ config:list system
from within your ownCloud installation folder
or
@@ -52,16 +60,14 @@ Insert your config.php content here
#### LDAP configuration (delete this part if not used)
```
-On ownCloud 7+ with access to your command line run e.g.:
+With access to your command line run e.g.:
sudo -u www-data php occ ldap:show-config
from within your ownCloud installation folder
-On ownCloud 6 with access to your command line run e.g.:
-sqlite3 data/owncloud.db or mysql -u root -p owncloud
-then execute: select * from oc_appconfig where appid='user_ldap';
-
Without access to your command line download the data/owncloud.db to your local
-computer or access your SQL server remotely and run the select query above.
+computer or access your SQL server remotely and run the select query:
+SELECT * FROM `oc_appconfig` WHERE `appid` = 'user_ldap';
+
Eventually replace sensitive data as the name/IP-address of your LDAP server or groups.
```
diff --git a/lib/autoloader.php b/lib/autoloader.php
index f0fbd9e9f27..e7262af0ca9 100644
--- a/lib/autoloader.php
+++ b/lib/autoloader.php
@@ -6,11 +6,12 @@
* @author Markus Goetz <markus@woboq.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Victor Dubiniuk <dubiniuk@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -112,9 +113,6 @@ class Autoloader {
$paths[] = \OC::$SERVERROOT . '/core/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
} else if ($split[1] === 'settings') {
$paths[] = \OC::$SERVERROOT . '/settings/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
- } else if ($split[1] === 'repair') {
- $paths[] = \OC::$SERVERROOT . '/lib/repair/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
-
} else {
$paths[] = \OC::$SERVERROOT . '/lib/private/' . $split[1] . '/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
}
diff --git a/lib/base.php b/lib/base.php
index feaf46e83f1..fc4a99287d0 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -26,16 +26,16 @@
* @author Phil Davis <phil.davis@inf.org>
* @author Ramiro Aparicio <rapariciog@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author scolebrook <scolebrook@mac.com>
- * @author Stefan Herbrechtsmeier <stefan@herbrechtsmeier.net>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
* @author Volkan Gezer <volkangezer@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -113,6 +113,11 @@ class OC {
public static $server = null;
/**
+ * @var \OC\Config
+ */
+ private static $config = null;
+
+ /**
* @throws \RuntimeException when the 3rdparty directory is missing or
* the app path list is empty or contains an invalid path
*/
@@ -124,7 +129,7 @@ class OC {
} else {
self::$configDir = OC::$SERVERROOT . '/config/';
}
- OC_Config::$object = new \OC\Config(self::$configDir);
+ self::$config = new \OC\Config(self::$configDir);
OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT)));
/**
@@ -137,7 +142,7 @@ class OC {
'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
],
];
- $fakeRequest = new \OC\AppFramework\Http\Request($params, null, new \OC\AllConfig(new \OC\SystemConfig()));
+ $fakeRequest = new \OC\AppFramework\Http\Request($params, null, new \OC\AllConfig(new \OC\SystemConfig(self::$config)));
$scriptName = $fakeRequest->getScriptName();
if (substr($scriptName, -1) == '/') {
$scriptName .= 'index.php';
@@ -152,7 +157,7 @@ class OC {
if (OC::$CLI) {
- OC::$WEBROOT = OC_Config::getValue('overwritewebroot', '');
+ OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
} else {
if (substr($scriptName, 0 - strlen(OC::$SUBURI)) === OC::$SUBURI) {
OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
@@ -165,13 +170,21 @@ class OC {
// This most likely means that we are calling from CLI.
// However some cron jobs still need to generate
// a web URL, so we use overwritewebroot as a fallback.
- OC::$WEBROOT = OC_Config::getValue('overwritewebroot', '');
+ OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
+ }
+
+ // Resolve /owncloud to /owncloud/ to ensure to always have a trailing
+ // slash which is required by URL generation.
+ if($_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
+ substr($_SERVER['REQUEST_URI'], -1) !== '/') {
+ header('Location: '.\OC::$WEBROOT.'/');
+ exit();
}
}
// search the 3rdparty folder
- OC::$THIRDPARTYROOT = OC_Config::getValue('3rdpartyroot', null);
- OC::$THIRDPARTYWEBROOT = OC_Config::getValue('3rdpartyurl', null);
+ OC::$THIRDPARTYROOT = self::$config->getValue('3rdpartyroot', null);
+ OC::$THIRDPARTYWEBROOT = self::$config->getValue('3rdpartyurl', null);
if (empty(OC::$THIRDPARTYROOT) && empty(OC::$THIRDPARTYWEBROOT)) {
if (file_exists(OC::$SERVERROOT . '/3rdparty')) {
@@ -189,7 +202,7 @@ class OC {
}
// search the apps folder
- $config_paths = OC_Config::getValue('apps_paths', array());
+ $config_paths = self::$config->getValue('apps_paths', array());
if (!empty($config_paths)) {
foreach ($config_paths as $paths) {
if (isset($paths['url']) && isset($paths['path'])) {
@@ -246,18 +259,21 @@ class OC {
$configFileWritable = is_writable($configFilePath);
if (!$configFileWritable && !OC_Helper::isReadOnlyConfigEnabled()
|| !$configFileWritable && self::checkUpgrade(false)) {
+
+ $urlGenerator = \OC::$server->getURLGenerator();
+
if (self::$CLI) {
echo $l->t('Cannot write into "config" directory!')."\n";
echo $l->t('This can usually be fixed by giving the webserver write access to the config directory')."\n";
echo "\n";
- echo $l->t('See %s', array(\OC_Helper::linkToDocs('admin-dir_permissions')))."\n";
+ echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-dir_permissions') ])."\n";
exit;
} else {
OC_Template::printErrorPage(
$l->t('Cannot write into "config" directory!'),
$l->t('This can usually be fixed by '
. '%sgiving the webserver write access to the config directory%s.',
- array('<a href="'.\OC_Helper::linkToDocs('admin-dir_permissions').'" target="_blank">', '</a>'))
+ array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'))
);
}
}
@@ -361,7 +377,7 @@ class OC {
// check whether this is a core update or apps update
$installedVersion = $systemConfig->getValue('version', '0.0.0');
- $currentVersion = implode('.', OC_Util::getVersion());
+ $currentVersion = implode('.', \OCP\Util::getVersion());
$appManager = \OC::$server->getAppManager();
@@ -376,7 +392,7 @@ class OC {
}
// get third party apps
- $ocVersion = OC_Util::getVersion();
+ $ocVersion = \OCP\Util::getVersion();
$tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
$tmpl->assign('incompatibleAppsList', $appManager->getIncompatibleApps($ocVersion));
$tmpl->assign('productName', 'ownCloud'); // for now
@@ -415,30 +431,17 @@ class OC {
//show the user a detailed error page
OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR);
OC_Template::printExceptionErrorPage($e);
+ die();
}
$sessionLifeTime = self::getSessionLifeTime();
- // regenerate session id periodically to avoid session fixation
- /**
- * @var \OCP\ISession $session
- */
- $session = self::$server->getSession();
- if (!$session->exists('SID_CREATED')) {
- $session->set('SID_CREATED', time());
- } else if (time() - $session->get('SID_CREATED') > $sessionLifeTime / 2) {
- session_regenerate_id(true);
- $session->set('SID_CREATED', time());
- }
// session timeout
if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), null, -1, self::$WEBROOT ? : '/');
- unset($_COOKIE[session_name()]);
}
- session_unset();
- session_destroy();
- session_start();
+ $session->clear();
}
$session->set('LAST_ACTIVITY', time());
@@ -453,7 +456,12 @@ class OC {
public static function loadAppClassPaths() {
foreach (OC_APP::getEnabledApps() as $app) {
- $file = OC_App::getAppPath($app) . '/appinfo/classpath.php';
+ $appPath = OC_App::getAppPath($app);
+ if ($appPath === false) {
+ continue;
+ }
+
+ $file = $appPath . '/appinfo/classpath.php';
if (file_exists($file)) {
require_once $file;
}
@@ -465,6 +473,7 @@ class OC {
*/
public static function setRequiredIniValues() {
@ini_set('default_charset', 'UTF-8');
+ @ini_set('gd.jpeg_ignore_warning', 1);
}
public static function init() {
@@ -480,9 +489,10 @@ class OC {
OC::$SERVERROOT . '/settings',
OC::$SERVERROOT . '/ocs',
OC::$SERVERROOT . '/ocs-provider',
- OC::$SERVERROOT . '/3rdparty',
- OC::$SERVERROOT . '/tests',
]);
+ if (defined('PHPUNIT_RUN')) {
+ self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
+ }
spl_autoload_register(array(self::$loader, 'load'));
$loaderEnd = microtime(true);
@@ -506,7 +516,7 @@ class OC {
}
// setup the basic server
- self::$server = new \OC\Server(\OC::$WEBROOT);
+ self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
\OC::$server->getEventLogger()->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
\OC::$server->getEventLogger()->start('boot', 'Initialize');
@@ -635,7 +645,6 @@ class OC {
}
self::registerShareHooks();
self::registerLogRotate();
- self::registerLocalAddressBook();
self::registerEncryptionWrapper();
self::registerEncryptionHooks();
@@ -691,14 +700,6 @@ class OC {
\OC::$server->getEventLogger()->end('boot');
}
- private static function registerLocalAddressBook() {
- self::$server->getContactsManager()->register(function() {
- $userManager = \OC::$server->getUserManager();
- \OC::$server->getContactsManager()->registerAddressBook(
- new \OC\Contacts\LocalAddressBook($userManager));
- });
- }
-
/**
* register hooks for the cache
*/
@@ -817,7 +818,7 @@ class OC {
$setupHelper = new OC\Setup(\OC::$server->getConfig(), \OC::$server->getIniWrapper(),
\OC::$server->getL10N('lib'), new \OC_Defaults(), \OC::$server->getLogger(),
\OC::$server->getSecureRandom());
- $controller = new OC\Core\Setup\Controller($setupHelper);
+ $controller = new OC\Core\Controller\SetupController($setupHelper);
$controller->run($_POST);
exit();
}
@@ -864,7 +865,7 @@ class OC {
// Handle redirect URL for logged in users
if (isset($_REQUEST['redirect_url']) && OC_User::isLoggedIn()) {
- $location = OC_Helper::makeURLAbsolute(urldecode($_REQUEST['redirect_url']));
+ $location = \OC::$server->getURLGenerator()->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
// Deny the redirect if the URL contains a @
// This prevents unvalidated redirects like ?redirect_url=:user@domain.com
@@ -887,7 +888,7 @@ class OC {
// this is needed to prevent "Token expired" messages while login if a session is expired
// @see https://github.com/owncloud/core/pull/8443#issuecomment-42425583
if(isset($_GET['logout']) && !OC_User::isLoggedIn()) {
- header("Location: " . OC::$WEBROOT.(empty(OC::$WEBROOT) ? '/' : ''));
+ header("Location: " . \OC::$server->getURLGenerator()->getAbsoluteURL('/'));
return;
}
@@ -903,7 +904,7 @@ class OC {
}
OC_User::logout();
// redirect to webroot and add slash if webroot is empty
- header("Location: " . OC::$WEBROOT.(empty(OC::$WEBROOT) ? '/' : ''));
+ header("Location: " . \OC::$server->getURLGenerator()->getAbsoluteURL('/'));
} else {
// Redirect to default application
OC_Util::redirectToDefaultPage();
@@ -1044,7 +1045,7 @@ class OC {
return false;
}
- if(!OC_Util::isCallRegistered()) {
+ if(!(\OC::$server->getRequest()->passesCSRFCheck())) {
return false;
}
OC_App::loadApps();
@@ -1067,7 +1068,7 @@ class OC {
if ($config->getSystemValue('debug', false)) {
self::$server->getLogger()->debug('Setting remember login to cookie', array('app' => 'core'));
}
- $token = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(32);
+ $token = \OC::$server->getSecureRandom()->generate(32);
$config->setUserValue($userId, 'login_token', $token, time());
OC_User::setMagicInCookie($userId, $token);
} else {
diff --git a/lib/l10n/ast.js b/lib/l10n/ast.js
index c3ca33e74ad..45939c5d99f 100644
--- a/lib/l10n/ast.js
+++ b/lib/l10n/ast.js
@@ -90,7 +90,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Compartir %s falló, yá que'l ficheru nun pudo atopase na caché de ficheru",
"Could not find category \"%s\"" : "Nun pudo alcontrase la estaya \"%s.\"",
"Apps" : "Aplicaciones",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Namái tan permitíos los siguientes caráuteres nun nome d'usuariu: \"a-z\", \"A-Z\", \"0-9\", y \"_.@-\"",
"A valid username must be provided" : "Tien d'apurrise un nome d'usuariu válidu",
"A valid password must be provided" : "Tien d'apurrise una contraseña válida",
"The username is already being used" : "El nome d'usuariu yá ta usándose",
@@ -110,8 +109,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Por favor, entruga al to alministrador pa reaniciar el sirvidor web.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 requeríu",
"Please upgrade your database version" : "Por favor, anueva la versión de la to base de datos",
- "Error occurred while checking PostgreSQL version" : "Asocedió un fallu mientres se comprobaba la versión de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Por favor, asegúrate que tienes PostgreSQL >= 9 o comprueba los rexistros pa más información tocante al fallu",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor, camuda los permisos a 0770 pa que'l direutoriu nun pueda llistase por otros usuarios.",
"Data directory (%s) is readable by other users" : "El direutoriu de datos (%s) ye llexible por otros usuarios",
"Data directory (%s) is invalid" : "Ye inválidu'l direutoriu de datos (%s)",
diff --git a/lib/l10n/ast.json b/lib/l10n/ast.json
index bfcaf8729d7..794bf0134a9 100644
--- a/lib/l10n/ast.json
+++ b/lib/l10n/ast.json
@@ -88,7 +88,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Compartir %s falló, yá que'l ficheru nun pudo atopase na caché de ficheru",
"Could not find category \"%s\"" : "Nun pudo alcontrase la estaya \"%s.\"",
"Apps" : "Aplicaciones",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Namái tan permitíos los siguientes caráuteres nun nome d'usuariu: \"a-z\", \"A-Z\", \"0-9\", y \"_.@-\"",
"A valid username must be provided" : "Tien d'apurrise un nome d'usuariu válidu",
"A valid password must be provided" : "Tien d'apurrise una contraseña válida",
"The username is already being used" : "El nome d'usuariu yá ta usándose",
@@ -108,8 +107,6 @@
"Please ask your server administrator to restart the web server." : "Por favor, entruga al to alministrador pa reaniciar el sirvidor web.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 requeríu",
"Please upgrade your database version" : "Por favor, anueva la versión de la to base de datos",
- "Error occurred while checking PostgreSQL version" : "Asocedió un fallu mientres se comprobaba la versión de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Por favor, asegúrate que tienes PostgreSQL >= 9 o comprueba los rexistros pa más información tocante al fallu",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor, camuda los permisos a 0770 pa que'l direutoriu nun pueda llistase por otros usuarios.",
"Data directory (%s) is readable by other users" : "El direutoriu de datos (%s) ye llexible por otros usuarios",
"Data directory (%s) is invalid" : "Ye inválidu'l direutoriu de datos (%s)",
diff --git a/lib/l10n/bg_BG.js b/lib/l10n/bg_BG.js
index fae7f894bcc..37a87706159 100644
--- a/lib/l10n/bg_BG.js
+++ b/lib/l10n/bg_BG.js
@@ -91,7 +91,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Неуспешно споделяне на %s, защото файлът не може да бъде намерен в кеша.",
"Could not find category \"%s\"" : "Невъзможно откриване на категорията \"%s\".",
"Apps" : "Приложения",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Само следните символи са разрешени в потребителското име: \"a-z\", \"A-Z\", \"0-9\", и \"_.@-\".",
"A valid username must be provided" : "Валидно потребителско име трябва да бъде зададено.",
"A valid password must be provided" : "Валидна парола трябва да бъде зададена.",
"The username is already being used" : "Това потребителско име е вече заето.",
@@ -111,8 +110,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Моля, поискай от своя администратор да рестартира уеб сървъра.",
"PostgreSQL >= 9 required" : "Изисква се PostgreSQL >= 9",
"Please upgrade your database version" : "Моля, обнови базата данни.",
- "Error occurred while checking PostgreSQL version" : "Настъпи грешка при проверката на версията на PostgreSQL.",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Моля, увери се, че PostgreSQL >= 9 или провери докладите за повече информация относно грешката.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Моля, промени правата за достъп на 0770, за да не може директорията да бъде видяна от други потребители.",
"Data directory (%s) is readable by other users" : "Data папката (%s) може да бъде разгледана от други потребители",
"Data directory (%s) is invalid" : "Data папката (%s) e невалидна",
diff --git a/lib/l10n/bg_BG.json b/lib/l10n/bg_BG.json
index 21361a20897..c26aaa692ff 100644
--- a/lib/l10n/bg_BG.json
+++ b/lib/l10n/bg_BG.json
@@ -89,7 +89,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Неуспешно споделяне на %s, защото файлът не може да бъде намерен в кеша.",
"Could not find category \"%s\"" : "Невъзможно откриване на категорията \"%s\".",
"Apps" : "Приложения",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Само следните символи са разрешени в потребителското име: \"a-z\", \"A-Z\", \"0-9\", и \"_.@-\".",
"A valid username must be provided" : "Валидно потребителско име трябва да бъде зададено.",
"A valid password must be provided" : "Валидна парола трябва да бъде зададена.",
"The username is already being used" : "Това потребителско име е вече заето.",
@@ -109,8 +108,6 @@
"Please ask your server administrator to restart the web server." : "Моля, поискай от своя администратор да рестартира уеб сървъра.",
"PostgreSQL >= 9 required" : "Изисква се PostgreSQL >= 9",
"Please upgrade your database version" : "Моля, обнови базата данни.",
- "Error occurred while checking PostgreSQL version" : "Настъпи грешка при проверката на версията на PostgreSQL.",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Моля, увери се, че PostgreSQL >= 9 или провери докладите за повече информация относно грешката.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Моля, промени правата за достъп на 0770, за да не може директорията да бъде видяна от други потребители.",
"Data directory (%s) is readable by other users" : "Data папката (%s) може да бъде разгледана от други потребители",
"Data directory (%s) is invalid" : "Data папката (%s) e невалидна",
diff --git a/lib/l10n/ca.js b/lib/l10n/ca.js
index 6df1b5245d4..ce74bc408a3 100644
--- a/lib/l10n/ca.js
+++ b/lib/l10n/ca.js
@@ -79,7 +79,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Ha fallat en compartir %s, perquè el fitxer no s'ha trobat en el fitxer cau",
"Could not find category \"%s\"" : "No s'ha trobat la categoria \"%s\"",
"Apps" : "Aplicacions",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Només els caràcters següents estan permesos en el nom d'usuari: \"a-z\", \"A-Z\", \"0-9\" i \"_.@-\"",
"A valid username must be provided" : "Heu de facilitar un nom d'usuari vàlid",
"A valid password must be provided" : "Heu de facilitar una contrasenya vàlida",
"The username is already being used" : "El nom d'usuari ja està en ús",
@@ -99,8 +98,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Demaneu a l'administrador que reinici el servidor web.",
"PostgreSQL >= 9 required" : "Es requereix PostgreSQL >= 9",
"Please upgrade your database version" : "Actualitzeu la versió de la base de dades",
- "Error occurred while checking PostgreSQL version" : "Hi ha hagut un error en comprovar la versió de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Assegureu-vos que teniu PostgreSQL >= 9 o comproveu els registres per més informació quant a l'error",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Canvieu els permisos a 0770 per tal que la carpeta no es pugui llistar per altres usuaris.",
"Data directory (%s) is readable by other users" : "La carpeta de dades (%s) és llegible per altres usuaris",
"Data directory (%s) is invalid" : "La carpeta de dades (%s) no és vàlida",
diff --git a/lib/l10n/ca.json b/lib/l10n/ca.json
index bd722389fdc..a0ae70b95fa 100644
--- a/lib/l10n/ca.json
+++ b/lib/l10n/ca.json
@@ -77,7 +77,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Ha fallat en compartir %s, perquè el fitxer no s'ha trobat en el fitxer cau",
"Could not find category \"%s\"" : "No s'ha trobat la categoria \"%s\"",
"Apps" : "Aplicacions",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Només els caràcters següents estan permesos en el nom d'usuari: \"a-z\", \"A-Z\", \"0-9\" i \"_.@-\"",
"A valid username must be provided" : "Heu de facilitar un nom d'usuari vàlid",
"A valid password must be provided" : "Heu de facilitar una contrasenya vàlida",
"The username is already being used" : "El nom d'usuari ja està en ús",
@@ -97,8 +96,6 @@
"Please ask your server administrator to restart the web server." : "Demaneu a l'administrador que reinici el servidor web.",
"PostgreSQL >= 9 required" : "Es requereix PostgreSQL >= 9",
"Please upgrade your database version" : "Actualitzeu la versió de la base de dades",
- "Error occurred while checking PostgreSQL version" : "Hi ha hagut un error en comprovar la versió de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Assegureu-vos que teniu PostgreSQL >= 9 o comproveu els registres per més informació quant a l'error",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Canvieu els permisos a 0770 per tal que la carpeta no es pugui llistar per altres usuaris.",
"Data directory (%s) is readable by other users" : "La carpeta de dades (%s) és llegible per altres usuaris",
"Data directory (%s) is invalid" : "La carpeta de dades (%s) no és vàlida",
diff --git a/lib/l10n/cs_CZ.js b/lib/l10n/cs_CZ.js
index 02d667e9cb8..668c349f66c 100644
--- a/lib/l10n/cs_CZ.js
+++ b/lib/l10n/cs_CZ.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Archivy typu %s nejsou podporovány",
"Failed to open archive when installing app" : "Chyba při otevírání archivu během instalace aplikace",
"App does not provide an info.xml file" : "Aplikace neposkytuje soubor info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Podpis nelze ověřit. Kontaktujte prosím vývojáře aplikace a zkontrolujte obrazovku administrace.",
"App can't be installed because of not allowed code in the App" : "Aplikace nemůže být nainstalována, protože obsahuje nepovolený kód",
"App can't be installed because it is not compatible with this version of ownCloud" : "Aplikace nemůže být nainstalována, protože není kompatibilní s touto verzí ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "Aplikace nemůže být nainstalována, protože obsahuje značku\n<shipped>\n\ntrue\n</shipped>\n\ncož není povoleno pro nedodávané aplikace",
@@ -96,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Sdílení položky %s selhalo, protože uživatel %s není členem skupiny %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Pro vytvoření veřejného odkazu je nutné zadat heslo, jsou povoleny pouze chráněné odkazy",
"Sharing %s failed, because sharing with links is not allowed" : "Sdílení položky %s selhalo, protože sdílení pomocí linků není povoleno",
+ "Not allowed to create a federated share with the same user" : "Není povoleno vytvořit propojené sdílení s tím samým uživatelem",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Sdílení %s selhalo, %s se nepodařilo nalézt, server pravděpodobně právě není dostupný.",
"Share type %s is not valid for %s" : "Sdílení typu %s není korektní pro %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Nastavení oprávnění pro %s selhalo, protože jsou k tomu nutná vyšší oprávnění, než jaká byla povolena pro %s",
@@ -111,9 +113,12 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Sdílení položky %s selhalo, protože znovu-sdílení není povoleno",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Sdílení položky %s selhalo, protože úložiště sdílení %s nenalezla zdroj",
"Sharing %s failed, because the file could not be found in the file cache" : "Sdílení položky %s selhalo, protože soubor nebyl nalezen ve vyrovnávací paměti",
+ "Cannot increase permissions of %s" : "Nelze navýšit oprávnění u %s",
+ "Expiration date is in the past" : "Datum vypršení je v minulosti",
+ "Cannot set expiration date more than %s days in the future" : "Datum vypršení nelze nastavit na více než %s dní do budoucnosti",
"Could not find category \"%s\"" : "Nelze nalézt kategorii \"%s\"",
"Apps" : "Aplikace",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Pouze následující znaky jsou povoleny v uživatelském jménu: \"a-z\", \"A-Z\", \"0-9\" a \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Pouze následující znaky jsou povoleny pro uživatelské jméno: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"",
"A valid username must be provided" : "Musíte zadat platné uživatelské jméno",
"A valid password must be provided" : "Musíte zadat platné heslo",
"The username is already being used" : "Uživatelské jméno je již využíváno",
@@ -140,8 +145,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Požádejte svého správce systému o restart webového serveru.",
"PostgreSQL >= 9 required" : "Je vyžadováno PostgreSQL >= 9",
"Please upgrade your database version" : "Aktualizujte prosím verzi své databáze",
- "Error occurred while checking PostgreSQL version" : "Při zjišťování verze PostgreSQL došlo k chybě",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Ujistěte se, že máte PostgreSQL >= 9, a zkontrolujte logy pro více informací o chybě.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Změňte prosím práva na 0770, aby adresář nemohl být otevřen ostatními uživateli.",
"Data directory (%s) is readable by other users" : "Datový adresář (%s) je čitelný i ostatními uživateli",
"Data directory (%s) must be an absolute path" : "Cesta k datovému adresáři (%s) musí být uvedena absolutně",
@@ -149,6 +152,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "Datový adresář (%s) je neplatný",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Ověřte prosím, že kořenový adresář s daty obsahuje soubor \".ocdata\".",
"Could not obtain lock type %d on \"%s\"." : "Nelze získat zámek typu %d na \"%s\".",
- "Storage not available" : "Úložiště není dostupné"
+ "Storage unauthorized. %s" : "Úložiště neověřeno. %s",
+ "Storage incomplete configuration. %s" : "Nekompletní konfigurace úložiště. %s",
+ "Storage connection error. %s" : "Chyba připojení úložiště. %s",
+ "Storage not available" : "Úložiště není dostupné",
+ "Storage connection timeout. %s" : "Vypršení připojení k úložišti. %s"
},
"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;");
diff --git a/lib/l10n/cs_CZ.json b/lib/l10n/cs_CZ.json
index d55cb2c9485..f7de6d610cf 100644
--- a/lib/l10n/cs_CZ.json
+++ b/lib/l10n/cs_CZ.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "Archivy typu %s nejsou podporovány",
"Failed to open archive when installing app" : "Chyba při otevírání archivu během instalace aplikace",
"App does not provide an info.xml file" : "Aplikace neposkytuje soubor info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Podpis nelze ověřit. Kontaktujte prosím vývojáře aplikace a zkontrolujte obrazovku administrace.",
"App can't be installed because of not allowed code in the App" : "Aplikace nemůže být nainstalována, protože obsahuje nepovolený kód",
"App can't be installed because it is not compatible with this version of ownCloud" : "Aplikace nemůže být nainstalována, protože není kompatibilní s touto verzí ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "Aplikace nemůže být nainstalována, protože obsahuje značku\n<shipped>\n\ntrue\n</shipped>\n\ncož není povoleno pro nedodávané aplikace",
@@ -94,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Sdílení položky %s selhalo, protože uživatel %s není členem skupiny %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Pro vytvoření veřejného odkazu je nutné zadat heslo, jsou povoleny pouze chráněné odkazy",
"Sharing %s failed, because sharing with links is not allowed" : "Sdílení položky %s selhalo, protože sdílení pomocí linků není povoleno",
+ "Not allowed to create a federated share with the same user" : "Není povoleno vytvořit propojené sdílení s tím samým uživatelem",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Sdílení %s selhalo, %s se nepodařilo nalézt, server pravděpodobně právě není dostupný.",
"Share type %s is not valid for %s" : "Sdílení typu %s není korektní pro %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Nastavení oprávnění pro %s selhalo, protože jsou k tomu nutná vyšší oprávnění, než jaká byla povolena pro %s",
@@ -109,9 +111,12 @@
"Sharing %s failed, because resharing is not allowed" : "Sdílení položky %s selhalo, protože znovu-sdílení není povoleno",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Sdílení položky %s selhalo, protože úložiště sdílení %s nenalezla zdroj",
"Sharing %s failed, because the file could not be found in the file cache" : "Sdílení položky %s selhalo, protože soubor nebyl nalezen ve vyrovnávací paměti",
+ "Cannot increase permissions of %s" : "Nelze navýšit oprávnění u %s",
+ "Expiration date is in the past" : "Datum vypršení je v minulosti",
+ "Cannot set expiration date more than %s days in the future" : "Datum vypršení nelze nastavit na více než %s dní do budoucnosti",
"Could not find category \"%s\"" : "Nelze nalézt kategorii \"%s\"",
"Apps" : "Aplikace",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Pouze následující znaky jsou povoleny v uživatelském jménu: \"a-z\", \"A-Z\", \"0-9\" a \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Pouze následující znaky jsou povoleny pro uživatelské jméno: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"",
"A valid username must be provided" : "Musíte zadat platné uživatelské jméno",
"A valid password must be provided" : "Musíte zadat platné heslo",
"The username is already being used" : "Uživatelské jméno je již využíváno",
@@ -138,8 +143,6 @@
"Please ask your server administrator to restart the web server." : "Požádejte svého správce systému o restart webového serveru.",
"PostgreSQL >= 9 required" : "Je vyžadováno PostgreSQL >= 9",
"Please upgrade your database version" : "Aktualizujte prosím verzi své databáze",
- "Error occurred while checking PostgreSQL version" : "Při zjišťování verze PostgreSQL došlo k chybě",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Ujistěte se, že máte PostgreSQL >= 9, a zkontrolujte logy pro více informací o chybě.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Změňte prosím práva na 0770, aby adresář nemohl být otevřen ostatními uživateli.",
"Data directory (%s) is readable by other users" : "Datový adresář (%s) je čitelný i ostatními uživateli",
"Data directory (%s) must be an absolute path" : "Cesta k datovému adresáři (%s) musí být uvedena absolutně",
@@ -147,6 +150,10 @@
"Data directory (%s) is invalid" : "Datový adresář (%s) je neplatný",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Ověřte prosím, že kořenový adresář s daty obsahuje soubor \".ocdata\".",
"Could not obtain lock type %d on \"%s\"." : "Nelze získat zámek typu %d na \"%s\".",
- "Storage not available" : "Úložiště není dostupné"
+ "Storage unauthorized. %s" : "Úložiště neověřeno. %s",
+ "Storage incomplete configuration. %s" : "Nekompletní konfigurace úložiště. %s",
+ "Storage connection error. %s" : "Chyba připojení úložiště. %s",
+ "Storage not available" : "Úložiště není dostupné",
+ "Storage connection timeout. %s" : "Vypršení připojení k úložišti. %s"
},"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
} \ No newline at end of file
diff --git a/lib/l10n/da.js b/lib/l10n/da.js
index 232934fdcad..4fab1992d42 100644
--- a/lib/l10n/da.js
+++ b/lib/l10n/da.js
@@ -113,7 +113,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Deling af %s mislykkedes, fordi filen ikke kunne findes i fil-cachen",
"Could not find category \"%s\"" : "Kunne ikke finde kategorien \"%s\"",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Det er kun tilladt at benytte følgene karakterer i et brugernavn \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Et gyldigt brugernavn skal angives",
"A valid password must be provided" : "En gyldig adgangskode skal angives",
"The username is already being used" : "Brugernavnet er allerede i brug",
@@ -140,8 +139,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Du bedes anmode din serveradministrator om at genstarte webserveren.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 kræves",
"Please upgrade your database version" : "Opgradér venligst din databaseversion",
- "Error occurred while checking PostgreSQL version" : "Der opstod fejl under tjek af PostgreSQL-versionen",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Sørg venligst for at du har PostgreSQL >= 9 eller tjek loggen for flere informationer om fejlen",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Tilpas venligst rettigheder til 0770, så mappen ikke fremvises for andre brugere.",
"Data directory (%s) is readable by other users" : "Datamappen (%s) kan læses af andre brugere",
"Data directory (%s) must be an absolute path" : "Datamappen (%s) skal have en absolut sti",
diff --git a/lib/l10n/da.json b/lib/l10n/da.json
index 8b1e7744583..d4d4d16135a 100644
--- a/lib/l10n/da.json
+++ b/lib/l10n/da.json
@@ -111,7 +111,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Deling af %s mislykkedes, fordi filen ikke kunne findes i fil-cachen",
"Could not find category \"%s\"" : "Kunne ikke finde kategorien \"%s\"",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Det er kun tilladt at benytte følgene karakterer i et brugernavn \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Et gyldigt brugernavn skal angives",
"A valid password must be provided" : "En gyldig adgangskode skal angives",
"The username is already being used" : "Brugernavnet er allerede i brug",
@@ -138,8 +137,6 @@
"Please ask your server administrator to restart the web server." : "Du bedes anmode din serveradministrator om at genstarte webserveren.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 kræves",
"Please upgrade your database version" : "Opgradér venligst din databaseversion",
- "Error occurred while checking PostgreSQL version" : "Der opstod fejl under tjek af PostgreSQL-versionen",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Sørg venligst for at du har PostgreSQL >= 9 eller tjek loggen for flere informationer om fejlen",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Tilpas venligst rettigheder til 0770, så mappen ikke fremvises for andre brugere.",
"Data directory (%s) is readable by other users" : "Datamappen (%s) kan læses af andre brugere",
"Data directory (%s) must be an absolute path" : "Datamappen (%s) skal have en absolut sti",
diff --git a/lib/l10n/de.js b/lib/l10n/de.js
index 7baf49e0650..b9f54fc3b51 100644
--- a/lib/l10n/de.js
+++ b/lib/l10n/de.js
@@ -113,7 +113,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Freigabe von %s fehlgeschlagen, da die Datei im Datei-Cache nicht gefunden werden konnte",
"Could not find category \"%s\"" : "Die Kategorie „%s“ konnte nicht gefunden werden",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“ und „_.@-“",
"A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden",
"A valid password must be provided" : "Es muss ein gültiges Passwort angegeben werden",
"The username is already being used" : "Dieser Benutzername existiert bereits",
@@ -140,8 +139,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Bitte kontaktiere Deinen Server-Administrator und bitte um den Neustart des Webservers.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 benötigt",
"Please upgrade your database version" : "Bitte aktualisiere Deine Datenbankversion",
- "Error occurred while checking PostgreSQL version" : "Es ist ein Fehler beim Prüfen der PostgreSQL-Version aufgetreten",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Stelle bitte sicher, dass Du PostgreSQL >= 9 verwendest oder prüfe die Logs für weitere Informationen über den Fehler",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändere die Berechtigungen auf 0770 sodass das Verzeichnis nicht von anderen Nutzer angezeigt werden kann.",
"Data directory (%s) is readable by other users" : "Daten-Verzeichnis (%s) ist von anderen Nutzern lesbar",
"Data directory (%s) must be an absolute path" : "Das Datenverzeichnis (%s) muss ein absoluter Pfad sein",
diff --git a/lib/l10n/de.json b/lib/l10n/de.json
index 927e610e0d0..826775e7a4c 100644
--- a/lib/l10n/de.json
+++ b/lib/l10n/de.json
@@ -111,7 +111,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Freigabe von %s fehlgeschlagen, da die Datei im Datei-Cache nicht gefunden werden konnte",
"Could not find category \"%s\"" : "Die Kategorie „%s“ konnte nicht gefunden werden",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“ und „_.@-“",
"A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden",
"A valid password must be provided" : "Es muss ein gültiges Passwort angegeben werden",
"The username is already being used" : "Dieser Benutzername existiert bereits",
@@ -138,8 +137,6 @@
"Please ask your server administrator to restart the web server." : "Bitte kontaktiere Deinen Server-Administrator und bitte um den Neustart des Webservers.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 benötigt",
"Please upgrade your database version" : "Bitte aktualisiere Deine Datenbankversion",
- "Error occurred while checking PostgreSQL version" : "Es ist ein Fehler beim Prüfen der PostgreSQL-Version aufgetreten",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Stelle bitte sicher, dass Du PostgreSQL >= 9 verwendest oder prüfe die Logs für weitere Informationen über den Fehler",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändere die Berechtigungen auf 0770 sodass das Verzeichnis nicht von anderen Nutzer angezeigt werden kann.",
"Data directory (%s) is readable by other users" : "Daten-Verzeichnis (%s) ist von anderen Nutzern lesbar",
"Data directory (%s) must be an absolute path" : "Das Datenverzeichnis (%s) muss ein absoluter Pfad sein",
diff --git a/lib/l10n/de_DE.js b/lib/l10n/de_DE.js
index c0c92a12037..b434ac56aad 100644
--- a/lib/l10n/de_DE.js
+++ b/lib/l10n/de_DE.js
@@ -107,9 +107,10 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Freigabe von %s fehlgeschlagen, da das nochmalige Freigeben einer Freigabe nicht erlaubt ist",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Freigabe von %s fehlgeschlagen, da das Freigabe-Backend für %s nicht in dieser Quelle gefunden werden konnte",
"Sharing %s failed, because the file could not be found in the file cache" : "Freigabe von %s fehlgeschlagen, da die Datei im Datei-Cache nicht gefunden werden konnte",
+ "Expiration date is in the past" : "Das Ablaufdatum liegt in der Vergangenheit.",
"Could not find category \"%s\"" : "Die Kategorie „%s“ konnte nicht gefunden werden",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“ und „_.@-“",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Nur die follgenden Zeichen sind im Benutzernamen erlaubt: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"",
"A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden",
"A valid password must be provided" : "Es muss ein gültiges Passwort angegeben werden",
"The username is already being used" : "Der Benutzername existiert bereits",
@@ -136,8 +137,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Bitte kontaktieren Sie Ihren Server-Administrator und bitten Sie um den Neustart des Webservers.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 benötigt",
"Please upgrade your database version" : "Bitte aktualisieren Sie Ihre Datenbankversion",
- "Error occurred while checking PostgreSQL version" : "Es ist ein Fehler beim Prüfen der PostgreSQL-Version aufgetreten",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Stellen Sie sicher, dass Sie PostgreSQL >= 9 verwenden oder prüfen Sie die Logs für weitere Informationen über den Fehler",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändern Sie die Berechtigungen auf 0770, so dass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann.",
"Data directory (%s) is readable by other users" : "Daten-Verzeichnis (%s) ist von anderen Benutzern lesbar",
"Data directory (%s) must be an absolute path" : "Das Datenverzeichnis (%s) muss ein absoluter Pfad sein",
diff --git a/lib/l10n/de_DE.json b/lib/l10n/de_DE.json
index afa38ec4705..09ce050c452 100644
--- a/lib/l10n/de_DE.json
+++ b/lib/l10n/de_DE.json
@@ -105,9 +105,10 @@
"Sharing %s failed, because resharing is not allowed" : "Freigabe von %s fehlgeschlagen, da das nochmalige Freigeben einer Freigabe nicht erlaubt ist",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Freigabe von %s fehlgeschlagen, da das Freigabe-Backend für %s nicht in dieser Quelle gefunden werden konnte",
"Sharing %s failed, because the file could not be found in the file cache" : "Freigabe von %s fehlgeschlagen, da die Datei im Datei-Cache nicht gefunden werden konnte",
+ "Expiration date is in the past" : "Das Ablaufdatum liegt in der Vergangenheit.",
"Could not find category \"%s\"" : "Die Kategorie „%s“ konnte nicht gefunden werden",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“ und „_.@-“",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Nur die follgenden Zeichen sind im Benutzernamen erlaubt: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"",
"A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden",
"A valid password must be provided" : "Es muss ein gültiges Passwort angegeben werden",
"The username is already being used" : "Der Benutzername existiert bereits",
@@ -134,8 +135,6 @@
"Please ask your server administrator to restart the web server." : "Bitte kontaktieren Sie Ihren Server-Administrator und bitten Sie um den Neustart des Webservers.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 benötigt",
"Please upgrade your database version" : "Bitte aktualisieren Sie Ihre Datenbankversion",
- "Error occurred while checking PostgreSQL version" : "Es ist ein Fehler beim Prüfen der PostgreSQL-Version aufgetreten",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Stellen Sie sicher, dass Sie PostgreSQL >= 9 verwenden oder prüfen Sie die Logs für weitere Informationen über den Fehler",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändern Sie die Berechtigungen auf 0770, so dass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann.",
"Data directory (%s) is readable by other users" : "Daten-Verzeichnis (%s) ist von anderen Benutzern lesbar",
"Data directory (%s) must be an absolute path" : "Das Datenverzeichnis (%s) muss ein absoluter Pfad sein",
diff --git a/lib/l10n/el.js b/lib/l10n/el.js
index 932028a22cd..209f35f040d 100644
--- a/lib/l10n/el.js
+++ b/lib/l10n/el.js
@@ -110,7 +110,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Ο διαμοιρασμός του %s απέτυχε, γιατί το αρχείο δεν βρέθηκε στην προσωρινή αποθήκευση αρχείων",
"Could not find category \"%s\"" : "Αδυναμία εύρεσης κατηγορίας \"%s\"",
"Apps" : "Εφαρμογές",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Μόνο οι παρακάτων χαρακτήρες επιτρέπονται σε ένα όνομα χρήστη: \"a-z\", \"A-Z\", \"0-9\" και \"_.@-\"",
"A valid username must be provided" : "Πρέπει να δοθεί έγκυρο όνομα χρήστη",
"A valid password must be provided" : "Πρέπει να δοθεί έγκυρο συνθηματικό",
"The username is already being used" : "Το όνομα χρήστη είναι κατειλημμένο",
@@ -137,8 +136,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Παρακαλώ ζητήστε από το διαχειριστή του διακομιστή σας να επανεκκινήσει το διακομιστή δικτύου σας.",
"PostgreSQL >= 9 required" : "Απαιτείται PostgreSQL >= 9",
"Please upgrade your database version" : "Παρακαλώ αναβαθμίστε την έκδοση της βάσης δεδομένων σας",
- "Error occurred while checking PostgreSQL version" : "Προέκυψε σφάλμα κατά τον έλεγχο της έκδοσης PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Παρακαλώ ελέγξτε ότι έχετε PostgreSQL >= 9 ή ελέγξτε στα ιστορικό σφαλμάτων για περισσότερες πληροφορίες για το σφάλμα",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Παρακαλώ αλλάξτε τις ρυθμίσεις σε 0770 έτσι ώστε ο κατάλογος να μην μπορεί να προβάλλεται από άλλους χρήστες.",
"Data directory (%s) is readable by other users" : "Ο κατάλογος δεδομένων (%s) είναι διαθέσιμος προς ανάγνωση για άλλους χρήστες",
"Data directory (%s) must be an absolute path" : "Κατάλογος δεδομένων (%s) πρεπει να είναι απόλυτη η διαδρομή",
diff --git a/lib/l10n/el.json b/lib/l10n/el.json
index 33a6abe2494..f5976188506 100644
--- a/lib/l10n/el.json
+++ b/lib/l10n/el.json
@@ -108,7 +108,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Ο διαμοιρασμός του %s απέτυχε, γιατί το αρχείο δεν βρέθηκε στην προσωρινή αποθήκευση αρχείων",
"Could not find category \"%s\"" : "Αδυναμία εύρεσης κατηγορίας \"%s\"",
"Apps" : "Εφαρμογές",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Μόνο οι παρακάτων χαρακτήρες επιτρέπονται σε ένα όνομα χρήστη: \"a-z\", \"A-Z\", \"0-9\" και \"_.@-\"",
"A valid username must be provided" : "Πρέπει να δοθεί έγκυρο όνομα χρήστη",
"A valid password must be provided" : "Πρέπει να δοθεί έγκυρο συνθηματικό",
"The username is already being used" : "Το όνομα χρήστη είναι κατειλημμένο",
@@ -135,8 +134,6 @@
"Please ask your server administrator to restart the web server." : "Παρακαλώ ζητήστε από το διαχειριστή του διακομιστή σας να επανεκκινήσει το διακομιστή δικτύου σας.",
"PostgreSQL >= 9 required" : "Απαιτείται PostgreSQL >= 9",
"Please upgrade your database version" : "Παρακαλώ αναβαθμίστε την έκδοση της βάσης δεδομένων σας",
- "Error occurred while checking PostgreSQL version" : "Προέκυψε σφάλμα κατά τον έλεγχο της έκδοσης PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Παρακαλώ ελέγξτε ότι έχετε PostgreSQL >= 9 ή ελέγξτε στα ιστορικό σφαλμάτων για περισσότερες πληροφορίες για το σφάλμα",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Παρακαλώ αλλάξτε τις ρυθμίσεις σε 0770 έτσι ώστε ο κατάλογος να μην μπορεί να προβάλλεται από άλλους χρήστες.",
"Data directory (%s) is readable by other users" : "Ο κατάλογος δεδομένων (%s) είναι διαθέσιμος προς ανάγνωση για άλλους χρήστες",
"Data directory (%s) must be an absolute path" : "Κατάλογος δεδομένων (%s) πρεπει να είναι απόλυτη η διαδρομή",
diff --git a/lib/l10n/en_GB.js b/lib/l10n/en_GB.js
index 1ea5f9ef3ed..a36477d2d2a 100644
--- a/lib/l10n/en_GB.js
+++ b/lib/l10n/en_GB.js
@@ -105,7 +105,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Sharing %s failed, because the file could not be found in the file cache",
"Could not find category \"%s\"" : "Could not find category \"%s\"",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "A valid username must be provided",
"A valid password must be provided" : "A valid password must be provided",
"The username is already being used" : "The username is already being used",
@@ -132,8 +131,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Please ask your server administrator to restart the web server.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 required",
"Please upgrade your database version" : "Please upgrade your database version",
- "Error occurred while checking PostgreSQL version" : "Error occurred while checking PostgreSQL version",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Please change the permissions to 0770 so that the directory cannot be listed by other users.",
"Data directory (%s) is readable by other users" : "Data directory (%s) is readable by other users",
"Data directory (%s) must be an absolute path" : "Data directory (%s) must be an absolute path",
diff --git a/lib/l10n/en_GB.json b/lib/l10n/en_GB.json
index ddc0cb947e4..b5785acef58 100644
--- a/lib/l10n/en_GB.json
+++ b/lib/l10n/en_GB.json
@@ -103,7 +103,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Sharing %s failed, because the file could not be found in the file cache",
"Could not find category \"%s\"" : "Could not find category \"%s\"",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "A valid username must be provided",
"A valid password must be provided" : "A valid password must be provided",
"The username is already being used" : "The username is already being used",
@@ -130,8 +129,6 @@
"Please ask your server administrator to restart the web server." : "Please ask your server administrator to restart the web server.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 required",
"Please upgrade your database version" : "Please upgrade your database version",
- "Error occurred while checking PostgreSQL version" : "Error occurred while checking PostgreSQL version",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Please change the permissions to 0770 so that the directory cannot be listed by other users.",
"Data directory (%s) is readable by other users" : "Data directory (%s) is readable by other users",
"Data directory (%s) must be an absolute path" : "Data directory (%s) must be an absolute path",
diff --git a/lib/l10n/eo.js b/lib/l10n/eo.js
index b69c0836197..a19f1d51d14 100644
--- a/lib/l10n/eo.js
+++ b/lib/l10n/eo.js
@@ -57,7 +57,6 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Kunhavigo de %s malsukcesis, ĉar rekunhavigo ne permesatas",
"Could not find category \"%s\"" : "Ne troviĝis kategorio “%s”",
"Apps" : "Aplikaĵoj",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Nur la jenaj signoj permesatas en uzantonomo: «a-z», «A-Z», «0-9» kaj «_.@-»",
"A valid username must be provided" : "Valida uzantonomo devas proviziĝi",
"A valid password must be provided" : "Valida pasvorto devas proviziĝi",
"The username is already being used" : "La uzantonomo jam uzatas",
@@ -70,7 +69,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Bonvolu peti viajn serviladministranton, ke ŝi/li reekfunkciigu la TTT-servilon.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 necesas",
"Please upgrade your database version" : "Bonvolu ĝisdatigi la eldonon de via datumbazo",
- "Error occurred while checking PostgreSQL version" : "Eraro okazis dum kontrolo de eldono de PostgreSQL",
"Data directory (%s) is readable by other users" : "Dosierujo de datumoj (%s) legeblas de aliaj uzantoj",
"Data directory (%s) must be an absolute path" : "Dosierujo de datumoj (%s) devas specifiĝi per absoluta vojo",
"Data directory (%s) is invalid" : "Dosierujo de datumoj (%s) ne validas"
diff --git a/lib/l10n/eo.json b/lib/l10n/eo.json
index 37558aef9e2..439b4f83f54 100644
--- a/lib/l10n/eo.json
+++ b/lib/l10n/eo.json
@@ -55,7 +55,6 @@
"Sharing %s failed, because resharing is not allowed" : "Kunhavigo de %s malsukcesis, ĉar rekunhavigo ne permesatas",
"Could not find category \"%s\"" : "Ne troviĝis kategorio “%s”",
"Apps" : "Aplikaĵoj",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Nur la jenaj signoj permesatas en uzantonomo: «a-z», «A-Z», «0-9» kaj «_.@-»",
"A valid username must be provided" : "Valida uzantonomo devas proviziĝi",
"A valid password must be provided" : "Valida pasvorto devas proviziĝi",
"The username is already being used" : "La uzantonomo jam uzatas",
@@ -68,7 +67,6 @@
"Please ask your server administrator to restart the web server." : "Bonvolu peti viajn serviladministranton, ke ŝi/li reekfunkciigu la TTT-servilon.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 necesas",
"Please upgrade your database version" : "Bonvolu ĝisdatigi la eldonon de via datumbazo",
- "Error occurred while checking PostgreSQL version" : "Eraro okazis dum kontrolo de eldono de PostgreSQL",
"Data directory (%s) is readable by other users" : "Dosierujo de datumoj (%s) legeblas de aliaj uzantoj",
"Data directory (%s) must be an absolute path" : "Dosierujo de datumoj (%s) devas specifiĝi per absoluta vojo",
"Data directory (%s) is invalid" : "Dosierujo de datumoj (%s) ne validas"
diff --git a/lib/l10n/es.js b/lib/l10n/es.js
index 3eb2e71a7d4..4a2613507f6 100644
--- a/lib/l10n/es.js
+++ b/lib/l10n/es.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Los ficheros de tipo %s no son soportados",
"Failed to open archive when installing app" : "Falló la apertura ded fichero mientras se instalaba la aplicación",
"App does not provide an info.xml file" : "La aplicación no suministra un fichero info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "La firma no pudo ser evaluada. Por favor, contacte con el desarrollador de la aplicación y compruebe su pantalla de administración.",
"App can't be installed because of not allowed code in the App" : "La aplicación no puede ser instalada por tener código no autorizado en la aplicación",
"App can't be installed because it is not compatible with this version of ownCloud" : "La aplicación no se puede instalar porque no es compatible con esta versión de ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "La aplicación no se puede instalar porque contiene la etiqueta\n<shipped>\ntrue\n</shipped>\nque no está permitida para aplicaciones no distribuidas",
@@ -87,6 +88,7 @@ OC.L10N.register(
"Sharing %s failed, because the backend does not allow shares from type %i" : "No se pudo compartir %s porque el repositorio no permite recursos compartidos del tipo %i",
"Sharing %s failed, because the file does not exist" : "No se pudo compartir %s porque el archivo no existe",
"You are not allowed to share %s" : "Usted no está autorizado para compartir %s",
+ "Sharing %s failed, because you can not share with yourself" : "Se falló al compartir %s, porque no puedes compartir contigo mismo",
"Sharing %s failed, because the user %s does not exist" : "Se ha fallado al compartir %s, ya que el usuario %s no existe",
"Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" : "Se ha fallado al compartir %s, ya que el usuario %s no es miembro de ningún grupo del que %s sea miembro",
"Sharing %s failed, because this item is already shared with %s" : "Se falló al compartir %s, ya que este elemento ya está compartido con %s",
@@ -95,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Se falló al compartir %s, ya que %s no es miembro del grupo %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Es necesario definir una contraseña para crear un enlace publico. Solo los enlaces protegidos están permitidos",
"Sharing %s failed, because sharing with links is not allowed" : "Se falló al compartir %s, ya que no está permitida la compartición con enlaces",
+ "Not allowed to create a federated share with the same user" : "No se permite crear un recurso compartido federado con el mismo usuario",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Se falló al compartir %s. No se pudo hallar %s, quizás haya un problema de conexión con el servidor.",
"Share type %s is not valid for %s" : "Compartir tipo %s no es válido para %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "La configuración de permisos para %s ha fallado, ya que los permisos superan los permisos dados a %s",
@@ -105,13 +108,16 @@ OC.L10N.register(
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "El motor compartido %s debe implementar la interfaz OCP\\Share_Backend",
"Sharing backend %s not found" : "El motor compartido %s no se ha encontrado",
"Sharing backend for %s not found" : "Motor compartido para %s no encontrado",
+ "Sharing failed, because the user %s is the original sharer" : "Se ha fallado al compartir, ya que el usuario %s es el compartidor original",
"Sharing %s failed, because the permissions exceed permissions granted to %s" : "Se ha fallado al compartir %s, ya que los permisos superan los permisos otorgados a %s",
"Sharing %s failed, because resharing is not allowed" : "Se ha fallado al compartir %s, ya que volver a compartir no está permitido",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Se ha fallado al compartir %s porque el motor compartido para %s podría no encontrar su origen",
"Sharing %s failed, because the file could not be found in the file cache" : "Se ha fallado al compartir %s, ya que el archivo no pudo ser encontrado en el cache de archivo",
+ "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s",
+ "Expiration date is in the past" : "Ha pasado la fecha de caducidad",
+ "Cannot set expiration date more than %s days in the future" : "No se puede fijar la fecha de caducidad más de %s días en el futuro.",
"Could not find category \"%s\"" : "No puede encontrar la categoría \"%s\"",
"Apps" : "Aplicaciones",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Solo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido",
"A valid password must be provided" : "Se debe proporcionar una contraseña válida",
"The username is already being used" : "El nombre de usuario ya está en uso",
@@ -138,8 +144,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Consulte al administrador de su servidor para reiniciar el servidor web.",
"PostgreSQL >= 9 required" : "PostgreSQL 9 o superior requerido.",
"Please upgrade your database version" : "Actualice su versión de base de datos.",
- "Error occurred while checking PostgreSQL version" : "Ha ocurrido un error mientras se comprobaba la versión de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Por favor, asegúrese de que tiene PostgreSQL 9 o superior, o revise los registros para obtener más información acerca del error.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambie los permisos a 0770 para que el directorio no se pueda mostrar para otros usuarios.",
"Data directory (%s) is readable by other users" : "El directorio de datos (%s) se puede leer por otros usuarios.",
"Data directory (%s) must be an absolute path" : "El directorio de datos (%s) debe ser una ruta absoluta",
@@ -147,6 +151,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "El directorio de datos (%s) no es válido",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Verifique que el directorio de datos contiene un archivo \".ocdata\" en su directorio raíz.",
"Could not obtain lock type %d on \"%s\"." : "No se pudo realizar el bloqueo %d en \"%s\".",
- "Storage not available" : "Almacenamiento no disponible"
+ "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s",
+ "Storage incomplete configuration. %s" : "Configuración de almacenamiento incompleta. %s",
+ "Storage connection error. %s" : "Error de conexión de almacenamiento. %s",
+ "Storage not available" : "Almacenamiento no disponible",
+ "Storage connection timeout. %s" : "Tiempo de conexión de almacenamiento agotado. %s"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/es.json b/lib/l10n/es.json
index bbc50f2b5b8..9856bb9938f 100644
--- a/lib/l10n/es.json
+++ b/lib/l10n/es.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "Los ficheros de tipo %s no son soportados",
"Failed to open archive when installing app" : "Falló la apertura ded fichero mientras se instalaba la aplicación",
"App does not provide an info.xml file" : "La aplicación no suministra un fichero info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "La firma no pudo ser evaluada. Por favor, contacte con el desarrollador de la aplicación y compruebe su pantalla de administración.",
"App can't be installed because of not allowed code in the App" : "La aplicación no puede ser instalada por tener código no autorizado en la aplicación",
"App can't be installed because it is not compatible with this version of ownCloud" : "La aplicación no se puede instalar porque no es compatible con esta versión de ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "La aplicación no se puede instalar porque contiene la etiqueta\n<shipped>\ntrue\n</shipped>\nque no está permitida para aplicaciones no distribuidas",
@@ -85,6 +86,7 @@
"Sharing %s failed, because the backend does not allow shares from type %i" : "No se pudo compartir %s porque el repositorio no permite recursos compartidos del tipo %i",
"Sharing %s failed, because the file does not exist" : "No se pudo compartir %s porque el archivo no existe",
"You are not allowed to share %s" : "Usted no está autorizado para compartir %s",
+ "Sharing %s failed, because you can not share with yourself" : "Se falló al compartir %s, porque no puedes compartir contigo mismo",
"Sharing %s failed, because the user %s does not exist" : "Se ha fallado al compartir %s, ya que el usuario %s no existe",
"Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" : "Se ha fallado al compartir %s, ya que el usuario %s no es miembro de ningún grupo del que %s sea miembro",
"Sharing %s failed, because this item is already shared with %s" : "Se falló al compartir %s, ya que este elemento ya está compartido con %s",
@@ -93,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Se falló al compartir %s, ya que %s no es miembro del grupo %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Es necesario definir una contraseña para crear un enlace publico. Solo los enlaces protegidos están permitidos",
"Sharing %s failed, because sharing with links is not allowed" : "Se falló al compartir %s, ya que no está permitida la compartición con enlaces",
+ "Not allowed to create a federated share with the same user" : "No se permite crear un recurso compartido federado con el mismo usuario",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Se falló al compartir %s. No se pudo hallar %s, quizás haya un problema de conexión con el servidor.",
"Share type %s is not valid for %s" : "Compartir tipo %s no es válido para %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "La configuración de permisos para %s ha fallado, ya que los permisos superan los permisos dados a %s",
@@ -103,13 +106,16 @@
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "El motor compartido %s debe implementar la interfaz OCP\\Share_Backend",
"Sharing backend %s not found" : "El motor compartido %s no se ha encontrado",
"Sharing backend for %s not found" : "Motor compartido para %s no encontrado",
+ "Sharing failed, because the user %s is the original sharer" : "Se ha fallado al compartir, ya que el usuario %s es el compartidor original",
"Sharing %s failed, because the permissions exceed permissions granted to %s" : "Se ha fallado al compartir %s, ya que los permisos superan los permisos otorgados a %s",
"Sharing %s failed, because resharing is not allowed" : "Se ha fallado al compartir %s, ya que volver a compartir no está permitido",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Se ha fallado al compartir %s porque el motor compartido para %s podría no encontrar su origen",
"Sharing %s failed, because the file could not be found in the file cache" : "Se ha fallado al compartir %s, ya que el archivo no pudo ser encontrado en el cache de archivo",
+ "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s",
+ "Expiration date is in the past" : "Ha pasado la fecha de caducidad",
+ "Cannot set expiration date more than %s days in the future" : "No se puede fijar la fecha de caducidad más de %s días en el futuro.",
"Could not find category \"%s\"" : "No puede encontrar la categoría \"%s\"",
"Apps" : "Aplicaciones",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Solo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido",
"A valid password must be provided" : "Se debe proporcionar una contraseña válida",
"The username is already being used" : "El nombre de usuario ya está en uso",
@@ -136,8 +142,6 @@
"Please ask your server administrator to restart the web server." : "Consulte al administrador de su servidor para reiniciar el servidor web.",
"PostgreSQL >= 9 required" : "PostgreSQL 9 o superior requerido.",
"Please upgrade your database version" : "Actualice su versión de base de datos.",
- "Error occurred while checking PostgreSQL version" : "Ha ocurrido un error mientras se comprobaba la versión de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Por favor, asegúrese de que tiene PostgreSQL 9 o superior, o revise los registros para obtener más información acerca del error.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambie los permisos a 0770 para que el directorio no se pueda mostrar para otros usuarios.",
"Data directory (%s) is readable by other users" : "El directorio de datos (%s) se puede leer por otros usuarios.",
"Data directory (%s) must be an absolute path" : "El directorio de datos (%s) debe ser una ruta absoluta",
@@ -145,6 +149,10 @@
"Data directory (%s) is invalid" : "El directorio de datos (%s) no es válido",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Verifique que el directorio de datos contiene un archivo \".ocdata\" en su directorio raíz.",
"Could not obtain lock type %d on \"%s\"." : "No se pudo realizar el bloqueo %d en \"%s\".",
- "Storage not available" : "Almacenamiento no disponible"
+ "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s",
+ "Storage incomplete configuration. %s" : "Configuración de almacenamiento incompleta. %s",
+ "Storage connection error. %s" : "Error de conexión de almacenamiento. %s",
+ "Storage not available" : "Almacenamiento no disponible",
+ "Storage connection timeout. %s" : "Tiempo de conexión de almacenamiento agotado. %s"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/es_AR.js b/lib/l10n/es_AR.js
index 58c5f473851..aff2406c699 100644
--- a/lib/l10n/es_AR.js
+++ b/lib/l10n/es_AR.js
@@ -1,6 +1,7 @@
OC.L10N.register(
"lib",
{
+ "Cannot write into \"config\" directory!" : "¡No se puede escribir en el directorio \"config\"!",
"Help" : "Ayuda",
"Personal" : "Personal",
"Users" : "Usuarios",
@@ -48,6 +49,7 @@ OC.L10N.register(
"Could not find category \"%s\"" : "No fue posible encontrar la categoría \"%s\"",
"Apps" : "Apps",
"A valid username must be provided" : "Debe ingresar un nombre de usuario válido",
- "A valid password must be provided" : "Debe ingresar una contraseña válida"
+ "A valid password must be provided" : "Debe ingresar una contraseña válida",
+ "Storage not available" : "Almacenamiento no disponible"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/es_AR.json b/lib/l10n/es_AR.json
index 605aecb1ab1..4cbbb8ad93f 100644
--- a/lib/l10n/es_AR.json
+++ b/lib/l10n/es_AR.json
@@ -1,4 +1,5 @@
{ "translations": {
+ "Cannot write into \"config\" directory!" : "¡No se puede escribir en el directorio \"config\"!",
"Help" : "Ayuda",
"Personal" : "Personal",
"Users" : "Usuarios",
@@ -46,6 +47,7 @@
"Could not find category \"%s\"" : "No fue posible encontrar la categoría \"%s\"",
"Apps" : "Apps",
"A valid username must be provided" : "Debe ingresar un nombre de usuario válido",
- "A valid password must be provided" : "Debe ingresar una contraseña válida"
+ "A valid password must be provided" : "Debe ingresar una contraseña válida",
+ "Storage not available" : "Almacenamiento no disponible"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/et_EE.js b/lib/l10n/et_EE.js
index d2146e8af30..397114f5886 100644
--- a/lib/l10n/et_EE.js
+++ b/lib/l10n/et_EE.js
@@ -33,6 +33,7 @@ OC.L10N.register(
"web services under your control" : "veebitenused sinu kontrolli all",
"Empty filename is not allowed" : "Tühi failinimi pole lubatud",
"Dot files are not allowed" : "Punktiga failid pole lubatud",
+ "File name is a reserved word" : "Failinimi sisaldab keelatud sõna",
"File name contains at least one invalid character" : "Faili nimesonvähemalt üks keelatud märk",
"File name is too long" : "Faili nimi on liiga pikk",
"Can't read file" : "Faili lugemine ebaõnnestus",
@@ -93,7 +94,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "%s jagamine ebaõnnestus, kuna faili ei suudetud leida failide puhvrist",
"Could not find category \"%s\"" : "Ei leia kategooriat \"%s\"",
"Apps" : "Rakendused",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Kasutajanimes on lubatud ainult järgnevad tähemärgid: \"a-z\", \"A-Z\", \"0-9\" ja \"_.@-\"",
"A valid username must be provided" : "Sisesta nõuetele vastav kasutajatunnus",
"A valid password must be provided" : "Sisesta nõuetele vastav parool",
"The username is already being used" : "Kasutajanimi on juba kasutuses",
@@ -114,8 +114,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Palu oma serveri haldajal veebiserver taaskäivitada.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 on nõutav",
"Please upgrade your database version" : "Palun uuenda oma andmebaasi versiooni",
- "Error occurred while checking PostgreSQL version" : "Viga PostgreSQL versiooni kontrollimisel",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Palun veendu, et kasutad PostgreSQL >=9 või vaata logidest vea kohta detailsemat informatsiooni",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Palun muuda kataloogi õigused 0770-ks, et kataloogi sisu poleks teistele kasutajatele nähtav",
"Data directory (%s) is readable by other users" : "Andmete kataloog (%s) on teistele kasutajate loetav",
"Data directory (%s) is invalid" : "Andmete kataloog (%s) pole korrektne",
diff --git a/lib/l10n/et_EE.json b/lib/l10n/et_EE.json
index 6c223ecfa4f..3716cc59f51 100644
--- a/lib/l10n/et_EE.json
+++ b/lib/l10n/et_EE.json
@@ -31,6 +31,7 @@
"web services under your control" : "veebitenused sinu kontrolli all",
"Empty filename is not allowed" : "Tühi failinimi pole lubatud",
"Dot files are not allowed" : "Punktiga failid pole lubatud",
+ "File name is a reserved word" : "Failinimi sisaldab keelatud sõna",
"File name contains at least one invalid character" : "Faili nimesonvähemalt üks keelatud märk",
"File name is too long" : "Faili nimi on liiga pikk",
"Can't read file" : "Faili lugemine ebaõnnestus",
@@ -91,7 +92,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "%s jagamine ebaõnnestus, kuna faili ei suudetud leida failide puhvrist",
"Could not find category \"%s\"" : "Ei leia kategooriat \"%s\"",
"Apps" : "Rakendused",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Kasutajanimes on lubatud ainult järgnevad tähemärgid: \"a-z\", \"A-Z\", \"0-9\" ja \"_.@-\"",
"A valid username must be provided" : "Sisesta nõuetele vastav kasutajatunnus",
"A valid password must be provided" : "Sisesta nõuetele vastav parool",
"The username is already being used" : "Kasutajanimi on juba kasutuses",
@@ -112,8 +112,6 @@
"Please ask your server administrator to restart the web server." : "Palu oma serveri haldajal veebiserver taaskäivitada.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 on nõutav",
"Please upgrade your database version" : "Palun uuenda oma andmebaasi versiooni",
- "Error occurred while checking PostgreSQL version" : "Viga PostgreSQL versiooni kontrollimisel",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Palun veendu, et kasutad PostgreSQL >=9 või vaata logidest vea kohta detailsemat informatsiooni",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Palun muuda kataloogi õigused 0770-ks, et kataloogi sisu poleks teistele kasutajatele nähtav",
"Data directory (%s) is readable by other users" : "Andmete kataloog (%s) on teistele kasutajate loetav",
"Data directory (%s) is invalid" : "Andmete kataloog (%s) pole korrektne",
diff --git a/lib/l10n/eu.js b/lib/l10n/eu.js
index 7b69f456692..43e4e35f258 100644
--- a/lib/l10n/eu.js
+++ b/lib/l10n/eu.js
@@ -93,7 +93,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "%s elkarbanatzeak huts egin du, fitxategia katxean aurkitu ez delako",
"Could not find category \"%s\"" : "Ezin da \"%s\" kategoria aurkitu",
"Apps" : "Aplikazioak",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Bakarrik hurrengo karaketerak onartzen dira erabiltzaile izenean: \"a-z\", \"A-Z\", \"0-9\", eta \"_.@-\"",
"A valid username must be provided" : "Baliozko erabiltzaile izena eman behar da",
"A valid password must be provided" : "Baliozko pasahitza eman behar da",
"The username is already being used" : "Erabiltzaile izena dagoeneko erabiltzen ari da",
@@ -113,8 +112,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Mesedez eskatu zerbitzariaren kudeatzaileari web zerbitzaria berrabiarazteko.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 behar da",
"Please upgrade your database version" : "Mesedez eguneratu zure datu basearen bertsioa",
- "Error occurred while checking PostgreSQL version" : "Errore bat gertatu da PostgreSQLren bertsioa egiaztatzerakoan",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Mesedez ziurtatu PostgreSQL >= 9 duzula edo begiratu logak erroreari buruzko informazio gehiago lortzeko",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Mesedez aldatu baimenak 0770ra beste erabiltzaileek karpetan sartu ezin izateko.",
"Data directory (%s) is readable by other users" : "Data karpeta (%s) beste erabiltzaileek irakur dezakete",
"Data directory (%s) is invalid" : "Datuen karpeta (%s) ez da baliogarria",
diff --git a/lib/l10n/eu.json b/lib/l10n/eu.json
index 591c31869ab..6e104c0fdc2 100644
--- a/lib/l10n/eu.json
+++ b/lib/l10n/eu.json
@@ -91,7 +91,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "%s elkarbanatzeak huts egin du, fitxategia katxean aurkitu ez delako",
"Could not find category \"%s\"" : "Ezin da \"%s\" kategoria aurkitu",
"Apps" : "Aplikazioak",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Bakarrik hurrengo karaketerak onartzen dira erabiltzaile izenean: \"a-z\", \"A-Z\", \"0-9\", eta \"_.@-\"",
"A valid username must be provided" : "Baliozko erabiltzaile izena eman behar da",
"A valid password must be provided" : "Baliozko pasahitza eman behar da",
"The username is already being used" : "Erabiltzaile izena dagoeneko erabiltzen ari da",
@@ -111,8 +110,6 @@
"Please ask your server administrator to restart the web server." : "Mesedez eskatu zerbitzariaren kudeatzaileari web zerbitzaria berrabiarazteko.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 behar da",
"Please upgrade your database version" : "Mesedez eguneratu zure datu basearen bertsioa",
- "Error occurred while checking PostgreSQL version" : "Errore bat gertatu da PostgreSQLren bertsioa egiaztatzerakoan",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Mesedez ziurtatu PostgreSQL >= 9 duzula edo begiratu logak erroreari buruzko informazio gehiago lortzeko",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Mesedez aldatu baimenak 0770ra beste erabiltzaileek karpetan sartu ezin izateko.",
"Data directory (%s) is readable by other users" : "Data karpeta (%s) beste erabiltzaileek irakur dezakete",
"Data directory (%s) is invalid" : "Datuen karpeta (%s) ez da baliogarria",
diff --git a/lib/l10n/fa.js b/lib/l10n/fa.js
index 950b37e631f..4e4d33d0ace 100644
--- a/lib/l10n/fa.js
+++ b/lib/l10n/fa.js
@@ -70,7 +70,6 @@ OC.L10N.register(
"PHP module %s not installed." : "ماژول PHP %s نصب نشده است.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 نیاز است",
"Please upgrade your database version" : "لطفا نسخه‌ی پایگاه‌داده‌ی خود را بروز کنید",
- "Error occurred while checking PostgreSQL version" : "خطا در هنگام بررسی نسخه‌ی PostgreSQL",
"Storage not available" : "فضای ذخیره سازی موجود نیست"
},
"nplurals=1; plural=0;");
diff --git a/lib/l10n/fa.json b/lib/l10n/fa.json
index 2f6270c7e7a..4ca821758dc 100644
--- a/lib/l10n/fa.json
+++ b/lib/l10n/fa.json
@@ -68,7 +68,6 @@
"PHP module %s not installed." : "ماژول PHP %s نصب نشده است.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 نیاز است",
"Please upgrade your database version" : "لطفا نسخه‌ی پایگاه‌داده‌ی خود را بروز کنید",
- "Error occurred while checking PostgreSQL version" : "خطا در هنگام بررسی نسخه‌ی PostgreSQL",
"Storage not available" : "فضای ذخیره سازی موجود نیست"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/lib/l10n/fi_FI.js b/lib/l10n/fi_FI.js
index c932fa35d60..2d9bd6f681d 100644
--- a/lib/l10n/fi_FI.js
+++ b/lib/l10n/fi_FI.js
@@ -54,6 +54,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Tyypin %s arkistot eivät ole tuettuja",
"Failed to open archive when installing app" : "Pakettitiedoston avaaminen epäonnistui sovellusta asennettaessa",
"App does not provide an info.xml file" : "Sovellus ei sisällä info.xml-tiedostoa",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Allekirjoituksen tarkistaminen ei onnistunut. Ota yhteys sovelluskehittäjään ja tarkista ylläpitonäkymä.",
"App can't be installed because of not allowed code in the App" : "Sovellusta ei voi asentaa, koska sovellus sisältää kiellettyä koodia",
"App can't be installed because it is not compatible with this version of ownCloud" : "Sovellusta ei voi asentaa, koska se ei ole yhteensopiva käytössä olevan ownCloud-version kanssa",
"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" : "Sovellusta ei voi asentaa, koska info.xml/version ilmoittaa versioksi eri arvon kuin sovelluskauppa",
@@ -87,6 +88,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Kohteen %s jakaminen epäonnistui, koska käyttäjä %s ei ole ryhmän %s jäsen",
"You need to provide a password to create a public link, only protected links are allowed" : "Anna salasana luodaksesi julkisen linkin. Vain suojatut linkit ovat sallittuja",
"Sharing %s failed, because sharing with links is not allowed" : "Kohteen %s jakaminen epäonnistui, koska jakaminen linkkejä käyttäen ei ole sallittu",
+ "Not allowed to create a federated share with the same user" : "Saman käyttäjän kanssa ei ole sallittua luoda federoitua jakoa",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Kohteen %s jakaminen epäonnistui, kohdetta %s ei löytynyt. Kenties palvelin ei ole juuri nyt tavoitettavissa.",
"Setting permissions for %s failed, because the item was not found" : "Kohteen %s oikeuksien asettaminen epäonnistui, koska kohdetta ei löytynyt",
"Cannot set expiration date. Expiration date is in the past" : "Vanhentumispäivää ei voi asettaa. Vanhentumispäivä on jo mennyt",
@@ -96,9 +98,12 @@ OC.L10N.register(
"Sharing failed, because the user %s is the original sharer" : "Jakaminen epäonnistui, koska käyttäjä %s ei ole alkuperäinen jakaja",
"Sharing %s failed, because resharing is not allowed" : "Kohteen %s jakaminen epäonnistui, koska jakaminen uudelleen ei ole sallittu",
"Sharing %s failed, because the file could not be found in the file cache" : "Kohteen %s jakaminen epäonnistui, koska tiedostoa ei löytynyt tiedostovälimuistista",
+ "Cannot increase permissions of %s" : "Kohteen %s käyttöoikeuksien lisääminen ei onnistu",
+ "Expiration date is in the past" : "Vanhenemispäivä on menneisyydessä",
+ "Cannot set expiration date more than %s days in the future" : "Vanhenemispäivä voi olla korkeintaan %s päivän päässä tulevaisuudessa",
"Could not find category \"%s\"" : "Luokkaa \"%s\" ei löytynyt",
"Apps" : "Sovellukset",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\" ja \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\" ja \"_.@-'\"",
"A valid username must be provided" : "Anna kelvollinen käyttäjätunnus",
"A valid password must be provided" : "Anna kelvollinen salasana",
"The username is already being used" : "Käyttäjätunnus on jo käytössä",
@@ -122,14 +127,16 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Pyydä palvelimen ylläpitäjää käynnistämään web-palvelin uudelleen.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 vaaditaan",
"Please upgrade your database version" : "Päivitä tietokantasi versio",
- "Error occurred while checking PostgreSQL version" : "Virhe PostgreSQL:n versiota tarkistaessa",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Varmista, että käytössäsi on PostgreSQL >= 9 tai tarkista lokit saadaksesi lisätietoja virheestä",
"Data directory (%s) is readable by other users" : "Datakansio (%s) on muiden käyttäjien luettavissa",
"Data directory (%s) must be an absolute path" : "Datahakemiston (%s) tulee olla absoluuttinen polku",
"Check the value of \"datadirectory\" in your configuration" : "Tarkista \"datadirectory\"-arvo asetuksistasi",
"Data directory (%s) is invalid" : "Datakansio (%s) on virheellinen",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Varmista, että datakansion juuressa on tiedosto \".ocdata\".",
"Could not obtain lock type %d on \"%s\"." : "Lukitustapaa %d ei saatu kohteelle \"%s\".",
- "Storage not available" : "Tallennustila ei ole käytettävissä"
+ "Storage unauthorized. %s" : "Tallennustila ei ole valtuutettu. %s",
+ "Storage incomplete configuration. %s" : "Tallennustilan puutteellinen määritys. %s",
+ "Storage connection error. %s" : "Tallennustilan yhteysvirhe. %s",
+ "Storage not available" : "Tallennustila ei ole käytettävissä",
+ "Storage connection timeout. %s" : "Tallennustilan yhteyden aikakatkaisu. %s"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/fi_FI.json b/lib/l10n/fi_FI.json
index 55209ee0b72..31ef261b6c9 100644
--- a/lib/l10n/fi_FI.json
+++ b/lib/l10n/fi_FI.json
@@ -52,6 +52,7 @@
"Archives of type %s are not supported" : "Tyypin %s arkistot eivät ole tuettuja",
"Failed to open archive when installing app" : "Pakettitiedoston avaaminen epäonnistui sovellusta asennettaessa",
"App does not provide an info.xml file" : "Sovellus ei sisällä info.xml-tiedostoa",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Allekirjoituksen tarkistaminen ei onnistunut. Ota yhteys sovelluskehittäjään ja tarkista ylläpitonäkymä.",
"App can't be installed because of not allowed code in the App" : "Sovellusta ei voi asentaa, koska sovellus sisältää kiellettyä koodia",
"App can't be installed because it is not compatible with this version of ownCloud" : "Sovellusta ei voi asentaa, koska se ei ole yhteensopiva käytössä olevan ownCloud-version kanssa",
"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" : "Sovellusta ei voi asentaa, koska info.xml/version ilmoittaa versioksi eri arvon kuin sovelluskauppa",
@@ -85,6 +86,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Kohteen %s jakaminen epäonnistui, koska käyttäjä %s ei ole ryhmän %s jäsen",
"You need to provide a password to create a public link, only protected links are allowed" : "Anna salasana luodaksesi julkisen linkin. Vain suojatut linkit ovat sallittuja",
"Sharing %s failed, because sharing with links is not allowed" : "Kohteen %s jakaminen epäonnistui, koska jakaminen linkkejä käyttäen ei ole sallittu",
+ "Not allowed to create a federated share with the same user" : "Saman käyttäjän kanssa ei ole sallittua luoda federoitua jakoa",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Kohteen %s jakaminen epäonnistui, kohdetta %s ei löytynyt. Kenties palvelin ei ole juuri nyt tavoitettavissa.",
"Setting permissions for %s failed, because the item was not found" : "Kohteen %s oikeuksien asettaminen epäonnistui, koska kohdetta ei löytynyt",
"Cannot set expiration date. Expiration date is in the past" : "Vanhentumispäivää ei voi asettaa. Vanhentumispäivä on jo mennyt",
@@ -94,9 +96,12 @@
"Sharing failed, because the user %s is the original sharer" : "Jakaminen epäonnistui, koska käyttäjä %s ei ole alkuperäinen jakaja",
"Sharing %s failed, because resharing is not allowed" : "Kohteen %s jakaminen epäonnistui, koska jakaminen uudelleen ei ole sallittu",
"Sharing %s failed, because the file could not be found in the file cache" : "Kohteen %s jakaminen epäonnistui, koska tiedostoa ei löytynyt tiedostovälimuistista",
+ "Cannot increase permissions of %s" : "Kohteen %s käyttöoikeuksien lisääminen ei onnistu",
+ "Expiration date is in the past" : "Vanhenemispäivä on menneisyydessä",
+ "Cannot set expiration date more than %s days in the future" : "Vanhenemispäivä voi olla korkeintaan %s päivän päässä tulevaisuudessa",
"Could not find category \"%s\"" : "Luokkaa \"%s\" ei löytynyt",
"Apps" : "Sovellukset",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\" ja \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\" ja \"_.@-'\"",
"A valid username must be provided" : "Anna kelvollinen käyttäjätunnus",
"A valid password must be provided" : "Anna kelvollinen salasana",
"The username is already being used" : "Käyttäjätunnus on jo käytössä",
@@ -120,14 +125,16 @@
"Please ask your server administrator to restart the web server." : "Pyydä palvelimen ylläpitäjää käynnistämään web-palvelin uudelleen.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 vaaditaan",
"Please upgrade your database version" : "Päivitä tietokantasi versio",
- "Error occurred while checking PostgreSQL version" : "Virhe PostgreSQL:n versiota tarkistaessa",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Varmista, että käytössäsi on PostgreSQL >= 9 tai tarkista lokit saadaksesi lisätietoja virheestä",
"Data directory (%s) is readable by other users" : "Datakansio (%s) on muiden käyttäjien luettavissa",
"Data directory (%s) must be an absolute path" : "Datahakemiston (%s) tulee olla absoluuttinen polku",
"Check the value of \"datadirectory\" in your configuration" : "Tarkista \"datadirectory\"-arvo asetuksistasi",
"Data directory (%s) is invalid" : "Datakansio (%s) on virheellinen",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Varmista, että datakansion juuressa on tiedosto \".ocdata\".",
"Could not obtain lock type %d on \"%s\"." : "Lukitustapaa %d ei saatu kohteelle \"%s\".",
- "Storage not available" : "Tallennustila ei ole käytettävissä"
+ "Storage unauthorized. %s" : "Tallennustila ei ole valtuutettu. %s",
+ "Storage incomplete configuration. %s" : "Tallennustilan puutteellinen määritys. %s",
+ "Storage connection error. %s" : "Tallennustilan yhteysvirhe. %s",
+ "Storage not available" : "Tallennustila ei ole käytettävissä",
+ "Storage connection timeout. %s" : "Tallennustilan yhteyden aikakatkaisu. %s"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/fr.js b/lib/l10n/fr.js
index e0ac89cbec8..d59fea314e3 100644
--- a/lib/l10n/fr.js
+++ b/lib/l10n/fr.js
@@ -55,6 +55,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Les archives de type %s ne sont pas prises en charge",
"Failed to open archive when installing app" : "Échec de l'ouverture de l'archive lors de l'installation de l'application",
"App does not provide an info.xml file" : "L'application ne fournit pas de fichier info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "La signature n'a pas pu être vérifiée. Merci de contacter le développeur de l'application et de vérifier votre page d'administration.",
"App can't be installed because of not allowed code in the App" : "L'application ne peut être installée car elle contient du code non-autorisé",
"App can't be installed because it is not compatible with this version of ownCloud" : "L'application ne peut être installée car elle n'est pas compatible avec cette version de ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "L'application ne peut être installée car elle contient la balise <shipped>true</shipped> qui n'est pas autorisée pour les applications non incluses par défaut",
@@ -95,6 +96,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Le partage de %s a échoué car %s n'est pas membre du groupe %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Vous devez fournir un mot de passe pour créer un lien public, seuls les liens protégés sont autorisées.",
"Sharing %s failed, because sharing with links is not allowed" : "Le partage de %s a échoué car le partage par lien n'est pas permis",
+ "Not allowed to create a federated share with the same user" : "Non autorisé à créer un partage fédéré avec le même utilisateur",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Le partage de %s a échoué : impossible de trouver %s. Peut-être le serveur est-il momentanément injoignable.",
"Share type %s is not valid for %s" : "Le type de partage %s n'est pas valide pour %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Le réglage des permissions pour %s a échoué car les permissions dépassent celles accordées à %s",
@@ -110,9 +112,12 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Le partage de %s a échoué car le repartage n'est pas autorisé",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Le partage de %s a échoué car le service %s n'a pas trouvé sa source..",
"Sharing %s failed, because the file could not be found in the file cache" : "Le partage de %s a échoué car le fichier n'a pas été trouvé dans les fichiers mis en cache.",
+ "Cannot increase permissions of %s" : "Impossible d'augmenter les permissions de %s",
+ "Expiration date is in the past" : "La date d'expiration est dans le passé",
+ "Cannot set expiration date more than %s days in the future" : "Impossible de définir la date d'expiration à plus de %s jours dans le futur",
"Could not find category \"%s\"" : "Impossible de trouver la catégorie \"%s\"",
"Apps" : "Applications",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", et \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", et \"_.@-'\"",
"A valid username must be provided" : "Un nom d'utilisateur valide doit être saisi",
"A valid password must be provided" : "Un mot de passe valide doit être saisi",
"The username is already being used" : "Ce nom d'utilisateur est déjà utilisé",
@@ -139,15 +144,17 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Veuillez demander à votre administrateur serveur de redémarrer le serveur web.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 requis",
"Please upgrade your database version" : "Veuillez mettre à jour votre gestionnaire de base de données",
- "Error occurred while checking PostgreSQL version" : "Une erreur s’est produite pendant la récupération du numéro de version de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Veuillez vérifier que vous utilisez PostgreSQL >= 9 , ou regardez dans le journal d’erreur pour plus d’informations sur ce problème",
- "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu puisse être listé par les autres utilisateurs.",
+ "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu ne puisse pas être listé par les autres utilisateurs.",
"Data directory (%s) is readable by other users" : "Le répertoire de données (%s) est lisible par les autres utilisateurs",
"Data directory (%s) must be an absolute path" : "Le chemin du dossier de données (%s) doit être absolu",
"Check the value of \"datadirectory\" in your configuration" : "Verifiez la valeur de \"datadirectory\" dans votre configuration",
"Data directory (%s) is invalid" : "Le répertoire (%s) n'est pas valide",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Veuillez vérifier que le répertoire de données contient un fichier \".ocdata\" à sa racine.",
"Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur \"%s\".",
- "Storage not available" : "Support de stockage non disponible"
+ "Storage unauthorized. %s" : "Espace de stockage non autorisé. %s",
+ "Storage incomplete configuration. %s" : "Configuration de l'espace de stockage incomplète. %s",
+ "Storage connection error. %s" : "Erreur de connexion à l'espace stockage. %s",
+ "Storage not available" : "Support de stockage non disponible",
+ "Storage connection timeout. %s" : "Le délai d'attente pour la connexion à l'espace de stockage a été dépassé. %s"
},
"nplurals=2; plural=(n > 1);");
diff --git a/lib/l10n/fr.json b/lib/l10n/fr.json
index 2d74c986a50..21ed66eb278 100644
--- a/lib/l10n/fr.json
+++ b/lib/l10n/fr.json
@@ -53,6 +53,7 @@
"Archives of type %s are not supported" : "Les archives de type %s ne sont pas prises en charge",
"Failed to open archive when installing app" : "Échec de l'ouverture de l'archive lors de l'installation de l'application",
"App does not provide an info.xml file" : "L'application ne fournit pas de fichier info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "La signature n'a pas pu être vérifiée. Merci de contacter le développeur de l'application et de vérifier votre page d'administration.",
"App can't be installed because of not allowed code in the App" : "L'application ne peut être installée car elle contient du code non-autorisé",
"App can't be installed because it is not compatible with this version of ownCloud" : "L'application ne peut être installée car elle n'est pas compatible avec cette version de ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "L'application ne peut être installée car elle contient la balise <shipped>true</shipped> qui n'est pas autorisée pour les applications non incluses par défaut",
@@ -93,6 +94,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Le partage de %s a échoué car %s n'est pas membre du groupe %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Vous devez fournir un mot de passe pour créer un lien public, seuls les liens protégés sont autorisées.",
"Sharing %s failed, because sharing with links is not allowed" : "Le partage de %s a échoué car le partage par lien n'est pas permis",
+ "Not allowed to create a federated share with the same user" : "Non autorisé à créer un partage fédéré avec le même utilisateur",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Le partage de %s a échoué : impossible de trouver %s. Peut-être le serveur est-il momentanément injoignable.",
"Share type %s is not valid for %s" : "Le type de partage %s n'est pas valide pour %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Le réglage des permissions pour %s a échoué car les permissions dépassent celles accordées à %s",
@@ -108,9 +110,12 @@
"Sharing %s failed, because resharing is not allowed" : "Le partage de %s a échoué car le repartage n'est pas autorisé",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Le partage de %s a échoué car le service %s n'a pas trouvé sa source..",
"Sharing %s failed, because the file could not be found in the file cache" : "Le partage de %s a échoué car le fichier n'a pas été trouvé dans les fichiers mis en cache.",
+ "Cannot increase permissions of %s" : "Impossible d'augmenter les permissions de %s",
+ "Expiration date is in the past" : "La date d'expiration est dans le passé",
+ "Cannot set expiration date more than %s days in the future" : "Impossible de définir la date d'expiration à plus de %s jours dans le futur",
"Could not find category \"%s\"" : "Impossible de trouver la catégorie \"%s\"",
"Apps" : "Applications",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", et \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", et \"_.@-'\"",
"A valid username must be provided" : "Un nom d'utilisateur valide doit être saisi",
"A valid password must be provided" : "Un mot de passe valide doit être saisi",
"The username is already being used" : "Ce nom d'utilisateur est déjà utilisé",
@@ -137,15 +142,17 @@
"Please ask your server administrator to restart the web server." : "Veuillez demander à votre administrateur serveur de redémarrer le serveur web.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 requis",
"Please upgrade your database version" : "Veuillez mettre à jour votre gestionnaire de base de données",
- "Error occurred while checking PostgreSQL version" : "Une erreur s’est produite pendant la récupération du numéro de version de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Veuillez vérifier que vous utilisez PostgreSQL >= 9 , ou regardez dans le journal d’erreur pour plus d’informations sur ce problème",
- "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu puisse être listé par les autres utilisateurs.",
+ "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu ne puisse pas être listé par les autres utilisateurs.",
"Data directory (%s) is readable by other users" : "Le répertoire de données (%s) est lisible par les autres utilisateurs",
"Data directory (%s) must be an absolute path" : "Le chemin du dossier de données (%s) doit être absolu",
"Check the value of \"datadirectory\" in your configuration" : "Verifiez la valeur de \"datadirectory\" dans votre configuration",
"Data directory (%s) is invalid" : "Le répertoire (%s) n'est pas valide",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Veuillez vérifier que le répertoire de données contient un fichier \".ocdata\" à sa racine.",
"Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur \"%s\".",
- "Storage not available" : "Support de stockage non disponible"
+ "Storage unauthorized. %s" : "Espace de stockage non autorisé. %s",
+ "Storage incomplete configuration. %s" : "Configuration de l'espace de stockage incomplète. %s",
+ "Storage connection error. %s" : "Erreur de connexion à l'espace stockage. %s",
+ "Storage not available" : "Support de stockage non disponible",
+ "Storage connection timeout. %s" : "Le délai d'attente pour la connexion à l'espace de stockage a été dépassé. %s"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/lib/l10n/gl.js b/lib/l10n/gl.js
index d6894749c0d..fa6435e8559 100644
--- a/lib/l10n/gl.js
+++ b/lib/l10n/gl.js
@@ -109,7 +109,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Fallou a compartición de %s, non foi posíbel atopar o ficheiro na caché de ficheiros",
"Could not find category \"%s\"" : "Non foi posíbel atopar a categoría «%s»",
"Apps" : "Aplicacións",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Só se permiten os seguintes caracteres no nome de usuario: «a-z», «A-Z», «0-9», e «_.@-»",
"A valid username must be provided" : "Debe fornecer un nome de usuario",
"A valid password must be provided" : "Debe fornecer un contrasinal",
"The username is already being used" : "Este nome de usuario xa está a ser usado",
@@ -136,8 +135,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Pregúntelle ao administrador do servidor polo reinicio do servidor web..",
"PostgreSQL >= 9 required" : "Requírese PostgreSQL >= 9",
"Please upgrade your database version" : "Anove a versión da súa base de datos",
- "Error occurred while checking PostgreSQL version" : "Produciuse un erro mentres comprobaba a versión de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Asegúrese de que dispón do PostgreSQL >= 9 ou comprobe os rexistros para obter máis información sobre este erro",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Cambie os permisos a 0770 para que o directorio non poida seren listado por outros usuarios.",
"Data directory (%s) is readable by other users" : "O directorio de datos (%s) é lexíbel por outros usuarios",
"Data directory (%s) must be an absolute path" : "O directorio de datos (%s) debe ser unha ruta absoluta",
diff --git a/lib/l10n/gl.json b/lib/l10n/gl.json
index 4dab647d768..781e880bbc0 100644
--- a/lib/l10n/gl.json
+++ b/lib/l10n/gl.json
@@ -107,7 +107,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Fallou a compartición de %s, non foi posíbel atopar o ficheiro na caché de ficheiros",
"Could not find category \"%s\"" : "Non foi posíbel atopar a categoría «%s»",
"Apps" : "Aplicacións",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Só se permiten os seguintes caracteres no nome de usuario: «a-z», «A-Z», «0-9», e «_.@-»",
"A valid username must be provided" : "Debe fornecer un nome de usuario",
"A valid password must be provided" : "Debe fornecer un contrasinal",
"The username is already being used" : "Este nome de usuario xa está a ser usado",
@@ -134,8 +133,6 @@
"Please ask your server administrator to restart the web server." : "Pregúntelle ao administrador do servidor polo reinicio do servidor web..",
"PostgreSQL >= 9 required" : "Requírese PostgreSQL >= 9",
"Please upgrade your database version" : "Anove a versión da súa base de datos",
- "Error occurred while checking PostgreSQL version" : "Produciuse un erro mentres comprobaba a versión de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Asegúrese de que dispón do PostgreSQL >= 9 ou comprobe os rexistros para obter máis información sobre este erro",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Cambie os permisos a 0770 para que o directorio non poida seren listado por outros usuarios.",
"Data directory (%s) is readable by other users" : "O directorio de datos (%s) é lexíbel por outros usuarios",
"Data directory (%s) must be an absolute path" : "O directorio de datos (%s) debe ser unha ruta absoluta",
diff --git a/lib/l10n/he.js b/lib/l10n/he.js
index 66acae5b804..5d7236a7604 100644
--- a/lib/l10n/he.js
+++ b/lib/l10n/he.js
@@ -1,23 +1,81 @@
OC.L10N.register(
"lib",
{
+ "Cannot write into \"config\" directory!" : "לא ניתן לכתוב לתיקיית \"config\"!",
+ "This can usually be fixed by giving the webserver write access to the config directory" : "בדרך כלל ניתן לפתור את הבעיה על ידי כך שנותנים ל- webserver הרשאות כניסה לתיקיית confg",
+ "See %s" : "ניתן לראות %s",
+ "This can usually be fixed by %sgiving the webserver write access to the config directory%s." : "בדרך כלל ניתן לפתור את הבעיה על ידי כך ש- %s נותן ל- webserver הרשאות כניסה לתיקיית config %s.",
+ "Sample configuration detected" : "התגלתה דוגמת תצורה",
+ "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "התגלה שדוגמת התצורה הועתקה. דבר זה עלול לשבור את ההתקנה ולא נתמך.יש לקרוא את מסמכי התיעוד לפני שמבצעים שינויים ב- config.php",
+ "PHP %s or higher is required." : "נדרש PHP בגרסת %s ומעלה.",
+ "PHP with a version lower than %s is required." : "נדרש PHP בגרסה נמוכה מ- %s.",
+ "Following databases are supported: %s" : "מסדי הנתונים הבאים נתמכים: %s",
+ "The command line tool %s could not be found" : "כלי שורת הפקודה %s לא אותר",
+ "The library %s is not available." : "הספריה %s אינה זמינה.",
+ "Library %s with a version higher than %s is required - available version %s." : "ספריה %s בגרסה גבוהה מ- %s נדרשת - גרסה זמינה %s.",
+ "Library %s with a version lower than %s is required - available version %s." : "ספריה %s בגרסה נמוכה מ- %s נדרשת - גרסה זמינה %s.",
+ "Following platforms are supported: %s" : "הפלטפורמות הבאות נתמכות: %s",
+ "ownCloud %s or higher is required." : "נדרש ownCloud %s ומעלה.",
+ "ownCloud %s or lower is required." : "נדרש ownCloud %s ומטה.",
"Help" : "עזרה",
"Personal" : "אישי",
"Users" : "משתמשים",
"Admin" : "מנהל",
+ "Recommended" : "מומלץ",
+ "App \"%s\" cannot be installed because it is not compatible with this version of ownCloud." : "היישום \"%s\" לא ניתן להתקנה כיוון שאינו תואם לגרסה זו של ownCloud.",
+ "App \"%s\" cannot be installed because the following dependencies are not fulfilled: %s" : "היישום \"%s\" לא ניתן להתקנה כיוון שיחסי התלות הבאים אינם מתקיימים: %s",
+ "No app name specified" : "לא הוגדר שם יישום",
+ "Unknown filetype" : "סוג קובץ לא מוכר",
+ "Invalid image" : "תמונה לא חוקית",
"today" : "היום",
"yesterday" : "אתמול",
+ "_%n day ago_::_%n days ago_" : ["לפני %n יום","לפני %n ימים"],
"last month" : "חודש שעבר",
"last year" : "שנה שעברה",
+ "_%n year ago_::_%n years ago_" : ["לפני %n שנה","לפני %n שנים"],
"seconds ago" : "שניות",
"web services under your control" : "שירותי רשת תחת השליטה שלך",
+ "Module with id: %s does not exist. Please enable it in your apps settings or contact your administrator." : "מודול עם זהות: %s אינו קיים. יש לאפשר את זה בהגדרות היישומים או ליצור קשר עם המנהל.",
+ "Empty filename is not allowed" : "שם קובץ ריק אינו מאושר",
+ "Dot files are not allowed" : "קבצי Dot אינם מותרים",
+ "4-byte characters are not supported in file names" : "תווי 4-byte אינם נתמכים בשמות קבצים",
+ "File name is a reserved word" : "שם קובץ הנו מילה שמורה",
+ "File name contains at least one invalid character" : "שם קובץ כולל לפחות תו אחד לא חוקי",
+ "File name is too long" : "שם קובץ ארוך מדי",
+ "File is currently busy, please try again later" : "הקובץ בשימוש כרגע, יש לנסות שוב מאוחר יותר",
+ "Can't read file" : "לא ניתן לקרוא קובץ",
+ "App directory already exists" : "תיקיית יישום כבר קיימת",
+ "Can't create app folder. Please fix permissions. %s" : "לא ניתן ליצור תיקיית יישום. יש לתקן הרשאות. %s",
+ "Archive does not contain a directory named %s" : "הארכיב לא כולל שם תיקייה %s",
+ "No source specified when installing app" : "לא נקבע מקור בתהליך התקנת היישום",
+ "No href specified when installing app from http" : "לא נקבע href בתהליך התקנת היישום מהאינטרנט",
+ "No path specified when installing app from local file" : "לא נקבע נתיב בתהליך התקנת היישום מקובץ מקומי",
+ "Archives of type %s are not supported" : "ארכיבים מסוג %s אינם נתמכים",
+ "Failed to open archive when installing app" : "פתיחת ארכיב נכשלה בתהליך התקנת היישום",
+ "App does not provide an info.xml file" : "היישום לא סיפק קובץ info.xml",
"Application is not enabled" : "יישומים אינם מופעלים",
"Authentication error" : "שגיאת הזדהות",
"Token expired. Please reload page." : "פג תוקף. נא לטעון שוב את הדף.",
+ "Unknown user" : "משתמש לא ידוע",
+ "%s enter the database username." : "%s נכנס למסד נתוני שמות המשתמשים.",
+ "%s enter the database name." : "%s נכנס למסד נתוני השמות.",
+ "DB Error: \"%s\"" : "שגיאת מסד נתונים: \"%s\"",
+ "Set an admin username." : "קביעת שם משתמש מנהל",
+ "Set an admin password." : "קביעת סיסמת מנהל",
"%s shared »%s« with you" : "%s שיתף/שיתפה איתך את »%s«",
+ "%s via %s" : "%s על בסיס %s",
+ "Expiration date is in the past" : "תאריך תפוגה הנו בעבר",
"Could not find category \"%s\"" : "לא ניתן למצוא את הקטגוריה „%s“",
"Apps" : "יישומים",
"A valid username must be provided" : "יש לספק שם משתמש תקני",
- "A valid password must be provided" : "יש לספק ססמה תקנית"
+ "A valid password must be provided" : "יש לספק ססמה תקנית",
+ "Cannot write into \"apps\" directory" : "לא ניתן לכתוב לתיקיית \"apps\"",
+ "PHP module %s not installed." : "מודול PHP %s אינו מותקן.",
+ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "זה ככל הנראה נגרם על ידי מאיץ/מטמון כמו Zend OPcache או eAccelerator.",
+ "Storage unauthorized. %s" : "אחסון לא מורשה. %s",
+ "Storage incomplete configuration. %s" : "תצורה לא מושלמת של האחסון. %s",
+ "Storage connection error. %s" : "שגיאת חיבור אחסון. %s",
+ "Storage not available" : "אחסון לא זמין",
+ "Storage connection timeout. %s" : "פסק זמן חיבור אחסון. %s"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/he.json b/lib/l10n/he.json
index 55df638cb11..69e8a16657a 100644
--- a/lib/l10n/he.json
+++ b/lib/l10n/he.json
@@ -1,21 +1,79 @@
{ "translations": {
+ "Cannot write into \"config\" directory!" : "לא ניתן לכתוב לתיקיית \"config\"!",
+ "This can usually be fixed by giving the webserver write access to the config directory" : "בדרך כלל ניתן לפתור את הבעיה על ידי כך שנותנים ל- webserver הרשאות כניסה לתיקיית confg",
+ "See %s" : "ניתן לראות %s",
+ "This can usually be fixed by %sgiving the webserver write access to the config directory%s." : "בדרך כלל ניתן לפתור את הבעיה על ידי כך ש- %s נותן ל- webserver הרשאות כניסה לתיקיית config %s.",
+ "Sample configuration detected" : "התגלתה דוגמת תצורה",
+ "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "התגלה שדוגמת התצורה הועתקה. דבר זה עלול לשבור את ההתקנה ולא נתמך.יש לקרוא את מסמכי התיעוד לפני שמבצעים שינויים ב- config.php",
+ "PHP %s or higher is required." : "נדרש PHP בגרסת %s ומעלה.",
+ "PHP with a version lower than %s is required." : "נדרש PHP בגרסה נמוכה מ- %s.",
+ "Following databases are supported: %s" : "מסדי הנתונים הבאים נתמכים: %s",
+ "The command line tool %s could not be found" : "כלי שורת הפקודה %s לא אותר",
+ "The library %s is not available." : "הספריה %s אינה זמינה.",
+ "Library %s with a version higher than %s is required - available version %s." : "ספריה %s בגרסה גבוהה מ- %s נדרשת - גרסה זמינה %s.",
+ "Library %s with a version lower than %s is required - available version %s." : "ספריה %s בגרסה נמוכה מ- %s נדרשת - גרסה זמינה %s.",
+ "Following platforms are supported: %s" : "הפלטפורמות הבאות נתמכות: %s",
+ "ownCloud %s or higher is required." : "נדרש ownCloud %s ומעלה.",
+ "ownCloud %s or lower is required." : "נדרש ownCloud %s ומטה.",
"Help" : "עזרה",
"Personal" : "אישי",
"Users" : "משתמשים",
"Admin" : "מנהל",
+ "Recommended" : "מומלץ",
+ "App \"%s\" cannot be installed because it is not compatible with this version of ownCloud." : "היישום \"%s\" לא ניתן להתקנה כיוון שאינו תואם לגרסה זו של ownCloud.",
+ "App \"%s\" cannot be installed because the following dependencies are not fulfilled: %s" : "היישום \"%s\" לא ניתן להתקנה כיוון שיחסי התלות הבאים אינם מתקיימים: %s",
+ "No app name specified" : "לא הוגדר שם יישום",
+ "Unknown filetype" : "סוג קובץ לא מוכר",
+ "Invalid image" : "תמונה לא חוקית",
"today" : "היום",
"yesterday" : "אתמול",
+ "_%n day ago_::_%n days ago_" : ["לפני %n יום","לפני %n ימים"],
"last month" : "חודש שעבר",
"last year" : "שנה שעברה",
+ "_%n year ago_::_%n years ago_" : ["לפני %n שנה","לפני %n שנים"],
"seconds ago" : "שניות",
"web services under your control" : "שירותי רשת תחת השליטה שלך",
+ "Module with id: %s does not exist. Please enable it in your apps settings or contact your administrator." : "מודול עם זהות: %s אינו קיים. יש לאפשר את זה בהגדרות היישומים או ליצור קשר עם המנהל.",
+ "Empty filename is not allowed" : "שם קובץ ריק אינו מאושר",
+ "Dot files are not allowed" : "קבצי Dot אינם מותרים",
+ "4-byte characters are not supported in file names" : "תווי 4-byte אינם נתמכים בשמות קבצים",
+ "File name is a reserved word" : "שם קובץ הנו מילה שמורה",
+ "File name contains at least one invalid character" : "שם קובץ כולל לפחות תו אחד לא חוקי",
+ "File name is too long" : "שם קובץ ארוך מדי",
+ "File is currently busy, please try again later" : "הקובץ בשימוש כרגע, יש לנסות שוב מאוחר יותר",
+ "Can't read file" : "לא ניתן לקרוא קובץ",
+ "App directory already exists" : "תיקיית יישום כבר קיימת",
+ "Can't create app folder. Please fix permissions. %s" : "לא ניתן ליצור תיקיית יישום. יש לתקן הרשאות. %s",
+ "Archive does not contain a directory named %s" : "הארכיב לא כולל שם תיקייה %s",
+ "No source specified when installing app" : "לא נקבע מקור בתהליך התקנת היישום",
+ "No href specified when installing app from http" : "לא נקבע href בתהליך התקנת היישום מהאינטרנט",
+ "No path specified when installing app from local file" : "לא נקבע נתיב בתהליך התקנת היישום מקובץ מקומי",
+ "Archives of type %s are not supported" : "ארכיבים מסוג %s אינם נתמכים",
+ "Failed to open archive when installing app" : "פתיחת ארכיב נכשלה בתהליך התקנת היישום",
+ "App does not provide an info.xml file" : "היישום לא סיפק קובץ info.xml",
"Application is not enabled" : "יישומים אינם מופעלים",
"Authentication error" : "שגיאת הזדהות",
"Token expired. Please reload page." : "פג תוקף. נא לטעון שוב את הדף.",
+ "Unknown user" : "משתמש לא ידוע",
+ "%s enter the database username." : "%s נכנס למסד נתוני שמות המשתמשים.",
+ "%s enter the database name." : "%s נכנס למסד נתוני השמות.",
+ "DB Error: \"%s\"" : "שגיאת מסד נתונים: \"%s\"",
+ "Set an admin username." : "קביעת שם משתמש מנהל",
+ "Set an admin password." : "קביעת סיסמת מנהל",
"%s shared »%s« with you" : "%s שיתף/שיתפה איתך את »%s«",
+ "%s via %s" : "%s על בסיס %s",
+ "Expiration date is in the past" : "תאריך תפוגה הנו בעבר",
"Could not find category \"%s\"" : "לא ניתן למצוא את הקטגוריה „%s“",
"Apps" : "יישומים",
"A valid username must be provided" : "יש לספק שם משתמש תקני",
- "A valid password must be provided" : "יש לספק ססמה תקנית"
+ "A valid password must be provided" : "יש לספק ססמה תקנית",
+ "Cannot write into \"apps\" directory" : "לא ניתן לכתוב לתיקיית \"apps\"",
+ "PHP module %s not installed." : "מודול PHP %s אינו מותקן.",
+ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "זה ככל הנראה נגרם על ידי מאיץ/מטמון כמו Zend OPcache או eAccelerator.",
+ "Storage unauthorized. %s" : "אחסון לא מורשה. %s",
+ "Storage incomplete configuration. %s" : "תצורה לא מושלמת של האחסון. %s",
+ "Storage connection error. %s" : "שגיאת חיבור אחסון. %s",
+ "Storage not available" : "אחסון לא זמין",
+ "Storage connection timeout. %s" : "פסק זמן חיבור אחסון. %s"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/hr.js b/lib/l10n/hr.js
index ef605582c78..4d7ce340625 100644
--- a/lib/l10n/hr.js
+++ b/lib/l10n/hr.js
@@ -86,7 +86,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Dijeljenje %s nije uspjelo jer u predmemoriji datoteke datoteka nije nađena.",
"Could not find category \"%s\"" : "Kategorija \"%s\" nije nađena",
"Apps" : "Aplikacije",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Samo su sljedeći znakovi dopušteni u korisničkom imenu: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Nužno je navesti ispravno korisničko ime",
"A valid password must be provided" : "Nužno je navesti ispravnu lozinku",
"The username is already being used" : "Korisničko ime se već koristi",
@@ -106,8 +105,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Molimo zamolite svog administratora poslužitelja da ponovno pokrene web poslužitelj.",
"PostgreSQL >= 9 required" : "Potreban je PostgreSQL >= 9",
"Please upgrade your database version" : "Molimo, ažurirajte svoju verziju baze podataka",
- "Error occurred while checking PostgreSQL version" : "Došlo je do pogreške tijekom provjeravanja verzije PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Pobrinite se da imate PostgreSQL >= 9. Za više informacija provjerite zapisnike.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Molimo promijenite dozvole na 0770 tako da se tim direktorijem ne mogu služiti drugi korisnici",
"Data directory (%s) is readable by other users" : "Podatkovni direktorij (%s) čitljiv je za druge korisnike",
"Data directory (%s) is invalid" : "Podatkovni direktorij (%s) nije ispravan",
diff --git a/lib/l10n/hr.json b/lib/l10n/hr.json
index 6e7e2bd432f..e17183ed169 100644
--- a/lib/l10n/hr.json
+++ b/lib/l10n/hr.json
@@ -84,7 +84,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Dijeljenje %s nije uspjelo jer u predmemoriji datoteke datoteka nije nađena.",
"Could not find category \"%s\"" : "Kategorija \"%s\" nije nađena",
"Apps" : "Aplikacije",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Samo su sljedeći znakovi dopušteni u korisničkom imenu: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Nužno je navesti ispravno korisničko ime",
"A valid password must be provided" : "Nužno je navesti ispravnu lozinku",
"The username is already being used" : "Korisničko ime se već koristi",
@@ -104,8 +103,6 @@
"Please ask your server administrator to restart the web server." : "Molimo zamolite svog administratora poslužitelja da ponovno pokrene web poslužitelj.",
"PostgreSQL >= 9 required" : "Potreban je PostgreSQL >= 9",
"Please upgrade your database version" : "Molimo, ažurirajte svoju verziju baze podataka",
- "Error occurred while checking PostgreSQL version" : "Došlo je do pogreške tijekom provjeravanja verzije PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Pobrinite se da imate PostgreSQL >= 9. Za više informacija provjerite zapisnike.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Molimo promijenite dozvole na 0770 tako da se tim direktorijem ne mogu služiti drugi korisnici",
"Data directory (%s) is readable by other users" : "Podatkovni direktorij (%s) čitljiv je za druge korisnike",
"Data directory (%s) is invalid" : "Podatkovni direktorij (%s) nije ispravan",
diff --git a/lib/l10n/hu_HU.js b/lib/l10n/hu_HU.js
index d065c509460..6a6b0dfaaf3 100644
--- a/lib/l10n/hu_HU.js
+++ b/lib/l10n/hu_HU.js
@@ -11,6 +11,7 @@ OC.L10N.register(
"PHP with a version lower than %s is required." : "Ennél régebbi PHP szükséges: %s.",
"Following databases are supported: %s" : "A következő adatbázis nem támogatott: %s",
"The library %s is not available." : "A könyvtár %s nem áll rendelkezésre.",
+ "Following platforms are supported: %s" : "Ezek a platformok támogatottak: %s",
"ownCloud %s or higher is required." : "ownCoud %s vagy ennél újabb szükséges.",
"ownCloud %s or lower is required." : "ownCoud %s vagy ennél régebbi szükséges.",
"Help" : "Súgó",
@@ -36,7 +37,9 @@ OC.L10N.register(
"Dot files are not allowed" : "Pontozott fájlok nem engedétlyezettek",
"4-byte characters are not supported in file names" : "4-byte karakterek nem támogatottak a fájl nevekben.",
"File name is a reserved word" : "A fajl neve egy rezervált szó",
+ "File name contains at least one invalid character" : "A fájlnév legalább egy érvénytelen karaktert tartalmaz!",
"File name is too long" : "A fájlnév túl hosszú!",
+ "File is currently busy, please try again later" : "A fájl jelenleg elfoglalt, kérjük próbáld újra később!",
"Can't read file" : "Nem olvasható a fájl",
"App directory already exists" : "Az alkalmazás mappája már létezik",
"Can't create app folder. Please fix permissions. %s" : "Nem lehetett létrehozni az alkalmazás mappáját. Kérem ellenőrizze a jogosultságokat. %s",
@@ -70,32 +73,38 @@ OC.L10N.register(
"Set an admin username." : "Állítson be egy felhasználói nevet az adminisztrációhoz.",
"Set an admin password." : "Állítson be egy jelszót az adminisztrációhoz.",
"Can't create or write into the data directory %s" : "Nem sikerült létrehozni vagy irni a \"data\" könyvtárba %s",
+ "Invalid Federated Cloud ID" : "Érvénytelen Egyesített Felhő Azonosító",
"%s shared »%s« with you" : "%s megosztotta Önnel ezt: »%s«",
"%s via %s" : "%s über %s",
+ "Sharing %s failed, because the backend does not allow shares from type %i" : "%s megosztása sikertelen, mert a megosztási alrendszer nem engedi a %l típus megosztását",
"Sharing %s failed, because the file does not exist" : "%s megosztása sikertelen, mert a fájl nem létezik",
"You are not allowed to share %s" : "Önnek nincs jogosultsága %s megosztására",
+ "Sharing %s failed, because you can not share with yourself" : "%s megosztása sikertelen, mert magaddal nem oszthatod meg",
"Sharing %s failed, because the user %s does not exist" : "%s megosztása nem sikerült, mert %s felhasználó nem létezik",
"Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" : "%s megosztása nem sikerült, mert %s felhasználó nem tagja egyik olyan csoportnak sem, aminek %s tagja",
"Sharing %s failed, because this item is already shared with %s" : "%s megosztása nem sikerült, mert ez már meg van osztva %s-vel",
+ "Sharing %s failed, because this item is already shared with user %s" : "%s megosztása sikertelen, mert már meg van osztva %s felhasználóval",
"Sharing %s failed, because the group %s does not exist" : "%s megosztása nem sikerült, mert %s csoport nem létezik",
"Sharing %s failed, because %s is not a member of the group %s" : "%s megosztása nem sikerült, mert %s felhasználó nem tagja a %s csoportnak",
"You need to provide a password to create a public link, only protected links are allowed" : "Meg kell adnia egy jelszót is, mert a nyilvános linkek csak jelszóval védetten használhatók",
"Sharing %s failed, because sharing with links is not allowed" : "%s megosztása nem sikerült, mert a linkekkel történő megosztás nincs engedélyezve",
+ "Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "%s megosztása sikertelen, mert %s nem található, talán a szerver jelenleg nem elérhető.",
"Share type %s is not valid for %s" : "A %s megosztási típus nem érvényes %s-re",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Nem sikerült %s-re beállítani az elérési jogosultságokat, mert a megadottak túllépik a %s-re érvényes jogosultságokat",
"Setting permissions for %s failed, because the item was not found" : "Nem sikerült %s-re beállítani az elérési jogosultságokat, mert a kérdéses állomány nem található",
"Cannot set expiration date. Shares cannot expire later than %s after they have been shared" : "Nem lehet beállítani a lejárati időt. A megosztások legfeljebb ennyi idővel járhatnak le a létrehozásukat követően: %s",
"Cannot set expiration date. Expiration date is in the past" : "Nem lehet beállítani a lejárati időt, mivel a megadott lejárati időpont már elmúlt.",
+ "Cannot clear expiration date. Shares are required to have an expiration date." : "Nem lehet beállítani a lejárati időt. A megosztásoknak kötelező megadni lejárati időt!",
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "Az %s megosztási alrendszernek támogatnia kell az OCP\\Share_Backend interface-t",
"Sharing backend %s not found" : "A %s megosztási alrendszer nem található",
"Sharing backend for %s not found" : "%s megosztási alrendszere nem található",
+ "Sharing failed, because the user %s is the original sharer" : "Megosztás sikertelen, mert %s felhasználó az eredeti megosztó",
"Sharing %s failed, because the permissions exceed permissions granted to %s" : "%s megosztása nem sikerült, mert a jogosultságok túllépik azt, ami %s rendelkezésére áll",
"Sharing %s failed, because resharing is not allowed" : "%s megosztása nem sikerült, mert a megosztás továbbadása nincs engedélyezve",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "%s megosztása nem sikerült, mert %s megosztási alrendszere nem találja",
"Sharing %s failed, because the file could not be found in the file cache" : "%s megosztása nem sikerült, mert a fájl nem található a gyorsítótárban",
"Could not find category \"%s\"" : "Ez a kategória nem található: \"%s\"",
"Apps" : "Alkalmazások",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "A felhasználónévben csak a következő karakterek fordulhatnak elő: \"a-z\", \"A-Z\", \"0-9\", és \"_.@-\"",
"A valid username must be provided" : "Érvényes felhasználónevet kell megadnia",
"A valid password must be provided" : "Érvényes jelszót kell megadnia",
"The username is already being used" : "Ez a bejelentkezési név már foglalt",
@@ -111,15 +120,15 @@ OC.L10N.register(
"Please install one of these locales on your system and restart your webserver." : "Kérjük állítsa be a következő lokalizációk valamelyikét a rendszeren és indítsa újra a webszervert!",
"Please ask your server administrator to install the module." : "Kérje meg a rendszergazdát, hogy telepítse a modult!",
"PHP module %s not installed." : "A %s PHP modul nincs telepítve.",
+ "PHP setting \"%s\" is not set to \"%s\"." : "%s PHP beállítás nincs \"%s\"-re állítva.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Ezt valószínűleg egy gyorsítótár ill. kódgyorsító, mint pl, a Zend, OPcache vagy eAccelererator okozza.",
"PHP modules have been installed, but they are still listed as missing?" : "A PHP modulok telepítve vannak, de a listában mégsincsenek felsorolva?",
"Please ask your server administrator to restart the web server." : "Kérje meg a rendszergazdát, hogy indítsa újra a webszervert!",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 szükséges",
"Please upgrade your database version" : "Kérem frissítse az adatbázis-szoftvert!",
- "Error occurred while checking PostgreSQL version" : "Hiba történt a PostgreSQL verziójának ellenőrzése közben",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Kérjük gondoskodjon róla, hogy a PostgreSQL legalább 9-es verziójú legyen, vagy ellenőrizze a naplófájlokat, hogy mi okozta a hibát!",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Kérjük módosítsa a könyvtár elérhetőségi engedélybeállítását 0770-re, hogy a tartalmát más felhasználó ne listázhassa!",
"Data directory (%s) is readable by other users" : "Az adatkönyvtár (%s) más felhasználók számára is olvasható ",
+ "Data directory (%s) must be an absolute path" : "Az adatkönyvtárnak (%s) abszolút elérési útnak kell lennie",
"Data directory (%s) is invalid" : "Érvénytelen a megadott adatkönyvtár (%s) ",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Kérjük ellenőrizze, hogy az adatkönyvtár tartalmaz a gyökerében egy \".ocdata\" nevű állományt!",
"Could not obtain lock type %d on \"%s\"." : "Nem sikerült %d típusú zárolást elérni itt: \"%s\".",
diff --git a/lib/l10n/hu_HU.json b/lib/l10n/hu_HU.json
index 4f864c1d75d..18c27c859e1 100644
--- a/lib/l10n/hu_HU.json
+++ b/lib/l10n/hu_HU.json
@@ -9,6 +9,7 @@
"PHP with a version lower than %s is required." : "Ennél régebbi PHP szükséges: %s.",
"Following databases are supported: %s" : "A következő adatbázis nem támogatott: %s",
"The library %s is not available." : "A könyvtár %s nem áll rendelkezésre.",
+ "Following platforms are supported: %s" : "Ezek a platformok támogatottak: %s",
"ownCloud %s or higher is required." : "ownCoud %s vagy ennél újabb szükséges.",
"ownCloud %s or lower is required." : "ownCoud %s vagy ennél régebbi szükséges.",
"Help" : "Súgó",
@@ -34,7 +35,9 @@
"Dot files are not allowed" : "Pontozott fájlok nem engedétlyezettek",
"4-byte characters are not supported in file names" : "4-byte karakterek nem támogatottak a fájl nevekben.",
"File name is a reserved word" : "A fajl neve egy rezervált szó",
+ "File name contains at least one invalid character" : "A fájlnév legalább egy érvénytelen karaktert tartalmaz!",
"File name is too long" : "A fájlnév túl hosszú!",
+ "File is currently busy, please try again later" : "A fájl jelenleg elfoglalt, kérjük próbáld újra később!",
"Can't read file" : "Nem olvasható a fájl",
"App directory already exists" : "Az alkalmazás mappája már létezik",
"Can't create app folder. Please fix permissions. %s" : "Nem lehetett létrehozni az alkalmazás mappáját. Kérem ellenőrizze a jogosultságokat. %s",
@@ -68,32 +71,38 @@
"Set an admin username." : "Állítson be egy felhasználói nevet az adminisztrációhoz.",
"Set an admin password." : "Állítson be egy jelszót az adminisztrációhoz.",
"Can't create or write into the data directory %s" : "Nem sikerült létrehozni vagy irni a \"data\" könyvtárba %s",
+ "Invalid Federated Cloud ID" : "Érvénytelen Egyesített Felhő Azonosító",
"%s shared »%s« with you" : "%s megosztotta Önnel ezt: »%s«",
"%s via %s" : "%s über %s",
+ "Sharing %s failed, because the backend does not allow shares from type %i" : "%s megosztása sikertelen, mert a megosztási alrendszer nem engedi a %l típus megosztását",
"Sharing %s failed, because the file does not exist" : "%s megosztása sikertelen, mert a fájl nem létezik",
"You are not allowed to share %s" : "Önnek nincs jogosultsága %s megosztására",
+ "Sharing %s failed, because you can not share with yourself" : "%s megosztása sikertelen, mert magaddal nem oszthatod meg",
"Sharing %s failed, because the user %s does not exist" : "%s megosztása nem sikerült, mert %s felhasználó nem létezik",
"Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" : "%s megosztása nem sikerült, mert %s felhasználó nem tagja egyik olyan csoportnak sem, aminek %s tagja",
"Sharing %s failed, because this item is already shared with %s" : "%s megosztása nem sikerült, mert ez már meg van osztva %s-vel",
+ "Sharing %s failed, because this item is already shared with user %s" : "%s megosztása sikertelen, mert már meg van osztva %s felhasználóval",
"Sharing %s failed, because the group %s does not exist" : "%s megosztása nem sikerült, mert %s csoport nem létezik",
"Sharing %s failed, because %s is not a member of the group %s" : "%s megosztása nem sikerült, mert %s felhasználó nem tagja a %s csoportnak",
"You need to provide a password to create a public link, only protected links are allowed" : "Meg kell adnia egy jelszót is, mert a nyilvános linkek csak jelszóval védetten használhatók",
"Sharing %s failed, because sharing with links is not allowed" : "%s megosztása nem sikerült, mert a linkekkel történő megosztás nincs engedélyezve",
+ "Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "%s megosztása sikertelen, mert %s nem található, talán a szerver jelenleg nem elérhető.",
"Share type %s is not valid for %s" : "A %s megosztási típus nem érvényes %s-re",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Nem sikerült %s-re beállítani az elérési jogosultságokat, mert a megadottak túllépik a %s-re érvényes jogosultságokat",
"Setting permissions for %s failed, because the item was not found" : "Nem sikerült %s-re beállítani az elérési jogosultságokat, mert a kérdéses állomány nem található",
"Cannot set expiration date. Shares cannot expire later than %s after they have been shared" : "Nem lehet beállítani a lejárati időt. A megosztások legfeljebb ennyi idővel járhatnak le a létrehozásukat követően: %s",
"Cannot set expiration date. Expiration date is in the past" : "Nem lehet beállítani a lejárati időt, mivel a megadott lejárati időpont már elmúlt.",
+ "Cannot clear expiration date. Shares are required to have an expiration date." : "Nem lehet beállítani a lejárati időt. A megosztásoknak kötelező megadni lejárati időt!",
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "Az %s megosztási alrendszernek támogatnia kell az OCP\\Share_Backend interface-t",
"Sharing backend %s not found" : "A %s megosztási alrendszer nem található",
"Sharing backend for %s not found" : "%s megosztási alrendszere nem található",
+ "Sharing failed, because the user %s is the original sharer" : "Megosztás sikertelen, mert %s felhasználó az eredeti megosztó",
"Sharing %s failed, because the permissions exceed permissions granted to %s" : "%s megosztása nem sikerült, mert a jogosultságok túllépik azt, ami %s rendelkezésére áll",
"Sharing %s failed, because resharing is not allowed" : "%s megosztása nem sikerült, mert a megosztás továbbadása nincs engedélyezve",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "%s megosztása nem sikerült, mert %s megosztási alrendszere nem találja",
"Sharing %s failed, because the file could not be found in the file cache" : "%s megosztása nem sikerült, mert a fájl nem található a gyorsítótárban",
"Could not find category \"%s\"" : "Ez a kategória nem található: \"%s\"",
"Apps" : "Alkalmazások",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "A felhasználónévben csak a következő karakterek fordulhatnak elő: \"a-z\", \"A-Z\", \"0-9\", és \"_.@-\"",
"A valid username must be provided" : "Érvényes felhasználónevet kell megadnia",
"A valid password must be provided" : "Érvényes jelszót kell megadnia",
"The username is already being used" : "Ez a bejelentkezési név már foglalt",
@@ -109,15 +118,15 @@
"Please install one of these locales on your system and restart your webserver." : "Kérjük állítsa be a következő lokalizációk valamelyikét a rendszeren és indítsa újra a webszervert!",
"Please ask your server administrator to install the module." : "Kérje meg a rendszergazdát, hogy telepítse a modult!",
"PHP module %s not installed." : "A %s PHP modul nincs telepítve.",
+ "PHP setting \"%s\" is not set to \"%s\"." : "%s PHP beállítás nincs \"%s\"-re állítva.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Ezt valószínűleg egy gyorsítótár ill. kódgyorsító, mint pl, a Zend, OPcache vagy eAccelererator okozza.",
"PHP modules have been installed, but they are still listed as missing?" : "A PHP modulok telepítve vannak, de a listában mégsincsenek felsorolva?",
"Please ask your server administrator to restart the web server." : "Kérje meg a rendszergazdát, hogy indítsa újra a webszervert!",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 szükséges",
"Please upgrade your database version" : "Kérem frissítse az adatbázis-szoftvert!",
- "Error occurred while checking PostgreSQL version" : "Hiba történt a PostgreSQL verziójának ellenőrzése közben",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Kérjük gondoskodjon róla, hogy a PostgreSQL legalább 9-es verziójú legyen, vagy ellenőrizze a naplófájlokat, hogy mi okozta a hibát!",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Kérjük módosítsa a könyvtár elérhetőségi engedélybeállítását 0770-re, hogy a tartalmát más felhasználó ne listázhassa!",
"Data directory (%s) is readable by other users" : "Az adatkönyvtár (%s) más felhasználók számára is olvasható ",
+ "Data directory (%s) must be an absolute path" : "Az adatkönyvtárnak (%s) abszolút elérési útnak kell lennie",
"Data directory (%s) is invalid" : "Érvénytelen a megadott adatkönyvtár (%s) ",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Kérjük ellenőrizze, hogy az adatkönyvtár tartalmaz a gyökerében egy \".ocdata\" nevű állományt!",
"Could not obtain lock type %d on \"%s\"." : "Nem sikerült %d típusú zárolást elérni itt: \"%s\".",
diff --git a/lib/l10n/id.js b/lib/l10n/id.js
index 70a47a4d87a..10848fd80f4 100644
--- a/lib/l10n/id.js
+++ b/lib/l10n/id.js
@@ -113,7 +113,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Gagal berbagi %s, karena berkas tidak ditemukan di berkas cache",
"Could not find category \"%s\"" : "Tidak menemukan kategori \"%s\"",
"Apps" : "Aplikasi",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Hanya karakter berikut yang diizinkan dalam nama pengguna: \"a-z\", \"A-Z\", \"0-9\", dan \"_.@-\"",
"A valid username must be provided" : "Tuliskan nama pengguna yang valid",
"A valid password must be provided" : "Tuliskan sandi yang valid",
"The username is already being used" : "Nama pengguna ini telah digunakan",
@@ -140,8 +139,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Mohon minta administrator Anda untuk menjalankan ulang server web.",
"PostgreSQL >= 9 required" : "Diperlukan PostgreSQL >= 9",
"Please upgrade your database version" : "Mohon perbarui versi basis data Anda",
- "Error occurred while checking PostgreSQL version" : "Terjadi kesalahan saat memeriksa versi PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Pastikan bahwa Anda memiliki PostgreSQL >= 9 atau periksa log untuk informasi lebih lanjut tentang kesalahan",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Mohon ubah perizinan menjadi 0770 sehingga direktori tersebut tidak dapat dilihat oleh pengguna lain.",
"Data directory (%s) is readable by other users" : "Direktori data (%s) dapat dibaca oleh pengguna lain",
"Data directory (%s) must be an absolute path" : "Direktori Data (%s) harus berupa lokasi lengkap",
diff --git a/lib/l10n/id.json b/lib/l10n/id.json
index 01f60eee2f7..a5edae82d83 100644
--- a/lib/l10n/id.json
+++ b/lib/l10n/id.json
@@ -111,7 +111,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Gagal berbagi %s, karena berkas tidak ditemukan di berkas cache",
"Could not find category \"%s\"" : "Tidak menemukan kategori \"%s\"",
"Apps" : "Aplikasi",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Hanya karakter berikut yang diizinkan dalam nama pengguna: \"a-z\", \"A-Z\", \"0-9\", dan \"_.@-\"",
"A valid username must be provided" : "Tuliskan nama pengguna yang valid",
"A valid password must be provided" : "Tuliskan sandi yang valid",
"The username is already being used" : "Nama pengguna ini telah digunakan",
@@ -138,8 +137,6 @@
"Please ask your server administrator to restart the web server." : "Mohon minta administrator Anda untuk menjalankan ulang server web.",
"PostgreSQL >= 9 required" : "Diperlukan PostgreSQL >= 9",
"Please upgrade your database version" : "Mohon perbarui versi basis data Anda",
- "Error occurred while checking PostgreSQL version" : "Terjadi kesalahan saat memeriksa versi PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Pastikan bahwa Anda memiliki PostgreSQL >= 9 atau periksa log untuk informasi lebih lanjut tentang kesalahan",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Mohon ubah perizinan menjadi 0770 sehingga direktori tersebut tidak dapat dilihat oleh pengguna lain.",
"Data directory (%s) is readable by other users" : "Direktori data (%s) dapat dibaca oleh pengguna lain",
"Data directory (%s) must be an absolute path" : "Direktori Data (%s) harus berupa lokasi lengkap",
diff --git a/lib/l10n/it.js b/lib/l10n/it.js
index 92fd849ef7e..eaaa186a41a 100644
--- a/lib/l10n/it.js
+++ b/lib/l10n/it.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Gli archivi di tipo %s non sono supportati",
"Failed to open archive when installing app" : "Apertura archivio non riuscita durante l'installazione dell'applicazione",
"App does not provide an info.xml file" : "L'applicazione non fornisce un file info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "La firma non può essere verificata. Contatta lo sviluppatore dell'applicazione e controlla la schermata di amministrazione.",
"App can't be installed because of not allowed code in the App" : "L'applicazione non può essere installata a causa di codice non consentito al suo interno",
"App can't be installed because it is not compatible with this version of ownCloud" : "L'applicazione non può essere installata poiché non è compatibile con questa versione di ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "L'applicazione non può essere installata poiché contiene il tag <shipped>true<shipped> che è consentito per le applicazioni native",
@@ -96,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Condivisione di %s non riuscita, poiché %s non appartiene al gruppo %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Devi fornire una password per creare un collegamento pubblico, sono consentiti solo i collegamenti protetti",
"Sharing %s failed, because sharing with links is not allowed" : "Condivisione di %s non riuscita, poiché i collegamenti non sono consentiti",
+ "Not allowed to create a federated share with the same user" : "Non è consentito creare una condivisione federata con lo stesso utente",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "La condivisione di %s non è riuscita, impossibile trovare %s, è probabile che il server non sia al momento raggiungibile.",
"Share type %s is not valid for %s" : "Il tipo di condivisione %s non è valido per %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Impostazione permessi per %s non riuscita, poiché i permessi superano i permessi accordati a %s",
@@ -111,9 +113,12 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Condivisione di %s non riuscita, poiché la ri-condivisione non è consentita",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Condivisione di %s non riuscita, poiché il motore di condivisione per %s non riesce a trovare la sua fonte",
"Sharing %s failed, because the file could not be found in the file cache" : "Condivisione di %s non riuscita, poiché il file non è stato trovato nella cache",
+ "Cannot increase permissions of %s" : "Impossibile aumentare i permessi di %s",
+ "Expiration date is in the past" : "La data di scadenza è nel passato",
+ "Cannot set expiration date more than %s days in the future" : "Impossibile impostare la data di scadenza a più di %s giorni nel futuro",
"Could not find category \"%s\"" : "Impossibile trovare la categoria \"%s\"",
"Apps" : "Applicazioni",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Solo i seguenti caratteri sono ammessi in un nome utente: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Solo i seguenti caratteri sono consentiti in un nome utente: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"",
"A valid username must be provided" : "Deve essere fornito un nome utente valido",
"A valid password must be provided" : "Deve essere fornita una password valida",
"The username is already being used" : "Il nome utente è già utilizzato",
@@ -140,8 +145,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Chiedi all'amministratore di riavviare il server web.",
"PostgreSQL >= 9 required" : "Richiesto PostgreSQL >= 9",
"Please upgrade your database version" : "Aggiorna la versione del tuo database",
- "Error occurred while checking PostgreSQL version" : "Si è verificato un errore durante il controllo della versione di PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Assicurati di avere PostgreSQL >= 9 o controlla i log per ulteriori informazioni sull'errore",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Modifica i permessi in 0770 in modo tale che la cartella non sia leggibile dagli altri utenti.",
"Data directory (%s) is readable by other users" : "La cartella dei dati (%s) è leggibile dagli altri utenti",
"Data directory (%s) must be an absolute path" : "La cartella dei dati (%s) deve essere un percorso assoluto",
@@ -149,6 +152,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "La cartella dei dati (%s) non è valida",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Verifica che la cartella dei dati contenga un file \".ocdata\" nella sua radice.",
"Could not obtain lock type %d on \"%s\"." : "Impossibile ottenere il blocco di tipo %d su \"%s\".",
- "Storage not available" : "Archiviazione non disponibile"
+ "Storage unauthorized. %s" : "Archiviazione non autorizzata. %s",
+ "Storage incomplete configuration. %s" : "Configurazione dell'archiviazione incompleta.%s",
+ "Storage connection error. %s" : "Errore di connessione all'archiviazione. %s",
+ "Storage not available" : "Archiviazione non disponibile",
+ "Storage connection timeout. %s" : "Timeout di connessione all'archiviazione. %s"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/it.json b/lib/l10n/it.json
index 080f2e87986..f29b3a2a740 100644
--- a/lib/l10n/it.json
+++ b/lib/l10n/it.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "Gli archivi di tipo %s non sono supportati",
"Failed to open archive when installing app" : "Apertura archivio non riuscita durante l'installazione dell'applicazione",
"App does not provide an info.xml file" : "L'applicazione non fornisce un file info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "La firma non può essere verificata. Contatta lo sviluppatore dell'applicazione e controlla la schermata di amministrazione.",
"App can't be installed because of not allowed code in the App" : "L'applicazione non può essere installata a causa di codice non consentito al suo interno",
"App can't be installed because it is not compatible with this version of ownCloud" : "L'applicazione non può essere installata poiché non è compatibile con questa versione di ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "L'applicazione non può essere installata poiché contiene il tag <shipped>true<shipped> che è consentito per le applicazioni native",
@@ -94,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Condivisione di %s non riuscita, poiché %s non appartiene al gruppo %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Devi fornire una password per creare un collegamento pubblico, sono consentiti solo i collegamenti protetti",
"Sharing %s failed, because sharing with links is not allowed" : "Condivisione di %s non riuscita, poiché i collegamenti non sono consentiti",
+ "Not allowed to create a federated share with the same user" : "Non è consentito creare una condivisione federata con lo stesso utente",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "La condivisione di %s non è riuscita, impossibile trovare %s, è probabile che il server non sia al momento raggiungibile.",
"Share type %s is not valid for %s" : "Il tipo di condivisione %s non è valido per %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Impostazione permessi per %s non riuscita, poiché i permessi superano i permessi accordati a %s",
@@ -109,9 +111,12 @@
"Sharing %s failed, because resharing is not allowed" : "Condivisione di %s non riuscita, poiché la ri-condivisione non è consentita",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Condivisione di %s non riuscita, poiché il motore di condivisione per %s non riesce a trovare la sua fonte",
"Sharing %s failed, because the file could not be found in the file cache" : "Condivisione di %s non riuscita, poiché il file non è stato trovato nella cache",
+ "Cannot increase permissions of %s" : "Impossibile aumentare i permessi di %s",
+ "Expiration date is in the past" : "La data di scadenza è nel passato",
+ "Cannot set expiration date more than %s days in the future" : "Impossibile impostare la data di scadenza a più di %s giorni nel futuro",
"Could not find category \"%s\"" : "Impossibile trovare la categoria \"%s\"",
"Apps" : "Applicazioni",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Solo i seguenti caratteri sono ammessi in un nome utente: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Solo i seguenti caratteri sono consentiti in un nome utente: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"",
"A valid username must be provided" : "Deve essere fornito un nome utente valido",
"A valid password must be provided" : "Deve essere fornita una password valida",
"The username is already being used" : "Il nome utente è già utilizzato",
@@ -138,8 +143,6 @@
"Please ask your server administrator to restart the web server." : "Chiedi all'amministratore di riavviare il server web.",
"PostgreSQL >= 9 required" : "Richiesto PostgreSQL >= 9",
"Please upgrade your database version" : "Aggiorna la versione del tuo database",
- "Error occurred while checking PostgreSQL version" : "Si è verificato un errore durante il controllo della versione di PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Assicurati di avere PostgreSQL >= 9 o controlla i log per ulteriori informazioni sull'errore",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Modifica i permessi in 0770 in modo tale che la cartella non sia leggibile dagli altri utenti.",
"Data directory (%s) is readable by other users" : "La cartella dei dati (%s) è leggibile dagli altri utenti",
"Data directory (%s) must be an absolute path" : "La cartella dei dati (%s) deve essere un percorso assoluto",
@@ -147,6 +150,10 @@
"Data directory (%s) is invalid" : "La cartella dei dati (%s) non è valida",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Verifica che la cartella dei dati contenga un file \".ocdata\" nella sua radice.",
"Could not obtain lock type %d on \"%s\"." : "Impossibile ottenere il blocco di tipo %d su \"%s\".",
- "Storage not available" : "Archiviazione non disponibile"
+ "Storage unauthorized. %s" : "Archiviazione non autorizzata. %s",
+ "Storage incomplete configuration. %s" : "Configurazione dell'archiviazione incompleta.%s",
+ "Storage connection error. %s" : "Errore di connessione all'archiviazione. %s",
+ "Storage not available" : "Archiviazione non disponibile",
+ "Storage connection timeout. %s" : "Timeout di connessione all'archiviazione. %s"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/ja.js b/lib/l10n/ja.js
index d00866d4ba6..e3433a18d7a 100644
--- a/lib/l10n/ja.js
+++ b/lib/l10n/ja.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "\"%s\"タイプのアーカイブ形式は未サポート",
"Failed to open archive when installing app" : "アプリをインストール中にアーカイブファイルを開けませんでした。",
"App does not provide an info.xml file" : "アプリにinfo.xmlファイルが入っていません",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "署名が確認できませんでした。このアプリの開発者へ連絡し、管理画面を確認してください。",
"App can't be installed because of not allowed code in the App" : "アプリで許可されないコードが入っているのが原因でアプリがインストールできません",
"App can't be installed because it is not compatible with this version of ownCloud" : "アプリは、このバージョンのownCloudと互換性がないためインストールできません。",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "非shippedアプリには許可されない<shipped>true</shipped>タグが含まれているためにアプリをインストールできません。",
@@ -96,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "%s を共有できませんでした。%s は、グループ %s のメンバーではありません。",
"You need to provide a password to create a public link, only protected links are allowed" : "公開用リンクの作成にはパスワードの設定が必要です",
"Sharing %s failed, because sharing with links is not allowed" : "%s を共有できませんでした。リンクでの共有は許可されていません。",
+ "Not allowed to create a federated share with the same user" : "同じユーザーでフェデレーション共有を作成することは出来ません",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "%s を共有できませんでした。%s が見つかりませんでした。現在サーバーに接続できないようです。",
"Share type %s is not valid for %s" : "%s の共有方法は、%s には適用できません。",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "%s を共有できませんでした。%s に許可されている権限を越えています。",
@@ -111,9 +113,11 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "%s を共有できませんでした。再共有は許可されていません。",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "%s の共有に失敗しました。%s のバックエンド共有に必要なソースが見つかりませんでした。",
"Sharing %s failed, because the file could not be found in the file cache" : "%s の共有に失敗しました。ファイルキャッシュにファイルがありませんでした。",
+ "Expiration date is in the past" : "有効期限が切れています",
+ "Cannot set expiration date more than %s days in the future" : "有効期限を%s日以降に設定できません。",
"Could not find category \"%s\"" : "カテゴリ \"%s\" が見つかりませんでした",
"Apps" : "アプリ",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "ユーザー名で利用できる文字列は、次のものです: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列は、次のものです: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "有効なユーザー名を指定する必要があります",
"A valid password must be provided" : "有効なパスワードを指定する必要があります",
"The username is already being used" : "ユーザー名はすでに使われています",
@@ -140,8 +144,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "サーバー管理者にWebサーバーを再起動するよう依頼してください。",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 が必要です",
"Please upgrade your database version" : "新しいバージョンのデータベースにアップグレードしてください",
- "Error occurred while checking PostgreSQL version" : "PostgreSQL のバージョンチェック中にエラーが発生しました",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "PostgreSQL >= 9 がインストールされているかどうか確認してください。もしくは、ログからエラーに関する詳細な情報を確認してください。",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "ディレクトリが他のユーザーから見えないように、パーミッションを 0770 に変更してください。",
"Data directory (%s) is readable by other users" : "データディレクトリ (%s) は他のユーザーも閲覧することができます",
"Data directory (%s) must be an absolute path" : "データディレクトリ (%s) は、絶対パスである必要があります。",
@@ -149,6 +151,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "データディレクトリ (%s) は無効です",
"Please check that the data directory contains a file \".ocdata\" in its root." : "データディレクトリに \".ocdata\" ファイルが含まれていることを確認してください。",
"Could not obtain lock type %d on \"%s\"." : "\"%s\" で %d タイプのロックを取得できませんでした。",
- "Storage not available" : "ストレージが利用できません"
+ "Storage unauthorized. %s" : "権限のないストレージです。 %s",
+ "Storage incomplete configuration. %s" : "設定が未完了のストレージです。 %s",
+ "Storage connection error. %s" : "ストレージへの接続エラー。 %s",
+ "Storage not available" : "ストレージが利用できません",
+ "Storage connection timeout. %s" : "ストレージへの接続がタイムアウト。 %s"
},
"nplurals=1; plural=0;");
diff --git a/lib/l10n/ja.json b/lib/l10n/ja.json
index e939520703e..a4b18386c7a 100644
--- a/lib/l10n/ja.json
+++ b/lib/l10n/ja.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "\"%s\"タイプのアーカイブ形式は未サポート",
"Failed to open archive when installing app" : "アプリをインストール中にアーカイブファイルを開けませんでした。",
"App does not provide an info.xml file" : "アプリにinfo.xmlファイルが入っていません",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "署名が確認できませんでした。このアプリの開発者へ連絡し、管理画面を確認してください。",
"App can't be installed because of not allowed code in the App" : "アプリで許可されないコードが入っているのが原因でアプリがインストールできません",
"App can't be installed because it is not compatible with this version of ownCloud" : "アプリは、このバージョンのownCloudと互換性がないためインストールできません。",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "非shippedアプリには許可されない<shipped>true</shipped>タグが含まれているためにアプリをインストールできません。",
@@ -94,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "%s を共有できませんでした。%s は、グループ %s のメンバーではありません。",
"You need to provide a password to create a public link, only protected links are allowed" : "公開用リンクの作成にはパスワードの設定が必要です",
"Sharing %s failed, because sharing with links is not allowed" : "%s を共有できませんでした。リンクでの共有は許可されていません。",
+ "Not allowed to create a federated share with the same user" : "同じユーザーでフェデレーション共有を作成することは出来ません",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "%s を共有できませんでした。%s が見つかりませんでした。現在サーバーに接続できないようです。",
"Share type %s is not valid for %s" : "%s の共有方法は、%s には適用できません。",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "%s を共有できませんでした。%s に許可されている権限を越えています。",
@@ -109,9 +111,11 @@
"Sharing %s failed, because resharing is not allowed" : "%s を共有できませんでした。再共有は許可されていません。",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "%s の共有に失敗しました。%s のバックエンド共有に必要なソースが見つかりませんでした。",
"Sharing %s failed, because the file could not be found in the file cache" : "%s の共有に失敗しました。ファイルキャッシュにファイルがありませんでした。",
+ "Expiration date is in the past" : "有効期限が切れています",
+ "Cannot set expiration date more than %s days in the future" : "有効期限を%s日以降に設定できません。",
"Could not find category \"%s\"" : "カテゴリ \"%s\" が見つかりませんでした",
"Apps" : "アプリ",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "ユーザー名で利用できる文字列は、次のものです: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列は、次のものです: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "有効なユーザー名を指定する必要があります",
"A valid password must be provided" : "有効なパスワードを指定する必要があります",
"The username is already being used" : "ユーザー名はすでに使われています",
@@ -138,8 +142,6 @@
"Please ask your server administrator to restart the web server." : "サーバー管理者にWebサーバーを再起動するよう依頼してください。",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 が必要です",
"Please upgrade your database version" : "新しいバージョンのデータベースにアップグレードしてください",
- "Error occurred while checking PostgreSQL version" : "PostgreSQL のバージョンチェック中にエラーが発生しました",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "PostgreSQL >= 9 がインストールされているかどうか確認してください。もしくは、ログからエラーに関する詳細な情報を確認してください。",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "ディレクトリが他のユーザーから見えないように、パーミッションを 0770 に変更してください。",
"Data directory (%s) is readable by other users" : "データディレクトリ (%s) は他のユーザーも閲覧することができます",
"Data directory (%s) must be an absolute path" : "データディレクトリ (%s) は、絶対パスである必要があります。",
@@ -147,6 +149,10 @@
"Data directory (%s) is invalid" : "データディレクトリ (%s) は無効です",
"Please check that the data directory contains a file \".ocdata\" in its root." : "データディレクトリに \".ocdata\" ファイルが含まれていることを確認してください。",
"Could not obtain lock type %d on \"%s\"." : "\"%s\" で %d タイプのロックを取得できませんでした。",
- "Storage not available" : "ストレージが利用できません"
+ "Storage unauthorized. %s" : "権限のないストレージです。 %s",
+ "Storage incomplete configuration. %s" : "設定が未完了のストレージです。 %s",
+ "Storage connection error. %s" : "ストレージへの接続エラー。 %s",
+ "Storage not available" : "ストレージが利用できません",
+ "Storage connection timeout. %s" : "ストレージへの接続がタイムアウト。 %s"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/lib/l10n/ko.js b/lib/l10n/ko.js
index 5a35f149f03..afdbd56bd6a 100644
--- a/lib/l10n/ko.js
+++ b/lib/l10n/ko.js
@@ -113,7 +113,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "%s을(를) 공유할 수 없습니다. 파일 캐시에서 찾을 수 없습니다",
"Could not find category \"%s\"" : "분류 \"%s\"을(를) 찾을 수 없습니다.",
"Apps" : "앱",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "사용자 이름에는 다음과 같은 문자만 사용할 수 있습니다: \"a-z\", \"A-Z\", \"0-9\", \"_.@-\"",
"A valid username must be provided" : "올바른 사용자 이름을 입력해야 합니다",
"A valid password must be provided" : "올바른 암호를 입력해야 합니다",
"The username is already being used" : "사용자 이름이 이미 존재합니다",
@@ -140,8 +139,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "서버 관리자에게 웹 서버 재시작을 요청하십시오.",
"PostgreSQL >= 9 required" : "PostgreSQL 버전 9 이상이 필요합니다",
"Please upgrade your database version" : "데이터베이스 버전을 업그레이드 하십시오",
- "Error occurred while checking PostgreSQL version" : "PostgreSQL 버전을 확인하는 중 오류가 발생했습니다",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "PostgreSQL 버전 9 이상이 있는지 확인하시고, 자세한 정보는 로그를 확인하십시오",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "권한을 0770으로 변경하여 다른 사용자가 읽을 수 없도록 하십시오.",
"Data directory (%s) is readable by other users" : "데이터 디렉터리(%s)를 다른 사용자가 읽을 수 있음",
"Data directory (%s) must be an absolute path" : "데이터 디렉터리(%s)는 반드시 절대 경로여야 함",
diff --git a/lib/l10n/ko.json b/lib/l10n/ko.json
index deb80e00e98..910c004a73d 100644
--- a/lib/l10n/ko.json
+++ b/lib/l10n/ko.json
@@ -111,7 +111,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "%s을(를) 공유할 수 없습니다. 파일 캐시에서 찾을 수 없습니다",
"Could not find category \"%s\"" : "분류 \"%s\"을(를) 찾을 수 없습니다.",
"Apps" : "앱",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "사용자 이름에는 다음과 같은 문자만 사용할 수 있습니다: \"a-z\", \"A-Z\", \"0-9\", \"_.@-\"",
"A valid username must be provided" : "올바른 사용자 이름을 입력해야 합니다",
"A valid password must be provided" : "올바른 암호를 입력해야 합니다",
"The username is already being used" : "사용자 이름이 이미 존재합니다",
@@ -138,8 +137,6 @@
"Please ask your server administrator to restart the web server." : "서버 관리자에게 웹 서버 재시작을 요청하십시오.",
"PostgreSQL >= 9 required" : "PostgreSQL 버전 9 이상이 필요합니다",
"Please upgrade your database version" : "데이터베이스 버전을 업그레이드 하십시오",
- "Error occurred while checking PostgreSQL version" : "PostgreSQL 버전을 확인하는 중 오류가 발생했습니다",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "PostgreSQL 버전 9 이상이 있는지 확인하시고, 자세한 정보는 로그를 확인하십시오",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "권한을 0770으로 변경하여 다른 사용자가 읽을 수 없도록 하십시오.",
"Data directory (%s) is readable by other users" : "데이터 디렉터리(%s)를 다른 사용자가 읽을 수 있음",
"Data directory (%s) must be an absolute path" : "데이터 디렉터리(%s)는 반드시 절대 경로여야 함",
diff --git a/lib/l10n/lt_LT.js b/lib/l10n/lt_LT.js
index 27392c84d2c..402167cb3c6 100644
--- a/lib/l10n/lt_LT.js
+++ b/lib/l10n/lt_LT.js
@@ -1,6 +1,12 @@
OC.L10N.register(
"lib",
{
+ "Cannot write into \"config\" directory!" : "Negalima rašyti į \"config\" aplanką!",
+ "This can usually be fixed by giving the webserver write access to the config directory" : "Tai gali būti ištaisyta suteikiant web serveriui rašymo teises į config aplanką",
+ "See %s" : "Žiūrėk %s",
+ "Sample configuration detected" : "Aptiktas konfigūracijos pavyzdys",
+ "PHP %s or higher is required." : "Reikalinga PHP %s arba aukštesnė.",
+ "Following databases are supported: %s" : "Palaikomos duomenų bazės: %s",
"Help" : "Pagalba",
"Personal" : "Asmeniniai",
"Users" : "Vartotojai",
@@ -17,6 +23,8 @@ OC.L10N.register(
"_%n minute ago_::_%n minutes ago_" : ["prieš %n min.","Prieš % minutes","Prieš %n minučių"],
"seconds ago" : "prieš sekundę",
"web services under your control" : "jūsų valdomos web paslaugos",
+ "Empty filename is not allowed" : "Tuščias failo pavadinimas neleidžiamas",
+ "File name is a reserved word" : "Failo pavadinimas negalimas, žodis rezervuotas",
"File name contains at least one invalid character" : "Failo vardas sudarytas iš neleistinų simbolių",
"App directory already exists" : "Programos aplankas jau egzistuoja",
"Can't create app folder. Please fix permissions. %s" : "Nepavyksta sukurti aplanko. Prašome pataisyti leidimus. %s",
diff --git a/lib/l10n/lt_LT.json b/lib/l10n/lt_LT.json
index 674939a7a0a..c4efe386655 100644
--- a/lib/l10n/lt_LT.json
+++ b/lib/l10n/lt_LT.json
@@ -1,4 +1,10 @@
{ "translations": {
+ "Cannot write into \"config\" directory!" : "Negalima rašyti į \"config\" aplanką!",
+ "This can usually be fixed by giving the webserver write access to the config directory" : "Tai gali būti ištaisyta suteikiant web serveriui rašymo teises į config aplanką",
+ "See %s" : "Žiūrėk %s",
+ "Sample configuration detected" : "Aptiktas konfigūracijos pavyzdys",
+ "PHP %s or higher is required." : "Reikalinga PHP %s arba aukštesnė.",
+ "Following databases are supported: %s" : "Palaikomos duomenų bazės: %s",
"Help" : "Pagalba",
"Personal" : "Asmeniniai",
"Users" : "Vartotojai",
@@ -15,6 +21,8 @@
"_%n minute ago_::_%n minutes ago_" : ["prieš %n min.","Prieš % minutes","Prieš %n minučių"],
"seconds ago" : "prieš sekundę",
"web services under your control" : "jūsų valdomos web paslaugos",
+ "Empty filename is not allowed" : "Tuščias failo pavadinimas neleidžiamas",
+ "File name is a reserved word" : "Failo pavadinimas negalimas, žodis rezervuotas",
"File name contains at least one invalid character" : "Failo vardas sudarytas iš neleistinų simbolių",
"App directory already exists" : "Programos aplankas jau egzistuoja",
"Can't create app folder. Please fix permissions. %s" : "Nepavyksta sukurti aplanko. Prašome pataisyti leidimus. %s",
diff --git a/lib/l10n/mk.js b/lib/l10n/mk.js
index 881388b4eac..0129d33517f 100644
--- a/lib/l10n/mk.js
+++ b/lib/l10n/mk.js
@@ -32,6 +32,7 @@ OC.L10N.register(
"Apps" : "Аппликации",
"A valid username must be provided" : "Мора да се обезбеди валидно корисничко име ",
"A valid password must be provided" : "Мора да се обезбеди валидна лозинка",
- "The username is already being used" : "Корисничкото име е веќе во употреба"
+ "The username is already being used" : "Корисничкото име е веќе во употреба",
+ "Storage not available" : "Сториџот не е достапен"
},
"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;");
diff --git a/lib/l10n/mk.json b/lib/l10n/mk.json
index 7dbfab7f01f..3a05e15b74b 100644
--- a/lib/l10n/mk.json
+++ b/lib/l10n/mk.json
@@ -30,6 +30,7 @@
"Apps" : "Аппликации",
"A valid username must be provided" : "Мора да се обезбеди валидно корисничко име ",
"A valid password must be provided" : "Мора да се обезбеди валидна лозинка",
- "The username is already being used" : "Корисничкото име е веќе во употреба"
+ "The username is already being used" : "Корисничкото име е веќе во употреба",
+ "Storage not available" : "Сториџот не е достапен"
},"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"
} \ No newline at end of file
diff --git a/lib/l10n/nb_NO.js b/lib/l10n/nb_NO.js
index 4f85c4975e0..2dbf45e950b 100644
--- a/lib/l10n/nb_NO.js
+++ b/lib/l10n/nb_NO.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Arkiver av type %s støttes ikke",
"Failed to open archive when installing app" : "Klarte ikke å åpne arkiv ved installering av app",
"App does not provide an info.xml file" : "App-en inneholder ikke filen info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Signatur kunne ikke sjekkes. Kontakt app-utvikleren og sjekk admin-bildet.",
"App can't be installed because of not allowed code in the App" : "App kan ikke installeres på grunn av ulovlig kode i appen.",
"App can't be installed because it is not compatible with this version of ownCloud" : "App kan ikke installeres fordi den ikke er kompatibel med denne versjonen av ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "App kan ikke installeres fordi den inneholder tag <shipped>true</shipped> som ikke er tillatt for apper som ikke leveres med systemet",
@@ -96,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Deling av %s feilet, fordi %s ikke er medlem av gruppen %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Du må oppgi et passord for å lage en offentlig lenke. Bare beskyttede lenker er tillatt",
"Sharing %s failed, because sharing with links is not allowed" : "Deling av %s feilet, fordi deling med lenker ikke er tillatt",
+ "Not allowed to create a federated share with the same user" : "Ikke tillatt å opprette en Sammenknyttet sky-deling med den samme brukeren",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Deling %s feilet, fant ikke %s, kanskje servern er utilgjengelig for øyeblikket.",
"Share type %s is not valid for %s" : "Delingstype %s er ikke gyldig for %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Setting av tillatelser for %s feilet, fordi tillatelsene gikk ut over tillatelsene som er gitt til %s",
@@ -111,9 +113,11 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Deling av %s feilet, fordi videre-deling ikke er tillatt",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Deling av %s feilet, fordi delings-serveren for %s ikke kunne finne kilden",
"Sharing %s failed, because the file could not be found in the file cache" : "Deling av %s feilet, fordi filen ikke ble funnet i fil-mellomlageret",
+ "Cannot increase permissions of %s" : "Kan ikke øke tillatelser for %s",
+ "Expiration date is in the past" : "Utløpsdato er tilbake i tid",
+ "Cannot set expiration date more than %s days in the future" : "Kan ikke sette utløpsdato mer enn %s dager fram i tid",
"Could not find category \"%s\"" : "Kunne ikke finne kategori \"%s\"",
"Apps" : "Apper",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Bare disse tegnene tillates i et brukernavn: \"a-z\", \"A-Z\", \"0-9\" og \"_.@-\"",
"A valid username must be provided" : "Oppgi et gyldig brukernavn",
"A valid password must be provided" : "Oppgi et gyldig passord",
"The username is already being used" : "Brukernavnet er allerede i bruk",
@@ -140,8 +144,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Be server-administratoren om å starte web-serveren på nytt.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 kreves",
"Please upgrade your database version" : "Vennligst oppgrader versjonen av databasen din",
- "Error occurred while checking PostgreSQL version" : "Det oppstod en feil ved sjekking av PostgreSQL-versjon",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Sjekk at du har PostgreSQL >= 9 eller sjekk loggene for mer informasjon om feilen",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endre tillatelsene til 0770 slik at mappen ikke kan listes av andre brukere.",
"Data directory (%s) is readable by other users" : "Data-mappen (%s) kan leses av andre brukere",
"Data directory (%s) must be an absolute path" : "Datamappen (%s) må være en absolutt sti",
@@ -149,6 +151,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "Data-mappe (%s) er ugyldig",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Sjekk at det ligger en fil \".ocdata\" i roten av data-mappen.",
"Could not obtain lock type %d on \"%s\"." : "Klarte ikke å låse med type %d på \"%s\".",
- "Storage not available" : "Lagringsplass ikke tilgjengelig"
+ "Storage unauthorized. %s" : "Lager uautorisert: %s",
+ "Storage incomplete configuration. %s" : "Ikke komplett oppsett for lager. %s",
+ "Storage connection error. %s" : "Tilkoblingsfeil for lager. %s",
+ "Storage not available" : "Lagringsplass ikke tilgjengelig",
+ "Storage connection timeout. %s" : "Tidsavbrudd ved tilkobling av lager: %s"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/nb_NO.json b/lib/l10n/nb_NO.json
index 80f1ba19fc9..d93e32b7469 100644
--- a/lib/l10n/nb_NO.json
+++ b/lib/l10n/nb_NO.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "Arkiver av type %s støttes ikke",
"Failed to open archive when installing app" : "Klarte ikke å åpne arkiv ved installering av app",
"App does not provide an info.xml file" : "App-en inneholder ikke filen info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Signatur kunne ikke sjekkes. Kontakt app-utvikleren og sjekk admin-bildet.",
"App can't be installed because of not allowed code in the App" : "App kan ikke installeres på grunn av ulovlig kode i appen.",
"App can't be installed because it is not compatible with this version of ownCloud" : "App kan ikke installeres fordi den ikke er kompatibel med denne versjonen av ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "App kan ikke installeres fordi den inneholder tag <shipped>true</shipped> som ikke er tillatt for apper som ikke leveres med systemet",
@@ -94,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Deling av %s feilet, fordi %s ikke er medlem av gruppen %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Du må oppgi et passord for å lage en offentlig lenke. Bare beskyttede lenker er tillatt",
"Sharing %s failed, because sharing with links is not allowed" : "Deling av %s feilet, fordi deling med lenker ikke er tillatt",
+ "Not allowed to create a federated share with the same user" : "Ikke tillatt å opprette en Sammenknyttet sky-deling med den samme brukeren",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Deling %s feilet, fant ikke %s, kanskje servern er utilgjengelig for øyeblikket.",
"Share type %s is not valid for %s" : "Delingstype %s er ikke gyldig for %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Setting av tillatelser for %s feilet, fordi tillatelsene gikk ut over tillatelsene som er gitt til %s",
@@ -109,9 +111,11 @@
"Sharing %s failed, because resharing is not allowed" : "Deling av %s feilet, fordi videre-deling ikke er tillatt",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Deling av %s feilet, fordi delings-serveren for %s ikke kunne finne kilden",
"Sharing %s failed, because the file could not be found in the file cache" : "Deling av %s feilet, fordi filen ikke ble funnet i fil-mellomlageret",
+ "Cannot increase permissions of %s" : "Kan ikke øke tillatelser for %s",
+ "Expiration date is in the past" : "Utløpsdato er tilbake i tid",
+ "Cannot set expiration date more than %s days in the future" : "Kan ikke sette utløpsdato mer enn %s dager fram i tid",
"Could not find category \"%s\"" : "Kunne ikke finne kategori \"%s\"",
"Apps" : "Apper",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Bare disse tegnene tillates i et brukernavn: \"a-z\", \"A-Z\", \"0-9\" og \"_.@-\"",
"A valid username must be provided" : "Oppgi et gyldig brukernavn",
"A valid password must be provided" : "Oppgi et gyldig passord",
"The username is already being used" : "Brukernavnet er allerede i bruk",
@@ -138,8 +142,6 @@
"Please ask your server administrator to restart the web server." : "Be server-administratoren om å starte web-serveren på nytt.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 kreves",
"Please upgrade your database version" : "Vennligst oppgrader versjonen av databasen din",
- "Error occurred while checking PostgreSQL version" : "Det oppstod en feil ved sjekking av PostgreSQL-versjon",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Sjekk at du har PostgreSQL >= 9 eller sjekk loggene for mer informasjon om feilen",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endre tillatelsene til 0770 slik at mappen ikke kan listes av andre brukere.",
"Data directory (%s) is readable by other users" : "Data-mappen (%s) kan leses av andre brukere",
"Data directory (%s) must be an absolute path" : "Datamappen (%s) må være en absolutt sti",
@@ -147,6 +149,10 @@
"Data directory (%s) is invalid" : "Data-mappe (%s) er ugyldig",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Sjekk at det ligger en fil \".ocdata\" i roten av data-mappen.",
"Could not obtain lock type %d on \"%s\"." : "Klarte ikke å låse med type %d på \"%s\".",
- "Storage not available" : "Lagringsplass ikke tilgjengelig"
+ "Storage unauthorized. %s" : "Lager uautorisert: %s",
+ "Storage incomplete configuration. %s" : "Ikke komplett oppsett for lager. %s",
+ "Storage connection error. %s" : "Tilkoblingsfeil for lager. %s",
+ "Storage not available" : "Lagringsplass ikke tilgjengelig",
+ "Storage connection timeout. %s" : "Tidsavbrudd ved tilkobling av lager: %s"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/nl.js b/lib/l10n/nl.js
index d1cfc134c38..e49ddc6d27c 100644
--- a/lib/l10n/nl.js
+++ b/lib/l10n/nl.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Archiefbestanden van type %s niet ondersteund",
"Failed to open archive when installing app" : "Kon archiefbestand bij installatie van de app niet openen",
"App does not provide an info.xml file" : "De app heeft geen info.xml bestand",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Handtekening kon niet worden geverifieerd. Nee contact op met de ontwikkelaar van de app en check uw beheerscherm.",
"App can't be installed because of not allowed code in the App" : "De app kan niet worden geïnstalleerd wegens onjuiste code in de app",
"App can't be installed because it is not compatible with this version of ownCloud" : "De app kan niet worden geïnstalleerd omdat die niet compatible is met deze versie van ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "De app kan niet worden geïnstallerd omdat het de <shipped>true</shipped> tag bevat die niet is toegestaan voor niet gepubliceerde apps",
@@ -96,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Delen van %s is mislukt, omdat %s geen lid is van groep %s",
"You need to provide a password to create a public link, only protected links are allowed" : "U moet een wachtwoord verstrekken om een openbare koppeling te maken, alleen beschermde links zijn toegestaan",
"Sharing %s failed, because sharing with links is not allowed" : "Delen van %s is mislukt, omdat het delen met links niet is toegestaan",
+ "Not allowed to create a federated share with the same user" : "Het is niet toegestaan om een gefedereerde share met dezelfde gebruikersserver te maken",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Delen van %s mislukt, kon %s niet vinden, misschien is de server niet bereikbaar.",
"Share type %s is not valid for %s" : "Delen van type %s is niet geldig voor %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Instellen van de permissies voor %s is mislukt, omdat de permissies hoger zijn dan de aan %s toegekende permissies",
@@ -111,9 +113,12 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Delen van %s is mislukt, omdat her-delen niet is toegestaan",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Delen van %s is mislukt, omdat de share-backend voor %s de bron niet kon vinden",
"Sharing %s failed, because the file could not be found in the file cache" : "Delen van %s is mislukt, omdat het bestand niet in de bestandscache kon worden gevonden",
+ "Cannot increase permissions of %s" : "Kan de rechten van %s niet verruimen",
+ "Expiration date is in the past" : "De vervaldatum ligt in het verleden",
+ "Cannot set expiration date more than %s days in the future" : "Kan vervaldatum niet verder dan %s dagen in de toekomst instellen",
"Could not find category \"%s\"" : "Kon categorie \"%s\" niet vinden",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Alleen de volgende tekens zijn toegestaan in een gebruikersnaam: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Alleen de volgende tekens zijn toegestaan in een gebruikersnaam: \"a-z\", \"A-Z\", \"0-9\", en \"_.@-\"",
"A valid username must be provided" : "Er moet een geldige gebruikersnaam worden opgegeven",
"A valid password must be provided" : "Er moet een geldig wachtwoord worden opgegeven",
"The username is already being used" : "De gebruikersnaam bestaat al",
@@ -140,8 +145,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Vraag uw beheerder de webserver opnieuw op te starten.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 vereist",
"Please upgrade your database version" : "Werk uw database versie bij",
- "Error occurred while checking PostgreSQL version" : "Een fout trad op bij checken PostgreSQL versie",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Verifieer dat u PostgreSQL >=9 draait of check de logs voor meer informatie over deze fout",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Wijzig de permissies in 0770 zodat de directory niet door anderen bekeken kan worden.",
"Data directory (%s) is readable by other users" : "De datadirectory (%s) is leesbaar voor andere gebruikers",
"Data directory (%s) must be an absolute path" : "De datadirectory (%s) moet een absoluut pad hebben",
@@ -149,6 +152,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "Data directory (%s) is ongeldig",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Verifieer dat de data directory een bestand \".ocdata\" in de hoofdmap heeft.",
"Could not obtain lock type %d on \"%s\"." : "Kon geen lock type %d krijgen op \"%s\".",
- "Storage not available" : "Opslag niet beschikbaar"
+ "Storage unauthorized. %s" : "Opslag niet toegestaan. %s",
+ "Storage incomplete configuration. %s" : "Incomplete opslagconfiguratie. %s",
+ "Storage connection error. %s" : "Opslagverbindingsfout. %s",
+ "Storage not available" : "Opslag niet beschikbaar",
+ "Storage connection timeout. %s" : "Opslagverbinding time-out. %s"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/nl.json b/lib/l10n/nl.json
index a38fbdbecc4..78b54fbbc6d 100644
--- a/lib/l10n/nl.json
+++ b/lib/l10n/nl.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "Archiefbestanden van type %s niet ondersteund",
"Failed to open archive when installing app" : "Kon archiefbestand bij installatie van de app niet openen",
"App does not provide an info.xml file" : "De app heeft geen info.xml bestand",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Handtekening kon niet worden geverifieerd. Nee contact op met de ontwikkelaar van de app en check uw beheerscherm.",
"App can't be installed because of not allowed code in the App" : "De app kan niet worden geïnstalleerd wegens onjuiste code in de app",
"App can't be installed because it is not compatible with this version of ownCloud" : "De app kan niet worden geïnstalleerd omdat die niet compatible is met deze versie van ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "De app kan niet worden geïnstallerd omdat het de <shipped>true</shipped> tag bevat die niet is toegestaan voor niet gepubliceerde apps",
@@ -94,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Delen van %s is mislukt, omdat %s geen lid is van groep %s",
"You need to provide a password to create a public link, only protected links are allowed" : "U moet een wachtwoord verstrekken om een openbare koppeling te maken, alleen beschermde links zijn toegestaan",
"Sharing %s failed, because sharing with links is not allowed" : "Delen van %s is mislukt, omdat het delen met links niet is toegestaan",
+ "Not allowed to create a federated share with the same user" : "Het is niet toegestaan om een gefedereerde share met dezelfde gebruikersserver te maken",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Delen van %s mislukt, kon %s niet vinden, misschien is de server niet bereikbaar.",
"Share type %s is not valid for %s" : "Delen van type %s is niet geldig voor %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Instellen van de permissies voor %s is mislukt, omdat de permissies hoger zijn dan de aan %s toegekende permissies",
@@ -109,9 +111,12 @@
"Sharing %s failed, because resharing is not allowed" : "Delen van %s is mislukt, omdat her-delen niet is toegestaan",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Delen van %s is mislukt, omdat de share-backend voor %s de bron niet kon vinden",
"Sharing %s failed, because the file could not be found in the file cache" : "Delen van %s is mislukt, omdat het bestand niet in de bestandscache kon worden gevonden",
+ "Cannot increase permissions of %s" : "Kan de rechten van %s niet verruimen",
+ "Expiration date is in the past" : "De vervaldatum ligt in het verleden",
+ "Cannot set expiration date more than %s days in the future" : "Kan vervaldatum niet verder dan %s dagen in de toekomst instellen",
"Could not find category \"%s\"" : "Kon categorie \"%s\" niet vinden",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Alleen de volgende tekens zijn toegestaan in een gebruikersnaam: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Alleen de volgende tekens zijn toegestaan in een gebruikersnaam: \"a-z\", \"A-Z\", \"0-9\", en \"_.@-\"",
"A valid username must be provided" : "Er moet een geldige gebruikersnaam worden opgegeven",
"A valid password must be provided" : "Er moet een geldig wachtwoord worden opgegeven",
"The username is already being used" : "De gebruikersnaam bestaat al",
@@ -138,8 +143,6 @@
"Please ask your server administrator to restart the web server." : "Vraag uw beheerder de webserver opnieuw op te starten.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 vereist",
"Please upgrade your database version" : "Werk uw database versie bij",
- "Error occurred while checking PostgreSQL version" : "Een fout trad op bij checken PostgreSQL versie",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Verifieer dat u PostgreSQL >=9 draait of check de logs voor meer informatie over deze fout",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Wijzig de permissies in 0770 zodat de directory niet door anderen bekeken kan worden.",
"Data directory (%s) is readable by other users" : "De datadirectory (%s) is leesbaar voor andere gebruikers",
"Data directory (%s) must be an absolute path" : "De datadirectory (%s) moet een absoluut pad hebben",
@@ -147,6 +150,10 @@
"Data directory (%s) is invalid" : "Data directory (%s) is ongeldig",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Verifieer dat de data directory een bestand \".ocdata\" in de hoofdmap heeft.",
"Could not obtain lock type %d on \"%s\"." : "Kon geen lock type %d krijgen op \"%s\".",
- "Storage not available" : "Opslag niet beschikbaar"
+ "Storage unauthorized. %s" : "Opslag niet toegestaan. %s",
+ "Storage incomplete configuration. %s" : "Incomplete opslagconfiguratie. %s",
+ "Storage connection error. %s" : "Opslagverbindingsfout. %s",
+ "Storage not available" : "Opslag niet beschikbaar",
+ "Storage connection timeout. %s" : "Opslagverbinding time-out. %s"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/oc.js b/lib/l10n/oc.js
index b304ccaeec0..74eeaa4a2ed 100644
--- a/lib/l10n/oc.js
+++ b/lib/l10n/oc.js
@@ -112,7 +112,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Lo partiment de %s a fracassat perque lo fichièr es pas estat trobat dins los fichièrs meses en escondedor.",
"Could not find category \"%s\"" : "Impossible de trobar la categoria \"%s\"",
"Apps" : "Aplicacions",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Sols los caractèrs seguents son autorizats dins un nom d'utilizaire : \"a-z\", \"A-Z\", \"0-9\", e \"_.@-\"",
"A valid username must be provided" : "Un nom d'utilizaire valid deu èsser sasit",
"A valid password must be provided" : "Un senhal valid deu èsser sasit",
"The username is already being used" : "Aqueste nom d'utilizaire es ja utilizat",
@@ -139,8 +138,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Demandatz a vòstre administrator servidor que reavie lo servidor web.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 requesit",
"Please upgrade your database version" : "Metètz a jorn vòstre gestionari de banca de donadas",
- "Error occurred while checking PostgreSQL version" : "Una error s’es produsida pendent la recuperacion del numèro de version de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Verificatz qu'utilizatz PostgreSQL >= 9 , o agachatz dins lo jornal d’error per mai d’informacions sus aqueste problèma",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Cambiatz las permissions del repertòri en mòde 0770 per fin que son contengut pòsca èsser listat pels autres utilizaires.",
"Data directory (%s) is readable by other users" : "Lo repertòri de donadas (%s) es legible pels autres utilizaires",
"Data directory (%s) must be an absolute path" : "Lo camin del dorsièr de donadas (%s) deu èsser absolut",
diff --git a/lib/l10n/oc.json b/lib/l10n/oc.json
index 2341f7d199b..20fb3c52851 100644
--- a/lib/l10n/oc.json
+++ b/lib/l10n/oc.json
@@ -110,7 +110,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Lo partiment de %s a fracassat perque lo fichièr es pas estat trobat dins los fichièrs meses en escondedor.",
"Could not find category \"%s\"" : "Impossible de trobar la categoria \"%s\"",
"Apps" : "Aplicacions",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Sols los caractèrs seguents son autorizats dins un nom d'utilizaire : \"a-z\", \"A-Z\", \"0-9\", e \"_.@-\"",
"A valid username must be provided" : "Un nom d'utilizaire valid deu èsser sasit",
"A valid password must be provided" : "Un senhal valid deu èsser sasit",
"The username is already being used" : "Aqueste nom d'utilizaire es ja utilizat",
@@ -137,8 +136,6 @@
"Please ask your server administrator to restart the web server." : "Demandatz a vòstre administrator servidor que reavie lo servidor web.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 requesit",
"Please upgrade your database version" : "Metètz a jorn vòstre gestionari de banca de donadas",
- "Error occurred while checking PostgreSQL version" : "Una error s’es produsida pendent la recuperacion del numèro de version de PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Verificatz qu'utilizatz PostgreSQL >= 9 , o agachatz dins lo jornal d’error per mai d’informacions sus aqueste problèma",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Cambiatz las permissions del repertòri en mòde 0770 per fin que son contengut pòsca èsser listat pels autres utilizaires.",
"Data directory (%s) is readable by other users" : "Lo repertòri de donadas (%s) es legible pels autres utilizaires",
"Data directory (%s) must be an absolute path" : "Lo camin del dorsièr de donadas (%s) deu èsser absolut",
diff --git a/lib/l10n/pl.js b/lib/l10n/pl.js
index e347fd6249a..76318fc8acb 100644
--- a/lib/l10n/pl.js
+++ b/lib/l10n/pl.js
@@ -90,7 +90,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Współdzielenie %s nie powiodło się, ponieważ plik nie może zostać odnaleziony w buforze plików",
"Could not find category \"%s\"" : "Nie można odnaleźć kategorii \"%s\"",
"Apps" : "Aplikacje",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "W nazwach użytkowników dozwolone są wyłącznie następujące znaki: \"a-z\", \"A-Z\", \"0-9\", oraz \"_.@-\"",
"A valid username must be provided" : "Należy podać prawidłową nazwę użytkownika",
"A valid password must be provided" : "Należy podać prawidłowe hasło",
"The username is already being used" : "Ta nazwa użytkownika jest już używana",
@@ -110,8 +109,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Poproś administratora serwera o restart serwera www.",
"PostgreSQL >= 9 required" : "Wymagany PostgreSQL >= 9",
"Please upgrade your database version" : "Uaktualnij wersję bazy danych",
- "Error occurred while checking PostgreSQL version" : "Wystąpił błąd podczas sprawdzania wersji PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Upewnij się, że PostgreSQL jest w wersji co najmniej 9 lub sprawdź log by uzyskać więcej informacji na temat błędu",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Zmień uprawnienia na 0770, żeby ukryć zawartość katalogu przed innymi użytkownikami.",
"Data directory (%s) is readable by other users" : "Katalog danych (%s) jest możliwy do odczytania przez innych użytkowników",
"Data directory (%s) is invalid" : "Katalog danych (%s) jest nieprawidłowy",
diff --git a/lib/l10n/pl.json b/lib/l10n/pl.json
index 5f4151f4012..2bd882c012f 100644
--- a/lib/l10n/pl.json
+++ b/lib/l10n/pl.json
@@ -88,7 +88,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Współdzielenie %s nie powiodło się, ponieważ plik nie może zostać odnaleziony w buforze plików",
"Could not find category \"%s\"" : "Nie można odnaleźć kategorii \"%s\"",
"Apps" : "Aplikacje",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "W nazwach użytkowników dozwolone są wyłącznie następujące znaki: \"a-z\", \"A-Z\", \"0-9\", oraz \"_.@-\"",
"A valid username must be provided" : "Należy podać prawidłową nazwę użytkownika",
"A valid password must be provided" : "Należy podać prawidłowe hasło",
"The username is already being used" : "Ta nazwa użytkownika jest już używana",
@@ -108,8 +107,6 @@
"Please ask your server administrator to restart the web server." : "Poproś administratora serwera o restart serwera www.",
"PostgreSQL >= 9 required" : "Wymagany PostgreSQL >= 9",
"Please upgrade your database version" : "Uaktualnij wersję bazy danych",
- "Error occurred while checking PostgreSQL version" : "Wystąpił błąd podczas sprawdzania wersji PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Upewnij się, że PostgreSQL jest w wersji co najmniej 9 lub sprawdź log by uzyskać więcej informacji na temat błędu",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Zmień uprawnienia na 0770, żeby ukryć zawartość katalogu przed innymi użytkownikami.",
"Data directory (%s) is readable by other users" : "Katalog danych (%s) jest możliwy do odczytania przez innych użytkowników",
"Data directory (%s) is invalid" : "Katalog danych (%s) jest nieprawidłowy",
diff --git a/lib/l10n/pt_BR.js b/lib/l10n/pt_BR.js
index 5939fc1f3ca..1ffbdc17a7b 100644
--- a/lib/l10n/pt_BR.js
+++ b/lib/l10n/pt_BR.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Arquivos do tipo %s não são suportados",
"Failed to open archive when installing app" : "Falha para abrir o arquivo enquanto instalava o aplicativo",
"App does not provide an info.xml file" : "O aplicativo não fornece um arquivo info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "A assinatura não pode ser verificada. Por favor entre em contato com o desenvolvedor do aplicativo e verificar sua tela de administração.",
"App can't be installed because of not allowed code in the App" : "O aplicativo não pode ser instalado por causa do código não permitido no Aplivativo",
"App can't be installed because it is not compatible with this version of ownCloud" : "O aplicativo não pode ser instalado porque não é compatível com esta versão do ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "O aplicativo não pode ser instalado porque ele contém a marca <shipped>verdadeiro</shipped> que não é permitido para aplicações não embarcadas",
@@ -96,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Compartilhamento %s falhou, porque %s não é membro do grupo %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Você precisa fornecer uma senha para criar um link público, apenas links protegidos são permitidos",
"Sharing %s failed, because sharing with links is not allowed" : "Compartilhamento %s falhou, porque compartilhamento com links não é permitido",
+ "Not allowed to create a federated share with the same user" : "Não é permitido criar um compartilhamento associado com o mesmo usuário",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "O compartilhamento %s falhou, porque não foi possível encontrar %s, talvez o servidor esteja inacessível.",
"Share type %s is not valid for %s" : "Tipo de compartilhamento %s não é válido para %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Definir permissões para %s falhou, porque as permissões excedem as permissões concedidas a %s",
@@ -111,9 +113,12 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Compartilhamento %s falhou, porque recompartilhamentos não são permitidos",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Compartilhamento %s falhou, porque a infra-estrutura de compartilhamento para %s não conseguiu encontrar a sua fonte",
"Sharing %s failed, because the file could not be found in the file cache" : "Compartilhamento %s falhou, porque o arquivo não pôde ser encontrado no cache de arquivos",
+ "Cannot increase permissions of %s" : "Não é possível aumentar as permissões de %s",
+ "Expiration date is in the past" : "Data de validade está ultrapassada",
+ "Cannot set expiration date more than %s days in the future" : "Não é possível definir a data de validade mais de %s dias no futuro",
"Could not find category \"%s\"" : "Impossível localizar categoria \"%s\"",
"Apps" : "Aplicações",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Somente os seguintes caracteres são permitidos no nome do usuário: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Somente os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"",
"A valid username must be provided" : "Forneça um nome de usuário válido",
"A valid password must be provided" : "Forneça uma senha válida",
"The username is already being used" : "Este nome de usuário já está sendo usado",
@@ -140,8 +145,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Por favor, peça ao seu administrador do servidor para reiniciar o servidor web.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 requirido",
"Please upgrade your database version" : "Por favor, atualize sua versão do banco de dados",
- "Error occurred while checking PostgreSQL version" : "Erro ao verificar a versão do PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Por favor, verifique se você tem PostgreSQL> = 9 ou verificar os logs para obter mais informações sobre o erro",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor, altere as permissões para 0770 para que o diretório não possa ser listado por outros usuários.",
"Data directory (%s) is readable by other users" : "Diretório de dados (%s) pode ser lido por outros usuários",
"Data directory (%s) must be an absolute path" : "Diretório de dados (%s) deve ser um caminho absoluto",
@@ -149,6 +152,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "Diretório de dados (%s) é inválido",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Por favor, verifique se o diretório de dados contém um arquivo \".ocdata\" em sua raiz.",
"Could not obtain lock type %d on \"%s\"." : "Não foi possível obter tipo de bloqueio %d em \"%s\".",
- "Storage not available" : "Armazanamento não disponível"
+ "Storage unauthorized. %s" : "Armazenamento não autorizado. %s",
+ "Storage incomplete configuration. %s" : "Incompleta configuração de armazenamento. %s",
+ "Storage connection error. %s" : "Erro na conexão de armazenamento. %s",
+ "Storage not available" : "Armazanamento não disponível",
+ "Storage connection timeout. %s" : "Tempo limite de conexão de armazenamento. %s"
},
"nplurals=2; plural=(n > 1);");
diff --git a/lib/l10n/pt_BR.json b/lib/l10n/pt_BR.json
index e25e14daa13..cb0e48af0db 100644
--- a/lib/l10n/pt_BR.json
+++ b/lib/l10n/pt_BR.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "Arquivos do tipo %s não são suportados",
"Failed to open archive when installing app" : "Falha para abrir o arquivo enquanto instalava o aplicativo",
"App does not provide an info.xml file" : "O aplicativo não fornece um arquivo info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "A assinatura não pode ser verificada. Por favor entre em contato com o desenvolvedor do aplicativo e verificar sua tela de administração.",
"App can't be installed because of not allowed code in the App" : "O aplicativo não pode ser instalado por causa do código não permitido no Aplivativo",
"App can't be installed because it is not compatible with this version of ownCloud" : "O aplicativo não pode ser instalado porque não é compatível com esta versão do ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "O aplicativo não pode ser instalado porque ele contém a marca <shipped>verdadeiro</shipped> que não é permitido para aplicações não embarcadas",
@@ -94,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Compartilhamento %s falhou, porque %s não é membro do grupo %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Você precisa fornecer uma senha para criar um link público, apenas links protegidos são permitidos",
"Sharing %s failed, because sharing with links is not allowed" : "Compartilhamento %s falhou, porque compartilhamento com links não é permitido",
+ "Not allowed to create a federated share with the same user" : "Não é permitido criar um compartilhamento associado com o mesmo usuário",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "O compartilhamento %s falhou, porque não foi possível encontrar %s, talvez o servidor esteja inacessível.",
"Share type %s is not valid for %s" : "Tipo de compartilhamento %s não é válido para %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Definir permissões para %s falhou, porque as permissões excedem as permissões concedidas a %s",
@@ -109,9 +111,12 @@
"Sharing %s failed, because resharing is not allowed" : "Compartilhamento %s falhou, porque recompartilhamentos não são permitidos",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Compartilhamento %s falhou, porque a infra-estrutura de compartilhamento para %s não conseguiu encontrar a sua fonte",
"Sharing %s failed, because the file could not be found in the file cache" : "Compartilhamento %s falhou, porque o arquivo não pôde ser encontrado no cache de arquivos",
+ "Cannot increase permissions of %s" : "Não é possível aumentar as permissões de %s",
+ "Expiration date is in the past" : "Data de validade está ultrapassada",
+ "Cannot set expiration date more than %s days in the future" : "Não é possível definir a data de validade mais de %s dias no futuro",
"Could not find category \"%s\"" : "Impossível localizar categoria \"%s\"",
"Apps" : "Aplicações",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Somente os seguintes caracteres são permitidos no nome do usuário: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Somente os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"",
"A valid username must be provided" : "Forneça um nome de usuário válido",
"A valid password must be provided" : "Forneça uma senha válida",
"The username is already being used" : "Este nome de usuário já está sendo usado",
@@ -138,8 +143,6 @@
"Please ask your server administrator to restart the web server." : "Por favor, peça ao seu administrador do servidor para reiniciar o servidor web.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 requirido",
"Please upgrade your database version" : "Por favor, atualize sua versão do banco de dados",
- "Error occurred while checking PostgreSQL version" : "Erro ao verificar a versão do PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Por favor, verifique se você tem PostgreSQL> = 9 ou verificar os logs para obter mais informações sobre o erro",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor, altere as permissões para 0770 para que o diretório não possa ser listado por outros usuários.",
"Data directory (%s) is readable by other users" : "Diretório de dados (%s) pode ser lido por outros usuários",
"Data directory (%s) must be an absolute path" : "Diretório de dados (%s) deve ser um caminho absoluto",
@@ -147,6 +150,10 @@
"Data directory (%s) is invalid" : "Diretório de dados (%s) é inválido",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Por favor, verifique se o diretório de dados contém um arquivo \".ocdata\" em sua raiz.",
"Could not obtain lock type %d on \"%s\"." : "Não foi possível obter tipo de bloqueio %d em \"%s\".",
- "Storage not available" : "Armazanamento não disponível"
+ "Storage unauthorized. %s" : "Armazenamento não autorizado. %s",
+ "Storage incomplete configuration. %s" : "Incompleta configuração de armazenamento. %s",
+ "Storage connection error. %s" : "Erro na conexão de armazenamento. %s",
+ "Storage not available" : "Armazanamento não disponível",
+ "Storage connection timeout. %s" : "Tempo limite de conexão de armazenamento. %s"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/lib/l10n/pt_PT.js b/lib/l10n/pt_PT.js
index a4207e996ad..b2f2a21afb5 100644
--- a/lib/l10n/pt_PT.js
+++ b/lib/l10n/pt_PT.js
@@ -4,7 +4,7 @@ OC.L10N.register(
"Cannot write into \"config\" directory!" : "Não é possível gravar na directoria \"configurar\"!",
"This can usually be fixed by giving the webserver write access to the config directory" : "Isto pode ser resolvido normalmente dando ao servidor web direitos de escrita ao directório de configuração",
"See %s" : "Ver %s",
- "This can usually be fixed by %sgiving the webserver write access to the config directory%s." : "Isto pode ser resolvido normalmente %sdando ao servidor web direitos de escrita no directório de configuração%s.",
+ "This can usually be fixed by %sgiving the webserver write access to the config directory%s." : "Isto pode ser resolvido normalmente %sdando priviégios de escrita no directório de configuração ao serviço web%s.",
"Sample configuration detected" : "Exemplo de configuração detectada",
"It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Foi detectado que a configuração de amostra foi copiada. Isso pode danificar a sua instalação e não é suportado. Por favor, leia a documentação antes de realizar mudanças no config.php",
"PHP %s or higher is required." : "Necessário PHP %s ou maior.",
@@ -53,6 +53,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Arquivos do tipo %s não são suportados",
"Failed to open archive when installing app" : "Ocorreu um erro ao abrir o ficheiro de instalação desta aplicação",
"App does not provide an info.xml file" : "A aplicação não disponibiliza um ficheiro info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Assinatura não foi verificada. Contate o desenvolvedor da aplicação e verifique o painel de administrador.",
"App can't be installed because of not allowed code in the App" : "A aplicação não pode ser instalado devido a código não permitido dentro da aplicação",
"App can't be installed because it is not compatible with this version of ownCloud" : "A aplicação não pode ser instalada por não ser compatível com esta versão do ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "Esta aplicação não pode ser instalada por que contém o tag <shipped>true</shipped> que só é permitido para aplicações nativas",
@@ -84,13 +85,16 @@ OC.L10N.register(
"Sharing %s failed, because the backend does not allow shares from type %i" : "A partilha de %s falhou porque a interface não permite as partilhas do tipo %i",
"Sharing %s failed, because the file does not exist" : "A partilha de %s falhou, porque o ficheiro não existe",
"You are not allowed to share %s" : "Não está autorizado a partilhar %s",
+ "Sharing %s failed, because you can not share with yourself" : "A partilha de %s falhou, porque não é possível partilhar consigo mesmo",
"Sharing %s failed, because the user %s does not exist" : "A partilha %s falhou, porque o utilizador %s nao existe",
"Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" : "A partilha %s falhou, porque o utilizador %s não pertence a nenhum dos grupos que %s é membro de",
"Sharing %s failed, because this item is already shared with %s" : "A partilha %s falhou, porque o item já está a ser partilhado com %s",
+ "Sharing %s failed, because this item is already shared with user %s" : "A partilha de %s falhou, porque este item já está a ser partilhado com o utilizador %s",
"Sharing %s failed, because the group %s does not exist" : "A partilha %s falhou, porque o grupo %s não existe",
"Sharing %s failed, because %s is not a member of the group %s" : "A partilha %s falhou, porque o utilizador %s não é membro do grupo %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Necessita de fornecer a senha para criar um link publico, só são permitidos links protegidos",
"Sharing %s failed, because sharing with links is not allowed" : "A partilha de %s falhou, porque partilhar com links não é permitido",
+ "Not allowed to create a federated share with the same user" : "Não é possível criar uma partilha federada com o mesmo utilizador",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "A partilha de %s falhou, não foi possível encontrar %s. É possível que o servidor esteja inacessível.",
"Share type %s is not valid for %s" : "O tipo de partilha %s não é válido para %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Definir permissões para %s falhou, porque as permissões excedem as permissões concedidas a %s",
@@ -106,14 +110,18 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "A partilha %s falhou, porque repartilhar não é permitido",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "A partilha %s falhou porque a partilha da interface para %s não conseguiu encontrar a sua fonte",
"Sharing %s failed, because the file could not be found in the file cache" : "A partilha %s falhou, devido ao ficheiro não poder ser encontrado na cache de ficheiros",
+ "Cannot increase permissions of %s" : "Não é possível aumentar as permissões de %s",
+ "Expiration date is in the past" : "A data de expiração está no passado",
+ "Cannot set expiration date more than %s days in the future" : "Não é possível definir data de expiração a mais de %s dias no futuro",
"Could not find category \"%s\"" : "Não foi encontrado a categoria \"%s\"",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Apenas os seguintes caracteres são permitidos no nome de utilizador: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Apenas os seguintes caracteres são permitidos num nome de utilizador: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"",
"A valid username must be provided" : "Um nome de utilizador válido deve ser fornecido",
"A valid password must be provided" : "Uma password válida deve ser fornecida",
"The username is already being used" : "O nome de utilizador já está a ser usado",
"No database drivers (sqlite, mysql, or postgresql) installed." : "Nenhuma base de dados de drivers (sqlite, mysql, or postgresql) instaladas.",
"Microsoft Windows Platform is not supported" : "A plataforma Microsoft Windows não é suportada",
+ "Running ownCloud Server on the Microsoft Windows platform is not supported. We suggest you use a Linux server in a virtual machine if you have no option for migrating the server itself. Find Linux packages as well as easy to deploy virtual machine images on <a href=\"%s\">%s</a>. For migrating existing installations to Linux you can find some tips and a migration script in <a href=\"%s\">our documentation</a>." : "Executar um Servidor ownCloud na plataforma Microsoft Windows não é suportado. Nós sugerimos que use um servidor Linux numa máquina virtual se não tiver opção parar migrar o servidor por si mesmo. Encontre pacotes Linux, assim como imagens de máquinas virtuais prontas a correr em <a href=\"%s\">%s</a>. Parar migrar instalações existentes para Linux, poderás encontrar algumas dicas e um script de migração na <a href=\"%s\">nossa documentação</a>.",
"Cannot write into \"config\" directory" : "Não é possível escrever na directoria \"configurar\"",
"Cannot write into \"apps\" directory" : "Não é possivel escrever na directoria \"aplicações\"",
"This can usually be fixed by %sgiving the webserver write access to the apps directory%s or disabling the appstore in the config file." : "Isto pode ser normalmente resolvido %sdando ao servidor web direito de escrita para o directório de aplicação%s ou desactivando a loja de aplicações no ficheiro de configuração.",
@@ -126,13 +134,14 @@ OC.L10N.register(
"PHP module %s not installed." : "O modulo %s PHP não está instalado.",
"PHP setting \"%s\" is not set to \"%s\"." : "Configuração PHP \"%s\" não está definida para \"%s\".",
"Adjusting this setting in php.ini will make ownCloud run again" : "Ajustar esta configuração no php.ini fará com que o ownCloud funcione de novo",
+ "mbstring.func_overload is set to \"%s\" instead of the expected value \"0\"" : "mbstring.func_overload está configurado para \"%s\" invés do valor habitual de \"0\"",
+ "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini" : "Para corrigir este problema altere o <code>mbstring.func_overload</code> para <code>0</code> no seu php.ini",
+ "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP está aparentemente configurado a remover blocos doc em linha. Isto vai tornar algumas aplicações básicas inacessíveis.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isto é provavelmente causado por uma cache/acelerador como o Zend OPcache or eAcelerador.",
"PHP modules have been installed, but they are still listed as missing?" : "Os módulos PHP foram instalados, mas eles ainda estão listados como desaparecidos?",
"Please ask your server administrator to restart the web server." : "Pro favor pergunte ao seu administrador do servidor para reiniciar o servidor da internet.",
"PostgreSQL >= 9 required" : "Necessita PostgreSQL >= 9",
"Please upgrade your database version" : "Por favor actualize a sua versão da base de dados",
- "Error occurred while checking PostgreSQL version" : "Ocorreu um erro enquanto pesquisava a versão do PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Por favor confirme que tem o PostgreSQL >= 9 ou verifique os registos para mais informação sobre o erro",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que esse directório não possa ser listado por outros utilizadores.",
"Data directory (%s) is readable by other users" : "O directório de dados (%s) é legível para outros utilizadores",
"Data directory (%s) must be an absolute path" : "Diretório de dados (%s) deve ser um caminho absoluto",
@@ -140,6 +149,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "Directoria data (%s) é invalida",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Por favor verifique que a directoria data contem um ficheiro \".ocdata\" na sua raiz.",
"Could not obtain lock type %d on \"%s\"." : "Não foi possível obter o tipo de bloqueio %d em \"%s\".",
- "Storage not available" : "Armazenamento indisposinvel"
+ "Storage unauthorized. %s" : "Armazenamento desautorizado. %s",
+ "Storage incomplete configuration. %s" : "Configuração incompleta do armazenamento. %s",
+ "Storage connection error. %s" : "Erro de ligação ao armazenamento. %s",
+ "Storage not available" : "Armazenamento indisposinvel",
+ "Storage connection timeout. %s" : "Tempo de ligação ao armazenamento expirou. %s"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/pt_PT.json b/lib/l10n/pt_PT.json
index 94a85e0d371..c1a7f6dfd4a 100644
--- a/lib/l10n/pt_PT.json
+++ b/lib/l10n/pt_PT.json
@@ -2,7 +2,7 @@
"Cannot write into \"config\" directory!" : "Não é possível gravar na directoria \"configurar\"!",
"This can usually be fixed by giving the webserver write access to the config directory" : "Isto pode ser resolvido normalmente dando ao servidor web direitos de escrita ao directório de configuração",
"See %s" : "Ver %s",
- "This can usually be fixed by %sgiving the webserver write access to the config directory%s." : "Isto pode ser resolvido normalmente %sdando ao servidor web direitos de escrita no directório de configuração%s.",
+ "This can usually be fixed by %sgiving the webserver write access to the config directory%s." : "Isto pode ser resolvido normalmente %sdando priviégios de escrita no directório de configuração ao serviço web%s.",
"Sample configuration detected" : "Exemplo de configuração detectada",
"It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Foi detectado que a configuração de amostra foi copiada. Isso pode danificar a sua instalação e não é suportado. Por favor, leia a documentação antes de realizar mudanças no config.php",
"PHP %s or higher is required." : "Necessário PHP %s ou maior.",
@@ -51,6 +51,7 @@
"Archives of type %s are not supported" : "Arquivos do tipo %s não são suportados",
"Failed to open archive when installing app" : "Ocorreu um erro ao abrir o ficheiro de instalação desta aplicação",
"App does not provide an info.xml file" : "A aplicação não disponibiliza um ficheiro info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Assinatura não foi verificada. Contate o desenvolvedor da aplicação e verifique o painel de administrador.",
"App can't be installed because of not allowed code in the App" : "A aplicação não pode ser instalado devido a código não permitido dentro da aplicação",
"App can't be installed because it is not compatible with this version of ownCloud" : "A aplicação não pode ser instalada por não ser compatível com esta versão do ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "Esta aplicação não pode ser instalada por que contém o tag <shipped>true</shipped> que só é permitido para aplicações nativas",
@@ -82,13 +83,16 @@
"Sharing %s failed, because the backend does not allow shares from type %i" : "A partilha de %s falhou porque a interface não permite as partilhas do tipo %i",
"Sharing %s failed, because the file does not exist" : "A partilha de %s falhou, porque o ficheiro não existe",
"You are not allowed to share %s" : "Não está autorizado a partilhar %s",
+ "Sharing %s failed, because you can not share with yourself" : "A partilha de %s falhou, porque não é possível partilhar consigo mesmo",
"Sharing %s failed, because the user %s does not exist" : "A partilha %s falhou, porque o utilizador %s nao existe",
"Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" : "A partilha %s falhou, porque o utilizador %s não pertence a nenhum dos grupos que %s é membro de",
"Sharing %s failed, because this item is already shared with %s" : "A partilha %s falhou, porque o item já está a ser partilhado com %s",
+ "Sharing %s failed, because this item is already shared with user %s" : "A partilha de %s falhou, porque este item já está a ser partilhado com o utilizador %s",
"Sharing %s failed, because the group %s does not exist" : "A partilha %s falhou, porque o grupo %s não existe",
"Sharing %s failed, because %s is not a member of the group %s" : "A partilha %s falhou, porque o utilizador %s não é membro do grupo %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Necessita de fornecer a senha para criar um link publico, só são permitidos links protegidos",
"Sharing %s failed, because sharing with links is not allowed" : "A partilha de %s falhou, porque partilhar com links não é permitido",
+ "Not allowed to create a federated share with the same user" : "Não é possível criar uma partilha federada com o mesmo utilizador",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "A partilha de %s falhou, não foi possível encontrar %s. É possível que o servidor esteja inacessível.",
"Share type %s is not valid for %s" : "O tipo de partilha %s não é válido para %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Definir permissões para %s falhou, porque as permissões excedem as permissões concedidas a %s",
@@ -104,14 +108,18 @@
"Sharing %s failed, because resharing is not allowed" : "A partilha %s falhou, porque repartilhar não é permitido",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "A partilha %s falhou porque a partilha da interface para %s não conseguiu encontrar a sua fonte",
"Sharing %s failed, because the file could not be found in the file cache" : "A partilha %s falhou, devido ao ficheiro não poder ser encontrado na cache de ficheiros",
+ "Cannot increase permissions of %s" : "Não é possível aumentar as permissões de %s",
+ "Expiration date is in the past" : "A data de expiração está no passado",
+ "Cannot set expiration date more than %s days in the future" : "Não é possível definir data de expiração a mais de %s dias no futuro",
"Could not find category \"%s\"" : "Não foi encontrado a categoria \"%s\"",
"Apps" : "Apps",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Apenas os seguintes caracteres são permitidos no nome de utilizador: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Apenas os seguintes caracteres são permitidos num nome de utilizador: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"",
"A valid username must be provided" : "Um nome de utilizador válido deve ser fornecido",
"A valid password must be provided" : "Uma password válida deve ser fornecida",
"The username is already being used" : "O nome de utilizador já está a ser usado",
"No database drivers (sqlite, mysql, or postgresql) installed." : "Nenhuma base de dados de drivers (sqlite, mysql, or postgresql) instaladas.",
"Microsoft Windows Platform is not supported" : "A plataforma Microsoft Windows não é suportada",
+ "Running ownCloud Server on the Microsoft Windows platform is not supported. We suggest you use a Linux server in a virtual machine if you have no option for migrating the server itself. Find Linux packages as well as easy to deploy virtual machine images on <a href=\"%s\">%s</a>. For migrating existing installations to Linux you can find some tips and a migration script in <a href=\"%s\">our documentation</a>." : "Executar um Servidor ownCloud na plataforma Microsoft Windows não é suportado. Nós sugerimos que use um servidor Linux numa máquina virtual se não tiver opção parar migrar o servidor por si mesmo. Encontre pacotes Linux, assim como imagens de máquinas virtuais prontas a correr em <a href=\"%s\">%s</a>. Parar migrar instalações existentes para Linux, poderás encontrar algumas dicas e um script de migração na <a href=\"%s\">nossa documentação</a>.",
"Cannot write into \"config\" directory" : "Não é possível escrever na directoria \"configurar\"",
"Cannot write into \"apps\" directory" : "Não é possivel escrever na directoria \"aplicações\"",
"This can usually be fixed by %sgiving the webserver write access to the apps directory%s or disabling the appstore in the config file." : "Isto pode ser normalmente resolvido %sdando ao servidor web direito de escrita para o directório de aplicação%s ou desactivando a loja de aplicações no ficheiro de configuração.",
@@ -124,13 +132,14 @@
"PHP module %s not installed." : "O modulo %s PHP não está instalado.",
"PHP setting \"%s\" is not set to \"%s\"." : "Configuração PHP \"%s\" não está definida para \"%s\".",
"Adjusting this setting in php.ini will make ownCloud run again" : "Ajustar esta configuração no php.ini fará com que o ownCloud funcione de novo",
+ "mbstring.func_overload is set to \"%s\" instead of the expected value \"0\"" : "mbstring.func_overload está configurado para \"%s\" invés do valor habitual de \"0\"",
+ "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini" : "Para corrigir este problema altere o <code>mbstring.func_overload</code> para <code>0</code> no seu php.ini",
+ "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP está aparentemente configurado a remover blocos doc em linha. Isto vai tornar algumas aplicações básicas inacessíveis.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isto é provavelmente causado por uma cache/acelerador como o Zend OPcache or eAcelerador.",
"PHP modules have been installed, but they are still listed as missing?" : "Os módulos PHP foram instalados, mas eles ainda estão listados como desaparecidos?",
"Please ask your server administrator to restart the web server." : "Pro favor pergunte ao seu administrador do servidor para reiniciar o servidor da internet.",
"PostgreSQL >= 9 required" : "Necessita PostgreSQL >= 9",
"Please upgrade your database version" : "Por favor actualize a sua versão da base de dados",
- "Error occurred while checking PostgreSQL version" : "Ocorreu um erro enquanto pesquisava a versão do PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Por favor confirme que tem o PostgreSQL >= 9 ou verifique os registos para mais informação sobre o erro",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que esse directório não possa ser listado por outros utilizadores.",
"Data directory (%s) is readable by other users" : "O directório de dados (%s) é legível para outros utilizadores",
"Data directory (%s) must be an absolute path" : "Diretório de dados (%s) deve ser um caminho absoluto",
@@ -138,6 +147,10 @@
"Data directory (%s) is invalid" : "Directoria data (%s) é invalida",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Por favor verifique que a directoria data contem um ficheiro \".ocdata\" na sua raiz.",
"Could not obtain lock type %d on \"%s\"." : "Não foi possível obter o tipo de bloqueio %d em \"%s\".",
- "Storage not available" : "Armazenamento indisposinvel"
+ "Storage unauthorized. %s" : "Armazenamento desautorizado. %s",
+ "Storage incomplete configuration. %s" : "Configuração incompleta do armazenamento. %s",
+ "Storage connection error. %s" : "Erro de ligação ao armazenamento. %s",
+ "Storage not available" : "Armazenamento indisposinvel",
+ "Storage connection timeout. %s" : "Tempo de ligação ao armazenamento expirou. %s"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/ro.js b/lib/l10n/ro.js
index 008fcd83349..92e739b7d54 100644
--- a/lib/l10n/ro.js
+++ b/lib/l10n/ro.js
@@ -51,7 +51,6 @@ OC.L10N.register(
"PHP modules have been installed, but they are still listed as missing?" : "Modulele PHP au fost instalate, dar apar ca lipsind?",
"PostgreSQL >= 9 required" : "Este necesară versiunea 9 sau mai mare a PostgreSQL",
"Please upgrade your database version" : "Actualizați baza de date la o versiune mai nouă",
- "Error occurred while checking PostgreSQL version" : "A apărut o eroare la verificarea versiunii PostgreSQL",
"Storage not available" : "Spațiu de stocare indisponibil"
},
"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));");
diff --git a/lib/l10n/ro.json b/lib/l10n/ro.json
index b23f99f410a..9f6abb00413 100644
--- a/lib/l10n/ro.json
+++ b/lib/l10n/ro.json
@@ -49,7 +49,6 @@
"PHP modules have been installed, but they are still listed as missing?" : "Modulele PHP au fost instalate, dar apar ca lipsind?",
"PostgreSQL >= 9 required" : "Este necesară versiunea 9 sau mai mare a PostgreSQL",
"Please upgrade your database version" : "Actualizați baza de date la o versiune mai nouă",
- "Error occurred while checking PostgreSQL version" : "A apărut o eroare la verificarea versiunii PostgreSQL",
"Storage not available" : "Spațiu de stocare indisponibil"
},"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"
} \ No newline at end of file
diff --git a/lib/l10n/ru.js b/lib/l10n/ru.js
index 58b05ccd2e5..14a2b11dc01 100644
--- a/lib/l10n/ru.js
+++ b/lib/l10n/ru.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Архивы %s не поддерживаются",
"Failed to open archive when installing app" : "Ошибка открытия архива при установке приложения",
"App does not provide an info.xml file" : "Приложение не имеет файла info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Подпись не может быть проверена. Пожалуйста, свяжитесь с разработчиком приложения и проверьте свою страницу администратора.",
"App can't be installed because of not allowed code in the App" : "Приложение невозможно установить. В нем содержится запрещенный код.",
"App can't be installed because it is not compatible with this version of ownCloud" : "Приложение невозможно установить. Не совместимо с текущей версией ownCloud.",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "Приложение невозможно установить. Оно содержит параметр <shipped>true</shipped> который не допустим для приложений, не входящих в поставку.",
@@ -96,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Не удалось поделиться %s, пользователь %s не является членом группы %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Вам нужно задать пароль для создания публичной ссылки. Разрешены только защищённые ссылки",
"Sharing %s failed, because sharing with links is not allowed" : "Не удалось поделиться %s, открытие доступа по ссылке запрещено",
+ "Not allowed to create a federated share with the same user" : "Не допускается создание федеративного общего ресурса с тем-же пользователем",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Не удалось поделиться %s, не удалось найти %s, возможно, сервер не доступен.",
"Share type %s is not valid for %s" : "Тип общего доступа %s недопустим для %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Не удалось настроить права доступа для %s, указанные права доступа превышают предоставленные для %s",
@@ -111,9 +113,12 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Не удалось поделиться %s, повторное открытие доступа запрещено",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Не удалось поделиться %s, бэкенд общего доступа не нашел путь до %s",
"Sharing %s failed, because the file could not be found in the file cache" : "Не удалось поделиться %s, элемент не найден в файловом кеше.",
+ "Cannot increase permissions of %s" : "Невозможно увеличить права доступа для %s",
+ "Expiration date is in the past" : "Дата окончания срока действия уже прошла",
+ "Cannot set expiration date more than %s days in the future" : "Невозможно установить дату окончания срока действия более %s дней",
"Could not find category \"%s\"" : "Категория \"%s\" не найдена",
"Apps" : "Приложения",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Только следующие символы допускаются в имени пользователя: \"a-z\", \"A-Z\", \"0-9\", и \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "В качестве имени пользователя допускаются следующие символы: \"a-z\", \"A-Z\", \"0-9\" и \"_.@-'\"",
"A valid username must be provided" : "Укажите правильное имя пользователя",
"A valid password must be provided" : "Укажите правильный пароль",
"The username is already being used" : "Имя пользователя уже используется",
@@ -140,8 +145,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Пожалуйста, попросите вашего администратора перезапустить веб-сервер.",
"PostgreSQL >= 9 required" : "Требуется PostgreSQL >= 9",
"Please upgrade your database version" : "Обновите базу данных",
- "Error occurred while checking PostgreSQL version" : "Произошла ошибка при проверке версии PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Убедитесь что версия PostgreSQL >= 9 или проверьте журналы для получения дополнительной информацией об ошибке",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Измените права доступа на 0770, чтобы другие пользователи не могли получить список файлов этого каталога.",
"Data directory (%s) is readable by other users" : "Каталог данных (%s) доступен для чтения другим пользователям",
"Data directory (%s) must be an absolute path" : "Директория данных (%s) должна иметь абсолютный путь",
@@ -149,6 +152,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "Каталог данных (%s) не верен",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Убедитесь, что файл \".ocdata\" присутствует в корне каталога данных.",
"Could not obtain lock type %d on \"%s\"." : "Не удалось получить блокировку типа %d для \"%s\"",
- "Storage not available" : "Хранилище недоступно"
+ "Storage unauthorized. %s" : "Хранилище неавторизовано. %s",
+ "Storage incomplete configuration. %s" : "Неполная конфигурация хранилища. %s",
+ "Storage connection error. %s" : "Ошибка подключения к хранилищу. %s",
+ "Storage not available" : "Хранилище недоступно",
+ "Storage connection timeout. %s" : "Истекло время ожидания подключения к хранилищу. %s"
},
"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/lib/l10n/ru.json b/lib/l10n/ru.json
index a5cf92180bb..592abd22e81 100644
--- a/lib/l10n/ru.json
+++ b/lib/l10n/ru.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "Архивы %s не поддерживаются",
"Failed to open archive when installing app" : "Ошибка открытия архива при установке приложения",
"App does not provide an info.xml file" : "Приложение не имеет файла info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Подпись не может быть проверена. Пожалуйста, свяжитесь с разработчиком приложения и проверьте свою страницу администратора.",
"App can't be installed because of not allowed code in the App" : "Приложение невозможно установить. В нем содержится запрещенный код.",
"App can't be installed because it is not compatible with this version of ownCloud" : "Приложение невозможно установить. Не совместимо с текущей версией ownCloud.",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "Приложение невозможно установить. Оно содержит параметр <shipped>true</shipped> который не допустим для приложений, не входящих в поставку.",
@@ -94,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Не удалось поделиться %s, пользователь %s не является членом группы %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Вам нужно задать пароль для создания публичной ссылки. Разрешены только защищённые ссылки",
"Sharing %s failed, because sharing with links is not allowed" : "Не удалось поделиться %s, открытие доступа по ссылке запрещено",
+ "Not allowed to create a federated share with the same user" : "Не допускается создание федеративного общего ресурса с тем-же пользователем",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Не удалось поделиться %s, не удалось найти %s, возможно, сервер не доступен.",
"Share type %s is not valid for %s" : "Тип общего доступа %s недопустим для %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Не удалось настроить права доступа для %s, указанные права доступа превышают предоставленные для %s",
@@ -109,9 +111,12 @@
"Sharing %s failed, because resharing is not allowed" : "Не удалось поделиться %s, повторное открытие доступа запрещено",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Не удалось поделиться %s, бэкенд общего доступа не нашел путь до %s",
"Sharing %s failed, because the file could not be found in the file cache" : "Не удалось поделиться %s, элемент не найден в файловом кеше.",
+ "Cannot increase permissions of %s" : "Невозможно увеличить права доступа для %s",
+ "Expiration date is in the past" : "Дата окончания срока действия уже прошла",
+ "Cannot set expiration date more than %s days in the future" : "Невозможно установить дату окончания срока действия более %s дней",
"Could not find category \"%s\"" : "Категория \"%s\" не найдена",
"Apps" : "Приложения",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Только следующие символы допускаются в имени пользователя: \"a-z\", \"A-Z\", \"0-9\", и \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "В качестве имени пользователя допускаются следующие символы: \"a-z\", \"A-Z\", \"0-9\" и \"_.@-'\"",
"A valid username must be provided" : "Укажите правильное имя пользователя",
"A valid password must be provided" : "Укажите правильный пароль",
"The username is already being used" : "Имя пользователя уже используется",
@@ -138,8 +143,6 @@
"Please ask your server administrator to restart the web server." : "Пожалуйста, попросите вашего администратора перезапустить веб-сервер.",
"PostgreSQL >= 9 required" : "Требуется PostgreSQL >= 9",
"Please upgrade your database version" : "Обновите базу данных",
- "Error occurred while checking PostgreSQL version" : "Произошла ошибка при проверке версии PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Убедитесь что версия PostgreSQL >= 9 или проверьте журналы для получения дополнительной информацией об ошибке",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Измените права доступа на 0770, чтобы другие пользователи не могли получить список файлов этого каталога.",
"Data directory (%s) is readable by other users" : "Каталог данных (%s) доступен для чтения другим пользователям",
"Data directory (%s) must be an absolute path" : "Директория данных (%s) должна иметь абсолютный путь",
@@ -147,6 +150,10 @@
"Data directory (%s) is invalid" : "Каталог данных (%s) не верен",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Убедитесь, что файл \".ocdata\" присутствует в корне каталога данных.",
"Could not obtain lock type %d on \"%s\"." : "Не удалось получить блокировку типа %d для \"%s\"",
- "Storage not available" : "Хранилище недоступно"
+ "Storage unauthorized. %s" : "Хранилище неавторизовано. %s",
+ "Storage incomplete configuration. %s" : "Неполная конфигурация хранилища. %s",
+ "Storage connection error. %s" : "Ошибка подключения к хранилищу. %s",
+ "Storage not available" : "Хранилище недоступно",
+ "Storage connection timeout. %s" : "Истекло время ожидания подключения к хранилищу. %s"
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
} \ No newline at end of file
diff --git a/lib/l10n/sk_SK.js b/lib/l10n/sk_SK.js
index 395b45b0dc5..b644fea0b9e 100644
--- a/lib/l10n/sk_SK.js
+++ b/lib/l10n/sk_SK.js
@@ -111,7 +111,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Zdieľanie %s zlyhalo, pretože súbor sa nenašiel vo vyrovnávacej pamäti súborov",
"Could not find category \"%s\"" : "Nemožno nájsť danú kategóriu \"%s\"",
"Apps" : "Aplikácie",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "V mene používateľa sú povolené len nasledovné znaky: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Musíte zadať platné používateľské meno",
"A valid password must be provided" : "Musíte zadať platné heslo",
"The username is already being used" : "Meno používateľa je už použité",
@@ -138,8 +137,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Prosím, požiadajte administrátora vášho servera o reštartovanie webového servera.",
"PostgreSQL >= 9 required" : "Vyžadované PostgreSQL >= 9",
"Please upgrade your database version" : "Prosím, aktualizujte verziu svojej databázy",
- "Error occurred while checking PostgreSQL version" : "Nastala chyba pri overovaní verzie PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Prosím, uistite sa, že máte PostgreSQL >= 9 alebo sa pozrite do protokolu, kde nájdete podrobnejšie informácie o chybe",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Prosím, zmeňte oprávnenia na 0770, aby tento priečinok nemohli ostatní používatelia otvoriť.",
"Data directory (%s) is readable by other users" : "Priečinok dát (%s) je prístupný na čítanie ostatným používateľom",
"Data directory (%s) must be an absolute path" : "Priečinok dát (%s) musí byť zadaný ako absolútna cesta",
diff --git a/lib/l10n/sk_SK.json b/lib/l10n/sk_SK.json
index 6fbfca2602b..9d02a1d264b 100644
--- a/lib/l10n/sk_SK.json
+++ b/lib/l10n/sk_SK.json
@@ -109,7 +109,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Zdieľanie %s zlyhalo, pretože súbor sa nenašiel vo vyrovnávacej pamäti súborov",
"Could not find category \"%s\"" : "Nemožno nájsť danú kategóriu \"%s\"",
"Apps" : "Aplikácie",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "V mene používateľa sú povolené len nasledovné znaky: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Musíte zadať platné používateľské meno",
"A valid password must be provided" : "Musíte zadať platné heslo",
"The username is already being used" : "Meno používateľa je už použité",
@@ -136,8 +135,6 @@
"Please ask your server administrator to restart the web server." : "Prosím, požiadajte administrátora vášho servera o reštartovanie webového servera.",
"PostgreSQL >= 9 required" : "Vyžadované PostgreSQL >= 9",
"Please upgrade your database version" : "Prosím, aktualizujte verziu svojej databázy",
- "Error occurred while checking PostgreSQL version" : "Nastala chyba pri overovaní verzie PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Prosím, uistite sa, že máte PostgreSQL >= 9 alebo sa pozrite do protokolu, kde nájdete podrobnejšie informácie o chybe",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Prosím, zmeňte oprávnenia na 0770, aby tento priečinok nemohli ostatní používatelia otvoriť.",
"Data directory (%s) is readable by other users" : "Priečinok dát (%s) je prístupný na čítanie ostatným používateľom",
"Data directory (%s) must be an absolute path" : "Priečinok dát (%s) musí byť zadaný ako absolútna cesta",
diff --git a/lib/l10n/sl.js b/lib/l10n/sl.js
index 07a21c894fb..4ae1e49705c 100644
--- a/lib/l10n/sl.js
+++ b/lib/l10n/sl.js
@@ -40,6 +40,7 @@ OC.L10N.register(
"File name is a reserved word" : "Ime datoteke je zadržana beseda",
"File name contains at least one invalid character" : "Ime datoteke vsebuje vsaj en neveljaven znak.",
"File name is too long" : "Ime datoteke je predolgo",
+ "File is currently busy, please try again later" : "Datoteka je trenutno v uporabi. Poskusite znova kasneje.",
"Can't read file" : "Datoteke ni mogoče prebrati.",
"App directory already exists" : "Programska mapa že obstaja",
"Can't create app folder. Please fix permissions. %s" : "Programske mape ni mogoče ustvariti. Ni ustreznih dovoljenj. %s",
@@ -99,7 +100,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Nastavljanje souporabe %s je spodletelo, ker v predpomnilniku zahtevana datoteka ne obstaja.",
"Could not find category \"%s\"" : "Kategorije \"%s\" ni mogoče najti.",
"Apps" : "Programi",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "V uporabniškem imenu je dovoljeno uporabiti le znake: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Navedeno mora biti veljavno uporabniško ime",
"A valid password must be provided" : "Navedeno mora biti veljavno geslo",
"The username is already being used" : "Vpisano uporabniško ime je že v uporabi",
@@ -120,13 +120,11 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Obvestite skrbnika strežnika, da je treba ponovno zagnati spletni strežnik.",
"PostgreSQL >= 9 required" : "Zahtevana je različica PostgreSQL >= 9.",
"Please upgrade your database version" : "Posodobite različico podatkovne zbirke.",
- "Error occurred while checking PostgreSQL version" : "Prišlo je do napake med preverjanjem različice PostgreSQL.",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Prepričajte se, da je nameščena različica PostgreSQL >= 9 in preverite dnevniški zapis za več podrobnosti o napaki.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Spremenite dovoljenja mape na 0770 in s tem onemogočite branje vsebine drugim uporabnikom.",
"Data directory (%s) is readable by other users" : "Podatkovna mapa (%s) ima določena dovoljenja za branje skupine.",
"Data directory (%s) is invalid" : "Podatkovna mapa (%s) ni veljavna.",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Preverite, ali je v korenu podatkovne mape datoteka \".ocdata\".",
"Could not obtain lock type %d on \"%s\"." : "Ni mogoče pridobiti zaklepa %d na \"%s\".",
- "Storage not available" : "Na voljo ni dovolj prostora"
+ "Storage not available" : "Shramba ni na voljo"
},
"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);");
diff --git a/lib/l10n/sl.json b/lib/l10n/sl.json
index ed518f770bb..8a34931889f 100644
--- a/lib/l10n/sl.json
+++ b/lib/l10n/sl.json
@@ -38,6 +38,7 @@
"File name is a reserved word" : "Ime datoteke je zadržana beseda",
"File name contains at least one invalid character" : "Ime datoteke vsebuje vsaj en neveljaven znak.",
"File name is too long" : "Ime datoteke je predolgo",
+ "File is currently busy, please try again later" : "Datoteka je trenutno v uporabi. Poskusite znova kasneje.",
"Can't read file" : "Datoteke ni mogoče prebrati.",
"App directory already exists" : "Programska mapa že obstaja",
"Can't create app folder. Please fix permissions. %s" : "Programske mape ni mogoče ustvariti. Ni ustreznih dovoljenj. %s",
@@ -97,7 +98,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Nastavljanje souporabe %s je spodletelo, ker v predpomnilniku zahtevana datoteka ne obstaja.",
"Could not find category \"%s\"" : "Kategorije \"%s\" ni mogoče najti.",
"Apps" : "Programi",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "V uporabniškem imenu je dovoljeno uporabiti le znake: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"",
"A valid username must be provided" : "Navedeno mora biti veljavno uporabniško ime",
"A valid password must be provided" : "Navedeno mora biti veljavno geslo",
"The username is already being used" : "Vpisano uporabniško ime je že v uporabi",
@@ -118,13 +118,11 @@
"Please ask your server administrator to restart the web server." : "Obvestite skrbnika strežnika, da je treba ponovno zagnati spletni strežnik.",
"PostgreSQL >= 9 required" : "Zahtevana je različica PostgreSQL >= 9.",
"Please upgrade your database version" : "Posodobite različico podatkovne zbirke.",
- "Error occurred while checking PostgreSQL version" : "Prišlo je do napake med preverjanjem različice PostgreSQL.",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Prepričajte se, da je nameščena različica PostgreSQL >= 9 in preverite dnevniški zapis za več podrobnosti o napaki.",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Spremenite dovoljenja mape na 0770 in s tem onemogočite branje vsebine drugim uporabnikom.",
"Data directory (%s) is readable by other users" : "Podatkovna mapa (%s) ima določena dovoljenja za branje skupine.",
"Data directory (%s) is invalid" : "Podatkovna mapa (%s) ni veljavna.",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Preverite, ali je v korenu podatkovne mape datoteka \".ocdata\".",
"Could not obtain lock type %d on \"%s\"." : "Ni mogoče pridobiti zaklepa %d na \"%s\".",
- "Storage not available" : "Na voljo ni dovolj prostora"
+ "Storage not available" : "Shramba ni na voljo"
},"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"
} \ No newline at end of file
diff --git a/lib/l10n/sq.js b/lib/l10n/sq.js
index 2cf6eeecdef..18805d6337a 100644
--- a/lib/l10n/sq.js
+++ b/lib/l10n/sq.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "Nuk mbulohen arkivat e llojit %s",
"Failed to open archive when installing app" : "Dështoi në hapje arkivi teksa instalohej aplikacioni",
"App does not provide an info.xml file" : "Aplikacioni s’ofron kartele të vlefshme .xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Nënshkrimi s’u kontrollua dot. Ju lutemi, lidhuni me zhvilluesin e aplikacionit dhe kontrolloni te skena juaj e përgjegjësit.",
"App can't be installed because of not allowed code in the App" : "Aplikacioni s’mund të instalohet, për shkak kodi të palejuar te Aplikacioni",
"App can't be installed because it is not compatible with this version of ownCloud" : "Aplikacioni s’mund të instalohet, ngaqë s’është i përputhshëm me këtë version të ownCloud-it",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "Aplikacioni s’mund të instalohet, ngaqë përmban etiketën <shipped>true</shipped> e cila nuk lejohet për aplikacione që s’janë hedhur në qarkullim",
@@ -96,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "Ndarja e %s me të tjerët dështoi, ngaqë %s s’është anëtar i grupit %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Lypset të jepni një fjalëkalim që të krijoni një lidhje publike, lejohen vetëm lidhje të mbrojtura",
"Sharing %s failed, because sharing with links is not allowed" : "Ndarja e %s me të tjerët dështoi, ngaqë nuk lejohet ndarja me lidhje",
+ "Not allowed to create a federated share with the same user" : "S’i lejohet të krijojë një ndarje të federuar me të njëjtin përdorues",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Ndarja për %s dështoi, s’u gjet dot %s, ndoshta shërbyesi është hëpërhë jashtë pune.",
"Share type %s is not valid for %s" : "Lloji i ndarjes %s s’është i vlefshëm për %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Caktimi i lejeve për %s dështoi, ngaqë lejet tejkalojnë lejet e akorduara për %s",
@@ -111,9 +113,12 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "Ndarja e %s me të tjerët dështoi, ngaqë nuk lejohen rindarje",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Ndarja e %s dështoi, ngaqë mekanizmi i shërbimit për ndarje për %s s’gjeti dot burimin për të",
"Sharing %s failed, because the file could not be found in the file cache" : "Ndarja e %s me të tjerët dështoi, ngaqë kartela s’u gjet dot te fshehtina e kartelave",
+ "Cannot increase permissions of %s" : "S’mund të shtohen lejet për %s",
+ "Expiration date is in the past" : "Data e skadimit bie në të kaluarën",
+ "Cannot set expiration date more than %s days in the future" : "S’mund të caktohet data e skadimit më shumë se %s ditë në të ardhmen",
"Could not find category \"%s\"" : "S’u gjet kategori \"%s\"",
"Apps" : "Aplikacione",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Në një emër përdoruesi lejohen vetëm shenjat vijuese: \"a-z\", \"A-Z\", \"0-9\", dhe \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Në një emër përdoruesi lejohen vetëm shenjat vijuese: \"a-z\", \"A-Z\", \"0-9\", dhe \"_.@-\"",
"A valid username must be provided" : "Duhet dhënë një emër i vlefshëm përdoruesi",
"A valid password must be provided" : "Duhet dhënë një fjalëkalim i vlefshëm",
"The username is already being used" : "Emri i përdoruesit është tashmë i përdorur",
@@ -140,8 +145,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Ju lutemi, kërkojini përgjegjësit të shërbyesit tuaj të rinisë shërbyesin web.",
"PostgreSQL >= 9 required" : "Lypset PostgreSQL >= 9",
"Please upgrade your database version" : "Ju lutemi, përmirësoni bazën tuaj të të dhënave me një version më të ri.",
- "Error occurred while checking PostgreSQL version" : "Ndodhi një gabim teksa kontrollohej versioni i PostgreSQL-së",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Ju lutemi, sigurohuni që keni PostgreSQL >= 9 ose kontrolloni regjistrat për më tepër të dhëna rreth gabimit",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ju lutemi, kalojani lejet në 0770, që kështu atë drejtori të mos mund ta shfaqin përdorues të tjerë.",
"Data directory (%s) is readable by other users" : "Drejtoria e të dhënave (%s) është e lexueshme nga përdorues të tjerë",
"Data directory (%s) must be an absolute path" : "Drejtoria e të dhënave (%s) duhet të jepë një shteg absolut",
@@ -149,6 +152,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "Drejtoria e të dhënave (%s) është e pavlefshme",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Ju lutemi, kontrolloni që drejtoria e të dhënave përmban në rrënjën e saj një kartelë \".ocdata\".",
"Could not obtain lock type %d on \"%s\"." : "S’u mor dot lloj kyçjeje %d në \"%s\".",
- "Storage not available" : "Pa depozitë gati"
+ "Storage unauthorized. %s" : "Depozitë e paautorizuar. %s",
+ "Storage incomplete configuration. %s" : "Formësim jo i plotë i depozitës. %s",
+ "Storage connection error. %s" : "Gabim lidhje te depozita. %s",
+ "Storage not available" : "Pa depozitë gati",
+ "Storage connection timeout. %s" : "Mbarim kohe lidhjeje për depozitën. %s"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/sq.json b/lib/l10n/sq.json
index ec412dfff53..353659069e5 100644
--- a/lib/l10n/sq.json
+++ b/lib/l10n/sq.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "Nuk mbulohen arkivat e llojit %s",
"Failed to open archive when installing app" : "Dështoi në hapje arkivi teksa instalohej aplikacioni",
"App does not provide an info.xml file" : "Aplikacioni s’ofron kartele të vlefshme .xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "Nënshkrimi s’u kontrollua dot. Ju lutemi, lidhuni me zhvilluesin e aplikacionit dhe kontrolloni te skena juaj e përgjegjësit.",
"App can't be installed because of not allowed code in the App" : "Aplikacioni s’mund të instalohet, për shkak kodi të palejuar te Aplikacioni",
"App can't be installed because it is not compatible with this version of ownCloud" : "Aplikacioni s’mund të instalohet, ngaqë s’është i përputhshëm me këtë version të ownCloud-it",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "Aplikacioni s’mund të instalohet, ngaqë përmban etiketën <shipped>true</shipped> e cila nuk lejohet për aplikacione që s’janë hedhur në qarkullim",
@@ -94,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "Ndarja e %s me të tjerët dështoi, ngaqë %s s’është anëtar i grupit %s",
"You need to provide a password to create a public link, only protected links are allowed" : "Lypset të jepni një fjalëkalim që të krijoni një lidhje publike, lejohen vetëm lidhje të mbrojtura",
"Sharing %s failed, because sharing with links is not allowed" : "Ndarja e %s me të tjerët dështoi, ngaqë nuk lejohet ndarja me lidhje",
+ "Not allowed to create a federated share with the same user" : "S’i lejohet të krijojë një ndarje të federuar me të njëjtin përdorues",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "Ndarja për %s dështoi, s’u gjet dot %s, ndoshta shërbyesi është hëpërhë jashtë pune.",
"Share type %s is not valid for %s" : "Lloji i ndarjes %s s’është i vlefshëm për %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "Caktimi i lejeve për %s dështoi, ngaqë lejet tejkalojnë lejet e akorduara për %s",
@@ -109,9 +111,12 @@
"Sharing %s failed, because resharing is not allowed" : "Ndarja e %s me të tjerët dështoi, ngaqë nuk lejohen rindarje",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "Ndarja e %s dështoi, ngaqë mekanizmi i shërbimit për ndarje për %s s’gjeti dot burimin për të",
"Sharing %s failed, because the file could not be found in the file cache" : "Ndarja e %s me të tjerët dështoi, ngaqë kartela s’u gjet dot te fshehtina e kartelave",
+ "Cannot increase permissions of %s" : "S’mund të shtohen lejet për %s",
+ "Expiration date is in the past" : "Data e skadimit bie në të kaluarën",
+ "Cannot set expiration date more than %s days in the future" : "S’mund të caktohet data e skadimit më shumë se %s ditë në të ardhmen",
"Could not find category \"%s\"" : "S’u gjet kategori \"%s\"",
"Apps" : "Aplikacione",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Në një emër përdoruesi lejohen vetëm shenjat vijuese: \"a-z\", \"A-Z\", \"0-9\", dhe \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Në një emër përdoruesi lejohen vetëm shenjat vijuese: \"a-z\", \"A-Z\", \"0-9\", dhe \"_.@-\"",
"A valid username must be provided" : "Duhet dhënë një emër i vlefshëm përdoruesi",
"A valid password must be provided" : "Duhet dhënë një fjalëkalim i vlefshëm",
"The username is already being used" : "Emri i përdoruesit është tashmë i përdorur",
@@ -138,8 +143,6 @@
"Please ask your server administrator to restart the web server." : "Ju lutemi, kërkojini përgjegjësit të shërbyesit tuaj të rinisë shërbyesin web.",
"PostgreSQL >= 9 required" : "Lypset PostgreSQL >= 9",
"Please upgrade your database version" : "Ju lutemi, përmirësoni bazën tuaj të të dhënave me një version më të ri.",
- "Error occurred while checking PostgreSQL version" : "Ndodhi një gabim teksa kontrollohej versioni i PostgreSQL-së",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Ju lutemi, sigurohuni që keni PostgreSQL >= 9 ose kontrolloni regjistrat për më tepër të dhëna rreth gabimit",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ju lutemi, kalojani lejet në 0770, që kështu atë drejtori të mos mund ta shfaqin përdorues të tjerë.",
"Data directory (%s) is readable by other users" : "Drejtoria e të dhënave (%s) është e lexueshme nga përdorues të tjerë",
"Data directory (%s) must be an absolute path" : "Drejtoria e të dhënave (%s) duhet të jepë një shteg absolut",
@@ -147,6 +150,10 @@
"Data directory (%s) is invalid" : "Drejtoria e të dhënave (%s) është e pavlefshme",
"Please check that the data directory contains a file \".ocdata\" in its root." : "Ju lutemi, kontrolloni që drejtoria e të dhënave përmban në rrënjën e saj një kartelë \".ocdata\".",
"Could not obtain lock type %d on \"%s\"." : "S’u mor dot lloj kyçjeje %d në \"%s\".",
- "Storage not available" : "Pa depozitë gati"
+ "Storage unauthorized. %s" : "Depozitë e paautorizuar. %s",
+ "Storage incomplete configuration. %s" : "Formësim jo i plotë i depozitës. %s",
+ "Storage connection error. %s" : "Gabim lidhje te depozita. %s",
+ "Storage not available" : "Pa depozitë gati",
+ "Storage connection timeout. %s" : "Mbarim kohe lidhjeje për depozitën. %s"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/sr.js b/lib/l10n/sr.js
index 677c14b92cc..4cb5661eedf 100644
--- a/lib/l10n/sr.js
+++ b/lib/l10n/sr.js
@@ -111,7 +111,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Дељење %s није успело зато што фајл није нађен у кешу фајлова",
"Could not find category \"%s\"" : "Не могу да пронађем категорију „%s“.",
"Apps" : "Апликације",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Само су следећи знакови дозвољени за корисничко име: „a-z“, „A-Z“, „0-9“ и „_.@-“",
"A valid username must be provided" : "Морате унети исправно корисничко име",
"A valid password must be provided" : "Морате унети исправну лозинку",
"The username is already being used" : "Корисничко име се већ користи",
@@ -138,8 +137,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Замолите вашег администратора сервера да поново покрене веб сервер.",
"PostgreSQL >= 9 required" : "Захтеван је ПостгреСкул >= 9",
"Please upgrade your database version" : "Надоградите ваше издање базе",
- "Error occurred while checking PostgreSQL version" : "Дошло је до грешке приликом провере издања програма ПостгреСкул",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Проверите да ли имате ПостгреСкул >= 9 или проверите дневнике записа за више информација о грешци",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Промените дозволе у 0770 како директоријуми не би могли бити излистани од стране других корисника.",
"Data directory (%s) is readable by other users" : "Директоријум података (%s) могу читати остали корисници",
"Data directory (%s) must be an absolute path" : "Директоријум података (%s) мора бити апсолутна путања",
diff --git a/lib/l10n/sr.json b/lib/l10n/sr.json
index 7ac58babca4..dd686f58fe9 100644
--- a/lib/l10n/sr.json
+++ b/lib/l10n/sr.json
@@ -109,7 +109,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Дељење %s није успело зато што фајл није нађен у кешу фајлова",
"Could not find category \"%s\"" : "Не могу да пронађем категорију „%s“.",
"Apps" : "Апликације",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Само су следећи знакови дозвољени за корисничко име: „a-z“, „A-Z“, „0-9“ и „_.@-“",
"A valid username must be provided" : "Морате унети исправно корисничко име",
"A valid password must be provided" : "Морате унети исправну лозинку",
"The username is already being used" : "Корисничко име се већ користи",
@@ -136,8 +135,6 @@
"Please ask your server administrator to restart the web server." : "Замолите вашег администратора сервера да поново покрене веб сервер.",
"PostgreSQL >= 9 required" : "Захтеван је ПостгреСкул >= 9",
"Please upgrade your database version" : "Надоградите ваше издање базе",
- "Error occurred while checking PostgreSQL version" : "Дошло је до грешке приликом провере издања програма ПостгреСкул",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Проверите да ли имате ПостгреСкул >= 9 или проверите дневнике записа за више информација о грешци",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Промените дозволе у 0770 како директоријуми не би могли бити излистани од стране других корисника.",
"Data directory (%s) is readable by other users" : "Директоријум података (%s) могу читати остали корисници",
"Data directory (%s) must be an absolute path" : "Директоријум података (%s) мора бити апсолутна путања",
diff --git a/lib/l10n/sv.js b/lib/l10n/sv.js
index f5e0ceaf114..e378f831d13 100644
--- a/lib/l10n/sv.js
+++ b/lib/l10n/sv.js
@@ -35,6 +35,7 @@ OC.L10N.register(
"_%n minute ago_::_%n minutes ago_" : ["%n minut sedan","%n minuter sedan"],
"seconds ago" : "sekunder sedan",
"web services under your control" : "webbtjänster under din kontroll",
+ "File name contains at least one invalid character" : "Filnamnet innehåller minst ett ogiltigt tecken",
"App directory already exists" : "Appens mapp finns redan",
"Can't create app folder. Please fix permissions. %s" : "Kan inte skapa appens mapp. Var god åtgärda rättigheterna. %s",
"No source specified when installing app" : "Ingen källa angiven vid installation av app ",
@@ -92,7 +93,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Delning %s misslyckades därför att filen inte kunde hittas i filcachen",
"Could not find category \"%s\"" : "Kunde inte hitta kategorin \"%s\"",
"Apps" : "Program",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Endast följande tecken är tillåtna i ett användarnamn: \"az\", \"AZ\", \"0-9\", och \"_ @ -.\"",
"A valid username must be provided" : "Ett giltigt användarnamn måste anges",
"A valid password must be provided" : "Ett giltigt lösenord måste anges",
"The username is already being used" : "Användarnamnet används redan",
@@ -112,8 +112,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Vänligen be din serveradministratör att starta om webservern.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 krävs",
"Please upgrade your database version" : "Vänligen uppgradera din databas-version",
- "Error occurred while checking PostgreSQL version" : "Ett fel inträffade vid kontroll utav PostgreSQL-version",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Vänligen säkerställ att du har PostgreSQL >= 9 eller kolla loggarna för mer information om felet",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Vänligen ändra rättigheterna till 0770 så att katalogen inte kan listas utav andra användare.",
"Data directory (%s) is readable by other users" : "Datakatalogen (%s) kan läsas av andra användare",
"Data directory (%s) is invalid" : "Datakatlogen (%s) är ogiltig",
diff --git a/lib/l10n/sv.json b/lib/l10n/sv.json
index 415f8de7e08..4cecd4711f5 100644
--- a/lib/l10n/sv.json
+++ b/lib/l10n/sv.json
@@ -33,6 +33,7 @@
"_%n minute ago_::_%n minutes ago_" : ["%n minut sedan","%n minuter sedan"],
"seconds ago" : "sekunder sedan",
"web services under your control" : "webbtjänster under din kontroll",
+ "File name contains at least one invalid character" : "Filnamnet innehåller minst ett ogiltigt tecken",
"App directory already exists" : "Appens mapp finns redan",
"Can't create app folder. Please fix permissions. %s" : "Kan inte skapa appens mapp. Var god åtgärda rättigheterna. %s",
"No source specified when installing app" : "Ingen källa angiven vid installation av app ",
@@ -90,7 +91,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Delning %s misslyckades därför att filen inte kunde hittas i filcachen",
"Could not find category \"%s\"" : "Kunde inte hitta kategorin \"%s\"",
"Apps" : "Program",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Endast följande tecken är tillåtna i ett användarnamn: \"az\", \"AZ\", \"0-9\", och \"_ @ -.\"",
"A valid username must be provided" : "Ett giltigt användarnamn måste anges",
"A valid password must be provided" : "Ett giltigt lösenord måste anges",
"The username is already being used" : "Användarnamnet används redan",
@@ -110,8 +110,6 @@
"Please ask your server administrator to restart the web server." : "Vänligen be din serveradministratör att starta om webservern.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 krävs",
"Please upgrade your database version" : "Vänligen uppgradera din databas-version",
- "Error occurred while checking PostgreSQL version" : "Ett fel inträffade vid kontroll utav PostgreSQL-version",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Vänligen säkerställ att du har PostgreSQL >= 9 eller kolla loggarna för mer information om felet",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Vänligen ändra rättigheterna till 0770 så att katalogen inte kan listas utav andra användare.",
"Data directory (%s) is readable by other users" : "Datakatalogen (%s) kan läsas av andra användare",
"Data directory (%s) is invalid" : "Datakatlogen (%s) är ogiltig",
diff --git a/lib/l10n/th_TH.js b/lib/l10n/th_TH.js
index d7cc862481a..a5116ec6e5c 100644
--- a/lib/l10n/th_TH.js
+++ b/lib/l10n/th_TH.js
@@ -56,6 +56,7 @@ OC.L10N.register(
"Archives of type %s are not supported" : "ประเภทข้อมูลที่เก็บของ %s ไม่ได้รับการสนับสนุน",
"Failed to open archive when installing app" : "ไม่สามารถเปิดที่เก็บข้อมูลเมื่อกำลังติดตั้งแอพพลิเคชั่น",
"App does not provide an info.xml file" : "แอพฯ ไม่ได้ระบุไฟล์ info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "ไม่สามารถตรวจสอบลายเซ็น โปรดติดต่อนักพัฒนาแอพพลิเคชันและตรวจสอบหน้าจอแผงควบคุมระบบของคุณ",
"App can't be installed because of not allowed code in the App" : "ไม่สามารถติดตั้งแอพพลิเคชันเพราะไม่ได้อนุญาตรหัสในแอพพลิเคชัน",
"App can't be installed because it is not compatible with this version of ownCloud" : "ไม่สามารถติดตั้งแอพพลิเคชันเพราะมันเข้ากันไม่ได้กับรุ่นของ ownCloud นี้",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "ไม่สามารถติดตั้งแอพพลิเคชันเพราะมันมี <shipped>จริง</shipped> แท็กที่ไม่ได้รับอนุญาต",
@@ -96,6 +97,7 @@ OC.L10N.register(
"Sharing %s failed, because %s is not a member of the group %s" : "การแชร์ %s ล้มเหลวเพราะ %s ไม่ได้เป็นสมาชิกของกลุ่ม %s",
"You need to provide a password to create a public link, only protected links are allowed" : "คุณจำเป็นต้องระบุรหัสผ่านเพื่อสร้างลิงค์สาธารณะ, ลิงค์ที่มีการป้องกันเท่านั้นที่ได้รับอนุญาต",
"Sharing %s failed, because sharing with links is not allowed" : "การแชร์ %s ล้มเหลวเพราะมีการแชร์ลิงค์ไม่ได้รับอนุญาต",
+ "Not allowed to create a federated share with the same user" : "ไม่อนุญาตให้สร้างแชร์สหพันธ์กับผู้ใช้เดียวกัน",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "การแชร์ %s ล้มเหลวไม่สามารถหา %s, บางทีอาจจะยังไม่สามารถเข้าถึงเซิร์ฟเวอร์ปัจจุบัน",
"Share type %s is not valid for %s" : "ประเภท %s ที่แชร์ไม่ถูกต้องสำหรับ %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "การตั้งค่าสิทธิ์สำหรับ %s ล้มเหลวเพราะเกินสิทธิ์ที่ได้อนุญาตให้ %s",
@@ -111,9 +113,12 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "การแชร์ %s ล้มเหลวเพราะการแชร์ต่อไม่ได้รับอนุญาต",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "การแชร์ %s ล้มเหลวเพราะการแชร์แบ็กเอนด์สำหรับ %s ไม่สามารถหาแหล่งที่มา",
"Sharing %s failed, because the file could not be found in the file cache" : "การแชร์ %s ล้มเหลวเพราะไม่พบไฟล์ในแคชไฟล์",
+ "Cannot increase permissions of %s" : "ไม่สามารถเพิ่มสิทธิ์ของ %s",
+ "Expiration date is in the past" : "วันหมดอายุอยู่ในอดีตที่ผ่านมา",
+ "Cannot set expiration date more than %s days in the future" : "ไม่สามารถกำหนดวันหมดอายุให้มากกว่า %s วันในอนาคต",
"Could not find category \"%s\"" : "ไม่พบหมวดหมู่ \"%s\"",
"Apps" : "แอปฯ",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "ตัวอักษรที่อนุญาตให้ใช้ในชื่อผู้ใช้: \"a-z\", \"A-Z\", \"0-9\" และ \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ชื่อผู้ใช้จะใช้ได้แค่อักษรดังต่อไปนี้: \"a-z\", \"A-Z\", \"0-9\" และ \"_.@-'\"",
"A valid username must be provided" : "จะต้องระบุชื่อผู้ใช้ที่ถูกต้อง",
"A valid password must be provided" : "รหัสผ่านที่ถูกต้องจะต้องให้",
"The username is already being used" : "มีคนใช้ชื่อผู้ใช้นี้ไปแล้ว",
@@ -140,8 +145,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "โปรดสอบถามผู้ดูแลระบบเซิร์ฟเวอร์ของคุณเพื่อเริ่มการทำงานของเว็บเซิร์ฟเวอร์",
"PostgreSQL >= 9 required" : "จำเป็นต้องใช้ PostgreSQL รุ่น >= 9",
"Please upgrade your database version" : "กรุณาอัพเดทฐานข้อมูลของคุณ",
- "Error occurred while checking PostgreSQL version" : "เกิดข้อผิดพลาดขึ้นขณะที่การตรวจสอบรุ่นของ PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "กรุณาให้แน่ใจว่าคุณมี PostgreSQL รุ่น >= 9 หรือตรวจสอบบันทึกสำหรับข้อมูลเพิ่มเติมเกี่ยวกับข้อผิดพลาด",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "กรุณาเปลี่ยนสิทธิ์การเข้าถึงเป็น 0770 เพื่อให้ไดเรกทอรีไม่สามารถแก้ไขโดยผู้ใช้อื่น",
"Data directory (%s) is readable by other users" : "ไดเรกทอรีข้อมูล (%s) สามารถอ่านได้โดยผู้ใช้อื่น",
"Data directory (%s) must be an absolute path" : "ไดเรกทอรีข้อมูล (%s) จะต้องเป็นเส้นทางที่แน่นอน",
@@ -149,6 +152,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "ไดเรกทอรีข้อมูล (%s) ไม่ถูกต้อง",
"Please check that the data directory contains a file \".ocdata\" in its root." : "กรุณาตรวจสอบว่าไดเรกทอรีข้อมูลมีแฟ้ม \".ocdata\" อยู่ในราก",
"Could not obtain lock type %d on \"%s\"." : "ไม่สามารถรับล็อคชนิด %d บน \"%s\"",
- "Storage not available" : "ไม่สามารถใช้พื้นที่จัดเก็บข้อมูลได้"
+ "Storage unauthorized. %s" : "การจัดเก็บข้อมูลไม่ได้รับอนุญาต %s",
+ "Storage incomplete configuration. %s" : "การตั้งค่าการจัดเก็บข้อมูลไม่สำเร็จ %s",
+ "Storage connection error. %s" : "ข้อผิดพลาดการเชื่อมต่อพื้นที่จัดเก็บข้อมูล %s",
+ "Storage not available" : "ไม่สามารถใช้พื้นที่จัดเก็บข้อมูลได้",
+ "Storage connection timeout. %s" : "หมดเวลาการเชื่อมต่อพื้นที่จัดเก็บข้อมูล %s"
},
"nplurals=1; plural=0;");
diff --git a/lib/l10n/th_TH.json b/lib/l10n/th_TH.json
index 3a9fc838bd7..52fb06d31d5 100644
--- a/lib/l10n/th_TH.json
+++ b/lib/l10n/th_TH.json
@@ -54,6 +54,7 @@
"Archives of type %s are not supported" : "ประเภทข้อมูลที่เก็บของ %s ไม่ได้รับการสนับสนุน",
"Failed to open archive when installing app" : "ไม่สามารถเปิดที่เก็บข้อมูลเมื่อกำลังติดตั้งแอพพลิเคชั่น",
"App does not provide an info.xml file" : "แอพฯ ไม่ได้ระบุไฟล์ info.xml",
+ "Signature could not get checked. Please contact the app developer and check your admin screen." : "ไม่สามารถตรวจสอบลายเซ็น โปรดติดต่อนักพัฒนาแอพพลิเคชันและตรวจสอบหน้าจอแผงควบคุมระบบของคุณ",
"App can't be installed because of not allowed code in the App" : "ไม่สามารถติดตั้งแอพพลิเคชันเพราะไม่ได้อนุญาตรหัสในแอพพลิเคชัน",
"App can't be installed because it is not compatible with this version of ownCloud" : "ไม่สามารถติดตั้งแอพพลิเคชันเพราะมันเข้ากันไม่ได้กับรุ่นของ ownCloud นี้",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "ไม่สามารถติดตั้งแอพพลิเคชันเพราะมันมี <shipped>จริง</shipped> แท็กที่ไม่ได้รับอนุญาต",
@@ -94,6 +95,7 @@
"Sharing %s failed, because %s is not a member of the group %s" : "การแชร์ %s ล้มเหลวเพราะ %s ไม่ได้เป็นสมาชิกของกลุ่ม %s",
"You need to provide a password to create a public link, only protected links are allowed" : "คุณจำเป็นต้องระบุรหัสผ่านเพื่อสร้างลิงค์สาธารณะ, ลิงค์ที่มีการป้องกันเท่านั้นที่ได้รับอนุญาต",
"Sharing %s failed, because sharing with links is not allowed" : "การแชร์ %s ล้มเหลวเพราะมีการแชร์ลิงค์ไม่ได้รับอนุญาต",
+ "Not allowed to create a federated share with the same user" : "ไม่อนุญาตให้สร้างแชร์สหพันธ์กับผู้ใช้เดียวกัน",
"Sharing %s failed, could not find %s, maybe the server is currently unreachable." : "การแชร์ %s ล้มเหลวไม่สามารถหา %s, บางทีอาจจะยังไม่สามารถเข้าถึงเซิร์ฟเวอร์ปัจจุบัน",
"Share type %s is not valid for %s" : "ประเภท %s ที่แชร์ไม่ถูกต้องสำหรับ %s",
"Setting permissions for %s failed, because the permissions exceed permissions granted to %s" : "การตั้งค่าสิทธิ์สำหรับ %s ล้มเหลวเพราะเกินสิทธิ์ที่ได้อนุญาตให้ %s",
@@ -109,9 +111,12 @@
"Sharing %s failed, because resharing is not allowed" : "การแชร์ %s ล้มเหลวเพราะการแชร์ต่อไม่ได้รับอนุญาต",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "การแชร์ %s ล้มเหลวเพราะการแชร์แบ็กเอนด์สำหรับ %s ไม่สามารถหาแหล่งที่มา",
"Sharing %s failed, because the file could not be found in the file cache" : "การแชร์ %s ล้มเหลวเพราะไม่พบไฟล์ในแคชไฟล์",
+ "Cannot increase permissions of %s" : "ไม่สามารถเพิ่มสิทธิ์ของ %s",
+ "Expiration date is in the past" : "วันหมดอายุอยู่ในอดีตที่ผ่านมา",
+ "Cannot set expiration date more than %s days in the future" : "ไม่สามารถกำหนดวันหมดอายุให้มากกว่า %s วันในอนาคต",
"Could not find category \"%s\"" : "ไม่พบหมวดหมู่ \"%s\"",
"Apps" : "แอปฯ",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "ตัวอักษรที่อนุญาตให้ใช้ในชื่อผู้ใช้: \"a-z\", \"A-Z\", \"0-9\" และ \"_.@-\"",
+ "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ชื่อผู้ใช้จะใช้ได้แค่อักษรดังต่อไปนี้: \"a-z\", \"A-Z\", \"0-9\" และ \"_.@-'\"",
"A valid username must be provided" : "จะต้องระบุชื่อผู้ใช้ที่ถูกต้อง",
"A valid password must be provided" : "รหัสผ่านที่ถูกต้องจะต้องให้",
"The username is already being used" : "มีคนใช้ชื่อผู้ใช้นี้ไปแล้ว",
@@ -138,8 +143,6 @@
"Please ask your server administrator to restart the web server." : "โปรดสอบถามผู้ดูแลระบบเซิร์ฟเวอร์ของคุณเพื่อเริ่มการทำงานของเว็บเซิร์ฟเวอร์",
"PostgreSQL >= 9 required" : "จำเป็นต้องใช้ PostgreSQL รุ่น >= 9",
"Please upgrade your database version" : "กรุณาอัพเดทฐานข้อมูลของคุณ",
- "Error occurred while checking PostgreSQL version" : "เกิดข้อผิดพลาดขึ้นขณะที่การตรวจสอบรุ่นของ PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "กรุณาให้แน่ใจว่าคุณมี PostgreSQL รุ่น >= 9 หรือตรวจสอบบันทึกสำหรับข้อมูลเพิ่มเติมเกี่ยวกับข้อผิดพลาด",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "กรุณาเปลี่ยนสิทธิ์การเข้าถึงเป็น 0770 เพื่อให้ไดเรกทอรีไม่สามารถแก้ไขโดยผู้ใช้อื่น",
"Data directory (%s) is readable by other users" : "ไดเรกทอรีข้อมูล (%s) สามารถอ่านได้โดยผู้ใช้อื่น",
"Data directory (%s) must be an absolute path" : "ไดเรกทอรีข้อมูล (%s) จะต้องเป็นเส้นทางที่แน่นอน",
@@ -147,6 +150,10 @@
"Data directory (%s) is invalid" : "ไดเรกทอรีข้อมูล (%s) ไม่ถูกต้อง",
"Please check that the data directory contains a file \".ocdata\" in its root." : "กรุณาตรวจสอบว่าไดเรกทอรีข้อมูลมีแฟ้ม \".ocdata\" อยู่ในราก",
"Could not obtain lock type %d on \"%s\"." : "ไม่สามารถรับล็อคชนิด %d บน \"%s\"",
- "Storage not available" : "ไม่สามารถใช้พื้นที่จัดเก็บข้อมูลได้"
+ "Storage unauthorized. %s" : "การจัดเก็บข้อมูลไม่ได้รับอนุญาต %s",
+ "Storage incomplete configuration. %s" : "การตั้งค่าการจัดเก็บข้อมูลไม่สำเร็จ %s",
+ "Storage connection error. %s" : "ข้อผิดพลาดการเชื่อมต่อพื้นที่จัดเก็บข้อมูล %s",
+ "Storage not available" : "ไม่สามารถใช้พื้นที่จัดเก็บข้อมูลได้",
+ "Storage connection timeout. %s" : "หมดเวลาการเชื่อมต่อพื้นที่จัดเก็บข้อมูล %s"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/lib/l10n/tr.js b/lib/l10n/tr.js
index 963bbbacc24..9facd084bec 100644
--- a/lib/l10n/tr.js
+++ b/lib/l10n/tr.js
@@ -87,6 +87,7 @@ OC.L10N.register(
"Sharing %s failed, because the backend does not allow shares from type %i" : "Arka uç %i türündeki paylaşımlara izin vermediğinden %s paylaşımı başarısız",
"Sharing %s failed, because the file does not exist" : "%s paylaşımı, dosya mevcut olmadığından başarısız oldu",
"You are not allowed to share %s" : "%s paylaşımını yapma izniniz yok",
+ "Sharing %s failed, because you can not share with yourself" : "%s paylaşımı başarısız, kendiniz ile paylaşamazsınız",
"Sharing %s failed, because the user %s does not exist" : "%s paylaşımı, %s kullanıcısı mevcut olmadığından başarısız oldu",
"Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" : "%s paylaşımı, %s kullanıcısının %s üyeliklerinden birine sahip olmadığından başarısız oldu",
"Sharing %s failed, because this item is already shared with %s" : "%s paylaşımı, %s ile zaten paylaşıldığından dolayı başarısız oldu",
@@ -105,13 +106,13 @@ OC.L10N.register(
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "Paylaşma arka ucu %s OCP\\Share_Backend arayüzünü desteklemeli",
"Sharing backend %s not found" : "Paylaşım arka ucu %s bulunamadı",
"Sharing backend for %s not found" : "%s için paylaşım arka ucu bulunamadı",
+ "Sharing failed, because the user %s is the original sharer" : "%s kullanıcısı özgün paylaşan kişi olduğundan başarısız oldu",
"Sharing %s failed, because the permissions exceed permissions granted to %s" : "%s paylaşımı, izinler %s için verilen izinleri aştığından dolayı başarısız oldu",
"Sharing %s failed, because resharing is not allowed" : "%s paylaşımı, tekrar paylaşımın izin verilmemesinden dolayı başarısız oldu",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "%s paylaşımı, %s için arka ucun kaynağını bulamamasından dolayı başarısız oldu",
"Sharing %s failed, because the file could not be found in the file cache" : "%s paylaşımı, dosyanın dosya önbelleğinde bulunamamasınndan dolayı başarısız oldu",
"Could not find category \"%s\"" : "\"%s\" kategorisi bulunamadı",
"Apps" : "Uygulamalar",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Kullanıcı adında sadece bu karakterlere izin verilmektedir: \"a-z\", \"A-Z\", \"0-9\", ve \"_.@-\"",
"A valid username must be provided" : "Geçerli bir kullanıcı adı mutlaka sağlanmalı",
"A valid password must be provided" : "Geçerli bir parola mutlaka sağlanmalı",
"The username is already being used" : "Bu kullanıcı adı zaten kullanımda",
@@ -138,8 +139,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Lütfen web sunucusunu yeniden başlatması için sunucu yöneticinize danışın.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 gerekli",
"Please upgrade your database version" : "Lütfen veritabanı sürümünüzü yükseltin",
- "Error occurred while checking PostgreSQL version" : "PostgreSQL sürümü denetlenirken hata oluştu",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "PostgreSQL >= 9 sürümüne sahip olduğunuzu doğrulayın veya hata hakkında daha fazla bilgi için günlükleri denetleyin",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Lütfen izinleri 0770 olarak ayarlayıp dizinin diğer kullanıcılar tarafından görülememesini sağlayın.",
"Data directory (%s) is readable by other users" : "Veri dizini (%s) diğer kullanıcılar tarafından okunabilir",
"Data directory (%s) must be an absolute path" : "Veri dizini (%s) tam yol olmalıdır",
diff --git a/lib/l10n/tr.json b/lib/l10n/tr.json
index 1880b659fa9..442c53181ea 100644
--- a/lib/l10n/tr.json
+++ b/lib/l10n/tr.json
@@ -85,6 +85,7 @@
"Sharing %s failed, because the backend does not allow shares from type %i" : "Arka uç %i türündeki paylaşımlara izin vermediğinden %s paylaşımı başarısız",
"Sharing %s failed, because the file does not exist" : "%s paylaşımı, dosya mevcut olmadığından başarısız oldu",
"You are not allowed to share %s" : "%s paylaşımını yapma izniniz yok",
+ "Sharing %s failed, because you can not share with yourself" : "%s paylaşımı başarısız, kendiniz ile paylaşamazsınız",
"Sharing %s failed, because the user %s does not exist" : "%s paylaşımı, %s kullanıcısı mevcut olmadığından başarısız oldu",
"Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" : "%s paylaşımı, %s kullanıcısının %s üyeliklerinden birine sahip olmadığından başarısız oldu",
"Sharing %s failed, because this item is already shared with %s" : "%s paylaşımı, %s ile zaten paylaşıldığından dolayı başarısız oldu",
@@ -103,13 +104,13 @@
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "Paylaşma arka ucu %s OCP\\Share_Backend arayüzünü desteklemeli",
"Sharing backend %s not found" : "Paylaşım arka ucu %s bulunamadı",
"Sharing backend for %s not found" : "%s için paylaşım arka ucu bulunamadı",
+ "Sharing failed, because the user %s is the original sharer" : "%s kullanıcısı özgün paylaşan kişi olduğundan başarısız oldu",
"Sharing %s failed, because the permissions exceed permissions granted to %s" : "%s paylaşımı, izinler %s için verilen izinleri aştığından dolayı başarısız oldu",
"Sharing %s failed, because resharing is not allowed" : "%s paylaşımı, tekrar paylaşımın izin verilmemesinden dolayı başarısız oldu",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "%s paylaşımı, %s için arka ucun kaynağını bulamamasından dolayı başarısız oldu",
"Sharing %s failed, because the file could not be found in the file cache" : "%s paylaşımı, dosyanın dosya önbelleğinde bulunamamasınndan dolayı başarısız oldu",
"Could not find category \"%s\"" : "\"%s\" kategorisi bulunamadı",
"Apps" : "Uygulamalar",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Kullanıcı adında sadece bu karakterlere izin verilmektedir: \"a-z\", \"A-Z\", \"0-9\", ve \"_.@-\"",
"A valid username must be provided" : "Geçerli bir kullanıcı adı mutlaka sağlanmalı",
"A valid password must be provided" : "Geçerli bir parola mutlaka sağlanmalı",
"The username is already being used" : "Bu kullanıcı adı zaten kullanımda",
@@ -136,8 +137,6 @@
"Please ask your server administrator to restart the web server." : "Lütfen web sunucusunu yeniden başlatması için sunucu yöneticinize danışın.",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 gerekli",
"Please upgrade your database version" : "Lütfen veritabanı sürümünüzü yükseltin",
- "Error occurred while checking PostgreSQL version" : "PostgreSQL sürümü denetlenirken hata oluştu",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "PostgreSQL >= 9 sürümüne sahip olduğunuzu doğrulayın veya hata hakkında daha fazla bilgi için günlükleri denetleyin",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Lütfen izinleri 0770 olarak ayarlayıp dizinin diğer kullanıcılar tarafından görülememesini sağlayın.",
"Data directory (%s) is readable by other users" : "Veri dizini (%s) diğer kullanıcılar tarafından okunabilir",
"Data directory (%s) must be an absolute path" : "Veri dizini (%s) tam yol olmalıdır",
diff --git a/lib/l10n/uk.js b/lib/l10n/uk.js
index b2537139cc2..e7b5747f068 100644
--- a/lib/l10n/uk.js
+++ b/lib/l10n/uk.js
@@ -102,7 +102,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "Не вдалося поділитися %s, елемент не знайдено у файловому кеші.",
"Could not find category \"%s\"" : "Не вдалося знайти категорію \"%s\"",
"Apps" : "Додатки",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Тільки такі символи допускаються в імені користувача: \"az\", \"AZ\", \"0-9\", і \"_.@ -\"",
"A valid username must be provided" : "Потрібно задати вірне ім'я користувача",
"A valid password must be provided" : "Потрібно задати вірний пароль",
"The username is already being used" : "Ім'я користувача вже використовується",
@@ -129,8 +128,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "Будь ласка, зверніться до адміністратора, щоб перезавантажити сервер.",
"PostgreSQL >= 9 required" : "Потрібно PostgreSQL> = 9",
"Please upgrade your database version" : "Оновіть версію бази даних",
- "Error occurred while checking PostgreSQL version" : "Сталася помилка при перевірці версії PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Переконайтеся що версія PostgreSQL> = 9 або перевірте журнали для отримання додаткової інформацією про помилку",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Змініть права доступу на 0770, щоб інші користувачі не могли отримати список файлів цього каталогу.",
"Data directory (%s) is readable by other users" : "Каталог даних (%s) доступний для читання іншим користувачам",
"Data directory (%s) must be an absolute path" : "Тека з даними (%s) має бути задана абсолютним шляхом",
diff --git a/lib/l10n/uk.json b/lib/l10n/uk.json
index f5b1bc77465..08b826c5ec6 100644
--- a/lib/l10n/uk.json
+++ b/lib/l10n/uk.json
@@ -100,7 +100,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "Не вдалося поділитися %s, елемент не знайдено у файловому кеші.",
"Could not find category \"%s\"" : "Не вдалося знайти категорію \"%s\"",
"Apps" : "Додатки",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "Тільки такі символи допускаються в імені користувача: \"az\", \"AZ\", \"0-9\", і \"_.@ -\"",
"A valid username must be provided" : "Потрібно задати вірне ім'я користувача",
"A valid password must be provided" : "Потрібно задати вірний пароль",
"The username is already being used" : "Ім'я користувача вже використовується",
@@ -127,8 +126,6 @@
"Please ask your server administrator to restart the web server." : "Будь ласка, зверніться до адміністратора, щоб перезавантажити сервер.",
"PostgreSQL >= 9 required" : "Потрібно PostgreSQL> = 9",
"Please upgrade your database version" : "Оновіть версію бази даних",
- "Error occurred while checking PostgreSQL version" : "Сталася помилка при перевірці версії PostgreSQL",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "Переконайтеся що версія PostgreSQL> = 9 або перевірте журнали для отримання додаткової інформацією про помилку",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Змініть права доступу на 0770, щоб інші користувачі не могли отримати список файлів цього каталогу.",
"Data directory (%s) is readable by other users" : "Каталог даних (%s) доступний для читання іншим користувачам",
"Data directory (%s) must be an absolute path" : "Тека з даними (%s) має бути задана абсолютним шляхом",
diff --git a/lib/l10n/zh_CN.js b/lib/l10n/zh_CN.js
index 1ec317736af..8a24877ca1a 100644
--- a/lib/l10n/zh_CN.js
+++ b/lib/l10n/zh_CN.js
@@ -72,7 +72,6 @@ OC.L10N.register(
"Sharing %s failed, because the file could not be found in the file cache" : "共享 %s 失败,因为未在文件缓存中找到文件。",
"Could not find category \"%s\"" : "无法找到分类 \"%s\"",
"Apps" : "应用",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "用户名只允许使用以下字符:“a-z”,“A-Z”,“0-9”,和“_.@-”",
"A valid username must be provided" : "必须提供合法的用户名",
"A valid password must be provided" : "必须提供合法的密码",
"The username is already being used" : "用户名已被使用",
@@ -88,7 +87,6 @@ OC.L10N.register(
"Please ask your server administrator to restart the web server." : "请联系服务器管理员重启网页服务器。",
"PostgreSQL >= 9 required" : "要求 PostgreSQL >= 9",
"Please upgrade your database version" : "请升级您的数据库版本",
- "Error occurred while checking PostgreSQL version" : "检查 PostgreSQL 版本时发生了一个错误",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "请更改权限为 0770 以避免其他用户查看目录。",
"Data directory (%s) is readable by other users" : "文件目录 (%s) 可以被其他用户读取",
"Data directory (%s) is invalid" : "文件目录 (%s) 无效",
diff --git a/lib/l10n/zh_CN.json b/lib/l10n/zh_CN.json
index d1ec158a8d3..b4e67c7ae20 100644
--- a/lib/l10n/zh_CN.json
+++ b/lib/l10n/zh_CN.json
@@ -70,7 +70,6 @@
"Sharing %s failed, because the file could not be found in the file cache" : "共享 %s 失败,因为未在文件缓存中找到文件。",
"Could not find category \"%s\"" : "无法找到分类 \"%s\"",
"Apps" : "应用",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "用户名只允许使用以下字符:“a-z”,“A-Z”,“0-9”,和“_.@-”",
"A valid username must be provided" : "必须提供合法的用户名",
"A valid password must be provided" : "必须提供合法的密码",
"The username is already being used" : "用户名已被使用",
@@ -86,7 +85,6 @@
"Please ask your server administrator to restart the web server." : "请联系服务器管理员重启网页服务器。",
"PostgreSQL >= 9 required" : "要求 PostgreSQL >= 9",
"Please upgrade your database version" : "请升级您的数据库版本",
- "Error occurred while checking PostgreSQL version" : "检查 PostgreSQL 版本时发生了一个错误",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "请更改权限为 0770 以避免其他用户查看目录。",
"Data directory (%s) is readable by other users" : "文件目录 (%s) 可以被其他用户读取",
"Data directory (%s) is invalid" : "文件目录 (%s) 无效",
diff --git a/lib/l10n/zh_TW.js b/lib/l10n/zh_TW.js
index 1284f83e541..fda0ebe90f6 100644
--- a/lib/l10n/zh_TW.js
+++ b/lib/l10n/zh_TW.js
@@ -81,6 +81,7 @@ OC.L10N.register(
"Can't create or write into the data directory %s" : "無法建立或寫入資料目錄 %s",
"Invalid Federated Cloud ID" : "無效的雲端聯盟ID:",
"%s shared »%s« with you" : "%s 與您分享了 %s",
+ "%s via %s" : "%s 經由 %s",
"Sharing %s failed, because the backend does not allow shares from type %i" : "分享 %s失敗,不允許分享這樣的 %i 類別",
"Sharing %s failed, because the file does not exist" : "分享 %s 失敗,因為檔案不存在",
"You are not allowed to share %s" : "你不被允許分享 %s",
@@ -108,9 +109,11 @@ OC.L10N.register(
"Sharing %s failed, because resharing is not allowed" : "分享 %s 失敗,不允許重複分享",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "分享 %s 失敗,因為 %s 的分享後端找不到它的來源",
"Sharing %s failed, because the file could not be found in the file cache" : "分享 %s 失敗,因為在快取中找不到該檔案",
+ "Cannot increase permissions of %s" : "無法增加%s的權限",
+ "Expiration date is in the past" : "到期日是之前的時間",
+ "Cannot set expiration date more than %s days in the future" : "無法設定到期日超過未來%s天",
"Could not find category \"%s\"" : "找不到分類:\"%s\"",
"Apps" : "應用程式",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "使用者名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\", 和 \"_.@-\"",
"A valid username must be provided" : "必須提供一個有效的用戶名",
"A valid password must be provided" : "一定要提供一個有效的密碼",
"The username is already being used" : "這個使用者名稱已經有人使用了",
@@ -131,12 +134,11 @@ OC.L10N.register(
"Adjusting this setting in php.ini will make ownCloud run again" : "調整php.ini裡的這項設定會讓ownCloud再次運行",
"mbstring.func_overload is set to \"%s\" instead of the expected value \"0\"" : "mbstring.func_overload 應該要被設定成 \"0\"而不是目前的設定 \"%s\" ",
"To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini" : "為了修正這個問題,請到php.ini將 <code>mbstring.func_overload</code> 的值改為 <code>0</code>",
+ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "這大概是由快取或是加速器像是 Zend OPcache, eAccelerator 造成的",
"PHP modules have been installed, but they are still listed as missing?" : "你已經安裝了指定的 PHP 模組,可是還是顯示為找不到嗎?",
"Please ask your server administrator to restart the web server." : "請聯絡您的系統管理員重新啟動網頁伺服器",
"PostgreSQL >= 9 required" : "需要 PostgreSQL 版本 >= 9",
"Please upgrade your database version" : "請升級您的資料庫版本",
- "Error occurred while checking PostgreSQL version" : "檢查 PostgreSQL 版本時發生錯誤",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "請確定您的 PostgreSQL 版本 >= 9,或是看看記錄檔是否有更詳細的訊息",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他使用者讀取",
"Data directory (%s) is readable by other users" : "資料目錄 (%s) 可以被其他使用者讀取",
"Data directory (%s) must be an absolute path" : "資料夾目錄(%s) 必須式絕對路徑",
@@ -144,6 +146,10 @@ OC.L10N.register(
"Data directory (%s) is invalid" : "資料目錄 (%s) 無效",
"Please check that the data directory contains a file \".ocdata\" in its root." : "請確保資料目錄當中包含一個 .ocdata 的檔案",
"Could not obtain lock type %d on \"%s\"." : "無法取得鎖定:類型 %d ,檔案 %s",
- "Storage not available" : "無法存取儲存空間"
+ "Storage unauthorized. %s" : "儲存空間未經授權。%s",
+ "Storage incomplete configuration. %s" : "儲存空間配置尚未完成。%s",
+ "Storage connection error. %s" : "儲存空間連線錯誤。%s",
+ "Storage not available" : "無法存取儲存空間",
+ "Storage connection timeout. %s" : "儲存空間連線逾時。%s"
},
"nplurals=1; plural=0;");
diff --git a/lib/l10n/zh_TW.json b/lib/l10n/zh_TW.json
index 93aeea2c6e1..1b27a722443 100644
--- a/lib/l10n/zh_TW.json
+++ b/lib/l10n/zh_TW.json
@@ -79,6 +79,7 @@
"Can't create or write into the data directory %s" : "無法建立或寫入資料目錄 %s",
"Invalid Federated Cloud ID" : "無效的雲端聯盟ID:",
"%s shared »%s« with you" : "%s 與您分享了 %s",
+ "%s via %s" : "%s 經由 %s",
"Sharing %s failed, because the backend does not allow shares from type %i" : "分享 %s失敗,不允許分享這樣的 %i 類別",
"Sharing %s failed, because the file does not exist" : "分享 %s 失敗,因為檔案不存在",
"You are not allowed to share %s" : "你不被允許分享 %s",
@@ -106,9 +107,11 @@
"Sharing %s failed, because resharing is not allowed" : "分享 %s 失敗,不允許重複分享",
"Sharing %s failed, because the sharing backend for %s could not find its source" : "分享 %s 失敗,因為 %s 的分享後端找不到它的來源",
"Sharing %s failed, because the file could not be found in the file cache" : "分享 %s 失敗,因為在快取中找不到該檔案",
+ "Cannot increase permissions of %s" : "無法增加%s的權限",
+ "Expiration date is in the past" : "到期日是之前的時間",
+ "Cannot set expiration date more than %s days in the future" : "無法設定到期日超過未來%s天",
"Could not find category \"%s\"" : "找不到分類:\"%s\"",
"Apps" : "應用程式",
- "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"" : "使用者名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\", 和 \"_.@-\"",
"A valid username must be provided" : "必須提供一個有效的用戶名",
"A valid password must be provided" : "一定要提供一個有效的密碼",
"The username is already being used" : "這個使用者名稱已經有人使用了",
@@ -129,12 +132,11 @@
"Adjusting this setting in php.ini will make ownCloud run again" : "調整php.ini裡的這項設定會讓ownCloud再次運行",
"mbstring.func_overload is set to \"%s\" instead of the expected value \"0\"" : "mbstring.func_overload 應該要被設定成 \"0\"而不是目前的設定 \"%s\" ",
"To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini" : "為了修正這個問題,請到php.ini將 <code>mbstring.func_overload</code> 的值改為 <code>0</code>",
+ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "這大概是由快取或是加速器像是 Zend OPcache, eAccelerator 造成的",
"PHP modules have been installed, but they are still listed as missing?" : "你已經安裝了指定的 PHP 模組,可是還是顯示為找不到嗎?",
"Please ask your server administrator to restart the web server." : "請聯絡您的系統管理員重新啟動網頁伺服器",
"PostgreSQL >= 9 required" : "需要 PostgreSQL 版本 >= 9",
"Please upgrade your database version" : "請升級您的資料庫版本",
- "Error occurred while checking PostgreSQL version" : "檢查 PostgreSQL 版本時發生錯誤",
- "Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error" : "請確定您的 PostgreSQL 版本 >= 9,或是看看記錄檔是否有更詳細的訊息",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他使用者讀取",
"Data directory (%s) is readable by other users" : "資料目錄 (%s) 可以被其他使用者讀取",
"Data directory (%s) must be an absolute path" : "資料夾目錄(%s) 必須式絕對路徑",
@@ -142,6 +144,10 @@
"Data directory (%s) is invalid" : "資料目錄 (%s) 無效",
"Please check that the data directory contains a file \".ocdata\" in its root." : "請確保資料目錄當中包含一個 .ocdata 的檔案",
"Could not obtain lock type %d on \"%s\"." : "無法取得鎖定:類型 %d ,檔案 %s",
- "Storage not available" : "無法存取儲存空間"
+ "Storage unauthorized. %s" : "儲存空間未經授權。%s",
+ "Storage incomplete configuration. %s" : "儲存空間配置尚未完成。%s",
+ "Storage connection error. %s" : "儲存空間連線錯誤。%s",
+ "Storage not available" : "無法存取儲存空間",
+ "Storage connection timeout. %s" : "儲存空間連線逾時。%s"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/lib/private/activity/event.php b/lib/private/activity/event.php
index 413ff613186..b7e271b2104 100644
--- a/lib/private/activity/event.php
+++ b/lib/private/activity/event.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Phil Davis <phil.davis@inf.org>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/activitymanager.php b/lib/private/activitymanager.php
index fadfedf277f..68bb8c13401 100644
--- a/lib/private/activitymanager.php
+++ b/lib/private/activitymanager.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -310,20 +310,19 @@ class ActivityManager implements IManager {
/**
* @param string $type
- * @param int $id
+ * @param string $id
*/
public function setFormattingObject($type, $id) {
$this->formattingObjectType = $type;
- $this->formattingObjectId = $id;
+ $this->formattingObjectId = (string) $id;
}
/**
* @return bool
*/
public function isFormattingFilteredObject() {
- return 'filter' === $this->request->getParam('filter')
- && $this->formattingObjectType === $this->request->getParam('objecttype')
- && $this->formattingObjectId === $this->request->getParam('objectid');
+ return $this->formattingObjectType === $this->request->getParam('object_type')
+ && $this->formattingObjectId === $this->request->getParam('object_id');
}
/**
diff --git a/lib/private/allconfig.php b/lib/private/allconfig.php
index 7c2037e8048..3c85bfacbb8 100644
--- a/lib/private/allconfig.php
+++ b/lib/private/allconfig.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -205,57 +205,28 @@ class AllConfig implements \OCP\IConfig {
// TODO - FIXME
$this->fixDIInit();
- // Check if the key does exist
- $sql = 'SELECT `configvalue` FROM `*PREFIX*preferences` '.
- 'WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?';
- $result = $this->connection->executeQuery($sql, array($userId, $appName, $key));
- $oldValue = $result->fetchColumn();
- $result->closeCursor();
- $exists = $oldValue !== false;
-
- if($oldValue === strval($value)) {
- // no changes
- return;
+ $preconditionArray = [];
+ if (isset($preCondition)) {
+ $preconditionArray = [
+ 'configvalue' => $preCondition,
+ ];
}
- $affectedRows = 0;
- if (!$exists && $preCondition === null) {
- $this->connection->insertIfNotExist('*PREFIX*preferences', [
- 'configvalue' => $value,
- 'userid' => $userId,
- 'appid' => $appName,
- 'configkey' => $key,
- ], ['configkey', 'userid', 'appid']);
- $affectedRows = 1;
- } elseif ($exists) {
- $data = array($value, $userId, $appName, $key);
-
- $sql = 'UPDATE `*PREFIX*preferences` SET `configvalue` = ? '.
- 'WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? ';
-
- if($preCondition !== null) {
- if($this->getSystemValue('dbtype', 'sqlite') === 'oci') {
- //oracle hack: need to explicitly cast CLOB to CHAR for comparison
- $sql .= 'AND to_char(`configvalue`) = ?';
- } else {
- $sql .= 'AND `configvalue` = ?';
- }
- $data[] = $preCondition;
- }
- $affectedRows = $this->connection->executeUpdate($sql, $data);
- }
+ $this->connection->setValues('preferences', [
+ 'userid' => $userId,
+ 'appid' => $appName,
+ 'configkey' => $key,
+ ], [
+ 'configvalue' => $value,
+ ], $preconditionArray);
// only add to the cache if we already loaded data for the user
- if ($affectedRows > 0 && isset($this->userCache[$userId])) {
+ if (isset($this->userCache[$userId])) {
if (!isset($this->userCache[$userId][$appName])) {
$this->userCache[$userId][$appName] = array();
}
$this->userCache[$userId][$appName][$key] = $value;
}
-
- if ($preCondition !== null && $affectedRows === 0) {
- throw new PreConditionNotMetException;
- }
}
/**
diff --git a/lib/private/api.php b/lib/private/api.php
index edee30dfc96..1fbe3201f85 100644
--- a/lib/private/api.php
+++ b/lib/private/api.php
@@ -13,7 +13,7 @@
* @author Tom Needham <tom@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/app.php b/lib/private/app.php
index c6e235eda4d..2abc015a91f 100644
--- a/lib/private/app.php
+++ b/lib/private/app.php
@@ -20,7 +20,8 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author RealRancor <Fisch.666@gmx.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Sam Tuke <mail@samtuke.com>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
@@ -28,7 +29,7 @@
* @author Tom Needham <tom@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -96,7 +97,7 @@ class OC_App {
* if $types is set, only apps of those types will be loaded
*/
public static function loadApps($types = null) {
- if (OC_Config::getValue('maintenance', false)) {
+ if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
return false;
}
// Load the enabled apps here
@@ -239,7 +240,7 @@ class OC_App {
* @return string[]
*/
public static function getEnabledApps($forceRefresh = false, $all = false) {
- if (!OC_Config::getValue('installed', false)) {
+ if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
return array();
}
// in incognito mode or when logged out, $user will be false,
@@ -312,14 +313,14 @@ class OC_App {
* @param string $app
* @return int
*/
- public static function downloadApp($app) {
+ private static function downloadApp($app) {
$ocsClient = new OCSClient(
\OC::$server->getHTTPClientService(),
\OC::$server->getConfig(),
\OC::$server->getLogger()
);
- $appData = $ocsClient->getApplication($app, \OC_Util::getVersion());
- $download= $ocsClient->getApplicationDownload($app, \OC_Util::getVersion());
+ $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
+ $download = $ocsClient->getApplicationDownload($app, \OCP\Util::getVersion());
if(isset($download['downloadlink']) and $download['downloadlink']!='') {
// Replace spaces in download link without encoding entire URL
$download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
@@ -361,37 +362,6 @@ class OC_App {
}
/**
- * marks a navigation entry as active
- *
- * @param string $id id of the entry
- * @return bool
- *
- * This function sets a navigation entry as active and removes the 'active'
- * property from all other entries. The templates can use this for
- * highlighting the current position of the user.
- *
- * @deprecated Use \OC::$server->getNavigationManager()->setActiveEntry() instead
- */
- public static function setActiveNavigationEntry($id) {
- OC::$server->getNavigationManager()->setActiveEntry($id);
- return true;
- }
-
- /**
- * gets the active Menu entry
- *
- * @return string id or empty string
- *
- * This function returns the id of the active navigation entry (set by
- * setActiveNavigationEntry
- *
- * @deprecated Use \OC::$server->getNavigationManager()->getActiveEntry() instead
- */
- public static function getActiveNavigationEntry() {
- return OC::$server->getNavigationManager()->getActiveEntry();
- }
-
- /**
* Returns the Settings Navigation
*
* @return string[]
@@ -401,19 +371,20 @@ class OC_App {
*/
public static function getSettingsNavigation() {
$l = \OC::$server->getL10N('lib');
+ $urlGenerator = \OC::$server->getURLGenerator();
$settings = array();
// by default, settings only contain the help menu
if (OC_Util::getEditionString() === '' &&
- OC_Config::getValue('knowledgebaseenabled', true) == true
+ \OC::$server->getSystemConfig()->getValue('knowledgebaseenabled', true) == true
) {
$settings = array(
array(
"id" => "help",
"order" => 1000,
- "href" => OC_Helper::linkToRoute("settings_help"),
+ "href" => $urlGenerator->linkToRoute('settings_help'),
"name" => $l->t("Help"),
- "icon" => OC_Helper::imagePath("settings", "help.svg")
+ "icon" => $urlGenerator->imagePath("settings", "help.svg")
)
);
}
@@ -424,9 +395,9 @@ class OC_App {
$settings[] = array(
"id" => "personal",
"order" => 1,
- "href" => OC_Helper::linkToRoute("settings_personal"),
+ "href" => $urlGenerator->linkToRoute('settings_personal'),
"name" => $l->t("Personal"),
- "icon" => OC_Helper::imagePath("settings", "personal.svg")
+ "icon" => $urlGenerator->imagePath("settings", "personal.svg")
);
//SubAdmins are also allowed to access user management
@@ -440,9 +411,9 @@ class OC_App {
$settings[] = array(
"id" => "core_users",
"order" => 2,
- "href" => OC_Helper::linkToRoute("settings_users"),
+ "href" => $urlGenerator->linkToRoute('settings_users'),
"name" => $l->t("Users"),
- "icon" => OC_Helper::imagePath("settings", "users.svg")
+ "icon" => $urlGenerator->imagePath("settings", "users.svg")
);
}
@@ -452,9 +423,9 @@ class OC_App {
$settings[] = array(
"id" => "admin",
"order" => 1000,
- "href" => OC_Helper::linkToRoute("settings_admin"),
+ "href" => $urlGenerator->linkToRoute('settings_admin'),
"name" => $l->t("Admin"),
- "icon" => OC_Helper::imagePath("settings", "admin.svg")
+ "icon" => $urlGenerator->imagePath("settings", "admin.svg")
);
}
}
@@ -486,7 +457,7 @@ class OC_App {
* @return string|false
*/
public static function getInstallPath() {
- if (OC_Config::getValue('appstoreenabled', true) == false) {
+ if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
return false;
}
@@ -505,9 +476,13 @@ class OC_App {
* search for an app in all app-directories
*
* @param string $appId
- * @return mixed (bool|string)
+ * @return false|string
*/
protected static function findAppInDirectories($appId) {
+ $sanitizedAppId = self::cleanAppId($appId);
+ if($sanitizedAppId !== $appId) {
+ return false;
+ }
static $app_dir = array();
if (isset($app_dir[$appId])) {
@@ -787,9 +762,12 @@ class OC_App {
* @param bool $onlyLocal
* @param bool $includeUpdateInfo Should we check whether there is an update
* in the app store?
+ * @param OCSClient $ocsClient
* @return array
*/
- public static function listAllApps($onlyLocal = false, $includeUpdateInfo = true) {
+ public static function listAllApps($onlyLocal = false,
+ $includeUpdateInfo = true,
+ OCSClient $ocsClient) {
$installedApps = OC_App::getAllApps();
//TODO which apps do we want to blacklist and how do we integrate
@@ -836,12 +814,12 @@ class OC_App {
$appIcon = self::getAppPath($app) . '/img/' . $app . '.svg';
if (file_exists($appIcon)) {
- $info['preview'] = OC_Helper::imagePath($app, $app . '.svg');
+ $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
$info['previewAsIcon'] = true;
} else {
$appIcon = self::getAppPath($app) . '/img/app.svg';
if (file_exists($appIcon)) {
- $info['preview'] = OC_Helper::imagePath($app, 'app.svg');
+ $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
$info['previewAsIcon'] = true;
}
}
@@ -852,7 +830,7 @@ class OC_App {
if ($onlyLocal) {
$remoteApps = [];
} else {
- $remoteApps = OC_App::getAppstoreApps();
+ $remoteApps = OC_App::getAppstoreApps('approved', null, $ocsClient);
}
if ($remoteApps) {
// Remove duplicates
@@ -879,7 +857,7 @@ class OC_App {
* @param string $ocsID
* @return string|false
*/
- protected static function getInternalAppIdByOcs($ocsID) {
+ public static function getInternalAppIdByOcs($ocsID) {
if(is_numeric($ocsID)) {
$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
if(array_search($ocsID, $idArray)) {
@@ -892,22 +870,18 @@ class OC_App {
/**
* Get a list of all apps on the appstore
* @param string $filter
- * @param string $category
+ * @param string|null $category
+ * @param OCSClient $ocsClient
* @return array|bool multi-dimensional array of apps.
* Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description
*/
- public static function getAppstoreApps($filter = 'approved', $category = null) {
+ public static function getAppstoreApps($filter = 'approved',
+ $category = null,
+ OCSClient $ocsClient) {
$categories = [$category];
- $ocsClient = new OCSClient(
- \OC::$server->getHTTPClientService(),
- \OC::$server->getConfig(),
- \OC::$server->getLogger()
- );
-
-
if (is_null($category)) {
- $categoryNames = $ocsClient->getCategories(\OC_Util::getVersion());
+ $categoryNames = $ocsClient->getCategories(\OCP\Util::getVersion());
if (is_array($categoryNames)) {
// Check that categories of apps were retrieved correctly
if (!$categories = array_keys($categoryNames)) {
@@ -919,7 +893,7 @@ class OC_App {
}
$page = 0;
- $remoteApps = $ocsClient->getApplications($categories, $page, $filter, \OC_Util::getVersion());
+ $remoteApps = $ocsClient->getApplications($categories, $page, $filter, \OCP\Util::getVersion());
$apps = [];
$i = 0;
$l = \OC::$server->getL10N('core');
@@ -940,6 +914,11 @@ class OC_App {
$apps[$i]['internalclass'] = 'recommendedapp';
}
+ // Apps from the appstore are always assumed to be compatible with the
+ // the current release as the initial filtering is done on the appstore
+ $apps[$i]['dependencies']['owncloud']['@attributes']['min-version'] = implode('.', \OCP\Util::getVersion());
+ $apps[$i]['dependencies']['owncloud']['@attributes']['max-version'] = implode('.', \OCP\Util::getVersion());
+
$i++;
}
@@ -1045,26 +1024,17 @@ class OC_App {
*/
public static function getAppVersions() {
static $versions;
- if (isset($versions)) { // simple cache, needs to be fixed
- return $versions; // when function is used besides in checkUpgrade
- }
- $versions = array();
- try {
- $query = OC_DB::prepare('SELECT `appid`, `configvalue` FROM `*PREFIX*appconfig`'
- . ' WHERE `configkey` = \'installed_version\'');
- $result = $query->execute();
- while ($row = $result->fetchRow()) {
- $versions[$row['appid']] = $row['configvalue'];
- }
- return $versions;
- } catch (\Exception $e) {
- return array();
+
+ if(!$versions) {
+ $appConfig = \OC::$server->getAppConfig();
+ $versions = $appConfig->getValues(false, 'installed_version');
}
+ return $versions;
}
/**
- * @param mixed $app
+ * @param string $app
* @return bool
* @throws Exception if app is not compatible with this version of ownCloud
* @throws Exception if no app-name was specified
@@ -1077,7 +1047,7 @@ class OC_App {
$config,
\OC::$server->getLogger()
);
- $appData = $ocsClient->getApplication($app, \OC_Util::getVersion());
+ $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
// check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string
if (!is_numeric($app)) {
@@ -1107,7 +1077,7 @@ class OC_App {
if ($app !== false) {
// check if the app is compatible with this version of ownCloud
$info = self::getAppInfo($app);
- $version = OC_Util::getVersion();
+ $version = \OCP\Util::getVersion();
if (!self::isAppCompatible($version, $info)) {
throw new \Exception(
$l->t('App "%s" cannot be installed because it is not compatible with this version of ownCloud.',
diff --git a/lib/private/app/appmanager.php b/lib/private/app/appmanager.php
index 1f993d8538f..bf07a2ef548 100644
--- a/lib/private/app/appmanager.php
+++ b/lib/private/app/appmanager.php
@@ -4,9 +4,10 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -34,6 +35,18 @@ use OCP\IUserSession;
class AppManager implements IAppManager {
+ /**
+ * Apps with these types can not be enabled for certain groups only
+ * @var string[]
+ */
+ protected $protectedAppTypes = [
+ 'filesystem',
+ 'prelogin',
+ 'authentication',
+ 'logging',
+ 'prevent_group_restriction',
+ ];
+
/** @var \OCP\IUserSession */
private $userSession;
@@ -77,6 +90,12 @@ class AppManager implements IAppManager {
private function getInstalledAppsValues() {
if (!$this->installedAppsCache) {
$values = $this->appConfig->getValues(false, 'enabled');
+
+ $alwaysEnabledApps = $this->getAlwaysEnabledApps();
+ foreach($alwaysEnabledApps as $appId) {
+ $values[$appId] = 'yes';
+ }
+
$this->installedAppsCache = array_filter($values, function ($value) {
return $value !== 'no';
});
@@ -141,7 +160,18 @@ class AppManager implements IAppManager {
} elseif (is_null($user)) {
return false;
} else {
+ if(empty($enabled)){
+ return false;
+ }
+
$groupIds = json_decode($enabled);
+
+ if (!is_array($groupIds)) {
+ $jsonError = json_last_error();
+ \OC::$server->getLogger()->warning('AppManger::checkAppForUser - can\'t decode group IDs: ' . print_r($enabled, true) . ' - json error code: ' . $jsonError, ['app' => 'lib']);
+ return false;
+ }
+
$userGroups = $this->groupManager->getUserGroupIds($user);
foreach ($userGroups as $groupId) {
if (array_search($groupId, $groupIds) !== false) {
@@ -179,8 +209,17 @@ class AppManager implements IAppManager {
*
* @param string $appId
* @param \OCP\IGroup[] $groups
+ * @throws \Exception if app can't be enabled for groups
*/
public function enableAppForGroups($appId, $groups) {
+ $info = $this->getAppInfo($appId);
+ if (!empty($info['types'])) {
+ $protectedTypes = array_intersect($this->protectedAppTypes, $info['types']);
+ if (!empty($protectedTypes)) {
+ throw new \Exception("$appId can't be enabled for groups.");
+ }
+ }
+
$groupIds = array_map(function ($group) {
/** @var \OCP\IGroup $group */
return $group->getGID();
diff --git a/lib/private/app/codechecker/abstractcheck.php b/lib/private/app/codechecker/abstractcheck.php
index c1c6524e42f..ca91d366482 100644
--- a/lib/private/app/codechecker/abstractcheck.php
+++ b/lib/private/app/codechecker/abstractcheck.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/app/codechecker/codechecker.php b/lib/private/app/codechecker/codechecker.php
index ef7dc7f3e4d..0ca597ccb4e 100644
--- a/lib/private/app/codechecker/codechecker.php
+++ b/lib/private/app/codechecker/codechecker.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/app/codechecker/deprecationcheck.php b/lib/private/app/codechecker/deprecationcheck.php
index 1d287edc858..fa5eae8ab1d 100644
--- a/lib/private/app/codechecker/deprecationcheck.php
+++ b/lib/private/app/codechecker/deprecationcheck.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/app/codechecker/emptycheck.php b/lib/private/app/codechecker/emptycheck.php
index 0e5df55d090..b779926d5e4 100644
--- a/lib/private/app/codechecker/emptycheck.php
+++ b/lib/private/app/codechecker/emptycheck.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/app/codechecker/icheck.php b/lib/private/app/codechecker/icheck.php
index a00e0d8fa13..97e0bc9b8a0 100644
--- a/lib/private/app/codechecker/icheck.php
+++ b/lib/private/app/codechecker/icheck.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/app/codechecker/infochecker.php b/lib/private/app/codechecker/infochecker.php
index 24835d8148f..ac92ee2661c 100644
--- a/lib/private/app/codechecker/infochecker.php
+++ b/lib/private/app/codechecker/infochecker.php
@@ -1,8 +1,9 @@
<?php
/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -83,13 +84,18 @@ class InfoChecker extends BasicEmitter {
'type' => 'duplicateRequirement',
'field' => 'min',
];
+ } else if (!isset($info['dependencies']['owncloud']['@attributes']['min-version'])) {
+ $this->emit('InfoChecker', 'missingRequirement', ['min']);
}
+
if (isset($info['dependencies']['owncloud']['@attributes']['max-version']) && $info['requiremax']) {
$this->emit('InfoChecker', 'duplicateRequirement', ['max']);
$errors[] = [
'type' => 'duplicateRequirement',
'field' => 'max',
];
+ } else if (!isset($info['dependencies']['owncloud']['@attributes']['max-version'])) {
+ $this->emit('InfoChecker', 'missingRequirement', ['max']);
}
foreach ($info as $key => $value) {
diff --git a/lib/private/app/codechecker/nodevisitor.php b/lib/private/app/codechecker/nodevisitor.php
index cf850147fd8..f9386caeeae 100644
--- a/lib/private/app/codechecker/nodevisitor.php
+++ b/lib/private/app/codechecker/nodevisitor.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/app/codechecker/privatecheck.php b/lib/private/app/codechecker/privatecheck.php
index bafcfd1d03e..32248ab21e2 100644
--- a/lib/private/app/codechecker/privatecheck.php
+++ b/lib/private/app/codechecker/privatecheck.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/app/codechecker/strongcomparisoncheck.php b/lib/private/app/codechecker/strongcomparisoncheck.php
index 3072027b258..919647a6a54 100644
--- a/lib/private/app/codechecker/strongcomparisoncheck.php
+++ b/lib/private/app/codechecker/strongcomparisoncheck.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/app/dependencyanalyzer.php b/lib/private/app/dependencyanalyzer.php
index 5d86368ea83..0cf4bc72161 100644
--- a/lib/private/app/dependencyanalyzer.php
+++ b/lib/private/app/dependencyanalyzer.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -73,7 +73,7 @@ class DependencyAnalyzer {
* 5.2.6.5 and 5.1 will be turned into 5.2 and 5.1
* @param string $first
* @param string $second
- * @return array first element is the first version, second element is the
+ * @return string[] first element is the first version, second element is the
* second version
*/
private function normalizeVersions($first, $second) {
diff --git a/lib/private/app/infoparser.php b/lib/private/app/infoparser.php
index 789f01e5bc4..c33e5349f3b 100644
--- a/lib/private/app/infoparser.php
+++ b/lib/private/app/infoparser.php
@@ -1,10 +1,11 @@
<?php
/**
* @author Andreas Fischer <bantu@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -59,9 +60,10 @@ class InfoParser {
$xml = simplexml_load_file($file);
libxml_disable_entity_loader($loadEntities);
if ($xml == false) {
+ libxml_clear_errors();
return null;
}
- $array = $this->xmlToArray($xml, false);
+ $array = $this->xmlToArray($xml);
if (is_null($array)) {
return null;
}
diff --git a/lib/private/app/platform.php b/lib/private/app/platform.php
index f433ecd9f9e..1d4c3767121 100644
--- a/lib/private/app/platform.php
+++ b/lib/private/app/platform.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -52,7 +52,7 @@ class Platform {
* @return string
*/
public function getOcVersion() {
- $v = OC_Util::getVersion();
+ $v = \OCP\Util::getVersion();
return join('.', $v);
}
diff --git a/lib/private/app/platformrepository.php b/lib/private/app/platformrepository.php
index fa71bd7d91a..7363b2a44b1 100644
--- a/lib/private/app/platformrepository.php
+++ b/lib/private/app/platformrepository.php
@@ -2,7 +2,7 @@
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -206,6 +206,9 @@ class PlatformRepository {
throw new \UnexpectedValueException('Invalid version string "' . $version . '"' . $extraMessage);
}
+ /**
+ * @param string $stability
+ */
private function expandStability($stability) {
$stability = strtolower($stability);
switch ($stability) {
diff --git a/lib/private/appconfig.php b/lib/private/appconfig.php
index d1c1e4bfc45..035495992ef 100644
--- a/lib/private/appconfig.php
+++ b/lib/private/appconfig.php
@@ -7,10 +7,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -251,14 +251,13 @@ class AppConfig implements IAppConfig {
if ($key === false) {
return $this->getAppValues($app);
} else {
- $configs = [];
- foreach ($this->getApps() as $appId) {
- if ($this->hasKey($appId, $key)) {
- $configs[$appId] = $this->getValue($appId, $key);
- }
- }
+ $appIds = $this->getApps();
+ $values = array_map(function($appId) use ($key) {
+ return isset($this->cache[$appId][$key]) ? $this->cache[$appId][$key] : null;
+ }, $appIds);
+ $result = array_combine($appIds, $values);
- return $configs;
+ return array_filter($result);
}
}
diff --git a/lib/private/appframework/app.php b/lib/private/appframework/app.php
index 0188d221be1..376a8559454 100644
--- a/lib/private/appframework/app.php
+++ b/lib/private/appframework/app.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +26,7 @@
namespace OC\AppFramework;
+use OC\AppFramework\Http\Dispatcher;
use OC_App;
use OC\AppFramework\DependencyInjection\DIContainer;
use OCP\AppFramework\QueryException;
@@ -97,6 +98,7 @@ class App {
}
// initialize the dispatcher and run all the middleware before the controller
+ /** @var Dispatcher $dispatcher */
$dispatcher = $container['Dispatcher'];
list(
diff --git a/lib/private/appframework/core/api.php b/lib/private/appframework/core/api.php
index 28c846b8d40..67b696948f0 100644
--- a/lib/private/appframework/core/api.php
+++ b/lib/private/appframework/core/api.php
@@ -4,10 +4,10 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/appframework/db/db.php b/lib/private/appframework/db/db.php
index 9f912f9c0a4..5fdc5d1066c 100644
--- a/lib/private/appframework/db/db.php
+++ b/lib/private/appframework/db/db.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -147,6 +147,21 @@ class Db implements IDb {
}
/**
+ * Insert or update a row value
+ *
+ * @param string $table
+ * @param array $keys (column name => value)
+ * @param array $values (column name => value)
+ * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
+ * @return int number of new rows
+ * @throws \Doctrine\DBAL\DBALException
+ * @throws PreconditionNotMetException
+ */
+ public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
+ return $this->connection->setValues($table, $keys, $values, $updatePreconditionValues);
+ }
+
+ /**
* Start a transaction
*/
public function beginTransaction() {
diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php
index a32d32fefc5..5fc45fdd2e8 100644
--- a/lib/private/appframework/dependencyinjection/dicontainer.php
+++ b/lib/private/appframework/dependencyinjection/dicontainer.php
@@ -1,15 +1,16 @@
<?php
/**
* @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,7 +32,6 @@ namespace OC\AppFramework\DependencyInjection;
use OC;
use OC\AppFramework\Http;
-use OC\AppFramework\Http\Request;
use OC\AppFramework\Http\Dispatcher;
use OC\AppFramework\Http\Output;
use OC\AppFramework\Core\API;
@@ -42,8 +42,6 @@ use OC\AppFramework\Middleware\SessionMiddleware;
use OC\AppFramework\Utility\SimpleContainer;
use OCP\AppFramework\IApi;
use OCP\AppFramework\IAppContainer;
-use OCP\AppFramework\Middleware;
-use OCP\IServerContainer;
class DIContainer extends SimpleContainer implements IAppContainer {
@@ -62,6 +60,10 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$this['AppName'] = $appName;
$this['urlParams'] = $urlParams;
+ /** @var \OC\ServerContainer $server */
+ $server = $this->getServer();
+ $server->registerAppContainer($appName, $this);
+
// aliases
$this->registerAlias('appName', 'AppName');
$this->registerAlias('webRoot', 'WebRoot');
@@ -130,6 +132,10 @@ class DIContainer extends SimpleContainer implements IAppContainer {
return $this->getServer()->getQueryLogger();
});
+ $this->registerService('OCP\\Files\\IMimeTypeDetector', function($c) {
+ return $this->getServer()->getMimeTypeDetector();
+ });
+
$this->registerService('OCP\\Files\\Config\\IMountProviderCollection', function($c) {
return $this->getServer()->getMountProviderCollection();
});
@@ -146,6 +152,10 @@ class DIContainer extends SimpleContainer implements IAppContainer {
return $this->getServer()->getL10N($c->query('AppName'));
});
+ $this->registerService('OCP\\L10N\\IFactory', function($c) {
+ return $this->getServer()->getL10NFactory();
+ });
+
$this->registerService('OCP\\ILogger', function($c) {
return $this->getServer()->getLogger();
});
@@ -157,10 +167,18 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$this->registerAlias('OCP\\AppFramework\\Utility\\IControllerMethodReflector', 'OC\AppFramework\Utility\ControllerMethodReflector');
$this->registerAlias('ControllerMethodReflector', 'OCP\\AppFramework\\Utility\\IControllerMethodReflector');
+ $this->registerService('OCP\\Files\\IMimeTypeDetector', function($c) {
+ return $this->getServer()->getMimeTypeDetector();
+ });
+
$this->registerService('OCP\\INavigationManager', function($c) {
return $this->getServer()->getNavigationManager();
});
+ $this->registerService('OCP\\Notification\IManager', function($c) {
+ return $this->getServer()->getNotificationManager();
+ });
+
$this->registerService('OCP\\IPreview', function($c) {
return $this->getServer()->getPreviewManager();
});
@@ -202,10 +220,26 @@ class DIContainer extends SimpleContainer implements IAppContainer {
return $this->getServer()->getHasher();
});
+ $this->registerService('OCP\\Security\\ICredentialsManager', function($c) {
+ return $this->getServer()->getCredentialsManager();
+ });
+
$this->registerService('OCP\\Security\\ISecureRandom', function($c) {
return $this->getServer()->getSecureRandom();
});
+ $this->registerService('OCP\\Share\\IManager', function($c) {
+ return $this->getServer()->getShareManager();
+ });
+
+ $this->registerService('OCP\\SystemTag\\ISystemTagManager', function() {
+ return $this->getServer()->getSystemTagManager();
+ });
+
+ $this->registerService('OCP\\SystemTag\\ISystemTagObjectMapper', function() {
+ return $this->getServer()->getSystemTagObjectMapper();
+ });
+
$this->registerService('OCP\\IURLGenerator', function($c) {
return $this->getServer()->getURLGenerator();
});
@@ -222,9 +256,14 @@ class DIContainer extends SimpleContainer implements IAppContainer {
return $this->getServer()->getSession();
});
+ $this->registerService('OCP\\Security\\IContentSecurityPolicyManager', function($c) {
+ return $this->getServer()->getContentSecurityPolicyManager();
+ });
+
$this->registerService('ServerContainer', function ($c) {
return $this->getServer();
});
+ $this->registerAlias('OCP\\IServerContainer', 'ServerContainer');
$this->registerService('Symfony\Component\EventDispatcher\EventDispatcherInterface', function ($c) {
return $this->getServer()->getEventDispatcher();
@@ -285,7 +324,8 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$app->getServer()->getLogger(),
$c['AppName'],
$app->isLoggedIn(),
- $app->isAdminUser()
+ $app->isAdminUser(),
+ $app->getServer()->getContentSecurityPolicyManager()
);
});
diff --git a/lib/private/appframework/http.php b/lib/private/appframework/http.php
index e64759fa924..a99f7ea437f 100644
--- a/lib/private/appframework/http.php
+++ b/lib/private/appframework/http.php
@@ -1,13 +1,14 @@
<?php
/**
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/appframework/http/dispatcher.php b/lib/private/appframework/http/dispatcher.php
index 5fabdad75b9..641339c0d94 100644
--- a/lib/private/appframework/http/dispatcher.php
+++ b/lib/private/appframework/http/dispatcher.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/appframework/http/output.php b/lib/private/appframework/http/output.php
index f4773ab1063..dfb03e6a516 100644
--- a/lib/private/appframework/http/output.php
+++ b/lib/private/appframework/http/output.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/appframework/http/request.php b/lib/private/appframework/http/request.php
index 96620838dfb..caddb5a235d 100644
--- a/lib/private/appframework/http/request.php
+++ b/lib/private/appframework/http/request.php
@@ -5,13 +5,16 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Mitar <mitar.git@tnode.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,6 +33,8 @@
namespace OC\AppFramework\Http;
+use OC\Security\CSRF\CsrfToken;
+use OC\Security\CSRF\CsrfTokenManager;
use OC\Security\TrustedDomainHelper;
use OCP\IConfig;
use OCP\IRequest;
@@ -42,7 +47,7 @@ use OCP\Security\ISecureRandom;
*/
class Request implements \ArrayAccess, \Countable, IRequest {
- const USER_AGENT_IE = '/MSIE/';
+ const USER_AGENT_IE = '/(MSIE)|(Trident)/';
const USER_AGENT_IE_8 = '/MSIE 8.0/';
// Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent
const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#';
@@ -72,6 +77,8 @@ class Request implements \ArrayAccess, \Countable, IRequest {
protected $requestId = '';
/** @var ICrypto */
protected $crypto;
+ /** @var CsrfTokenManager|null */
+ protected $csrfTokenManager;
/** @var bool */
protected $contentDecoded = false;
@@ -89,17 +96,20 @@ class Request implements \ArrayAccess, \Countable, IRequest {
* - string|false 'requesttoken' the requesttoken or false when not available
* @param ISecureRandom $secureRandom
* @param IConfig $config
+ * @param CsrfTokenManager|null $csrfTokenManager
* @param string $stream
* @see http://www.php.net/manual/en/reserved.variables.php
*/
public function __construct(array $vars=array(),
ISecureRandom $secureRandom = null,
IConfig $config,
- $stream='php://input') {
+ CsrfTokenManager $csrfTokenManager = null,
+ $stream = 'php://input') {
$this->inputStream = $stream;
$this->items['params'] = array();
$this->secureRandom = $secureRandom;
$this->config = $config;
+ $this->csrfTokenManager = $csrfTokenManager;
if(!array_key_exists('method', $vars)) {
$vars['method'] = 'GET';
@@ -418,10 +428,9 @@ class Request implements \ArrayAccess, \Countable, IRequest {
/**
* Checks if the CSRF check was correct
* @return bool true if CSRF check passed
- * @see OC_Util::callRegister()
*/
public function passesCSRFCheck() {
- if($this->items['requesttoken'] === false) {
+ if($this->csrfTokenManager === null) {
return false;
}
@@ -435,23 +444,9 @@ class Request implements \ArrayAccess, \Countable, IRequest {
//no token found.
return false;
}
+ $token = new CsrfToken($token);
- // Deobfuscate token to prevent BREACH like attacks
- $token = explode(':', $token);
- if (count($token) !== 2) {
- return false;
- }
-
- $obfuscatedToken = $token[0];
- $secret = $token[1];
- $deobfuscatedToken = base64_decode($obfuscatedToken) ^ $secret;
-
- // Check if the token is valid
- if(\OCP\Security\StringUtils::equals($deobfuscatedToken, $this->items['requesttoken'])) {
- return true;
- } else {
- return false;
- }
+ return $this->csrfTokenManager->isTokenValid($token);
}
/**
@@ -465,7 +460,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
}
if(empty($this->requestId)) {
- $this->requestId = $this->secureRandom->getLowStrengthGenerator()->generate(20);
+ $this->requestId = $this->secureRandom->generate(20);
}
return $this->requestId;
@@ -541,7 +536,8 @@ class Request implements \ArrayAccess, \Countable, IRequest {
if (isset($this->server['HTTPS'])
&& $this->server['HTTPS'] !== null
- && $this->server['HTTPS'] !== 'off') {
+ && $this->server['HTTPS'] !== 'off'
+ && $this->server['HTTPS'] !== '') {
return 'https';
}
@@ -674,6 +670,9 @@ class Request implements \ArrayAccess, \Countable, IRequest {
* @return bool true if at least one of the given agent matches, false otherwise
*/
public function isUserAgent(array $agent) {
+ if (!isset($this->server['HTTP_USER_AGENT'])) {
+ return false;
+ }
foreach ($agent as $regex) {
if (preg_match($regex, $this->server['HTTP_USER_AGENT'])) {
return true;
diff --git a/lib/private/appframework/middleware/middlewaredispatcher.php b/lib/private/appframework/middleware/middlewaredispatcher.php
index 5d4cf3786f1..e2b2eff42ab 100644
--- a/lib/private/appframework/middleware/middlewaredispatcher.php
+++ b/lib/private/appframework/middleware/middlewaredispatcher.php
@@ -6,7 +6,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/appframework/middleware/security/corsmiddleware.php b/lib/private/appframework/middleware/security/corsmiddleware.php
index 74b0dd09974..e42513b44a2 100644
--- a/lib/private/appframework/middleware/security/corsmiddleware.php
+++ b/lib/private/appframework/middleware/security/corsmiddleware.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +23,7 @@
namespace OC\AppFramework\Middleware\Security;
+use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
diff --git a/lib/private/appframework/middleware/security/exceptions/appnotenabledexception.php b/lib/private/appframework/middleware/security/exceptions/appnotenabledexception.php
new file mode 100644
index 00000000000..59e247f3307
--- /dev/null
+++ b/lib/private/appframework/middleware/security/exceptions/appnotenabledexception.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Appframework\Middleware\Security\Exceptions;
+
+use OCP\AppFramework\Http;
+
+/**
+ * Class AppNotEnabledException is thrown when a resource for an application is
+ * requested that is not enabled.
+ *
+ * @package OC\Appframework\Middleware\Security\Exceptions
+ */
+class AppNotEnabledException extends SecurityException {
+ public function __construct() {
+ parent::__construct('App is not enabled', Http::STATUS_PRECONDITION_FAILED);
+ }
+}
diff --git a/lib/private/appframework/middleware/security/exceptions/crosssiterequestforgeryexception.php b/lib/private/appframework/middleware/security/exceptions/crosssiterequestforgeryexception.php
new file mode 100644
index 00000000000..0eeb81730d4
--- /dev/null
+++ b/lib/private/appframework/middleware/security/exceptions/crosssiterequestforgeryexception.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Appframework\Middleware\Security\Exceptions;
+
+use OCP\AppFramework\Http;
+
+/**
+ * Class CrossSiteRequestForgeryException is thrown when a CSRF exception has
+ * been encountered.
+ *
+ * @package OC\Appframework\Middleware\Security\Exceptions
+ */
+class CrossSiteRequestForgeryException extends SecurityException {
+ public function __construct() {
+ parent::__construct('CSRF check failed', Http::STATUS_PRECONDITION_FAILED);
+ }
+}
diff --git a/lib/private/appframework/middleware/security/exceptions/notadminexception.php b/lib/private/appframework/middleware/security/exceptions/notadminexception.php
new file mode 100644
index 00000000000..be0f2f9d2a9
--- /dev/null
+++ b/lib/private/appframework/middleware/security/exceptions/notadminexception.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Appframework\Middleware\Security\Exceptions;
+
+use OCP\AppFramework\Http;
+
+/**
+ * Class NotAdminException is thrown when a resource has been requested by a
+ * non-admin user that is not accessible to non-admin users.
+ *
+ * @package OC\Appframework\Middleware\Security\Exceptions
+ */
+class NotAdminException extends SecurityException {
+ public function __construct() {
+ parent::__construct('Logged in user must be an admin', Http::STATUS_FORBIDDEN);
+ }
+}
diff --git a/lib/private/appframework/middleware/security/exceptions/notloggedinexception.php b/lib/private/appframework/middleware/security/exceptions/notloggedinexception.php
new file mode 100644
index 00000000000..f5b2e032032
--- /dev/null
+++ b/lib/private/appframework/middleware/security/exceptions/notloggedinexception.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Appframework\Middleware\Security\Exceptions;
+
+use OCP\AppFramework\Http;
+
+/**
+ * Class NotLoggedInException is thrown when a resource has been requested by a
+ * guest user that is not accessible to the public.
+ *
+ * @package OC\Appframework\Middleware\Security\Exceptions
+ */
+class NotLoggedInException extends SecurityException {
+ public function __construct() {
+ parent::__construct('Current user is not logged in', Http::STATUS_UNAUTHORIZED);
+ }
+}
diff --git a/lib/private/appframework/middleware/security/securityexception.php b/lib/private/appframework/middleware/security/exceptions/securityexception.php
index 6f96b9a1d80..c86614ec477 100644
--- a/lib/private/appframework/middleware/security/securityexception.php
+++ b/lib/private/appframework/middleware/security/exceptions/securityexception.php
@@ -1,9 +1,10 @@
<?php
/**
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,20 +21,12 @@
*
*/
-
-namespace OC\AppFramework\Middleware\Security;
-
+namespace OC\AppFramework\Middleware\Security\Exceptions;
/**
- * Thrown when the security middleware encounters a security problem
+ * Class SecurityException is the base class for security exceptions thrown by
+ * the security middleware.
+ *
+ * @package OC\AppFramework\Middleware\Security\Exceptions
*/
-class SecurityException extends \Exception {
-
- /**
- * @param string $msg the security error message
- */
- public function __construct($msg, $code = 0) {
- parent::__construct($msg, $code);
- }
-
-}
+class SecurityException extends \Exception {}
diff --git a/lib/private/appframework/middleware/security/securitymiddleware.php b/lib/private/appframework/middleware/security/securitymiddleware.php
index 34c626ce8be..f1ba98254f0 100644
--- a/lib/private/appframework/middleware/security/securitymiddleware.php
+++ b/lib/private/appframework/middleware/security/securitymiddleware.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,9 +27,15 @@
namespace OC\AppFramework\Middleware\Security;
-use OC\AppFramework\Http;
+use OC\Appframework\Middleware\Security\Exceptions\AppNotEnabledException;
+use OC\Appframework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException;
+use OC\Appframework\Middleware\Security\Exceptions\NotAdminException;
+use OC\Appframework\Middleware\Security\Exceptions\NotLoggedInException;
use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\Security\CSP\ContentSecurityPolicyManager;
+use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\RedirectResponse;
+use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\JSONResponse;
@@ -39,7 +45,7 @@ use OCP\IRequest;
use OCP\ILogger;
use OCP\AppFramework\Controller;
use OCP\Util;
-
+use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
/**
* Used to do all the authentication and checking stuff for a controller method
@@ -48,15 +54,24 @@ use OCP\Util;
* check fails
*/
class SecurityMiddleware extends Middleware {
-
+ /** @var INavigationManager */
private $navigationManager;
+ /** @var IRequest */
private $request;
+ /** @var ControllerMethodReflector */
private $reflector;
+ /** @var string */
private $appName;
+ /** @var IURLGenerator */
private $urlGenerator;
+ /** @var ILogger */
private $logger;
+ /** @var bool */
private $isLoggedIn;
+ /** @var bool */
private $isAdminUser;
+ /** @var ContentSecurityPolicyManager */
+ private $contentSecurityPolicyManager;
/**
* @param IRequest $request
@@ -67,6 +82,7 @@ class SecurityMiddleware extends Middleware {
* @param string $appName
* @param bool $isLoggedIn
* @param bool $isAdminUser
+ * @param ContentSecurityPolicyManager $contentSecurityPolicyManager
*/
public function __construct(IRequest $request,
ControllerMethodReflector $reflector,
@@ -75,7 +91,8 @@ class SecurityMiddleware extends Middleware {
ILogger $logger,
$appName,
$isLoggedIn,
- $isAdminUser){
+ $isAdminUser,
+ ContentSecurityPolicyManager $contentSecurityPolicyManager) {
$this->navigationManager = $navigationManager;
$this->request = $request;
$this->reflector = $reflector;
@@ -84,6 +101,7 @@ class SecurityMiddleware extends Middleware {
$this->logger = $logger;
$this->isLoggedIn = $isLoggedIn;
$this->isAdminUser = $isAdminUser;
+ $this->contentSecurityPolicyManager = $contentSecurityPolicyManager;
}
@@ -95,7 +113,7 @@ class SecurityMiddleware extends Middleware {
* @param string $methodName the name of the method
* @throws SecurityException when a security check fails
*/
- public function beforeController($controller, $methodName){
+ public function beforeController($controller, $methodName) {
// this will set the current navigation entry of the app, use this only
// for normal HTML requests and not for AJAX requests
@@ -105,12 +123,12 @@ class SecurityMiddleware extends Middleware {
$isPublicPage = $this->reflector->hasAnnotation('PublicPage');
if(!$isPublicPage) {
if(!$this->isLoggedIn) {
- throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED);
+ throw new NotLoggedInException();
}
if(!$this->reflector->hasAnnotation('NoAdminRequired')) {
if(!$this->isAdminUser) {
- throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN);
+ throw new NotAdminException();
}
}
}
@@ -119,22 +137,41 @@ class SecurityMiddleware extends Middleware {
Util::callRegister();
if(!$this->reflector->hasAnnotation('NoCSRFRequired')) {
if(!$this->request->passesCSRFCheck()) {
- throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED);
+ throw new CrossSiteRequestForgeryException();
}
}
/**
* FIXME: Use DI once available
- * Checks if app is enabled (also inclues a check whether user is allowed to access the resource)
+ * Checks if app is enabled (also includes a check whether user is allowed to access the resource)
* The getAppPath() check is here since components such as settings also use the AppFramework and
* therefore won't pass this check.
*/
if(\OC_App::getAppPath($this->appName) !== false && !\OC_App::isEnabled($this->appName)) {
- throw new SecurityException('App is not enabled', Http::STATUS_PRECONDITION_FAILED);
+ throw new AppNotEnabledException();
}
}
+ /**
+ * Performs the default CSP modifications that may be injected by other
+ * applications
+ *
+ * @param Controller $controller
+ * @param string $methodName
+ * @param Response $response
+ * @return Response
+ */
+ public function afterController($controller, $methodName, Response $response) {
+ $policy = !is_null($response->getContentSecurityPolicy()) ? $response->getContentSecurityPolicy() : new ContentSecurityPolicy();
+
+ $defaultPolicy = $this->contentSecurityPolicyManager->getDefaultPolicy();
+ $defaultPolicy = $this->contentSecurityPolicyManager->mergePolicies($defaultPolicy, $policy);
+
+ $response->setContentSecurityPolicy($defaultPolicy);
+
+ return $response;
+ }
/**
* If an SecurityException is being caught, ajax requests return a JSON error
@@ -146,28 +183,28 @@ class SecurityMiddleware extends Middleware {
* @throws \Exception the passed in exception if it cant handle it
* @return Response a Response object or null in case that the exception could not be handled
*/
- public function afterException($controller, $methodName, \Exception $exception){
- if($exception instanceof SecurityException){
-
- if (stripos($this->request->getHeader('Accept'),'html')===false) {
+ public function afterException($controller, $methodName, \Exception $exception) {
+ if($exception instanceof SecurityException) {
+ if (stripos($this->request->getHeader('Accept'),'html') === false) {
$response = new JSONResponse(
array('message' => $exception->getMessage()),
$exception->getCode()
);
- $this->logger->debug($exception->getMessage());
} else {
-
- // TODO: replace with link to route
- $url = $this->urlGenerator->getAbsoluteURL('index.php');
- // add redirect URL to redirect to the previous page after login
- $url .= '?redirect_url=' . urlencode($this->request->server['REQUEST_URI']);
- $response = new RedirectResponse($url);
- $this->logger->debug($exception->getMessage());
+ if($exception instanceof NotLoggedInException) {
+ // TODO: replace with link to route
+ $url = $this->urlGenerator->getAbsoluteURL('index.php');
+ $url .= '?redirect_url=' . urlencode($this->request->server['REQUEST_URI']);
+ $response = new RedirectResponse($url);
+ } else {
+ $response = new TemplateResponse('core', '403', ['file' => $exception->getMessage()], 'guest');
+ $response->setStatus($exception->getCode());
+ }
}
+ $this->logger->debug($exception->getMessage());
return $response;
-
}
throw $exception;
diff --git a/lib/private/appframework/middleware/sessionmiddleware.php b/lib/private/appframework/middleware/sessionmiddleware.php
index 64f0b5e5c51..b218b48ea11 100644
--- a/lib/private/appframework/middleware/sessionmiddleware.php
+++ b/lib/private/appframework/middleware/sessionmiddleware.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/appframework/routing/routeactionhandler.php b/lib/private/appframework/routing/routeactionhandler.php
index 1dfa9425814..b282fc1b452 100644
--- a/lib/private/appframework/routing/routeactionhandler.php
+++ b/lib/private/appframework/routing/routeactionhandler.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/appframework/routing/routeconfig.php b/lib/private/appframework/routing/routeconfig.php
index 7cef3f700b4..dd029ba9a00 100644
--- a/lib/private/appframework/routing/routeconfig.php
+++ b/lib/private/appframework/routing/routeconfig.php
@@ -4,10 +4,10 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Patrick Paysant <ppaysant@linagora.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/appframework/utility/controllermethodreflector.php b/lib/private/appframework/utility/controllermethodreflector.php
index 63cf5ac24f0..de83749fbaf 100644
--- a/lib/private/appframework/utility/controllermethodreflector.php
+++ b/lib/private/appframework/utility/controllermethodreflector.php
@@ -3,11 +3,10 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -60,16 +59,18 @@ class ControllerMethodReflector implements IControllerMethodReflector{
// extract type parameter information
preg_match_all('/@param\h+(?P<type>\w+)\h+\$(?P<var>\w+)/', $docs, $matches);
- // this is just a fix for PHP 5.3 (array_combine raises warning if called with
- // two empty arrays
- if($matches['var'] === array() && $matches['type'] === array()) {
- $this->types = array();
- } else {
- $this->types = array_combine($matches['var'], $matches['type']);
- }
+ $this->types = array_combine($matches['var'], $matches['type']);
- // get method parameters
foreach ($reflection->getParameters() as $param) {
+ // extract type information from PHP 7 scalar types and prefer them
+ // over phpdoc annotations
+ if (method_exists($param, 'getType')) {
+ $type = $param->getType();
+ if ($type !== null) {
+ $this->types[$param->getName()] = (string) $type;
+ }
+ }
+
if($param->isOptional()) {
$default = $param->getDefaultValue();
} else {
@@ -82,9 +83,9 @@ class ControllerMethodReflector implements IControllerMethodReflector{
/**
* Inspects the PHPDoc parameters for types
- * @param string $parameter the parameter whose type comments should be
+ * @param string $parameter the parameter whose type comments should be
* parsed
- * @return string|null type in the type parameters (@param int $something)
+ * @return string|null type in the type parameters (@param int $something)
* would return int or null if not existing
*/
public function getType($parameter) {
diff --git a/lib/private/appframework/utility/simplecontainer.php b/lib/private/appframework/utility/simplecontainer.php
index bcae351e023..78ded39735e 100644
--- a/lib/private/appframework/utility/simplecontainer.php
+++ b/lib/private/appframework/utility/simplecontainer.php
@@ -4,10 +4,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,9 +29,7 @@ namespace OC\AppFramework\Utility;
use ReflectionClass;
use ReflectionException;
use Closure;
-
use Pimple\Container;
-
use OCP\AppFramework\QueryException;
use OCP\IContainer;
diff --git a/lib/private/appframework/utility/timefactory.php b/lib/private/appframework/utility/timefactory.php
index 011413db6bb..5241b367069 100644
--- a/lib/private/appframework/utility/timefactory.php
+++ b/lib/private/appframework/utility/timefactory.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/apphelper.php b/lib/private/apphelper.php
index 9084d2b8ab4..c19ed2f5b67 100644
--- a/lib/private/apphelper.php
+++ b/lib/private/apphelper.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -36,6 +36,12 @@ class AppHelper implements \OCP\IHelper {
* @deprecated 8.1.0 Use \OCP\IServerContainer::getHTTPClientService
*/
public function getUrlContent($url) {
- return \OC_Util::getUrlContent($url);
+ try {
+ $client = \OC::$server->getHTTPClientService()->newClient();
+ $response = $client->get($url);
+ return $response->getBody();
+ } catch (\Exception $e) {
+ return false;
+ }
}
}
diff --git a/lib/private/archive.php b/lib/private/archive.php
index 54c5a71f715..62512d1448a 100644
--- a/lib/private/archive.php
+++ b/lib/private/archive.php
@@ -8,11 +8,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Remco Brenninkmeijer <requist1@starmail.nl>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/archive/tar.php b/lib/private/archive/tar.php
index 4448e56850d..905d99f116b 100644
--- a/lib/private/archive/tar.php
+++ b/lib/private/archive/tar.php
@@ -1,6 +1,7 @@
<?php
/**
* @author Bart Visscher <bartv@thisnet.nl>
+ * @author Christian Weiske <cweiske@cweiske.de>
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Felix Moeller <mail@felixmoeller.de>
* @author Frank Karlitschek <frank@owncloud.org>
@@ -9,11 +10,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Remco Brenninkmeijer <requist1@starmail.nl>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -86,7 +87,7 @@ class OC_Archive_TAR extends OC_Archive {
* @return bool
*/
function addFolder($path) {
- $tmpBase = OC_Helper::tmpFolder();
+ $tmpBase = \OC::$server->getTempManager()->getTemporaryFolder();
if (substr($path, -1, 1) != '/') {
$path .= '/';
}
diff --git a/lib/private/archive/zip.php b/lib/private/archive/zip.php
index 430dccc49b7..2c617a8e633 100644
--- a/lib/private/archive/zip.php
+++ b/lib/private/archive/zip.php
@@ -11,7 +11,7 @@
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/avatar.php b/lib/private/avatar.php
index baaccaa86e6..ef7d99fd292 100644
--- a/lib/private/avatar.php
+++ b/lib/private/avatar.php
@@ -6,11 +6,11 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,46 +29,52 @@
namespace OC;
-use OC\Files\Filesystem;
+use OC\User\User;
+use OCP\Files\Folder;
+use OCP\Files\File;
+use OCP\Files\NotFoundException;
+use OCP\IAvatar;
+use OCP\IImage;
+use OCP\IL10N;
use OC_Image;
/**
* This class gets and sets users avatars.
*/
-class Avatar implements \OCP\IAvatar {
- /** @var Files\View */
- private $view;
+class Avatar implements IAvatar {
+ /** @var Folder */
+ private $folder;
+ /** @var IL10N */
+ private $l;
+ /** @var User */
+ private $user;
/**
* constructor
- * @param string $user user to do avatar-management with
- * @throws \Exception In case the username is potentially dangerous
+ *
+ * @param Folder $folder The folder where the avatars are
+ * @param IL10N $l
+ * @param User $user
*/
- public function __construct ($user) {
- if(!Filesystem::isValidPath($user)) {
- throw new \Exception('Username may not contain slashes');
- }
- $this->view = new \OC\Files\View('/'.$user);
+ public function __construct (Folder $folder, IL10N $l, $user) {
+ $this->folder = $folder;
+ $this->l = $l;
+ $this->user = $user;
}
/**
- * get the users avatar
- * @param int $size size in px of the avatar, avatars are square, defaults to 64
- * @return boolean|\OCP\IImage containing the avatar or false if there's no image
- */
+ * @inheritdoc
+ */
public function get ($size = 64) {
- if ($this->view->file_exists('avatar.jpg')) {
- $ext = 'jpg';
- } elseif ($this->view->file_exists('avatar.png')) {
- $ext = 'png';
- } else {
+ try {
+ $file = $this->getFile($size);
+ } catch (NotFoundException $e) {
return false;
}
$avatar = new OC_Image();
- $avatar->loadFromData($this->view->file_get_contents('avatar.'.$ext));
- $avatar->resize($size);
+ $avatar->loadFromData($file->getContent());
return $avatar;
}
@@ -78,20 +84,20 @@ class Avatar implements \OCP\IAvatar {
* @return bool
*/
public function exists() {
- return $this->view->file_exists('avatar.jpg') || $this->view->file_exists('avatar.png');
+ return $this->folder->nodeExists('avatar.jpg') || $this->folder->nodeExists('avatar.png');
}
/**
* sets the users avatar
- * @param \OCP\IImage|resource|string $data An image object, imagedata or path to set a new avatar
+ * @param IImage|resource|string $data An image object, imagedata or path to set a new avatar
* @throws \Exception if the provided file is not a jpg or png image
* @throws \Exception if the provided image is not valid
- * @throws \OC\NotSquareException if the image is not square
+ * @throws NotSquareException if the image is not square
* @return void
*/
public function set ($data) {
- if($data instanceOf \OCP\IImage) {
+ if($data instanceOf IImage) {
$img = $data;
$data = $img->data();
} else {
@@ -102,22 +108,20 @@ class Avatar implements \OCP\IAvatar {
$type = 'jpg';
}
if ($type !== 'jpg' && $type !== 'png') {
- $l = \OC::$server->getL10N('lib');
- throw new \Exception($l->t("Unknown filetype"));
+ throw new \Exception($this->l->t("Unknown filetype"));
}
if (!$img->valid()) {
- $l = \OC::$server->getL10N('lib');
- throw new \Exception($l->t("Invalid image"));
+ throw new \Exception($this->l->t("Invalid image"));
}
if (!($img->height() === $img->width())) {
- throw new \OC\NotSquareException();
+ throw new NotSquareException();
}
- $this->view->unlink('avatar.jpg');
- $this->view->unlink('avatar.png');
- $this->view->file_put_contents('avatar.'.$type, $data);
+ $this->remove();
+ $this->folder->newFile('avatar.'.$type)->putContent($data);
+ $this->user->triggerChange();
}
/**
@@ -125,7 +129,62 @@ class Avatar implements \OCP\IAvatar {
* @return void
*/
public function remove () {
- $this->view->unlink('avatar.jpg');
- $this->view->unlink('avatar.png');
+ $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/';
+ $avatars = $this->folder->search('avatar');
+
+ foreach ($avatars as $avatar) {
+ if (preg_match($regex, $avatar->getName())) {
+ $avatar->delete();
+ }
+ }
+ $this->user->triggerChange();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getFile($size) {
+ $ext = $this->getExtension();
+
+ if ($size === -1) {
+ $path = 'avatar.' . $ext;
+ } else {
+ $path = 'avatar.' . $size . '.' . $ext;
+ }
+
+ try {
+ $file = $this->folder->get($path);
+ } catch (NotFoundException $e) {
+ if ($size <= 0) {
+ throw new NotFoundException;
+ }
+
+ $avatar = new OC_Image();
+ /** @var File $file */
+ $file = $this->folder->get('avatar.' . $ext);
+ $avatar->loadFromData($file->getContent());
+ if ($size !== -1) {
+ $avatar->resize($size);
+ }
+ $file = $this->folder->newFile($path);
+ $file->putContent($avatar->data());
+ }
+
+ return $file;
+ }
+
+ /**
+ * Get the extension of the avatar. If there is no avatar throw Exception
+ *
+ * @return string
+ * @throws NotFoundException
+ */
+ private function getExtension() {
+ if ($this->folder->nodeExists('avatar.jpg')) {
+ return 'jpg';
+ } elseif ($this->folder->nodeExists('avatar.png')) {
+ return 'png';
+ }
+ throw new NotFoundException;
}
}
diff --git a/lib/private/avatarmanager.php b/lib/private/avatarmanager.php
index 143874b6be3..b39f5495122 100644
--- a/lib/private/avatarmanager.php
+++ b/lib/private/avatarmanager.php
@@ -4,10 +4,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,13 +27,33 @@
namespace OC;
use OCP\IAvatarManager;
-use OC\Avatar;
+use OCP\IUserManager;
+use OCP\Files\IRootFolder;
+use OCP\IL10N;
/**
* This class implements methods to access Avatar functionality
*/
class AvatarManager implements IAvatarManager {
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ /** @var IL10N */
+ private $l;
+
+ public function __construct(
+ IUserManager $userManager,
+ IRootFolder $rootFolder,
+ IL10N $l) {
+ $this->userManager = $userManager;
+ $this->rootFolder = $rootFolder;
+ $this->l = $l;
+ }
+
/**
* return a user specific instance of \OCP\IAvatar
* @see \OCP\IAvatar
@@ -41,7 +61,11 @@ class AvatarManager implements IAvatarManager {
* @return \OCP\IAvatar
* @throws \Exception In case the username is potentially dangerous
*/
- public function getAvatar($user) {
- return new Avatar($user);
+ public function getAvatar($userId) {
+ $user = $this->userManager->get($userId);
+ if (is_null($user)) {
+ throw new \Exception('user does not exist');
+ }
+ return new Avatar($this->rootFolder->getUserFolder($userId)->getParent(), $this->l, $user);
}
}
diff --git a/lib/private/backgroundjob/job.php b/lib/private/backgroundjob/job.php
index 88682cd09bb..e7268894848 100644
--- a/lib/private/backgroundjob/job.php
+++ b/lib/private/backgroundjob/job.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -52,9 +52,11 @@ abstract class Job implements IJob {
$this->run($this->argument);
} catch (\Exception $e) {
if ($logger) {
- $logger->error('Error while running background job: ' . $e->getMessage());
+ $logger->logException($e, [
+ 'app' => 'core',
+ 'message' => 'Error while running background job (class: ' . get_class($this) . ', arguments: ' . print_r($this->argument, true) . ')'
+ ]);
}
- $jobList->remove($this, $this->argument);
}
}
diff --git a/lib/private/backgroundjob/joblist.php b/lib/private/backgroundjob/joblist.php
index 03c9180ddb0..2920cb5214c 100644
--- a/lib/private/backgroundjob/joblist.php
+++ b/lib/private/backgroundjob/joblist.php
@@ -1,11 +1,11 @@
<?php
/**
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,134 +24,182 @@
namespace OC\BackgroundJob;
+use OCP\AppFramework\QueryException;
+use OCP\BackgroundJob\IJob;
use OCP\BackgroundJob\IJobList;
use OCP\AutoloadNotAllowedException;
class JobList implements IJobList {
- /**
- * @var \OCP\IDBConnection
- */
- private $conn;
+ /** @var \OCP\IDBConnection */
+ protected $connection;
/**
* @var \OCP\IConfig $config
*/
- private $config;
+ protected $config;
/**
- * @param \OCP\IDBConnection $conn
+ * @param \OCP\IDBConnection $connection
* @param \OCP\IConfig $config
*/
- public function __construct($conn, $config) {
- $this->conn = $conn;
+ public function __construct($connection, $config) {
+ $this->connection = $connection;
$this->config = $config;
}
/**
- * @param Job|string $job
+ * @param IJob|string $job
* @param mixed $argument
*/
public function add($job, $argument = null) {
if (!$this->has($job, $argument)) {
- if ($job instanceof Job) {
+ if ($job instanceof IJob) {
$class = get_class($job);
} else {
$class = $job;
}
+
$argument = json_encode($argument);
if (strlen($argument) > 4000) {
throw new \InvalidArgumentException('Background job arguments can\'t exceed 4000 characters (json encoded)');
}
- $query = $this->conn->prepare('INSERT INTO `*PREFIX*jobs`(`class`, `argument`, `last_run`) VALUES(?, ?, 0)');
- $query->execute(array($class, $argument));
+
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('jobs')
+ ->values([
+ 'class' => $query->createNamedParameter($class),
+ 'argument' => $query->createNamedParameter($argument),
+ 'last_run' => $query->createNamedParameter(0, \PDO::PARAM_INT),
+ ]);
+ $query->execute();
}
}
/**
- * @param Job|string $job
+ * @param IJob|string $job
* @param mixed $argument
*/
public function remove($job, $argument = null) {
- if ($job instanceof Job) {
+ if ($job instanceof IJob) {
$class = get_class($job);
} else {
$class = $job;
}
+
+ $query = $this->connection->getQueryBuilder();
+ $query->delete('jobs')
+ ->where($query->expr()->eq('class', $query->createNamedParameter($class)));
if (!is_null($argument)) {
$argument = json_encode($argument);
- $query = $this->conn->prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?');
- $query->execute(array($class, $argument));
- } else {
- $query = $this->conn->prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ?');
- $query->execute(array($class));
+ $query->andWhere($query->expr()->eq('argument', $query->createNamedParameter($argument)));
}
+ $query->execute();
}
+ /**
+ * @param int $id
+ */
protected function removeById($id) {
- $query = $this->conn->prepare('DELETE FROM `*PREFIX*jobs` WHERE `id` = ?');
- $query->execute([$id]);
+ $query = $this->connection->getQueryBuilder();
+ $query->delete('jobs')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($id, \PDO::PARAM_INT)));
+ $query->execute();
}
/**
* check if a job is in the list
*
- * @param Job|string $job
+ * @param IJob|string $job
* @param mixed $argument
* @return bool
*/
public function has($job, $argument) {
- if ($job instanceof Job) {
+ if ($job instanceof IJob) {
$class = get_class($job);
} else {
$class = $job;
}
$argument = json_encode($argument);
- $query = $this->conn->prepare('SELECT `id` FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?');
- $query->execute(array($class, $argument));
- return (bool)$query->fetch();
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select('id')
+ ->from('jobs')
+ ->where($query->expr()->eq('class', $query->createNamedParameter($class)))
+ ->andWhere($query->expr()->eq('argument', $query->createNamedParameter($argument)))
+ ->setMaxResults(1);
+
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ return (bool) $row;
}
/**
* get all jobs in the list
*
- * @return Job[]
+ * @return IJob[]
+ * @deprecated 9.0.0 - This method is dangerous since it can cause load and
+ * memory problems when creating too many instances.
*/
public function getAll() {
- $query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs`');
- $query->execute();
- $jobs = array();
- while ($row = $query->fetch()) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from('jobs');
+ $result = $query->execute();
+
+ $jobs = [];
+ while ($row = $result->fetch()) {
$job = $this->buildJob($row);
if ($job) {
$jobs[] = $job;
}
}
+ $result->closeCursor();
+
return $jobs;
}
/**
* get the next job in the list
*
- * @return Job
+ * @return IJob|null
*/
public function getNext() {
$lastId = $this->getLastJob();
- $query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` > ? ORDER BY `id` ASC', 1);
- $query->execute(array($lastId));
- if ($row = $query->fetch()) {
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from('jobs')
+ ->where($query->expr()->gt('id', $query->createNamedParameter($lastId, \PDO::PARAM_INT)))
+ ->orderBy('id', 'ASC')
+ ->setMaxResults(1);
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
$jobId = $row['id'];
$job = $this->buildJob($row);
} else {
//begin at the start of the queue
- $query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` ORDER BY `id` ASC', 1);
- $query->execute();
- if ($row = $query->fetch()) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from('jobs')
+ ->orderBy('id', 'ASC')
+ ->setMaxResults(1);
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
$jobId = $row['id'];
$job = $this->buildJob($row);
} else {
return null; //empty job list
}
}
+
if (is_null($job)) {
$this->removeById($jobId);
return $this->getNext();
@@ -162,12 +210,18 @@ class JobList implements IJobList {
/**
* @param int $id
- * @return Job|null
+ * @return IJob|null
*/
public function getById($id) {
- $query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` = ?');
- $query->execute(array($id));
- if ($row = $query->fetch()) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from('jobs')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($id, \PDO::PARAM_INT)));
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
return $this->buildJob($row);
} else {
return null;
@@ -178,33 +232,38 @@ class JobList implements IJobList {
* get the job object from a row in the db
*
* @param array $row
- * @return Job
+ * @return IJob|null
*/
private function buildJob($row) {
- $class = $row['class'];
- /**
- * @var Job $job
- */
try {
- if (!class_exists($class)) {
- // job from disabled app or old version of an app, no need to do anything
- return null;
+ try {
+ // Try to load the job as a service
+ /** @var IJob $job */
+ $job = \OC::$server->query($row['class']);
+ } catch (QueryException $e) {
+ if (class_exists($row['class'])) {
+ $class = $row['class'];
+ $job = new $class();
+ } else {
+ // job from disabled app or old version of an app, no need to do anything
+ return null;
+ }
}
- $job = new $class();
+
$job->setId($row['id']);
$job->setLastRun($row['last_run']);
$job->setArgument(json_decode($row['argument'], true));
return $job;
} catch (AutoloadNotAllowedException $e) {
// job is from a disabled app, ignore
+ return null;
}
- return null;
}
/**
* set the job that was last ran
*
- * @param Job $job
+ * @param IJob $job
*/
public function setLastJob($job) {
$this->config->setAppValue('backgroundjob', 'lastjob', $job->getId());
@@ -213,19 +272,22 @@ class JobList implements IJobList {
/**
* get the id of the last ran job
*
- * @return string
+ * @return int
*/
public function getLastJob() {
- return $this->config->getAppValue('backgroundjob', 'lastjob', 0);
+ return (int) $this->config->getAppValue('backgroundjob', 'lastjob', 0);
}
/**
* set the lastRun of $job to now
*
- * @param Job $job
+ * @param IJob $job
*/
public function setLastRun($job) {
- $query = $this->conn->prepare('UPDATE `*PREFIX*jobs` SET `last_run` = ? WHERE `id` = ?');
- $query->execute(array(time(), $job->getId()));
+ $query = $this->connection->getQueryBuilder();
+ $query->update('jobs')
+ ->set('last_run', $query->createNamedParameter(time(), \PDO::PARAM_INT))
+ ->where($query->expr()->eq('id', $query->createNamedParameter($job->getId(), \PDO::PARAM_INT)));
+ $query->execute();
}
}
diff --git a/lib/private/backgroundjob/legacy/queuedjob.php b/lib/private/backgroundjob/legacy/queuedjob.php
index e9d5825ca9a..983c06fe551 100644
--- a/lib/private/backgroundjob/legacy/queuedjob.php
+++ b/lib/private/backgroundjob/legacy/queuedjob.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/backgroundjob/legacy/regularjob.php b/lib/private/backgroundjob/legacy/regularjob.php
index 49a777a1e27..8e8b6634c11 100644
--- a/lib/private/backgroundjob/legacy/regularjob.php
+++ b/lib/private/backgroundjob/legacy/regularjob.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/backgroundjob/queuedjob.php b/lib/private/backgroundjob/queuedjob.php
index c4cf8b0e5e0..bf34db7cc02 100644
--- a/lib/private/backgroundjob/queuedjob.php
+++ b/lib/private/backgroundjob/queuedjob.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/backgroundjob/timedjob.php b/lib/private/backgroundjob/timedjob.php
index 63db1fed61c..abf487a89e1 100644
--- a/lib/private/backgroundjob/timedjob.php
+++ b/lib/private/backgroundjob/timedjob.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/cache/cappedmemorycache.php b/lib/private/cache/cappedmemorycache.php
new file mode 100644
index 00000000000..e3efbf76a23
--- /dev/null
+++ b/lib/private/cache/cappedmemorycache.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Cache;
+
+use OCP\ICache;
+
+/**
+ * In-memory cache with a capacity limit to keep memory usage in check
+ *
+ * Uses a simple FIFO expiry mechanism
+ */
+class CappedMemoryCache implements ICache, \ArrayAccess {
+
+ private $capacity;
+ private $cache = [];
+
+ public function __construct($capacity = 512) {
+ $this->capacity = $capacity;
+ }
+
+ public function hasKey($key) {
+ return isset($this->cache[$key]);
+ }
+
+ public function get($key) {
+ return isset($this->cache[$key]) ? $this->cache[$key] : null;
+ }
+
+ public function set($key, $value, $ttl = 0) {
+ $this->cache[$key] = $value;
+ $this->garbageCollect();
+ }
+
+ public function remove($key) {
+ unset($this->cache[$key]);
+ return true;
+ }
+
+ public function clear($prefix = '') {
+ $this->cache = [];
+ return true;
+ }
+
+ public function offsetExists($offset) {
+ return $this->hasKey($offset);
+ }
+
+ public function &offsetGet($offset) {
+ return $this->cache[$offset];
+ }
+
+ public function offsetSet($offset, $value) {
+ $this->set($offset, $value);
+ }
+
+ public function offsetUnset($offset) {
+ $this->remove($offset);
+ }
+
+
+ private function garbageCollect() {
+ while (count($this->cache) > $this->capacity) {
+ reset($this->cache);
+ $key = key($this->cache);
+ $this->remove($key);
+ }
+ }
+}
diff --git a/lib/private/cache/file.php b/lib/private/cache/file.php
index 1cda05f28e5..989e05275b7 100644
--- a/lib/private/cache/file.php
+++ b/lib/private/cache/file.php
@@ -1,10 +1,12 @@
<?php
/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -99,7 +101,7 @@ class File implements ICache {
$storage = $this->getStorage();
$result = false;
// unique id to avoid chunk collision, just in case
- $uniqueId = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(
+ $uniqueId = \OC::$server->getSecureRandom()->generate(
16,
ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER
);
@@ -185,6 +187,8 @@ class File implements ICache {
} catch (\OCP\Lock\LockedException $e) {
// ignore locked chunks
\OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core'));
+ } catch (\OCP\Files\ForbiddenException $e) {
+ \OC::$server->getLogger()->debug('Could not cleanup forbidden chunk "' . $file . '"', array('app' => 'core'));
} catch (\OCP\Files\LockNotAcquiredException $e) {
\OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core'));
}
diff --git a/lib/private/capabilitiesmanager.php b/lib/private/capabilitiesmanager.php
index c36a96af68b..8b89692faa9 100644
--- a/lib/private/capabilitiesmanager.php
+++ b/lib/private/capabilitiesmanager.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/command/asyncbus.php b/lib/private/command/asyncbus.php
index c007affc7f4..eb692f9a8fb 100644
--- a/lib/private/command/asyncbus.php
+++ b/lib/private/command/asyncbus.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/command/callablejob.php b/lib/private/command/callablejob.php
index b61721863f0..acfeb83d606 100644
--- a/lib/private/command/callablejob.php
+++ b/lib/private/command/callablejob.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/command/closurejob.php b/lib/private/command/closurejob.php
index bae98db51cf..be2b5f0a4ba 100644
--- a/lib/private/command/closurejob.php
+++ b/lib/private/command/closurejob.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/command/commandjob.php b/lib/private/command/commandjob.php
index 9f0292fc38b..5d613c0305b 100644
--- a/lib/private/command/commandjob.php
+++ b/lib/private/command/commandjob.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/command/fileaccess.php b/lib/private/command/fileaccess.php
index b4af557153e..6fe3e111aef 100644
--- a/lib/private/command/fileaccess.php
+++ b/lib/private/command/fileaccess.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/command/queuebus.php b/lib/private/command/queuebus.php
index 76caf76a575..be4ee589e6f 100644
--- a/lib/private/command/queuebus.php
+++ b/lib/private/command/queuebus.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/comments/comment.php b/lib/private/comments/comment.php
new file mode 100644
index 00000000000..36189d9523b
--- /dev/null
+++ b/lib/private/comments/comment.php
@@ -0,0 +1,375 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Comments;
+
+use OCP\Comments\IComment;
+use OCP\Comments\IllegalIDChangeException;
+
+class Comment implements IComment {
+
+ protected $data = [
+ 'id' => '',
+ 'parentId' => '0',
+ 'topmostParentId' => '0',
+ 'childrenCount' => '0',
+ 'message' => '',
+ 'verb' => '',
+ 'actorType' => '',
+ 'actorId' => '',
+ 'objectType' => '',
+ 'objectId' => '',
+ 'creationDT' => null,
+ 'latestChildDT' => null,
+ ];
+
+ /**
+ * Comment constructor.
+ *
+ * @param [] $data optional, array with keys according to column names from
+ * the comments database scheme
+ */
+ public function __construct(array $data = null) {
+ if(is_array($data)) {
+ $this->fromArray($data);
+ }
+ }
+
+ /**
+ * returns the ID of the comment
+ *
+ * It may return an empty string, if the comment was not stored.
+ * It is expected that the concrete Comment implementation gives an ID
+ * by itself (e.g. after saving).
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getId() {
+ return $this->data['id'];
+ }
+
+ /**
+ * sets the ID of the comment and returns itself
+ *
+ * It is only allowed to set the ID only, if the current id is an empty
+ * string (which means it is not stored in a database, storage or whatever
+ * the concrete implementation does), or vice versa. Changing a given ID is
+ * not permitted and must result in an IllegalIDChangeException.
+ *
+ * @param string $id
+ * @return IComment
+ * @throws IllegalIDChangeException
+ * @since 9.0.0
+ */
+ public function setId($id) {
+ if(!is_string($id)) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+
+ $id = trim($id);
+ if($this->data['id'] === '' || ($this->data['id'] !== '' && $id === '')) {
+ $this->data['id'] = $id;
+ return $this;
+ }
+
+ throw new IllegalIDChangeException('Not allowed to assign a new ID to an already saved comment.');
+ }
+
+ /**
+ * returns the parent ID of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getParentId() {
+ return $this->data['parentId'];
+ }
+
+ /**
+ * sets the parent ID and returns itself
+ *
+ * @param string $parentId
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setParentId($parentId) {
+ if(!is_string($parentId)) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['parentId'] = trim($parentId);
+ return $this;
+ }
+
+ /**
+ * returns the topmost parent ID of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getTopmostParentId() {
+ return $this->data['topmostParentId'];
+ }
+
+
+ /**
+ * sets the topmost parent ID and returns itself
+ *
+ * @param string $id
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setTopmostParentId($id) {
+ if(!is_string($id)) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['topmostParentId'] = trim($id);
+ return $this;
+ }
+
+ /**
+ * returns the number of children
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getChildrenCount() {
+ return $this->data['childrenCount'];
+ }
+
+ /**
+ * sets the number of children
+ *
+ * @param int $count
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setChildrenCount($count) {
+ if(!is_int($count)) {
+ throw new \InvalidArgumentException('Integer expected.');
+ }
+ $this->data['childrenCount'] = $count;
+ return $this;
+ }
+
+ /**
+ * returns the message of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getMessage() {
+ return $this->data['message'];
+ }
+
+ /**
+ * sets the message of the comment and returns itself
+ *
+ * @param string $message
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setMessage($message) {
+ if(!is_string($message)) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['message'] = trim($message);
+ return $this;
+ }
+
+ /**
+ * returns the verb of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getVerb() {
+ return $this->data['verb'];
+ }
+
+ /**
+ * sets the verb of the comment, e.g. 'comment' or 'like'
+ *
+ * @param string $verb
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setVerb($verb) {
+ if(!is_string($verb) || !trim($verb)) {
+ throw new \InvalidArgumentException('Non-empty String expected.');
+ }
+ $this->data['verb'] = trim($verb);
+ return $this;
+ }
+
+ /**
+ * returns the actor type
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getActorType() {
+ return $this->data['actorType'];
+ }
+
+ /**
+ * returns the actor ID
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getActorId() {
+ return $this->data['actorId'];
+ }
+
+ /**
+ * sets (overwrites) the actor type and id
+ *
+ * @param string $actorType e.g. 'users'
+ * @param string $actorId e.g. 'zombie234'
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setActor($actorType, $actorId) {
+ if(
+ !is_string($actorType) || !trim($actorType)
+ || !is_string($actorId) || !trim($actorId)
+ ) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['actorType'] = trim($actorType);
+ $this->data['actorId'] = trim($actorId);
+ return $this;
+ }
+
+ /**
+ * returns the creation date of the comment.
+ *
+ * If not explicitly set, it shall default to the time of initialization.
+ *
+ * @return \DateTime
+ * @since 9.0.0
+ */
+ public function getCreationDateTime() {
+ return $this->data['creationDT'];
+ }
+
+ /**
+ * sets the creation date of the comment and returns itself
+ *
+ * @param \DateTime $timestamp
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setCreationDateTime(\DateTime $timestamp) {
+ $this->data['creationDT'] = $timestamp;
+ return $this;
+ }
+
+ /**
+ * returns the DateTime of the most recent child, if set, otherwise null
+ *
+ * @return \DateTime|null
+ * @since 9.0.0
+ */
+ public function getLatestChildDateTime() {
+ return $this->data['latestChildDT'];
+ }
+
+ /**
+ * sets the date of the most recent child
+ *
+ * @param \DateTime $dateTime
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setLatestChildDateTime(\DateTime $dateTime = null) {
+ $this->data['latestChildDT'] = $dateTime;
+ return $this;
+ }
+
+ /**
+ * returns the object type the comment is attached to
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getObjectType() {
+ return $this->data['objectType'];
+ }
+
+ /**
+ * returns the object id the comment is attached to
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getObjectId() {
+ return $this->data['objectId'];
+ }
+
+ /**
+ * sets (overwrites) the object of the comment
+ *
+ * @param string $objectType e.g. 'files'
+ * @param string $objectId e.g. '16435'
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setObject($objectType, $objectId) {
+ if(
+ !is_string($objectType) || !trim($objectType)
+ || !is_string($objectId) || !trim($objectId)
+ ) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['objectType'] = trim($objectType);
+ $this->data['objectId'] = trim($objectId);
+ return $this;
+ }
+
+ /**
+ * sets the comment data based on an array with keys as taken from the
+ * database.
+ *
+ * @param [] $data
+ * @return IComment
+ */
+ protected function fromArray($data) {
+ foreach(array_keys($data) as $key) {
+ // translate DB keys to internal setter names
+ $setter = 'set' . str_replace('_', '', ucwords($key,'_'));
+ $setter = str_replace('Timestamp', 'DateTime', $setter);
+
+ if(method_exists($this, $setter)) {
+ $this->$setter($data[$key]);
+ }
+ }
+
+ foreach(['actor', 'object'] as $role) {
+ if(isset($data[$role . '_type']) && isset($data[$role . '_id'])) {
+ $setter = 'set' . ucfirst($role);
+ $this->$setter($data[$role . '_type'], $data[$role . '_id']);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/lib/private/comments/manager.php b/lib/private/comments/manager.php
new file mode 100644
index 00000000000..0cacc1cce71
--- /dev/null
+++ b/lib/private/comments/manager.php
@@ -0,0 +1,710 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Comments;
+
+use Doctrine\DBAL\Exception\DriverException;
+use OCP\Comments\IComment;
+use OCP\Comments\ICommentsManager;
+use OCP\Comments\NotFoundException;
+use OCP\IDBConnection;
+use OCP\IConfig;
+use OCP\ILogger;
+use OCP\IUser;
+
+class Manager implements ICommentsManager {
+
+ /** @var IDBConnection */
+ protected $dbConn;
+
+ /** @var ILogger */
+ protected $logger;
+
+ /** @var IComment[] */
+ protected $commentsCache = [];
+
+ /** @var IConfig */
+ protected $config;
+
+ public function __construct(
+ IDBConnection $dbConn,
+ ILogger $logger,
+ IConfig $config
+ ) {
+ $this->dbConn = $dbConn;
+ $this->logger = $logger;
+ $this->config = $config;
+ }
+
+ /**
+ * converts data base data into PHP native, proper types as defined by
+ * IComment interface.
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function normalizeDatabaseData(array $data) {
+ $data['id'] = strval($data['id']);
+ $data['parent_id'] = strval($data['parent_id']);
+ $data['topmost_parent_id'] = strval($data['topmost_parent_id']);
+ $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']);
+ if (!is_null($data['latest_child_timestamp'])) {
+ $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']);
+ }
+ $data['children_count'] = intval($data['children_count']);
+ return $data;
+ }
+
+ /**
+ * prepares a comment for an insert or update operation after making sure
+ * all necessary fields have a value assigned.
+ *
+ * @param IComment $comment
+ * @return IComment returns the same updated IComment instance as provided
+ * by parameter for convenience
+ * @throws \UnexpectedValueException
+ */
+ protected function prepareCommentForDatabaseWrite(IComment $comment) {
+ if( !$comment->getActorType()
+ || !$comment->getActorId()
+ || !$comment->getObjectType()
+ || !$comment->getObjectId()
+ || !$comment->getVerb()
+ ) {
+ throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving');
+ }
+
+ if($comment->getId() === '') {
+ $comment->setChildrenCount(0);
+ $comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC')));
+ $comment->setLatestChildDateTime(null);
+ }
+
+ if(is_null($comment->getCreationDateTime())) {
+ $comment->setCreationDateTime(new \DateTime());
+ }
+
+ if($comment->getParentId() !== '0') {
+ $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId()));
+ } else {
+ $comment->setTopmostParentId('0');
+ }
+
+ $this->cache($comment);
+
+ return $comment;
+ }
+
+ /**
+ * returns the topmost parent id of a given comment identified by ID
+ *
+ * @param string $id
+ * @return string
+ * @throws NotFoundException
+ */
+ protected function determineTopmostParentId($id) {
+ $comment = $this->get($id);
+ if($comment->getParentId() === '0') {
+ return $comment->getId();
+ } else {
+ return $this->determineTopmostParentId($comment->getId());
+ }
+ }
+
+ /**
+ * updates child information of a comment
+ *
+ * @param string $id
+ * @param \DateTime $cDateTime the date time of the most recent child
+ * @throws NotFoundException
+ */
+ protected function updateChildrenInformation($id, \DateTime $cDateTime) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->select($qb->createFunction('COUNT(`id`)'))
+ ->from('comments')
+ ->where($qb->expr()->eq('parent_id', $qb->createParameter('id')))
+ ->setParameter('id', $id);
+
+ $resultStatement = $query->execute();
+ $data = $resultStatement->fetch(\PDO::FETCH_NUM);
+ $resultStatement->closeCursor();
+ $children = intval($data[0]);
+
+ $comment = $this->get($id);
+ $comment->setChildrenCount($children);
+ $comment->setLatestChildDateTime($cDateTime);
+ $this->save($comment);
+ }
+
+ /**
+ * Tests whether actor or object type and id parameters are acceptable.
+ * Throws exception if not.
+ *
+ * @param string $role
+ * @param string $type
+ * @param string $id
+ * @throws \InvalidArgumentException
+ */
+ protected function checkRoleParameters($role, $type, $id) {
+ if(
+ !is_string($type) || empty($type)
+ || !is_string($id) || empty($id)
+ ) {
+ throw new \InvalidArgumentException($role . ' parameters must be string and not empty');
+ }
+ }
+
+ /**
+ * run-time caches a comment
+ *
+ * @param IComment $comment
+ */
+ protected function cache(IComment $comment) {
+ $id = $comment->getId();
+ if(empty($id)) {
+ return;
+ }
+ $this->commentsCache[strval($id)] = $comment;
+ }
+
+ /**
+ * removes an entry from the comments run time cache
+ *
+ * @param mixed $id the comment's id
+ */
+ protected function uncache($id) {
+ $id = strval($id);
+ if (isset($this->commentsCache[$id])) {
+ unset($this->commentsCache[$id]);
+ }
+ }
+
+ /**
+ * returns a comment instance
+ *
+ * @param string $id the ID of the comment
+ * @return IComment
+ * @throws NotFoundException
+ * @throws \InvalidArgumentException
+ * @since 9.0.0
+ */
+ public function get($id) {
+ if(intval($id) === 0) {
+ throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.');
+ }
+
+ if(isset($this->commentsCache[$id])) {
+ return $this->commentsCache[$id];
+ }
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $resultStatement = $qb->select('*')
+ ->from('comments')
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter('id', $id, \PDO::PARAM_INT)
+ ->execute();
+
+ $data = $resultStatement->fetch();
+ $resultStatement->closeCursor();
+ if(!$data) {
+ throw new NotFoundException();
+ }
+
+ $comment = new Comment($this->normalizeDatabaseData($data));
+ $this->cache($comment);
+ return $comment;
+ }
+
+ /**
+ * returns the comment specified by the id and all it's child comments.
+ * At this point of time, we do only support one level depth.
+ *
+ * @param string $id
+ * @param int $limit max number of entries to return, 0 returns all
+ * @param int $offset the start entry
+ * @return array
+ * @since 9.0.0
+ *
+ * The return array looks like this
+ * [
+ * 'comment' => IComment, // root comment
+ * 'replies' =>
+ * [
+ * 0 =>
+ * [
+ * 'comment' => IComment,
+ * 'replies' => []
+ * ]
+ * 1 =>
+ * [
+ * 'comment' => IComment,
+ * 'replies'=> []
+ * ],
+ * …
+ * ]
+ * ]
+ */
+ public function getTree($id, $limit = 0, $offset = 0) {
+ $tree = [];
+ $tree['comment'] = $this->get($id);
+ $tree['replies'] = [];
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->select('*')
+ ->from('comments')
+ ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id')))
+ ->orderBy('creation_timestamp', 'DESC')
+ ->setParameter('id', $id);
+
+ if($limit > 0) {
+ $query->setMaxResults($limit);
+ }
+ if($offset > 0) {
+ $query->setFirstResult($offset);
+ }
+
+ $resultStatement = $query->execute();
+ while($data = $resultStatement->fetch()) {
+ $comment = new Comment($this->normalizeDatabaseData($data));
+ $this->cache($comment);
+ $tree['replies'][] = [
+ 'comment' => $comment,
+ 'replies' => []
+ ];
+ }
+ $resultStatement->closeCursor();
+
+ return $tree;
+ }
+
+ /**
+ * returns comments for a specific object (e.g. a file).
+ *
+ * The sort order is always newest to oldest.
+ *
+ * @param string $objectType the object type, e.g. 'files'
+ * @param string $objectId the id of the object
+ * @param int $limit optional, number of maximum comments to be returned. if
+ * not specified, all comments are returned.
+ * @param int $offset optional, starting point
+ * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
+ * that may be returned
+ * @return IComment[]
+ * @since 9.0.0
+ */
+ public function getForObject(
+ $objectType,
+ $objectId,
+ $limit = 0,
+ $offset = 0,
+ \DateTime $notOlderThan = null
+ ) {
+ $comments = [];
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->select('*')
+ ->from('comments')
+ ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
+ ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
+ ->orderBy('creation_timestamp', 'DESC')
+ ->setParameter('type', $objectType)
+ ->setParameter('id', $objectId);
+
+ if($limit > 0) {
+ $query->setMaxResults($limit);
+ }
+ if($offset > 0) {
+ $query->setFirstResult($offset);
+ }
+ if(!is_null($notOlderThan)) {
+ $query
+ ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
+ ->setParameter('notOlderThan', $notOlderThan, 'datetime');
+ }
+
+ $resultStatement = $query->execute();
+ while($data = $resultStatement->fetch()) {
+ $comment = new Comment($this->normalizeDatabaseData($data));
+ $this->cache($comment);
+ $comments[] = $comment;
+ }
+ $resultStatement->closeCursor();
+
+ return $comments;
+ }
+
+ /**
+ * @param $objectType string the object type, e.g. 'files'
+ * @param $objectId string the id of the object
+ * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
+ * that may be returned
+ * @return Int
+ * @since 9.0.0
+ */
+ public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->select($qb->createFunction('COUNT(`id`)'))
+ ->from('comments')
+ ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
+ ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
+ ->setParameter('type', $objectType)
+ ->setParameter('id', $objectId);
+
+ if(!is_null($notOlderThan)) {
+ $query
+ ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
+ ->setParameter('notOlderThan', $notOlderThan, 'datetime');
+ }
+
+ $resultStatement = $query->execute();
+ $data = $resultStatement->fetch(\PDO::FETCH_NUM);
+ $resultStatement->closeCursor();
+ return intval($data[0]);
+ }
+
+ /**
+ * creates a new comment and returns it. At this point of time, it is not
+ * saved in the used data storage. Use save() after setting other fields
+ * of the comment (e.g. message or verb).
+ *
+ * @param string $actorType the actor type (e.g. 'users')
+ * @param string $actorId a user id
+ * @param string $objectType the object type the comment is attached to
+ * @param string $objectId the object id the comment is attached to
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function create($actorType, $actorId, $objectType, $objectId) {
+ $comment = new Comment();
+ $comment
+ ->setActor($actorType, $actorId)
+ ->setObject($objectType, $objectId);
+ return $comment;
+ }
+
+ /**
+ * permanently deletes the comment specified by the ID
+ *
+ * When the comment has child comments, their parent ID will be changed to
+ * the parent ID of the item that is to be deleted.
+ *
+ * @param string $id
+ * @return bool
+ * @throws \InvalidArgumentException
+ * @since 9.0.0
+ */
+ public function delete($id) {
+ if(!is_string($id)) {
+ throw new \InvalidArgumentException('Parameter must be string');
+ }
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->delete('comments')
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter('id', $id);
+
+ try {
+ $affectedRows = $query->execute();
+ $this->uncache($id);
+ } catch (DriverException $e) {
+ $this->logger->logException($e, ['app' => 'core_comments']);
+ return false;
+ }
+ return ($affectedRows > 0);
+ }
+
+ /**
+ * saves the comment permanently and returns it
+ *
+ * if the supplied comment has an empty ID, a new entry comment will be
+ * saved and the instance updated with the new ID.
+ *
+ * Otherwise, an existing comment will be updated.
+ *
+ * Throws NotFoundException when a comment that is to be updated does not
+ * exist anymore at this point of time.
+ *
+ * @param IComment $comment
+ * @return bool
+ * @throws NotFoundException
+ * @since 9.0.0
+ */
+ public function save(IComment $comment) {
+ if($this->prepareCommentForDatabaseWrite($comment)->getId() === '') {
+ $result = $this->insert($comment);
+ } else {
+ $result = $this->update($comment);
+ }
+
+ if($result && !!$comment->getParentId()) {
+ $this->updateChildrenInformation(
+ $comment->getParentId(),
+ $comment->getCreationDateTime()
+ );
+ $this->cache($comment);
+ }
+
+ return $result;
+ }
+
+ /**
+ * inserts the provided comment in the database
+ *
+ * @param IComment $comment
+ * @return bool
+ */
+ protected function insert(IComment &$comment) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $affectedRows = $qb
+ ->insert('comments')
+ ->values([
+ 'parent_id' => $qb->createNamedParameter($comment->getParentId()),
+ 'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()),
+ 'children_count' => $qb->createNamedParameter($comment->getChildrenCount()),
+ 'actor_type' => $qb->createNamedParameter($comment->getActorType()),
+ 'actor_id' => $qb->createNamedParameter($comment->getActorId()),
+ 'message' => $qb->createNamedParameter($comment->getMessage()),
+ 'verb' => $qb->createNamedParameter($comment->getVerb()),
+ 'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'),
+ 'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'),
+ 'object_type' => $qb->createNamedParameter($comment->getObjectType()),
+ 'object_id' => $qb->createNamedParameter($comment->getObjectId()),
+ ])
+ ->execute();
+
+ if ($affectedRows > 0) {
+ $comment->setId(strval($qb->getLastInsertId()));
+ }
+
+ return $affectedRows > 0;
+ }
+
+ /**
+ * updates a Comment data row
+ *
+ * @param IComment $comment
+ * @return bool
+ * @throws NotFoundException
+ */
+ protected function update(IComment $comment) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $affectedRows = $qb
+ ->update('comments')
+ ->set('parent_id', $qb->createNamedParameter($comment->getParentId()))
+ ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId()))
+ ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount()))
+ ->set('actor_type', $qb->createNamedParameter($comment->getActorType()))
+ ->set('actor_id', $qb->createNamedParameter($comment->getActorId()))
+ ->set('message', $qb->createNamedParameter($comment->getMessage()))
+ ->set('verb', $qb->createNamedParameter($comment->getVerb()))
+ ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'))
+ ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'))
+ ->set('object_type', $qb->createNamedParameter($comment->getObjectType()))
+ ->set('object_id', $qb->createNamedParameter($comment->getObjectId()))
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter('id', $comment->getId())
+ ->execute();
+
+ if($affectedRows === 0) {
+ throw new NotFoundException('Comment to update does ceased to exist');
+ }
+
+ return $affectedRows > 0;
+ }
+
+ /**
+ * removes references to specific actor (e.g. on user delete) of a comment.
+ * The comment itself must not get lost/deleted.
+ *
+ * @param string $actorType the actor type (e.g. 'users')
+ * @param string $actorId a user id
+ * @return boolean
+ * @since 9.0.0
+ */
+ public function deleteReferencesOfActor($actorType, $actorId) {
+ $this->checkRoleParameters('Actor', $actorType, $actorId);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $affectedRows = $qb
+ ->update('comments')
+ ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
+ ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
+ ->where($qb->expr()->eq('actor_type', $qb->createParameter('type')))
+ ->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id')))
+ ->setParameter('type', $actorType)
+ ->setParameter('id', $actorId)
+ ->execute();
+
+ $this->commentsCache = [];
+
+ return is_int($affectedRows);
+ }
+
+ /**
+ * deletes all comments made of a specific object (e.g. on file delete)
+ *
+ * @param string $objectType the object type (e.g. 'files')
+ * @param string $objectId e.g. the file id
+ * @return boolean
+ * @since 9.0.0
+ */
+ public function deleteCommentsAtObject($objectType, $objectId) {
+ $this->checkRoleParameters('Object', $objectType, $objectId);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $affectedRows = $qb
+ ->delete('comments')
+ ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
+ ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
+ ->setParameter('type', $objectType)
+ ->setParameter('id', $objectId)
+ ->execute();
+
+ $this->commentsCache = [];
+
+ return is_int($affectedRows);
+ }
+
+ /**
+ * deletes the read markers for the specified user
+ *
+ * @param \OCP\IUser $user
+ * @return bool
+ * @since 9.0.0
+ */
+ public function deleteReadMarksFromUser(IUser $user) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->delete('comments_read_markers')
+ ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
+ ->setParameter('user_id', $user->getUID());
+
+ try {
+ $affectedRows = $query->execute();
+ } catch (DriverException $e) {
+ $this->logger->logException($e, ['app' => 'core_comments']);
+ return false;
+ }
+ return ($affectedRows > 0);
+ }
+
+ /**
+ * sets the read marker for a given file to the specified date for the
+ * provided user
+ *
+ * @param string $objectType
+ * @param string $objectId
+ * @param \DateTime $dateTime
+ * @param IUser $user
+ * @since 9.0.0
+ */
+ public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) {
+ $this->checkRoleParameters('Object', $objectType, $objectId);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $values = [
+ 'user_id' => $qb->createNamedParameter($user->getUID()),
+ 'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'),
+ 'object_type' => $qb->createNamedParameter($objectType),
+ 'object_id' => $qb->createNamedParameter($objectId),
+ ];
+
+ // Strategy: try to update, if this does not return affected rows, do an insert.
+ $affectedRows = $qb
+ ->update('comments_read_markers')
+ ->set('user_id', $values['user_id'])
+ ->set('marker_datetime', $values['marker_datetime'])
+ ->set('object_type', $values['object_type'])
+ ->set('object_id', $values['object_id'])
+ ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
+ ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
+ ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
+ ->setParameter('user_id', $user->getUID(), \PDO::PARAM_STR)
+ ->setParameter('object_type', $objectType, \PDO::PARAM_STR)
+ ->setParameter('object_id', $objectId, \PDO::PARAM_STR)
+ ->execute();
+
+ if ($affectedRows > 0) {
+ return;
+ }
+
+ $qb->insert('comments_read_markers')
+ ->values($values)
+ ->execute();
+ }
+
+ /**
+ * returns the read marker for a given file to the specified date for the
+ * provided user. It returns null, when the marker is not present, i.e.
+ * no comments were marked as read.
+ *
+ * @param string $objectType
+ * @param string $objectId
+ * @param IUser $user
+ * @return \DateTime|null
+ * @since 9.0.0
+ */
+ public function getReadMark($objectType, $objectId, IUser $user) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $resultStatement = $qb->select('marker_datetime')
+ ->from('comments_read_markers')
+ ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
+ ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
+ ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
+ ->setParameter('user_id', $user->getUID(), \PDO::PARAM_STR)
+ ->setParameter('object_type', $objectType, \PDO::PARAM_STR)
+ ->setParameter('object_id', $objectId, \PDO::PARAM_STR)
+ ->execute();
+
+ $data = $resultStatement->fetch();
+ $resultStatement->closeCursor();
+ if(!$data || is_null($data['marker_datetime'])) {
+ return null;
+ }
+
+ return new \DateTime($data['marker_datetime']);
+ }
+
+ /**
+ * deletes the read markers on the specified object
+ *
+ * @param string $objectType
+ * @param string $objectId
+ * @return bool
+ * @since 9.0.0
+ */
+ public function deleteReadMarksOnObject($objectType, $objectId) {
+ $this->checkRoleParameters('Object', $objectType, $objectId);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->delete('comments_read_markers')
+ ->where($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
+ ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
+ ->setParameter('object_type', $objectType)
+ ->setParameter('object_id', $objectId);
+
+ try {
+ $affectedRows = $query->execute();
+ } catch (DriverException $e) {
+ $this->logger->logException($e, ['app' => 'core_comments']);
+ return false;
+ }
+ return ($affectedRows > 0);
+ }
+}
diff --git a/lib/private/comments/managerfactory.php b/lib/private/comments/managerfactory.php
new file mode 100644
index 00000000000..d3f6c44e539
--- /dev/null
+++ b/lib/private/comments/managerfactory.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Comments;
+
+use OCP\Comments\ICommentsManager;
+use OCP\Comments\ICommentsManagerFactory;
+use OCP\IServerContainer;
+
+class ManagerFactory implements ICommentsManagerFactory {
+
+ /**
+ * Server container
+ *
+ * @var IServerContainer
+ */
+ private $serverContainer;
+
+ /**
+ * Constructor for the comments manager factory
+ *
+ * @param IServerContainer $serverContainer server container
+ */
+ public function __construct(IServerContainer $serverContainer) {
+ $this->serverContainer = $serverContainer;
+ }
+
+ /**
+ * creates and returns an instance of the ICommentsManager
+ *
+ * @return ICommentsManager
+ * @since 9.0.0
+ */
+ public function getManager() {
+ return new Manager(
+ $this->serverContainer->getDatabaseConnection(),
+ $this->serverContainer->getLogger(),
+ $this->serverContainer->getConfig()
+ );
+ }
+}
diff --git a/lib/private/config.php b/lib/private/config.php
index 3ad800a00be..368dafd0460 100644
--- a/lib/private/config.php
+++ b/lib/private/config.php
@@ -12,10 +12,9 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Volkan Gezer <volkangezer@gmail.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -185,7 +184,7 @@ class Config {
// Include file and merge config
foreach ($configFiles as $file) {
- $filePointer = @fopen($file, 'r');
+ $filePointer = file_exists($file) ? fopen($file, 'r') : false;
if($file === $this->configFilePath &&
$filePointer === false &&
@!file_exists($this->configFilePath)) {
@@ -234,7 +233,9 @@ class Config {
// File does not exist, this can happen when doing a fresh install
if(!is_resource ($filePointer)) {
- $url = \OC_Helper::linkToDocs('admin-dir_permissions');
+ // TODO fix this via DI once it is very clear that this doesn't cause side effects due to initialization order
+ // currently this breaks app routes but also could have other side effects especially during setup and exception handling
+ $url = \OC::$server->getURLGenerator()->linkToDocs('admin-dir_permissions');
throw new HintException(
"Can't write into config directory!",
'This can usually be fixed by '
diff --git a/lib/private/console/application.php b/lib/private/console/application.php
index 55c817d497f..c7d9c24d7cb 100644
--- a/lib/private/console/application.php
+++ b/lib/private/console/application.php
@@ -1,11 +1,11 @@
<?php
/**
- * @author Martin Mattel <martin.mattel@diemattels.at>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -48,25 +48,31 @@ class Application {
/**
* @param OutputInterface $output
+ * @throws \Exception
*/
public function loadCommands(OutputInterface $output) {
// $application is required to be defined in the register_command scripts
$application = $this->application;
- require_once \OC::$SERVERROOT . '/core/register_command.php';
+ require_once __DIR__ . '/../../../core/register_command.php';
if ($this->config->getSystemValue('installed', false)) {
- if (!\OCP\Util::needUpgrade()) {
+ if (\OCP\Util::needUpgrade()) {
+ $output->writeln("ownCloud or one of the apps require upgrade - only a limited number of commands are available");
+ $output->writeln("You may use your browser or the occ upgrade command to do the upgrade");
+ } elseif ($this->config->getSystemValue('maintenance', false)) {
+ $output->writeln("ownCloud is in maintenance mode - no app have been loaded");
+ } else {
OC_App::loadApps();
foreach (\OC::$server->getAppManager()->getInstalledApps() as $app) {
$appPath = \OC_App::getAppPath($app);
+ if($appPath === false) {
+ continue;
+ }
\OC::$loader->addValidRoot($appPath);
$file = $appPath . '/appinfo/register_command.php';
if (file_exists($file)) {
require $file;
}
}
- } else {
- $output->writeln("ownCloud or one of the apps require upgrade - only a limited number of commands are available");
- $output->writeln("You may use your browser or the occ upgrade command to do the upgrade");
}
} else {
$output->writeln("ownCloud is not installed - only a limited number of commands are available");
@@ -85,6 +91,11 @@ class Application {
}
}
+ /**
+ * Sets whether to automatically exit after a command execution or not.
+ *
+ * @param bool $boolean Whether to automatically exit after a command execution or not
+ */
public function setAutoExit($boolean) {
$this->application->setAutoExit($boolean);
}
diff --git a/lib/private/console/timestampformatter.php b/lib/private/console/timestampformatter.php
index f0c0f4c4520..3beac5e2f9f 100644
--- a/lib/private/console/timestampformatter.php
+++ b/lib/private/console/timestampformatter.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/contacts/localaddressbook.php b/lib/private/contacts/localaddressbook.php
deleted file mode 100644
index 7f10c6d3338..00000000000
--- a/lib/private/contacts/localaddressbook.php
+++ /dev/null
@@ -1,118 +0,0 @@
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OC\Contacts;
-
-class LocalAddressBook implements \OCP\IAddressBook {
-
- /**
- * @var \OCP\IUserManager
- */
- private $userManager;
-
- /**
- * @param $userManager
- */
- public function __construct($userManager) {
- $this->userManager = $userManager;
- }
-
- /**
- * @return string defining the technical unique key
- */
- public function getKey() {
- return 'local';
- }
-
- /**
- * In comparison to getKey() this function returns a human readable (maybe translated) name
- *
- * @return mixed
- */
- public function getDisplayName() {
- return "Local users";
- }
-
- /**
- * @param string $pattern which should match within the $searchProperties
- * @param array $searchProperties defines the properties within the query pattern should match
- * @param array $options - for future use. One should always have options!
- * @return array an array of contacts which are arrays of key-value-pairs
- */
- public function search($pattern, $searchProperties, $options) {
- $users = array();
- if($pattern == '') {
- // Fetch all contacts
- $users = $this->userManager->search('');
- } else {
- foreach($searchProperties as $property) {
- $result = array();
- if($property === 'FN') {
- $result = $this->userManager->searchDisplayName($pattern);
- } else if ($property === 'id') {
- $result = $this->userManager->search($pattern);
- }
- if (is_array($result)) {
- $users = array_merge($users, $result);
- }
- }
- }
-
- $contacts = array();
- foreach($users as $user){
- $contact = array(
- "id" => $user->getUID(),
- "FN" => $user->getDisplayname(),
- "EMAIL" => array(),
- "IMPP" => array(
- "x-owncloud-handle:" . $user->getUID()
- )
- );
- $contacts[] = $contact;
- }
- return $contacts;
- }
-
- /**
- * @param array $properties this array if key-value-pairs defines a contact
- * @return array an array representing the contact just created or updated
- */
- public function createOrUpdate($properties) {
- return array();
- }
-
- /**
- * @return int
- */
- public function getPermissions() {
- return \OCP\Constants::PERMISSION_READ;
- }
-
- /**
- * @param object $id the unique identifier to a contact
- * @return bool successful or not
- */
- public function delete($id) {
- return false;
- }
-}
diff --git a/lib/private/contactsmanager.php b/lib/private/contactsmanager.php
index 28285412377..a2640d36945 100644
--- a/lib/private/contactsmanager.php
+++ b/lib/private/contactsmanager.php
@@ -3,11 +3,11 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tobia De Koninck <tobia@ledfan.be>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/databaseexception.php b/lib/private/databaseexception.php
index a382a4ac60b..4d50fe82b0f 100644
--- a/lib/private/databaseexception.php
+++ b/lib/private/databaseexception.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/databasesetupexception.php b/lib/private/databasesetupexception.php
index 395b85d5349..30bd00de2d6 100644
--- a/lib/private/databasesetupexception.php
+++ b/lib/private/databasesetupexception.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/datetimeformatter.php b/lib/private/datetimeformatter.php
index 912a5faa2e3..5639ab1cace 100644
--- a/lib/private/datetimeformatter.php
+++ b/lib/private/datetimeformatter.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/datetimezone.php b/lib/private/datetimezone.php
index 512c39be3ea..5359cd6b391 100644
--- a/lib/private/datetimezone.php
+++ b/lib/private/datetimezone.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db.php b/lib/private/db.php
index a4a7b7d17d4..6535bb70d6d 100644
--- a/lib/private/db.php
+++ b/lib/private/db.php
@@ -2,17 +2,15 @@
/**
* @author Andreas Fischer <bantu@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
- * @author Dan Bartram <daneybartram@gmail.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Tom Needham <tom@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -36,13 +34,6 @@
class OC_DB {
/**
- * @return \OCP\IDBConnection
- */
- static public function getConnection() {
- return \OC::$server->getDatabaseConnection();
- }
-
- /**
* get MDB2 schema manager
*
* @return \OC\DB\MDB2SchemaManager
@@ -158,42 +149,6 @@ class OC_DB {
}
/**
- * gets last value of autoincrement
- * @param string $table The optional table name (will replace *PREFIX*) and add sequence suffix
- * @return string id
- * @throws \OC\DatabaseException
- *
- * \Doctrine\DBAL\Connection lastInsertId
- *
- * Call this method right after the insert command or other functions may
- * cause trouble!
- */
- public static function insertid($table=null) {
- return \OC::$server->getDatabaseConnection()->lastInsertId($table);
- }
-
- /**
- * Start a transaction
- */
- public static function beginTransaction() {
- return \OC::$server->getDatabaseConnection()->beginTransaction();
- }
-
- /**
- * Commit the database changes done during a transaction that is in progress
- */
- public static function commit() {
- return \OC::$server->getDatabaseConnection()->commit();
- }
-
- /**
- * Rollback the database changes done during a transaction that is in progress
- */
- public static function rollback() {
- return \OC::$server->getDatabaseConnection()->rollback();
- }
-
- /**
* saves database schema to xml file
* @param string $file name of file
* @param int $mode
@@ -254,15 +209,6 @@ class OC_DB {
}
/**
- * drop a table - the database prefix will be prepended
- * @param string $tableName the table to drop
- */
- public static function dropTable($tableName) {
- $connection = \OC::$server->getDatabaseConnection();
- $connection->dropTable($tableName);
- }
-
- /**
* remove all tables defined in a database structure xml file
* @param string $file the xml file describing the tables
*/
@@ -272,15 +218,6 @@ class OC_DB {
}
/**
- * check if a result is an error, works with Doctrine
- * @param mixed $result
- * @return bool
- */
- public static function isError($result) {
- //Doctrine returns false on error (and throws an exception)
- return $result === false;
- }
- /**
* check if a result is an error and throws an exception, works with \Doctrine\DBAL\DBALException
* @param mixed $result
* @param string $message
@@ -288,20 +225,16 @@ class OC_DB {
* @throws \OC\DatabaseException
*/
public static function raiseExceptionOnError($result, $message = null) {
- if(self::isError($result)) {
+ if($result === false) {
if ($message === null) {
$message = self::getErrorMessage();
} else {
$message .= ', Root cause:' . self::getErrorMessage();
}
- throw new \OC\DatabaseException($message, self::getErrorCode());
+ throw new \OC\DatabaseException($message, \OC::$server->getDatabaseConnection()->errorCode());
}
}
- public static function getErrorCode() {
- $connection = \OC::$server->getDatabaseConnection();
- return $connection->errorCode();
- }
/**
* returns the error code and message as a string for logging
* works with DoctrineException
diff --git a/lib/private/db/adapter.php b/lib/private/db/adapter.php
index f104a62d2d5..9522f768c88 100644
--- a/lib/private/db/adapter.php
+++ b/lib/private/db/adapter.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/adaptermysql.php b/lib/private/db/adaptermysql.php
index fda8554e1c4..ab87c589747 100644
--- a/lib/private/db/adaptermysql.php
+++ b/lib/private/db/adaptermysql.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/adapteroci8.php b/lib/private/db/adapteroci8.php
index 6e7857e6620..970d3eefa4d 100644
--- a/lib/private/db/adapteroci8.php
+++ b/lib/private/db/adapteroci8.php
@@ -3,8 +3,9 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +27,9 @@ namespace OC\DB;
class AdapterOCI8 extends Adapter {
public function lastInsertId($table) {
+ if (is_null($table)) {
+ throw new \InvalidArgumentException('Oracle requires a table name to be passed into lastInsertId()');
+ }
if ($table !== null) {
$suffix = '_SEQ';
$table = '"' . $table . $suffix . '"';
diff --git a/lib/private/db/adapterpgsql.php b/lib/private/db/adapterpgsql.php
index 1f2119e92a5..a7d9377a0bf 100644
--- a/lib/private/db/adapterpgsql.php
+++ b/lib/private/db/adapterpgsql.php
@@ -3,7 +3,7 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/adaptersqlite.php b/lib/private/db/adaptersqlite.php
index e133a20f543..d7769238abc 100644
--- a/lib/private/db/adaptersqlite.php
+++ b/lib/private/db/adaptersqlite.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/adaptersqlsrv.php b/lib/private/db/adaptersqlsrv.php
index 7e181c37cc5..f208b2ba787 100644
--- a/lib/private/db/adaptersqlsrv.php
+++ b/lib/private/db/adaptersqlsrv.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/connection.php b/lib/private/db/connection.php
index 1b86d3d383a..82b52bbc9d7 100644
--- a/lib/private/db/connection.php
+++ b/lib/private/db/connection.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,9 +29,10 @@ use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\Common\EventManager;
-use OC\DB\QueryBuilder\ExpressionBuilder;
use OC\DB\QueryBuilder\QueryBuilder;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+use OCP\PreconditionNotMetException;
class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
/**
@@ -154,7 +155,7 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
$statement = $this->replaceTablePrefix($statement);
$statement = $this->adapter->fixupStatement($statement);
- if(\OC_Config::getValue( 'log_query', false)) {
+ if(\OC::$server->getSystemConfig()->getValue( 'log_query', false)) {
\OCP\Util::writeLog('core', 'DB prepare : '.$statement, \OCP\Util::DEBUG);
}
return parent::prepare($statement);
@@ -214,8 +215,7 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
* @param string $seqName Name of the sequence object from which the ID should be returned.
* @return string A string representation of the last inserted ID.
*/
- public function lastInsertId($seqName = null)
- {
+ public function lastInsertId($seqName = null) {
if ($seqName) {
$seqName = $this->replaceTablePrefix($seqName);
}
@@ -242,6 +242,64 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
return $this->adapter->insertIfNotExist($table, $input, $compare);
}
+ private function getType($value) {
+ if (is_bool($value)) {
+ return IQueryBuilder::PARAM_BOOL;
+ } else if (is_int($value)) {
+ return IQueryBuilder::PARAM_INT;
+ } else {
+ return IQueryBuilder::PARAM_STR;
+ }
+ }
+
+ /**
+ * Insert or update a row value
+ *
+ * @param string $table
+ * @param array $keys (column name => value)
+ * @param array $values (column name => value)
+ * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
+ * @return int number of new rows
+ * @throws \Doctrine\DBAL\DBALException
+ * @throws PreconditionNotMetException
+ */
+ public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
+ try {
+ $insertQb = $this->getQueryBuilder();
+ $insertQb->insert($table)
+ ->values(
+ array_map(function($value) use ($insertQb) {
+ return $insertQb->createNamedParameter($value, $this->getType($value));
+ }, array_merge($keys, $values))
+ );
+ return $insertQb->execute();
+ } catch (\Doctrine\DBAL\Exception\ConstraintViolationException $e) {
+ // value already exists, try update
+ $updateQb = $this->getQueryBuilder();
+ $updateQb->update($table);
+ foreach ($values as $name => $value) {
+ $updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
+ }
+ $where = $updateQb->expr()->andx();
+ $whereValues = array_merge($keys, $updatePreconditionValues);
+ foreach ($whereValues as $name => $value) {
+ $where->add($updateQb->expr()->eq(
+ $name,
+ $updateQb->createNamedParameter($value, $this->getType($value)),
+ $this->getType($value)
+ ));
+ }
+ $updateQb->where($where);
+ $affected = $updateQb->execute();
+
+ if ($affected === 0) {
+ throw new PreconditionNotMetException();
+ }
+
+ return 0;
+ }
+ }
+
/**
* returns the error code and message as a string for logging
* works with DoctrineException
diff --git a/lib/private/db/connectionfactory.php b/lib/private/db/connectionfactory.php
index b6c3396e147..0856d8d19c0 100644
--- a/lib/private/db/connectionfactory.php
+++ b/lib/private/db/connectionfactory.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/mdb2schemamanager.php b/lib/private/db/mdb2schemamanager.php
index aef485ed686..bcabb6fe57a 100644
--- a/lib/private/db/mdb2schemamanager.php
+++ b/lib/private/db/mdb2schemamanager.php
@@ -5,11 +5,11 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author tbelau666 <thomas.belau@gmx.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -49,13 +49,12 @@ class MDB2SchemaManager {
/**
* saves database scheme to xml file
* @param string $file name of file
- * @param int|string $mode
* @return bool
*
* TODO: write more documentation
*/
public function getDbStructure($file) {
- return \OC_DB_MDB2SchemaWriter::saveSchemaToFile($file, $this->conn);
+ return \OC\DB\MDB2SchemaWriter::saveSchemaToFile($file, $this->conn);
}
/**
@@ -75,7 +74,7 @@ class MDB2SchemaManager {
* @return \OC\DB\Migrator
*/
public function getMigrator() {
- $random = \OC::$server->getSecureRandom()->getMediumStrengthGenerator();
+ $random = \OC::$server->getSecureRandom();
$platform = $this->conn->getDatabasePlatform();
$config = \OC::$server->getConfig();
if ($platform instanceof SqlitePlatform) {
@@ -123,7 +122,7 @@ class MDB2SchemaManager {
/**
* update the database scheme
* @param string $file file to read structure from
- * @return string|boolean
+ * @return boolean
*/
public function simulateUpdateDbFromStructure($file) {
$toSchema = $this->readSchemaFromFile($file);
diff --git a/lib/private/db/mdb2schemareader.php b/lib/private/db/mdb2schemareader.php
index 946ef1c621d..6f99206e5c8 100644
--- a/lib/private/db/mdb2schemareader.php
+++ b/lib/private/db/mdb2schemareader.php
@@ -5,12 +5,12 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Oliver Gasser <oliver.gasser@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/mdb2schemawriter.php b/lib/private/db/mdb2schemawriter.php
index 8b74b545b3b..803e7cda0b4 100644
--- a/lib/private/db/mdb2schemawriter.php
+++ b/lib/private/db/mdb2schemawriter.php
@@ -7,7 +7,7 @@
* @author tbelau666 <thomas.belau@gmx.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,7 +24,12 @@
*
*/
-class OC_DB_MDB2SchemaWriter {
+namespace OC\DB;
+
+use Doctrine\DBAL\Schema\Column;
+use Doctrine\DBAL\Schema\Index;
+
+class MDB2SchemaWriter {
/**
* @param string $file
@@ -34,7 +39,7 @@ class OC_DB_MDB2SchemaWriter {
static public function saveSchemaToFile($file, \OC\DB\Connection $conn) {
$config = \OC::$server->getConfig();
- $xml = new SimpleXMLElement('<database/>');
+ $xml = new \SimpleXMLElement('<database/>');
$xml->addChild('name', $config->getSystemValue('dbname', 'owncloud'));
$xml->addChild('create', 'true');
$xml->addChild('overwrite', 'false');
@@ -56,7 +61,8 @@ class OC_DB_MDB2SchemaWriter {
}
/**
- * @param SimpleXMLElement $xml
+ * @param \Doctrine\DBAL\Schema\Table $table
+ * @param \SimpleXMLElement $xml
*/
private static function saveTable($table, $xml) {
$xml->addChild('name', $table->getName());
@@ -81,7 +87,8 @@ class OC_DB_MDB2SchemaWriter {
}
/**
- * @param SimpleXMLElement $xml
+ * @param Column $column
+ * @param \SimpleXMLElement $xml
*/
private static function saveColumn($column, $xml) {
$xml->addChild('name', $column->getName());
@@ -147,7 +154,8 @@ class OC_DB_MDB2SchemaWriter {
}
/**
- * @param SimpleXMLElement $xml
+ * @param Index $index
+ * @param \SimpleXMLElement $xml
*/
private static function saveIndex($index, $xml) {
$xml->addChild('name', $index->getName());
diff --git a/lib/private/db/migrationexception.php b/lib/private/db/migrationexception.php
index e79644f2268..57e4c5b8334 100644
--- a/lib/private/db/migrationexception.php
+++ b/lib/private/db/migrationexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/migrator.php b/lib/private/db/migrator.php
index 6a587ede631..7ca3f981358 100644
--- a/lib/private/db/migrator.php
+++ b/lib/private/db/migrator.php
@@ -8,7 +8,7 @@
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -52,7 +52,7 @@ class Migrator {
protected $config;
/**
- * @param \Doctrine\DBAL\Connection $connection
+ * @param Connection $connection
* @param ISecureRandom $random
* @param IConfig $config
*/
diff --git a/lib/private/db/mysqlmigrator.php b/lib/private/db/mysqlmigrator.php
index 41f179db000..1b3f70a817d 100644
--- a/lib/private/db/mysqlmigrator.php
+++ b/lib/private/db/mysqlmigrator.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/nocheckmigrator.php b/lib/private/db/nocheckmigrator.php
index 3ecbe6b721c..23afae11816 100644
--- a/lib/private/db/nocheckmigrator.php
+++ b/lib/private/db/nocheckmigrator.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/ocsqliteplatform.php b/lib/private/db/ocsqliteplatform.php
index 2456d262fe3..fe68bc3cc91 100644
--- a/lib/private/db/ocsqliteplatform.php
+++ b/lib/private/db/ocsqliteplatform.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/oracleconnection.php b/lib/private/db/oracleconnection.php
index 15cd1231b77..a95f37a8e6c 100644
--- a/lib/private/db/oracleconnection.php
+++ b/lib/private/db/oracleconnection.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/oraclemigrator.php b/lib/private/db/oraclemigrator.php
index fa30a9989aa..ceb89cf64d4 100644
--- a/lib/private/db/oraclemigrator.php
+++ b/lib/private/db/oraclemigrator.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/pgsqltools.php b/lib/private/db/pgsqltools.php
index 9a95d0e81d2..e9e507551e6 100644
--- a/lib/private/db/pgsqltools.php
+++ b/lib/private/db/pgsqltools.php
@@ -5,7 +5,7 @@
* @author tbelau666 <thomas.belau@gmx.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/querybuilder/compositeexpression.php b/lib/private/db/querybuilder/compositeexpression.php
index 523f397e235..927dfe38378 100644
--- a/lib/private/db/querybuilder/compositeexpression.php
+++ b/lib/private/db/querybuilder/compositeexpression.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/querybuilder/expressionbuilder.php b/lib/private/db/querybuilder/expressionbuilder.php
index cd5b7fbfc54..b688ebfabbe 100644
--- a/lib/private/db/querybuilder/expressionbuilder.php
+++ b/lib/private/db/querybuilder/expressionbuilder.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,10 +27,10 @@ use OCP\IDBConnection;
class ExpressionBuilder implements IExpressionBuilder {
/** @var \Doctrine\DBAL\Query\Expression\ExpressionBuilder */
- private $expressionBuilder;
+ protected $expressionBuilder;
/** @var QuoteHelper */
- private $helper;
+ protected $helper;
/**
* Initializes a new <tt>ExpressionBuilder</tt>.
@@ -86,12 +86,14 @@ class ExpressionBuilder implements IExpressionBuilder {
* Creates a comparison expression.
*
* @param mixed $x The left expression.
- * @param string $operator One of the ExpressionBuilder::* constants.
+ * @param string $operator One of the IExpressionBuilder::* constants.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function comparison($x, $operator, $y) {
+ public function comparison($x, $operator, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->comparison($x, $operator, $y);
@@ -109,10 +111,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function eq($x, $y) {
+ public function eq($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->eq($x, $y);
@@ -129,10 +133,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function neq($x, $y) {
+ public function neq($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->neq($x, $y);
@@ -149,10 +155,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function lt($x, $y) {
+ public function lt($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->lt($x, $y);
@@ -169,10 +177,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function lte($x, $y) {
+ public function lte($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->lte($x, $y);
@@ -189,10 +199,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function gt($x, $y) {
+ public function gt($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->gt($x, $y);
@@ -209,10 +221,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function gte($x, $y) {
+ public function gte($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->gte($x, $y);
@@ -247,10 +261,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param string $x Field in string format to be inspected by LIKE() comparison.
* @param mixed $y Argument to be used in LIKE() comparison.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function like($x, $y) {
+ public function like($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->like($x, $y);
@@ -261,10 +277,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param string $x Field in string format to be inspected by NOT LIKE() comparison.
* @param mixed $y Argument to be used in NOT LIKE() comparison.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function notLike($x, $y) {
+ public function notLike($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->notLike($x, $y);
@@ -275,10 +293,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param string $x The field in string format to be inspected by IN() comparison.
* @param string|array $y The placeholder or the array of values to be used by IN() comparison.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function in($x, $y) {
+ public function in($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnNames($y);
return $this->expressionBuilder->in($x, $y);
@@ -289,10 +309,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param string $x The field in string format to be inspected by NOT IN() comparison.
* @param string|array $y The placeholder or the array of values to be used by NOT IN() comparison.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function notIn($x, $y) {
+ public function notIn($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnNames($y);
return $this->expressionBuilder->notIn($x, $y);
@@ -302,7 +324,7 @@ class ExpressionBuilder implements IExpressionBuilder {
* Quotes a given input parameter.
*
* @param mixed $input The parameter to be quoted.
- * @param string|null $type The type of the parameter.
+ * @param mixed|null $type One of the IQueryBuilder::PARAM_* constants
*
* @return Literal
*/
diff --git a/lib/private/db/querybuilder/literal.php b/lib/private/db/querybuilder/literal.php
index 361b5ccf3b8..0cc96ab48b4 100644
--- a/lib/private/db/querybuilder/literal.php
+++ b/lib/private/db/querybuilder/literal.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/querybuilder/ociexpressionbuilder.php b/lib/private/db/querybuilder/ociexpressionbuilder.php
new file mode 100644
index 00000000000..4c127bd752d
--- /dev/null
+++ b/lib/private/db/querybuilder/ociexpressionbuilder.php
@@ -0,0 +1,135 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\DB\QueryBuilder;
+
+
+use OCP\DB\QueryBuilder\ILiteral;
+use OCP\DB\QueryBuilder\IParameter;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+
+class OCIExpressionBuilder extends ExpressionBuilder {
+
+ /**
+ * @param mixed $column
+ * @param mixed|null $type
+ * @return array|QueryFunction|string
+ */
+ protected function prepareColumn($column, $type) {
+ if ($type === IQueryBuilder::PARAM_STR && !is_array($column) && !($column instanceof IParameter) && !($column instanceof ILiteral)) {
+ $column = $this->helper->quoteColumnName($column);
+ $column = new QueryFunction('to_char(' . $column . ')');
+ } else {
+ $column = $this->helper->quoteColumnNames($column);
+ }
+ return $column;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function comparison($x, $operator, $y, $type = null) {
+ $x = $this->prepareColumn($x, $type);
+ $y = $this->prepareColumn($y, $type);
+
+ return $this->expressionBuilder->comparison($x, $operator, $y);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function eq($x, $y, $type = null) {
+ $x = $this->prepareColumn($x, $type);
+ $y = $this->prepareColumn($y, $type);
+
+ return $this->expressionBuilder->eq($x, $y);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function neq($x, $y, $type = null) {
+ $x = $this->prepareColumn($x, $type);
+ $y = $this->prepareColumn($y, $type);
+
+ return $this->expressionBuilder->neq($x, $y);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function lt($x, $y, $type = null) {
+ $x = $this->prepareColumn($x, $type);
+ $y = $this->prepareColumn($y, $type);
+
+ return $this->expressionBuilder->lt($x, $y);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function lte($x, $y, $type = null) {
+ $x = $this->prepareColumn($x, $type);
+ $y = $this->prepareColumn($y, $type);
+
+ return $this->expressionBuilder->lte($x, $y);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function gt($x, $y, $type = null) {
+ $x = $this->prepareColumn($x, $type);
+ $y = $this->prepareColumn($y, $type);
+
+ return $this->expressionBuilder->gt($x, $y);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function gte($x, $y, $type = null) {
+ $x = $this->prepareColumn($x, $type);
+ $y = $this->prepareColumn($y, $type);
+
+ return $this->expressionBuilder->gte($x, $y);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function in($x, $y, $type = null) {
+ $x = $this->prepareColumn($x, $type);
+ $y = $this->prepareColumn($y, $type);
+
+ return $this->expressionBuilder->in($x, $y);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function notIn($x, $y, $type = null) {
+ $x = $this->prepareColumn($x, $type);
+ $y = $this->prepareColumn($y, $type);
+
+ return $this->expressionBuilder->notIn($x, $y);
+ }
+}
diff --git a/lib/private/db/querybuilder/parameter.php b/lib/private/db/querybuilder/parameter.php
index c14b4e21925..1c233c83f1d 100644
--- a/lib/private/db/querybuilder/parameter.php
+++ b/lib/private/db/querybuilder/parameter.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/querybuilder/querybuilder.php b/lib/private/db/querybuilder/querybuilder.php
index 1d97faf77cc..42b290b90e7 100644
--- a/lib/private/db/querybuilder/querybuilder.php
+++ b/lib/private/db/querybuilder/querybuilder.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,6 +21,7 @@
namespace OC\DB\QueryBuilder;
+use OC\DB\OracleConnection;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
use OCP\DB\QueryBuilder\IParameter;
@@ -40,6 +41,9 @@ class QueryBuilder implements IQueryBuilder {
/** @var bool */
private $automaticTablePrefix = true;
+ /** @var string */
+ protected $lastInsertedTable;
+
/**
* Initializes a new QueryBuilder.
*
@@ -79,7 +83,11 @@ class QueryBuilder implements IQueryBuilder {
* @return \OCP\DB\QueryBuilder\IExpressionBuilder
*/
public function expr() {
- return new ExpressionBuilder($this->connection);
+ if ($this->connection instanceof OracleConnection) {
+ return new OCIExpressionBuilder($this->connection);
+ } else {
+ return new ExpressionBuilder($this->connection);
+ }
}
/**
@@ -301,6 +309,52 @@ class QueryBuilder implements IQueryBuilder {
}
/**
+ * Specifies an item that is to be returned with a different name in the query result.
+ *
+ * <code>
+ * $qb = $conn->getQueryBuilder()
+ * ->selectAlias('u.id', 'user_id')
+ * ->from('users', 'u')
+ * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
+ * </code>
+ *
+ * @param mixed $select The selection expressions.
+ * @param string $alias The column alias used in the constructed query.
+ *
+ * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance.
+ */
+ public function selectAlias($select, $alias) {
+
+ $this->queryBuilder->addSelect(
+ $this->helper->quoteColumnName($select) . ' AS ' . $this->helper->quoteColumnName($alias)
+ );
+
+ return $this;
+ }
+
+ /**
+ * Specifies an item that is to be returned uniquely in the query result.
+ *
+ * <code>
+ * $qb = $conn->getQueryBuilder()
+ * ->selectDistinct('type')
+ * ->from('users');
+ * </code>
+ *
+ * @param mixed $select The selection expressions.
+ *
+ * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance.
+ */
+ public function selectDistinct($select) {
+
+ $this->queryBuilder->addSelect(
+ 'DISTINCT ' . $this->helper->quoteColumnName($select)
+ );
+
+ return $this;
+ }
+
+ /**
* Adds an item that is to be returned in the query result.
*
* <code>
@@ -399,6 +453,8 @@ class QueryBuilder implements IQueryBuilder {
$this->getTableName($insert)
);
+ $this->lastInsertedTable = $insert;
+
return $this;
}
@@ -1000,14 +1056,57 @@ class QueryBuilder implements IQueryBuilder {
}
/**
+ * Used to get the id of the last inserted element
+ * @return int
+ * @throws \BadMethodCallException When being called before an insert query has been run.
+ */
+ public function getLastInsertId() {
+ if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::INSERT && $this->lastInsertedTable) {
+ // lastInsertId() needs the prefix but no quotes
+ $table = $this->prefixTableName($this->lastInsertedTable);
+ return (int) $this->connection->lastInsertId($table);
+ }
+
+ throw new \BadMethodCallException('Invalid call to getLastInsertId without using insert() before.');
+ }
+
+ /**
+ * Returns the table name quoted and with database prefix as needed by the implementation
+ *
+ * @param string $table
+ * @return string
+ */
+ public function getTableName($table) {
+ $table = $this->prefixTableName($table);
+ return $this->helper->quoteColumnName($table);
+ }
+
+ /**
+ * Returns the table name with database prefix as needed by the implementation
+ *
* @param string $table
* @return string
*/
- private function getTableName($table) {
+ protected function prefixTableName($table) {
if ($this->automaticTablePrefix === false || strpos($table, '*PREFIX*') === 0) {
- return $this->helper->quoteColumnName($table);
+ return $table;
+ }
+
+ return '*PREFIX*' . $table;
+ }
+
+ /**
+ * Returns the column name quoted and with table alias prefix as needed by the implementation
+ *
+ * @param string $column
+ * @param string $tableAlias
+ * @return string
+ */
+ public function getColumnName($column, $tableAlias = '') {
+ if ($tableAlias !== '') {
+ $tableAlias .= '.';
}
- return $this->helper->quoteColumnName('*PREFIX*' . $table);
+ return $this->helper->quoteColumnName($tableAlias . $column);
}
}
diff --git a/lib/private/db/querybuilder/queryfunction.php b/lib/private/db/querybuilder/queryfunction.php
index 2a47d83b917..ac6d73f3cbf 100644
--- a/lib/private/db/querybuilder/queryfunction.php
+++ b/lib/private/db/querybuilder/queryfunction.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/querybuilder/quotehelper.php b/lib/private/db/querybuilder/quotehelper.php
index 4b62fee6a6c..fda243a3786 100644
--- a/lib/private/db/querybuilder/quotehelper.php
+++ b/lib/private/db/querybuilder/quotehelper.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -61,7 +61,7 @@ class QuoteHelper {
}
if (substr_count($string, '.')) {
- list($alias, $columnName) = explode('.', $string);
+ list($alias, $columnName) = explode('.', $string, 2);
if ($columnName === '*') {
return $string;
diff --git a/lib/private/db/sqlitemigrator.php b/lib/private/db/sqlitemigrator.php
index 063ccd87841..8ea32581011 100644
--- a/lib/private/db/sqlitemigrator.php
+++ b/lib/private/db/sqlitemigrator.php
@@ -5,7 +5,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/sqlitesessioninit.php b/lib/private/db/sqlitesessioninit.php
index c8d2a3940d1..0683c47d08e 100644
--- a/lib/private/db/sqlitesessioninit.php
+++ b/lib/private/db/sqlitesessioninit.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/db/statementwrapper.php b/lib/private/db/statementwrapper.php
index 4bdaf01f071..6422d8d5f1b 100644
--- a/lib/private/db/statementwrapper.php
+++ b/lib/private/db/statementwrapper.php
@@ -5,10 +5,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -64,7 +64,7 @@ class OC_DB_StatementWrapper {
* @return \OC_DB_StatementWrapper|int
*/
public function execute($input=array()) {
- if(OC_Config::getValue( "log_query", false)) {
+ if(\OC::$server->getSystemConfig()->getValue( "log_query", false)) {
$params_str = str_replace("\n", " ", var_export($input, true));
\OCP\Util::writeLog('core', 'DB execute with arguments : '.$params_str, \OCP\Util::DEBUG);
}
diff --git a/lib/private/defaults.php b/lib/private/defaults.php
index 16f45943f54..43e8c8082cc 100644
--- a/lib/private/defaults.php
+++ b/lib/private/defaults.php
@@ -7,12 +7,12 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Pascal de Bruijn <pmjdebruijn@pcode.nl>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author scolebrook <scolebrook@mac.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Volkan Gezer <volkangezer@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -49,7 +49,7 @@ class OC_Defaults {
function __construct() {
$this->l = \OC::$server->getL10N('lib');
- $version = OC_Util::getVersion();
+ $version = \OCP\Util::getVersion();
$this->defaultEntity = 'ownCloud'; /* e.g. company name, used for footers and copyright notices */
$this->defaultName = 'ownCloud'; /* short name, used when referring to the software */
@@ -261,6 +261,9 @@ class OC_Defaults {
return $footer;
}
+ /**
+ * @param string $key
+ */
public function buildDocLinkToKey($key) {
if ($this->themeExist('buildDocLinkToKey')) {
return $this->theme->buildDocLinkToKey($key);
diff --git a/lib/private/diagnostics/event.php b/lib/private/diagnostics/event.php
index 541a84ffa10..8b5bb7e3bd8 100644
--- a/lib/private/diagnostics/event.php
+++ b/lib/private/diagnostics/event.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/diagnostics/eventlogger.php b/lib/private/diagnostics/eventlogger.php
index 2345abb3fff..3d909ce79cd 100644
--- a/lib/private/diagnostics/eventlogger.php
+++ b/lib/private/diagnostics/eventlogger.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/diagnostics/nulleventlogger.php b/lib/private/diagnostics/nulleventlogger.php
index 0a8d656a5fc..1b5e7af3ac9 100644
--- a/lib/private/diagnostics/nulleventlogger.php
+++ b/lib/private/diagnostics/nulleventlogger.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/diagnostics/nullquerylogger.php b/lib/private/diagnostics/nullquerylogger.php
index e35d28118d6..98ddef2e783 100644
--- a/lib/private/diagnostics/nullquerylogger.php
+++ b/lib/private/diagnostics/nullquerylogger.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/diagnostics/query.php b/lib/private/diagnostics/query.php
index 203ef15d677..567bc83ed4b 100644
--- a/lib/private/diagnostics/query.php
+++ b/lib/private/diagnostics/query.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/diagnostics/querylogger.php b/lib/private/diagnostics/querylogger.php
index 289005a1c41..66a65b71d04 100644
--- a/lib/private/diagnostics/querylogger.php
+++ b/lib/private/diagnostics/querylogger.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -53,7 +53,7 @@ class QueryLogger implements IQueryLogger {
}
/**
- * @return \OCP\Diagnostics\IQuery[]
+ * @return Query[]
*/
public function getQueries() {
return $this->queries;
diff --git a/lib/private/encryption/decryptall.php b/lib/private/encryption/decryptall.php
index e19ee6b745f..7a965a5f227 100644
--- a/lib/private/encryption/decryptall.php
+++ b/lib/private/encryption/decryptall.php
@@ -2,7 +2,7 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/exceptions/decryptionfailedexception.php b/lib/private/encryption/exceptions/decryptionfailedexception.php
index 406ae12968e..a0cbbc5cce0 100644
--- a/lib/private/encryption/exceptions/decryptionfailedexception.php
+++ b/lib/private/encryption/exceptions/decryptionfailedexception.php
@@ -3,7 +3,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/exceptions/emptyencryptiondataexception.php b/lib/private/encryption/exceptions/emptyencryptiondataexception.php
index 739614b3ec2..2c90c2db7df 100644
--- a/lib/private/encryption/exceptions/emptyencryptiondataexception.php
+++ b/lib/private/encryption/exceptions/emptyencryptiondataexception.php
@@ -3,7 +3,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/exceptions/encryptionfailedexception.php b/lib/private/encryption/exceptions/encryptionfailedexception.php
index 4195ca0a5a8..98e92eb199c 100644
--- a/lib/private/encryption/exceptions/encryptionfailedexception.php
+++ b/lib/private/encryption/exceptions/encryptionfailedexception.php
@@ -3,7 +3,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php b/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php
index d927939484f..ab1a166018c 100644
--- a/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php
+++ b/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/exceptions/encryptionheadertolargeexception.php b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php
index 40c51782a32..7b706e621de 100644
--- a/lib/private/encryption/exceptions/encryptionheadertolargeexception.php
+++ b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php
@@ -3,7 +3,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/exceptions/modulealreadyexistsexception.php b/lib/private/encryption/exceptions/modulealreadyexistsexception.php
index c72ad7b7ab2..fcd08679acc 100644
--- a/lib/private/encryption/exceptions/modulealreadyexistsexception.php
+++ b/lib/private/encryption/exceptions/modulealreadyexistsexception.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/exceptions/moduledoesnotexistsexception.php b/lib/private/encryption/exceptions/moduledoesnotexistsexception.php
index d6fbb2b6e51..282c9ec080b 100644
--- a/lib/private/encryption/exceptions/moduledoesnotexistsexception.php
+++ b/lib/private/encryption/exceptions/moduledoesnotexistsexception.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/exceptions/unknowncipherexception.php b/lib/private/encryption/exceptions/unknowncipherexception.php
index 91535183169..beb4cb7f2e5 100644
--- a/lib/private/encryption/exceptions/unknowncipherexception.php
+++ b/lib/private/encryption/exceptions/unknowncipherexception.php
@@ -3,7 +3,7 @@
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/file.php b/lib/private/encryption/file.php
index 6d261f46d0f..ec55c2cea00 100644
--- a/lib/private/encryption/file.php
+++ b/lib/private/encryption/file.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/hookmanager.php b/lib/private/encryption/hookmanager.php
index 8969379c957..0bc42ec8159 100644
--- a/lib/private/encryption/hookmanager.php
+++ b/lib/private/encryption/hookmanager.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php
index e21fd62e366..47360f45aa5 100644
--- a/lib/private/encryption/keys/storage.php
+++ b/lib/private/encryption/keys/storage.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php
index d38ec6684a6..d1d17a92887 100644
--- a/lib/private/encryption/manager.php
+++ b/lib/private/encryption/manager.php
@@ -5,7 +5,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/update.php b/lib/private/encryption/update.php
index 64cccc16ed8..62c23c1fe0c 100644
--- a/lib/private/encryption/update.php
+++ b/lib/private/encryption/update.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php
index ef500883865..860c541934a 100644
--- a/lib/private/encryption/util.php
+++ b/lib/private/encryption/util.php
@@ -5,7 +5,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/eventsource.php b/lib/private/eventsource.php
index c076b87ddd9..f567d1e6ca5 100644
--- a/lib/private/eventsource.php
+++ b/lib/private/eventsource.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -76,7 +76,7 @@ class OC_EventSource implements \OCP\IEventSource {
} else {
header("Content-Type: text/event-stream");
}
- if (!OC_Util::isCallRegistered()) {
+ if (!(\OC::$server->getRequest()->passesCSRFCheck())) {
$this->send('error', 'Possible CSRF attack. Connection will be closed.');
$this->close();
exit();
diff --git a/lib/private/filechunking.php b/lib/private/filechunking.php
index 64399ad4366..8c341df4a8b 100644
--- a/lib/private/filechunking.php
+++ b/lib/private/filechunking.php
@@ -10,7 +10,7 @@
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files.php b/lib/private/files.php
index 9be5fc9a12f..a18bcc76519 100644
--- a/lib/private/files.php
+++ b/lib/private/files.php
@@ -3,6 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
+ * @author Clark Tomlinson <fallen013@gmail.com>
* @author Frank Karlitschek <frank@owncloud.org>
* @author Jakob Sack <mail@jakobsack.de>
* @author Joas Schilling <nickvergessen@owncloud.com>
@@ -10,14 +11,14 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Nicolai Ehemann <en@enlightened.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thibaut GRIDEL <tgridel@free.fr>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -115,7 +116,7 @@ class OC_Files {
self::lockFiles($view, $dir, $files);
$streamer->sendHeaders($name);
- $executionTime = intval(ini_get('max_execution_time'));
+ $executionTime = intval(OC::$server->getIniWrapper()->getNumeric('max_execution_time'));
set_time_limit(0);
if ($getType === self::ZIP_FILES) {
foreach ($files as $file) {
@@ -142,6 +143,11 @@ class OC_Files {
$l = \OC::$server->getL10N('core');
$hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
\OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint);
+ } catch (\OCP\Files\ForbiddenException $ex) {
+ self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
+ OC::$server->getLogger()->logException($ex);
+ $l = \OC::$server->getL10N('core');
+ \OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage());
} catch (\Exception $ex) {
self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
OC::$server->getLogger()->logException($ex);
@@ -154,6 +160,8 @@ class OC_Files {
/**
* @param View $view
* @param string $name
+ * @param string $dir
+ * @param boolean $onlyHeader
*/
private static function getSingleFile($view, $dir, $name, $onlyHeader) {
$filename = $dir . '/' . $name;
@@ -179,7 +187,7 @@ class OC_Files {
/**
* @param View $view
- * @param $dir
+ * @param string $dir
* @param string[]|string $files
*/
public static function lockFiles($view, $dir, $files) {
@@ -284,11 +292,11 @@ class OC_Files {
}
/**
- * @param $dir
+ * @param string $dir
* @param $files
- * @param $getType
+ * @param integer $getType
* @param View $view
- * @param $filename
+ * @param string $filename
*/
private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) {
if ($getType === self::FILE) {
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php
index 40477243324..22b9f49e528 100644
--- a/lib/private/files/cache/cache.php
+++ b/lib/private/files/cache/cache.php
@@ -1,7 +1,6 @@
<?php
/**
* @author Andreas Fischer <bantu@owncloud.com>
- * @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
* @author Florin Peter <github@florin-peter.de>
* @author Jens-Christian Fischer <jens-christian.fischer@switch.ch>
@@ -10,12 +9,12 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author TheSFReader <TheSFReader@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -34,6 +33,8 @@
namespace OC\Files\Cache;
+use OCP\Files\Cache\ICache;
+use OCP\Files\Cache\ICacheEntry;
use \OCP\Files\IMimeTypeLoader;
use OCP\IDBConnection;
@@ -47,11 +48,10 @@ use OCP\IDBConnection;
* - Updater: listens to changes made to the filesystem inside of the ownCloud instance and updates the cache where needed
* - ChangePropagator: updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater
*/
-class Cache {
- const NOT_FOUND = 0;
- const PARTIAL = 1; //only partial data available, file not cached in the database
- const SHALLOW = 2; //folder in cache, but not all child files are completely scanned
- const COMPLETE = 3;
+class Cache implements ICache {
+ use MoveFromCacheTrait {
+ MoveFromCacheTrait::moveFromCache as moveFromCacheFallback;
+ }
/**
* @var array partial data for the cache
@@ -106,28 +106,8 @@ class Cache {
/**
* get the stored metadata of a file or folder
*
- * the returned cache entry contains at least the following values:
- * [
- * 'fileid' => int, the numeric id of a file (see getId)
- * 'storage' => int, the numeric id of the storage the file is stored on
- * 'path' => string, the path of the file within the storage ('foo/bar.txt')
- * 'name' => string, the basename of a file ('bar.txt)
- * 'mimetype' => string, the full mimetype of the file ('text/plain')
- * 'mimepart' => string, the first half of the mimetype ('text')
- * 'size' => int, the size of the file or folder in bytes
- * 'mtime' => int, the last modified date of the file as unix timestamp as shown in the ui
- * 'storage_mtime' => int, the last modified date of the file as unix timestamp as stored on the storage
- * Note that when a file is updated we also update the mtime of all parent folders to make it visible to the user which folder has had updates most recently
- * This can differ from the mtime on the underlying storage which usually only changes when a direct child is added, removed or renamed
- * 'etag' => string, the etag for the file
- * An etag is used for change detection of files and folders, an etag of a file changes whenever the content of the file changes
- * Etag for folders change whenever a file in the folder has changed
- * 'permissions' int, the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE
- * \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE
- * ]
- *
* @param string | int $file either the path of a file or folder or the file id for a file or folder
- * @return array|false the cache entry as array of false if the file is not found in the cache
+ * @return ICacheEntry|false the cache entry as array of false if the file is not found in the cache
*/
public function get($file) {
if (is_string($file) or $file == '') {
@@ -141,7 +121,7 @@ class Cache {
$params = array($file);
}
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
- `storage_mtime`, `encrypted`, `etag`, `permissions`
+ `storage_mtime`, `encrypted`, `etag`, `permissions`, `checksum`
FROM `*PREFIX*filecache` ' . $where;
$result = $this->connection->executeQuery($sql, $params);
$data = $result->fetch();
@@ -157,9 +137,11 @@ class Cache {
if (isset($this->partial[$file])) {
$data = $this->partial[$file];
}
+ return $data;
} else {
//fix types
$data['fileid'] = (int)$data['fileid'];
+ $data['parent'] = (int)$data['parent'];
$data['size'] = 0 + $data['size'];
$data['mtime'] = (int)$data['mtime'];
$data['storage_mtime'] = (int)$data['storage_mtime'];
@@ -171,16 +153,15 @@ class Cache {
$data['storage_mtime'] = $data['mtime'];
}
$data['permissions'] = (int)$data['permissions'];
+ return new CacheEntry($data);
}
-
- return $data;
}
/**
* get the metadata of all files stored in $folder
*
* @param string $folder
- * @return array
+ * @return ICacheEntry[]
*/
public function getFolderContents($folder) {
$fileId = $this->getId($folder);
@@ -191,12 +172,12 @@ class Cache {
* get the metadata of all files stored in $folder
*
* @param int $fileId the file id of the folder
- * @return array
+ * @return ICacheEntry[]
*/
public function getFolderContentsById($fileId) {
if ($fileId > -1) {
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
- `storage_mtime`, `encrypted`, `etag`, `permissions`
+ `storage_mtime`, `encrypted`, `etag`, `permissions`, `checksum`
FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC';
$result = $this->connection->executeQuery($sql, [$fileId]);
$files = $result->fetchAll();
@@ -211,14 +192,16 @@ class Cache {
$file['storage_mtime'] = (int)$file['storage_mtime'];
$file['size'] = 0 + $file['size'];
}
- return $files;
+ return array_map(function (array $data) {
+ return new CacheEntry($data);
+ }, $files);
} else {
return array();
}
}
/**
- * store meta data for a file or folder
+ * insert or update meta data for a file or folder
*
* @param string $file
* @param array $data
@@ -231,49 +214,62 @@ class Cache {
$this->update($id, $data);
return $id;
} else {
- // normalize file
- $file = $this->normalize($file);
+ return $this->insert($file, $data);
+ }
+ }
- if (isset($this->partial[$file])) { //add any saved partial data
- $data = array_merge($this->partial[$file], $data);
- unset($this->partial[$file]);
- }
+ /**
+ * insert meta data for a new file or folder
+ *
+ * @param string $file
+ * @param array $data
+ *
+ * @return int file id
+ * @throws \RuntimeException
+ */
+ public function insert($file, array $data) {
+ // normalize file
+ $file = $this->normalize($file);
- $requiredFields = array('size', 'mtime', 'mimetype');
- foreach ($requiredFields as $field) {
- if (!isset($data[$field])) { //data not complete save as partial and return
- $this->partial[$file] = $data;
- return -1;
- }
- }
+ if (isset($this->partial[$file])) { //add any saved partial data
+ $data = array_merge($this->partial[$file], $data);
+ unset($this->partial[$file]);
+ }
- $data['path'] = $file;
- $data['parent'] = $this->getParentId($file);
- $data['name'] = \OC_Util::basename($file);
-
- list($queryParts, $params) = $this->buildParts($data);
- $queryParts[] = '`storage`';
- $params[] = $this->getNumericStorageId();
-
- $queryParts = array_map(function ($item) {
- return trim($item, "`");
- }, $queryParts);
- $values = array_combine($queryParts, $params);
- if (\OC::$server->getDatabaseConnection()->insertIfNotExist('*PREFIX*filecache', $values, [
- 'storage',
- 'path_hash',
- ])
- ) {
- return (int)$this->connection->lastInsertId('*PREFIX*filecache');
+ $requiredFields = array('size', 'mtime', 'mimetype');
+ foreach ($requiredFields as $field) {
+ if (!isset($data[$field])) { //data not complete save as partial and return
+ $this->partial[$file] = $data;
+ return -1;
}
+ }
- // The file was created in the mean time
- if (($id = $this->getId($file)) > -1) {
- $this->update($id, $data);
- return $id;
- } else {
- throw new \RuntimeException('File entry could not be inserted with insertIfNotExist() but could also not be selected with getId() in order to perform an update. Please try again.');
- }
+ $data['path'] = $file;
+ $data['parent'] = $this->getParentId($file);
+ $data['name'] = \OC_Util::basename($file);
+
+ list($queryParts, $params) = $this->buildParts($data);
+ $queryParts[] = '`storage`';
+ $params[] = $this->getNumericStorageId();
+
+ $queryParts = array_map(function ($item) {
+ return trim($item, "`");
+ }, $queryParts);
+ $values = array_combine($queryParts, $params);
+ if (\OC::$server->getDatabaseConnection()->insertIfNotExist('*PREFIX*filecache', $values, [
+ 'storage',
+ 'path_hash',
+ ])
+ ) {
+ return (int)$this->connection->lastInsertId('*PREFIX*filecache');
+ }
+
+ // The file was created in the mean time
+ if (($id = $this->getId($file)) > -1) {
+ $this->update($id, $data);
+ return $id;
+ } else {
+ throw new \RuntimeException('File entry could not be inserted with insertIfNotExist() but could also not be selected with getId() in order to perform an update. Please try again.');
}
}
@@ -304,7 +300,10 @@ class Cache {
// don't update if the data we try to set is the same as the one in the record
// some databases (Postgres) don't like superfluous updates
$sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? ' .
- 'WHERE (' . implode(' <> ? OR ', $queryParts) . ' <> ? ) AND `fileid` = ? ';
+ 'WHERE (' .
+ implode(' <> ? OR ', $queryParts) . ' <> ? OR ' .
+ implode(' IS NULL OR ', $queryParts) . ' IS NULL' .
+ ') AND `fileid` = ? ';
$this->connection->executeQuery($sql, $params);
}
@@ -320,7 +319,7 @@ class Cache {
protected function buildParts(array $data) {
$fields = array(
'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted',
- 'etag', 'permissions');
+ 'etag', 'permissions', 'checksum');
$doNotCopyStorageMTime = false;
if (array_key_exists('mtime', $data) && $data['mtime'] === null) {
@@ -391,12 +390,17 @@ class Cache {
if ($file === '') {
return -1;
} else {
- $parent = dirname($file);
- if ($parent === '.') {
- $parent = '';
- }
- return $this->getId($parent);
+ $parent = $this->getParentPath($file);
+ return (int)$this->getId($parent);
+ }
+ }
+
+ private function getParentPath($path) {
+ $parent = dirname($path);
+ if ($parent === '.') {
+ $parent = '';
}
+ return $parent;
}
/**
@@ -476,45 +480,48 @@ class Cache {
/**
* Move a file or folder in the cache
*
- * @param \OC\Files\Cache\Cache $sourceCache
+ * @param \OCP\Files\Cache\ICache $sourceCache
* @param string $sourcePath
* @param string $targetPath
* @throws \OC\DatabaseException
*/
- public function moveFromCache(Cache $sourceCache, $sourcePath, $targetPath) {
- // normalize source and target
- $sourcePath = $this->normalize($sourcePath);
- $targetPath = $this->normalize($targetPath);
-
- $sourceData = $sourceCache->get($sourcePath);
- $sourceId = $sourceData['fileid'];
- $newParentId = $this->getParentId($targetPath);
-
- list($sourceStorageId, $sourcePath) = $sourceCache->getMoveInfo($sourcePath);
- list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath);
-
- // sql for final update
- $moveSql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?';
-
- if ($sourceData['mimetype'] === 'httpd/unix-directory') {
- //find all child entries
- $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?';
- $result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath) . '/%']);
- $childEntries = $result->fetchAll();
- $sourceLength = strlen($sourcePath);
- $this->connection->beginTransaction();
- $query = $this->connection->prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?');
-
- foreach ($childEntries as $child) {
- $newTargetPath = $targetPath . substr($child['path'], $sourceLength);
- $query->execute([$targetStorageId, $newTargetPath, md5($newTargetPath), $child['fileid']]);
+ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
+ if ($sourceCache instanceof Cache) {
+ // normalize source and target
+ $sourcePath = $this->normalize($sourcePath);
+ $targetPath = $this->normalize($targetPath);
+
+ $sourceData = $sourceCache->get($sourcePath);
+ $sourceId = $sourceData['fileid'];
+ $newParentId = $this->getParentId($targetPath);
+
+ list($sourceStorageId, $sourcePath) = $sourceCache->getMoveInfo($sourcePath);
+ list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath);
+
+ // sql for final update
+ $moveSql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?';
+
+ if ($sourceData['mimetype'] === 'httpd/unix-directory') {
+ //find all child entries
+ $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?';
+ $result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath) . '/%']);
+ $childEntries = $result->fetchAll();
+ $sourceLength = strlen($sourcePath);
+ $this->connection->beginTransaction();
+ $query = $this->connection->prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?');
+
+ foreach ($childEntries as $child) {
+ $newTargetPath = $targetPath . substr($child['path'], $sourceLength);
+ $query->execute([$targetStorageId, $newTargetPath, md5($newTargetPath), $child['fileid']]);
+ }
+ $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
+ $this->connection->commit();
+ } else {
+ $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
}
- $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
- $this->connection->commit();
} else {
- $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
+ $this->moveFromCacheFallback($sourceCache, $sourcePath, $targetPath);
}
-
}
/**
@@ -566,7 +573,7 @@ class Cache {
* search for files matching $pattern
*
* @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%')
- * @return array an array of cache entries where the name matches the search pattern
+ * @return ICacheEntry[] an array of cache entries where the name matches the search pattern
*/
public function search($pattern) {
// normalize pattern
@@ -576,7 +583,7 @@ class Cache {
$sql = '
SELECT `fileid`, `storage`, `path`, `parent`, `name`,
`mimetype`, `mimepart`, `size`, `mtime`, `encrypted`,
- `etag`, `permissions`
+ `etag`, `permissions`, `checksum`
FROM `*PREFIX*filecache`
WHERE `storage` = ? AND `name` ILIKE ?';
$result = $this->connection->executeQuery($sql,
@@ -589,7 +596,9 @@ class Cache {
$row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']);
$files[] = $row;
}
- return $files;
+ return array_map(function(array $data) {
+ return new CacheEntry($data);
+ }, $files);
}
/**
@@ -597,7 +606,7 @@ class Cache {
*
* @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image')
* where it will search for all mimetypes in the group ('image/*')
- * @return array an array of cache entries where the mimetype matches the search
+ * @return ICacheEntry[] an array of cache entries where the mimetype matches the search
*/
public function searchByMime($mimetype) {
if (strpos($mimetype, '/')) {
@@ -605,7 +614,7 @@ class Cache {
} else {
$where = '`mimepart` = ?';
}
- $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`, `permissions`
+ $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`, `permissions`, `checksum`
FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?';
$mimetype = $this->mimetypeLoader->getId($mimetype);
$result = $this->connection->executeQuery($sql, array($mimetype, $this->getNumericStorageId()));
@@ -615,7 +624,9 @@ class Cache {
$row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']);
$files[] = $row;
}
- return $files;
+ return array_map(function (array $data) {
+ return new CacheEntry($data);
+ }, $files);
}
/**
@@ -625,12 +636,12 @@ class Cache {
*
* @param string|int $tag name or tag id
* @param string $userId owner of the tags
- * @return array file data
+ * @return ICacheEntry[] file data
*/
public function searchByTag($tag, $userId) {
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
'`mimetype`, `mimepart`, `size`, `mtime`, ' .
- '`encrypted`, `etag`, `permissions` ' .
+ '`encrypted`, `etag`, `permissions`, `checksum` ' .
'FROM `*PREFIX*filecache` `file`, ' .
'`*PREFIX*vcategory_to_object` `tagmap`, ' .
'`*PREFIX*vcategory` `tag` ' .
@@ -660,7 +671,9 @@ class Cache {
while ($row = $result->fetch()) {
$files[] = $row;
}
- return $files;
+ return array_map(function (array $data) {
+ return new CacheEntry($data);
+ }, $files);
}
/**
diff --git a/lib/private/files/cache/cacheentry.php b/lib/private/files/cache/cacheentry.php
new file mode 100644
index 00000000000..3db3b3f8aa0
--- /dev/null
+++ b/lib/private/files/cache/cacheentry.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Files\Cache;
+
+use OCP\Files\Cache\ICacheEntry;
+
+/**
+ * meta data for a file or folder
+ */
+class CacheEntry implements ICacheEntry, \ArrayAccess {
+ /**
+ * @var array
+ */
+ private $data;
+
+ public function __construct(array $data) {
+ $this->data = $data;
+ }
+
+ public function offsetSet($offset, $value) {
+ $this->data[$offset] = $value;
+ }
+
+ public function offsetExists($offset) {
+ return isset($this->data[$offset]);
+ }
+
+ public function offsetUnset($offset) {
+ unset($this->data[$offset]);
+ }
+
+ public function offsetGet($offset) {
+ if (isset($this->data[$offset])) {
+ return $this->data[$offset];
+ } else {
+ return null;
+ }
+ }
+
+ public function getId() {
+ return (int)$this->data['fileid'];
+ }
+
+ public function getStorageId() {
+ return $this->data['storage'];
+ }
+
+
+ public function getPath() {
+ return $this->data['path'];
+ }
+
+
+ public function getName() {
+ return $this->data['name'];
+ }
+
+
+ public function getMimeType() {
+ return $this->data['mimetype'];
+ }
+
+
+ public function getMimePart() {
+ return $this->data['mimepart'];
+ }
+
+ public function getSize() {
+ return $this->data['size'];
+ }
+
+ public function getMTime() {
+ return $this->data['mtime'];
+ }
+
+ public function getStorageMTime() {
+ return $this->data['storage_mtime'];
+ }
+
+ public function getEtag() {
+ return $this->data['etag'];
+ }
+
+ public function getPermissions() {
+ return $this->data['permissions'];
+ }
+
+ public function isEncrypted() {
+ return isset($this->data['encrypted']) && $this->data['encrypted'];
+ }
+
+ public function getData() {
+ return $this->data;
+ }
+}
diff --git a/lib/private/files/cache/changepropagator.php b/lib/private/files/cache/changepropagator.php
deleted file mode 100644
index 9696a82257e..00000000000
--- a/lib/private/files/cache/changepropagator.php
+++ /dev/null
@@ -1,117 +0,0 @@
-<?php
-/**
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OC\Files\Cache;
-
-use OC\Hooks\BasicEmitter;
-
-/**
- * Propagates changes in etag and mtime up the filesystem tree
- *
- * @package OC\Files\Cache
- */
-class ChangePropagator extends BasicEmitter {
- /**
- * @var string[]
- */
- protected $changedFiles = array();
-
- /**
- * @var \OC\Files\View
- */
- protected $view;
-
- /**
- * @param \OC\Files\View $view
- */
- public function __construct(\OC\Files\View $view) {
- $this->view = $view;
- }
-
- public function addChange($path) {
- $this->changedFiles[] = $path;
- }
-
- public function getChanges() {
- return $this->changedFiles;
- }
-
- /**
- * propagate the registered changes to their parent folders
- *
- * @param int $time (optional) the mtime to set for the folders, if not set the current time is used
- */
- public function propagateChanges($time = null) {
- $parents = $this->getAllParents();
- $this->changedFiles = array();
- if (!$time) {
- $time = time();
- }
- foreach ($parents as $parent) {
- /**
- * @var \OC\Files\Storage\Storage $storage
- * @var string $internalPath
- */
-
- list($storage, $internalPath) = $this->view->resolvePath($parent);
- if ($storage) {
- $cache = $storage->getCache();
- $entry = $cache->get($internalPath);
- $cache->update($entry['fileid'], array('mtime' => max($time, $entry['mtime']), 'etag' => $storage->getETag($internalPath)));
- $this->emit('\OC\Files', 'propagate', [$parent, $entry]);
- }
- }
- }
-
- /**
- * @return string[]
- */
- public function getAllParents() {
- $parents = array();
- foreach ($this->getChanges() as $path) {
- $parents = array_values(array_unique(array_merge($parents, $this->getParents($path))));
- }
- return $parents;
- }
-
- /**
- * get all parent folders of $path
- *
- * @param string $path
- * @return string[]
- */
- protected function getParents($path) {
- $parts = explode('/', $path);
-
- // remove the singe file
- array_pop($parts);
- $result = array('/');
- $resultPath = '';
- foreach ($parts as $part) {
- if ($part) {
- $resultPath .= '/' . $part;
- $result[] = $resultPath;
- }
- }
- return $result;
- }
-}
diff --git a/lib/private/files/cache/homecache.php b/lib/private/files/cache/homecache.php
index 1b85462d615..ae92504ddd6 100644
--- a/lib/private/files/cache/homecache.php
+++ b/lib/private/files/cache/homecache.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +26,8 @@
namespace OC\Files\Cache;
+use OCP\Files\Cache\ICacheEntry;
+
class HomeCache extends Cache {
/**
* get the size of a folder and set it in the cache
@@ -67,7 +69,7 @@ class HomeCache extends Cache {
/**
* @param string $path
- * @return array
+ * @return ICacheEntry
*/
public function get($path) {
$data = parent::get($path);
diff --git a/lib/private/files/cache/movefromcachetrait.php b/lib/private/files/cache/movefromcachetrait.php
new file mode 100644
index 00000000000..7d8ed7b5d21
--- /dev/null
+++ b/lib/private/files/cache/movefromcachetrait.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Files\Cache;
+
+use OCP\Files\Cache\ICache;
+use OCP\Files\Cache\ICacheEntry;
+
+/**
+ * Fallback implementation for moveFromCache
+ */
+trait MoveFromCacheTrait {
+ /**
+ * store meta data for a file or folder
+ *
+ * @param string $file
+ * @param array $data
+ *
+ * @return int file id
+ * @throws \RuntimeException
+ */
+ abstract public function put($file, array $data);
+
+ /**
+ * Move a file or folder in the cache
+ *
+ * @param \OCP\Files\Cache\ICache $sourceCache
+ * @param string $sourcePath
+ * @param string $targetPath
+ */
+ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
+ $sourceEntry = $sourceCache->get($sourcePath);
+
+ $this->copyFromCache($sourceCache, $sourceEntry, $targetPath);
+
+ $sourceCache->remove($sourcePath);
+ }
+
+ /**
+ * Copy a file or folder in the cache
+ *
+ * @param \OCP\Files\Cache\ICache $sourceCache
+ * @param ICacheEntry $sourceEntry
+ * @param string $targetPath
+ */
+ public function copyFromCache(ICache $sourceCache, ICacheEntry $sourceEntry, $targetPath) {
+ $this->put($targetPath, $this->cacheEntryToArray($sourceEntry));
+ if ($sourceEntry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE) {
+ $folderContent = $sourceCache->getFolderContentsById($sourceEntry->getId());
+ foreach ($folderContent as $subEntry) {
+ $subTargetPath = $targetPath . '/' . $subEntry->getName();
+ $this->copyFromCache($sourceCache, $subEntry, $subTargetPath);
+ }
+ }
+ }
+
+ private function cacheEntryToArray(ICacheEntry $entry) {
+ return [
+ 'size' => $entry->getSize(),
+ 'mtime' => $entry->getMTime(),
+ 'storage_mtime' => $entry->getStorageMTime(),
+ 'mimetype' => $entry->getMimeType(),
+ 'mimepart' => $entry->getMimePart(),
+ 'etag' => $entry->getEtag(),
+ 'permissions' => $entry->getPermissions(),
+ 'encrypted' => $entry->isEncrypted()
+ ];
+ }
+}
diff --git a/lib/private/files/cache/propagator.php b/lib/private/files/cache/propagator.php
new file mode 100644
index 00000000000..50264e54d44
--- /dev/null
+++ b/lib/private/files/cache/propagator.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Files\Cache;
+
+use OCP\Files\Cache\IPropagator;
+
+/**
+ * Propagate etags and mtimes within the storage
+ */
+class Propagator implements IPropagator {
+ /**
+ * @var \OC\Files\Storage\Storage
+ */
+ protected $storage;
+
+ /**
+ * @param \OC\Files\Storage\Storage $storage
+ */
+ public function __construct(\OC\Files\Storage\Storage $storage) {
+ $this->storage = $storage;
+ }
+
+
+ /**
+ * @param string $internalPath
+ * @param int $time
+ * @param int $sizeDifference number of bytes the file has grown
+ * @return array[] all propagated entries
+ */
+ public function propagateChange($internalPath, $time, $sizeDifference = 0) {
+ $cache = $this->storage->getCache($internalPath);
+
+ $parentId = $cache->getParentId($internalPath);
+ $propagatedEntries = [];
+ while ($parentId !== -1) {
+ $entry = $cache->get($parentId);
+ $propagatedEntries[] = $entry;
+ if (!$entry) {
+ return $propagatedEntries;
+ }
+ $mtime = max($time, $entry['mtime']);
+
+ if ($entry['size'] === -1) {
+ $newSize = -1;
+ } else {
+ $newSize = $entry['size'] + $sizeDifference;
+ }
+ $cache->update($parentId, ['mtime' => $mtime, 'etag' => $this->storage->getETag($entry['path']), 'size' => $newSize]);
+
+ $parentId = $entry['parent'];
+ }
+
+ return $propagatedEntries;
+ }
+}
diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php
index 35043029dc3..60daa323b4b 100644
--- a/lib/private/files/cache/scanner.php
+++ b/lib/private/files/cache/scanner.php
@@ -2,6 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Björn Schießle <schiessle@owncloud.com>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Martin Mattel <martin.mattel@diemattels.at>
@@ -10,11 +11,11 @@
* @author Olivier Paroz <github@oparoz.com>
* @author Owen Winkler <a_github@midnightcircus.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -36,6 +37,8 @@ namespace OC\Files\Cache;
use OC\Files\Filesystem;
use OC\Hooks\BasicEmitter;
use OCP\Config;
+use OCP\Files\Cache\IScanner;
+use OCP\Files\Storage\ILockingStorage;
use OCP\Lock\ILockingProvider;
/**
@@ -49,7 +52,7 @@ use OCP\Lock\ILockingProvider;
*
* @package OC\Files\Cache
*/
-class Scanner extends BasicEmitter {
+class Scanner extends BasicEmitter implements IScanner {
/**
* @var \OC\Files\Storage\Storage $storage
*/
@@ -80,12 +83,6 @@ class Scanner extends BasicEmitter {
*/
protected $lockingProvider;
- const SCAN_RECURSIVE = true;
- const SCAN_SHALLOW = false;
-
- const REUSE_ETAG = 1;
- const REUSE_SIZE = 2;
-
public function __construct(\OC\Files\Storage\Storage $storage) {
$this->storage = $storage;
$this->storageId = $this->storage->getId();
@@ -111,7 +108,7 @@ class Scanner extends BasicEmitter {
* @param string $path
* @return array an array of metadata of the file
*/
- public function getData($path) {
+ protected function getData($path) {
$data = $this->storage->getMetaData($path);
if (is_null($data)) {
\OCP\Util::writeLog('OC\Files\Cache\Scanner', "!!! Path '$path' is not accessible or present !!!", \OCP\Util::DEBUG);
@@ -132,16 +129,27 @@ class Scanner extends BasicEmitter {
* @throws \OCP\Lock\LockedException
*/
public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) {
- if (!self::isPartialFile($file)
- and !Filesystem::isFileBlacklisted($file)
- ) {
+
+ // only proceed if $file is not a partial file nor a blacklisted file
+ if (!self::isPartialFile($file) and !Filesystem::isFileBlacklisted($file)) {
+
+ //acquire a lock
if ($lock) {
- $this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
+ if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
+ }
}
- $this->emit('\OC\Files\Cache\Scanner', 'scanFile', array($file, $this->storageId));
- \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId));
+
$data = $this->getData($file);
+
if ($data) {
+
+ // pre-emit only if it was a file. By that we avoid counting/treating folders as files
+ if ($data['mimetype'] !== 'httpd/unix-directory') {
+ $this->emit('\OC\Files\Cache\Scanner', 'scanFile', array($file, $this->storageId));
+ \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId));
+ }
+
$parent = dirname($file);
if ($parent === '.' or $parent === '/') {
$parent = '';
@@ -159,6 +167,7 @@ class Scanner extends BasicEmitter {
$data['parent'] = $parentId;
}
if (is_null($cacheData)) {
+ /** @var CacheEntry $cacheData */
$cacheData = $this->cache->get($file);
}
if ($cacheData and $reuseExisting and isset($cacheData['fileid'])) {
@@ -181,7 +190,7 @@ class Scanner extends BasicEmitter {
}
}
// Only update metadata that has changed
- $newData = array_diff_assoc($data, $cacheData);
+ $newData = array_diff_assoc($data, $cacheData->getData());
} else {
$newData = $data;
$fileId = -1;
@@ -189,16 +198,28 @@ class Scanner extends BasicEmitter {
if (!empty($newData)) {
$data['fileid'] = $this->addToCache($file, $newData, $fileId);
}
- $this->emit('\OC\Files\Cache\Scanner', 'postScanFile', array($file, $this->storageId));
- \OC_Hook::emit('\OC\Files\Cache\Scanner', 'post_scan_file', array('path' => $file, 'storage' => $this->storageId));
+ $data['oldSize'] = $cacheData['size'];
+
+ // post-emit only if it was a file. By that we avoid counting/treating folders as files
+ if ($data['mimetype'] !== 'httpd/unix-directory') {
+ $this->emit('\OC\Files\Cache\Scanner', 'postScanFile', array($file, $this->storageId));
+ \OC_Hook::emit('\OC\Files\Cache\Scanner', 'post_scan_file', array('path' => $file, 'storage' => $this->storageId));
+ }
+
} else {
$this->removeFromCache($file);
}
+
+ //release the acquired lock
if ($lock) {
- $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
+ if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
+ }
}
+
return $data;
}
+
return null;
}
@@ -262,7 +283,9 @@ class Scanner extends BasicEmitter {
$reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG;
}
if ($lock) {
- $this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
+ if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
+ }
}
$data = $this->scanFile($path, $reuse, -1, null, $lock);
if ($data and $data['mimetype'] === 'httpd/unix-directory') {
@@ -270,7 +293,9 @@ class Scanner extends BasicEmitter {
$data['size'] = $size;
}
if ($lock) {
- $this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
+ if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
+ }
}
return $data;
}
@@ -336,7 +361,7 @@ class Scanner extends BasicEmitter {
$newChildren = $this->getNewChildren($path);
if ($this->useTransactions) {
- \OC_DB::beginTransaction();
+ \OC::$server->getDatabaseConnection()->beginTransaction();
}
$exceptionOccurred = false;
foreach ($newChildren as $file) {
@@ -361,7 +386,7 @@ class Scanner extends BasicEmitter {
$exceptionOccurred = true;
} catch (\OCP\Lock\LockedException $e) {
if ($this->useTransactions) {
- \OC_DB::rollback();
+ \OC::$server->getDatabaseConnection()->rollback();
}
throw $e;
}
@@ -372,7 +397,7 @@ class Scanner extends BasicEmitter {
$this->removeFromCache($child);
}
if ($this->useTransactions) {
- \OC_DB::commit();
+ \OC::$server->getDatabaseConnection()->commit();
}
if ($exceptionOccurred) {
// It might happen that the parallel scan process has already
@@ -432,6 +457,8 @@ class Scanner extends BasicEmitter {
// skip unavailable storages
} catch (\OCP\Files\StorageNotAvailableException $e) {
// skip unavailable storages
+ } catch (\OCP\Files\ForbiddenException $e) {
+ // skip forbidden storages
} catch (\OCP\Lock\LockedException $e) {
// skip unavailable storages
}
diff --git a/lib/private/files/cache/storage.php b/lib/private/files/cache/storage.php
index cee69194095..90c451ecc21 100644
--- a/lib/private/files/cache/storage.php
+++ b/lib/private/files/cache/storage.php
@@ -4,11 +4,11 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -58,10 +58,10 @@ class Storage {
if ($row = self::getStorageById($this->storageId)) {
$this->numericId = $row['numeric_id'];
} else {
- $connection = \OC_DB::getConnection();
+ $connection = \OC::$server->getDatabaseConnection();
$available = $isAvailable ? 1 : 0;
if ($connection->insertIfNotExist('*PREFIX*storages', ['id' => $this->storageId, 'available' => $available])) {
- $this->numericId = \OC_DB::insertid('*PREFIX*storages');
+ $this->numericId = $connection->lastInsertId('*PREFIX*storages');
} else {
if ($row = self::getStorageById($this->storageId)) {
$this->numericId = $row['numeric_id'];
diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php
index 85dcc8589de..80ba704883e 100644
--- a/lib/private/files/cache/updater.php
+++ b/lib/private/files/cache/updater.php
@@ -1,13 +1,12 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,35 +24,47 @@
*/
namespace OC\Files\Cache;
+use OCP\Files\Cache\IUpdater;
+use OCP\Files\Storage\IStorage;
/**
* Update the cache and propagate changes
*
- * Unlike most other classes an Updater is not related to a specific storage but handles updates for all storages in a users filesystem.
- * This is needed because the propagation of mtime and etags need to cross storage boundaries
*/
-class Updater {
+class Updater implements IUpdater {
/**
* @var bool
*/
protected $enabled = true;
/**
- * @var \OC\Files\View
+ * @var \OC\Files\Storage\Storage
*/
- protected $view;
+ protected $storage;
/**
- * @var \OC\Files\Cache\ChangePropagator
+ * @var \OC\Files\Cache\Propagator
*/
protected $propagator;
/**
- * @param \OC\Files\View $view the view the updater works on, usually the view of the logged in user
+ * @var Scanner
*/
- public function __construct($view) {
- $this->view = $view;
- $this->propagator = new ChangePropagator($view);
+ protected $scanner;
+
+ /**
+ * @var Cache
+ */
+ protected $cache;
+
+ /**
+ * @param \OC\Files\Storage\Storage $storage
+ */
+ public function __construct(\OC\Files\Storage\Storage $storage) {
+ $this->storage = $storage;
+ $this->propagator = $storage->getPropagator();
+ $this->scanner = $storage->getScanner();
+ $this->cache = $storage->getCache();
}
/**
@@ -73,7 +84,7 @@ class Updater {
/**
* Get the propagator for etags and mtime for the view the updater works on
*
- * @return ChangePropagator
+ * @return Propagator
*/
public function getPropagator() {
return $this->propagator;
@@ -89,8 +100,7 @@ class Updater {
if (Scanner::isPartialFile($path)) {
return;
}
- $this->propagator->addChange($path);
- $this->propagator->propagateChanges($time);
+ $this->propagator->propagateChange($path, $time);
}
/**
@@ -103,20 +113,20 @@ class Updater {
if (!$this->enabled or Scanner::isPartialFile($path)) {
return;
}
- /**
- * @var \OC\Files\Storage\Storage $storage
- * @var string $internalPath
- */
- list($storage, $internalPath) = $this->view->resolvePath($path);
- if ($storage) {
- $this->propagator->addChange($path);
- $cache = $storage->getCache($internalPath);
- $scanner = $storage->getScanner($internalPath);
- $data = $scanner->scan($internalPath, Scanner::SCAN_SHALLOW, -1, false);
- $this->correctParentStorageMtime($storage, $internalPath);
- $cache->correctFolderSize($internalPath, $data);
- $this->propagator->propagateChanges($time);
+ if (is_null($time)) {
+ $time = time();
+ }
+
+ $data = $this->scanner->scan($path, Scanner::SCAN_SHALLOW, -1, false);
+ if (isset($data['oldSize']) && isset($data['size'])) {
+ $sizeDifference = $data['size'] - $data['oldSize'];
+ } else {
+ // scanner didn't provide size info, fallback to full size calculation
+ $sizeDifference = 0;
+ $this->cache->correctFolderSize($path, $data);
}
+ $this->correctParentStorageMtime($path);
+ $this->propagator->propagateChange($path, $time, $sizeDifference);
}
/**
@@ -128,87 +138,73 @@ class Updater {
if (!$this->enabled or Scanner::isPartialFile($path)) {
return;
}
- /**
- * @var \OC\Files\Storage\Storage $storage
- * @var string $internalPath
- */
- list($storage, $internalPath) = $this->view->resolvePath($path);
- if ($storage) {
- $parent = dirname($internalPath);
- if ($parent === '.') {
- $parent = '';
- }
- $this->propagator->addChange($path);
- $cache = $storage->getCache($internalPath);
- $cache->remove($internalPath);
- $cache->correctFolderSize($parent);
- $this->correctParentStorageMtime($storage, $internalPath);
- $this->propagator->propagateChanges();
+
+ $parent = dirname($path);
+ if ($parent === '.') {
+ $parent = '';
}
+
+ $this->cache->remove($path);
+ $this->cache->correctFolderSize($parent);
+ $this->correctParentStorageMtime($path);
+ $this->propagator->propagateChange($path, time());
}
/**
* Rename a file or folder in the cache and update the size, etag and mtime of the parent folders
*
+ * @param IStorage $sourceStorage
* @param string $source
* @param string $target
*/
- public function rename($source, $target) {
+ public function renameFromStorage(IStorage $sourceStorage, $source, $target) {
if (!$this->enabled or Scanner::isPartialFile($source) or Scanner::isPartialFile($target)) {
return;
}
- /**
- * @var \OC\Files\Storage\Storage $sourceStorage
- * @var \OC\Files\Storage\Storage $targetStorage
- * @var string $sourceInternalPath
- * @var string $targetInternalPath
- */
- list($sourceStorage, $sourceInternalPath) = $this->view->resolvePath($source);
- // if it's a moved mountpoint we dont need to do anything
- if ($sourceInternalPath === '') {
- return;
- }
- list($targetStorage, $targetInternalPath) = $this->view->resolvePath($target);
-
- if ($sourceStorage && $targetStorage) {
- $targetCache = $targetStorage->getCache($sourceInternalPath);
- if ($sourceStorage->getCache($sourceInternalPath)->inCache($sourceInternalPath)) {
- if ($targetCache->inCache($targetInternalPath)) {
- $targetCache->remove($targetInternalPath);
- }
- if ($sourceStorage === $targetStorage) {
- $targetCache->move($sourceInternalPath, $targetInternalPath);
- } else {
- $targetCache->moveFromCache($sourceStorage->getCache(), $sourceInternalPath, $targetInternalPath);
- }
+
+ $time = time();
+
+ $sourceCache = $sourceStorage->getCache();
+ $sourceUpdater = $sourceStorage->getUpdater();
+ $sourcePropagator = $sourceStorage->getPropagator();
+
+ if ($sourceCache->inCache($source)) {
+ if ($this->cache->inCache($target)) {
+ $this->cache->remove($target);
}
- if (pathinfo($sourceInternalPath, PATHINFO_EXTENSION) !== pathinfo($targetInternalPath, PATHINFO_EXTENSION)) {
- // handle mime type change
- $mimeType = $targetStorage->getMimeType($targetInternalPath);
- $fileId = $targetCache->getId($targetInternalPath);
- $targetCache->update($fileId, array('mimetype' => $mimeType));
+ if ($sourceStorage === $this->storage) {
+ $this->cache->move($source, $target);
+ } else {
+ $this->cache->moveFromCache($sourceCache, $source, $target);
}
+ }
- $targetCache->correctFolderSize($sourceInternalPath);
- $targetCache->correctFolderSize($targetInternalPath);
- $this->correctParentStorageMtime($sourceStorage, $sourceInternalPath);
- $this->correctParentStorageMtime($targetStorage, $targetInternalPath);
- $this->updateStorageMTimeOnly($targetStorage, $targetInternalPath);
- $this->propagator->addChange($source);
- $this->propagator->addChange($target);
- $this->propagator->propagateChanges();
+ if (pathinfo($source, PATHINFO_EXTENSION) !== pathinfo($target, PATHINFO_EXTENSION)) {
+ // handle mime type change
+ $mimeType = $this->storage->getMimeType($target);
+ $fileId = $this->cache->getId($target);
+ $this->cache->update($fileId, ['mimetype' => $mimeType]);
}
+
+ $sourceCache->correctFolderSize($source);
+ $this->cache->correctFolderSize($target);
+ if ($sourceUpdater instanceof Updater) {
+ $sourceUpdater->correctParentStorageMtime($source);
+ }
+ $this->correctParentStorageMtime($target);
+ $this->updateStorageMTimeOnly($target);
+ $sourcePropagator->propagateChange($source, $time);
+ $this->propagator->propagateChange($target, $time);
}
- private function updateStorageMTimeOnly($storage, $internalPath) {
- $cache = $storage->getCache();
- $fileId = $cache->getId($internalPath);
+ private function updateStorageMTimeOnly($internalPath) {
+ $fileId = $this->cache->getId($internalPath);
if ($fileId !== -1) {
- $cache->update(
+ $this->cache->update(
$fileId, [
'mtime' => null, // this magic tells it to not overwrite mtime
- 'storage_mtime' => $storage->filemtime($internalPath)
+ 'storage_mtime' => $this->storage->filemtime($internalPath)
]
);
}
@@ -217,20 +213,13 @@ class Updater {
/**
* update the storage_mtime of the direct parent in the cache to the mtime from the storage
*
- * @param \OC\Files\Storage\Storage $storage
* @param string $internalPath
*/
- private function correctParentStorageMtime($storage, $internalPath) {
- $cache = $storage->getCache();
- $parentId = $cache->getParentId($internalPath);
+ private function correctParentStorageMtime($internalPath) {
+ $parentId = $this->cache->getParentId($internalPath);
$parent = dirname($internalPath);
if ($parentId != -1) {
- $cache->update($parentId, array('storage_mtime' => $storage->filemtime($parent)));
+ $this->cache->update($parentId, array('storage_mtime' => $this->storage->filemtime($parent)));
}
}
-
- public function __destruct() {
- // propagate any leftover changes
- $this->propagator->propagateChanges();
- }
}
diff --git a/lib/private/files/cache/watcher.php b/lib/private/files/cache/watcher.php
index e660e56bfee..a00e875a2d4 100644
--- a/lib/private/files/cache/watcher.php
+++ b/lib/private/files/cache/watcher.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,14 +22,13 @@
*/
namespace OC\Files\Cache;
+use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\Cache\IWatcher;
/**
* check the storage backends for updates and change the cache accordingly
*/
-class Watcher {
- const CHECK_NEVER = 0; // never check the underlying filesystem for updates
- const CHECK_ONCE = 1; // check the underlying filesystem for updates once every request for each file
- const CHECK_ALWAYS = 2; // always check the underlying filesystem for updates
+class Watcher implements IWatcher {
protected $watchPolicy = self::CHECK_ONCE;
@@ -77,7 +76,7 @@ class Watcher {
* check $path for updates and update if needed
*
* @param string $path
- * @param array $cachedEntry
+ * @param ICacheEntry|null $cachedEntry
* @return boolean true if path was updated
*/
public function checkUpdate($path, $cachedEntry = null) {
@@ -96,7 +95,7 @@ class Watcher {
* Update the cache for changes to $path
*
* @param string $path
- * @param array $cachedData
+ * @param ICacheEntry $cachedData
*/
public function update($path, $cachedData) {
if ($this->storage->is_dir($path)) {
@@ -114,7 +113,7 @@ class Watcher {
* Check if the cache for $path needs to be updated
*
* @param string $path
- * @param array $cachedData
+ * @param ICacheEntry $cachedData
* @return bool
*/
public function needsUpdate($path, $cachedData) {
diff --git a/lib/private/files/cache/wrapper/cachejail.php b/lib/private/files/cache/wrapper/cachejail.php
index 9a673b07737..868e63cdf81 100644
--- a/lib/private/files/cache/wrapper/cachejail.php
+++ b/lib/private/files/cache/wrapper/cachejail.php
@@ -2,10 +2,10 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -34,7 +34,7 @@ class CacheJail extends CacheWrapper {
protected $root;
/**
- * @param \OC\Files\Cache\Cache $cache
+ * @param \OCP\Files\Cache\ICache $cache
* @param string $root
*/
public function __construct($cache, $root) {
@@ -95,15 +95,16 @@ class CacheJail extends CacheWrapper {
}
/**
- * store meta data for a file or folder
+ * insert meta data for a new file or folder
*
* @param string $file
* @param array $data
*
* @return int file id
+ * @throws \RuntimeException
*/
- public function put($file, array $data) {
- return $this->cache->put($this->getSourcePath($file), $data);
+ public function insert($file, array $data) {
+ return $this->cache->insert($this->getSourcePath($file), $data);
}
/**
@@ -113,7 +114,7 @@ class CacheJail extends CacheWrapper {
* @param array $data
*/
public function update($id, array $data) {
- $this->cache->update($this->getSourcePath($id), $data);
+ $this->cache->update($id, $data);
}
/**
diff --git a/lib/private/files/cache/wrapper/cachepermissionsmask.php b/lib/private/files/cache/wrapper/cachepermissionsmask.php
index 15307a4d7e8..b3a7bcb3a73 100644
--- a/lib/private/files/cache/wrapper/cachepermissionsmask.php
+++ b/lib/private/files/cache/wrapper/cachepermissionsmask.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,7 +29,7 @@ class CachePermissionsMask extends CacheWrapper {
protected $mask;
/**
- * @param \OC\Files\Cache\Cache $cache
+ * @param \OCP\Files\Cache\ICache $cache
* @param int $mask
*/
public function __construct($cache, $mask) {
diff --git a/lib/private/files/cache/wrapper/cachewrapper.php b/lib/private/files/cache/wrapper/cachewrapper.php
index bb136456762..4080883419e 100644
--- a/lib/private/files/cache/wrapper/cachewrapper.php
+++ b/lib/private/files/cache/wrapper/cachewrapper.php
@@ -2,10 +2,10 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,15 +25,17 @@
namespace OC\Files\Cache\Wrapper;
use OC\Files\Cache\Cache;
+use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\Cache\ICache;
class CacheWrapper extends Cache {
/**
- * @var \OC\Files\Cache\Cache
+ * @var \OCP\Files\Cache\ICache
*/
protected $cache;
/**
- * @param \OC\Files\Cache\Cache $cache
+ * @param \OCP\Files\Cache\ICache $cache
*/
public function __construct($cache) {
$this->cache = $cache;
@@ -42,8 +44,8 @@ class CacheWrapper extends Cache {
/**
* Make it easy for wrappers to modify every returned cache entry
*
- * @param array $entry
- * @return array
+ * @param ICacheEntry $entry
+ * @return ICacheEntry
*/
protected function formatCacheEntry($entry) {
return $entry;
@@ -53,7 +55,7 @@ class CacheWrapper extends Cache {
* get the stored metadata of a file or folder
*
* @param string /int $file
- * @return array|false
+ * @return ICacheEntry|false
*/
public function get($file) {
$result = $this->cache->get($file);
@@ -67,7 +69,7 @@ class CacheWrapper extends Cache {
* get the metadata of all files stored in $folder
*
* @param string $folder
- * @return array
+ * @return ICacheEntry[]
*/
public function getFolderContents($folder) {
// cant do a simple $this->cache->.... call here since getFolderContentsById needs to be called on this
@@ -88,15 +90,34 @@ class CacheWrapper extends Cache {
}
/**
- * store meta data for a file or folder
+ * insert or update meta data for a file or folder
*
* @param string $file
* @param array $data
*
* @return int file id
+ * @throws \RuntimeException
*/
public function put($file, array $data) {
- return $this->cache->put($file, $data);
+ if (($id = $this->getId($file)) > -1) {
+ $this->update($id, $data);
+ return $id;
+ } else {
+ return $this->insert($file, $data);
+ }
+ }
+
+ /**
+ * insert meta data for a new file or folder
+ *
+ * @param string $file
+ * @param array $data
+ *
+ * @return int file id
+ * @throws \RuntimeException
+ */
+ public function insert($file, array $data) {
+ return $this->cache->insert($file, $data);
}
/**
@@ -158,6 +179,10 @@ class CacheWrapper extends Cache {
$this->cache->move($source, $target);
}
+ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
+ $this->cache->moveFromCache($sourceCache, $sourcePath, $targetPath);
+ }
+
/**
* remove all entries for files that are stored on the storage from the cache
*/
@@ -178,7 +203,7 @@ class CacheWrapper extends Cache {
* search for files matching $pattern
*
* @param string $pattern
- * @return array an array of file data
+ * @return ICacheEntry[] an array of file data
*/
public function search($pattern) {
$results = $this->cache->search($pattern);
@@ -189,7 +214,7 @@ class CacheWrapper extends Cache {
* search for files by mimetype
*
* @param string $mimetype
- * @return array
+ * @return ICacheEntry[]
*/
public function searchByMime($mimetype) {
$results = $this->cache->searchByMime($mimetype);
@@ -201,7 +226,7 @@ class CacheWrapper extends Cache {
*
* @param string|int $tag name or tag id
* @param string $userId owner of the tags
- * @return array file data
+ * @return ICacheEntry[] file data
*/
public function searchByTag($tag, $userId) {
$results = $this->cache->searchByTag($tag, $userId);
diff --git a/lib/private/files/config/cachedmountinfo.php b/lib/private/files/config/cachedmountinfo.php
new file mode 100644
index 00000000000..dba07715edc
--- /dev/null
+++ b/lib/private/files/config/cachedmountinfo.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Files\Config;
+
+use OC\Files\Filesystem;
+use OCP\Files\Config\ICachedMountInfo;
+use OCP\Files\Node;
+use OCP\IUser;
+
+class CachedMountInfo implements ICachedMountInfo {
+ /**
+ * @var IUser
+ */
+ private $user;
+
+ /**
+ * @var int
+ */
+ private $storageId;
+
+ /**
+ * @var int
+ */
+ private $rootId;
+
+ /**
+ * @var string
+ */
+ private $mountPoint;
+
+ /**
+ * CachedMountInfo constructor.
+ *
+ * @param IUser $user
+ * @param int $storageId
+ * @param int $rootId
+ * @param string $mountPoint
+ */
+ public function __construct(IUser $user, $storageId, $rootId, $mountPoint) {
+ $this->user = $user;
+ $this->storageId = $storageId;
+ $this->rootId = $rootId;
+ $this->mountPoint = $mountPoint;
+ }
+
+ /**
+ * @return IUser
+ */
+ public function getUser() {
+ return $this->user;
+ }
+
+ /**
+ * @return int the numeric storage id of the mount
+ */
+ public function getStorageId() {
+ return $this->storageId;
+ }
+
+ /**
+ * @return int the fileid of the root of the mount
+ */
+ public function getRootId() {
+ return $this->rootId;
+ }
+
+ /**
+ * @return Node the root node of the mount
+ */
+ public function getMountPointNode() {
+ // TODO injection etc
+ Filesystem::initMountPoints($this->user->getUID());
+ $userNode = \OC::$server->getUserFolder($this->user->getUID());
+ $nodes = $userNode->getById($this->rootId);
+ if (count($nodes) > 0) {
+ return $nodes[0];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @return string the mount point of the mount for the user
+ */
+ public function getMountPoint() {
+ return $this->mountPoint;
+ }
+}
diff --git a/lib/private/files/config/mountprovidercollection.php b/lib/private/files/config/mountprovidercollection.php
index c75c64ae445..499fa576fbc 100644
--- a/lib/private/files/config/mountprovidercollection.php
+++ b/lib/private/files/config/mountprovidercollection.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,6 +26,8 @@ use OC\Hooks\Emitter;
use OC\Hooks\EmitterTrait;
use OCP\Files\Config\IMountProviderCollection;
use OCP\Files\Config\IMountProvider;
+use OCP\Files\Config\IUserMountCache;
+use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage\IStorageFactory;
use OCP\IUser;
@@ -43,10 +45,17 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
private $loader;
/**
+ * @var \OCP\Files\Config\IUserMountCache
+ */
+ private $mountCache;
+
+ /**
* @param \OCP\Files\Storage\IStorageFactory $loader
+ * @param IUserMountCache $mountCache
*/
- public function __construct(IStorageFactory $loader) {
+ public function __construct(IStorageFactory $loader, IUserMountCache $mountCache) {
$this->loader = $loader;
+ $this->mountCache = $mountCache;
}
/**
@@ -77,4 +86,23 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
$this->providers[] = $provider;
$this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]);
}
+
+ /**
+ * Cache mounts for user
+ *
+ * @param IUser $user
+ * @param IMountPoint[] $mountPoints
+ */
+ public function registerMounts(IUser $user, array $mountPoints) {
+ $this->mountCache->registerMounts($user, $mountPoints);
+ }
+
+ /**
+ * Get the mount cache which can be used to search for mounts without setting up the filesystem
+ *
+ * @return IUserMountCache
+ */
+ public function getMountCache() {
+ return $this->mountCache;
+ }
}
diff --git a/lib/private/files/config/usermountcache.php b/lib/private/files/config/usermountcache.php
new file mode 100644
index 00000000000..a2da3e9f528
--- /dev/null
+++ b/lib/private/files/config/usermountcache.php
@@ -0,0 +1,291 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Files\Config;
+
+use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
+use OC\Files\Filesystem;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\Files\Config\ICachedMountInfo;
+use OCP\Files\Config\IUserMountCache;
+use OCP\Files\Mount\IMountPoint;
+use OCP\Files\NotFoundException;
+use OCP\ICache;
+use OCP\IDBConnection;
+use OCP\ILogger;
+use OCP\IUser;
+use OCP\IUserManager;
+
+/**
+ * Cache mounts points per user in the cache so we can easilly look them up
+ */
+class UserMountCache implements IUserMountCache {
+ /**
+ * @var IDBConnection
+ */
+ private $connection;
+
+ /**
+ * @var IUserManager
+ */
+ private $userManager;
+
+ /** @var ICachedMountInfo[][] [$userId => [$cachedMountInfo, ....], ...] */
+ private $mountsForUsers = [];
+
+ /**
+ * @var ILogger
+ */
+ private $logger;
+
+ private $cacheInfoCache = [];
+
+ /**
+ * UserMountCache constructor.
+ *
+ * @param IDBConnection $connection
+ * @param IUserManager $userManager
+ * @param ILogger $logger
+ */
+ public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
+ $this->connection = $connection;
+ $this->userManager = $userManager;
+ $this->logger = $logger;
+ }
+
+ public function registerMounts(IUser $user, array $mounts) {
+ // filter out non-proper storages coming from unit tests
+ $mounts = array_filter($mounts, function (IMountPoint $mount) {
+ return $mount->getStorage() && $mount->getStorage()->getCache();
+ });
+ /** @var ICachedMountInfo[] $newMounts */
+ $newMounts = array_map(function (IMountPoint $mount) use ($user) {
+ $storage = $mount->getStorage();
+ $rootId = (int)$storage->getCache()->getId('');
+ $storageId = (int)$storage->getStorageCache()->getNumericId();
+ // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
+ if ($rootId === -1) {
+ return null;
+ } else {
+ return new CachedMountInfo($user, $storageId, $rootId, $mount->getMountPoint());
+ }
+ }, $mounts);
+ $newMounts = array_values(array_filter($newMounts));
+
+ $cachedMounts = $this->getMountsForUser($user);
+ $mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
+ // since we are only looking for mounts for a specific user comparing on root id is enough
+ return $mount1->getRootId() - $mount2->getRootId();
+ };
+
+ /** @var ICachedMountInfo[] $addedMounts */
+ $addedMounts = array_udiff($newMounts, $cachedMounts, $mountDiff);
+ /** @var ICachedMountInfo[] $removedMounts */
+ $removedMounts = array_udiff($cachedMounts, $newMounts, $mountDiff);
+
+ $changedMounts = array_uintersect($newMounts, $cachedMounts, function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
+ // filter mounts with the same root id and different mountpoints
+ if ($mount1->getRootId() !== $mount2->getRootId()) {
+ return -1;
+ }
+ return ($mount1->getMountPoint() !== $mount2->getMountPoint()) ? 0 : 1;
+ });
+
+ foreach ($addedMounts as $mount) {
+ $this->addToCache($mount);
+ $this->mountsForUsers[$user->getUID()][] = $mount;
+ }
+ foreach ($removedMounts as $mount) {
+ $this->removeFromCache($mount);
+ $index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
+ unset($this->mountsForUsers[$user->getUID()][$index]);
+ }
+ foreach ($changedMounts as $mount) {
+ $this->setMountPoint($mount);
+ }
+ }
+
+ private function addToCache(ICachedMountInfo $mount) {
+ $this->connection->insertIfNotExist('*PREFIX*mounts', [
+ 'storage_id' => $mount->getStorageId(),
+ 'root_id' => $mount->getRootId(),
+ 'user_id' => $mount->getUser()->getUID(),
+ 'mount_point' => $mount->getMountPoint()
+ ]);
+ }
+
+ private function setMountPoint(ICachedMountInfo $mount) {
+ $builder = $this->connection->getQueryBuilder();
+
+ $query = $builder->update('mounts')
+ ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
+ ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
+ ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
+
+ $query->execute();
+ }
+
+ private function removeFromCache(ICachedMountInfo $mount) {
+ $builder = $this->connection->getQueryBuilder();
+
+ $query = $builder->delete('mounts')
+ ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
+ ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
+ $query->execute();
+ }
+
+ private function dbRowToMountInfo(array $row) {
+ $user = $this->userManager->get($row['user_id']);
+ return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point']);
+ }
+
+ /**
+ * @param IUser $user
+ * @return ICachedMountInfo[]
+ */
+ public function getMountsForUser(IUser $user) {
+ if (!isset($this->mountsForUsers[$user->getUID()])) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point')
+ ->from('mounts')
+ ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
+
+ $rows = $query->execute()->fetchAll();
+
+ $this->mountsForUsers[$user->getUID()] = array_map([$this, 'dbRowToMountInfo'], $rows);
+ }
+ return $this->mountsForUsers[$user->getUID()];
+ }
+
+ /**
+ * @param int $numericStorageId
+ * @return CachedMountInfo[]
+ */
+ public function getMountsForStorageId($numericStorageId) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point')
+ ->from('mounts')
+ ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
+
+ $rows = $query->execute()->fetchAll();
+
+ return array_map([$this, 'dbRowToMountInfo'], $rows);
+ }
+
+ /**
+ * @param int $rootFileId
+ * @return CachedMountInfo[]
+ */
+ public function getMountsForRootId($rootFileId) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point')
+ ->from('mounts')
+ ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
+
+ $rows = $query->execute()->fetchAll();
+
+ return array_map([$this, 'dbRowToMountInfo'], $rows);
+ }
+
+ /**
+ * @param $fileId
+ * @return array
+ * @throws \OCP\Files\NotFoundException
+ */
+ private function getCacheInfoFromFileId($fileId) {
+ if (!isset($this->cacheInfoCache[$fileId])) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->select('storage', 'path')
+ ->from('filecache')
+ ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
+
+ $row = $query->execute()->fetch();
+ if (is_array($row)) {
+ $this->cacheInfoCache[$fileId] = [
+ (int)$row['storage'],
+ $row['path']
+ ];
+ } else {
+ throw new NotFoundException('File with id "' . $fileId . '" not found');
+ }
+ }
+ return $this->cacheInfoCache[$fileId];
+ }
+
+ /**
+ * @param int $fileId
+ * @return ICachedMountInfo[]
+ * @since 9.0.0
+ */
+ public function getMountsForFileId($fileId) {
+ try {
+ list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId);
+ } catch (NotFoundException $e) {
+ return [];
+ }
+ $mountsForStorage = $this->getMountsForStorageId($storageId);
+
+ // filter mounts that are from the same storage but a different directory
+ return array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
+ if ($fileId === $mount->getRootId()) {
+ return true;
+ }
+ try {
+ list(, $internalMountPath) = $this->getCacheInfoFromFileId($mount->getRootId());
+ } catch (NotFoundException $e) {
+ return false;
+ }
+
+ return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
+ });
+
+ }
+
+ /**
+ * Remove all cached mounts for a user
+ *
+ * @param IUser $user
+ */
+ public function removeUserMounts(IUser $user) {
+ $builder = $this->connection->getQueryBuilder();
+
+ $query = $builder->delete('mounts')
+ ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
+ $query->execute();
+ }
+
+ public function removeUserStorageMount($storageId, $userId) {
+ $builder = $this->connection->getQueryBuilder();
+
+ $query = $builder->delete('mounts')
+ ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
+ ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
+ $query->execute();
+ }
+
+ public function remoteStorageMounts($storageId) {
+ $builder = $this->connection->getQueryBuilder();
+
+ $query = $builder->delete('mounts')
+ ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
+ $query->execute();
+ }
+}
diff --git a/lib/private/files/config/usermountcachelistener.php b/lib/private/files/config/usermountcachelistener.php
new file mode 100644
index 00000000000..344bebe342d
--- /dev/null
+++ b/lib/private/files/config/usermountcachelistener.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Files\Config;
+
+use OC\User\Manager;
+use OCP\Files\Config\IUserMountCache;
+
+/**
+ * Listen to hooks and update the mount cache as needed
+ */
+class UserMountCacheListener {
+ /**
+ * @var IUserMountCache
+ */
+ private $userMountCache;
+
+ /**
+ * UserMountCacheListener constructor.
+ *
+ * @param IUserMountCache $userMountCache
+ */
+ public function __construct(IUserMountCache $userMountCache) {
+ $this->userMountCache = $userMountCache;
+ }
+
+ public function listen(Manager $manager) {
+ $manager->listen('\OC\User', 'postDelete', [$this->userMountCache, 'removeUserMounts']);
+ }
+}
diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php
index bb810dd45ed..f22e1099e26 100644
--- a/lib/private/files/fileinfo.php
+++ b/lib/private/files/fileinfo.php
@@ -4,12 +4,13 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author tbartenstein <tbartenstein@users.noreply.github.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,6 +29,7 @@
namespace OC\Files;
+use OCP\Files\Cache\ICacheEntry;
use OCP\IUser;
class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
@@ -62,10 +64,15 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
private $owner;
/**
+ * @var string[]
+ */
+ private $childEtags = [];
+
+ /**
* @param string|boolean $path
* @param Storage\Storage $storage
* @param string $internalPath
- * @param array $data
+ * @param array|ICacheEntry $data
* @param \OCP\Files\Mount\IMountPoint $mount
* @param \OCP\IUser|null $owner
*/
@@ -93,6 +100,10 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
public function offsetGet($offset) {
if ($offset === 'type') {
return $this->getType();
+ } else if ($offset === 'etag') {
+ return $this->getEtag();
+ } elseif ($offset === 'permissions') {
+ return $this->getPermissions();
} elseif (isset($this->data[$offset])) {
return $this->data[$offset];
} else {
@@ -153,7 +164,12 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
* @return string
*/
public function getEtag() {
- return $this->data['etag'];
+ if (count($this->childEtags) > 0) {
+ $combinedEtag = $this->data['etag'] . '::' . implode('::', $this->childEtags);
+ return md5($combinedEtag);
+ } else {
+ return $this->data['etag'];
+ }
}
/**
@@ -181,7 +197,11 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
* @return int
*/
public function getPermissions() {
- return $this->data['permissions'];
+ $perms = $this->data['permissions'];
+ if (\OCP\Util::isSharingDisabledForUser() || ($this->isShared() && !\OC\Share\Share::isResharingAllowed())) {
+ $perms = $perms & ~\OCP\Constants::PERMISSION_SHARE;
+ }
+ return $perms;
}
/**
@@ -285,4 +305,33 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
public function getOwner() {
return $this->owner;
}
+
+ /**
+ * Add a cache entry which is the child of this folder
+ *
+ * Sets the size, etag and size to for cross-storage childs
+ *
+ * @param array $data cache entry for the child
+ * @param string $entryPath full path of the child entry
+ */
+ public function addSubEntry($data, $entryPath) {
+ $this->data['size'] += isset($data['size']) ? $data['size'] : 0;
+ if (isset($data['mtime'])) {
+ $this->data['mtime'] = max($this->data['mtime'], $data['mtime']);
+ }
+ if (isset($data['etag'])) {
+ // prefix the etag with the relative path of the subentry to propagate etag on mount moves
+ $relativeEntryPath = substr($entryPath, strlen($this->getPath()));
+ // attach the permissions to propagate etag on permision changes of submounts
+ $permissions = isset($data['permissions']) ? $data['permissions'] : 0;
+ $this->childEtags[] = $relativeEntryPath . '/' . $data['etag'] . $permissions;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getChecksum() {
+ return $this->data['checksum'];
+ }
}
diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php
index 0f7508b8f26..9d4a2c0aa05 100644
--- a/lib/private/files/filesystem.php
+++ b/lib/private/files/filesystem.php
@@ -11,13 +11,13 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Sam Tuke <mail@samtuke.com>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Stephan Peijnik <speijnik@anexia-it.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -58,10 +58,11 @@
namespace OC\Files;
-use OC\Cache\File;
use OC\Files\Config\MountProviderCollection;
+use OC\Files\Mount\MountPoint;
use OC\Files\Storage\StorageFactory;
use OCP\Files\Config\IMountProvider;
+use OCP\Files\Mount\IMountPoint;
use OCP\Files\NotFoundException;
use OCP\IUserManager;
@@ -386,7 +387,7 @@ class Filesystem {
throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
}
- $homeStorage = \OC_Config::getValue('objectstore');
+ $homeStorage = \OC::$server->getConfig()->getSystemValue('objectstore');
if (!empty($homeStorage)) {
// sanity checks
if (empty($homeStorage['class'])) {
@@ -413,7 +414,8 @@ class Filesystem {
$homeStorage['arguments']['legacy'] = true;
}
- self::mount($homeStorage['class'], $homeStorage['arguments'], $user);
+ $mount = new MountPoint($homeStorage['class'], '/' . $user, $homeStorage['arguments'], self::getLoader());
+ self::getMountManager()->addMount($mount);
$home = \OC\Files\Filesystem::getStorage($user);
@@ -425,6 +427,8 @@ class Filesystem {
if ($userObject) {
$mounts = $mountConfigManager->getMountsForUser($userObject);
array_walk($mounts, array(self::$mounts, 'addMount'));
+ $mounts[] = $mount;
+ $mountConfigManager->registerMounts($userObject, $mounts);
}
self::listenForNewMountProviders($mountConfigManager, $userManager);
@@ -458,7 +462,7 @@ class Filesystem {
* @param string $user user name
*/
private static function mountCacheDir($user) {
- $cacheBaseDir = \OC_Config::getValue('cache_path', '');
+ $cacheBaseDir = \OC::$server->getConfig()->getSystemValue('cache_path', '');
if ($cacheBaseDir !== '') {
$cacheDir = rtrim($cacheBaseDir, '/') . '/' . $user;
if (!file_exists($cacheDir)) {
@@ -603,7 +607,7 @@ class Filesystem {
static public function isFileBlacklisted($filename) {
$filename = self::normalizePath($filename);
- $blacklist = \OC_Config::getValue('blacklisted_files', array('.htaccess'));
+ $blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', array('.htaccess'));
$filename = strtolower(basename($filename));
return in_array($filename, $blacklist);
}
diff --git a/lib/private/files/mount/manager.php b/lib/private/files/mount/manager.php
index d5bd4d7ddf4..ba4a7f8d910 100644
--- a/lib/private/files/mount/manager.php
+++ b/lib/private/files/mount/manager.php
@@ -3,9 +3,9 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/mount/mountpoint.php b/lib/private/files/mount/mountpoint.php
index fad8678aae1..b606c625cb1 100644
--- a/lib/private/files/mount/mountpoint.php
+++ b/lib/private/files/mount/mountpoint.php
@@ -4,11 +4,11 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/mount/moveablemount.php b/lib/private/files/mount/moveablemount.php
index d0f7703d80a..8a1bd7dd9c5 100644
--- a/lib/private/files/mount/moveablemount.php
+++ b/lib/private/files/mount/moveablemount.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/node/file.php b/lib/private/files/node/file.php
index f66f87bfc2d..cf163b9b763 100644
--- a/lib/private/files/node/file.php
+++ b/lib/private/files/node/file.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -99,8 +99,9 @@ class File extends Node implements \OCP\Files\File {
public function delete() {
if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
$this->sendHooks(array('preDelete'));
+ $fileInfo = $this->getFileInfo();
$this->view->unlink($this->path);
- $nonExisting = new NonExistingFile($this->root, $this->view, $this->path);
+ $nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo);
$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
$this->exists = false;
$this->fileInfo = null;
@@ -163,4 +164,11 @@ class File extends Node implements \OCP\Files\File {
public function hash($type, $raw = false) {
return $this->view->hash($type, $this->path, $raw);
}
+
+ /**
+ * @inheritdoc
+ */
+ public function getChecksum() {
+ return $this->fileInfo->getChecksum();
+ }
}
diff --git a/lib/private/files/node/folder.php b/lib/private/files/node/folder.php
index 9032c2bfb9d..e8c49cd2c0b 100644
--- a/lib/private/files/node/folder.php
+++ b/lib/private/files/node/folder.php
@@ -3,10 +3,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -295,8 +295,9 @@ class Folder extends Node implements \OCP\Files\Folder {
public function delete() {
if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
$this->sendHooks(array('preDelete'));
+ $fileInfo = $this->getFileInfo();
$this->view->rmdir($this->path);
- $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path);
+ $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
$this->exists = false;
} else {
diff --git a/lib/private/files/node/hookconnector.php b/lib/private/files/node/hookconnector.php
index c42a329d319..5c36ca3848e 100644
--- a/lib/private/files/node/hookconnector.php
+++ b/lib/private/files/node/hookconnector.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,9 +21,9 @@
namespace OC\Files\Node;
+use OCP\Files\FileInfo;
use OC\Files\Filesystem;
use OC\Files\View;
-use OCP\Files\FileInfo;
use OCP\Util;
class HookConnector {
@@ -38,6 +38,11 @@ class HookConnector {
private $view;
/**
+ * @var FileInfo[]
+ */
+ private $deleteMetaCache = [];
+
+ /**
* HookConnector constructor.
*
* @param Root $root
@@ -90,11 +95,13 @@ class HookConnector {
public function delete($arguments) {
$node = $this->getNodeForPath($arguments['path']);
+ $this->deleteMetaCache[$node->getPath()] = $node->getFileInfo();
$this->root->emit('\OC\Files', 'preDelete', [$node]);
}
public function postDelete($arguments) {
$node = $this->getNodeForPath($arguments['path']);
+ unset($this->deleteMetaCache[$node->getPath()]);
$this->root->emit('\OC\Files', 'postDelete', [$node]);
}
@@ -135,11 +142,17 @@ class HookConnector {
private function getNodeForPath($path) {
$info = Filesystem::getView()->getFileInfo($path);
if (!$info) {
+
$fullPath = Filesystem::getView()->getAbsolutePath($path);
+ if (isset($this->deleteMetaCache[$fullPath])) {
+ $info = $this->deleteMetaCache[$fullPath];
+ } else {
+ $info = null;
+ }
if (Filesystem::is_dir($path)) {
- return new NonExistingFolder($this->root, $this->view, $fullPath);
+ return new NonExistingFolder($this->root, $this->view, $fullPath, $info);
} else {
- return new NonExistingFile($this->root, $this->view, $fullPath);
+ return new NonExistingFile($this->root, $this->view, $fullPath, $info);
}
}
if ($info->getType() === FileInfo::TYPE_FILE) {
diff --git a/lib/private/files/node/node.php b/lib/private/files/node/node.php
index 1b52243fcb4..9feccac50bc 100644
--- a/lib/private/files/node/node.php
+++ b/lib/private/files/node/node.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -351,4 +351,8 @@ class Node implements \OCP\Files\Node {
public function getOwner() {
return $this->getFileInfo()->getOwner();
}
+
+ public function getChecksum() {
+ return;
+ }
}
diff --git a/lib/private/files/node/nonexistingfile.php b/lib/private/files/node/nonexistingfile.php
index b1de15d0535..c1d09bcc491 100644
--- a/lib/private/files/node/nonexistingfile.php
+++ b/lib/private/files/node/nonexistingfile.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -46,7 +46,11 @@ class NonExistingFile extends File {
}
public function getId() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getId();
+ } else {
+ throw new NotFoundException();
+ }
}
public function stat() {
@@ -54,35 +58,67 @@ class NonExistingFile extends File {
}
public function getMTime() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getMTime();
+ } else {
+ throw new NotFoundException();
+ }
}
public function getSize() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getSize();
+ } else {
+ throw new NotFoundException();
+ }
}
public function getEtag() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getEtag();
+ } else {
+ throw new NotFoundException();
+ }
}
public function getPermissions() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getPermissions();
+ } else {
+ throw new NotFoundException();
+ }
}
public function isReadable() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::isReadable();
+ } else {
+ throw new NotFoundException();
+ }
}
public function isUpdateable() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::isUpdateable();
+ } else {
+ throw new NotFoundException();
+ }
}
public function isDeletable() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::isDeletable();
+ } else {
+ throw new NotFoundException();
+ }
}
public function isShareable() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::isShareable();
+ } else {
+ throw new NotFoundException();
+ }
}
public function getContent() {
@@ -94,7 +130,11 @@ class NonExistingFile extends File {
}
public function getMimeType() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getMimeType();
+ } else {
+ throw new NotFoundException();
+ }
}
public function fopen($mode) {
diff --git a/lib/private/files/node/nonexistingfolder.php b/lib/private/files/node/nonexistingfolder.php
index be58103da90..7d6576f1bd6 100644
--- a/lib/private/files/node/nonexistingfolder.php
+++ b/lib/private/files/node/nonexistingfolder.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -47,7 +47,11 @@ class NonExistingFolder extends Folder {
}
public function getId() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getId();
+ } else {
+ throw new NotFoundException();
+ }
}
public function stat() {
@@ -55,35 +59,67 @@ class NonExistingFolder extends Folder {
}
public function getMTime() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getMTime();
+ } else {
+ throw new NotFoundException();
+ }
}
public function getSize() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getSize();
+ } else {
+ throw new NotFoundException();
+ }
}
public function getEtag() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getEtag();
+ } else {
+ throw new NotFoundException();
+ }
}
public function getPermissions() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::getPermissions();
+ } else {
+ throw new NotFoundException();
+ }
}
public function isReadable() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::isReadable();
+ } else {
+ throw new NotFoundException();
+ }
}
public function isUpdateable() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::isUpdateable();
+ } else {
+ throw new NotFoundException();
+ }
}
public function isDeletable() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::isDeletable();
+ } else {
+ throw new NotFoundException();
+ }
}
public function isShareable() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::isShareable();
+ } else {
+ throw new NotFoundException();
+ }
}
public function get($path) {
@@ -127,6 +163,10 @@ class NonExistingFolder extends Folder {
}
public function isCreatable() {
- throw new NotFoundException();
+ if ($this->fileInfo) {
+ return parent::isCreatable();
+ } else {
+ throw new NotFoundException();
+ }
}
}
diff --git a/lib/private/files/node/root.php b/lib/private/files/node/root.php
index 4df926748de..40ed531d5df 100644
--- a/lib/private/files/node/root.php
+++ b/lib/private/files/node/root.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -169,7 +169,7 @@ class Root extends Folder implements IRootFolder {
* @param string $path
* @throws \OCP\Files\NotFoundException
* @throws \OCP\Files\NotPermittedException
- * @return \OCP\Files\Node
+ * @return string
*/
public function get($path) {
$path = $this->normalizePath($path);
diff --git a/lib/private/files/objectstore/homeobjectstorestorage.php b/lib/private/files/objectstore/homeobjectstorestorage.php
index 77b5437c24d..6a330e2dab3 100644
--- a/lib/private/files/objectstore/homeobjectstorestorage.php
+++ b/lib/private/files/objectstore/homeobjectstorestorage.php
@@ -4,7 +4,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/objectstore/noopscanner.php b/lib/private/files/objectstore/noopscanner.php
index cdcc0149ab3..f5316175ecf 100644
--- a/lib/private/files/objectstore/noopscanner.php
+++ b/lib/private/files/objectstore/noopscanner.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/objectstore/objectstorestorage.php b/lib/private/files/objectstore/objectstorestorage.php
index e108d7662d4..35c2c19c75b 100644
--- a/lib/private/files/objectstore/objectstorestorage.php
+++ b/lib/private/files/objectstore/objectstorestorage.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +25,7 @@
namespace OC\Files\ObjectStore;
use Icewind\Streams\IteratorDirectory;
+use OC\Files\Cache\CacheEntry;
use OCP\Files\ObjectStore\IObjectStore;
class ObjectStoreStorage extends \OC\Files\Storage\Common {
@@ -192,7 +193,12 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
public function stat($path) {
$path = $this->normalizePath($path);
- return $this->getCache()->get($path);
+ $cacheEntry = $this->getCache()->get($path);
+ if ($cacheEntry instanceof CacheEntry) {
+ return $cacheEntry->getData();
+ } else {
+ return false;
+ }
}
/**
@@ -274,7 +280,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
} else {
$ext = '';
}
- $tmpFile = \OC_Helper::tmpFile($ext);
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
if ($this->file_exists($path)) {
$source = $this->fopen($path, 'r');
@@ -329,7 +335,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
$stat['mtime'] = $mtime;
$this->getCache()->update($stat['fileid'], $stat);
} else {
- $mimeType = \OC_Helper::getFileNameMimeType($path);
+ $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
// create new file
$stat = array(
'etag' => $this->getETag($path),
@@ -370,7 +376,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
$stat['size'] = filesize($tmpFile);
$stat['mtime'] = $mTime;
$stat['storage_mtime'] = $mTime;
- $stat['mimetype'] = \OC_Helper::getMimeType($tmpFile);
+ $stat['mimetype'] = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
$stat['etag'] = $this->getETag($path);
$fileId = $this->getCache()->put($path, $stat);
diff --git a/lib/private/files/objectstore/swift.php b/lib/private/files/objectstore/swift.php
index 89ef40360a7..4af09dca254 100644
--- a/lib/private/files/objectstore/swift.php
+++ b/lib/private/files/objectstore/swift.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -73,11 +73,16 @@ class Swift implements IObjectStore {
// the OpenCloud client library will default to 'cloudFiles' if $serviceName is null
$serviceName = null;
- if ($this->params['serviceName']) {
+ if (isset($this->params['serviceName'])) {
$serviceName = $this->params['serviceName'];
}
- $this->objectStoreService = $this->client->objectStoreService($serviceName, $this->params['region']);
+ // the OpenCloud client library will default to 'publicURL' if $urlType is null
+ $urlType = null;
+ if (isset($this->params['urlType'])) {
+ $urlType = $this->params['urlType'];
+ }
+ $this->objectStoreService = $this->client->objectStoreService($serviceName, $this->params['region'], $urlType);
try {
$this->container = $this->objectStoreService->getContainer($this->params['container']);
diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php
index 77a70226b37..7d8d9ebd25e 100644
--- a/lib/private/files/storage/common.php
+++ b/lib/private/files/storage/common.php
@@ -11,13 +11,13 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Sam Tuke <mail@samtuke.com>
* @author scambra <sergio@entrecables.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -37,13 +37,16 @@
namespace OC\Files\Storage;
use OC\Files\Cache\Cache;
+use OC\Files\Cache\Propagator;
use OC\Files\Cache\Scanner;
+use OC\Files\Cache\Updater;
use OC\Files\Filesystem;
use OC\Files\Cache\Watcher;
use OCP\Files\FileNameTooLongException;
use OCP\Files\InvalidCharacterInPathException;
use OCP\Files\InvalidPathException;
use OCP\Files\ReservedWordException;
+use OCP\Files\Storage\ILockingStorage;
use OCP\Lock\ILockingProvider;
/**
@@ -57,14 +60,16 @@ use OCP\Lock\ILockingProvider;
* Some \OC\Files\Storage\Common methods call functions which are first defined
* in classes which extend it, e.g. $this->stat() .
*/
-abstract class Common implements Storage {
+abstract class Common implements Storage, ILockingStorage {
use LocalTempFileTrait;
protected $cache;
protected $scanner;
protected $watcher;
+ protected $propagator;
protected $storageCache;
+ protected $updater;
protected $mountOptions = [];
@@ -137,10 +142,6 @@ abstract class Common implements Storage {
}
public function isSharable($path) {
- if (\OC_Util::isSharingDisabledForUser()) {
- return false;
- }
-
return $this->isReadable($path);
}
@@ -225,7 +226,7 @@ abstract class Common implements Storage {
if ($this->is_dir($path)) {
return 'httpd/unix-directory';
} elseif ($this->file_exists($path)) {
- return \OC_Helper::getFileNameMimeType($path);
+ return \OC::$server->getMimeTypeDetector()->detectPath($path);
} else {
return false;
}
@@ -248,7 +249,7 @@ abstract class Common implements Storage {
}
public function getLocalFolder($path) {
- $baseDir = \OC_Helper::tmpFolder();
+ $baseDir = \OC::$server->getTempManager()->getTemporaryFolder();
$this->addLocalFolder($path, $baseDir);
return $baseDir;
}
@@ -345,6 +346,32 @@ abstract class Common implements Storage {
return $this->watcher;
}
+ /**
+ * get a propagator instance for the cache
+ *
+ * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
+ * @return \OC\Files\Cache\Propagator
+ */
+ public function getPropagator($storage = null) {
+ if (!$storage) {
+ $storage = $this;
+ }
+ if (!isset($this->propagator)) {
+ $this->propagator = new Propagator($storage);
+ }
+ return $this->propagator;
+ }
+
+ public function getUpdater($storage = null) {
+ if (!$storage) {
+ $storage = $this;
+ }
+ if (!isset($this->updater)) {
+ $this->updater = new Updater($storage);
+ }
+ return $this->updater;
+ }
+
public function getStorageCache($storage = null) {
if (!$storage) {
$storage = $this;
@@ -369,7 +396,7 @@ abstract class Common implements Storage {
* get the ETag for a file or folder
*
* @param string $path
- * @return string|false
+ * @return string
*/
public function getETag($path) {
return uniqid();
diff --git a/lib/private/files/storage/commontest.php b/lib/private/files/storage/commontest.php
index d4dbeecbbd6..0047a51169c 100644
--- a/lib/private/files/storage/commontest.php
+++ b/lib/private/files/storage/commontest.php
@@ -8,7 +8,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php
index dcde7b8029b..a6e77e1b232 100644
--- a/lib/private/files/storage/dav.php
+++ b/lib/private/files/storage/dav.php
@@ -14,7 +14,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -34,6 +34,7 @@
namespace OC\Files\Storage;
use Exception;
+use GuzzleHttp\Exception\RequestException;
use OC\Files\Filesystem;
use OC\Files\Stream\Close;
use Icewind\Streams\IteratorDirectory;
@@ -47,6 +48,7 @@ use OCP\Files\StorageNotAvailableException;
use OCP\Util;
use Sabre\DAV\Client;
use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Xml\Property\ResourceType;
use Sabre\HTTP\ClientException;
use Sabre\HTTP\ClientHttpException;
@@ -104,6 +106,7 @@ class DAV extends Common {
$this->secure = false;
}
if ($this->secure === true) {
+ // inject mock for testing
$certPath = \OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt';
if (file_exists($certPath)) {
$this->certPath = $certPath;
@@ -137,7 +140,7 @@ class DAV extends Common {
$this->client->setThrowExceptions(true);
if ($this->secure === true && $this->certPath) {
- $this->client->addTrustedCertificates($this->certPath);
+ $this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
}
}
@@ -280,7 +283,8 @@ class DAV extends Common {
$response = $this->propfind($path);
$responseType = array();
if (isset($response["{DAV:}resourcetype"])) {
- $responseType = $response["{DAV:}resourcetype"]->resourceType;
+ /** @var ResourceType[] $response */
+ $responseType = $response["{DAV:}resourcetype"]->getValue();
}
return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
} catch (ClientHttpException $e) {
@@ -336,15 +340,20 @@ class DAV extends Common {
switch ($mode) {
case 'r':
case 'rb':
- if (!$this->file_exists($path)) {
- return false;
+ try {
+ $response = $this->httpClientService
+ ->newClient()
+ ->get($this->createBaseUri() . $this->encodePath($path), [
+ 'auth' => [$this->user, $this->password],
+ 'stream' => true
+ ]);
+ } catch (RequestException $e) {
+ if ($e->getResponse()->getStatusCode() === 404) {
+ return false;
+ } else {
+ throw $e;
+ }
}
- $response = $this->httpClientService
- ->newClient()
- ->get($this->createBaseUri() . $this->encodePath($path), [
- 'auth' => [$this->user, $this->password],
- 'stream' => true
- ]);
if ($response->getStatusCode() !== Http::STATUS_OK) {
if ($response->getStatusCode() === Http::STATUS_LOCKED) {
@@ -554,7 +563,8 @@ class DAV extends Common {
$response = $this->propfind($path);
$responseType = array();
if (isset($response["{DAV:}resourcetype"])) {
- $responseType = $response["{DAV:}resourcetype"]->resourceType;
+ /** @var ResourceType[] $response */
+ $responseType = $response["{DAV:}resourcetype"]->getValue();
}
$type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
if ($type == 'dir') {
diff --git a/lib/private/files/storage/flysystem.php b/lib/private/files/storage/flysystem.php
index 3ad2b8adc4c..608639b71a6 100644
--- a/lib/private/files/storage/flysystem.php
+++ b/lib/private/files/storage/flysystem.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/storage/home.php b/lib/private/files/storage/home.php
index 1b4297ddd76..35a7e8360f3 100644
--- a/lib/private/files/storage/home.php
+++ b/lib/private/files/storage/home.php
@@ -6,7 +6,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php
index 2b2a433c013..aa2b4628283 100644
--- a/lib/private/files/storage/local.php
+++ b/lib/private/files/storage/local.php
@@ -14,7 +14,7 @@
* @author Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/storage/localtempfiletrait.php b/lib/private/files/storage/localtempfiletrait.php
index 84331f49b19..88f11e4e752 100644
--- a/lib/private/files/storage/localtempfiletrait.php
+++ b/lib/private/files/storage/localtempfiletrait.php
@@ -1,9 +1,10 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -70,7 +71,7 @@ trait LocalTempFileTrait {
} else {
$extension = '';
}
- $tmpFile = \OC_Helper::tmpFile($extension);
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
$target = fopen($tmpFile, 'w');
\OC_Helper::streamCopy($source, $target);
fclose($target);
diff --git a/lib/private/files/storage/polyfill/copydirectory.php b/lib/private/files/storage/polyfill/copydirectory.php
index df4f5c27dcf..22bfe369738 100644
--- a/lib/private/files/storage/polyfill/copydirectory.php
+++ b/lib/private/files/storage/polyfill/copydirectory.php
@@ -3,7 +3,7 @@
* @author Martin Mattel <martin.mattel@diemattels.at>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/storage/storage.php b/lib/private/files/storage/storage.php
index f46ac544b56..c066336d4b8 100644
--- a/lib/private/files/storage/storage.php
+++ b/lib/private/files/storage/storage.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -68,6 +68,22 @@ interface Storage extends \OCP\Files\Storage {
public function getWatcher($path = '', $storage = null);
/**
+ * get a propagator instance for the cache
+ *
+ * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
+ * @return \OC\Files\Cache\Propagator
+ */
+ public function getPropagator($storage = null);
+
+ /**
+ * get a updater instance for the cache
+ *
+ * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
+ * @return \OC\Files\Cache\Updater
+ */
+ public function getUpdater($storage = null);
+
+ /**
* @return \OC\Files\Cache\Storage
*/
public function getStorageCache();
diff --git a/lib/private/files/storage/storagefactory.php b/lib/private/files/storage/storagefactory.php
index e8df5090f09..5df91fd1eb4 100644
--- a/lib/private/files/storage/storagefactory.php
+++ b/lib/private/files/storage/storagefactory.php
@@ -6,7 +6,7 @@
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/storage/temporary.php b/lib/private/files/storage/temporary.php
index c8b99a55637..2d8e84c2d52 100644
--- a/lib/private/files/storage/temporary.php
+++ b/lib/private/files/storage/temporary.php
@@ -5,7 +5,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,7 +29,7 @@ namespace OC\Files\Storage;
*/
class Temporary extends Local{
public function __construct($arguments = null) {
- parent::__construct(array('datadir' => \OC_Helper::tmpFolder()));
+ parent::__construct(array('datadir' => \OC::$server->getTempManager()->getTemporaryFolder()));
}
public function cleanUp() {
diff --git a/lib/private/files/storage/wrapper/availability.php b/lib/private/files/storage/wrapper/availability.php
index d6ce78f6e44..1550c318ce3 100644
--- a/lib/private/files/storage/wrapper/availability.php
+++ b/lib/private/files/storage/wrapper/availability.php
@@ -1,8 +1,9 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -399,7 +400,6 @@ class Availability extends Wrapper {
/** {@inheritdoc} */
public function getOwner($path) {
- $this->checkAvailability();
try {
return parent::getOwner($path);
} catch (\OCP\Files\StorageNotAvailableException $e) {
diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php
index 8f5a7a05f01..69438ef0c7c 100644
--- a/lib/private/files/storage/wrapper/encryption.php
+++ b/lib/private/files/storage/wrapper/encryption.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,6 +28,7 @@ namespace OC\Files\Storage\Wrapper;
use OC\Encryption\Exceptions\ModuleDoesNotExistsException;
use OC\Encryption\Update;
use OC\Encryption\Util;
+use OC\Files\Cache\CacheEntry;
use OC\Files\Filesystem;
use OC\Files\Mount\Manager;
use OC\Files\Storage\LocalTempFileTrait;
@@ -123,13 +124,14 @@ class Encryption extends Wrapper {
public function filesize($path) {
$fullPath = $this->getFullPath($path);
+ /** @var CacheEntry $info */
$info = $this->getCache()->get($path);
if (isset($this->unencryptedSize[$fullPath])) {
$size = $this->unencryptedSize[$fullPath];
// update file cache
$info['encrypted'] = true;
$info['size'] = $size;
- $this->getCache()->put($path, $info);
+ $this->getCache()->put($path, $info->getData());
return $size;
}
diff --git a/lib/private/files/storage/wrapper/jail.php b/lib/private/files/storage/wrapper/jail.php
index 2857e74de46..40738befd93 100644
--- a/lib/private/files/storage/wrapper/jail.php
+++ b/lib/private/files/storage/wrapper/jail.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/storage/wrapper/permissionsmask.php b/lib/private/files/storage/wrapper/permissionsmask.php
index e1822905692..7fa64f82ba6 100644
--- a/lib/private/files/storage/wrapper/permissionsmask.php
+++ b/lib/private/files/storage/wrapper/permissionsmask.php
@@ -3,9 +3,9 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php
index 98664e27e2d..844505679df 100644
--- a/lib/private/files/storage/wrapper/quota.php
+++ b/lib/private/files/storage/wrapper/quota.php
@@ -3,10 +3,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,6 +25,8 @@
namespace OC\Files\Storage\Wrapper;
+use OCP\Files\Cache\ICacheEntry;
+
class Quota extends Wrapper {
/**
@@ -64,7 +66,7 @@ class Quota extends Wrapper {
$cache = $storage->getCache();
}
$data = $cache->get($path);
- if (is_array($data) and isset($data['size'])) {
+ if ($data instanceof ICacheEntry and isset($data['size'])) {
return $data['size'];
} else {
return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php
index 048738170db..c632aa399e1 100644
--- a/lib/private/files/storage/wrapper/wrapper.php
+++ b/lib/private/files/storage/wrapper/wrapper.php
@@ -2,11 +2,11 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,9 +26,10 @@
namespace OC\Files\Storage\Wrapper;
use OCP\Files\InvalidPathException;
+use OCP\Files\Storage\ILockingStorage;
use OCP\Lock\ILockingProvider;
-class Wrapper implements \OC\Files\Storage\Storage {
+class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage {
/**
* @var \OC\Files\Storage\Storage $storage
*/
@@ -430,6 +431,20 @@ class Wrapper implements \OC\Files\Storage\Storage {
return $this->storage->getWatcher($path, $storage);
}
+ public function getPropagator($storage = null) {
+ if (!$storage) {
+ $storage = $this;
+ }
+ return $this->storage->getPropagator($storage);
+ }
+
+ public function getUpdater($storage = null) {
+ if (!$storage) {
+ $storage = $this;
+ }
+ return $this->storage->getUpdater($storage);
+ }
+
/**
* @return \OC\Files\Cache\Storage
*/
@@ -569,7 +584,9 @@ class Wrapper implements \OC\Files\Storage\Storage {
* @throws \OCP\Lock\LockedException
*/
public function acquireLock($path, $type, ILockingProvider $provider) {
- $this->storage->acquireLock($path, $type, $provider);
+ if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $this->storage->acquireLock($path, $type, $provider);
+ }
}
/**
@@ -578,7 +595,9 @@ class Wrapper implements \OC\Files\Storage\Storage {
* @param \OCP\Lock\ILockingProvider $provider
*/
public function releaseLock($path, $type, ILockingProvider $provider) {
- $this->storage->releaseLock($path, $type, $provider);
+ if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $this->storage->releaseLock($path, $type, $provider);
+ }
}
/**
@@ -587,6 +606,8 @@ class Wrapper implements \OC\Files\Storage\Storage {
* @param \OCP\Lock\ILockingProvider $provider
*/
public function changeLock($path, $type, ILockingProvider $provider) {
- $this->storage->changeLock($path, $type, $provider);
+ if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $this->storage->changeLock($path, $type, $provider);
+ }
}
}
diff --git a/lib/private/files/stream/close.php b/lib/private/files/stream/close.php
index f704c875a14..1c9b30705dd 100644
--- a/lib/private/files/stream/close.php
+++ b/lib/private/files/stream/close.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/stream/dir.php b/lib/private/files/stream/dir.php
index 94f1cf81a2f..7489ee683a2 100644
--- a/lib/private/files/stream/dir.php
+++ b/lib/private/files/stream/dir.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -58,6 +58,7 @@ class Dir {
/**
* @param string $path
+ * @param string[] $content
*/
public static function register($path, $content) {
self::$dirs[$path] = $content;
diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php
index e0d263d80b1..c884cd8fa07 100644
--- a/lib/private/files/stream/encryption.php
+++ b/lib/private/files/stream/encryption.php
@@ -2,10 +2,11 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author jknockaert <jasper@knockaert.nl>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -167,7 +168,7 @@ class Encryption extends Wrapper {
)
));
- return self::wrapSource($source, $mode, $context, 'ocencryption', $wrapper);
+ return self::wrapSource($source, $context, 'ocencryption', $wrapper, $mode);
}
/**
@@ -181,7 +182,7 @@ class Encryption extends Wrapper {
* @return resource
* @throws \BadMethodCallException
*/
- protected static function wrapSource($source, $mode, $context, $protocol, $class) {
+ protected static function wrapSource($source, $context, $protocol, $class, $mode = 'r+') {
try {
stream_wrapper_register($protocol, $class);
if (@rewinddir($source) === false) {
@@ -471,4 +472,13 @@ class Encryption extends Wrapper {
return parent::stream_seek($position);
}
+ /**
+ * @param string $path
+ * @param array $options
+ * @return bool
+ */
+ public function dir_opendir($path, $options) {
+ return false;
+ }
+
}
diff --git a/lib/private/files/stream/oc.php b/lib/private/files/stream/oc.php
index 9087b812b2a..8439770e8fa 100644
--- a/lib/private/files/stream/oc.php
+++ b/lib/private/files/stream/oc.php
@@ -3,9 +3,9 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/stream/quota.php b/lib/private/files/stream/quota.php
index 5db58817a2b..8d27575c568 100644
--- a/lib/private/files/stream/quota.php
+++ b/lib/private/files/stream/quota.php
@@ -5,7 +5,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/stream/staticstream.php b/lib/private/files/stream/staticstream.php
index 74f921ceb96..7aacf7a9fe4 100644
--- a/lib/private/files/stream/staticstream.php
+++ b/lib/private/files/stream/staticstream.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/type/detection.php b/lib/private/files/type/detection.php
index c102e739e04..f106a98064f 100644
--- a/lib/private/files/type/detection.php
+++ b/lib/private/files/type/detection.php
@@ -5,11 +5,11 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -121,7 +121,7 @@ class Detection implements IMimeTypeDetector {
}
/**
- * @return array
+ * @return string[]
*/
public function getAllAliases() {
$this->loadAliases();
@@ -238,7 +238,7 @@ class Detection implements IMimeTypeDetector {
$finfo = finfo_open(FILEINFO_MIME);
return finfo_buffer($finfo, $data);
} else {
- $tmpFile = \OC_Helper::tmpFile();
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile();
$fh = fopen($tmpFile, 'wb');
fwrite($fh, $data, 8024);
fclose($fh);
@@ -264,7 +264,7 @@ class Detection implements IMimeTypeDetector {
/**
* Get path to the icon of a file type
- * @param string $mimeType the MIME type
+ * @param string $mimetype the MIME type
* @return string the url
*/
public function mimeTypeIcon($mimetype) {
diff --git a/lib/private/files/type/loader.php b/lib/private/files/type/loader.php
index 55dc09ab9b8..95ba7597257 100644
--- a/lib/private/files/type/loader.php
+++ b/lib/private/files/type/loader.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/type/templatemanager.php b/lib/private/files/type/templatemanager.php
index 33d3f7bfc76..363fb7a2a6c 100644
--- a/lib/private/files/type/templatemanager.php
+++ b/lib/private/files/type/templatemanager.php
@@ -2,9 +2,9 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/files/utils/scanner.php b/lib/private/files/utils/scanner.php
index 460c8007bf4..59673a306cb 100644
--- a/lib/private/files/utils/scanner.php
+++ b/lib/private/files/utils/scanner.php
@@ -7,7 +7,7 @@
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,12 +26,12 @@
namespace OC\Files\Utils;
-use OC\Files\View;
-use OC\Files\Cache\ChangePropagator;
use OC\Files\Filesystem;
use OC\ForbiddenException;
use OC\Hooks\PublicEmitter;
use OC\Lock\DBLockingProvider;
+use OCP\Files\StorageNotAvailableException;
+use OCP\ILogger;
/**
* Class Scanner
@@ -49,22 +49,23 @@ class Scanner extends PublicEmitter {
private $user;
/**
- * @var \OC\Files\Cache\ChangePropagator
+ * @var \OCP\IDBConnection
*/
- protected $propagator;
+ protected $db;
/**
- * @var \OCP\IDBConnection
+ * @var ILogger
*/
- protected $db;
+ protected $logger;
/**
* @param string $user
* @param \OCP\IDBConnection $db
+ * @param ILogger $logger
*/
- public function __construct($user, $db) {
+ public function __construct($user, $db, ILogger $logger) {
+ $this->logger = $logger;
$this->user = $user;
- $this->propagator = new ChangePropagator(new View(''));
$this->db = $db;
}
@@ -107,14 +108,6 @@ class Scanner extends PublicEmitter {
$scanner->listen('\OC\Files\Cache\Scanner', 'postScanFolder', function ($path) use ($mount, $emitter) {
$emitter->emit('\OC\Files\Utils\Scanner', 'postScanFolder', array($mount->getMountPoint() . $path));
});
- // propagate etag and mtimes when files are changed or removed
- $propagator = $this->propagator;
- $propagatorListener = function ($path) use ($mount, $propagator) {
- $fullPath = Filesystem::normalizePath($mount->getMountPoint() . $path);
- $propagator->addChange($fullPath);
- };
- $scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', $propagatorListener);
- $scanner->listen('\OC\Files\Cache\Scanner', 'removeFromCache', $propagatorListener);
}
/**
@@ -130,7 +123,6 @@ class Scanner extends PublicEmitter {
$this->attachListener($mount);
$scanner->backgroundScan();
}
- $this->propagator->propagateChanges(time());
}
/**
@@ -161,12 +153,17 @@ class Scanner extends PublicEmitter {
if (!$isDbLocking) {
$this->db->beginTransaction();
}
- $scanner->scan($relativePath, \OC\Files\Cache\Scanner::SCAN_RECURSIVE, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE);
+ try {
+ $scanner->scan($relativePath, \OC\Files\Cache\Scanner::SCAN_RECURSIVE, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE);
+ } catch (StorageNotAvailableException $e) {
+ $this->logger->error('Storage ' . $storage->getId() . ' not available');
+ $this->logger->logException($e);
+ $this->emit('\OC\Files\Utils\Scanner', 'StorageNotAvailable', [$e]);
+ }
if (!$isDbLocking) {
$this->db->commit();
}
}
- $this->propagator->propagateChanges(time());
}
}
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index 7dd83588ec6..2656e34cddf 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -15,15 +15,14 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
- * @author Roman Geber <rgeber@owncloudapps.com>
* @author Sam Tuke <mail@samtuke.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -44,13 +43,18 @@
namespace OC\Files;
use Icewind\Streams\CallbackWrapper;
-use OC\Files\Cache\Updater;
use OC\Files\Mount\MoveableMount;
+use OC\Files\Storage\Storage;
+use OC\User\User;
+use OCP\Constants;
+use OCP\Files\Cache\ICacheEntry;
use OCP\Files\FileNameTooLongException;
use OCP\Files\InvalidCharacterInPathException;
use OCP\Files\InvalidPathException;
use OCP\Files\NotFoundException;
use OCP\Files\ReservedWordException;
+use OCP\Files\Storage\ILockingStorage;
+use OCP\IUser;
use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
@@ -74,9 +78,6 @@ class View {
/** @var string */
private $fakeRoot = '';
- /** @var \OC\Files\Cache\Updater */
- protected $updater;
-
/**
* @var \OCP\Lock\ILockingProvider
*/
@@ -84,6 +85,10 @@ class View {
private $lockingEnabled;
+ private $updaterEnabled = true;
+
+ private $userManager;
+
/**
* @param string $root
* @throws \Exception If $root contains an invalid path
@@ -97,9 +102,9 @@ class View {
}
$this->fakeRoot = $root;
- $this->updater = new Updater($this);
$this->lockingProvider = \OC::$server->getLockingProvider();
$this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
+ $this->userManager = \OC::$server->getUserManager();
}
public function getAbsolutePath($path = '/') {
@@ -284,6 +289,35 @@ class View {
}
}
+ public function disableCacheUpdate() {
+ $this->updaterEnabled = false;
+ }
+
+ public function enableCacheUpdate() {
+ $this->updaterEnabled = true;
+ }
+
+ protected function writeUpdate(Storage $storage, $internalPath, $time = null) {
+ if ($this->updaterEnabled) {
+ if (is_null($time)) {
+ $time = time();
+ }
+ $storage->getUpdater()->update($internalPath, $time);
+ }
+ }
+
+ protected function removeUpdate(Storage $storage, $internalPath) {
+ if ($this->updaterEnabled) {
+ $storage->getUpdater()->remove($internalPath);
+ }
+ }
+
+ protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) {
+ if ($this->updaterEnabled) {
+ $targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ }
+ }
+
/**
* @param string $path
* @return bool|mixed
@@ -567,7 +601,7 @@ class View {
fclose($target);
fclose($data);
- $this->updater->update($path);
+ $this->writeUpdate($storage, $internalPath);
$this->changeLock($path, ILockingProvider::LOCK_SHARED);
@@ -687,28 +721,25 @@ class View {
} else {
$result = false;
}
- // moving a file/folder within the same mount point
+ // moving a file/folder within the same mount point
} elseif ($storage1 == $storage2) {
if ($storage1) {
$result = $storage1->rename($internalPath1, $internalPath2);
} else {
$result = false;
}
- // moving a file/folder between storages (from $storage1 to $storage2)
+ // moving a file/folder between storages (from $storage1 to $storage2)
} else {
$result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
}
if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
// if it was a rename from a part file to a regular file it was a write and not a rename operation
- $this->updater->update($path2);
+
+ $this->writeUpdate($storage2, $internalPath2);
} else if ($result) {
if ($internalPath1 !== '') { // dont do a cache update for moved mounts
- $this->updater->rename($path1, $path2);
- } else { // only do etag propagation
- $this->getUpdater()->getPropagator()->addChange($path1);
- $this->getUpdater()->getPropagator()->addChange($path2);
- $this->getUpdater()->getPropagator()->propagateChanges();
+ $this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
}
}
@@ -805,7 +836,7 @@ class View {
$result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2);
}
- $this->updater->update($path2);
+ $this->writeUpdate($storage2, $internalPath2);
$this->changeLock($path2, ILockingProvider::LOCK_SHARED);
$lockTypePath2 = ILockingProvider::LOCK_SHARED;
@@ -885,7 +916,7 @@ class View {
$source = $this->fopen($path, 'r');
if ($source) {
$extension = pathinfo($path, PATHINFO_EXTENSION);
- $tmpFile = \OC_Helper::tmpFile($extension);
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
file_put_contents($tmpFile, $source);
return $tmpFile;
} else {
@@ -1015,6 +1046,7 @@ class View {
}
$run = $this->runHooks($hooks, $path);
+ /** @var \OC\Files\Storage\Storage $storage */
list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
if ($run and $storage) {
if (in_array('write', $hooks) || in_array('delete', $hooks)) {
@@ -1036,13 +1068,13 @@ class View {
}
if (in_array('delete', $hooks) and $result) {
- $this->updater->remove($path);
+ $this->removeUpdate($storage, $internalPath);
}
if (in_array('write', $hooks) and $operation !== 'fopen') {
- $this->updater->update($path);
+ $this->writeUpdate($storage, $internalPath);
}
if (in_array('touch', $hooks)) {
- $this->updater->update($path, $extraParam);
+ $this->writeUpdate($storage, $internalPath, $extraParam);
}
if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) {
@@ -1164,19 +1196,73 @@ class View {
}
/**
+ * @param string $ownerId
+ * @return \OC\User\User
+ */
+ private function getUserObjectForOwner($ownerId) {
+ $owner = $this->userManager->get($ownerId);
+ if ($owner instanceof IUser) {
+ return $owner;
+ } else {
+ return new User($ownerId, null);
+ }
+ }
+
+ /**
+ * Get file info from cache
+ *
+ * If the file is not in cached it will be scanned
+ * If the file has changed on storage the cache will be updated
+ *
+ * @param \OC\Files\Storage\Storage $storage
+ * @param string $internalPath
+ * @param string $relativePath
+ * @return array|bool
+ */
+ private function getCacheEntry($storage, $internalPath, $relativePath) {
+ $cache = $storage->getCache($internalPath);
+ $data = $cache->get($internalPath);
+ $watcher = $storage->getWatcher($internalPath);
+
+ try {
+ // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data
+ if (!$data || $data['size'] === -1) {
+ $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
+ if (!$storage->file_exists($internalPath)) {
+ $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
+ return false;
+ }
+ $scanner = $storage->getScanner($internalPath);
+ $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
+ $data = $cache->get($internalPath);
+ $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
+ } else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) {
+ $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
+ $watcher->update($internalPath, $data);
+ $storage->getPropagator()->propagateChange($internalPath, time());
+ $data = $cache->get($internalPath);
+ $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
+ }
+ } catch (LockedException $e) {
+ // if the file is locked we just use the old cache info
+ }
+
+ return $data;
+ }
+
+ /**
* get the filesystem info
*
* @param string $path
* @param boolean|string $includeMountPoints true to add mountpoint sizes,
* 'ext' to add only ext storage mount point sizes. Defaults to true.
* defaults to true
- * @return \OC\Files\FileInfo|bool False if file does not exist
+ * @return \OC\Files\FileInfo|false False if file does not exist
*/
public function getFileInfo($path, $includeMountPoints = true) {
$this->assertPathLength($path);
- $data = array();
if (!Filesystem::isValidPath($path)) {
- return $data;
+ return false;
}
if (Cache\Scanner::isPartialFile($path)) {
return $this->getPartFileInfo($path);
@@ -1187,48 +1273,27 @@ class View {
$mount = Filesystem::getMountManager()->find($path);
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($path);
- $data = null;
if ($storage) {
- $cache = $storage->getCache($internalPath);
+ $data = $this->getCacheEntry($storage, $internalPath, $relativePath);
- $data = $cache->get($internalPath);
- $watcher = $storage->getWatcher($internalPath);
+ if (!$data instanceof ICacheEntry) {
+ return false;
+ }
- try {
- // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data
- if (!$data) {
- $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
- if (!$storage->file_exists($internalPath)) {
- $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
- return false;
- }
- $scanner = $storage->getScanner($internalPath);
- $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
- $data = $cache->get($internalPath);
- $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
- } else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) {
- $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
- $watcher->update($internalPath, $data);
- $this->updater->propagate($path);
- $data = $cache->get($internalPath);
- $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
- }
- } catch (LockedException $e) {
- // if the file is locked we just use the old cache info
+ if ($mount instanceof MoveableMount && $internalPath === '') {
+ $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
}
+ $owner = $this->getUserObjectForOwner($storage->getOwner($internalPath));
+ $info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner);
+
if ($data and isset($data['fileid'])) {
- // upgrades from oc6 or lower might not have the permissions set in the file cache
- if ($data['permissions'] === 0) {
- $data['permissions'] = $storage->getPermissions($data['path']);
- $cache->update($data['fileid'], array('permissions' => $data['permissions']));
- }
if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') {
//add the sizes of other mount points to the folder
$extOnly = ($includeMountPoints === 'ext');
- $mountPoints = Filesystem::getMountPoints($path);
- foreach ($mountPoints as $mountPoint) {
- $subStorage = Filesystem::getStorage($mountPoint);
+ $mounts = Filesystem::getMountManager()->findIn($path);
+ foreach ($mounts as $mount) {
+ $subStorage = $mount->getStorage();
if ($subStorage) {
// exclude shared storage ?
if ($extOnly && $subStorage instanceof \OC\Files\Storage\Shared) {
@@ -1236,22 +1301,16 @@ class View {
}
$subCache = $subStorage->getCache('');
$rootEntry = $subCache->get('');
- $data['size'] += isset($rootEntry['size']) ? $rootEntry['size'] : 0;
+ $info->addSubEntry($rootEntry, $mount->getMountPoint());
}
}
}
}
- }
- if (!$data) {
- return false;
- }
- if ($mount instanceof MoveableMount && $internalPath === '') {
- $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
+ return $info;
}
- $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
- return new FileInfo($path, $storage, $internalPath, $data, $mount, $owner);
+ return false;
}
/**
@@ -1263,9 +1322,8 @@ class View {
*/
public function getDirectoryContent($directory, $mimetype_filter = '') {
$this->assertPathLength($directory);
- $result = array();
if (!Filesystem::isValidPath($directory)) {
- return $result;
+ return [];
}
$path = $this->getAbsolutePath($directory);
$path = Filesystem::normalizePath($path);
@@ -1276,50 +1334,26 @@ class View {
$cache = $storage->getCache($internalPath);
$user = \OC_User::getUser();
- /**
- * @var \OC\Files\FileInfo[] $files
- */
- $files = array();
+ $data = $this->getCacheEntry($storage, $internalPath, $directory);
- $data = $cache->get($internalPath);
- $watcher = $storage->getWatcher($internalPath);
- try {
- if (!$data or $data['size'] === -1) {
- $this->lockFile($directory, ILockingProvider::LOCK_SHARED);
- if (!$storage->file_exists($internalPath)) {
- $this->unlockFile($directory, ILockingProvider::LOCK_SHARED);
- return array();
- }
- $scanner = $storage->getScanner($internalPath);
- $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
- $data = $cache->get($internalPath);
- $this->unlockFile($directory, ILockingProvider::LOCK_SHARED);
- } else if ($watcher->needsUpdate($internalPath, $data)) {
- $this->lockFile($directory, ILockingProvider::LOCK_SHARED);
- $watcher->update($internalPath, $data);
- $this->updater->propagate($path);
- $data = $cache->get($internalPath);
- $this->unlockFile($directory, ILockingProvider::LOCK_SHARED);
- }
- } catch (LockedException $e) {
- // if the file is locked we just use the old cache info
+ if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() && Constants::PERMISSION_READ)) {
+ return [];
}
$folderId = $data['fileid'];
$contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
- foreach ($contents as $content) {
- if ($content['permissions'] === 0) {
- $content['permissions'] = $storage->getPermissions($content['path']);
- $cache->update($content['fileid'], array('permissions' => $content['permissions']));
- }
- // if sharing was disabled for the user we remove the share permissions
- if (\OCP\Util::isSharingDisabledForUser()) {
+ $sharingDisabled = \OCP\Util::isSharingDisabledForUser();
+ /**
+ * @var \OC\Files\FileInfo[] $files
+ */
+ $files = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
+ if ($sharingDisabled) {
$content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
}
- $owner = \OC::$server->getUserManager()->get($storage->getOwner($content['path']));
- $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
- }
+ $owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
+ return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
+ }, $contents);
//add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
$mounts = Filesystem::getMountManager()->findIn($path);
@@ -1330,7 +1364,8 @@ class View {
if ($subStorage) {
$subCache = $subStorage->getCache('');
- if ($subCache->getStatus('') === Cache\Cache::NOT_FOUND) {
+ $rootEntry = $subCache->get('');
+ if (!$rootEntry) {
$subScanner = $subStorage->getScanner('');
try {
$subScanner->scanFile('');
@@ -1348,17 +1383,17 @@ class View {
);
continue;
}
+ $rootEntry = $subCache->get('');
}
- $rootEntry = $subCache->get('');
- if ($rootEntry) {
+ if ($rootEntry && ($rootEntry->getPermissions() && Constants::PERMISSION_READ)) {
$relativePath = trim(substr($mountPoint, $dirLength), '/');
if ($pos = strpos($relativePath, '/')) {
//mountpoint inside subfolder add size to the correct folder
$entryName = substr($relativePath, 0, $pos);
foreach ($files as &$entry) {
- if ($entry['name'] === $entryName) {
- $entry['size'] += $rootEntry['size'];
+ if ($entry->getName() === $entryName) {
+ $entry->addSubEntry($rootEntry, $mountPoint);
}
}
} else { //mountpoint in this folder, add an entry for it
@@ -1387,7 +1422,7 @@ class View {
$rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
}
- $owner = \OC::$server->getUserManager()->get($subStorage->getOwner(''));
+ $owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
$files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
}
}
@@ -1395,23 +1430,19 @@ class View {
}
if ($mimetype_filter) {
- foreach ($files as $file) {
+ $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
if (strpos($mimetype_filter, '/')) {
- if ($file['mimetype'] === $mimetype_filter) {
- $result[] = $file;
- }
+ return $file->getMimetype() === $mimetype_filter;
} else {
- if ($file['mimepart'] === $mimetype_filter) {
- $result[] = $file;
- }
+ return $file->getMimePart() === $mimetype_filter;
}
- }
- } else {
- $result = $files;
+ });
}
- }
- return $result;
+ return $files;
+ } else {
+ return [];
+ }
}
/**
@@ -1543,10 +1574,15 @@ class View {
* Get the owner for a file or folder
*
* @param string $path
- * @return string
+ * @return string the user id of the owner
+ * @throws NotFoundException
*/
public function getOwner($path) {
- return $this->basicOperation('getOwner', $path);
+ $info = $this->getFileInfo($path);
+ if (!$info) {
+ throw new NotFoundException($path . ' not found while trying to get owner');
+ }
+ return $info->getOwner()->getUID();
}
/**
@@ -1692,13 +1728,6 @@ class View {
}
/**
- * @return Updater
- */
- public function getUpdater() {
- return $this->updater;
- }
-
- /**
* @param string $path
* @param string $fileName
* @throws InvalidPathException
@@ -1812,11 +1841,14 @@ class View {
$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
if ($mount) {
try {
- $mount->getStorage()->acquireLock(
- $mount->getInternalPath($absolutePath),
- $type,
- $this->lockingProvider
- );
+ $storage = $mount->getStorage();
+ if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $storage->acquireLock(
+ $mount->getInternalPath($absolutePath),
+ $type,
+ $this->lockingProvider
+ );
+ }
} catch (\OCP\Lock\LockedException $e) {
// rethrow with the a human-readable path
throw new \OCP\Lock\LockedException(
@@ -1850,11 +1882,14 @@ class View {
$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
if ($mount) {
try {
- $mount->getStorage()->changeLock(
- $mount->getInternalPath($absolutePath),
- $type,
- $this->lockingProvider
- );
+ $storage = $mount->getStorage();
+ if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $storage->changeLock(
+ $mount->getInternalPath($absolutePath),
+ $type,
+ $this->lockingProvider
+ );
+ }
} catch (\OCP\Lock\LockedException $e) {
// rethrow with the a human-readable path
throw new \OCP\Lock\LockedException(
@@ -1885,11 +1920,14 @@ class View {
$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
if ($mount) {
- $mount->getStorage()->releaseLock(
- $mount->getInternalPath($absolutePath),
- $type,
- $this->lockingProvider
- );
+ $storage = $mount->getStorage();
+ if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
+ $storage->releaseLock(
+ $mount->getInternalPath($absolutePath),
+ $type,
+ $this->lockingProvider
+ );
+ }
}
return true;
@@ -1989,4 +2027,28 @@ class View {
}
return '';
}
+
+ /**
+ * @param string $filename
+ * @return array
+ * @throws \OC\User\NoUserException
+ * @throws NotFoundException
+ */
+ public function getUidAndFilename($filename) {
+ $info = $this->getFileInfo($filename);
+ if (!$info instanceof \OCP\Files\FileInfo) {
+ throw new NotFoundException($this->getAbsolutePath($filename) . ' not found');
+ }
+ $uid = $info->getOwner()->getUID();
+ if ($uid != \OCP\User::getUser()) {
+ Filesystem::initMountPoints($uid);
+ $ownerView = new View('/' . $uid . '/files');
+ try {
+ $filename = $ownerView->getPath($info['fileid']);
+ } catch (NotFoundException $e) {
+ throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid);
+ }
+ }
+ return [$uid, $filename];
+ }
}
diff --git a/lib/private/forbiddenexception.php b/lib/private/forbiddenexception.php
index e40cb33f4cf..48be35ba316 100644
--- a/lib/private/forbiddenexception.php
+++ b/lib/private/forbiddenexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/group.php b/lib/private/group.php
index 4eed2a85450..48fbe51007a 100644
--- a/lib/private/group.php
+++ b/lib/private/group.php
@@ -12,11 +12,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Qingping Hou <dave2008713@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -183,7 +183,7 @@ class OC_Group {
*
* This function fetches all groups a user belongs to. It does not check
* if the user exists at all.
- * @deprecated Use \OC::$server->getGroupManager->getuserGroupIds($user)
+ * @deprecated Use \OC::$server->getGroupManager->getUserGroupIds($user)
*/
public static function getUserGroups($uid) {
$user = self::getUserManager()->get($uid);
diff --git a/lib/private/group/backend.php b/lib/private/group/backend.php
index 52afb8fdcf0..ed2a2f4bb68 100644
--- a/lib/private/group/backend.php
+++ b/lib/private/group/backend.php
@@ -8,10 +8,10 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -53,7 +53,7 @@ define('OC_GROUP_BACKEND_COUNT_USERS', 0x00100000);
/**
* Abstract base class for user management
*/
-abstract class OC_Group_Backend implements OC_Group_Interface {
+abstract class OC_Group_Backend implements \OCP\GroupInterface {
/**
* error code for functions not provided by the group backend
*/
@@ -82,7 +82,7 @@ abstract class OC_Group_Backend implements OC_Group_Interface {
* @return int bitwise-or'ed actions
*
* Returns the supported actions as int to be
- * compared with OC_USER_BACKEND_CREATE_USER etc.
+ * compared with \OC_Group_Backend::CREATE_GROUP etc.
*/
public function getSupportedActions() {
$actions = 0;
@@ -101,7 +101,7 @@ abstract class OC_Group_Backend implements OC_Group_Interface {
* @return bool
*
* Returns the supported actions as int to be
- * compared with OC_GROUP_BACKEND_CREATE_GROUP etc.
+ * compared with \OC_Group_Backend::CREATE_GROUP etc.
*/
public function implementsActions($actions) {
return (bool)($this->getSupportedActions() & $actions);
diff --git a/lib/private/group/database.php b/lib/private/group/database.php
index ad6174808bb..21e7b103554 100644
--- a/lib/private/group/database.php
+++ b/lib/private/group/database.php
@@ -9,10 +9,10 @@
* @author michag86 <micha_g@arcor.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -50,6 +50,30 @@
*/
class OC_Group_Database extends OC_Group_Backend {
+ /** @var string[] */
+ private $groupCache = [];
+
+ /** @var \OCP\IDBConnection */
+ private $dbConn;
+
+ /**
+ * OC_Group_Database constructor.
+ *
+ * @param \OCP\IDBConnection|null $dbConn
+ */
+ public function __construct(\OCP\IDBConnection $dbConn = null) {
+ $this->dbConn = $dbConn;
+ }
+
+ /**
+ * FIXME: This function should not be required!
+ */
+ private function fixDI() {
+ if ($this->dbConn === null) {
+ $this->dbConn = \OC::$server->getDatabaseConnection();
+ }
+ }
+
/**
* Try to create a new group
* @param string $gid The name of the group to create
@@ -59,21 +83,17 @@ class OC_Group_Database extends OC_Group_Backend {
* be returned.
*/
public function createGroup( $gid ) {
- // Check for existence
- $stmt = OC_DB::prepare( "SELECT `gid` FROM `*PREFIX*groups` WHERE `gid` = ?" );
- $result = $stmt->execute( array( $gid ));
+ $this->fixDI();
- if( $result->fetchRow() ) {
- // Can not add an existing group
- return false;
- }
- else{
- // Add group and exit
- $stmt = OC_DB::prepare( "INSERT INTO `*PREFIX*groups` ( `gid` ) VALUES( ? )" );
- $result = $stmt->execute( array( $gid ));
+ // Add group
+ $result = $this->dbConn->insertIfNotExist('*PREFIX*groups', [
+ 'gid' => $gid,
+ ]);
- return $result ? true : false;
- }
+ // Add to cache
+ $this->groupCache[$gid] = $gid;
+
+ return $result === 1;
}
/**
@@ -84,17 +104,28 @@ class OC_Group_Database extends OC_Group_Backend {
* Deletes a group and removes it from the group_user-table
*/
public function deleteGroup( $gid ) {
+ $this->fixDI();
+
// Delete the group
- $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*groups` WHERE `gid` = ?" );
- $stmt->execute( array( $gid ));
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->delete('groups')
+ ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
+ ->execute();
// Delete the group-user relation
- $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*group_user` WHERE `gid` = ?" );
- $stmt->execute( array( $gid ));
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->delete('group_user')
+ ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
+ ->execute();
// Delete the group-groupadmin relation
- $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*group_admin` WHERE `gid` = ?" );
- $stmt->execute( array( $gid ));
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->delete('group_admin')
+ ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
+ ->execute();
+
+ // Delete from cache
+ unset($this->groupCache[$gid]);
return true;
}
@@ -108,11 +139,20 @@ class OC_Group_Database extends OC_Group_Backend {
* Checks whether the user is member of a group or not.
*/
public function inGroup( $uid, $gid ) {
+ $this->fixDI();
+
// check
- $stmt = OC_DB::prepare( "SELECT `uid` FROM `*PREFIX*group_user` WHERE `gid` = ? AND `uid` = ?" );
- $result = $stmt->execute( array( $gid, $uid ));
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('uid')
+ ->from('group_user')
+ ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
+ ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
+ ->execute();
- return $result->fetchRow() ? true : false;
+ $result = $cursor->fetch();
+ $cursor->closeCursor();
+
+ return $result ? true : false;
}
/**
@@ -124,10 +164,15 @@ class OC_Group_Database extends OC_Group_Backend {
* Adds a user to a group.
*/
public function addToGroup( $uid, $gid ) {
+ $this->fixDI();
+
// No duplicate entries!
if( !$this->inGroup( $uid, $gid )) {
- $stmt = OC_DB::prepare( "INSERT INTO `*PREFIX*group_user` ( `uid`, `gid` ) VALUES( ?, ? )" );
- $stmt->execute( array( $uid, $gid ));
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('group_user')
+ ->setValue('uid', $qb->createNamedParameter($uid))
+ ->setValue('gid', $qb->createNamedParameter($gid))
+ ->execute();
return true;
}else{
return false;
@@ -143,8 +188,13 @@ class OC_Group_Database extends OC_Group_Backend {
* removes the user from a group.
*/
public function removeFromGroup( $uid, $gid ) {
- $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*group_user` WHERE `uid` = ? AND `gid` = ?" );
- $stmt->execute( array( $uid, $gid ));
+ $this->fixDI();
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->delete('group_user')
+ ->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
+ ->andWhere($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
+ ->execute();
return true;
}
@@ -158,14 +208,21 @@ class OC_Group_Database extends OC_Group_Backend {
* if the user exists at all.
*/
public function getUserGroups( $uid ) {
+ $this->fixDI();
+
// No magic!
- $stmt = OC_DB::prepare( "SELECT `gid` FROM `*PREFIX*group_user` WHERE `uid` = ?" );
- $result = $stmt->execute( array( $uid ));
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('gid')
+ ->from('group_user')
+ ->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
+ ->execute();
- $groups = array();
- while( $row = $result->fetchRow()) {
+ $groups = [];
+ while( $row = $cursor->fetch()) {
$groups[] = $row["gid"];
+ $this->groupCache[$row['gid']] = $row['gid'];
}
+ $cursor->closeCursor();
return $groups;
}
@@ -202,9 +259,23 @@ class OC_Group_Database extends OC_Group_Backend {
* @return bool
*/
public function groupExists($gid) {
- $query = OC_DB::prepare('SELECT `gid` FROM `*PREFIX*groups` WHERE `gid` = ?');
- $result = $query->execute(array($gid))->fetchOne();
+ $this->fixDI();
+
+ // Check cache first
+ if (isset($this->groupCache[$gid])) {
+ return true;
+ }
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('gid')
+ ->from('groups')
+ ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
+ ->execute();
+ $result = $cursor->fetch();
+ $cursor->closeCursor();
+
if ($result !== false) {
+ $this->groupCache[$gid] = $gid;
return true;
}
return false;
diff --git a/lib/private/group/dummy.php b/lib/private/group/dummy.php
index 330b086ab3f..c0d206a34e1 100644
--- a/lib/private/group/dummy.php
+++ b/lib/private/group/dummy.php
@@ -6,11 +6,11 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/group/example.php b/lib/private/group/example.php
index fa2ed06129b..17fae90f2e0 100644
--- a/lib/private/group/example.php
+++ b/lib/private/group/example.php
@@ -6,9 +6,9 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/group/group.php b/lib/private/group/group.php
index f76ea1f36a7..064b9f899e6 100644
--- a/lib/private/group/group.php
+++ b/lib/private/group/group.php
@@ -6,9 +6,9 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/group/interface.php b/lib/private/group/interface.php
index c3a3cc052d6..240a50fe961 100644
--- a/lib/private/group/interface.php
+++ b/lib/private/group/interface.php
@@ -5,9 +5,9 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,63 +24,8 @@
*
*/
-interface OC_Group_Interface {
- /**
- * Check if backend implements actions
- * @param int $actions bitwise-or'ed actions
- * @return boolean
- *
- * Returns the supported actions as int to be
- * compared with \OC_Group_Backend::CREATE_GROUP etc.
- */
- public function implementsActions($actions);
-
- /**
- * is user in group?
- * @param string $uid uid of the user
- * @param string $gid gid of the group
- * @return bool
- *
- * Checks whether the user is member of a group or not.
- */
- public function inGroup($uid, $gid);
-
- /**
- * Get all groups a user belongs to
- * @param string $uid Name of the user
- * @return array an array of group names
- *
- * This function fetches all groups a user belongs to. It does not check
- * if the user exists at all.
- */
- public function getUserGroups($uid);
-
- /**
- * get a list of all groups
- * @param string $search
- * @param int $limit
- * @param int $offset
- * @return array an array of group names
- *
- * Returns a list with all groups
- */
- public function getGroups($search = '', $limit = -1, $offset = 0);
-
- /**
- * check if a group exists
- * @param string $gid
- * @return bool
- */
- public function groupExists($gid);
-
- /**
- * get a list of all users in a group
- * @param string $gid
- * @param string $search
- * @param int $limit
- * @param int $offset
- * @return array an array of user ids
- */
- public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0);
-
-}
+/**
+ * Interface OC_Group_Interface
+ * @deprecated use the public \OCP\GroupInterface instead
+ */
+interface OC_Group_Interface extends \OCP\GroupInterface {}
diff --git a/lib/private/group/manager.php b/lib/private/group/manager.php
index 73ff0e537c6..98e5551bcc5 100644
--- a/lib/private/group/manager.php
+++ b/lib/private/group/manager.php
@@ -8,12 +8,12 @@
* @author macjohnny <estebanmarin@gmx.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author voxsim <Simon Vocella>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -33,6 +33,7 @@
namespace OC\Group;
use OC\Hooks\PublicEmitter;
+use OCP\GroupInterface;
use OCP\IGroupManager;
/**
@@ -52,7 +53,7 @@ use OCP\IGroupManager;
*/
class Manager extends PublicEmitter implements IGroupManager {
/**
- * @var \OC_Group_Backend[]|\OC_Group_Database[] $backends
+ * @var GroupInterface[] $backends
*/
private $backends = array();
@@ -121,14 +122,19 @@ class Manager extends PublicEmitter implements IGroupManager {
}
/**
- * @param \OC_Group_Backend $backend
+ * @param \OCP\GroupInterface $backend
*/
public function addBackend($backend) {
$this->backends[] = $backend;
+ $this->clearCaches();
}
public function clearBackends() {
$this->backends = array();
+ $this->clearCaches();
+ }
+
+ protected function clearCaches() {
$this->cachedGroups = array();
$this->cachedUserGroups = array();
}
@@ -210,10 +216,13 @@ class Manager extends PublicEmitter implements IGroupManager {
}
/**
- * @param \OC\User\User $user
+ * @param \OC\User\User|null $user
* @return \OC\Group\Group[]
*/
public function getUserGroups($user) {
+ if (is_null($user)) {
+ return false;
+ }
return $this->getUserIdGroups($user->getUID());
}
diff --git a/lib/private/group/metadata.php b/lib/private/group/metadata.php
index 63ac0928563..8e0866479c1 100644
--- a/lib/private/group/metadata.php
+++ b/lib/private/group/metadata.php
@@ -7,7 +7,7 @@
* @author Stephan Peijnik <speijnik@anexia-it.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/helper.php b/lib/private/helper.php
index ee2f520fe2b..495f95e72d2 100644
--- a/lib/private/helper.php
+++ b/lib/private/helper.php
@@ -4,10 +4,10 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
* @author Christopher Schäpers <kondou@ts.unde.re>
+ * @author Clark Tomlinson <fallen013@gmail.com>
* @author Fabian Henze <flyser42@gmx.de>
* @author Felix Moeller <mail@felixmoeller.de>
* @author Frank Karlitschek <frank@owncloud.org>
- * @author François Kubler <francois@kubler.org>
* @author Georg Ehrke <georg@owncloud.com>
* @author Jakob Sack <mail@jakobsack.de>
* @author Jan-Christoph Borchardt <hey@jancborchardt.net>
@@ -16,20 +16,18 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Nicolas Grekas <nicolas.grekas@gmail.com>
* @author Olivier Paroz <github@oparoz.com>
* @author Owen Winkler <a_github@midnightcircus.com>
* @author Pellaeon Lin <nfsmwlin@gmail.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Simon Könnecke <simonkoennecke@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Valerio Ponte <valerio.ponte@gmail.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -54,97 +52,6 @@ class OC_Helper {
private static $templateManager;
/**
- * Creates an url using a defined route
- * @param string $route
- * @param array $parameters with param=>value, will be appended to the returned url
- * @return string the url
- * @deprecated Use \OC::$server->getURLGenerator()->linkToRoute($route, $parameters)
- *
- * Returns a url to the given app and file.
- */
- public static function linkToRoute($route, $parameters = array()) {
- return OC::$server->getURLGenerator()->linkToRoute($route, $parameters);
- }
-
- /**
- * Creates an url
- * @param string $app app
- * @param string $file file
- * @param array $args array with param=>value, will be appended to the returned url
- * The value of $args will be urlencoded
- * @return string the url
- * @deprecated Use \OC::$server->getURLGenerator()->linkTo($app, $file, $args)
- *
- * Returns a url to the given app and file.
- */
- public static function linkTo( $app, $file, $args = array() ) {
- return OC::$server->getURLGenerator()->linkTo($app, $file, $args);
- }
-
- /**
- * @param string $key
- * @return string url to the online documentation
- * @deprecated Use \OC::$server->getURLGenerator()->linkToDocs($key)
- */
- public static function linkToDocs($key) {
- return OC::$server->getURLGenerator()->linkToDocs($key);
- }
-
- /**
- * Creates an absolute url
- * @param string $app app
- * @param string $file file
- * @param array $args array with param=>value, will be appended to the returned url
- * The value of $args will be urlencoded
- * @return string the url
- *
- * Returns a absolute url to the given app and file.
- */
- public static function linkToAbsolute($app, $file, $args = array()) {
- return OC::$server->getURLGenerator()->getAbsoluteURL(
- self::linkTo($app, $file, $args)
- );
- }
-
- /**
- * Makes an $url absolute
- * @param string $url the url
- * @return string the absolute url
- * @deprecated Use \OC::$server->getURLGenerator()->getAbsoluteURL($url)
- *
- * Returns a absolute url to the given app and file.
- */
- public static function makeURLAbsolute($url) {
- return OC::$server->getURLGenerator()->getAbsoluteURL($url);
- }
-
- /**
- * Creates an url for remote use
- * @param string $service id
- * @return string the url
- *
- * Returns a url to the given service.
- */
- public static function linkToRemoteBase($service) {
- return self::linkTo('', 'remote.php') . '/' . $service;
- }
-
- /**
- * Creates an absolute url for remote use
- * @param string $service id
- * @param bool $add_slash
- * @return string the url
- *
- * Returns a absolute url to the given service.
- */
- public static function linkToRemote($service, $add_slash = true) {
- return OC::$server->getURLGenerator()->getAbsoluteURL(
- self::linkToRemoteBase($service)
- . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : '')
- );
- }
-
- /**
* Creates an absolute url for public use
* @param string $service id
* @param bool $add_slash
@@ -156,37 +63,12 @@ class OC_Helper {
if ($service === 'files') {
$url = OC::$server->getURLGenerator()->getAbsoluteURL('/s');
} else {
- $url = OC::$server->getURLGenerator()->getAbsoluteURL(self::linkTo('', 'public.php').'?service='.$service);
+ $url = OC::$server->getURLGenerator()->getAbsoluteURL(OC::$server->getURLGenerator()->linkTo('', 'public.php').'?service='.$service);
}
return $url . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : '');
}
/**
- * Creates path to an image
- * @param string $app app
- * @param string $image image name
- * @return string the url
- * @deprecated Use \OC::$server->getURLGenerator()->imagePath($app, $image)
- *
- * Returns the path to the image.
- */
- public static function imagePath($app, $image) {
- return OC::$server->getURLGenerator()->imagePath($app, $image);
- }
-
- /**
- * get path to icon of file type
- * @param string $mimetype mimetype
- * @return string the url
- *
- * Returns the path to the image of this file type.
- * @deprecated 8.2.0 Use \OC::$server->getMimeTypeDetector()->mimeTypeIcon($mimetype)
- */
- public static function mimetypeIcon($mimetype) {
- return \OC::$server->getMimeTypeDetector()->mimeTypeIcon($mimetype);
- }
-
- /**
* get path to preview of file
* @param string $path path
* @return string the url
@@ -194,21 +76,11 @@ class OC_Helper {
* Returns the path to the preview of the file.
*/
public static function previewIcon($path) {
- return self::linkToRoute( 'core_ajax_preview', array('x' => 32, 'y' => 32, 'file' => $path ));
+ return \OC::$server->getURLGenerator()->linkToRoute('core_ajax_preview', ['x' => 32, 'y' => 32, 'file' => $path]);
}
public static function publicPreviewIcon( $path, $token ) {
- return self::linkToRoute( 'core_ajax_public_preview', array('x' => 32, 'y' => 32, 'file' => $path, 't' => $token));
- }
-
- /**
- * shows whether the user has an avatar
- * @param string $user username
- * @return bool avatar set or not
- **/
- public static function userAvatarSet($user) {
- $avatar = new \OC\Avatar($user);
- return $avatar->exists();
+ return \OC::$server->getURLGenerator()->linkToRoute('core_ajax_public_preview', ['x' => 32, 'y' => 32, 'file' => $path, 't' => $token]);
}
/**
@@ -227,7 +99,7 @@ class OC_Helper {
}
$bytes = round($bytes / 1024, 0);
if ($bytes < 1024) {
- return "$bytes kB";
+ return "$bytes KB";
}
$bytes = round($bytes / 1024, 1);
if ($bytes < 1024) {
@@ -373,14 +245,6 @@ class OC_Helper {
}
/**
- * @return \OC\Files\Type\Detection
- * @deprecated 8.2.0 use \OC::$server->getMimeTypeDetector()
- */
- static public function getMimetypeDetector() {
- return \OC::$server->getMimeTypeDetector();
- }
-
- /**
* @return \OC\Files\Type\TemplateManager
*/
static public function getFileTemplateManager() {
@@ -391,51 +255,6 @@ class OC_Helper {
}
/**
- * Try to guess the mimetype based on filename
- *
- * @param string $path
- * @return string
- * @deprecated 8.2.0 Use \OC::$server->getMimeTypeDetector()->detectPath($path)
- */
- static public function getFileNameMimeType($path) {
- return \OC::$server->getMimeTypeDetector()->detectPath($path);
- }
-
- /**
- * get the mimetype form a local file
- *
- * @param string $path
- * @return string
- * does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead
- * @deprecated 8.2.0 Use \OC::$server->getMimeTypeDetector()->detect($path)
- */
- static function getMimeType($path) {
- return \OC::$server->getMimeTypeDetector()->detect($path);
- }
-
- /**
- * Get a secure mimetype that won't expose potential XSS.
- *
- * @param string $mimeType
- * @return string
- * @deprecated 8.2.0 Use \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType)
- */
- static function getSecureMimeType($mimeType) {
- return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
- }
-
- /**
- * get the mimetype form a data string
- *
- * @param string $data
- * @return string
- * @deprecated 8.2.0 Use \OC::$server->getMimeTypeDetector()->detectString($data)
- */
- static function getStringMimeType($data) {
- return \OC::$server->getMimeTypeDetector()->detectString($data);
- }
-
- /**
* detect if a given program is found in the search PATH
*
* @param string $name
@@ -462,7 +281,7 @@ class OC_Helper {
// Default check will be done with $path directories :
$dirs = explode(PATH_SEPARATOR, $path);
// WARNING : We have to check if open_basedir is enabled :
- $obd = ini_get('open_basedir');
+ $obd = OC::$server->getIniWrapper()->getString('open_basedir');
if ($obd != "none") {
$obd_values = explode(PATH_SEPARATOR, $obd);
if (count($obd_values) > 0 and $obd_values[0]) {
@@ -514,31 +333,6 @@ class OC_Helper {
}
/**
- * create a temporary file with an unique filename
- *
- * @param string $postfix
- * @return string
- * @deprecated Use the TempManager instead
- *
- * temporary files are automatically cleaned up after the script is finished
- */
- public static function tmpFile($postfix = '') {
- return \OC::$server->getTempManager()->getTemporaryFile($postfix);
- }
-
- /**
- * create a temporary folder with an unique filename
- *
- * @return string
- * @deprecated Use the TempManager instead
- *
- * temporary files are automatically cleaned up after the script is finished
- */
- public static function tmpFolder() {
- return \OC::$server->getTempManager()->getTemporaryFolder();
- }
-
- /**
* Adds a suffix to the name in case the file exists
*
* @param string $path
@@ -645,37 +439,6 @@ class OC_Helper {
}
/**
- * replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement.
- *
- * @param string $string
- * @param string $replacement The replacement string.
- * @param int $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string.
- * @param int $length Length of the part to be replaced
- * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
- * @return string
- * @deprecated 8.2.0 Use substr_replace() instead.
- */
- public static function mb_substr_replace($string, $replacement, $start, $length = 0, $encoding = 'UTF-8') {
- return substr_replace($string, $replacement, $start, $length);
- }
-
- /**
- * Replace all occurrences of the search string with the replacement string
- *
- * @param string $search The value being searched for, otherwise known as the needle.
- * @param string $replace The replacement
- * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack.
- * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
- * @param int $count If passed, this will be set to the number of replacements performed.
- * @return string
- * @deprecated 8.2.0 Use str_replace() instead.
- *
- */
- public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) {
- return str_replace($search, $replace, $subject, $count);
- }
-
- /**
* performs a search in a nested array
* @param array $haystack the array to be searched
* @param string $needle the search string
@@ -753,8 +516,9 @@ class OC_Helper {
* @return int PHP upload file size limit
*/
public static function uploadLimit() {
- $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize'));
- $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size'));
+ $ini = \OC::$server->getIniWrapper();
+ $upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize'));
+ $post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size'));
if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
return INF;
} elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) {
@@ -774,12 +538,13 @@ class OC_Helper {
if (!function_exists($function_name)) {
return false;
}
- $disabled = explode(',', ini_get('disable_functions'));
+ $ini = \OC::$server->getIniWrapper();
+ $disabled = explode(',', $ini->get('disable_functions'));
$disabled = array_map('trim', $disabled);
if (in_array($function_name, $disabled)) {
return false;
}
- $disabled = explode(',', ini_get('suhosin.executor.func.blacklist'));
+ $disabled = explode(',', $ini->get('suhosin.executor.func.blacklist'));
$disabled = array_map('trim', $disabled);
if (in_array($function_name, $disabled)) {
return false;
@@ -832,7 +597,7 @@ class OC_Helper {
*/
public static function getStorageInfo($path, $rootInfo = null) {
// return storage info without adding mount points
- $includeExtStorage = \OC_Config::getValue('quota_include_external_storage', false);
+ $includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
if (!$rootInfo) {
$rootInfo = \OC\Files\Filesystem::getFileInfo($path, false);
diff --git a/lib/private/hintexception.php b/lib/private/hintexception.php
index 3afc029f322..7c4754a92ef 100644
--- a/lib/private/hintexception.php
+++ b/lib/private/hintexception.php
@@ -5,7 +5,7 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -38,6 +38,9 @@ class HintException extends \Exception {
}
public function getHint() {
+ if (empty($this->hint)) {
+ return $this->message;
+ }
return $this->hint;
}
}
diff --git a/lib/private/hook.php b/lib/private/hook.php
index 2ff045c8a66..e9b18b3fc38 100644
--- a/lib/private/hook.php
+++ b/lib/private/hook.php
@@ -5,12 +5,12 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Sam Tuke <mail@samtuke.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -56,7 +56,7 @@ class OC_Hook{
self::$registered[$signalClass][$signalName] = array();
}
- // dont connect hooks twice
+ // don't connect hooks twice
foreach (self::$registered[$signalClass][$signalName] as $hook) {
if ($hook['class'] === $slotClass and $hook['name'] === $slotName) {
return false;
@@ -79,8 +79,8 @@ class OC_Hook{
* @param string $signalName name of signal
* @param mixed $params default: array() array with additional data
* @return bool true if slots exists or false if not
- * @throws \OC\ServerNotAvailableException
- * Emits a signal. To get data from the slot use references!
+ * @throws \OC\HintException
+ * @throws \OC\ServerNotAvailableException Emits a signal. To get data from the slot use references!
*
* TODO: write example
*/
@@ -104,38 +104,30 @@ class OC_Hook{
call_user_func( array( $i["class"], $i["name"] ), $params );
} catch (Exception $e){
self::$thrownExceptions[] = $e;
- $class = $i["class"];
- if (is_object($i["class"])) {
- $class = get_class($i["class"]);
- }
- $message = $e->getMessage();
- if (empty($message)) {
- $message = get_class($e);
+ \OC::$server->getLogger()->logException($e);
+ if($e instanceof \OC\HintException) {
+ throw $e;
}
- \OCP\Util::writeLog('hook',
- 'error while running hook (' . $class . '::' . $i["name"] . '): ' . $message,
- \OCP\Util::ERROR);
if($e instanceof \OC\ServerNotAvailableException) {
throw $e;
}
}
}
- // return true
return true;
}
/**
* clear hooks
- * @param string $signalclass
- * @param string $signalname
+ * @param string $signalClass
+ * @param string $signalName
*/
- static public function clear($signalclass='', $signalname='') {
- if($signalclass) {
- if($signalname) {
- self::$registered[$signalclass][$signalname]=array();
+ static public function clear($signalClass='', $signalName='') {
+ if ($signalClass) {
+ if ($signalName) {
+ self::$registered[$signalClass][$signalName]=array();
}else{
- self::$registered[$signalclass]=array();
+ self::$registered[$signalClass]=array();
}
}else{
self::$registered=array();
diff --git a/lib/private/hooks/basicemitter.php b/lib/private/hooks/basicemitter.php
index ae0f96fbc8c..067962ec081 100644
--- a/lib/private/hooks/basicemitter.php
+++ b/lib/private/hooks/basicemitter.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/hooks/emitter.php b/lib/private/hooks/emitter.php
index bea3f289b8d..d639e5ef892 100644
--- a/lib/private/hooks/emitter.php
+++ b/lib/private/hooks/emitter.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/hooks/emittertrait.php b/lib/private/hooks/emittertrait.php
index 256bf468c4f..775f46f838c 100644
--- a/lib/private/hooks/emittertrait.php
+++ b/lib/private/hooks/emittertrait.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/hooks/forwardingemitter.php b/lib/private/hooks/forwardingemitter.php
index 90c1970f480..6a1fc571cea 100644
--- a/lib/private/hooks/forwardingemitter.php
+++ b/lib/private/hooks/forwardingemitter.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/hooks/legacyemitter.php b/lib/private/hooks/legacyemitter.php
index b28854f4638..ac83477a144 100644
--- a/lib/private/hooks/legacyemitter.php
+++ b/lib/private/hooks/legacyemitter.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/hooks/publicemitter.php b/lib/private/hooks/publicemitter.php
index 12de07b27c7..4fe71073a1e 100644
--- a/lib/private/hooks/publicemitter.php
+++ b/lib/private/hooks/publicemitter.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/http/client/client.php b/lib/private/http/client/client.php
index 5f298e1acd7..bd9e82ddae7 100644
--- a/lib/private/http/client/client.php
+++ b/lib/private/http/client/client.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -58,12 +58,18 @@ class Client implements IClient {
* Sets the default options to the client
*/
private function setDefaultOptions() {
- // Either use default bundle or the user bundle if nothing is specified
- if($this->certificateManager->listCertificates() !== []) {
- $dataDir = $this->config->getSystemValue('datadirectory');
- $this->client->setDefaultOption('verify', $dataDir.'/'.$this->certificateManager->getCertificateBundle());
+ // Either use user bundle or the system bundle if nothing is specified
+ if ($this->certificateManager->listCertificates() !== []) {
+ $this->client->setDefaultOption('verify', $this->certificateManager->getAbsoluteBundlePath());
} else {
- $this->client->setDefaultOption('verify', \OC::$SERVERROOT . '/resources/config/ca-bundle.crt');
+ // If the instance is not yet setup we need to use the static path as
+ // $this->certificateManager->getAbsoluteBundlePath() tries to instantiiate
+ // a view
+ if($this->config->getSystemValue('installed', false)) {
+ $this->client->setDefaultOption('verify', $this->certificateManager->getAbsoluteBundlePath(null));
+ } else {
+ $this->client->setDefaultOption('verify', \OC::$SERVERROOT . '/resources/config/ca-bundle.crt');
+ }
}
$this->client->setDefaultOption('headers/User-Agent', 'ownCloud Server Crawler');
diff --git a/lib/private/http/client/clientservice.php b/lib/private/http/client/clientservice.php
index c9b415a7429..7e280dbf3ca 100644
--- a/lib/private/http/client/clientservice.php
+++ b/lib/private/http/client/clientservice.php
@@ -2,7 +2,7 @@
/**
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/http/client/response.php b/lib/private/http/client/response.php
index b3429f36d04..7a879eab111 100644
--- a/lib/private/http/client/response.php
+++ b/lib/private/http/client/response.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/httphelper.php b/lib/private/httphelper.php
index 9d9edb6a351..f33d4a51745 100644
--- a/lib/private/httphelper.php
+++ b/lib/private/httphelper.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/image.php b/lib/private/image.php
index 4ca9b811100..dc01f989d79 100644
--- a/lib/private/image.php
+++ b/lib/private/image.php
@@ -1,8 +1,8 @@
<?php
/**
* @author Andreas Fischer <bantu@owncloud.com>
- * @author Bart Visscher <bartv@thisnet.nl>
* @author Bartek Przybylski <bart.p.pl@gmail.com>
+ * @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
* @author Byron Marohn <combustible@live.com>
* @author Christopher Schäpers <kondou@ts.unde.re>
@@ -11,6 +11,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Johannes Willnecker <johannes@willnecker.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
* @author Robin Appelman <icewind@owncloud.com>
@@ -18,7 +19,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -39,17 +40,19 @@
* Class for basic image manipulation
*/
class OC_Image implements \OCP\IImage {
+ /** @var false|resource */
protected $resource = false; // tmp resource.
+ /** @var int */
protected $imageType = IMAGETYPE_PNG; // Default to png if file type isn't evident.
- protected $mimeType = "image/png"; // Default to png
+ /** @var string */
+ protected $mimeType = 'image/png'; // Default to png
+ /** @var int */
protected $bitDepth = 24;
+ /** @var null|string */
protected $filePath = null;
-
+ /** @var finfo */
private $fileInfo;
-
- /**
- * @var \OCP\ILogger
- */
+ /** @var \OCP\ILogger */
private $logger;
/**
diff --git a/lib/private/installer.php b/lib/private/installer.php
index 86968a7c189..f30db9ca659 100644
--- a/lib/private/installer.php
+++ b/lib/private/installer.php
@@ -3,6 +3,7 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Brice Maron <brice@bmaron.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Felix Moeller <mail@felixmoeller.de>
* @author Frank Karlitschek <frank@owncloud.org>
@@ -15,13 +16,12 @@
* @author michag86 <micha_g@arcor.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author root <root@oc.(none)>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -38,6 +38,9 @@
*
*/
+use OC\App\CodeChecker\CodeChecker;
+use OC\App\CodeChecker\EmptyCheck;
+use OC\App\CodeChecker\PrivateCheck;
use OC\OCSClient;
/**
@@ -82,9 +85,10 @@ class OC_Installer{
$l = \OC::$server->getL10N('lib');
list($extractDir, $path) = self::downloadApp($data);
- $info = self::checkAppsIntegrity($data, $extractDir, $path);
- $basedir=OC_App::getInstallPath().'/'.$info['id'];
+ $info = self::checkAppsIntegrity($data, $extractDir, $path);
+ $appId = OC_App::cleanAppId($info['id']);
+ $basedir = OC_App::getInstallPath().'/'.$appId;
//check if the destination directory already exists
if(is_dir($basedir)) {
OC_Helper::rmdirr($extractDir);
@@ -127,8 +131,8 @@ class OC_Installer{
}
//run appinfo/install.php
- if((!isset($data['noinstall']) or $data['noinstall']==false) and file_exists($basedir.'/appinfo/install.php')) {
- include $basedir.'/appinfo/install.php';
+ if((!isset($data['noinstall']) or $data['noinstall']==false)) {
+ self::includeAppScript($basedir . '/appinfo/install.php');
}
//set the installed version
@@ -163,6 +167,8 @@ class OC_Installer{
* @brief Update an application
* @param array $info
* @param bool $isShipped
+ * @throws Exception
+ * @return bool
*
* This function could work like described below, but currently it disables and then
* enables the app again. This does result in an updated app.
@@ -191,7 +197,7 @@ class OC_Installer{
* upgrade.php can determine the current installed version of the app using
* "\OC::$server->getAppConfig()->getValue($appid, 'installed_version')"
*/
- public static function updateApp( $info=array(), $isShipped=false) {
+ public static function updateApp($info=array(), $isShipped=false) {
list($extractDir, $path) = self::downloadApp($info);
$info = self::checkAppsIntegrity($info, $extractDir, $path, $isShipped);
@@ -232,8 +238,8 @@ class OC_Installer{
\OC::$server->getConfig(),
\OC::$server->getLogger()
);
- $appData = $ocsClient->getApplication($ocsId, \OC_Util::getVersion());
- $download = $ocsClient->getApplicationDownload($ocsId, \OC_Util::getVersion());
+ $appData = $ocsClient->getApplication($ocsId, \OCP\Util::getVersion());
+ $download = $ocsClient->getApplicationDownload($ocsId, \OCP\Util::getVersion());
if (isset($download['downloadlink']) && trim($download['downloadlink']) !== '') {
$download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
@@ -264,7 +270,7 @@ class OC_Installer{
//download the file if necessary
if($data['source']=='http') {
$pathInfo = pathinfo($data['href']);
- $path=OC_Helper::tmpFile('.' . $pathInfo['extension']);
+ $path = \OC::$server->getTempManager()->getTemporaryFile('.' . $pathInfo['extension']);
if(!isset($data['href'])) {
throw new \Exception($l->t("No href specified when installing app from http"));
}
@@ -278,13 +284,13 @@ class OC_Installer{
}
//detect the archive type
- $mime=OC_Helper::getMimeType($path);
+ $mime = \OC::$server->getMimeTypeDetector()->detect($path);
if ($mime !=='application/zip' && $mime !== 'application/x-gzip' && $mime !== 'application/x-bzip2') {
throw new \Exception($l->t("Archives of type %s are not supported", array($mime)));
}
//extract the archive in a temporary folder
- $extractDir=OC_Helper::tmpFolder();
+ $extractDir = \OC::$server->getTempManager()->getTemporaryFolder();
OC_Helper::rmdirr($extractDir);
mkdir($extractDir);
if($archive=OC_Archive::open($path)) {
@@ -307,11 +313,12 @@ class OC_Installer{
* check an app's integrity
* @param array $data
* @param string $extractDir
+ * @param string $path
* @param bool $isShipped
* @return array
* @throws \Exception
*/
- public static function checkAppsIntegrity($data, $extractDir, $path, $isShipped=false) {
+ public static function checkAppsIntegrity($data, $extractDir, $path, $isShipped = false) {
$l = \OC::$server->getL10N('lib');
//load the info.xml file of the app
if(!is_file($extractDir.'/appinfo/info.xml')) {
@@ -329,12 +336,41 @@ class OC_Installer{
}
if(!is_file($extractDir.'/appinfo/info.xml')) {
OC_Helper::rmdirr($extractDir);
- if($data['source']=='http') {
+ if($data['source'] === 'http') {
unlink($path);
}
throw new \Exception($l->t("App does not provide an info.xml file"));
}
- $info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml', true);
+
+ $info = OC_App::getAppInfo($extractDir.'/appinfo/info.xml', true);
+
+ // We can't trust the parsed info.xml file as it may have been tampered
+ // with by an attacker and thus we need to use the local data to check
+ // whether the application needs to be signed.
+ $appId = OC_App::cleanAppId($data['appdata']['id']);
+ $appBelongingToId = OC_App::getInternalAppIdByOcs($appId);
+ if(is_string($appBelongingToId)) {
+ $previouslySigned = \OC::$server->getConfig()->getAppValue($appBelongingToId, 'signed', 'false');
+ } else {
+ $appBelongingToId = $info['id'];
+ $previouslySigned = 'false';
+ }
+ if($data['appdata']['level'] === OC_App::officialApp || $previouslySigned === 'true') {
+ \OC::$server->getConfig()->setAppValue($appBelongingToId, 'signed', 'true');
+ $integrityResult = \OC::$server->getIntegrityCodeChecker()->verifyAppSignature(
+ $appBelongingToId,
+ $extractDir
+ );
+ if($integrityResult !== []) {
+ $e = new \Exception(
+ $l->t(
+ 'Signature could not get checked. Please contact the app developer and check your admin screen.'
+ )
+ );
+ throw $e;
+ }
+ }
+
// check the code for not allowed calls
if(!$isShipped && !OC_Installer::checkCode($extractDir)) {
OC_Helper::rmdirr($extractDir);
@@ -342,7 +378,7 @@ class OC_Installer{
}
// check if the app is compatible with this version of ownCloud
- if(!OC_App::isAppCompatible(OC_Util::getVersion(), $info)) {
+ if(!OC_App::isAppCompatible(\OCP\Util::getVersion(), $info)) {
OC_Helper::rmdirr($extractDir);
throw new \Exception($l->t("App can't be installed because it is not compatible with this version of ownCloud"));
}
@@ -400,7 +436,7 @@ class OC_Installer{
\OC::$server->getConfig(),
\OC::$server->getLogger()
);
- $ocsdata = $ocsClient->getApplication($ocsid, \OC_Util::getVersion());
+ $ocsdata = $ocsClient->getApplication($ocsid, \OCP\Util::getVersion());
$ocsversion= (string) $ocsdata['version'];
$currentversion=OC_App::getAppVersion($app);
if (version_compare($ocsversion, $currentversion, '>')) {
@@ -506,9 +542,10 @@ class OC_Installer{
if(!OC_Installer::isInstalled($filename)) {
$info=OC_App::getAppInfo($filename);
$enabled = isset($info['default_enable']);
- if( $enabled ) {
+ if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
+ && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
OC_Installer::installShippedApp($filename);
- \OC::$server->getAppConfig()->setValue($filename, 'enabled', 'yes');
+ \OC::$server->getConfig()->setAppValue($filename, 'enabled', 'yes');
}
}
}
@@ -526,29 +563,33 @@ class OC_Installer{
*/
public static function installShippedApp($app) {
//install the database
- if(is_file(OC_App::getAppPath($app)."/appinfo/database.xml")) {
- OC_DB::createDbFromStructure(OC_App::getAppPath($app)."/appinfo/database.xml");
+ $appPath = OC_App::getAppPath($app);
+ if(is_file("$appPath/appinfo/database.xml")) {
+ OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
}
//run appinfo/install.php
- if(is_file(OC_App::getAppPath($app)."/appinfo/install.php")) {
- include OC_App::getAppPath($app)."/appinfo/install.php";
- }
- $info=OC_App::getAppInfo($app);
+ \OC::$loader->addValidRoot($appPath);
+ self::includeAppScript("$appPath/appinfo/install.php");
+
+ $info = OC_App::getAppInfo($app);
if (is_null($info)) {
return false;
}
- \OC::$server->getAppConfig()->setValue($app, 'installed_version', OC_App::getAppVersion($app));
+
+ $config = \OC::$server->getConfig();
+
+ $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app));
if (array_key_exists('ocsid', $info)) {
- \OC::$server->getAppConfig()->setValue($app, 'ocsid', $info['ocsid']);
+ $config->setAppValue($app, 'ocsid', $info['ocsid']);
}
//set remote/public handlers
foreach($info['remote'] as $name=>$path) {
- OCP\CONFIG::setAppValue('core', 'remote_'.$name, $app.'/'.$path);
+ $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
}
foreach($info['public'] as $name=>$path) {
- OCP\CONFIG::setAppValue('core', 'public_'.$name, $app.'/'.$path);
+ $config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
}
OC_App::setAppTypes($info['id']);
@@ -563,13 +604,22 @@ class OC_Installer{
*/
public static function checkCode($folder) {
// is the code checker enabled?
- if(!OC_Config::getValue('appcodechecker', false)) {
+ if(!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) {
return true;
}
- $codeChecker = new \OC\App\CodeChecker();
+ $codeChecker = new CodeChecker(new PrivateCheck(new EmptyCheck()));
$errors = $codeChecker->analyseFolder($folder);
return empty($errors);
}
+
+ /**
+ * @param $basedir
+ */
+ private static function includeAppScript($script) {
+ if ( file_exists($script) ){
+ include $script;
+ }
+ }
}
diff --git a/lib/private/integritycheck/checker.php b/lib/private/integritycheck/checker.php
new file mode 100644
index 00000000000..e6f9f9a1457
--- /dev/null
+++ b/lib/private/integritycheck/checker.php
@@ -0,0 +1,523 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\IntegrityCheck;
+
+use OC\IntegrityCheck\Exceptions\InvalidSignatureException;
+use OC\IntegrityCheck\Helpers\AppLocator;
+use OC\IntegrityCheck\Helpers\EnvironmentHelper;
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
+use OC\Integritycheck\Iterator\ExcludeFileByNameFilterIterator;
+use OC\IntegrityCheck\Iterator\ExcludeFoldersByPathFilterIterator;
+use OCP\App\IAppManager;
+use OCP\ICache;
+use OCP\ICacheFactory;
+use OCP\IConfig;
+use phpseclib\Crypt\RSA;
+use phpseclib\File\X509;
+
+/**
+ * Class Checker handles the code signing using X.509 and RSA. ownCloud ships with
+ * a public root certificate certificate that allows to issue new certificates that
+ * will be trusted for signing code. The CN will be used to verify that a certificate
+ * given to a third-party developer may not be used for other applications. For
+ * example the author of the application "calendar" would only receive a certificate
+ * only valid for this application.
+ *
+ * @package OC\IntegrityCheck
+ */
+class Checker {
+ const CACHE_KEY = 'oc.integritycheck.checker';
+ /** @var EnvironmentHelper */
+ private $environmentHelper;
+ /** @var AppLocator */
+ private $appLocator;
+ /** @var FileAccessHelper */
+ private $fileAccessHelper;
+ /** @var IConfig */
+ private $config;
+ /** @var ICache */
+ private $cache;
+ /** @var IAppManager */
+ private $appManager;
+
+ /**
+ * @param EnvironmentHelper $environmentHelper
+ * @param FileAccessHelper $fileAccessHelper
+ * @param AppLocator $appLocator
+ * @param IConfig $config
+ * @param ICacheFactory $cacheFactory
+ * @param IAppManager $appManager
+ */
+ public function __construct(EnvironmentHelper $environmentHelper,
+ FileAccessHelper $fileAccessHelper,
+ AppLocator $appLocator,
+ IConfig $config = null,
+ ICacheFactory $cacheFactory,
+ IAppManager $appManager = null) {
+ $this->environmentHelper = $environmentHelper;
+ $this->fileAccessHelper = $fileAccessHelper;
+ $this->appLocator = $appLocator;
+ $this->config = $config;
+ $this->cache = $cacheFactory->create(self::CACHE_KEY);
+ $this->appManager = $appManager;
+ }
+
+ /**
+ * Whether code signing is enforced or not.
+ *
+ * @return bool
+ */
+ public function isCodeCheckEnforced() {
+ // FIXME: Once the signing server is instructed to sign daily, beta and
+ // RCs as well these need to be included also.
+ $signedChannels = [
+ 'daily',
+ 'testing',
+ 'stable',
+ ];
+ if(!in_array($this->environmentHelper->getChannel(), $signedChannels, true)) {
+ return false;
+ }
+
+ /**
+ * This config option is undocumented and supposed to be so, it's only
+ * applicable for very specific scenarios and we should not advertise it
+ * too prominent. So please do not add it to config.sample.php.
+ */
+ $isIntegrityCheckDisabled = $this->config->getSystemValue('integrity.check.disabled', false);
+ if($isIntegrityCheckDisabled === true) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Enumerates all files belonging to the folder. Sensible defaults are excluded.
+ *
+ * @param string $folderToIterate
+ * @param string $root
+ * @return \RecursiveIteratorIterator
+ * @throws \Exception
+ */
+ private function getFolderIterator($folderToIterate, $root = '') {
+ $dirItr = new \RecursiveDirectoryIterator(
+ $folderToIterate,
+ \RecursiveDirectoryIterator::SKIP_DOTS
+ );
+ if($root === '') {
+ $root = \OC::$SERVERROOT;
+ }
+ $root = rtrim($root, '/');
+
+ $excludeGenericFilesIterator = new ExcludeFileByNameFilterIterator($dirItr);
+ $excludeFoldersIterator = new ExcludeFoldersByPathFilterIterator($excludeGenericFilesIterator, $root);
+
+ return new \RecursiveIteratorIterator(
+ $excludeFoldersIterator,
+ \RecursiveIteratorIterator::SELF_FIRST
+ );
+ }
+
+ /**
+ * Returns an array of ['filename' => 'SHA512-hash-of-file'] for all files found
+ * in the iterator.
+ *
+ * @param \RecursiveIteratorIterator $iterator
+ * @param string $path
+ * @return array Array of hashes.
+ */
+ private function generateHashes(\RecursiveIteratorIterator $iterator,
+ $path) {
+ $hashes = [];
+
+ $baseDirectoryLength = strlen($path);
+ foreach($iterator as $filename => $data) {
+ /** @var \DirectoryIterator $data */
+ if($data->isDir()) {
+ continue;
+ }
+
+ $relativeFileName = substr($filename, $baseDirectoryLength);
+ $relativeFileName = ltrim($relativeFileName, '/');
+
+ // Exclude signature.json files in the appinfo and root folder
+ if($relativeFileName === 'appinfo/signature.json') {
+ continue;
+ }
+ // Exclude signature.json files in the appinfo and core folder
+ if($relativeFileName === 'core/signature.json') {
+ continue;
+ }
+
+ // The .htaccess file in the root folder of ownCloud can contain
+ // custom content after the installation due to the fact that dynamic
+ // content is written into it at installation time as well. This
+ // includes for example the 404 and 403 instructions.
+ // Thus we ignore everything below the first occurrence of
+ // "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####" and have the
+ // hash generated based on this.
+ if($filename === $this->environmentHelper->getServerRoot() . '/.htaccess') {
+ $fileContent = file_get_contents($filename);
+ $explodedArray = explode('#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####', $fileContent);
+ if(count($explodedArray) === 2) {
+ $hashes[$relativeFileName] = hash('sha512', $explodedArray[0]);
+ continue;
+ }
+ }
+
+ $hashes[$relativeFileName] = hash_file('sha512', $filename);
+ }
+ return $hashes;
+ }
+
+ /**
+ * Creates the signature data
+ *
+ * @param array $hashes
+ * @param X509 $certificate
+ * @param RSA $privateKey
+ * @return string
+ */
+ private function createSignatureData(array $hashes,
+ X509 $certificate,
+ RSA $privateKey) {
+ ksort($hashes);
+
+ $privateKey->setSignatureMode(RSA::SIGNATURE_PSS);
+ $privateKey->setMGFHash('sha512');
+ $signature = $privateKey->sign(json_encode($hashes));
+
+ return [
+ 'hashes' => $hashes,
+ 'signature' => base64_encode($signature),
+ 'certificate' => $certificate->saveX509($certificate->currentCert),
+ ];
+ }
+
+ /**
+ * Write the signature of the app in the specified folder
+ *
+ * @param string $path
+ * @param X509 $certificate
+ * @param RSA $privateKey
+ * @throws \Exception
+ */
+ public function writeAppSignature($path,
+ X509 $certificate,
+ RSA $privateKey) {
+ if(!is_dir($path)) {
+ throw new \Exception('Directory does not exist.');
+ }
+ $iterator = $this->getFolderIterator($path);
+ $hashes = $this->generateHashes($iterator, $path);
+ $signature = $this->createSignatureData($hashes, $certificate, $privateKey);
+ $this->fileAccessHelper->file_put_contents(
+ $path . '/appinfo/signature.json',
+ json_encode($signature, JSON_PRETTY_PRINT)
+ );
+ }
+
+ /**
+ * Write the signature of core
+ *
+ * @param X509 $certificate
+ * @param RSA $rsa
+ * @param string $path
+ */
+ public function writeCoreSignature(X509 $certificate,
+ RSA $rsa,
+ $path) {
+ $iterator = $this->getFolderIterator($path, $path);
+ $hashes = $this->generateHashes($iterator, $path);
+ $signatureData = $this->createSignatureData($hashes, $certificate, $rsa);
+ $this->fileAccessHelper->file_put_contents(
+ $path . '/core/signature.json',
+ json_encode($signatureData, JSON_PRETTY_PRINT)
+ );
+ }
+
+ /**
+ * Verifies the signature for the specified path.
+ *
+ * @param string $signaturePath
+ * @param string $basePath
+ * @param string $certificateCN
+ * @return array
+ * @throws InvalidSignatureException
+ * @throws \Exception
+ */
+ private function verify($signaturePath, $basePath, $certificateCN) {
+ if(!$this->isCodeCheckEnforced()) {
+ return [];
+ }
+
+ $signatureData = json_decode($this->fileAccessHelper->file_get_contents($signaturePath), true);
+ if(!is_array($signatureData)) {
+ throw new InvalidSignatureException('Signature data not found.');
+ }
+
+ $expectedHashes = $signatureData['hashes'];
+ ksort($expectedHashes);
+ $signature = base64_decode($signatureData['signature']);
+ $certificate = $signatureData['certificate'];
+
+ // Check if certificate is signed by ownCloud Root Authority
+ $x509 = new \phpseclib\File\X509();
+ $rootCertificatePublicKey = $this->fileAccessHelper->file_get_contents($this->environmentHelper->getServerRoot().'/resources/codesigning/root.crt');
+ $x509->loadCA($rootCertificatePublicKey);
+ $x509->loadX509($certificate);
+ if(!$x509->validateSignature()) {
+ throw new InvalidSignatureException('Certificate is not valid.');
+ }
+ // Verify if certificate has proper CN. "core" CN is always trusted.
+ if($x509->getDN(X509::DN_OPENSSL)['CN'] !== $certificateCN && $x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') {
+ throw new InvalidSignatureException(
+ sprintf('Certificate is not valid for required scope. (Requested: %s, current: %s)', $certificateCN, $x509->getDN(true))
+ );
+ }
+
+ // Check if the signature of the files is valid
+ $rsa = new \phpseclib\Crypt\RSA();
+ $rsa->loadKey($x509->currentCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']);
+ $rsa->setSignatureMode(RSA::SIGNATURE_PSS);
+ $rsa->setMGFHash('sha512');
+ if(!$rsa->verify(json_encode($expectedHashes), $signature)) {
+ throw new InvalidSignatureException('Signature could not get verified.');
+ }
+
+ // Compare the list of files which are not identical
+ $currentInstanceHashes = $this->generateHashes($this->getFolderIterator($basePath), $basePath);
+ $differencesA = array_diff($expectedHashes, $currentInstanceHashes);
+ $differencesB = array_diff($currentInstanceHashes, $expectedHashes);
+ $differences = array_unique(array_merge($differencesA, $differencesB));
+ $differenceArray = [];
+ foreach($differences as $filename => $hash) {
+ // Check if file should not exist in the new signature table
+ if(!array_key_exists($filename, $expectedHashes)) {
+ $differenceArray['EXTRA_FILE'][$filename]['expected'] = '';
+ $differenceArray['EXTRA_FILE'][$filename]['current'] = $hash;
+ continue;
+ }
+
+ // Check if file is missing
+ if(!array_key_exists($filename, $currentInstanceHashes)) {
+ $differenceArray['FILE_MISSING'][$filename]['expected'] = $expectedHashes[$filename];
+ $differenceArray['FILE_MISSING'][$filename]['current'] = '';
+ continue;
+ }
+
+ // Check if hash does mismatch
+ if($expectedHashes[$filename] !== $currentInstanceHashes[$filename]) {
+ $differenceArray['INVALID_HASH'][$filename]['expected'] = $expectedHashes[$filename];
+ $differenceArray['INVALID_HASH'][$filename]['current'] = $currentInstanceHashes[$filename];
+ continue;
+ }
+
+ // Should never happen.
+ throw new \Exception('Invalid behaviour in file hash comparison experienced. Please report this error to the developers.');
+ }
+
+ return $differenceArray;
+ }
+
+ /**
+ * Whether the code integrity check has passed successful or not
+ *
+ * @return bool
+ */
+ public function hasPassedCheck() {
+ $results = $this->getResults();
+ if(empty($results)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return array
+ */
+ public function getResults() {
+ $cachedResults = $this->cache->get(self::CACHE_KEY);
+ if(!is_null($cachedResults)) {
+ return json_decode($cachedResults, true);
+ }
+
+ return json_decode($this->config->getAppValue('core', self::CACHE_KEY, '{}'), true);
+ }
+
+ /**
+ * Stores the results in the app config as well as cache
+ *
+ * @param string $scope
+ * @param array $result
+ */
+ private function storeResults($scope, array $result) {
+ $resultArray = $this->getResults();
+ unset($resultArray[$scope]);
+ if(!empty($result)) {
+ $resultArray[$scope] = $result;
+ }
+ $this->config->setAppValue('core', self::CACHE_KEY, json_encode($resultArray));
+ $this->cache->set(self::CACHE_KEY, json_encode($resultArray));
+ }
+
+ /**
+ *
+ * Clean previous results for a proper rescanning. Otherwise
+ */
+ private function cleanResults() {
+ $this->config->deleteAppValue('core', self::CACHE_KEY);
+ $this->cache->remove(self::CACHE_KEY);
+ }
+
+ /**
+ * Verify the signature of $appId. Returns an array with the following content:
+ * [
+ * 'FILE_MISSING' =>
+ * [
+ * 'filename' => [
+ * 'expected' => 'expectedSHA512',
+ * 'current' => 'currentSHA512',
+ * ],
+ * ],
+ * 'EXTRA_FILE' =>
+ * [
+ * 'filename' => [
+ * 'expected' => 'expectedSHA512',
+ * 'current' => 'currentSHA512',
+ * ],
+ * ],
+ * 'INVALID_HASH' =>
+ * [
+ * 'filename' => [
+ * 'expected' => 'expectedSHA512',
+ * 'current' => 'currentSHA512',
+ * ],
+ * ],
+ * ]
+ *
+ * Array may be empty in case no problems have been found.
+ *
+ * @param string $appId
+ * @param string $path Optional path. If none is given it will be guessed.
+ * @return array
+ */
+ public function verifyAppSignature($appId, $path = '') {
+ try {
+ if($path === '') {
+ $path = $this->appLocator->getAppPath($appId);
+ }
+ $result = $this->verify(
+ $path . '/appinfo/signature.json',
+ $path,
+ $appId
+ );
+ } catch (\Exception $e) {
+ $result = [
+ 'EXCEPTION' => [
+ 'class' => get_class($e),
+ 'message' => $e->getMessage(),
+ ],
+ ];
+ }
+ $this->storeResults($appId, $result);
+
+ return $result;
+ }
+
+ /**
+ * Verify the signature of core. Returns an array with the following content:
+ * [
+ * 'FILE_MISSING' =>
+ * [
+ * 'filename' => [
+ * 'expected' => 'expectedSHA512',
+ * 'current' => 'currentSHA512',
+ * ],
+ * ],
+ * 'EXTRA_FILE' =>
+ * [
+ * 'filename' => [
+ * 'expected' => 'expectedSHA512',
+ * 'current' => 'currentSHA512',
+ * ],
+ * ],
+ * 'INVALID_HASH' =>
+ * [
+ * 'filename' => [
+ * 'expected' => 'expectedSHA512',
+ * 'current' => 'currentSHA512',
+ * ],
+ * ],
+ * ]
+ *
+ * Array may be empty in case no problems have been found.
+ *
+ * @return array
+ */
+ public function verifyCoreSignature() {
+ try {
+ $result = $this->verify(
+ $this->environmentHelper->getServerRoot() . '/core/signature.json',
+ $this->environmentHelper->getServerRoot(),
+ 'core'
+ );
+ } catch (\Exception $e) {
+ $result = [
+ 'EXCEPTION' => [
+ 'class' => get_class($e),
+ 'message' => $e->getMessage(),
+ ],
+ ];
+ }
+ $this->storeResults('core', $result);
+
+ return $result;
+ }
+
+ /**
+ * Verify the core code of the instance as well as all applicable applications
+ * and store the results.
+ */
+ public function runInstanceVerification() {
+ $this->cleanResults();
+ $this->verifyCoreSignature();
+ $appIds = $this->appLocator->getAllApps();
+ foreach($appIds as $appId) {
+ // If an application is shipped a valid signature is required
+ $isShipped = $this->appManager->isShipped($appId);
+ $appNeedsToBeChecked = false;
+ if ($isShipped) {
+ $appNeedsToBeChecked = true;
+ } elseif ($this->fileAccessHelper->file_exists($this->appLocator->getAppPath($appId) . '/appinfo/signature.json')) {
+ // Otherwise only if the application explicitly ships a signature.json file
+ $appNeedsToBeChecked = true;
+ }
+
+ if($appNeedsToBeChecked) {
+ $this->verifyAppSignature($appId);
+ }
+ }
+ }
+}
diff --git a/lib/private/integritycheck/exceptions/invalidsignatureexception.php b/lib/private/integritycheck/exceptions/invalidsignatureexception.php
new file mode 100644
index 00000000000..521171642b2
--- /dev/null
+++ b/lib/private/integritycheck/exceptions/invalidsignatureexception.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\IntegrityCheck\Exceptions;
+
+/**
+ * Class InvalidSignatureException is thrown in case the signature of the hashes
+ * cannot be properly validated. This indicates that either files
+ *
+ * @package OC\IntegrityCheck\Exceptions
+ */
+class InvalidSignatureException extends \Exception {}
diff --git a/lib/private/integritycheck/helpers/applocator.php b/lib/private/integritycheck/helpers/applocator.php
new file mode 100644
index 00000000000..af22fca1fe4
--- /dev/null
+++ b/lib/private/integritycheck/helpers/applocator.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\IntegrityCheck\Helpers;
+
+/**
+ * Class AppLocator provides a non-static helper for OC_App::getPath($appId)
+ * it is not possible to use IAppManager at this point as IAppManager has a
+ * dependency on a running ownCloud.
+ *
+ * @package OC\IntegrityCheck\Helpers
+ */
+class AppLocator {
+ /**
+ * Provides \OC_App::getAppPath($appId)
+ *
+ * @param string $appId
+ * @return string
+ * @throws \Exception If the app cannot be found
+ */
+ public function getAppPath($appId) {
+ $path = \OC_App::getAppPath($appId);
+ if($path === false) {
+
+ throw new \Exception('App not found');
+ }
+ return $path;
+ }
+
+ /**
+ * Providers \OC_App::getAllApps()
+ *
+ * @return array
+ */
+ public function getAllApps() {
+ return \OC_App::getAllApps();
+ }
+}
diff --git a/lib/private/integritycheck/helpers/environmenthelper.php b/lib/private/integritycheck/helpers/environmenthelper.php
new file mode 100644
index 00000000000..f56f07486c2
--- /dev/null
+++ b/lib/private/integritycheck/helpers/environmenthelper.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\IntegrityCheck\Helpers;
+
+/**
+ * Class EnvironmentHelper provides a non-static helper for access to static
+ * variables such as \OC::$SERVERROOT.
+ *
+ * @package OC\IntegrityCheck\Helpers
+ */
+class EnvironmentHelper {
+ /**
+ * Provides \OC::$SERVERROOT
+ *
+ * @return string
+ */
+ public function getServerRoot() {
+ return rtrim(\OC::$SERVERROOT, '/');
+ }
+
+ /**
+ * Provides \OC_Util::getChannel()
+ *
+ * @return string
+ */
+ public function getChannel() {
+ return \OC_Util::getChannel();
+ }
+}
diff --git a/lib/private/integritycheck/helpers/fileaccesshelper.php b/lib/private/integritycheck/helpers/fileaccesshelper.php
new file mode 100644
index 00000000000..f0bf6576d35
--- /dev/null
+++ b/lib/private/integritycheck/helpers/fileaccesshelper.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\IntegrityCheck\Helpers;
+
+/**
+ * Class FileAccessHelper provides a helper around file_get_contents and
+ * file_put_contents
+ *
+ * @package OC\IntegrityCheck\Helpers
+ */
+class FileAccessHelper {
+ /**
+ * Wrapper around file_get_contents($filename, $data)
+ *
+ * @param string $filename
+ * @return string|false
+ */
+ public function file_get_contents($filename) {
+ return file_get_contents($filename);
+ }
+
+ /**
+ * Wrapper around file_exists($filename)
+ *
+ * @param string $filename
+ * @return bool
+ */
+ public function file_exists($filename) {
+ return file_exists($filename);
+ }
+
+ /**
+ * Wrapper around file_put_contents($filename, $data)
+ *
+ * @param string $filename
+ * @param $data
+ * @return int|false
+ */
+ public function file_put_contents($filename, $data) {
+ return file_put_contents($filename, $data);
+ }
+}
diff --git a/lib/private/integritycheck/iterator/excludefilebynamefilteriterator.php b/lib/private/integritycheck/iterator/excludefilebynamefilteriterator.php
new file mode 100644
index 00000000000..51850852cbd
--- /dev/null
+++ b/lib/private/integritycheck/iterator/excludefilebynamefilteriterator.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\IntegrityCheck\Iterator;
+
+/**
+ * Class ExcludeFileByNameFilterIterator provides a custom iterator which excludes
+ * entries with the specified file name from the file list.
+ *
+ * @package OC\Integritycheck\Iterator
+ */
+class ExcludeFileByNameFilterIterator extends \RecursiveFilterIterator {
+ /**
+ * Array of excluded file names. Those are not scanned by the integrity checker.
+ * This is used to exclude files which administrators could upload by mistakes
+ * such as .DS_Store files.
+ *
+ * @var array
+ */
+ private $excludedFilenames = [
+ '.DS_Store', // Mac OS X
+ 'Thumbs.db', // Microsoft Windows
+ '.directory', // Dolphin (KDE)
+ ];
+
+ /**
+ * @return bool
+ */
+ public function accept() {
+ if($this->isDir()) {
+ return true;
+ }
+
+ return !in_array(
+ $this->current()->getFilename(),
+ $this->excludedFilenames,
+ true
+ );
+ }
+}
diff --git a/lib/private/integritycheck/iterator/excludefoldersbypathfilteriterator.php b/lib/private/integritycheck/iterator/excludefoldersbypathfilteriterator.php
new file mode 100644
index 00000000000..67bcd423b68
--- /dev/null
+++ b/lib/private/integritycheck/iterator/excludefoldersbypathfilteriterator.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\IntegrityCheck\Iterator;
+
+class ExcludeFoldersByPathFilterIterator extends \RecursiveFilterIterator {
+ private $excludedFolders = [];
+
+ public function __construct(\RecursiveIterator $iterator, $root = '') {
+ parent::__construct($iterator);
+
+ $appFolders = \OC::$APPSROOTS;
+ foreach($appFolders as $key => $appFolder) {
+ $appFolders[$key] = rtrim($appFolder['path'], '/');
+ }
+
+ $this->excludedFolders = array_merge([
+ rtrim($root . '/data', '/'),
+ rtrim($root .'/themes', '/'),
+ rtrim($root.'/config', '/'),
+ rtrim($root.'/apps', '/'),
+ ], $appFolders);
+ }
+
+ /**
+ * @return bool
+ */
+ public function accept() {
+ return !in_array(
+ $this->current()->getPathName(),
+ $this->excludedFolders,
+ true
+ );
+ }
+}
diff --git a/lib/private/json.php b/lib/private/json.php
index eba374f4da2..adee28a1593 100644
--- a/lib/private/json.php
+++ b/lib/private/json.php
@@ -11,7 +11,7 @@
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -76,7 +76,7 @@ class OC_JSON{
* @deprecated Use annotation based CSRF checks from the AppFramework instead
*/
public static function callCheck() {
- if( !OC_Util::isCallRegistered()) {
+ if( !(\OC::$server->getRequest()->passesCSRFCheck())) {
$l = \OC::$server->getL10N('lib');
self::error(array( 'data' => array( 'message' => $l->t('Token expired. Please reload page.'), 'error' => 'token_expired' )));
exit();
diff --git a/lib/private/l10n/factory.php b/lib/private/l10n/factory.php
index b92c21b2d5d..f4f7d897061 100644
--- a/lib/private/l10n/factory.php
+++ b/lib/private/l10n/factory.php
@@ -4,9 +4,9 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,16 +25,56 @@
namespace OC\L10N;
+use OCP\IConfig;
+use OCP\IRequest;
+use OCP\IUserSession;
use OCP\L10N\IFactory;
/**
* A factory that generates language instances
*/
class Factory implements IFactory {
+
+ /** @var string */
+ protected $requestLanguage = '';
+
/**
* cached instances
+ * @var array Structure: Lang => App => \OCP\IL10N
+ */
+ protected $instances = [];
+
+ /**
+ * @var array Structure: App => string[]
+ */
+ protected $availableLanguages = [];
+
+ /**
+ * @var array Structure: string => callable
*/
- protected $instances = array();
+ protected $pluralFunctions = [];
+
+ /** @var IConfig */
+ protected $config;
+
+ /** @var IRequest */
+ protected $request;
+
+ /** @var IUserSession */
+ protected $userSession;
+
+ /**
+ * @param IConfig $config
+ * @param IRequest $request
+ * @param IUserSession $userSession
+ */
+ public function __construct(IConfig $config,
+ IRequest $request,
+ IUserSession $userSession) {
+ $this->config = $config;
+ $this->request = $request;
+ $this->userSession = $userSession;
+ }
/**
* Get a language instance
@@ -44,16 +84,285 @@ class Factory implements IFactory {
* @return \OCP\IL10N
*/
public function get($app, $lang = null) {
+ $app = \OC_App::cleanAppId($app);
+ if ($lang !== null) {
+ $lang = str_replace(array('\0', '/', '\\', '..'), '', (string) $lang);
+ }
$key = $lang;
- if ($key === null) {
+ if ($key === null || !$this->languageExists($app, $lang)) {
$key = 'null';
+ $lang = $this->findLanguage($app);
}
if (!isset($this->instances[$key][$app])) {
- $this->instances[$key][$app] = new \OC_L10N($app, $lang);
+ $this->instances[$key][$app] = new L10N(
+ $this, $app, $lang,
+ $this->getL10nFilesForApp($app, $lang)
+ );
}
return $this->instances[$key][$app];
}
+ /**
+ * Find the best language
+ *
+ * @param string|null $app App id or null for core
+ * @return string language If nothing works it returns 'en'
+ */
+ public function findLanguage($app = null) {
+ if ($this->requestLanguage !== '' && $this->languageExists($app, $this->requestLanguage)) {
+ return $this->requestLanguage;
+ }
+
+ /**
+ * At this point ownCloud might not yet be installed and thus the lookup
+ * in the preferences table might fail. For this reason we need to check
+ * whether the instance has already been installed
+ *
+ * @link https://github.com/owncloud/core/issues/21955
+ */
+ if($this->config->getSystemValue('installed', false)) {
+ $userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() : null;
+ if(!is_null($userId)) {
+ $userLang = $this->config->getUserValue($userId, 'core', 'lang', null);
+ } else {
+ $userLang = null;
+ }
+ } else {
+ $userId = null;
+ $userLang = null;
+ }
+
+ if ($userLang) {
+ $this->requestLanguage = $userLang;
+ if ($this->languageExists($app, $userLang)) {
+ return $userLang;
+ }
+ }
+
+ $defaultLanguage = $this->config->getSystemValue('default_language', false);
+
+ if ($defaultLanguage !== false && $this->languageExists($app, $defaultLanguage)) {
+ return $defaultLanguage;
+ }
+
+ $lang = $this->setLanguageFromRequest($app);
+ if ($userId !== null && $app === null && !$userLang) {
+ $this->config->setUserValue($userId, 'core', 'lang', $lang);
+ }
+
+ return $lang;
+ }
+
+ /**
+ * Find all available languages for an app
+ *
+ * @param string|null $app App id or null for core
+ * @return array an array of available languages
+ */
+ public function findAvailableLanguages($app = null) {
+ $key = $app;
+ if ($key === null) {
+ $key = 'null';
+ }
+
+ // also works with null as key
+ if (!empty($this->availableLanguages[$key])) {
+ return $this->availableLanguages[$key];
+ }
+
+ $available = ['en']; //english is always available
+ $dir = $this->findL10nDir($app);
+ if (is_dir($dir)) {
+ $files = scandir($dir);
+ if ($files !== false) {
+ foreach ($files as $file) {
+ if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
+ $available[] = substr($file, 0, -5);
+ }
+ }
+ }
+ }
+
+ $this->availableLanguages[$key] = $available;
+ return $available;
+ }
+
+ /**
+ * @param string|null $app App id or null for core
+ * @param string $lang
+ * @return bool
+ */
+ public function languageExists($app, $lang) {
+ if ($lang === 'en') {//english is always available
+ return true;
+ }
+
+ $languages = $this->findAvailableLanguages($app);
+ return array_search($lang, $languages) !== false;
+ }
+
+ /**
+ * @param string|null $app App id or null for core
+ * @return string
+ */
+ public function setLanguageFromRequest($app = null) {
+ $header = $this->request->getHeader('ACCEPT_LANGUAGE');
+ if ($header) {
+ $available = $this->findAvailableLanguages($app);
+
+ // E.g. make sure that 'de' is before 'de_DE'.
+ sort($available);
+
+ $preferences = preg_split('/,\s*/', strtolower($header));
+ foreach ($preferences as $preference) {
+ list($preferred_language) = explode(';', $preference);
+ $preferred_language = str_replace('-', '_', $preferred_language);
+
+ foreach ($available as $available_language) {
+ if ($preferred_language === strtolower($available_language)) {
+ if ($app === null && !$this->requestLanguage) {
+ $this->requestLanguage = $available_language;
+ }
+ return $available_language;
+ }
+ }
+
+ // Fallback from de_De to de
+ foreach ($available as $available_language) {
+ if (substr($preferred_language, 0, 2) === $available_language) {
+ if ($app === null && !$this->requestLanguage) {
+ $this->requestLanguage = $available_language;
+ }
+ return $available_language;
+ }
+ }
+ }
+ }
+
+ if (!$this->requestLanguage) {
+ $this->requestLanguage = 'en';
+ }
+ return 'en'; // Last try: English
+ }
+
+ /**
+ * Get a list of language files that should be loaded
+ *
+ * @param string $app
+ * @param string $lang
+ * @return string[]
+ */
+ // FIXME This method is only public, until OC_L10N does not need it anymore,
+ // FIXME This is also the reason, why it is not in the public interface
+ public function getL10nFilesForApp($app, $lang) {
+ $languageFiles = [];
+
+ $i18nDir = $this->findL10nDir($app);
+ $transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';
+
+ if ((\OC_Helper::isSubDirectory($transFile, \OC::$SERVERROOT . '/core/l10n/')
+ || \OC_Helper::isSubDirectory($transFile, \OC::$SERVERROOT . '/lib/l10n/')
+ || \OC_Helper::isSubDirectory($transFile, \OC::$SERVERROOT . '/settings/l10n/')
+ || \OC_Helper::isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
+ )
+ && file_exists($transFile)) {
+ // load the translations file
+ $languageFiles[] = $transFile;
+
+ // merge with translations from theme
+ $theme = $this->config->getSystemValue('theme');
+ if (!empty($theme)) {
+ $transFile = \OC::$SERVERROOT . '/themes/' . $theme . substr($transFile, strlen(\OC::$SERVERROOT));
+ if (file_exists($transFile)) {
+ $languageFiles[] = $transFile;
+ }
+ }
+ }
+
+ return $languageFiles;
+ }
+
+ /**
+ * find the l10n directory
+ *
+ * @param string $app App id or empty string for core
+ * @return string directory
+ */
+ protected function findL10nDir($app = null) {
+ if (in_array($app, ['core', 'lib', 'settings'])) {
+ if (file_exists(\OC::$SERVERROOT . '/' . $app . '/l10n/')) {
+ return \OC::$SERVERROOT . '/' . $app . '/l10n/';
+ }
+ } else if ($app && \OC_App::getAppPath($app) !== false) {
+ // Check if the app is in the app folder
+ return \OC_App::getAppPath($app) . '/l10n/';
+ }
+ return \OC::$SERVERROOT . '/core/l10n/';
+ }
+
+
+ /**
+ * Creates a function from the plural string
+ *
+ * Parts of the code is copied from Habari:
+ * https://github.com/habari/system/blob/master/classes/locale.php
+ * @param string $string
+ * @return string
+ */
+ public function createPluralFunction($string) {
+ if (isset($this->pluralFunctions[$string])) {
+ return $this->pluralFunctions[$string];
+ }
+
+ if (preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
+ // sanitize
+ $nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
+ $plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
+
+ $body = str_replace(
+ array( 'plural', 'n', '$n$plurals', ),
+ array( '$plural', '$n', '$nplurals', ),
+ 'nplurals='. $nplurals . '; plural=' . $plural
+ );
+
+ // add parents
+ // important since PHP's ternary evaluates from left to right
+ $body .= ';';
+ $res = '';
+ $p = 0;
+ for($i = 0; $i < strlen($body); $i++) {
+ $ch = $body[$i];
+ switch ( $ch ) {
+ case '?':
+ $res .= ' ? (';
+ $p++;
+ break;
+ case ':':
+ $res .= ') : (';
+ break;
+ case ';':
+ $res .= str_repeat( ')', $p ) . ';';
+ $p = 0;
+ break;
+ default:
+ $res .= $ch;
+ }
+ }
+
+ $body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
+ $function = create_function('$n', $body);
+ $this->pluralFunctions[$string] = $function;
+ return $function;
+ } else {
+ // default: one plural form for all cases but n==1 (english)
+ $function = create_function(
+ '$n',
+ '$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
+ );
+ $this->pluralFunctions[$string] = $function;
+ return $function;
+ }
+ }
}
diff --git a/lib/private/l10n/l10n.php b/lib/private/l10n/l10n.php
new file mode 100644
index 00000000000..3e999e8c671
--- /dev/null
+++ b/lib/private/l10n/l10n.php
@@ -0,0 +1,216 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\L10N;
+
+use OCP\IL10N;
+use OCP\L10N\IFactory;
+use Punic\Calendar;
+
+class L10N implements IL10N {
+
+ /** @var IFactory */
+ protected $factory;
+
+ /** @var string App of this object */
+ protected $app;
+
+ /** @var string Language of this object */
+ protected $lang;
+
+ /** @var string Plural forms (string) */
+ private $pluralFormString = 'nplurals=2; plural=(n != 1);';
+
+ /** @var string Plural forms (function) */
+ private $pluralFormFunction = null;
+
+ /** @var string[] */
+ private $translations = [];
+
+ /**
+ * @param IFactory $factory
+ * @param string $app
+ * @param string $lang
+ * @param array $files
+ */
+ public function __construct(IFactory $factory, $app, $lang, array $files) {
+ $this->factory = $factory;
+ $this->app = $app;
+ $this->lang = $lang;
+
+ $this->translations = [];
+ foreach ($files as $languageFile) {
+ $this->load($languageFile);
+ }
+ }
+
+ /**
+ * The code (en, de, ...) of the language that is used for this instance
+ *
+ * @return string language
+ */
+ public function getLanguageCode() {
+ return $this->lang;
+ }
+
+ /**
+ * Translating
+ * @param string $text The text we need a translation for
+ * @param array $parameters default:array() Parameters for sprintf
+ * @return string Translation or the same text
+ *
+ * Returns the translation. If no translation is found, $text will be
+ * returned.
+ */
+ public function t($text, $parameters = array()) {
+ return (string) new \OC_L10N_String($this, $text, $parameters);
+ }
+
+ /**
+ * Translating
+ * @param string $text_singular the string to translate for exactly one object
+ * @param string $text_plural the string to translate for n objects
+ * @param integer $count Number of objects
+ * @param array $parameters default:array() Parameters for sprintf
+ * @return string Translation or the same text
+ *
+ * Returns the translation. If no translation is found, $text will be
+ * returned. %n will be replaced with the number of objects.
+ *
+ * The correct plural is determined by the plural_forms-function
+ * provided by the po file.
+ *
+ */
+ public function n($text_singular, $text_plural, $count, $parameters = array()) {
+ $identifier = "_${text_singular}_::_${text_plural}_";
+ if (isset($this->translations[$identifier])) {
+ return (string) new \OC_L10N_String($this, $identifier, $parameters, $count);
+ } else {
+ if ($count === 1) {
+ return (string) new \OC_L10N_String($this, $text_singular, $parameters, $count);
+ } else {
+ return (string) new \OC_L10N_String($this, $text_plural, $parameters, $count);
+ }
+ }
+ }
+
+ /**
+ * Localization
+ * @param string $type Type of localization
+ * @param \DateTime|int|string $data parameters for this localization
+ * @param array $options
+ * @return string|int|false
+ *
+ * Returns the localized data.
+ *
+ * Implemented types:
+ * - date
+ * - Creates a date
+ * - params: timestamp (int/string)
+ * - datetime
+ * - Creates date and time
+ * - params: timestamp (int/string)
+ * - time
+ * - Creates a time
+ * - params: timestamp (int/string)
+ * - firstday: Returns the first day of the week (0 sunday - 6 saturday)
+ * - jsdate: Returns the short JS date format
+ */
+ public function l($type, $data = null, $options = array()) {
+ // Use the language of the instance
+ $locale = $this->getLanguageCode();
+ if ($locale === 'sr@latin') {
+ $locale = 'sr_latn';
+ }
+
+ if ($type === 'firstday') {
+ return (int) Calendar::getFirstWeekday($locale);
+ }
+ if ($type === 'jsdate') {
+ return (string) Calendar::getDateFormat('short', $locale);
+ }
+
+ $value = new \DateTime();
+ if ($data instanceof \DateTime) {
+ $value = $data;
+ } else if (is_string($data) && !is_numeric($data)) {
+ $data = strtotime($data);
+ $value->setTimestamp($data);
+ } else if ($data !== null) {
+ $value->setTimestamp($data);
+ }
+
+ $options = array_merge(array('width' => 'long'), $options);
+ $width = $options['width'];
+ switch ($type) {
+ case 'date':
+ return (string) Calendar::formatDate($value, $width, $locale);
+ case 'datetime':
+ return (string) Calendar::formatDatetime($value, $width, $locale);
+ case 'time':
+ return (string) Calendar::formatTime($value, $width, $locale);
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Returns an associative array with all translations
+ *
+ * Called by \OC_L10N_String
+ * @return array
+ */
+ public function getTranslations() {
+ return $this->translations;
+ }
+
+ /**
+ * Returnsed function accepts the argument $n
+ *
+ * Called by \OC_L10N_String
+ * @return string the plural form function
+ */
+ public function getPluralFormFunction() {
+ if (is_null($this->pluralFormFunction)) {
+ $this->pluralFormFunction = $this->factory->createPluralFunction($this->pluralFormString);
+ }
+ return $this->pluralFormFunction;
+ }
+
+ /**
+ * @param $translationFile
+ * @return bool
+ */
+ protected function load($translationFile) {
+ $json = json_decode(file_get_contents($translationFile), true);
+ if (!is_array($json)) {
+ $jsonError = json_last_error();
+ \OC::$server->getLogger()->warning("Failed to load $translationFile - json error code: $jsonError", ['app' => 'l10n']);
+ return false;
+ }
+
+ if (!empty($json['pluralForm'])) {
+ $this->pluralFormString = $json['pluralForm'];
+ }
+ $this->translations = array_merge($this->translations, $json['translations']);
+ return true;
+ }
+}
diff --git a/lib/private/l10n/string.php b/lib/private/l10n/string.php
index 77469f88d19..9c93b8c5a64 100644
--- a/lib/private/l10n/string.php
+++ b/lib/private/l10n/string.php
@@ -8,7 +8,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,28 +26,23 @@
*/
class OC_L10N_String implements JsonSerializable {
- /**
- * @var OC_L10N
- */
+ /** @var \OC_L10N|\OC\L10N\L10N */
protected $l10n;
- /**
- * @var string
- */
+ /** @var string */
protected $text;
- /**
- * @var array
- */
+ /** @var array */
protected $parameters;
- /**
- * @var integer
- */
+ /** @var integer */
protected $count;
/**
- * @param OC_L10N $l10n
+ * @param \OC_L10N|\OC\L10N\L10N $l10n
+ * @param string|string[] $text
+ * @param array $parameters
+ * @param int $count
*/
public function __construct($l10n, $text, $parameters, $count = 1) {
$this->l10n = $l10n;
@@ -80,5 +75,4 @@ class OC_L10N_String implements JsonSerializable {
public function jsonSerialize() {
return $this->__toString();
}
-
}
diff --git a/lib/private/largefilehelper.php b/lib/private/largefilehelper.php
index 3e841850456..f5252ee01e7 100644
--- a/lib/private/largefilehelper.php
+++ b/lib/private/largefilehelper.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/legacy/config.php b/lib/private/legacy/config.php
deleted file mode 100644
index 1835d4a4b1c..00000000000
--- a/lib/private/legacy/config.php
+++ /dev/null
@@ -1,94 +0,0 @@
-<?php
-/**
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Michael Gapczynski <GapczynskiM@gmail.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-/**
- * This class is responsible for reading and writing config.php, the very basic
- * configuration file of ownCloud.
- *
- * @deprecated use \OC::$server->getConfig() to get an \OCP\Config instance
- */
-class OC_Config {
-
- /** @var \OC\Config */
- public static $object;
-
- /**
- * Lists all available config keys
- * @return array an array of key names
- *
- * This function returns all keys saved in config.php. Please note that it
- * does not return the values.
- */
- public static function getKeys() {
- return self::$object->getKeys();
- }
-
- /**
- * Gets a value from config.php
- * @param string $key key
- * @param mixed $default = null default value
- * @return mixed the value or $default
- *
- * This function gets the value from config.php. If it does not exist,
- * $default will be returned.
- */
- public static function getValue($key, $default = null) {
- return self::$object->getValue($key, $default);
- }
-
- /**
- * Sets a value
- * @param string $key key
- * @param mixed $value value
- *
- * This function sets the value and writes the config.php.
- *
- */
- public static function setValue($key, $value) {
- self::$object->setValue($key, $value);
- }
-
- /**
- * Sets and deletes values and writes the config.php
- *
- * @param array $configs Associative array with `key => value` pairs
- * If value is null, the config key will be deleted
- */
- public static function setValues(array $configs) {
- self::$object->setValues($configs);
- }
-
- /**
- * Removes a key from the config
- * @param string $key key
- *
- * This function removes a key from the config.php.
- */
- public static function deleteKey($key) {
- self::$object->deleteKey($key);
- }
-}
diff --git a/lib/private/l10n.php b/lib/private/legacy/l10n.php
index 86335bce92f..5d5d89100ac 100644
--- a/lib/private/l10n.php
+++ b/lib/private/legacy/l10n.php
@@ -4,7 +4,6 @@
* @author Andreas Fischer <bantu@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Bernhard Posselt <dev@bernhard-posselt.com>
- * @author Felix Moeller <mail@felixmoeller.de>
* @author Jakob Sack <mail@jakobsack.de>
* @author Jan-Christoph Borchardt <hey@jancborchardt.net>
* @author Joas Schilling <nickvergessen@owncloud.com>
@@ -13,13 +12,13 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -38,6 +37,7 @@
/**
* This class is for i18n and l10n
+ * @deprecated 9.0.0 Use \OC::$server->getL10NFactory()->get() instead
*/
class OC_L10N implements \OCP\IL10N {
/**
@@ -77,69 +77,35 @@ class OC_L10N implements \OCP\IL10N {
private $pluralFormFunction = null;
/**
- * get an L10N instance
- * @param string $app
- * @param string|null $lang
- * @return \OCP\IL10N
- * @deprecated Use \OC::$server->getL10NFactory()->get() instead
- */
- public static function get($app, $lang=null) {
- return \OC::$server->getL10NFactory()->get($app, $lang);
- }
-
- /**
* The constructor
* @param string $app app requesting l10n
* @param string $lang default: null Language
*
* If language is not set, the constructor tries to find the right
* language.
+ * @deprecated 9.0.0 Use \OC::$server->getL10NFactory()->get() instead
*/
public function __construct($app, $lang = null) {
+ $app = \OC_App::cleanAppId($app);
$this->app = $app;
- $this->lang = $lang;
- }
- /**
- * @return string
- */
- public static function setLanguageFromRequest() {
- if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
- $available = self::findAvailableLanguages();
-
- // E.g. make sure that 'de' is before 'de_DE'.
- sort($available);
-
- $preferences = preg_split('/,\s*/', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']));
- foreach ($preferences as $preference) {
- list($preferred_language) = explode(';', $preference);
- $preferred_language = str_replace('-', '_', $preferred_language);
- foreach ($available as $available_language) {
- if ($preferred_language === strtolower($available_language)) {
- self::$language = $available_language;
- return $available_language;
- }
- }
- foreach ($available as $available_language) {
- if (substr($preferred_language, 0, 2) === $available_language) {
- self::$language = $available_language;
- return $available_language;
- }
- }
- }
+ if ($lang !== null) {
+ $lang = str_replace(array('\0', '/', '\\', '..'), '', $lang);
}
- self::$language = 'en';
- // Last try: English
- return 'en';
+ // Find the right language
+ if ($app !== 'test' && !\OC::$server->getL10NFactory()->languageExists($app, $lang)) {
+ $lang = \OC::$server->getL10NFactory()->findLanguage($app);
+ }
+
+ $this->lang = $lang;
}
/**
* @param $transFile
- * @param bool $mergeTranslations
* @return bool
*/
- public function load($transFile, $mergeTranslations = false) {
+ public function load($transFile) {
$this->app = true;
$json = json_decode(file_get_contents($transFile), true);
@@ -152,11 +118,7 @@ class OC_L10N implements \OCP\IL10N {
$this->pluralFormString = $json['pluralForm'];
$translations = $json['translations'];
- if ($mergeTranslations) {
- $this->translations = array_merge($this->translations, $translations);
- } else {
- $this->translations = $translations;
- }
+ $this->translations = array_merge($this->translations, $translations);
return true;
}
@@ -165,101 +127,17 @@ class OC_L10N implements \OCP\IL10N {
if ($this->app === true) {
return;
}
- $app = OC_App::cleanAppId($this->app);
- $lang = str_replace(array('\0', '/', '\\', '..'), '', $this->lang);
+ $app = $this->app;
+ $lang = $this->lang;
$this->app = true;
- // Find the right language
- if(is_null($lang) || $lang == '') {
- $lang = self::findLanguage($app);
- }
- // Use cache if possible
- if(array_key_exists($app.'::'.$lang, self::$cache)) {
- $this->translations = self::$cache[$app.'::'.$lang]['t'];
- } else{
- $i18nDir = self::findI18nDir($app);
- $transFile = strip_tags($i18nDir).strip_tags($lang).'.json';
- // Texts are in $i18ndir
- // (Just no need to define date/time format etc. twice)
- if((OC_Helper::isSubDirectory($transFile, OC::$SERVERROOT.'/core/l10n/')
- || OC_Helper::isSubDirectory($transFile, OC::$SERVERROOT.'/lib/l10n/')
- || OC_Helper::isSubDirectory($transFile, OC::$SERVERROOT.'/settings')
- || OC_Helper::isSubDirectory($transFile, OC_App::getAppPath($app).'/l10n/')
- )
- && file_exists($transFile)) {
- // load the translations file
- if($this->load($transFile)) {
- //merge with translations from theme
- $theme = \OC::$server->getConfig()->getSystemValue('theme');
- if (!empty($theme)) {
- $transFile = OC::$SERVERROOT.'/themes/'.$theme.substr($transFile, strlen(OC::$SERVERROOT));
- if (file_exists($transFile)) {
- $this->load($transFile, true);
- }
- }
- }
- }
-
- self::$cache[$app.'::'.$lang]['t'] = $this->translations;
- }
- }
-
- /**
- * Creates a function that The constructor
- *
- * If language is not set, the constructor tries to find the right
- * language.
- *
- * Parts of the code is copied from Habari:
- * https://github.com/habari/system/blob/master/classes/locale.php
- * @param string $string
- * @return string
- */
- protected function createPluralFormFunction($string){
- if(preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
- // sanitize
- $nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
- $plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
-
- $body = str_replace(
- array( 'plural', 'n', '$n$plurals', ),
- array( '$plural', '$n', '$nplurals', ),
- 'nplurals='. $nplurals . '; plural=' . $plural
- );
-
- // add parents
- // important since PHP's ternary evaluates from left to right
- $body .= ';';
- $res = '';
- $p = 0;
- for($i = 0; $i < strlen($body); $i++) {
- $ch = $body[$i];
- switch ( $ch ) {
- case '?':
- $res .= ' ? (';
- $p++;
- break;
- case ':':
- $res .= ') : (';
- break;
- case ';':
- $res .= str_repeat( ')', $p ) . ';';
- $p = 0;
- break;
- default:
- $res .= $ch;
- }
- }
+ /** @var \OC\L10N\Factory $factory */
+ $factory = \OC::$server->getL10NFactory();
+ $languageFiles = $factory->getL10nFilesForApp($app, $lang);
- $body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
- return create_function('$n', $body);
- }
- else {
- // default: one plural form for all cases but n==1 (english)
- return create_function(
- '$n',
- '$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
- );
+ $this->translations = [];
+ foreach ($languageFiles as $languageFile) {
+ $this->load($languageFile);
}
}
@@ -324,8 +202,8 @@ class OC_L10N implements \OCP\IL10N {
*/
public function getPluralFormFunction() {
$this->init();
- if(is_null($this->pluralFormFunction)) {
- $this->pluralFormFunction = $this->createPluralFormFunction($this->pluralFormString);
+ if (is_null($this->pluralFormFunction)) {
+ $this->pluralFormFunction = \OC::$server->getL10NFactory()->createPluralFunction($this->pluralFormString);
}
return $this->pluralFormFunction;
}
@@ -349,6 +227,8 @@ class OC_L10N implements \OCP\IL10N {
* - time
* - Creates a time
* - params: timestamp (int/string)
+ * - firstday: Returns the first day of the week (0 sunday - 6 saturday)
+ * - jsdate: Returns the short JS date format
*/
public function l($type, $data, $options = array()) {
if ($type === 'firstday') {
@@ -369,12 +249,8 @@ class OC_L10N implements \OCP\IL10N {
$value->setTimestamp($data);
}
- // Use the language of the instance, before falling back to the current user's language
- $locale = $this->lang;
- if ($locale === null) {
- $locale = self::findLanguage();
- }
- $locale = $this->transformToCLDRLocale($locale);
+ // Use the language of the instance
+ $locale = $this->transformToCLDRLocale($this->getLanguageCode());
$options = array_merge(array('width' => 'long'), $options);
$width = $options['width'];
@@ -396,132 +272,77 @@ class OC_L10N implements \OCP\IL10N {
* @return string language
*/
public function getLanguageCode() {
- return $this->lang ? $this->lang : self::findLanguage();
+ return $this->lang;
}
/**
- * find the best language
- * @param string $app
- * @return string language
- *
- * If nothing works it returns 'en'
+ * @return string
+ * @throws \Punic\Exception\ValueNotInList
+ * @deprecated 9.0.0 Use $this->l('jsdate', null) instead
*/
- public static function findLanguage($app = null) {
- if(self::$language != '') {
- return self::$language;
- }
-
- $config = \OC::$server->getConfig();
- $userId = \OC_User::getUser();
-
- if($userId && $config->getUserValue($userId, 'core', 'lang')) {
- $lang = $config->getUserValue($userId, 'core', 'lang');
- self::$language = $lang;
- if(self::languageExists($app, $lang)) {
- return $lang;
- }
- }
-
- $default_language = $config->getSystemValue('default_language', false);
-
- if($default_language !== false) {
- return $default_language;
- }
-
- $lang = self::setLanguageFromRequest();
- if($userId && !$config->getUserValue($userId, 'core', 'lang')) {
- $config->setUserValue($userId, 'core', 'lang', $lang);
- }
-
- return $lang;
+ public function getDateFormat() {
+ $locale = $this->transformToCLDRLocale($this->getLanguageCode());
+ return Punic\Calendar::getDateFormat('short', $locale);
}
/**
- * find the l10n directory
- * @param string $app App that needs to be translated
- * @return string directory
+ * @return int
+ * @deprecated 9.0.0 Use $this->l('firstday', null) instead
*/
- protected static function findI18nDir($app) {
- // find the i18n dir
- $i18nDir = OC::$SERVERROOT.'/core/l10n/';
- if($app != '') {
- // Check if the app is in the app folder
- if(file_exists(OC_App::getAppPath($app).'/l10n/')) {
- $i18nDir = OC_App::getAppPath($app).'/l10n/';
- }
- else{
- $i18nDir = OC::$SERVERROOT.'/'.$app.'/l10n/';
- }
- }
- return $i18nDir;
+ public function getFirstWeekDay() {
+ $locale = $this->transformToCLDRLocale($this->getLanguageCode());
+ return Punic\Calendar::getFirstWeekday($locale);
}
/**
- * find all available languages for an app
- * @param string $app App that needs to be translated
- * @return array an array of available languages
+ * @param string $locale
+ * @return string
*/
- public static function findAvailableLanguages($app=null) {
- // also works with null as key
- if(isset(self::$availableLanguages[$app]) && !empty(self::$availableLanguages[$app])) {
- return self::$availableLanguages[$app];
- }
- $available=array('en');//english is always available
- $dir = self::findI18nDir($app);
- if(is_dir($dir)) {
- $files=scandir($dir);
- foreach($files as $file) {
- if(substr($file, -5, 5) === '.json' && substr($file, 0, 4) !== 'l10n') {
- $i = substr($file, 0, -5);
- $available[] = $i;
- }
- }
+ private function transformToCLDRLocale($locale) {
+ if ($locale === 'sr@latin') {
+ return 'sr_latn';
}
- self::$availableLanguages[$app] = $available;
- return $available;
+ return $locale;
}
/**
+ * find the best language
* @param string $app
- * @param string $lang
- * @return bool
+ * @return string language
+ *
+ * If nothing works it returns 'en'
+ * @deprecated 9.0.0 Use \OC::$server->getL10NFactory()->findLanguage() instead
*/
- public static function languageExists($app, $lang) {
- if ($lang === 'en') {//english is always available
- return true;
- }
- $dir = self::findI18nDir($app);
- if(is_dir($dir)) {
- return file_exists($dir.'/'.$lang.'.json');
- }
- return false;
+ public static function findLanguage($app = null) {
+ return \OC::$server->getL10NFactory()->findLanguage($app);
}
/**
* @return string
- * @throws \Punic\Exception\ValueNotInList
+ * @deprecated 9.0.0 Use \OC::$server->getL10NFactory()->setLanguageFromRequest() instead
*/
- public function getDateFormat() {
- $locale = $this->getLanguageCode();
- $locale = $this->transformToCLDRLocale($locale);
- return Punic\Calendar::getDateFormat('short', $locale);
+ public static function setLanguageFromRequest() {
+ return \OC::$server->getL10NFactory()->setLanguageFromRequest();
}
/**
- * @return int
+ * find all available languages for an app
+ * @param string $app App that needs to be translated
+ * @return array an array of available languages
+ * @deprecated 9.0.0 Use \OC::$server->getL10NFactory()->findAvailableLanguages() instead
*/
- public function getFirstWeekDay() {
- $locale = $this->getLanguageCode();
- $locale = $this->transformToCLDRLocale($locale);
- return Punic\Calendar::getFirstWeekday($locale);
+ public static function findAvailableLanguages($app=null) {
+ return \OC::$server->getL10NFactory()->findAvailableLanguages($app);
}
- private function transformToCLDRLocale($locale) {
- if ($locale === 'sr@latin') {
- return 'sr_latn';
- }
-
- return $locale;
+ /**
+ * @param string $app
+ * @param string $lang
+ * @return bool
+ * @deprecated 9.0.0 Use \OC::$server->getL10NFactory()->languageExists() instead
+ */
+ public static function languageExists($app, $lang) {
+ return \OC::$server->getL10NFactory()->languageExists($app, $lang);
}
}
diff --git a/lib/private/lock/abstractlockingprovider.php b/lib/private/lock/abstractlockingprovider.php
index c7a29380efe..7dee8c709a0 100644
--- a/lib/private/lock/abstractlockingprovider.php
+++ b/lib/private/lock/abstractlockingprovider.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,6 +28,8 @@ use OCP\Lock\ILockingProvider;
* to release any left over locks at the end of the request
*/
abstract class AbstractLockingProvider implements ILockingProvider {
+ const TTL = 3600; // how long until we clear stray locks in seconds
+
protected $acquiredLocks = [
'shared' => [],
'exclusive' => []
diff --git a/lib/private/lock/dblockingprovider.php b/lib/private/lock/dblockingprovider.php
index 90657e6725f..647250cdb6f 100644
--- a/lib/private/lock/dblockingprovider.php
+++ b/lib/private/lock/dblockingprovider.php
@@ -5,7 +5,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -51,8 +51,6 @@ class DBLockingProvider extends AbstractLockingProvider {
private $sharedLocks = [];
- const TTL = 3600; // how long until we clear stray locks in seconds
-
/**
* Check if we have an open shared lock for a path
*
@@ -235,10 +233,10 @@ class DBLockingProvider extends AbstractLockingProvider {
/**
* cleanup empty locks
*/
- public function cleanEmptyLocks() {
+ public function cleanExpiredLocks() {
$expire = $this->timeFactory->getTime();
$this->connection->executeUpdate(
- 'DELETE FROM `*PREFIX*file_locks` WHERE `lock` = 0 AND `ttl` < ?',
+ 'DELETE FROM `*PREFIX*file_locks` WHERE `ttl` < ?',
[$expire]
);
}
@@ -262,7 +260,7 @@ class DBLockingProvider extends AbstractLockingProvider {
public function __destruct() {
try {
- $this->cleanEmptyLocks();
+ $this->cleanExpiredLocks();
} catch (\Exception $e) {
// If the table is missing, the clean up was successful
if ($this->connection->tableExists('file_locks')) {
diff --git a/lib/private/lock/memcachelockingprovider.php b/lib/private/lock/memcachelockingprovider.php
index e4158dcdfdf..08c92950e49 100644
--- a/lib/private/lock/memcachelockingprovider.php
+++ b/lib/private/lock/memcachelockingprovider.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,6 +21,7 @@
namespace OC\Lock;
+use OCP\IMemcacheTTL;
use OCP\Lock\LockedException;
use OCP\IMemcache;
@@ -37,6 +38,12 @@ class MemcacheLockingProvider extends AbstractLockingProvider {
$this->memcache = $memcache;
}
+ private function setTTL($path) {
+ if ($this->memcache instanceof IMemcacheTTL) {
+ $this->memcache->setTTL($path, self::TTL);
+ }
+ }
+
/**
* @param string $path
* @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE
@@ -69,6 +76,7 @@ class MemcacheLockingProvider extends AbstractLockingProvider {
throw new LockedException($path);
}
}
+ $this->setTTL($path);
$this->markAcquire($path, $type);
}
@@ -106,6 +114,7 @@ class MemcacheLockingProvider extends AbstractLockingProvider {
throw new LockedException($path);
}
}
+ $this->setTTL($path);
$this->markChange($path, $targetType);
}
}
diff --git a/lib/private/lock/nooplockingprovider.php b/lib/private/lock/nooplockingprovider.php
index 9f88e6148f8..dc58230f77e 100644
--- a/lib/private/lock/nooplockingprovider.php
+++ b/lib/private/lock/nooplockingprovider.php
@@ -3,7 +3,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/log.php b/lib/private/log.php
index ee5d61e98df..addefe6e53d 100644
--- a/lib/private/log.php
+++ b/lib/private/log.php
@@ -2,13 +2,14 @@
/**
* @author Bart Visscher <bartv@thisnet.nl>
* @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,6 +32,7 @@ use InterfaSys\LogNormalizer\Normalizer;
use \OCP\ILogger;
use OCP\Security\StringUtils;
+use OCP\Util;
/**
* logging utilities
@@ -46,11 +48,13 @@ class Log implements ILogger {
/** @var string */
private $logger;
+
/** @var SystemConfig */
private $config;
/** @var boolean|null cache the result of the log condition check for the request */
private $logConditionSatisfied = null;
+
/** @var Normalizer */
private $normalizer;
@@ -82,15 +86,15 @@ class Log implements ILogger {
}
-
/**
* System is unusable.
*
* @param string $message
* @param array $context
+ * @return void
*/
public function emergency($message, array $context = array()) {
- $this->log(\OCP\Util::FATAL, $message, $context);
+ $this->log(Util::FATAL, $message, $context);
}
/**
@@ -101,9 +105,10 @@ class Log implements ILogger {
*
* @param string $message
* @param array $context
+ * @return void
*/
public function alert($message, array $context = array()) {
- $this->log(\OCP\Util::ERROR, $message, $context);
+ $this->log(Util::ERROR, $message, $context);
}
/**
@@ -113,9 +118,10 @@ class Log implements ILogger {
*
* @param string $message
* @param array $context
+ * @return void
*/
public function critical($message, array $context = array()) {
- $this->log(\OCP\Util::ERROR, $message, $context);
+ $this->log(Util::ERROR, $message, $context);
}
/**
@@ -124,9 +130,10 @@ class Log implements ILogger {
*
* @param string $message
* @param array $context
+ * @return void
*/
public function error($message, array $context = array()) {
- $this->log(\OCP\Util::ERROR, $message, $context);
+ $this->log(Util::ERROR, $message, $context);
}
/**
@@ -137,9 +144,10 @@ class Log implements ILogger {
*
* @param string $message
* @param array $context
+ * @return void
*/
public function warning($message, array $context = array()) {
- $this->log(\OCP\Util::WARN, $message, $context);
+ $this->log(Util::WARN, $message, $context);
}
/**
@@ -147,9 +155,10 @@ class Log implements ILogger {
*
* @param string $message
* @param array $context
+ * @return void
*/
public function notice($message, array $context = array()) {
- $this->log(\OCP\Util::INFO, $message, $context);
+ $this->log(Util::INFO, $message, $context);
}
/**
@@ -159,9 +168,10 @@ class Log implements ILogger {
*
* @param string $message
* @param array $context
+ * @return void
*/
public function info($message, array $context = array()) {
- $this->log(\OCP\Util::INFO, $message, $context);
+ $this->log(Util::INFO, $message, $context);
}
/**
@@ -169,9 +179,10 @@ class Log implements ILogger {
*
* @param string $message
* @param array $context
+ * @return void
*/
public function debug($message, array $context = array()) {
- $this->log(\OCP\Util::DEBUG, $message, $context);
+ $this->log(Util::DEBUG, $message, $context);
}
@@ -181,9 +192,10 @@ class Log implements ILogger {
* @param mixed $level
* @param string $message
* @param array $context
+ * @return void
*/
public function log($level, $message, array $context = array()) {
- $minLevel = min($this->config->getValue('loglevel', \OCP\Util::WARN), \OCP\Util::ERROR);
+ $minLevel = min($this->config->getValue('loglevel', Util::WARN), Util::ERROR);
$logCondition = $this->config->getValue('log.condition', []);
array_walk($context, [$this->normalizer, 'format']);
@@ -198,7 +210,7 @@ class Log implements ILogger {
if(!empty($logCondition)
&& isset($logCondition['apps'])
&& in_array($app, $logCondition['apps'], true)) {
- $minLevel = \OCP\Util::DEBUG;
+ $minLevel = Util::DEBUG;
}
} else {
@@ -227,7 +239,7 @@ class Log implements ILogger {
$request = \OC::$server->getRequest();
// if token is found in the request change set the log condition to satisfied
- if($request && StringUtils::equals($request->getParam('log_secret'), $logCondition['shared_secret'])) {
+ if($request && hash_equals($logCondition['shared_secret'], $request->getParam('log_secret'))) {
$this->logConditionSatisfied = true;
}
}
@@ -246,7 +258,7 @@ class Log implements ILogger {
// if log condition is satisfied change the required log level to DEBUG
if($this->logConditionSatisfied) {
- $minLevel = \OCP\Util::DEBUG;
+ $minLevel = Util::DEBUG;
}
if ($level >= $minLevel) {
@@ -273,6 +285,8 @@ class Log implements ILogger {
'Line' => $exception->getLine(),
);
$exception['Trace'] = preg_replace('!(login|checkPassword)\(.*\)!', '$1(*** username and password replaced ***)', $exception['Trace']);
- $this->error('Exception: ' . json_encode($exception), $context);
+ $msg = isset($context['message']) ? $context['message'] : 'Exception';
+ $msg .= ': ' . json_encode($exception);
+ $this->error($msg, $context);
}
}
diff --git a/lib/private/log/errorhandler.php b/lib/private/log/errorhandler.php
index d10c44cc0cd..27cde4aa242 100644
--- a/lib/private/log/errorhandler.php
+++ b/lib/private/log/errorhandler.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/log/owncloud.php b/lib/private/log/owncloud.php
index 1af989588d1..dabf95d7616 100644
--- a/lib/private/log/owncloud.php
+++ b/lib/private/log/owncloud.php
@@ -2,13 +2,14 @@
/**
* @author Andreas Fischer <bantu@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
+ * @author Christian Schnidrig <christian.schnidrig@switch.ch>
* @author Georg Ehrke <georg@owncloud.com>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -38,20 +39,22 @@ class OC_Log_Owncloud {
* Init class data
*/
public static function init() {
- $defaultLogFile = OC_Config::getValue("datadirectory", OC::$SERVERROOT.'/data').'/owncloud.log';
- self::$logFile = OC_Config::getValue("logfile", $defaultLogFile);
+ $systemConfig = \OC::$server->getSystemConfig();
+ $defaultLogFile = $systemConfig->getValue("datadirectory", OC::$SERVERROOT.'/data').'/owncloud.log';
+ self::$logFile = $systemConfig->getValue("logfile", $defaultLogFile);
- /*
- * Fall back to default log file if specified logfile does not exist
- * and can not be created. Error suppression is required in order to
- * not end up in the error handler which will try to log the error.
- * A better solution (compared to error suppression) would be checking
- * !is_writable(dirname(self::$logFile)) before touch(), but
- * is_writable() on directories used to be pretty unreliable on Windows
- * for at least some time.
- */
- if (!file_exists(self::$logFile) && !@touch(self::$logFile)) {
- self::$logFile = $defaultLogFile;
+ /**
+ * Fall back to default log file if specified logfile does not exist
+ * and can not be created.
+ */
+ if (!file_exists(self::$logFile)) {
+ if(!is_writable(dirname(self::$logFile))) {
+ self::$logFile = $defaultLogFile;
+ } else {
+ if(!touch(self::$logFile)) {
+ self::$logFile = $defaultLogFile;
+ }
+ }
}
}
@@ -66,13 +69,16 @@ class OC_Log_Owncloud {
// default to ISO8601
$format = $config->getValue('logdateformat', 'c');
- $logtimezone = $config->getValue( "logtimezone", 'UTC' );
+ $logTimeZone = $config->getValue( "logtimezone", 'UTC' );
try {
- $timezone = new DateTimeZone($logtimezone);
+ $timezone = new DateTimeZone($logTimeZone);
} catch (Exception $e) {
$timezone = new DateTimeZone('UTC');
}
- $time = DateTime::createFromFormat("U.u", microtime(true), $timezone);
+ $time = DateTime::createFromFormat("U.u", number_format(microtime(true), 4, ".", ""), $timezone);
+ if ($time === false) {
+ $time = new DateTime(null, $timezone);
+ }
$request = \OC::$server->getRequest();
$reqId = $request->getId();
$remoteAddr = $request->getRemoteAddress();
@@ -97,6 +103,9 @@ class OC_Log_Owncloud {
// Fall back to error_log
error_log($entry);
}
+ if (php_sapi_name() === 'cli-server') {
+ error_log($message, 4);
+ }
}
/**
@@ -107,7 +116,7 @@ class OC_Log_Owncloud {
*/
public static function getEntries($limit=50, $offset=0) {
self::init();
- $minLevel=OC_Config::getValue( "loglevel", \OCP\Util::WARN );
+ $minLevel = \OC::$server->getSystemConfig()->getValue("loglevel", \OCP\Util::WARN);
$entries = array();
$handle = @fopen(self::$logFile, 'rb');
if ($handle) {
diff --git a/lib/private/log/rotate.php b/lib/private/log/rotate.php
index 27731c07db2..458661c82d0 100644
--- a/lib/private/log/rotate.php
+++ b/lib/private/log/rotate.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,7 +32,7 @@ namespace OC\Log;
class Rotate extends \OC\BackgroundJob\Job {
private $max_log_size;
public function run($logFile) {
- $this->max_log_size = \OC_Config::getValue('log_rotate_size', false);
+ $this->max_log_size = \OC::$server->getConfig()->getSystemValue('log_rotate_size', false);
if ($this->max_log_size) {
$filesize = @filesize($logFile);
if ($filesize >= $this->max_log_size) {
diff --git a/lib/private/log/syslog.php b/lib/private/log/syslog.php
index cc4c5a29c39..96cf463d042 100644
--- a/lib/private/log/syslog.php
+++ b/lib/private/log/syslog.php
@@ -3,9 +3,8 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Volker Fröhlich <volker27@gmx.at>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,7 +34,7 @@ class OC_Log_Syslog {
* Init class data
*/
public static function init() {
- openlog(OC_Config::getValue("syslog_tag", "ownCloud"), LOG_PID | LOG_CONS, LOG_USER);
+ openlog(\OC::$server->getSystemConfig()->getValue("syslog_tag", "ownCloud"), LOG_PID | LOG_CONS, LOG_USER);
// Close at shutdown
register_shutdown_function('closelog');
}
diff --git a/lib/private/mail/mailer.php b/lib/private/mail/mailer.php
index bd93f3e3d58..742ff554892 100644
--- a/lib/private/mail/mailer.php
+++ b/lib/private/mail/mailer.php
@@ -2,7 +2,7 @@
/**
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/mail/message.php b/lib/private/mail/message.php
index 0fdca49e6d6..0e33e6383f7 100644
--- a/lib/private/mail/message.php
+++ b/lib/private/mail/message.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -238,4 +239,14 @@ class Message {
public function getSwiftMessage() {
return $this->swiftMessage;
}
+
+ /**
+ * @param string $body
+ * @param string $contentType
+ * @return $this
+ */
+ public function setBody($body, $contentType) {
+ $this->swiftMessage->setBody($body, $contentType);
+ return $this;
+ }
}
diff --git a/lib/private/memcache/apc.php b/lib/private/memcache/apc.php
index f768cdc1c6e..2354ad07749 100644
--- a/lib/private/memcache/apc.php
+++ b/lib/private/memcache/apc.php
@@ -1,11 +1,12 @@
<?php
/**
* @author Andreas Fischer <bantu@owncloud.com>
+ * @author Clark Tomlinson <fallen013@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Otto Sabart <ottosabart@seberm.com>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -115,9 +116,9 @@ class APC extends Cache implements IMemcache {
static public function isAvailable() {
if (!extension_loaded('apc')) {
return false;
- } elseif (!ini_get('apc.enabled')) {
+ } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
return false;
- } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) {
+ } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
return false;
} else {
return true;
diff --git a/lib/private/memcache/apcu.php b/lib/private/memcache/apcu.php
index 9a8da2ae60c..ddd16ae1202 100644
--- a/lib/private/memcache/apcu.php
+++ b/lib/private/memcache/apcu.php
@@ -2,10 +2,11 @@
/**
* @author Andreas Fischer <bantu@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
+ * @author Clark Tomlinson <fallen013@gmail.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,15 +25,112 @@
namespace OC\Memcache;
-class APCu extends APC {
+use OCP\IMemcache;
+
+class APCu extends Cache implements IMemcache {
+ use CASTrait {
+ cas as casEmulated;
+ }
+
+ use CADTrait;
+
+ public function get($key) {
+ $result = apcu_fetch($this->getPrefix() . $key, $success);
+ if (!$success) {
+ return null;
+ }
+ return $result;
+ }
+
+ public function set($key, $value, $ttl = 0) {
+ return apcu_store($this->getPrefix() . $key, $value, $ttl);
+ }
+
+ public function hasKey($key) {
+ return apcu_exists($this->getPrefix() . $key);
+ }
+
+ public function remove($key) {
+ return apcu_delete($this->getPrefix() . $key);
+ }
+
+ public function clear($prefix = '') {
+ $ns = $this->getPrefix() . $prefix;
+ $ns = preg_quote($ns, '/');
+ if(class_exists('\APCIterator')) {
+ $iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
+ } else {
+ $iter = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
+ }
+ return apcu_delete($iter);
+ }
+
+ /**
+ * Set a value in the cache if it's not already stored
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
+ * @return bool
+ */
+ public function add($key, $value, $ttl = 0) {
+ return apcu_add($this->getPrefix() . $key, $value, $ttl);
+ }
+
+ /**
+ * Increase a stored number
+ *
+ * @param string $key
+ * @param int $step
+ * @return int | bool
+ */
+ public function inc($key, $step = 1) {
+ $this->add($key, 0);
+ return apcu_inc($this->getPrefix() . $key, $step);
+ }
+
+ /**
+ * Decrease a stored number
+ *
+ * @param string $key
+ * @param int $step
+ * @return int | bool
+ */
+ public function dec($key, $step = 1) {
+ return apcu_dec($this->getPrefix() . $key, $step);
+ }
+
+ /**
+ * Compare and set
+ *
+ * @param string $key
+ * @param mixed $old
+ * @param mixed $new
+ * @return bool
+ */
+ public function cas($key, $old, $new) {
+ // apc only does cas for ints
+ if (is_int($old) and is_int($new)) {
+ return apcu_cas($this->getPrefix() . $key, $old, $new);
+ } else {
+ return $this->casEmulated($key, $old, $new);
+ }
+ }
+
+ /**
+ * @return bool
+ */
static public function isAvailable() {
if (!extension_loaded('apcu')) {
return false;
- } elseif (!ini_get('apc.enabled')) {
+ } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
return false;
- } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) {
+ } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
return false;
- } elseif (version_compare(phpversion('apc'), '4.0.6') === -1) {
+ } elseif (
+ version_compare(phpversion('apc'), '4.0.6') === -1 &&
+ version_compare(phpversion('apcu'), '5.1.0') === -1
+ ) {
return false;
} else {
return true;
diff --git a/lib/private/memcache/arraycache.php b/lib/private/memcache/arraycache.php
index 33c8bea8746..837f888a307 100644
--- a/lib/private/memcache/arraycache.php
+++ b/lib/private/memcache/arraycache.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/memcache/cache.php b/lib/private/memcache/cache.php
index 30fae30aaea..63d20721aac 100644
--- a/lib/private/memcache/cache.php
+++ b/lib/private/memcache/cache.php
@@ -3,9 +3,9 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/memcache/cadtrait.php b/lib/private/memcache/cadtrait.php
index e9836e24040..d44d98cba0b 100644
--- a/lib/private/memcache/cadtrait.php
+++ b/lib/private/memcache/cadtrait.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/memcache/castrait.php b/lib/private/memcache/castrait.php
index c52538023fb..43253fc966b 100644
--- a/lib/private/memcache/castrait.php
+++ b/lib/private/memcache/castrait.php
@@ -2,7 +2,7 @@
/**
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php
index fe82558e731..21149d8b6bf 100644
--- a/lib/private/memcache/factory.php
+++ b/lib/private/memcache/factory.php
@@ -5,11 +5,11 @@
* @author Markus Goetz <markus@woboq.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/memcache/memcached.php b/lib/private/memcache/memcached.php
index ce7c6fa9577..c13be68b47f 100644
--- a/lib/private/memcache/memcached.php
+++ b/lib/private/memcache/memcached.php
@@ -4,9 +4,10 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -41,9 +42,9 @@ class Memcached extends Cache implements IMemcache {
parent::__construct($prefix);
if (is_null(self::$cache)) {
self::$cache = new \Memcached();
- $servers = \OC_Config::getValue('memcached_servers');
+ $servers = \OC::$server->getSystemConfig()->getValue('memcached_servers');
if (!$servers) {
- $server = \OC_Config::getValue('memcached_server');
+ $server = \OC::$server->getSystemConfig()->getValue('memcached_server');
if ($server) {
$servers = array($server);
} else {
@@ -72,10 +73,12 @@ class Memcached extends Cache implements IMemcache {
public function set($key, $value, $ttl = 0) {
if ($ttl > 0) {
- return self::$cache->set($this->getNamespace() . $key, $value, $ttl);
+ $result = self::$cache->set($this->getNamespace() . $key, $value, $ttl);
} else {
- return self::$cache->set($this->getNamespace() . $key, $value);
+ $result = self::$cache->set($this->getNamespace() . $key, $value);
}
+ $this->verifyReturnCode();
+ return $result;
}
public function hasKey($key) {
@@ -84,7 +87,9 @@ class Memcached extends Cache implements IMemcache {
}
public function remove($key) {
- return self::$cache->delete($this->getNamespace() . $key);
+ $result= self::$cache->delete($this->getNamespace() . $key);
+ $this->verifyReturnCode();
+ return $result;
}
public function clear($prefix = '') {
@@ -121,7 +126,9 @@ class Memcached extends Cache implements IMemcache {
* @return bool
*/
public function add($key, $value, $ttl = 0) {
- return self::$cache->add($this->getPrefix() . $key, $value, $ttl);
+ $result = self::$cache->add($this->getPrefix() . $key, $value, $ttl);
+ $this->verifyReturnCode();
+ return $result;
}
/**
@@ -133,7 +140,9 @@ class Memcached extends Cache implements IMemcache {
*/
public function inc($key, $step = 1) {
$this->add($key, 0);
- return self::$cache->increment($this->getPrefix() . $key, $step);
+ $result = self::$cache->increment($this->getPrefix() . $key, $step);
+ $this->verifyReturnCode();
+ return $result;
}
/**
@@ -144,10 +153,24 @@ class Memcached extends Cache implements IMemcache {
* @return int | bool
*/
public function dec($key, $step = 1) {
- return self::$cache->decrement($this->getPrefix() . $key, $step);
+ $result = self::$cache->decrement($this->getPrefix() . $key, $step);
+ $this->verifyReturnCode();
+ return $result;
}
static public function isAvailable() {
return extension_loaded('memcached');
}
+
+ /**
+ * @throws \Exception
+ */
+ private function verifyReturnCode() {
+ $code = self::$cache->getResultCode();
+ if ($code === \Memcached::RES_SUCCESS) {
+ return;
+ }
+ $message = self::$cache->getResultMessage();
+ throw new \Exception("Error $code interacting with memcached : $message");
+ }
}
diff --git a/lib/private/memcache/nullcache.php b/lib/private/memcache/nullcache.php
index de27b03e71d..c490ca7e03c 100644
--- a/lib/private/memcache/nullcache.php
+++ b/lib/private/memcache/nullcache.php
@@ -2,11 +2,11 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/memcache/redis.php b/lib/private/memcache/redis.php
index 83be662eabf..db5461db669 100644
--- a/lib/private/memcache/redis.php
+++ b/lib/private/memcache/redis.php
@@ -2,11 +2,12 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Michael Telatynski <7t3chguy@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,9 +26,9 @@
namespace OC\Memcache;
-use OCP\IMemcache;
+use OCP\IMemcacheTTL;
-class Redis extends Cache implements IMemcache {
+class Redis extends Cache implements IMemcacheTTL {
/**
* @var \Redis $cache
*/
@@ -195,6 +196,10 @@ class Redis extends Cache implements IMemcache {
return false;
}
+ public function setTTL($key, $ttl) {
+ self::$cache->expire($this->getNamespace() . $key, $ttl);
+ }
+
static public function isAvailable() {
return extension_loaded('redis')
&& version_compare(phpversion('redis'), '2.2.5', '>=');
diff --git a/lib/private/memcache/xcache.php b/lib/private/memcache/xcache.php
index a6265ed5622..eea55fefc4d 100644
--- a/lib/private/memcache/xcache.php
+++ b/lib/private/memcache/xcache.php
@@ -2,11 +2,12 @@
/**
* @author Andreas Fischer <bantu@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
+ * @author Clark Tomlinson <fallen013@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -118,13 +119,13 @@ class XCache extends Cache implements IMemcache {
if (\OC::$CLI && !getenv('XCACHE_TEST')) {
return false;
}
- if (!function_exists('xcache_unset_by_prefix') && ini_get('xcache.admin.enable_auth')) {
+ if (!function_exists('xcache_unset_by_prefix') && \OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
// We do not want to use XCache if we can not clear it without
// using the administration function xcache_clear_cache()
// AND administration functions are password-protected.
return false;
}
- $var_size = (int)ini_get('xcache.var_size');
+ $var_size = \OC::$server->getIniWrapper()->getNumeric('xcache.var_size');
if (!$var_size) {
return false;
}
diff --git a/lib/private/naturalsort.php b/lib/private/naturalsort.php
index 2071ede43e0..f44e8032d36 100644
--- a/lib/private/naturalsort.php
+++ b/lib/private/naturalsort.php
@@ -3,11 +3,11 @@
* @author AW-UC <git@a-wesemann.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/naturalsort_defaultcollator.php b/lib/private/naturalsort_defaultcollator.php
index ba408121088..7b8400fa8e1 100644
--- a/lib/private/naturalsort_defaultcollator.php
+++ b/lib/private/naturalsort_defaultcollator.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/navigationmanager.php b/lib/private/navigationmanager.php
index f724963aa1b..6dbb9c925e0 100644
--- a/lib/private/navigationmanager.php
+++ b/lib/private/navigationmanager.php
@@ -3,10 +3,10 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/needsupdateexception.php b/lib/private/needsupdateexception.php
index 5024d8ce924..90c642780d8 100644
--- a/lib/private/needsupdateexception.php
+++ b/lib/private/needsupdateexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/notification/action.php b/lib/private/notification/action.php
index 958b085b38e..deac6807653 100644
--- a/lib/private/notification/action.php
+++ b/lib/private/notification/action.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,6 +22,8 @@
namespace OC\Notification;
+use OCP\Notification\IAction;
+
class Action implements IAction {
/** @var string */
@@ -50,7 +52,7 @@ class Action implements IAction {
$this->labelParsed = '';
$this->link = '';
$this->requestType = '';
- $this->icon = '';
+ $this->primary = false;
}
/**
@@ -99,6 +101,7 @@ class Action implements IAction {
/**
* @param $primary bool
+ * @return $this
* @throws \InvalidArgumentException if $primary is invalid
* @since 9.0.0
*/
@@ -108,6 +111,7 @@ class Action implements IAction {
}
$this->primary = $primary;
+ return $this;
}
/**
diff --git a/lib/private/notification/manager.php b/lib/private/notification/manager.php
index 0d5bb9be514..a14a1deec0c 100644
--- a/lib/private/notification/manager.php
+++ b/lib/private/notification/manager.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,6 +22,11 @@
namespace OC\Notification;
+use OCP\Notification\IApp;
+use OCP\Notification\IManager;
+use OCP\Notification\INotification;
+use OCP\Notification\INotifier;
+
class Manager implements IManager {
/** @var IApp */
protected $apps;
@@ -29,17 +34,25 @@ class Manager implements IManager {
/** @var INotifier */
protected $notifiers;
- /** @var \Closure */
+ /** @var array[] */
+ protected $notifiersInfo;
+
+ /** @var \Closure[] */
protected $appsClosures;
- /** @var \Closure */
+ /** @var \Closure[] */
protected $notifiersClosures;
+ /** @var \Closure[] */
+ protected $notifiersInfoClosures;
+
public function __construct() {
$this->apps = [];
$this->notifiers = [];
+ $this->notifiersInfo = [];
$this->appsClosures = [];
$this->notifiersClosures = [];
+ $this->notifiersInfoClosures = [];
}
/**
@@ -56,12 +69,16 @@ class Manager implements IManager {
/**
* @param \Closure $service The service must implement INotifier, otherwise a
* \InvalidArgumentException is thrown later
+ * @param \Closure $info An array with the keys 'id' and 'name' containing
+ * the app id and the app name
* @return null
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $info was added in 9.0.0
*/
- public function registerNotifier(\Closure $service) {
+ public function registerNotifier(\Closure $service, \Closure $info) {
$this->notifiersClosures[] = $service;
+ $this->notifiersInfoClosures[] = $info;
$this->notifiers = [];
+ $this->notifiersInfo = [];
}
/**
@@ -96,7 +113,7 @@ class Manager implements IManager {
foreach ($this->notifiersClosures as $closure) {
$notifier = $closure();
if (!($notifier instanceof INotifier)) {
- throw new \InvalidArgumentException('The given notification app does not implement the INotifier interface');
+ throw new \InvalidArgumentException('The given notifier does not implement the INotifier interface');
}
$this->notifiers[] = $notifier;
}
@@ -105,6 +122,29 @@ class Manager implements IManager {
}
/**
+ * @return array[]
+ */
+ public function listNotifiers() {
+ if (!empty($this->notifiersInfo)) {
+ return $this->notifiersInfo;
+ }
+
+ $this->notifiersInfo = [];
+ foreach ($this->notifiersInfoClosures as $closure) {
+ $notifier = $closure();
+ if (!is_array($notifier) || sizeof($notifier) !== 2 || !isset($notifier['id']) || !isset($notifier['name'])) {
+ throw new \InvalidArgumentException('The given notifier information is invalid');
+ }
+ if (isset($this->notifiersInfo[$notifier['id']])) {
+ throw new \InvalidArgumentException('The given notifier ID ' . $notifier['id'] . ' is already in use');
+ }
+ $this->notifiersInfo[$notifier['id']] = $notifier['name'];
+ }
+
+ return $this->notifiersInfo;
+ }
+
+ /**
* @return INotification
* @since 8.2.0
*/
diff --git a/lib/private/notification/notification.php b/lib/private/notification/notification.php
index 01df659d4a1..6568f53f255 100644
--- a/lib/private/notification/notification.php
+++ b/lib/private/notification/notification.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,6 +22,9 @@
namespace OC\Notification;
+use OCP\Notification\IAction;
+use OCP\Notification\INotification;
+
class Notification implements INotification {
/** @var string */
protected $app;
@@ -29,13 +32,13 @@ class Notification implements INotification {
/** @var string */
protected $user;
- /** @var int */
- protected $timestamp;
+ /** @var \DateTime */
+ protected $dateTime;
/** @var string */
protected $objectType;
- /** @var int */
+ /** @var string */
protected $objectId;
/** @var string */
@@ -80,9 +83,10 @@ class Notification implements INotification {
public function __construct() {
$this->app = '';
$this->user = '';
- $this->timestamp = 0;
+ $this->dateTime = new \DateTime();
+ $this->dateTime->setTimestamp(0);
$this->objectType = '';
- $this->objectId = 0;
+ $this->objectId = '';
$this->subject = '';
$this->subjectParameters = [];
$this->subjectParsed = '';
@@ -140,33 +144,33 @@ class Notification implements INotification {
}
/**
- * @param int $timestamp
+ * @param \DateTime $dateTime
* @return $this
- * @throws \InvalidArgumentException if the timestamp is invalid
- * @since 8.2.0
+ * @throws \InvalidArgumentException if the $dateTime is invalid
+ * @since 9.0.0
*/
- public function setTimestamp($timestamp) {
- if (!is_int($timestamp)) {
- throw new \InvalidArgumentException('The given timestamp is invalid');
+ public function setDateTime(\DateTime $dateTime) {
+ if ($dateTime->getTimestamp() === 0) {
+ throw new \InvalidArgumentException('The given date time is invalid');
}
- $this->timestamp = $timestamp;
+ $this->dateTime = $dateTime;
return $this;
}
/**
- * @return int
- * @since 8.2.0
+ * @return \DateTime
+ * @since 9.0.0
*/
- public function getTimestamp() {
- return $this->timestamp;
+ public function getDateTime() {
+ return $this->dateTime;
}
/**
* @param string $type
- * @param int $id
+ * @param string $id
* @return $this
* @throws \InvalidArgumentException if the object type or id is invalid
- * @since 8.2.0
+ * @since 8.2.0 - 9.0.0: Type of $id changed to string
*/
public function setObject($type, $id) {
if (!is_string($type) || $type === '' || isset($type[64])) {
@@ -174,10 +178,10 @@ class Notification implements INotification {
}
$this->objectType = $type;
- if (!is_int($id)) {
+ if (!is_int($id) && (!is_string($id) || $id === '' || isset($id[64]))) {
throw new \InvalidArgumentException('The given object id is invalid');
}
- $this->objectId = $id;
+ $this->objectId = (string) $id;
return $this;
}
@@ -190,8 +194,8 @@ class Notification implements INotification {
}
/**
- * @return int
- * @since 8.2.0
+ * @return string
+ * @since 8.2.0 - 9.0.0: Return type changed to string
*/
public function getObjectId() {
return $this->objectId;
@@ -438,11 +442,11 @@ class Notification implements INotification {
&&
$this->getUser() !== ''
&&
- $this->getTimestamp() !== 0
+ $this->getDateTime()->getTimestamp() !== 0
&&
$this->getObjectType() !== ''
&&
- $this->getObjectId() !== 0
+ $this->getObjectId() !== ''
;
}
}
diff --git a/lib/private/notsquareexception.php b/lib/private/notsquareexception.php
index 23d6ebca2c0..e3494463850 100644
--- a/lib/private/notsquareexception.php
+++ b/lib/private/notsquareexception.php
@@ -3,7 +3,7 @@
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/ocs.php b/lib/private/ocs.php
index 7b474fa439f..f48879a98b1 100644
--- a/lib/private/ocs.php
+++ b/lib/private/ocs.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/ocs/cloud.php b/lib/private/ocs/cloud.php
index 0d93819b9e4..1d47fb208a7 100644
--- a/lib/private/ocs/cloud.php
+++ b/lib/private/ocs/cloud.php
@@ -5,7 +5,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,7 +26,7 @@ class OC_OCS_Cloud {
public static function getCapabilities() {
$result = array();
- list($major, $minor, $micro) = OC_Util::getVersion();
+ list($major, $minor, $micro) = \OCP\Util::getVersion();
$result['version'] = array(
'major' => $major,
'minor' => $minor,
@@ -41,11 +41,11 @@ class OC_OCS_Cloud {
}
public static function getCurrentUser() {
- $email=\OC::$server->getConfig()->getUserValue(OC_User::getUser(), 'settings', 'email', '');
+ $userObject = \OC::$server->getUserManager()->get(OC_User::getUser());
$data = array(
- 'id' => OC_User::getUser(),
- 'display-name' => OC_User::getDisplayName(),
- 'email' => $email,
+ 'id' => $userObject->getUID(),
+ 'display-name' => $userObject->getDisplayName(),
+ 'email' => $userObject->getEMailAddress(),
);
return new OC_OCS_Result($data);
}
diff --git a/lib/private/ocs/config.php b/lib/private/ocs/config.php
index fc9640b6cc4..db04dcbd400 100644
--- a/lib/private/ocs/config.php
+++ b/lib/private/ocs/config.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/ocs/corecapabilities.php b/lib/private/ocs/corecapabilities.php
index f2d530a8419..388a58791b4 100644
--- a/lib/private/ocs/corecapabilities.php
+++ b/lib/private/ocs/corecapabilities.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/ocs/exception.php b/lib/private/ocs/exception.php
index 93bee773771..ca67ac5e841 100644
--- a/lib/private/ocs/exception.php
+++ b/lib/private/ocs/exception.php
@@ -2,7 +2,7 @@
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/ocs/person.php b/lib/private/ocs/person.php
index 0059982c55e..7162fa5e4fb 100644
--- a/lib/private/ocs/person.php
+++ b/lib/private/ocs/person.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/ocs/privatedata.php b/lib/private/ocs/privatedata.php
index 92f029aa12a..e514c05a3dd 100644
--- a/lib/private/ocs/privatedata.php
+++ b/lib/private/ocs/privatedata.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/ocs/result.php b/lib/private/ocs/result.php
index 2c3f676510c..c342bc582fe 100644
--- a/lib/private/ocs/result.php
+++ b/lib/private/ocs/result.php
@@ -5,11 +5,11 @@
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/ocsclient.php b/lib/private/ocsclient.php
index e2973f82605..a783a1f8425 100644
--- a/lib/private/ocsclient.php
+++ b/lib/private/ocsclient.php
@@ -9,11 +9,11 @@
* @author Kamil Domanski <kdomanski@kdemail.net>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Sam Tuke <mail@samtuke.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -97,6 +97,7 @@ class OCSClient {
libxml_disable_entity_loader($loadEntities);
if($data === false) {
+ libxml_clear_errors();
$this->logger->error(
sprintf('Could not get %s, content was no valid XML', $action),
[
@@ -283,7 +284,7 @@ class OCSClient {
}
$app = [];
- $app['id'] = (int)$tmp->id;
+ $app['id'] = (int)$id;
$app['name'] = (string)$tmp->name;
$app['version'] = (string)$tmp->version;
$app['type'] = (string)$tmp->typeid;
diff --git a/lib/private/preview.php b/lib/private/preview.php
index b2accdfd00f..df6eeceddcb 100644
--- a/lib/private/preview.php
+++ b/lib/private/preview.php
@@ -9,10 +9,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tobias Kaminsky <tobias@kaminsky.me>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -1168,7 +1169,7 @@ class Preview {
*/
private function getMimeIcon() {
$image = new \OC_Image();
- $mimeIconWebPath = \OC_Helper::mimetypeIcon($this->mimeType);
+ $mimeIconWebPath = \OC::$server->getMimeTypeDetector()->mimeTypeIcon($this->mimeType);
if (empty(\OC::$WEBROOT)) {
$mimeIconServerPath = \OC::$SERVERROOT . $mimeIconWebPath;
} else {
@@ -1250,7 +1251,7 @@ class Preview {
* @param array $args
* @param string $prefix
*/
- public static function prepare_delete($args, $prefix = '') {
+ public static function prepare_delete(array $args, $prefix = '') {
$path = $args['path'];
if (substr($path, 0, 1) === '/') {
$path = substr($path, 1);
@@ -1259,7 +1260,11 @@ class Preview {
$view = new \OC\Files\View('/' . \OC_User::getUser() . '/' . $prefix);
$absPath = Files\Filesystem::normalizePath($view->getAbsolutePath($path));
- self::addPathToDeleteFileMapper($absPath, $view->getFileInfo($path));
+ $fileInfo = $view->getFileInfo($path);
+ if($fileInfo === false) {
+ return;
+ }
+ self::addPathToDeleteFileMapper($absPath, $fileInfo);
if ($view->is_dir($path)) {
$children = self::getAllChildren($view, $path);
self::$deleteChildrenMapper[$absPath] = $children;
diff --git a/lib/private/preview/bitmap.php b/lib/private/preview/bitmap.php
index ad0ef000510..34bc2f93fc7 100644
--- a/lib/private/preview/bitmap.php
+++ b/lib/private/preview/bitmap.php
@@ -5,7 +5,7 @@
* @author Olivier Paroz <github@oparoz.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/bmp.php b/lib/private/preview/bmp.php
index 36439626f08..da13cd9e5b8 100644
--- a/lib/private/preview/bmp.php
+++ b/lib/private/preview/bmp.php
@@ -2,7 +2,7 @@
/**
* @author Olivier Paroz <github@oparoz.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/font.php b/lib/private/preview/font.php
index 197297a6df6..caac2923789 100644
--- a/lib/private/preview/font.php
+++ b/lib/private/preview/font.php
@@ -2,7 +2,7 @@
/**
* @author Olivier Paroz <github@oparoz.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/gif.php b/lib/private/preview/gif.php
index a3b57484999..0716a6f4406 100644
--- a/lib/private/preview/gif.php
+++ b/lib/private/preview/gif.php
@@ -2,7 +2,7 @@
/**
* @author Olivier Paroz <github@oparoz.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/illustrator.php b/lib/private/preview/illustrator.php
index ac9dcb5ffbf..ef8448d7b53 100644
--- a/lib/private/preview/illustrator.php
+++ b/lib/private/preview/illustrator.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/image.php b/lib/private/preview/image.php
index 9287d9c888b..b377f0e855d 100644
--- a/lib/private/preview/image.php
+++ b/lib/private/preview/image.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/jpeg.php b/lib/private/preview/jpeg.php
index 96f89f4d57e..2ee5dd24419 100644
--- a/lib/private/preview/jpeg.php
+++ b/lib/private/preview/jpeg.php
@@ -2,7 +2,7 @@
/**
* @author Olivier Paroz <github@oparoz.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/markdown.php b/lib/private/preview/markdown.php
index f5e74697621..394af6576c7 100644
--- a/lib/private/preview/markdown.php
+++ b/lib/private/preview/markdown.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/movie.php b/lib/private/preview/movie.php
index f71eaaf3eb2..ee56f017229 100644
--- a/lib/private/preview/movie.php
+++ b/lib/private/preview/movie.php
@@ -2,10 +2,11 @@
/**
* @author Georg Ehrke <georg@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -46,7 +47,7 @@ class Movie extends Provider {
if ($useFileDirectly) {
$absPath = $fileview->getLocalFile($path);
} else {
- $absPath = \OC_Helper::tmpFile();
+ $absPath = \OC::$server->getTempManager()->getTemporaryFile();
$handle = $fileview->fopen($path, 'rb');
@@ -79,7 +80,7 @@ class Movie extends Provider {
* @return bool|\OCP\IImage
*/
private function generateThumbNail($maxX, $maxY, $absPath, $second) {
- $tmpPath = \OC_Helper::tmpFile();
+ $tmpPath = \OC::$server->getTempManager()->getTemporaryFile();
if (self::$avconvBinary) {
$cmd = self::$avconvBinary . ' -an -y -ss ' . escapeshellarg($second) .
diff --git a/lib/private/preview/mp3.php b/lib/private/preview/mp3.php
index ffe596db71b..b984cb4e10d 100644
--- a/lib/private/preview/mp3.php
+++ b/lib/private/preview/mp3.php
@@ -5,7 +5,7 @@
* @author Olivier Paroz <github@oparoz.com>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/msoffice2003.php b/lib/private/preview/msoffice2003.php
index dd00cacedf3..20dbe13543a 100644
--- a/lib/private/preview/msoffice2003.php
+++ b/lib/private/preview/msoffice2003.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/msoffice2007.php b/lib/private/preview/msoffice2007.php
index 8fcdabc0484..ef6758843f1 100644
--- a/lib/private/preview/msoffice2007.php
+++ b/lib/private/preview/msoffice2007.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/msofficedoc.php b/lib/private/preview/msofficedoc.php
index 6ce003387fb..05d839d508f 100644
--- a/lib/private/preview/msofficedoc.php
+++ b/lib/private/preview/msofficedoc.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/office.php b/lib/private/preview/office.php
index 415220ed4af..6496e091b1d 100644
--- a/lib/private/preview/office.php
+++ b/lib/private/preview/office.php
@@ -1,11 +1,12 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -79,8 +80,9 @@ abstract class Office extends Provider {
private function initCmd() {
$cmd = '';
- if (is_string(\OC_Config::getValue('preview_libreoffice_path', null))) {
- $cmd = \OC_Config::getValue('preview_libreoffice_path', null);
+ $libreOfficePath = \OC::$server->getConfig()->getSystemValue('preview_libreoffice_path', null);
+ if (is_string($libreOfficePath)) {
+ $cmd = $libreOfficePath;
}
$whichLibreOffice = shell_exec('command -v libreoffice');
diff --git a/lib/private/preview/opendocument.php b/lib/private/preview/opendocument.php
index 21df2b5909a..0da1e88cafa 100644
--- a/lib/private/preview/opendocument.php
+++ b/lib/private/preview/opendocument.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/pdf.php b/lib/private/preview/pdf.php
index 220cbf14faf..6ddf33cdea2 100644
--- a/lib/private/preview/pdf.php
+++ b/lib/private/preview/pdf.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/photoshop.php b/lib/private/preview/photoshop.php
index 73c2e82d096..df91247f072 100644
--- a/lib/private/preview/photoshop.php
+++ b/lib/private/preview/photoshop.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/png.php b/lib/private/preview/png.php
index bab63c16ada..5dd9ae484a5 100644
--- a/lib/private/preview/png.php
+++ b/lib/private/preview/png.php
@@ -2,7 +2,7 @@
/**
* @author Olivier Paroz <github@oparoz.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/postscript.php b/lib/private/preview/postscript.php
index d69e86edc7f..edfd43968c2 100644
--- a/lib/private/preview/postscript.php
+++ b/lib/private/preview/postscript.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/provider.php b/lib/private/preview/provider.php
index 8f4a9f9fc3f..738d13d7fc8 100644
--- a/lib/private/preview/provider.php
+++ b/lib/private/preview/provider.php
@@ -6,7 +6,7 @@
* @author Olivier Paroz <github@oparoz.com>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/staroffice.php b/lib/private/preview/staroffice.php
index b06de79f707..6ea4efa5144 100644
--- a/lib/private/preview/staroffice.php
+++ b/lib/private/preview/staroffice.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/svg.php b/lib/private/preview/svg.php
index 26ce0fa9411..6618c1fbf82 100644
--- a/lib/private/preview/svg.php
+++ b/lib/private/preview/svg.php
@@ -5,7 +5,7 @@
* @author Olivier Paroz <github@oparoz.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/tiff.php b/lib/private/preview/tiff.php
index 624eb5ddff2..006ced6aec0 100644
--- a/lib/private/preview/tiff.php
+++ b/lib/private/preview/tiff.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/txt.php b/lib/private/preview/txt.php
index b6c21b7c1b1..a27517c9f39 100644
--- a/lib/private/preview/txt.php
+++ b/lib/private/preview/txt.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/preview/xbitmap.php b/lib/private/preview/xbitmap.php
index 7887f2b73f5..604a51a6a83 100644
--- a/lib/private/preview/xbitmap.php
+++ b/lib/private/preview/xbitmap.php
@@ -2,7 +2,7 @@
/**
* @author Olivier Paroz <github@oparoz.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/previewmanager.php b/lib/private/previewmanager.php
index e351c010c85..f3c7a4de0d0 100644
--- a/lib/private/previewmanager.php
+++ b/lib/private/previewmanager.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/repair.php b/lib/private/repair.php
index f6ac7ebe65b..d40c6464e14 100644
--- a/lib/private/repair.php
+++ b/lib/private/repair.php
@@ -9,7 +9,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -40,7 +40,6 @@ use OC\Repair\SqliteAutoincrement;
use OC\Repair\DropOldTables;
use OC\Repair\FillETags;
use OC\Repair\InnoDB;
-use OC\Repair\RepairConfig;
use OC\Repair\RepairLegacyStorages;
use OC\Repair\RepairMimeTypes;
use OC\Repair\SearchLuceneTables;
@@ -107,7 +106,6 @@ class Repair extends BasicEmitter {
return [
new RepairMimeTypes(\OC::$server->getConfig()),
new RepairLegacyStorages(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
- new RepairConfig(),
new AssetCache(),
new FillETags(\OC::$server->getDatabaseConnection()),
new CleanTags(\OC::$server->getDatabaseConnection()),
@@ -138,13 +136,13 @@ class Repair extends BasicEmitter {
* @return array of RepairStep instances
*/
public static function getBeforeUpgradeRepairSteps() {
- $steps = array(
+ $connection = \OC::$server->getDatabaseConnection();
+ $steps = [
new InnoDB(),
- new Collation(\OC::$server->getConfig(), \OC_DB::getConnection()),
- new SqliteAutoincrement(\OC_DB::getConnection()),
+ new Collation(\OC::$server->getConfig(), $connection),
+ new SqliteAutoincrement($connection),
new SearchLuceneTables(),
- new RepairConfig()
- );
+ ];
//There is no need to delete all previews on every single update
//only 7.0.0 through 7.0.2 generated broken previews
diff --git a/lib/repair/assetcache.php b/lib/private/repair/assetcache.php
index c46aa63a3e4..72fe99bbe1a 100644
--- a/lib/repair/assetcache.php
+++ b/lib/private/repair/assetcache.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/cleantags.php b/lib/private/repair/cleantags.php
index d16a49fbca7..537c4da78aa 100644
--- a/lib/repair/cleantags.php
+++ b/lib/private/repair/cleantags.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +24,7 @@ namespace OC\Repair;
use OC\Hooks\BasicEmitter;
use OC\RepairStep;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
/**
@@ -134,7 +135,7 @@ class CleanTags extends BasicEmitter implements RepairStep {
$qb->expr()->eq('type', $qb->expr()->literal('files'))
)
->andWhere($qb->expr()->in($deleteId, $qb->createParameter('ids')));
- $qb->setParameter('ids', $items, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
+ $qb->setParameter('ids', $items, IQueryBuilder::PARAM_INT_ARRAY);
$qb->execute();
}
}
diff --git a/lib/repair/collation.php b/lib/private/repair/collation.php
index 7eb14f0ded2..48035f8d331 100644
--- a/lib/repair/collation.php
+++ b/lib/private/repair/collation.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/dropoldjobs.php b/lib/private/repair/dropoldjobs.php
index 89d7f96a144..2d6172047c2 100644
--- a/lib/repair/dropoldjobs.php
+++ b/lib/private/repair/dropoldjobs.php
@@ -2,7 +2,7 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/dropoldtables.php b/lib/private/repair/dropoldtables.php
index e8b0eba61d4..abd3bd49b0a 100644
--- a/lib/repair/dropoldtables.php
+++ b/lib/private/repair/dropoldtables.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -77,6 +78,7 @@ class DropOldTables extends BasicEmitter implements RepairStep {
'file_map',
'foldersize',
'fscache',
+ 'gallery_sharing',
'locks',
'log',
'media_albums',
diff --git a/lib/repair/filletags.php b/lib/private/repair/filletags.php
index 8cfc4a7c258..dc2ffdcbc36 100644
--- a/lib/repair/filletags.php
+++ b/lib/private/repair/filletags.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/innodb.php b/lib/private/repair/innodb.php
index ab94c79468d..4e157e66045 100644
--- a/lib/repair/innodb.php
+++ b/lib/private/repair/innodb.php
@@ -5,7 +5,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -37,7 +37,7 @@ class InnoDB extends BasicEmitter implements \OC\RepairStep {
* Fix mime types
*/
public function run() {
- $connection = \OC_DB::getConnection();
+ $connection = \OC::$server->getDatabaseConnection();
if (!$connection->getDatabasePlatform() instanceof MySqlPlatform) {
$this->emit('\OC\Repair', 'info', array('Not a mysql database -> nothing to do'));
return;
diff --git a/lib/repair/oldgroupmembershipshares.php b/lib/private/repair/oldgroupmembershipshares.php
index 2d701ac9fb7..bae1bf61a7f 100644
--- a/lib/repair/oldgroupmembershipshares.php
+++ b/lib/private/repair/oldgroupmembershipshares.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/preview.php b/lib/private/repair/preview.php
index 2284da93734..481e98b42d1 100644
--- a/lib/repair/preview.php
+++ b/lib/private/repair/preview.php
@@ -2,7 +2,7 @@
/**
* @author Georg Ehrke <georg@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/removegetetagentries.php b/lib/private/repair/removegetetagentries.php
index 40040763654..e118da7973a 100644
--- a/lib/repair/removegetetagentries.php
+++ b/lib/private/repair/removegetetagentries.php
@@ -2,7 +2,7 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/repairinvalidshares.php b/lib/private/repair/repairinvalidshares.php
index 5a4cb445ce9..ee8b23906e5 100644
--- a/lib/repair/repairinvalidshares.php
+++ b/lib/private/repair/repairinvalidshares.php
@@ -1,9 +1,10 @@
<?php
/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/repairlegacystorages.php b/lib/private/repair/repairlegacystorages.php
index 5ba452cbbc6..ee189110a87 100644
--- a/lib/repair/repairlegacystorages.php
+++ b/lib/private/repair/repairlegacystorages.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/repairmimetypes.php b/lib/private/repair/repairmimetypes.php
index e687dbde688..b84f19a3082 100644
--- a/lib/repair/repairmimetypes.php
+++ b/lib/private/repair/repairmimetypes.php
@@ -8,7 +8,7 @@
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -293,6 +293,17 @@ class RepairMimeTypes extends BasicEmitter implements \OC\RepairStep {
self::updateMimetypes($updatedMimetypes);
}
+ private function introduceRichDocumentsMimeTypes() {
+ $updatedMimetypes = array(
+ 'lwp' => 'application/vnd.lotus-wordpro',
+ 'one' => 'application/msonenote',
+ 'vsd' => 'application/vnd.visio',
+ 'wpd' => 'application/vnd.wordperfect',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
/**
* Fix mime types
*/
@@ -356,5 +367,11 @@ class RepairMimeTypes extends BasicEmitter implements \OC\RepairStep {
$this->emit('\OC\Repair', 'info', array('Fixed rtf mime type'));
}
}
+
+ if (version_compare($ocVersionFromBeforeUpdate, '9.0.0.10', '<')) {
+ if ($this->introduceRichDocumentsMimeTypes()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed richdocuments additional office mime types'));
+ }
+ }
}
}
diff --git a/lib/repair/searchlucenetables.php b/lib/private/repair/searchlucenetables.php
index 5ae8a300246..9f3601eeb03 100644
--- a/lib/repair/searchlucenetables.php
+++ b/lib/private/repair/searchlucenetables.php
@@ -3,7 +3,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -52,10 +52,10 @@ class SearchLuceneTables extends BasicEmitter implements \OC\RepairStep {
* search_lucene will then reindex the fileids without a status when the next indexing job is executed
*/
public function run() {
- if (\OC_DB::tableExists('lucene_status')) {
+ $connection = \OC::$server->getDatabaseConnection();
+ if ($connection->tableExists('lucene_status')) {
$this->emit('\OC\Repair', 'info', array('removing duplicate entries from lucene_status'));
- $connection = \OC_DB::getConnection();
$query = $connection->prepare('
DELETE FROM `*PREFIX*lucene_status`
WHERE `fileid` IN (
diff --git a/lib/repair/sqliteautoincrement.php b/lib/private/repair/sqliteautoincrement.php
index 70d0adae5d7..d7cac57229d 100644
--- a/lib/repair/sqliteautoincrement.php
+++ b/lib/private/repair/sqliteautoincrement.php
@@ -2,7 +2,7 @@
/**
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/updatecertificatestore.php b/lib/private/repair/updatecertificatestore.php
index 5fad309a959..ae7585f07f6 100644
--- a/lib/repair/updatecertificatestore.php
+++ b/lib/private/repair/updatecertificatestore.php
@@ -2,7 +2,7 @@
/**
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/repair/updateoutdatedocsids.php b/lib/private/repair/updateoutdatedocsids.php
index 5f6ee029536..60024b3055c 100644
--- a/lib/repair/updateoutdatedocsids.php
+++ b/lib/private/repair/updateoutdatedocsids.php
@@ -2,7 +2,7 @@
/**
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/repairexception.php b/lib/private/repairexception.php
index 8add3958c9b..e244f2bb820 100644
--- a/lib/private/repairexception.php
+++ b/lib/private/repairexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/repairstep.php b/lib/private/repairstep.php
index 25cb91da68e..e1b8442fb8a 100644
--- a/lib/private/repairstep.php
+++ b/lib/private/repairstep.php
@@ -2,7 +2,7 @@
/**
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/response.php b/lib/private/response.php
index b0eb8adc4d5..5c7eb9b52d5 100644
--- a/lib/private/response.php
+++ b/lib/private/response.php
@@ -5,11 +5,11 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -260,6 +260,8 @@ class OC_Response {
header('X-Content-Type-Options: nosniff'); // Disable sniffing the content type for IE
header('X-Frame-Options: Sameorigin'); // Disallow iFraming from other domains
header('X-Robots-Tag: none'); // https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
+ header('X-Download-Options: noopen'); // https://msdn.microsoft.com/en-us/library/jj542450(v=vs.85).aspx
+ header('X-Permitted-Cross-Domain-Policies: none'); // https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html
}
}
diff --git a/lib/private/route/cachingrouter.php b/lib/private/route/cachingrouter.php
index 734aa5aea4b..4c702bb8e04 100644
--- a/lib/private/route/cachingrouter.php
+++ b/lib/private/route/cachingrouter.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,6 +22,8 @@
namespace OC\Route;
+use OCP\ILogger;
+
class CachingRouter extends Router {
/**
* @var \OCP\ICache
@@ -30,10 +32,11 @@ class CachingRouter extends Router {
/**
* @param \OCP\ICache $cache
+ * @param ILogger $logger
*/
- public function __construct($cache) {
+ public function __construct($cache, ILogger $logger) {
$this->cache = $cache;
- parent::__construct();
+ parent::__construct($logger);
}
/**
diff --git a/lib/private/route/route.php b/lib/private/route/route.php
index 86f05b85e5b..966790a63c0 100644
--- a/lib/private/route/route.php
+++ b/lib/private/route/route.php
@@ -5,10 +5,10 @@
* @author Felix Moeller <mail@felixmoeller.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/route/router.php b/lib/private/route/router.php
index f4abfae0f43..13f7a7a1cfb 100644
--- a/lib/private/route/router.php
+++ b/lib/private/route/router.php
@@ -7,11 +7,12 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,8 +31,11 @@
namespace OC\Route;
+use OCP\ILogger;
use OCP\Route\IRouter;
use OCP\AppFramework\App;
+use OCP\Util;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\RequestContext;
@@ -39,47 +43,36 @@ use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
class Router implements IRouter {
- /**
- * @var \Symfony\Component\Routing\RouteCollection[]
- */
- protected $collections = array();
-
- /**
- * @var \Symfony\Component\Routing\RouteCollection
- */
+ /** @var RouteCollection[] */
+ protected $collections = [];
+ /** @var null|RouteCollection */
protected $collection = null;
-
- /**
- * @var string
- */
+ /** @var null|string */
protected $collectionName = null;
-
- /**
- * @var \Symfony\Component\Routing\RouteCollection
- */
+ /** @var null|RouteCollection */
protected $root = null;
-
- /**
- * @var \Symfony\Component\Routing\Generator\UrlGenerator
- */
+ /** @var null|UrlGenerator */
protected $generator = null;
-
- /**
- * @var string[]
- */
+ /** @var string[] */
protected $routingFiles;
+ /** @var bool */
+ protected $loaded = false;
+ /** @var array */
+ protected $loadedApps = [];
+ /** @var ILogger */
+ protected $logger;
+ /** @var RequestContext */
+ protected $context;
/**
- * @var string
+ * @param ILogger $logger
*/
- protected $cacheKey;
-
- protected $loaded = false;
-
- protected $loadedApps = array();
-
- public function __construct() {
- $baseUrl = \OC_Helper::linkTo('', 'index.php');
+ public function __construct(ILogger $logger) {
+ $this->logger = $logger;
+ $baseUrl = \OC::$WEBROOT;
+ if(!(getenv('front_controller_active') === 'true')) {
+ $baseUrl = \OC::$server->getURLGenerator()->linkTo('', 'index.php');
+ }
if (!\OC::$CLI) {
$method = $_SERVER['REQUEST_METHOD'];
} else {
@@ -100,7 +93,7 @@ class Router implements IRouter {
*/
public function getRoutingFiles() {
if (!isset($this->routingFiles)) {
- $this->routingFiles = array();
+ $this->routingFiles = [];
foreach (\OC_APP::getEnabledApps() as $app) {
$file = \OC_App::getAppPath($app) . '/appinfo/routes.php';
if (file_exists($file)) {
@@ -112,22 +105,9 @@ class Router implements IRouter {
}
/**
- * @return string
- */
- public function getCacheKey() {
- if (!isset($this->cacheKey)) {
- $files = $this->getRoutingFiles();
- $files[] = 'settings/routes.php';
- $files[] = 'core/routes.php';
- $files[] = 'ocs/routes.php';
- $this->cacheKey = \OC\Cache::generateCacheKeyFromFiles($files);
- }
- return $this->cacheKey;
- }
-
- /**
- * loads the api routes
- * @return void
+ * Loads the routes
+ *
+ * @param null|string $app
*/
public function loadRoutes($app = null) {
$requestedApp = $app;
@@ -142,10 +122,10 @@ class Router implements IRouter {
return;
}
$file = \OC_App::getAppPath($app) . '/appinfo/routes.php';
- if (file_exists($file)) {
- $routingFiles = array($app => $file);
+ if ($file !== false && file_exists($file)) {
+ $routingFiles = [$app => $file];
} else {
- $routingFiles = array();
+ $routingFiles = [];
}
}
\OC::$server->getEventLogger()->start('loadroutes' . $requestedApp, 'Loading Routes');
@@ -168,12 +148,12 @@ class Router implements IRouter {
if (!isset($this->loadedApps['core'])) {
$this->loadedApps['core'] = true;
$this->useCollection('root');
- require_once 'settings/routes.php';
- require_once 'core/routes.php';
+ require_once __DIR__ . '/../../../settings/routes.php';
+ require_once __DIR__ . '/../../../core/routes.php';
}
if ($this->loaded) {
// include ocs routes, must be loaded last for /ocs prefix
- require_once 'ocs/routes.php';
+ require_once __DIR__ . '/../../../ocs/routes.php';
$collection = $this->getCollection('ocs');
$collection->addPrefix('/ocs');
$this->root->addCollection($collection);
@@ -182,6 +162,14 @@ class Router implements IRouter {
}
/**
+ * @return string
+ * @deprecated
+ */
+ public function getCacheKey() {
+ return '';
+ }
+
+ /**
* @param string $name
* @return \Symfony\Component\Routing\RouteCollection
*/
@@ -222,7 +210,10 @@ class Router implements IRouter {
* @param array $requirements An array of requirements for parameters (regexes)
* @return \OC\Route\Route
*/
- public function create($name, $pattern, array $defaults = array(), array $requirements = array()) {
+ public function create($name,
+ $pattern,
+ array $defaults = [],
+ array $requirements = []) {
$route = new Route($pattern, $defaults, $requirements);
$this->collection->add($name, $route);
return $route;
@@ -245,7 +236,7 @@ class Router implements IRouter {
$this->loadRoutes($app);
} else if (substr($url, 0, 6) === '/core/' or substr($url, 0, 10) === '/settings/') {
\OC::$REQUESTEDAPP = $url;
- if (!\OC_Config::getValue('maintenance', false) && !\OCP\Util::needUpgrade()) {
+ if (!\OC::$server->getConfig()->getSystemValue('maintenance', false) && !Util::needUpgrade()) {
\OC_App::loadApps();
}
$this->loadRoutes('core');
@@ -290,6 +281,7 @@ class Router implements IRouter {
/**
* Get the url generator
+ *
* @return \Symfony\Component\Routing\Generator\UrlGenerator
*
*/
@@ -309,13 +301,25 @@ class Router implements IRouter {
* @param bool $absolute
* @return string
*/
- public function generate($name, $parameters = array(), $absolute = false) {
+ public function generate($name,
+ $parameters = [],
+ $absolute = false) {
$this->loadRoutes();
- return $this->getGenerator()->generate($name, $parameters, $absolute);
+ try {
+ $referenceType = UrlGenerator::ABSOLUTE_URL;
+ if ($absolute === false) {
+ $referenceType = UrlGenerator::ABSOLUTE_PATH;
+ }
+ return $this->getGenerator()->generate($name, $parameters, $referenceType);
+ } catch (RouteNotFoundException $e) {
+ $this->logger->logException($e);
+ return '';
+ }
}
/**
* To isolate the variable scope used inside the $file it is required in it's own method
+ *
* @param string $file the route file location to include
* @param string $appName
*/
@@ -331,6 +335,7 @@ class Router implements IRouter {
* \OCA\MyApp\AppInfo\Application. If that class does not exist, a default
* App will be intialized. This makes it optional to ship an
* appinfo/application.php by using the built in query resolver
+ *
* @param array $routes the application routes
* @param string $appName the name of the app.
*/
@@ -349,6 +354,4 @@ class Router implements IRouter {
$application->registerRoutes($this, $routes);
}
}
-
-
}
diff --git a/lib/private/search.php b/lib/private/search.php
index ea77fa4f151..7d1e2734195 100644
--- a/lib/private/search.php
+++ b/lib/private/search.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/search/provider/file.php b/lib/private/search/provider/file.php
index 73d57def644..69ffbd3ae6b 100644
--- a/lib/private/search/provider/file.php
+++ b/lib/private/search/provider/file.php
@@ -6,7 +6,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/search/result/audio.php b/lib/private/search/result/audio.php
index 8e135ea5d29..3f9b3dc640c 100644
--- a/lib/private/search/result/audio.php
+++ b/lib/private/search/result/audio.php
@@ -4,7 +4,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/search/result/file.php b/lib/private/search/result/file.php
index 4329f504a7d..d987d6c8e73 100644
--- a/lib/private/search/result/file.php
+++ b/lib/private/search/result/file.php
@@ -5,7 +5,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/search/result/folder.php b/lib/private/search/result/folder.php
index 18f7de2e481..6f0c0a7b2a5 100644
--- a/lib/private/search/result/folder.php
+++ b/lib/private/search/result/folder.php
@@ -4,7 +4,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/search/result/image.php b/lib/private/search/result/image.php
index bf4425a55f9..87b36fc9f73 100644
--- a/lib/private/search/result/image.php
+++ b/lib/private/search/result/image.php
@@ -4,7 +4,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/security/certificate.php b/lib/private/security/certificate.php
index 0d7fcc4148d..54486ff51fe 100644
--- a/lib/private/security/certificate.php
+++ b/lib/private/security/certificate.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/security/certificatemanager.php b/lib/private/security/certificatemanager.php
index ded81863a73..f4932ca568e 100644
--- a/lib/private/security/certificatemanager.php
+++ b/lib/private/security/certificatemanager.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -50,7 +50,7 @@ class CertificateManager implements ICertificateManager {
/**
* @param string $uid
- * @param \OC\Files\View $view relative zu data/
+ * @param \OC\Files\View $view relative to data/
* @param IConfig $config
*/
public function __construct($uid, \OC\Files\View $view, IConfig $config) {
@@ -83,7 +83,8 @@ class CertificateManager implements ICertificateManager {
if ($file != '.' && $file != '..') {
try {
$result[] = new Certificate($this->view->file_get_contents($path . $file), $file);
- } catch(\Exception $e) {}
+ } catch (\Exception $e) {
+ }
}
}
closedir($handle);
@@ -97,22 +98,34 @@ class CertificateManager implements ICertificateManager {
$path = $this->getPathToCertificates();
$certs = $this->listCertificates();
- $fh_certs = $this->view->fopen($path . '/rootcerts.crt', 'w');
+ if (!$this->view->file_exists($path)) {
+ $this->view->mkdir($path);
+ }
+
+ $fhCerts = $this->view->fopen($path . '/rootcerts.crt', 'w');
// Write user certificates
foreach ($certs as $cert) {
$file = $path . '/uploads/' . $cert->getName();
$data = $this->view->file_get_contents($file);
if (strpos($data, 'BEGIN CERTIFICATE')) {
- fwrite($fh_certs, $data);
- fwrite($fh_certs, "\r\n");
+ fwrite($fhCerts, $data);
+ fwrite($fhCerts, "\r\n");
}
}
// Append the default certificates
$defaultCertificates = file_get_contents(\OC::$SERVERROOT . '/resources/config/ca-bundle.crt');
- fwrite($fh_certs, $defaultCertificates);
- fclose($fh_certs);
+ fwrite($fhCerts, $defaultCertificates);
+
+ // Append the system certificate bundle
+ $systemBundle = $this->getCertificateBundle(null);
+ if ($this->view->file_exists($systemBundle)) {
+ $systemCertificates = $this->view->file_get_contents($systemBundle);
+ fwrite($fhCerts, $systemCertificates);
+ }
+
+ fclose($fhCerts);
}
/**
@@ -166,18 +179,72 @@ class CertificateManager implements ICertificateManager {
/**
* Get the path to the certificate bundle for this user
*
+ * @param string $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle
* @return string
*/
- public function getCertificateBundle() {
- return $this->getPathToCertificates() . 'rootcerts.crt';
+ public function getCertificateBundle($uid = '') {
+ if ($uid === '') {
+ $uid = $this->uid;
+ }
+ return $this->getPathToCertificates($uid) . 'rootcerts.crt';
+ }
+
+ /**
+ * Get the full local path to the certificate bundle for this user
+ *
+ * @param string $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle
+ * @return string
+ */
+ public function getAbsoluteBundlePath($uid = '') {
+ if ($uid === '') {
+ $uid = $this->uid;
+ }
+ if ($this->needsRebundling($uid)) {
+ if (is_null($uid)) {
+ $manager = new CertificateManager(null, $this->view, $this->config);
+ $manager->createCertificateBundle();
+ } else {
+ $this->createCertificateBundle();
+ }
+ }
+ return $this->view->getLocalFile($this->getCertificateBundle($uid));
}
/**
+ * @param string $uid (optional) user to get the certificate path for, use `null` to get the system path
* @return string
*/
- private function getPathToCertificates() {
- $path = is_null($this->uid) ? '/files_external/' : '/' . $this->uid . '/files_external/';
+ private function getPathToCertificates($uid = '') {
+ if ($uid === '') {
+ $uid = $this->uid;
+ }
+ $path = is_null($uid) ? '/files_external/' : '/' . $uid . '/files_external/';
return $path;
}
+
+ /**
+ * Check if we need to re-bundle the certificates because one of the sources has updated
+ *
+ * @param string $uid (optional) user to get the certificate path for, use `null` to get the system path
+ * @return bool
+ */
+ private function needsRebundling($uid = '') {
+ if ($uid === '') {
+ $uid = $this->uid;
+ }
+ $sourceMTimes = [filemtime(\OC::$SERVERROOT . '/resources/config/ca-bundle.crt')];
+ $targetBundle = $this->getCertificateBundle($uid);
+ if (!$this->view->file_exists($targetBundle)) {
+ return true;
+ }
+ if (!is_null($uid)) { // also depend on the system bundle
+ $sourceBundles[] = $this->view->filemtime($this->getCertificateBundle(null));
+ }
+
+ $sourceMTime = array_reduce($sourceMTimes, function ($max, $mtime) {
+ return max($max, $mtime);
+ }, 0);
+ return $sourceMTime > $this->view->filemtime($targetBundle);
+ }
}
diff --git a/lib/private/security/credentialsmanager.php b/lib/private/security/credentialsmanager.php
new file mode 100644
index 00000000000..405922847be
--- /dev/null
+++ b/lib/private/security/credentialsmanager.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Security;
+
+use OCP\Security\ICrypto;
+use OCP\IDBConnection;
+use OCP\Security\ICredentialsManager;
+use OCP\IConfig;
+
+/**
+ * Store and retrieve credentials for external services
+ *
+ * @package OC\Security
+ */
+class CredentialsManager implements ICredentialsManager {
+
+ const DB_TABLE = 'credentials';
+
+ /** @var ICrypto */
+ protected $crypto;
+
+ /** @var IDBConnection */
+ protected $dbConnection;
+
+ /**
+ * @param ICrypto $crypto
+ * @param IDBConnection $dbConnection
+ */
+ public function __construct(ICrypto $crypto, IDBConnection $dbConnection) {
+ $this->crypto = $crypto;
+ $this->dbConnection = $dbConnection;
+ }
+
+ /**
+ * Store a set of credentials
+ *
+ * @param string|null $userId Null for system-wide credentials
+ * @param string $identifier
+ * @param mixed $credentials
+ */
+ public function store($userId, $identifier, $credentials) {
+ $value = $this->crypto->encrypt(json_encode($credentials));
+
+ $this->dbConnection->setValues(self::DB_TABLE, [
+ 'user' => $userId,
+ 'identifier' => $identifier,
+ ], [
+ 'credentials' => $value,
+ ]);
+ }
+
+ /**
+ * Retrieve a set of credentials
+ *
+ * @param string|null $userId Null for system-wide credentials
+ * @param string $identifier
+ * @return mixed
+ */
+ public function retrieve($userId, $identifier) {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->select('credentials')
+ ->from(self::DB_TABLE)
+ ->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
+ ->andWhere($qb->expr()->eq('identifier', $qb->createNamedParameter($identifier)))
+ ;
+ $result = $qb->execute()->fetch();
+
+ if (!$result) {
+ return null;
+ }
+ $value = $result['credentials'];
+
+ return json_decode($this->crypto->decrypt($value), true);
+ }
+
+ /**
+ * Delete a set of credentials
+ *
+ * @param string|null $userId Null for system-wide credentials
+ * @param string $identifier
+ * @return int rows removed
+ */
+ public function delete($userId, $identifier) {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->delete(self::DB_TABLE)
+ ->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
+ ->andWhere($qb->expr()->eq('identifier', $qb->createNamedParameter($identifier)))
+ ;
+ return $qb->execute();
+ }
+
+ /**
+ * Erase all credentials stored for a user
+ *
+ * @param string $userId
+ * @return int rows removed
+ */
+ public function erase($userId) {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->delete(self::DB_TABLE)
+ ->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
+ ;
+ return $qb->execute();
+ }
+
+}
diff --git a/lib/private/security/crypto.php b/lib/private/security/crypto.php
index 0bd34df3f36..3c3ffb47398 100644
--- a/lib/private/security/crypto.php
+++ b/lib/private/security/crypto.php
@@ -3,8 +3,9 @@
* @author Andreas Fischer <bantu@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -90,7 +91,7 @@ class Crypto implements ICrypto {
}
$this->cipher->setPassword($password);
- $iv = $this->random->getLowStrengthGenerator()->generate($this->ivLength);
+ $iv = $this->random->generate($this->ivLength);
$this->cipher->setIV($iv);
$ciphertext = bin2hex($this->cipher->encrypt($plaintext));
@@ -123,7 +124,7 @@ class Crypto implements ICrypto {
$this->cipher->setIV($iv);
- if(!\OCP\Security\StringUtils::equals($this->calculateHMAC($parts[0].$parts[1], $password), $hmac)) {
+ if(!hash_equals($this->calculateHMAC($parts[0].$parts[1], $password), $hmac)) {
throw new \Exception('HMAC does not match.');
}
diff --git a/lib/private/security/csp/contentsecuritypolicy.php b/lib/private/security/csp/contentsecuritypolicy.php
new file mode 100644
index 00000000000..25eacfab1d6
--- /dev/null
+++ b/lib/private/security/csp/contentsecuritypolicy.php
@@ -0,0 +1,199 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Security\CSP;
+
+/**
+ * Class ContentSecurityPolicy extends the public class and adds getter and setters.
+ * This is necessary since we don't want to expose the setters and getters to the
+ * public API.
+ *
+ * @package OC\Security\CSP
+ */
+class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy {
+ /**
+ * @return boolean
+ */
+ public function isInlineScriptAllowed() {
+ return $this->inlineScriptAllowed;
+ }
+
+ /**
+ * @param boolean $inlineScriptAllowed
+ */
+ public function setInlineScriptAllowed($inlineScriptAllowed) {
+ $this->inlineScriptAllowed = $inlineScriptAllowed;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isEvalScriptAllowed() {
+ return $this->evalScriptAllowed;
+ }
+
+ /**
+ * @param boolean $evalScriptAllowed
+ */
+ public function setEvalScriptAllowed($evalScriptAllowed) {
+ $this->evalScriptAllowed = $evalScriptAllowed;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedScriptDomains() {
+ return $this->allowedScriptDomains;
+ }
+
+ /**
+ * @param array $allowedScriptDomains
+ */
+ public function setAllowedScriptDomains($allowedScriptDomains) {
+ $this->allowedScriptDomains = $allowedScriptDomains;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isInlineStyleAllowed() {
+ return $this->inlineStyleAllowed;
+ }
+
+ /**
+ * @param boolean $inlineStyleAllowed
+ */
+ public function setInlineStyleAllowed($inlineStyleAllowed) {
+ $this->inlineStyleAllowed = $inlineStyleAllowed;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedStyleDomains() {
+ return $this->allowedStyleDomains;
+ }
+
+ /**
+ * @param array $allowedStyleDomains
+ */
+ public function setAllowedStyleDomains($allowedStyleDomains) {
+ $this->allowedStyleDomains = $allowedStyleDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedImageDomains() {
+ return $this->allowedImageDomains;
+ }
+
+ /**
+ * @param array $allowedImageDomains
+ */
+ public function setAllowedImageDomains($allowedImageDomains) {
+ $this->allowedImageDomains = $allowedImageDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedConnectDomains() {
+ return $this->allowedConnectDomains;
+ }
+
+ /**
+ * @param array $allowedConnectDomains
+ */
+ public function setAllowedConnectDomains($allowedConnectDomains) {
+ $this->allowedConnectDomains = $allowedConnectDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedMediaDomains() {
+ return $this->allowedMediaDomains;
+ }
+
+ /**
+ * @param array $allowedMediaDomains
+ */
+ public function setAllowedMediaDomains($allowedMediaDomains) {
+ $this->allowedMediaDomains = $allowedMediaDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedObjectDomains() {
+ return $this->allowedObjectDomains;
+ }
+
+ /**
+ * @param array $allowedObjectDomains
+ */
+ public function setAllowedObjectDomains($allowedObjectDomains) {
+ $this->allowedObjectDomains = $allowedObjectDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedFrameDomains() {
+ return $this->allowedFrameDomains;
+ }
+
+ /**
+ * @param array $allowedFrameDomains
+ */
+ public function setAllowedFrameDomains($allowedFrameDomains) {
+ $this->allowedFrameDomains = $allowedFrameDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedFontDomains() {
+ return $this->allowedFontDomains;
+ }
+
+ /**
+ * @param array $allowedFontDomains
+ */
+ public function setAllowedFontDomains($allowedFontDomains) {
+ $this->allowedFontDomains = $allowedFontDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedChildSrcDomains() {
+ return $this->allowedChildSrcDomains;
+ }
+
+ /**
+ * @param array $allowedChildSrcDomains
+ */
+ public function setAllowedChildSrcDomains($allowedChildSrcDomains) {
+ $this->allowedChildSrcDomains = $allowedChildSrcDomains;
+ }
+
+}
diff --git a/lib/private/security/csp/contentsecuritypolicymanager.php b/lib/private/security/csp/contentsecuritypolicymanager.php
new file mode 100644
index 00000000000..760cd36e56b
--- /dev/null
+++ b/lib/private/security/csp/contentsecuritypolicymanager.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Security\CSP;
+
+use OCP\AppFramework\Http\ContentSecurityPolicy;
+use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
+use OCP\Security\IContentSecurityPolicyManager;
+
+class ContentSecurityPolicyManager implements IContentSecurityPolicyManager {
+ /** @var ContentSecurityPolicy[] */
+ private $policies = [];
+
+ /** {@inheritdoc} */
+ public function addDefaultPolicy(EmptyContentSecurityPolicy $policy) {
+ $this->policies[] = $policy;
+ }
+
+ /**
+ * Get the configured default policy. This is not in the public namespace
+ * as it is only supposed to be used by core itself.
+ *
+ * @return ContentSecurityPolicy
+ */
+ public function getDefaultPolicy() {
+ $defaultPolicy = new \OC\Security\CSP\ContentSecurityPolicy();
+ foreach($this->policies as $policy) {
+ $defaultPolicy = $this->mergePolicies($defaultPolicy, $policy);
+ }
+ return $defaultPolicy;
+ }
+
+ /**
+ * Merges the first given policy with the second one
+ *
+ * @param ContentSecurityPolicy $defaultPolicy
+ * @param EmptyContentSecurityPolicy $originalPolicy
+ * @return ContentSecurityPolicy
+ */
+ public function mergePolicies(ContentSecurityPolicy $defaultPolicy,
+ EmptyContentSecurityPolicy $originalPolicy) {
+ foreach((object)(array)$originalPolicy as $name => $value) {
+ $setter = 'set'.ucfirst($name);
+ if(is_array($value)) {
+ $getter = 'get'.ucfirst($name);
+ $currentValues = is_array($defaultPolicy->$getter()) ? $defaultPolicy->$getter() : [];
+ $defaultPolicy->$setter(array_values(array_unique(array_merge($currentValues, $value))));
+ } elseif (is_bool($value)) {
+ $defaultPolicy->$setter($value);
+ }
+ }
+
+ return $defaultPolicy;
+ }
+}
diff --git a/lib/private/security/csrf/csrftoken.php b/lib/private/security/csrf/csrftoken.php
new file mode 100644
index 00000000000..4524d0db6e6
--- /dev/null
+++ b/lib/private/security/csrf/csrftoken.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Security\CSRF;
+
+/**
+ * Class CsrfToken represents the stored or provided CSRF token. To mitigate
+ * BREACH alike vulnerabilities the token is returned in an encrypted value as
+ * well in an unencrypted value. For display measures to the user always the
+ * unencrypted one should be chosen.
+ *
+ * @package OC\Security\CSRF
+ */
+class CsrfToken {
+ /** @var string */
+ private $value;
+
+ /**
+ * @param string $value Value of the token. Can be encrypted or not encrypted.
+ */
+ public function __construct($value) {
+ $this->value = $value;
+ }
+
+ /**
+ * Encrypted value of the token. This is used to mitigate BREACH alike
+ * vulnerabilities. For display measures do use this functionality.
+ *
+ * @return string
+ */
+ public function getEncryptedValue() {
+ $sharedSecret = base64_encode(random_bytes(strlen($this->value)));
+ return base64_encode($this->value ^ $sharedSecret) .':'.$sharedSecret;
+ }
+
+ /**
+ * The unencrypted value of the token. Used for decrypting an already
+ * encrypted token.
+ *
+ * @return int
+ */
+ public function getDecryptedValue() {
+ $token = explode(':', $this->value);
+ if (count($token) !== 2) {
+ return '';
+ }
+ $obfuscatedToken = $token[0];
+ $secret = $token[1];
+ return base64_decode($obfuscatedToken) ^ $secret;
+ }
+}
diff --git a/lib/private/security/csrf/csrftokengenerator.php b/lib/private/security/csrf/csrftokengenerator.php
new file mode 100644
index 00000000000..6ea71636d22
--- /dev/null
+++ b/lib/private/security/csrf/csrftokengenerator.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Security\CSRF;
+
+use OCP\Security\ISecureRandom;
+
+/**
+ * Class CsrfTokenGenerator is used to generate a cryptographically secure
+ * pseudo-random number for the token.
+ *
+ * @package OC\Security\CSRF
+ */
+class CsrfTokenGenerator {
+ /** @var ISecureRandom */
+ private $random;
+
+ /**
+ * @param ISecureRandom $random
+ */
+ public function __construct(ISecureRandom $random) {
+ $this->random = $random;
+ }
+
+ /**
+ * Generate a new CSRF token.
+ *
+ * @param int $length Length of the token in characters.
+ * @return string
+ */
+ public function generateToken($length = 32) {
+ return $this->random->generate($length);
+ }
+}
diff --git a/lib/private/security/csrf/csrftokenmanager.php b/lib/private/security/csrf/csrftokenmanager.php
new file mode 100644
index 00000000000..8d1bf5c0819
--- /dev/null
+++ b/lib/private/security/csrf/csrftokenmanager.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Security\CSRF;
+
+use OC\Security\CSRF\TokenStorage\SessionStorage;
+
+/**
+ * Class CsrfTokenManager is the manager for all CSRF token related activities.
+ *
+ * @package OC\Security\CSRF
+ */
+class CsrfTokenManager {
+ /** @var CsrfTokenGenerator */
+ private $tokenGenerator;
+ /** @var SessionStorage */
+ private $sessionStorage;
+
+ /**
+ * @param CsrfTokenGenerator $tokenGenerator
+ * @param SessionStorage $storageInterface
+ */
+ public function __construct(CsrfTokenGenerator $tokenGenerator,
+ SessionStorage $storageInterface) {
+ $this->tokenGenerator = $tokenGenerator;
+ $this->sessionStorage = $storageInterface;
+ }
+
+ /**
+ * Returns the current CSRF token, if none set it will create a new one.
+ *
+ * @return CsrfToken
+ */
+ public function getToken() {
+ if($this->sessionStorage->hasToken()) {
+ $value = $this->sessionStorage->getToken();
+ } else {
+ $value = $this->tokenGenerator->generateToken();
+ $this->sessionStorage->setToken($value);
+ }
+
+ return new CsrfToken($value);
+ }
+
+ /**
+ * Invalidates any current token and sets a new one.
+ *
+ * @return CsrfToken
+ */
+ public function refreshToken() {
+ $value = $this->tokenGenerator->generateToken();
+ $this->sessionStorage->setToken($value);
+ return new CsrfToken($value);
+ }
+
+ /**
+ * Remove the current token from the storage.
+ */
+ public function removeToken() {
+ $this->sessionStorage->removeToken();
+ }
+
+ /**
+ * Verifies whether the provided token is valid.
+ *
+ * @param CsrfToken $token
+ * @return bool
+ */
+ public function isTokenValid(CsrfToken $token) {
+ if(!$this->sessionStorage->hasToken()) {
+ return false;
+ }
+
+ return hash_equals(
+ $this->sessionStorage->getToken(),
+ $token->getDecryptedValue()
+ );
+ }
+}
diff --git a/lib/private/security/csrf/tokenstorage/sessionstorage.php b/lib/private/security/csrf/tokenstorage/sessionstorage.php
new file mode 100644
index 00000000000..e1c8c96e920
--- /dev/null
+++ b/lib/private/security/csrf/tokenstorage/sessionstorage.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Security\CSRF\TokenStorage;
+
+use OCP\ISession;
+
+/**
+ * Class SessionStorage provides the session storage
+ *
+ * @package OC\Security\CSRF\TokenStorage
+ */
+class SessionStorage {
+ /** @var ISession */
+ private $session;
+
+ /**
+ * @param ISession $session
+ */
+ public function __construct(ISession $session) {
+ $this->session = $session;
+ }
+
+ /**
+ * Returns the current token or throws an exception if none is found.
+ *
+ * @return string
+ * @throws \Exception
+ */
+ public function getToken() {
+ $token = $this->session->get('requesttoken');
+ if(empty($token)) {
+ throw new \Exception('Session does not contain a requesttoken');
+ }
+
+ return $token;
+ }
+
+ /**
+ * Set the valid current token to $value.
+ *
+ * @param string $value
+ */
+ public function setToken($value) {
+ $this->session->set('requesttoken', $value);
+ }
+
+ /**
+ * Removes the current token.
+ */
+ public function removeToken() {
+ $this->session->remove('requesttoken');
+ }
+ /**
+ * Whether the storage has a storage.
+ *
+ * @return bool
+ */
+ public function hasToken() {
+ return $this->session->exists('requesttoken');
+ }
+}
diff --git a/lib/private/security/hasher.php b/lib/private/security/hasher.php
index a5dd22e5dc8..a8b81aa60eb 100644
--- a/lib/private/security/hasher.php
+++ b/lib/private/security/hasher.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -109,7 +109,7 @@ class Hasher implements IHasher {
// Verify whether it matches a legacy PHPass or SHA1 string
$hashLength = strlen($hash);
if($hashLength === 60 && password_verify($message.$this->legacySalt, $hash) ||
- $hashLength === 40 && StringUtils::equals($hash, sha1($message))) {
+ $hashLength === 40 && hash_equals($hash, sha1($message))) {
$newHash = $this->hash($message);
return true;
}
diff --git a/lib/private/security/securerandom.php b/lib/private/security/securerandom.php
index 87dca68985e..45cb3f17ee4 100644
--- a/lib/private/security/securerandom.php
+++ b/lib/private/security/securerandom.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,25 +27,15 @@ use Sabre\DAV\Exception;
use OCP\Security\ISecureRandom;
/**
- * Class SecureRandom provides a layer around RandomLib to generate
- * secure random strings. For PHP 7 the native CSPRNG is used.
+ * Class SecureRandom provides a wrapper around the random_int function to generate
+ * secure random strings. For PHP 7 the native CSPRNG is used, older versions do
+ * use a fallback.
*
* Usage:
- * \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(10);
- *
+ * \OC::$server->getSecureRandom()->generate(10);
* @package OC\Security
*/
class SecureRandom implements ISecureRandom {
-
- /** @var \RandomLib\Factory */
- var $factory;
- /** @var \RandomLib\Generator */
- var $generator;
-
- function __construct() {
- $this->factory = new RandomLib\Factory;
- }
-
/**
* Convenience method to get a low strength random number generator.
*
@@ -53,10 +43,10 @@ class SecureRandom implements ISecureRandom {
* in a non-cryptographical setting. They are not strong enough to be
* used as keys or salts. They are however useful for one-time use tokens.
*
+ * @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int()
* @return $this
*/
public function getLowStrengthGenerator() {
- $this->generator = $this->factory->getLowStrengthGenerator();
return $this;
}
@@ -67,10 +57,10 @@ class SecureRandom implements ISecureRandom {
* They are strong enough to be used as keys and salts. However, they do
* take some time and resources to generate, so they should not be over-used
*
+ * @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int()
* @return $this
*/
public function getMediumStrengthGenerator() {
- $this->generator = $this->factory->getMediumStrengthGenerator();
return $this;
}
@@ -80,26 +70,17 @@ class SecureRandom implements ISecureRandom {
* @param string $characters An optional list of characters to use if no character list is
* specified all valid base64 characters are used.
* @return string
- * @throws \Exception If the generator is not initialized.
*/
public function generate($length,
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') {
- if(is_null($this->generator)) {
- throw new \Exception('Generator is not initialized.');
- }
+ $maxCharIndex = strlen($characters) - 1;
+ $randomString = '';
- if(function_exists('random_int')) {
- $maxCharIndex = strlen($characters) - 1;
- $randomString = '';
-
- while($length > 0) {
- $randomNumber = random_int(0, $maxCharIndex);
- $randomString .= $characters[$randomNumber];
- $length--;
- }
- return $randomString;
+ while($length > 0) {
+ $randomNumber = \random_int(0, $maxCharIndex);
+ $randomString .= $characters[$randomNumber];
+ $length--;
}
-
- return $this->generator->generateString($length, $characters);
+ return $randomString;
}
}
diff --git a/lib/private/security/stringutils.php b/lib/private/security/stringutils.php
deleted file mode 100644
index fa4342a2b45..00000000000
--- a/lib/private/security/stringutils.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OC\Security;
-
-class StringUtils {
-
- /**
- * Compares whether two strings are equal. To prevent guessing of the string
- * length this is done by comparing two hashes against each other and afterwards
- * a comparison of the real string to prevent against the unlikely chance of
- * collisions.
- *
- * Be aware that this function may leak whether the string to compare have a different
- * length.
- *
- * @param string $expected The expected value
- * @param string $input The input to compare against
- * @return bool True if the two strings are equal, otherwise false.
- */
- public static function equals($expected, $input) {
-
- if(!is_string($expected) || !is_string($input)) {
- return false;
- }
-
- if(function_exists('hash_equals')) {
- return hash_equals($expected, $input);
- }
-
- $randomString = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(10);
-
- if(hash('sha512', $expected.$randomString) === hash('sha512', $input.$randomString)) {
- if($expected === $input) {
- return true;
- }
- }
-
- return false;
- }
-} \ No newline at end of file
diff --git a/lib/private/security/trusteddomainhelper.php b/lib/private/security/trusteddomainhelper.php
index 6dbaadfdb60..885ceee23c3 100644
--- a/lib/private/security/trusteddomainhelper.php
+++ b/lib/private/security/trusteddomainhelper.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -74,16 +74,11 @@ class TrustedDomainHelper {
return false;
}
- // TODO: Workaround for older instances still with port applied. Remove for ownCloud 9.
- if(in_array($domainWithPort, $trustedList)) {
- return true;
- }
-
// Always allow access from localhost
if (preg_match(Request::REGEX_LOCALHOST, $domain) === 1) {
return true;
}
- return in_array($domain, $trustedList);
+ return in_array($domain, $trustedList, true);
}
}
diff --git a/lib/private/server.php b/lib/private/server.php
index ea5937dfea4..55ac64a0c2d 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -12,14 +12,14 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Sander <brantje@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -47,23 +47,35 @@ use OC\Diagnostics\EventLogger;
use OC\Diagnostics\NullEventLogger;
use OC\Diagnostics\NullQueryLogger;
use OC\Diagnostics\QueryLogger;
+use OC\Files\Config\UserMountCache;
+use OC\Files\Config\UserMountCacheListener;
use OC\Files\Node\HookConnector;
use OC\Files\Node\Root;
use OC\Files\View;
use OC\Http\Client\ClientService;
+use OC\IntegrityCheck\Checker;
+use OC\IntegrityCheck\Helpers\AppLocator;
+use OC\IntegrityCheck\Helpers\EnvironmentHelper;
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
use OC\Lock\DBLockingProvider;
use OC\Lock\MemcacheLockingProvider;
use OC\Lock\NoopLockingProvider;
use OC\Mail\Mailer;
use OC\Notification\Manager;
use OC\Security\CertificateManager;
+use OC\Security\CSP\ContentSecurityPolicyManager;
use OC\Security\Crypto;
+use OC\Security\CSRF\CsrfTokenGenerator;
+use OC\Security\CSRF\CsrfTokenManager;
+use OC\Security\CSRF\TokenStorage\SessionStorage;
use OC\Security\Hasher;
+use OC\Security\CredentialsManager;
use OC\Security\SecureRandom;
use OC\Security\TrustedDomainHelper;
use OC\Session\CryptoWrapper;
use OC\Tagging\TagMapper;
use OCP\IServerContainer;
+use OCP\Security\IContentSecurityPolicyManager;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -74,14 +86,15 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
*
* TODO: hookup all manager classes
*/
-class Server extends SimpleContainer implements IServerContainer {
+class Server extends ServerContainer implements IServerContainer {
/** @var string */
private $webRoot;
/**
* @param string $webRoot
+ * @param \OC\Config $config
*/
- public function __construct($webRoot) {
+ public function __construct($webRoot, \OC\Config $config) {
parent::__construct();
$this->webRoot = $webRoot;
@@ -131,13 +144,26 @@ class Server extends SimpleContainer implements IServerContainer {
return new Encryption\Keys\Storage($view, $util);
});
- $this->registerService('TagMapper', function(Server $c) {
+ $this->registerService('TagMapper', function (Server $c) {
return new TagMapper($c->getDatabaseConnection());
});
$this->registerService('TagManager', function (Server $c) {
$tagMapper = $c->query('TagMapper');
return new TagManager($tagMapper, $c->getUserSession());
});
+ $this->registerService('SystemTagManagerFactory', function (Server $c) {
+ $config = $c->getConfig();
+ $factoryClass = $config->getSystemValue('systemtags.managerFactory', '\OC\SystemTag\ManagerFactory');
+ /** @var \OC\SystemTag\ManagerFactory $factory */
+ $factory = new $factoryClass($this);
+ return $factory;
+ });
+ $this->registerService('SystemTagManager', function (Server $c) {
+ return $c->query('SystemTagManagerFactory')->getManager();
+ });
+ $this->registerService('SystemTagObjectMapper', function (Server $c) {
+ return $c->query('SystemTagManagerFactory')->getObjectMapper();
+ });
$this->registerService('RootFolder', function (Server $c) {
// TODO: get user and user manager from container as well
$user = \OC_User::getUser();
@@ -218,6 +244,10 @@ class Server extends SimpleContainer implements IServerContainer {
$userSession->listen('\OC\User', 'logout', function () {
\OC_Hook::emit('OC_User', 'logout', array());
});
+ $userSession->listen('\OC\User', 'changeUser', function ($user) {
+ /** @var $user \OC\User\User */
+ \OC_Hook::emit('OC_User', 'changeUser', array('run' => true, 'user' => $user));
+ });
return $userSession;
});
$this->registerService('NavigationManager', function ($c) {
@@ -228,14 +258,18 @@ class Server extends SimpleContainer implements IServerContainer {
$c->getSystemConfig()
);
});
- $this->registerService('SystemConfig', function ($c) {
- return new \OC\SystemConfig();
+ $this->registerService('SystemConfig', function ($c) use ($config) {
+ return new \OC\SystemConfig($config);
});
- $this->registerService('AppConfig', function ($c) {
- return new \OC\AppConfig(\OC_DB::getConnection());
+ $this->registerService('AppConfig', function (Server $c) {
+ return new \OC\AppConfig($c->getDatabaseConnection());
});
- $this->registerService('L10NFactory', function ($c) {
- return new \OC\L10N\Factory();
+ $this->registerService('L10NFactory', function (Server $c) {
+ return new \OC\L10N\Factory(
+ $c->getConfig(),
+ $c->getRequest(),
+ $c->getUserSession()
+ );
});
$this->registerService('URLGenerator', function (Server $c) {
$config = $c->getConfig();
@@ -254,13 +288,13 @@ class Server extends SimpleContainer implements IServerContainer {
$this->registerService('MemCacheFactory', function (Server $c) {
$config = $c->getConfig();
- if($config->getSystemValue('installed', false) && !(defined('PHPUNIT_RUN') && PHPUNIT_RUN)) {
+ if ($config->getSystemValue('installed', false) && !(defined('PHPUNIT_RUN') && PHPUNIT_RUN)) {
$v = \OC_App::getAppVersions();
$v['core'] = md5(file_get_contents(\OC::$SERVERROOT . '/version.php'));
$version = implode(',', $v);
$instanceId = \OC_Util::getInstanceId();
$path = \OC::$SERVERROOT;
- $prefix = md5($instanceId.'-'.$version.'-'.$path);
+ $prefix = md5($instanceId . '-' . $version . '-' . $path);
return new \OC\Memcache\Factory($prefix, $c->getLogger(),
$config->getSystemValue('memcache.local', null),
$config->getSystemValue('memcache.distributed', null),
@@ -281,8 +315,12 @@ class Server extends SimpleContainer implements IServerContainer {
$c->getConfig()
);
});
- $this->registerService('AvatarManager', function ($c) {
- return new AvatarManager();
+ $this->registerService('AvatarManager', function (Server $c) {
+ return new AvatarManager(
+ $c->getUserManager(),
+ $c->getRootFolder(),
+ $c->getL10N('lib')
+ );
});
$this->registerService('Logger', function (Server $c) {
$logClass = $c->query('AllConfig')->getSystemValue('log_type', 'owncloud');
@@ -297,10 +335,11 @@ class Server extends SimpleContainer implements IServerContainer {
});
$this->registerService('Router', function (Server $c) {
$cacheFactory = $c->getMemCacheFactory();
+ $logger = $c->getLogger();
if ($cacheFactory->isAvailable()) {
- $router = new \OC\Route\CachingRouter($cacheFactory->create('route'));
+ $router = new \OC\Route\CachingRouter($cacheFactory->create('route'), $logger);
} else {
- $router = new \OC\Route\Router();
+ $router = new \OC\Route\Router($logger);
}
return $router;
});
@@ -316,6 +355,9 @@ class Server extends SimpleContainer implements IServerContainer {
$this->registerService('Hasher', function (Server $c) {
return new Hasher($c->getConfig());
});
+ $this->registerService('CredentialsManager', function (Server $c) {
+ return new CredentialsManager($c->getCrypto(), $c->getDatabaseConnection());
+ });
$this->registerService('DatabaseConnection', function (Server $c) {
$factory = new \OC\DB\ConnectionFactory();
$systemConfig = $c->getSystemConfig();
@@ -366,7 +408,7 @@ class Server extends SimpleContainer implements IServerContainer {
$c->getConfig()
);
});
- $this->registerService('AppManager', function(Server $c) {
+ $this->registerService('AppManager', function (Server $c) {
return new \OC\App\AppManager(
$c->getUserSession(),
$c->getAppConfig(),
@@ -374,13 +416,13 @@ class Server extends SimpleContainer implements IServerContainer {
$c->getMemCacheFactory()
);
});
- $this->registerService('DateTimeZone', function(Server $c) {
+ $this->registerService('DateTimeZone', function (Server $c) {
return new DateTimeZone(
$c->getConfig(),
$c->getSession()
);
});
- $this->registerService('DateTimeFormatter', function(Server $c) {
+ $this->registerService('DateTimeFormatter', function (Server $c) {
$language = $c->getConfig()->getUserValue($c->getSession()->get('user_id'), 'core', 'lang', null);
return new DateTimeFormatter(
@@ -388,9 +430,16 @@ class Server extends SimpleContainer implements IServerContainer {
$c->getL10N('lib', $language)
);
});
- $this->registerService('MountConfigManager', function () {
+ $this->registerService('UserMountCache', function (Server $c) {
+ $mountCache = new UserMountCache($c->getDatabaseConnection(), $c->getUserManager(), $c->getLogger());
+ $listener = new UserMountCacheListener($mountCache);
+ $listener->listen($c->getUserManager());
+ return $mountCache;
+ });
+ $this->registerService('MountConfigManager', function (Server $c) {
$loader = \OC\Files\Filesystem::getLoader();
- return new \OC\Files\Config\MountProviderCollection($loader);
+ $mountCache = $c->query('UserMountCache');
+ return new \OC\Files\Config\MountProviderCollection($loader, $mountCache);
});
$this->registerService('IniWrapper', function ($c) {
return new IniGetWrapper();
@@ -402,6 +451,26 @@ class Server extends SimpleContainer implements IServerContainer {
$this->registerService('TrustedDomainHelper', function ($c) {
return new TrustedDomainHelper($this->getConfig());
});
+ $this->registerService('IntegrityCodeChecker', function (Server $c) {
+ // IConfig and IAppManager requires a working database. This code
+ // might however be called when ownCloud is not yet setup.
+ if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
+ $config = $c->getConfig();
+ $appManager = $c->getAppManager();
+ } else {
+ $config = null;
+ $appManager = null;
+ }
+
+ return new Checker(
+ new EnvironmentHelper(),
+ new FileAccessHelper(),
+ new AppLocator(),
+ $config,
+ $c->getMemCacheFactory(),
+ $appManager
+ );
+ });
$this->registerService('Request', function ($c) {
if (isset($this['urlParams'])) {
$urlParams = $this['urlParams'];
@@ -409,12 +478,6 @@ class Server extends SimpleContainer implements IServerContainer {
$urlParams = [];
}
- if ($this->getSession()->exists('requesttoken')) {
- $requestToken = $this->getSession()->get('requesttoken');
- } else {
- $requestToken = false;
- }
-
if (defined('PHPUNIT_RUN') && PHPUNIT_RUN
&& in_array('fakeinput', stream_get_wrappers())
) {
@@ -435,21 +498,21 @@ class Server extends SimpleContainer implements IServerContainer {
? $_SERVER['REQUEST_METHOD']
: null,
'urlParams' => $urlParams,
- 'requesttoken' => $requestToken,
],
$this->getSecureRandom(),
$this->getConfig(),
+ $this->getCsrfTokenManager(),
$stream
);
});
- $this->registerService('Mailer', function(Server $c) {
+ $this->registerService('Mailer', function (Server $c) {
return new Mailer(
$c->getConfig(),
$c->getLogger(),
new \OC_Defaults()
);
});
- $this->registerService('OcsClient', function(Server $c) {
+ $this->registerService('OcsClient', function (Server $c) {
return new OCSClient(
$this->getHTTPClientService(),
$this->getConfig(),
@@ -471,29 +534,36 @@ class Server extends SimpleContainer implements IServerContainer {
$this->registerService('MountManager', function () {
return new \OC\Files\Mount\Manager();
});
- $this->registerService('MimeTypeDetector', function(Server $c) {
+ $this->registerService('MimeTypeDetector', function (Server $c) {
return new \OC\Files\Type\Detection(
$c->getURLGenerator(),
\OC::$SERVERROOT . '/config/',
\OC::$SERVERROOT . '/resources/config/'
- );
+ );
});
- $this->registerService('MimeTypeLoader', function(Server $c) {
+ $this->registerService('MimeTypeLoader', function (Server $c) {
return new \OC\Files\Type\Loader(
$c->getDatabaseConnection()
);
});
- $this->registerService('NotificationManager', function() {
+ $this->registerService('NotificationManager', function () {
return new Manager();
});
$this->registerService('CapabilitiesManager', function (Server $c) {
$manager = new \OC\CapabilitiesManager();
- $manager->registerCapability(function() use ($c) {
+ $manager->registerCapability(function () use ($c) {
return new \OC\OCS\CoreCapabilities($c->getConfig());
});
return $manager;
});
- $this->registerService('EventDispatcher', function() {
+ $this->registerService('CommentsManager', function(Server $c) {
+ $config = $c->getConfig();
+ $factoryClass = $config->getSystemValue('comments.managerFactory', '\OC\Comments\ManagerFactory');
+ /** @var \OCP\Comments\ICommentsManagerFactory $factory */
+ $factory = new $factoryClass($this);
+ return $factory->getManager();
+ });
+ $this->registerService('EventDispatcher', function () {
return new EventDispatcher();
});
$this->registerService('CryptoWrapper', function (Server $c) {
@@ -510,7 +580,7 @@ class Server extends SimpleContainer implements IServerContainer {
? $_SERVER['REQUEST_METHOD']
: null,
],
- new SecureRandom(),
+ $c->getSecureRandom(),
$c->getConfig()
);
@@ -521,6 +591,39 @@ class Server extends SimpleContainer implements IServerContainer {
$request
);
});
+ $this->registerService('CsrfTokenManager', function (Server $c) {
+ $tokenGenerator = new CsrfTokenGenerator($c->getSecureRandom());
+ $sessionStorage = new SessionStorage($c->getSession());
+
+ return new CsrfTokenManager(
+ $tokenGenerator,
+ $sessionStorage
+ );
+ });
+ $this->registerService('ContentSecurityPolicyManager', function (Server $c) {
+ return new ContentSecurityPolicyManager();
+ });
+ $this->registerService('ShareManager', function(Server $c) {
+ $config = $c->getConfig();
+ $factoryClass = $config->getSystemValue('sharing.managerFactory', '\OC\Share20\ProviderFactory');
+ /** @var \OC\Share20\IProviderFactory $factory */
+ $factory = new $factoryClass($this);
+
+ $manager = new \OC\Share20\Manager(
+ $c->getLogger(),
+ $c->getConfig(),
+ $c->getSecureRandom(),
+ $c->getHasher(),
+ $c->getMountManager(),
+ $c->getGroupManager(),
+ $c->getL10N('core'),
+ $factory,
+ $c->getUserManager(),
+ $c->getRootFolder()
+ );
+
+ return $manager;
+ });
}
/**
@@ -582,6 +685,29 @@ class Server extends SimpleContainer implements IServerContainer {
}
/**
+ * Returns the system-tag manager
+ *
+ * @return \OCP\SystemTag\ISystemTagManager
+ *
+ * @since 9.0.0
+ */
+ public function getSystemTagManager() {
+ return $this->query('SystemTagManager');
+ }
+
+ /**
+ * Returns the system-tag object mapper
+ *
+ * @return \OCP\SystemTag\ISystemTagObjectMapper
+ *
+ * @since 9.0.0
+ */
+ public function getSystemTagObjectMapper() {
+ return $this->query('SystemTagObjectMapper');
+ }
+
+
+ /**
* Returns the avatar manager, used for avatar functionality
*
* @return \OCP\IAvatarManager
@@ -625,7 +751,6 @@ class Server extends SimpleContainer implements IServerContainer {
public function getAppFolder() {
$dir = '/' . \OC_App::getCurrentApp();
$root = $this->getRootFolder();
- $folder = null;
if (!$root->nodeExists($dir)) {
$folder = $root->newFolder($dir);
} else {
@@ -835,7 +960,17 @@ class Server extends SimpleContainer implements IServerContainer {
}
/**
+ * Returns a CredentialsManager instance
+ *
+ * @return \OCP\Security\ICredentialsManager
+ */
+ public function getCredentialsManager() {
+ return $this->query('CredentialsManager');
+ }
+
+ /**
* Returns an instance of the db facade
+ *
* @deprecated use getDatabaseConnection, will be removed in ownCloud 10
* @return \OCP\IDb
*/
@@ -845,6 +980,7 @@ class Server extends SimpleContainer implements IServerContainer {
/**
* Returns an instance of the HTTP helper class
+ *
* @deprecated Use getHTTPClientService()
* @return \OC\HTTPHelper
*/
@@ -855,11 +991,11 @@ class Server extends SimpleContainer implements IServerContainer {
/**
* Get the certificate manager for the user
*
- * @param string $userId (optional) if not specified the current loggedin user is used
+ * @param string $userId (optional) if not specified the current loggedin user is used, use null to get the system certificate manager
* @return \OCP\ICertificateManager | null if $uid is null and no user is logged in
*/
- public function getCertificateManager($userId = null) {
- if (is_null($userId)) {
+ public function getCertificateManager($userId = '') {
+ if ($userId === '') {
$userSession = $this->getUserSession();
$user = $userSession->getUser();
if (is_null($user)) {
@@ -970,7 +1106,7 @@ class Server extends SimpleContainer implements IServerContainer {
/**
* @return \OCP\Files\Config\IMountProviderCollection
*/
- public function getMountProviderCollection(){
+ public function getMountProviderCollection() {
return $this->query('MountConfigManager');
}
@@ -986,7 +1122,7 @@ class Server extends SimpleContainer implements IServerContainer {
/**
* @return \OCP\Command\IBus
*/
- public function getCommandBus(){
+ public function getCommandBus() {
return $this->query('AsyncCommandBus');
}
@@ -1056,7 +1192,7 @@ class Server extends SimpleContainer implements IServerContainer {
/**
* Get the Notification Manager
*
- * @return \OC\Notification\IManager
+ * @return \OCP\Notification\IManager
* @since 8.2.0
*/
public function getNotificationManager() {
@@ -1064,6 +1200,20 @@ class Server extends SimpleContainer implements IServerContainer {
}
/**
+ * @return \OCP\Comments\ICommentsManager
+ */
+ public function getCommentsManager() {
+ return $this->query('CommentsManager');
+ }
+
+ /**
+ * @return \OC\IntegrityCheck\Checker
+ */
+ public function getIntegrityCodeChecker() {
+ return $this->query('IntegrityCodeChecker');
+ }
+
+ /**
* @return \OC\Session\CryptoWrapper
*/
public function getSessionCryptoWrapper() {
@@ -1071,7 +1221,22 @@ class Server extends SimpleContainer implements IServerContainer {
}
/**
+ * @return CsrfTokenManager
+ */
+ public function getCsrfTokenManager() {
+ return $this->query('CsrfTokenManager');
+ }
+
+ /**
+ * @return IContentSecurityPolicyManager
+ */
+ public function getContentSecurityPolicyManager() {
+ return $this->query('ContentSecurityPolicyManager');
+ }
+
+ /**
* Not a public API as of 8.2, wait for 9.0
+ *
* @return \OCA\Files_External\Service\BackendService
*/
public function getStoragesBackendService() {
@@ -1080,6 +1245,7 @@ class Server extends SimpleContainer implements IServerContainer {
/**
* Not a public API as of 8.2, wait for 9.0
+ *
* @return \OCA\Files_External\Service\GlobalStoragesService
*/
public function getGlobalStoragesService() {
@@ -1088,6 +1254,7 @@ class Server extends SimpleContainer implements IServerContainer {
/**
* Not a public API as of 8.2, wait for 9.0
+ *
* @return \OCA\Files_External\Service\UserGlobalStoragesService
*/
public function getUserGlobalStoragesService() {
@@ -1096,10 +1263,18 @@ class Server extends SimpleContainer implements IServerContainer {
/**
* Not a public API as of 8.2, wait for 9.0
+ *
* @return \OCA\Files_External\Service\UserStoragesService
*/
public function getUserStoragesService() {
return \OC_Mount_Config::$app->getContainer()->query('OCA\\Files_External\\Service\\UserStoragesService');
}
-
+
+ /**
+ * @return \OCP\Share\IManager
+ */
+ public function getShareManager() {
+ return $this->query('ShareManager');
+ }
+
}
diff --git a/lib/private/servercontainer.php b/lib/private/servercontainer.php
new file mode 100644
index 00000000000..d297c9fd39c
--- /dev/null
+++ b/lib/private/servercontainer.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC;
+
+
+use OC\AppFramework\DependencyInjection\DIContainer;
+use OC\AppFramework\Utility\SimpleContainer;
+use OCP\AppFramework\QueryException;
+
+/**
+ * Class ServerContainer
+ *
+ * @package OC
+ */
+class ServerContainer extends SimpleContainer {
+ /** @var DIContainer[] */
+ protected $appContainers;
+
+ /**
+ * ServerContainer constructor.
+ */
+ public function __construct() {
+ parent::__construct();
+ $this->appContainers = [];
+ }
+
+ /**
+ * @param string $appName
+ * @param DIContainer $container
+ */
+ public function registerAppContainer($appName, DIContainer $container) {
+ $this->appContainers[$appName] = $container;
+ }
+
+ /**
+ * @param string $appName
+ * @return DIContainer
+ */
+ public function getAppContainer($appName) {
+ if (isset($this->appContainers[$appName])) {
+ return $this->appContainers[$appName];
+ }
+
+ return new DIContainer($appName);
+ }
+
+ /**
+ * @param string $name name of the service to query for
+ * @return mixed registered service for the given $name
+ * @throws QueryException if the query could not be resolved
+ */
+ public function query($name) {
+ $name = $this->sanitizeName($name);
+
+ // In case the service starts with OCA\ we try to find the service in
+ // the apps container first.
+ if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
+ $segments = explode('\\', $name);
+ $appContainer = $this->getAppContainer(strtolower($segments[1]));
+ try {
+ return $appContainer->query($name);
+ } catch (QueryException $e) {
+ // Didn't find the service in the respective app container,
+ // ignore it and fall back to the core container.
+ }
+ }
+
+ return parent::query($name);
+ }
+}
diff --git a/lib/private/servernotavailableexception.php b/lib/private/servernotavailableexception.php
index b273f50be98..f4b5f4f8cf3 100644
--- a/lib/private/servernotavailableexception.php
+++ b/lib/private/servernotavailableexception.php
@@ -2,7 +2,7 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/serviceunavailableexception.php b/lib/private/serviceunavailableexception.php
index 2c08f37897c..fb4920b3607 100644
--- a/lib/private/serviceunavailableexception.php
+++ b/lib/private/serviceunavailableexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/session/cryptosessiondata.php b/lib/private/session/cryptosessiondata.php
index dcae1648fe1..f6c585c1611 100644
--- a/lib/private/session/cryptosessiondata.php
+++ b/lib/private/session/cryptosessiondata.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -132,6 +132,16 @@ class CryptoSessionData implements \ArrayAccess, ISession {
}
/**
+ * Wrapper around session_regenerate_id
+ *
+ * @param bool $deleteOldSession Whether to delete the old associated session file or not.
+ * @return void
+ */
+ public function regenerateId($deleteOldSession = true) {
+ $this->session->regenerateId($deleteOldSession);
+ }
+
+ /**
* Close the session and release the lock, also writes all changed data in batch
*/
public function close() {
diff --git a/lib/private/session/cryptowrapper.php b/lib/private/session/cryptowrapper.php
index c79778587e0..f1819b31b89 100644
--- a/lib/private/session/cryptowrapper.php
+++ b/lib/private/session/cryptowrapper.php
@@ -3,8 +3,9 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Phil Davis <phil.davis@inf.org>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,7 +24,6 @@
namespace OC\Session;
-use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
use OCP\IRequest;
use OCP\ISession;
@@ -75,7 +75,7 @@ class CryptoWrapper {
if (!is_null($request->getCookie(self::COOKIE_NAME))) {
$this->passphrase = $request->getCookie(self::COOKIE_NAME);
} else {
- $this->passphrase = $this->random->getMediumStrengthGenerator()->generate(128);
+ $this->passphrase = $this->random->generate(128);
$secureCookie = $request->getServerProtocol() === 'https';
// FIXME: Required for CI
if (!defined('PHPUNIT_RUN')) {
diff --git a/lib/private/session/internal.php b/lib/private/session/internal.php
index 0b6152acf12..09175bf1f2f 100644
--- a/lib/private/session/internal.php
+++ b/lib/private/session/internal.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -89,10 +89,9 @@ class Internal extends Session {
}
}
-
public function clear() {
session_unset();
- @session_regenerate_id(true);
+ $this->regenerateId();
@session_start();
$_SESSION = array();
}
@@ -102,14 +101,35 @@ class Internal extends Session {
parent::close();
}
- public function reopen() {
- throw new \Exception('The session cannot be reopened - reopen() is ony to be used in unit testing.');
- }
+ /**
+ * Wrapper around session_regenerate_id
+ *
+ * @param bool $deleteOldSession Whether to delete the old associated session file or not.
+ * @return void
+ */
+ public function regenerateId($deleteOldSession = true) {
+ @session_regenerate_id($deleteOldSession);
+ }
+
+ /**
+ * @throws \Exception
+ */
+ public function reopen() {
+ throw new \Exception('The session cannot be reopened - reopen() is ony to be used in unit testing.');
+ }
+ /**
+ * @param int $errorNumber
+ * @param string $errorString
+ * @throws \ErrorException
+ */
public function trapError($errorNumber, $errorString) {
throw new \ErrorException($errorString);
}
+ /**
+ * @throws \Exception
+ */
private function validateSession() {
if ($this->sessionClosed) {
throw new \Exception('Session has been closed - no further changes to the session are allowed');
diff --git a/lib/private/session/memory.php b/lib/private/session/memory.php
index ff95efc5345..777458a9aa5 100644
--- a/lib/private/session/memory.php
+++ b/lib/private/session/memory.php
@@ -1,12 +1,13 @@
<?php
/**
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Phil Davis <phil.davis@inf.org>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -81,6 +82,13 @@ class Memory extends Session {
}
/**
+ * Stub since the session ID does not need to get regenerated for the cache
+ *
+ * @param bool $deleteOldSession
+ */
+ public function regenerateId($deleteOldSession = true) {}
+
+ /**
* Helper function for PHPUnit execution - don't use in non-test code
*/
public function reopen() {
diff --git a/lib/private/session/session.php b/lib/private/session/session.php
index f9a1b5afa0f..198d0049956 100644
--- a/lib/private/session/session.php
+++ b/lib/private/session/session.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/setup.php b/lib/private/setup.php
index 8f1ae389e45..b9f8828227e 100644
--- a/lib/private/setup.php
+++ b/lib/private/setup.php
@@ -10,13 +10,15 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Martin Mattel <martin.mattel@diemattels.at>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Sean Comeau <sean@ftlnetworks.ca>
* @author Serge Martin <edb@sigluy.net>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -192,7 +194,9 @@ class Setup {
// Create data directory to test whether the .htaccess works
// Notice that this is not necessarily the same data directory as the one
// that will effectively be used.
- @mkdir($dataDir);
+ if(!file_exists($dataDir)) {
+ @mkdir($dataDir);
+ }
$htAccessWorking = true;
if (is_dir($dataDir) && is_writable($dataDir)) {
// Protect data directory here, so we can test if the protection is working
@@ -310,9 +314,9 @@ class Setup {
}
//generate a random salt that is used to salt the local user passwords
- $salt = $this->random->getLowStrengthGenerator()->generate(30);
+ $salt = $this->random->generate(30);
// generate a secret
- $secret = $this->random->getMediumStrengthGenerator()->generate(48);
+ $secret = $this->random->generate(48);
//write the config file
$this->config->setSystemValues([
@@ -322,7 +326,7 @@ class Setup {
'datadirectory' => $dataDir,
'overwrite.cli.url' => $request->getServerProtocol() . '://' . $request->getInsecureServerHost() . \OC::$WEBROOT,
'dbtype' => $dbType,
- 'version' => implode('.', \OC_Util::getVersion()),
+ 'version' => implode('.', \OCP\Util::getVersion()),
]);
try {
@@ -369,11 +373,9 @@ class Setup {
// out that this is indeed an ownCloud data directory
file_put_contents($config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', '');
- // Update htaccess files for apache hosts
- if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
- self::updateHtaccess();
- self::protectDataDirectory();
- }
+ // Update .htaccess files
+ Setup::updateHtaccess();
+ Setup::protectDataDirectory();
//try to write logtimezone
if (date_default_timezone_get()) {
@@ -395,35 +397,20 @@ class Setup {
}
/**
- * Checks if the .htaccess contains the current version parameter
- *
- * @return bool
- */
- private function isCurrentHtaccess() {
- $version = \OC_Util::getVersion();
- unset($version[3]);
-
- return !strpos(
- file_get_contents($this->pathToHtaccess()),
- 'Version: '.implode('.', $version)
- ) === false;
- }
-
- /**
* Append the correct ErrorDocument path for Apache hosts
- *
- * @throws \OC\HintException If .htaccess does not include the current version
*/
public static function updateHtaccess() {
+ // From CLI we don't know the defined web root. Thus we can't write any
+ // directives into the .htaccess file.
+ if(\OC::$CLI) {
+ return;
+ }
$setupHelper = new \OC\Setup(\OC::$server->getConfig(), \OC::$server->getIniWrapper(),
\OC::$server->getL10N('lib'), new \OC_Defaults(), \OC::$server->getLogger(),
\OC::$server->getSecureRandom());
- if(!$setupHelper->isCurrentHtaccess()) {
- throw new \OC\HintException('.htaccess file has the wrong version. Please upload the correct version. Maybe you forgot to replace it after updating?');
- }
$htaccessContent = file_get_contents($setupHelper->pathToHtaccess());
- $content = '';
+ $content = "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####\n";
if (strpos($htaccessContent, 'ErrorDocument 403') === false) {
//custom 403 error page
$content.= "\nErrorDocument 403 ".\OC::$WEBROOT."/core/templates/403.php";
@@ -432,6 +419,19 @@ class Setup {
//custom 404 error page
$content.= "\nErrorDocument 404 ".\OC::$WEBROOT."/core/templates/404.php";
}
+
+ // Add rewrite base
+ $webRoot = !empty(\OC::$WEBROOT) ? \OC::$WEBROOT : '/';
+ $content.="\n<IfModule mod_rewrite.c>";
+ $content.="\n RewriteBase ".$webRoot;
+ $content .= "\n <IfModule mod_env.c>";
+ $content .= "\n SetEnv front_controller_active true";
+ $content .= "\n <IfModule mod_dir.c>";
+ $content .= "\n DirectorySlash off";
+ $content .= "\n </IfModule>";
+ $content.="\n </IfModule>";
+ $content.="\n</IfModule>";
+
if ($content !== '') {
//suppress errors in case we don't have permissions for it
@file_put_contents($setupHelper->pathToHtaccess(), $content . "\n", FILE_APPEND);
@@ -453,7 +453,9 @@ class Setup {
$content.= "</ifModule>\n\n";
$content.= "# section for Apache 2.2 and 2.4\n";
$content.= "IndexIgnore *\n";
- file_put_contents(\OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data').'/.htaccess', $content);
- file_put_contents(\OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data').'/index.html', '');
+
+ $baseDir = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data');
+ file_put_contents($baseDir . '/.htaccess', $content);
+ file_put_contents($baseDir . '/index.html', '');
}
}
diff --git a/lib/private/setup/abstractdatabase.php b/lib/private/setup/abstractdatabase.php
index 1ec853c3b02..c97302ab252 100644
--- a/lib/private/setup/abstractdatabase.php
+++ b/lib/private/setup/abstractdatabase.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/setup/mysql.php b/lib/private/setup/mysql.php
index f2d2b15cd90..e6afad6033a 100644
--- a/lib/private/setup/mysql.php
+++ b/lib/private/setup/mysql.php
@@ -3,9 +3,10 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Michael Göhler <somebody.here@gmx.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -89,15 +90,28 @@ class MySQL extends AbstractDatabase {
* @throws \OC\DatabaseSetupException
*/
private function connect() {
- $type = 'mysql';
+
$connectionParams = array(
- 'host' => $this->dbHost,
- 'user' => $this->dbUser,
- 'password' => $this->dbPassword,
- 'tablePrefix' => $this->tablePrefix,
+ 'host' => $this->dbHost,
+ 'user' => $this->dbUser,
+ 'password' => $this->dbPassword,
+ 'tablePrefix' => $this->tablePrefix,
);
+
+ // adding port support
+ if (strpos($this->dbHost, ':')) {
+ // Host variable may carry a port or socket.
+ list($host, $portOrSocket) = explode(':', $this->dbHost, 2);
+ if (ctype_digit($portOrSocket)) {
+ $connectionParams['port'] = $portOrSocket;
+ } else {
+ $connectionParams['unix_socket'] = $portOrSocket;
+ }
+ $connectionParams['host'] = $host;
+ }
+
$cf = new ConnectionFactory();
- return $cf->getConnection($type, $connectionParams);
+ return $cf->getConnection('mysql', $connectionParams);
}
/**
@@ -130,7 +144,7 @@ class MySQL extends AbstractDatabase {
$this->dbUser = $adminUser;
//create a random password so we don't need to store the admin password in the config file
- $this->dbPassword = $this->random->getMediumStrengthGenerator()->generate(30);
+ $this->dbPassword = $this->random->generate(30);
$this->createDBUser($connection);
diff --git a/lib/private/setup/oci.php b/lib/private/setup/oci.php
index e5634572d90..3d5aca96c1f 100644
--- a/lib/private/setup/oci.php
+++ b/lib/private/setup/oci.php
@@ -5,10 +5,11 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -106,7 +107,7 @@ class OCI extends AbstractDatabase {
//add prefix to the oracle user name to prevent collisions
$this->dbUser='oc_'.$username;
//create a new password so we don't need to store the admin config in the config file
- $this->dbPassword=\OC_Util::generateRandomBytes(30);
+ $this->dbPassword = \OC::$server->getSecureRandom()->generate(30, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
//oracle passwords are treated as identifiers:
// must start with alphanumeric char
diff --git a/lib/private/setup/postgresql.php b/lib/private/setup/postgresql.php
index 0a559e7a589..4c17de4b84d 100644
--- a/lib/private/setup/postgresql.php
+++ b/lib/private/setup/postgresql.php
@@ -3,9 +3,11 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author eduardo <eduardo@vnexu.net>
* @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -61,12 +63,13 @@ class PostgreSQL extends AbstractDatabase {
//add prefix to the postgresql user name to prevent collisions
$this->dbUser='oc_'.$username;
//create a new password so we don't need to store the admin config in the config file
- $this->dbPassword=\OC_Util::generateRandomBytes(30);
+ $this->dbPassword = \OC::$server->getSecureRandom()->generate(30, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
$this->createDBUser($connection);
}
- \OC_Config::setValues([
+ $systemConfig = \OC::$server->getSystemConfig();
+ $systemConfig->setValues([
'dbuser' => $this->dbUser,
'dbpassword' => $this->dbPassword,
]);
@@ -78,8 +81,8 @@ class PostgreSQL extends AbstractDatabase {
pg_close($connection);
// connect to the ownCloud database (dbname=$this->dbname) and check if it needs to be filled
- $this->dbUser = \OC_Config::getValue('dbuser');
- $this->dbPassword = \OC_Config::getValue('dbpassword');
+ $this->dbUser = $systemConfig->getValue('dbuser');
+ $this->dbPassword = $systemConfig->getValue('dbpassword');
$e_host = addslashes($this->dbHost);
$e_dbname = addslashes($this->dbName);
diff --git a/lib/private/setup/sqlite.php b/lib/private/setup/sqlite.php
index 820a89d4cff..61bc501fd75 100644
--- a/lib/private/setup/sqlite.php
+++ b/lib/private/setup/sqlite.php
@@ -1,8 +1,9 @@
<?php
/**
* @author Bart Visscher <bartv@thisnet.nl>
+ * @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,7 +32,7 @@ class Sqlite extends AbstractDatabase {
}
public function setupDatabase($username) {
- $datadir = \OC_Config::getValue('datadirectory');
+ $datadir = \OC::$server->getSystemConfig()->getValue('datadirectory');
//delete the old sqlite database first, might cause infinte loops otherwise
if(file_exists("$datadir/owncloud.db")) {
diff --git a/lib/private/share/constants.php b/lib/private/share/constants.php
index 695d0c6714c..e2b87d72476 100644
--- a/lib/private/share/constants.php
+++ b/lib/private/share/constants.php
@@ -4,7 +4,7 @@
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/share/helper.php b/lib/private/share/helper.php
index 26bbca81317..1645e4451ab 100644
--- a/lib/private/share/helper.php
+++ b/lib/private/share/helper.php
@@ -5,11 +5,11 @@
* @author Miguel Prokop <miguel.prokop@vtu.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -289,4 +289,38 @@ class Helper extends \OC\Share\Constants {
$hint = $l->t('Invalid Federated Cloud ID');
throw new HintException('Invalid Fededrated Cloud ID', $hint);
}
+
+ /**
+ * check if two federated cloud IDs refer to the same user
+ *
+ * @param string $user1
+ * @param string $server1
+ * @param string $user2
+ * @param string $server2
+ * @return bool true if both users and servers are the same
+ */
+ public static function isSameUserOnSameServer($user1, $server1, $user2, $server2) {
+ $normalizedServer1 = strtolower(\OC\Share\Share::removeProtocolFromUrl($server1));
+ $normalizedServer2 = strtolower(\OC\Share\Share::removeProtocolFromUrl($server2));
+
+ if (rtrim($normalizedServer1, '/') === rtrim($normalizedServer2, '/')) {
+ // FIXME this should be a method in the user management instead
+ \OCP\Util::emitHook(
+ '\OCA\Files_Sharing\API\Server2Server',
+ 'preLoginNameUsedAsUserName',
+ array('uid' => &$user1)
+ );
+ \OCP\Util::emitHook(
+ '\OCA\Files_Sharing\API\Server2Server',
+ 'preLoginNameUsedAsUserName',
+ array('uid' => &$user2)
+ );
+
+ if ($user1 === $user2) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/lib/private/share/hooks.php b/lib/private/share/hooks.php
index 98143124e82..c939164e39e 100644
--- a/lib/private/share/hooks.php
+++ b/lib/private/share/hooks.php
@@ -2,9 +2,9 @@
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -38,7 +38,7 @@ class Hooks extends \OC\Share\Constants {
public static function post_deleteUser($arguments) {
// Delete any items shared with the deleted user
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`'
- .' WHERE `share_with` = ? AND `share_type` = ? OR `share_type` = ?');
+ .' WHERE `share_with` = ? AND (`share_type` = ? OR `share_type` = ?)');
$query->execute(array($arguments['uid'], self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
// Delete any items the deleted user shared
$query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `uid_owner` = ?');
diff --git a/lib/private/share/mailnotifications.php b/lib/private/share/mailnotifications.php
index 2797e5ed99b..5d24b30cbe2 100644
--- a/lib/private/share/mailnotifications.php
+++ b/lib/private/share/mailnotifications.php
@@ -4,11 +4,13 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author scolebrook <scolebrook@mac.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -28,11 +30,12 @@
namespace OC\Share;
use DateTime;
-use OCP\IConfig;
use OCP\IL10N;
+use OCP\IUser;
use OCP\Mail\IMailer;
use OCP\ILogger;
use OCP\Defaults;
+use OCP\Util;
/**
* Class MailNotifications
@@ -41,16 +44,14 @@ use OCP\Defaults;
*/
class MailNotifications {
- /** @var string sender userId */
- private $userId;
+ /** @var IUser sender userId */
+ private $user;
/** @var string sender email address */
private $replyTo;
/** @var string */
private $senderDisplayName;
/** @var IL10N */
private $l;
- /** @var IConfig */
- private $config;
/** @var IMailer */
private $mailer;
/** @var Defaults */
@@ -59,34 +60,31 @@ class MailNotifications {
private $logger;
/**
- * @param string $uid user id
- * @param IConfig $config
+ * @param IUser $user
* @param IL10N $l10n
* @param IMailer $mailer
* @param ILogger $logger
* @param Defaults $defaults
*/
- public function __construct($uid,
- IConfig $config,
+ public function __construct(IUser $user,
IL10N $l10n,
IMailer $mailer,
ILogger $logger,
Defaults $defaults) {
$this->l = $l10n;
- $this->userId = $uid;
- $this->config = $config;
+ $this->user = $user;
$this->mailer = $mailer;
$this->logger = $logger;
$this->defaults = $defaults;
- $this->replyTo = $this->config->getUserValue($this->userId, 'settings', 'email', null);
- $this->senderDisplayName = \OCP\User::getDisplayName($this->userId);
+ $this->replyTo = $this->user->getEMailAddress();
+ $this->senderDisplayName = $this->user->getDisplayName();
}
/**
* inform users if a file was shared with them
*
- * @param array $recipientList list of recipients
+ * @param IUser[] $recipientList list of recipients
* @param string $itemSource shared item source
* @param string $itemType shared item type
* @return array list of user to whom the mail send operation failed
@@ -95,15 +93,15 @@ class MailNotifications {
$noMail = [];
foreach ($recipientList as $recipient) {
- $recipientDisplayName = \OCP\User::getDisplayName($recipient);
- $to = $this->config->getUserValue($recipient, 'settings', 'email', '');
+ $recipientDisplayName = $recipient->getDisplayName();
+ $to = $recipient->getEMailAddress();
if ($to === '') {
$noMail[] = $recipientDisplayName;
continue;
}
- $items = \OCP\Share::getItemSharedWithUser($itemType, $itemSource, $recipient);
+ $items = $this->getItemSharedWithUser($itemSource, $itemType, $recipient);
$filename = trim($items[0]['file_target'], '/');
$subject = (string) $this->l->t('%s shared »%s« with you', array($this->senderDisplayName, $filename));
$expiration = null;
@@ -134,7 +132,7 @@ class MailNotifications {
);
}
- $link = \OCP\Util::linkToAbsolute('files', 'index.php', $args);
+ $link = Util::linkToAbsolute('files', 'index.php', $args);
list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration, 'internal');
@@ -146,7 +144,7 @@ class MailNotifications {
$message->setHtmlBody($htmlBody);
$message->setPlainBody($textBody);
$message->setFrom([
- \OCP\Util::getDefaultEmailAddress('sharing-noreply') =>
+ Util::getDefaultEmailAddress('sharing-noreply') =>
(string)$this->l->t('%s via %s', [
$this->senderDisplayName,
$this->defaults->getName()
@@ -174,20 +172,22 @@ class MailNotifications {
* @param string $filename the shared file
* @param string $link the public link
* @param int $expiration expiration date (timestamp)
- * @return array $result of failed recipients
+ * @return string[] $result of failed recipients
*/
public function sendLinkShareMail($recipient, $filename, $link, $expiration) {
$subject = (string)$this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]);
list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration);
+ $recipient = str_replace([', ', '; ', ',', ';', ' '], ',', $recipient);
+ $recipients = explode(',', $recipient);
try {
$message = $this->mailer->createMessage();
$message->setSubject($subject);
- $message->setTo([$recipient]);
+ $message->setTo($recipients);
$message->setHtmlBody($htmlBody);
$message->setPlainBody($textBody);
$message->setFrom([
- \OCP\Util::getDefaultEmailAddress('sharing-noreply') =>
+ Util::getDefaultEmailAddress('sharing-noreply') =>
(string)$this->l->t('%s via %s', [
$this->senderDisplayName,
$this->defaults->getName()
@@ -210,7 +210,7 @@ class MailNotifications {
* @param string $filename the shared file
* @param string $link link to the shared file
* @param int $expiration expiration date (timestamp)
- * @param bool $prefix prefix of mail template files
+ * @param string $prefix prefix of mail template files
* @return array an array of the html mail body and the plain text mail body
*/
private function createMailBody($filename, $link, $expiration, $prefix = '') {
@@ -233,4 +233,14 @@ class MailNotifications {
return [$htmlMail, $plainTextMail];
}
+ /**
+ * @param string $itemSource
+ * @param string $itemType
+ * @param IUser $recipient
+ * @return array
+ */
+ protected function getItemSharedWithUser($itemSource, $itemType, $recipient) {
+ return Share::getItemSharedWithUser($itemType, $itemSource, $recipient->getUID());
+ }
+
}
diff --git a/lib/private/share/searchresultsorter.php b/lib/private/share/searchresultsorter.php
index bde2fd05073..c220699103a 100644
--- a/lib/private/share/searchresultsorter.php
+++ b/lib/private/share/searchresultsorter.php
@@ -2,10 +2,10 @@
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/share/share.php b/lib/private/share/share.php
index 4503818a9ec..96b920fe994 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -11,14 +11,14 @@
* @author Michael Kuhn <suraia@ikkoku.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Sebastian Döll <sebastian.doell@libasys.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
* @author Volkan Gezer <volkangezer@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -38,6 +38,7 @@
namespace OC\Share;
use OC\Files\Filesystem;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IUserSession;
use OCP\IDBConnection;
use OCP\IConfig;
@@ -426,7 +427,7 @@ class Share extends Constants {
if (!empty($groups)) {
$where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
$arguments = array($itemSource, $itemType, $groups);
- $types = array(null, null, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
+ $types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
if ($owner !== null) {
$where .= ' AND `uid_owner` = ?';
@@ -436,7 +437,7 @@ class Share extends Constants {
// TODO: inject connection, hopefully one day in the future when this
// class isn't static anymore...
- $conn = \OC_DB::getConnection();
+ $conn = \OC::$server->getDatabaseConnection();
$result = $conn->executeQuery(
'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
$arguments,
@@ -491,7 +492,7 @@ class Share extends Constants {
public static function getShareByToken($token, $checkPasswordProtection = true) {
$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
$result = $query->execute(array($token));
- if (\OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, \OCP\Util::ERROR);
}
$row = $result->fetchRow();
@@ -635,7 +636,7 @@ class Share extends Constants {
throw new \Exception($message_t);
}
// verify that the user has share permission
- if (!\OC\Files\Filesystem::isSharable($path)) {
+ if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
$message = 'You are not allowed to share %s';
$message_t = $l->t('You are not allowed to share %s', [$path]);
\OCP\Util::writeLog('OCP\Share', sprintf($message, $path), \OCP\Util::DEBUG);
@@ -745,10 +746,8 @@ class Share extends Constants {
// The check for each user in the group is done inside the put() function
if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
null, self::FORMAT_NONE, null, 1, true, true)) {
- // Only allow the same share to occur again if it is the same
- // owner and is not a group share, this use case is for increasing
- // permissions for a specific user
- if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
+
+ if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
$message = 'Sharing %s failed, because this item is already shared with %s';
$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
@@ -764,6 +763,11 @@ class Share extends Constants {
$updateExistingShare = false;
if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
+ // IF the password is changed via the old ajax endpoint verify it before deleting the old share
+ if ($passwordChanged === true) {
+ self::verifyPassword($shareWith);
+ }
+
// when updating a link share
// FIXME Don't delete link if we update it
if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
@@ -816,7 +820,7 @@ class Share extends Constants {
if (isset($oldToken)) {
$token = $oldToken;
} else {
- $token = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(self::TOKEN_LENGTH,
+ $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
\OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_UPPER.
\OCP\Security\ISecureRandom::CHAR_DIGITS
);
@@ -846,11 +850,20 @@ class Share extends Constants {
throw new \Exception($message_t);
}
+ // don't allow federated shares if source and target server are the same
+ list($user, $remote) = Helper::splitUserRemote($shareWith);
+ $currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
+ $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
+ if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
+ $message = 'Not allowed to create a federated share with the same user.';
+ $message_t = $l->t('Not allowed to create a federated share with the same user');
+ \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
+ throw new \Exception($message_t);
+ }
- $token = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
+ $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
\OCP\Security\ISecureRandom::CHAR_DIGITS);
- list($user, $remote) = Helper::splitUserRemote($shareWith);
$shareWith = $user . '@' . $remote;
$shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
@@ -1088,13 +1101,33 @@ class Share extends Constants {
*/
public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) {
$l = \OC::$server->getL10N('lib');
- if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith,
+ $connection = \OC::$server->getDatabaseConnection();
+
+ $intArrayToLiteralArray = function($intArray, $eb) {
+ return array_map(function($int) use ($eb) {
+ return $eb->literal((int)$int, 'integer');
+ }, $intArray);
+ };
+ $sanitizeItem = function($item) {
+ $item['id'] = (int)$item['id'];
+ $item['premissions'] = (int)$item['permissions'];
+ return $item;
+ };
+
+ if ($rootItem = self::getItems($itemType, $itemSource, $shareType, $shareWith,
\OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) {
// Check if this item is a reshare and verify that the permissions
// granted don't exceed the parent shared item
- if (isset($item['parent'])) {
- $query = \OC_DB::prepare('SELECT `permissions` FROM `*PREFIX*share` WHERE `id` = ?', 1);
- $result = $query->execute(array($item['parent']))->fetchRow();
+ if (isset($rootItem['parent'])) {
+ $qb = $connection->getQueryBuilder();
+ $qb->select('permissions')
+ ->from('share')
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter(':id', $rootItem['parent']);
+ $dbresult = $qb->execute();
+
+ $result = $dbresult->fetch();
+ $dbresult->closeCursor();
if (~(int)$result['permissions'] & $permissions) {
$message = 'Setting permissions for %s failed,'
.' because the permissions exceed permissions granted to %s';
@@ -1103,8 +1136,13 @@ class Share extends Constants {
throw new \Exception($message_t);
}
}
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
- $query->execute(array($permissions, $item['id']));
+ $qb = $connection->getQueryBuilder();
+ $qb->update('share')
+ ->set('permissions', $qb->createParameter('permissions'))
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter(':id', $rootItem['id'])
+ ->setParameter(':permissions', $permissions);
+ $qb->execute();
if ($itemType === 'file' || $itemType === 'folder') {
\OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
'itemType' => $itemType,
@@ -1113,56 +1151,104 @@ class Share extends Constants {
'shareWith' => $shareWith,
'uidOwner' => \OC_User::getUser(),
'permissions' => $permissions,
- 'path' => $item['path'],
- 'share' => $item
+ 'path' => $rootItem['path'],
+ 'share' => $rootItem
));
}
+
+ // Share id's to update with the new permissions
+ $ids = [];
+ $items = [];
+
// Check if permissions were removed
- if ($item['permissions'] & ~$permissions) {
+ if ((int)$rootItem['permissions'] & ~$permissions) {
// If share permission is removed all reshares must be deleted
- if (($item['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) {
+ if (($rootItem['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) {
// delete all shares, keep parent and group children
- Helper::delete($item['id'], true, null, null, true);
- } else {
- $ids = array();
- $items = [];
- $parents = array($item['id']);
- while (!empty($parents)) {
- $parents = "'".implode("','", $parents)."'";
- $query = \OC_DB::prepare('SELECT `id`, `permissions`, `item_type` FROM `*PREFIX*share`'
- .' WHERE `parent` IN ('.$parents.')');
- $result = $query->execute();
- // Reset parents array, only go through loop again if
- // items are found that need permissions removed
- $parents = array();
- while ($item = $result->fetchRow()) {
- $items[] = $item;
- // Check if permissions need to be removed
- if ($item['permissions'] & ~$permissions) {
- // Add to list of items that need permissions removed
- $ids[] = $item['id'];
- $parents[] = $item['id'];
- }
- }
- }
- // Remove the permissions for all reshares of this item
- if (!empty($ids)) {
- $ids = "'".implode("','", $ids)."'";
- // TODO this should be done with Doctrine platform objects
- if (\OC_Config::getValue( "dbtype") === 'oci') {
- $andOp = 'BITAND(`permissions`, ?)';
- } else {
- $andOp = '`permissions` & ?';
+ Helper::delete($rootItem['id'], true, null, null, true);
+ }
+
+ // Remove permission from all children
+ $parents = [$rootItem['id']];
+ while (!empty($parents)) {
+ $parents = $intArrayToLiteralArray($parents, $qb->expr());
+ $qb = $connection->getQueryBuilder();
+ $qb->select('id', 'permissions', 'item_type')
+ ->from('share')
+ ->where($qb->expr()->in('parent', $parents));
+ $result = $qb->execute();
+ // Reset parents array, only go through loop again if
+ // items are found that need permissions removed
+ $parents = [];
+ while ($item = $result->fetch()) {
+ $item = $sanitizeItem($item);
+
+ $items[] = $item;
+ // Check if permissions need to be removed
+ if ($item['permissions'] & ~$permissions) {
+ // Add to list of items that need permissions removed
+ $ids[] = $item['id'];
+ $parents[] = $item['id'];
}
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp
- .' WHERE `id` IN ('.$ids.')');
- $query->execute(array($permissions));
}
+ $result->closeCursor();
+ }
- foreach ($items as $item) {
- \OC_Hook::emit('OCP\Share', 'post_update_permissions', ['share' => $item]);
+ // Remove the permissions for all reshares of this item
+ if (!empty($ids)) {
+ $ids = "'".implode("','", $ids)."'";
+ // TODO this should be done with Doctrine platform objects
+ if (\OC::$server->getConfig()->getSystemValue("dbtype") === 'oci') {
+ $andOp = 'BITAND(`permissions`, ?)';
+ } else {
+ $andOp = '`permissions` & ?';
}
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp
+ .' WHERE `id` IN ('.$ids.')');
+ $query->execute(array($permissions));
+ }
+
+ }
+
+ /*
+ * Permissions were added
+ * Update all USERGROUP shares. (So group shares where the user moved their mountpoint).
+ */
+ if ($permissions & ~(int)$rootItem['permissions']) {
+ $qb = $connection->getQueryBuilder();
+ $qb->select('id', 'permissions', 'item_type')
+ ->from('share')
+ ->where($qb->expr()->eq('parent', $qb->createParameter('parent')))
+ ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('share_type')))
+ ->andWhere($qb->expr()->neq('permissions', $qb->createParameter('shareDeleted')))
+ ->setParameter(':parent', (int)$rootItem['id'])
+ ->setParameter(':share_type', 2)
+ ->setParameter(':shareDeleted', 0);
+ $result = $qb->execute();
+
+ $ids = [];
+ while ($item = $result->fetch()) {
+ $item = $sanitizeItem($item);
+ $items[] = $item;
+ $ids[] = $item['id'];
}
+ $result->closeCursor();
+
+ // Add permssions for all USERGROUP shares of this item
+ if (!empty($ids)) {
+ $ids = $intArrayToLiteralArray($ids, $qb->expr());
+
+ $qb = $connection->getQueryBuilder();
+ $qb->update('share')
+ ->set('permissions', $qb->createParameter('permissions'))
+ ->where($qb->expr()->in('id', $ids))
+ ->setParameter(':permissions', $permissions);
+ $qb->execute();
+ }
+ }
+
+ foreach ($items as $item) {
+ \OC_Hook::emit('OCP\Share', 'post_update_permissions', ['share' => $item]);
}
return true;
@@ -1710,7 +1796,7 @@ class Share extends Constants {
$root = strlen($root);
$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
$result = $query->execute($queryArgs);
- if (\OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('OCP\Share',
\OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
\OCP\Util::ERROR);
@@ -1774,7 +1860,7 @@ class Share extends Constants {
if (isset($row['parent'])) {
$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
$parentResult = $query->execute(array($row['parent']));
- if (\OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
\OCP\Util::ERROR);
@@ -1811,7 +1897,7 @@ class Share extends Constants {
}
}
// Check if resharing is allowed, if not remove share permission
- if (isset($row['permissions']) && (!self::isResharingAllowed() | \OC_Util::isSharingDisabledForUser())) {
+ if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
$row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
}
// Add display names to result
@@ -2179,7 +2265,7 @@ class Share extends Constants {
if ($isGroupShare) {
$id = self::insertShare($queriesToExecute['groupShare']);
// Save this id, any extra rows for this group share will need to reference it
- $parent = \OC_DB::insertid('*PREFIX*share');
+ $parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
unset($queriesToExecute['groupShare']);
}
@@ -2243,7 +2329,13 @@ class Share extends Constants {
} else {
// TODO Don't check if inside folder
$result['parent'] = $checkReshare['id'];
- $result['expirationDate'] = min($expirationDate, $checkReshare['expiration']);
+
+ $result['expirationDate'] = $expirationDate;
+ // $checkReshare['expiration'] could be null and then is always less than any value
+ if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
+ $result['expirationDate'] = $checkReshare['expiration'];
+ }
+
// only suggest the same name as new target if it is a reshare of the
// same file/folder and not the reshare of a child
if ($checkReshare[$column] === $itemSource) {
@@ -2332,22 +2424,7 @@ class Share extends Constants {
$id = false;
if ($result) {
- $id = \OC::$server->getDatabaseConnection()->lastInsertId();
- // Fallback, if lastInterId() doesn't work we need to perform a select
- // to get the ID (seems to happen sometimes on Oracle)
- if (!$id) {
- $getId = \OC_DB::prepare('
- SELECT `id`
- FROM`*PREFIX*share`
- WHERE `uid_owner` = ? AND `item_target` = ? AND `item_source` = ? AND `stime` = ?
- ');
- $r = $getId->execute(array($shareData['uidOwner'], $shareData['itemTarget'], $shareData['itemSource'], $shareData['shareTime']));
- if ($r) {
- $row = $r->fetchRow();
- $id = $row['id'];
- }
- }
-
+ $id = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
}
return $id;
@@ -2516,7 +2593,7 @@ class Share extends Constants {
* @param string $url
* @return string
*/
- private static function removeProtocolFromUrl($url) {
+ public static function removeProtocolFromUrl($url) {
if (strpos($url, 'https://') === 0) {
return substr($url, strlen('https://'));
} else if (strpos($url, 'http://') === 0) {
@@ -2581,7 +2658,10 @@ class Share extends Constants {
$result = self::tryHttpPost($url, $fields);
$status = json_decode($result['result'], true);
- return ($result['success'] && $status['ocs']['meta']['statuscode'] === 100);
+ if ($result['success'] && $status['ocs']['meta']['statuscode'] === 100) {
+ \OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
+ return true;
+ }
}
diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php
index 7f21d3aadf5..0ab0dc81fa7 100644
--- a/lib/private/share20/defaultshareprovider.php
+++ b/lib/private/share20/defaultshareprovider.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,68 +20,256 @@
*/
namespace OC\Share20;
-use OC\Share20\Exception\ShareNotFound;
+use OCP\Files\File;
+use OCP\Share\IShareProvider;
+use OC\Share20\Exception\InvalidShare;
+use OC\Share20\Exception\ProviderException;
+use OCP\Share\Exceptions\ShareNotFound;
use OC\Share20\Exception\BackendError;
-use OCP\IUser;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\Files\NotFoundException;
+use OCP\IGroup;
+use OCP\IGroupManager;
+use OCP\IUserManager;
+use OCP\Files\IRootFolder;
+use OCP\IDBConnection;
+use OCP\Files\Node;
+/**
+ * Class DefaultShareProvider
+ *
+ * @package OC\Share20
+ */
class DefaultShareProvider implements IShareProvider {
- /** @var \OCP\IDBConnection */
+ // Special share type for user modified group shares
+ const SHARE_TYPE_USERGROUP = 2;
+
+ /** @var IDBConnection */
private $dbConn;
- /** @var \OCP\IUserManager */
+ /** @var IUserManager */
private $userManager;
- /** @var \OCP\IGroupManager */
+ /** @var IGroupManager */
private $groupManager;
- /** @var \OCP\Files\Folder */
- private $userFolder;
+ /** @var IRootFolder */
+ private $rootFolder;
- public function __construct(\OCP\IDBConnection $connection,
- \OCP\IUserManager $userManager,
- \OCP\IGroupManager $groupManager,
- \OCP\Files\Folder $userFolder) {
+ /**
+ * DefaultShareProvider constructor.
+ *
+ * @param IDBConnection $connection
+ * @param IUserManager $userManager
+ * @param IGroupManager $groupManager
+ * @param IRootFolder $rootFolder
+ */
+ public function __construct(
+ IDBConnection $connection,
+ IUserManager $userManager,
+ IGroupManager $groupManager,
+ IRootFolder $rootFolder) {
$this->dbConn = $connection;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
- $this->userFolder = $userFolder;
+ $this->rootFolder = $rootFolder;
+ }
+
+ /**
+ * Return the identifier of this provider.
+ *
+ * @return string Containing only [a-zA-Z0-9]
+ */
+ public function identifier() {
+ return 'ocinternal';
}
/**
* Share a path
- *
- * @param Share $share
- * @return Share The share object
+ *
+ * @param \OCP\Share\IShare $share
+ * @return \OCP\Share\IShare The share object
+ * @throws ShareNotFound
+ * @throws \Exception
*/
- public function create(Share $share) {
- throw new \Exception();
+ public function create(\OCP\Share\IShare $share) {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->insert('share');
+ $qb->setValue('share_type', $qb->createNamedParameter($share->getShareType()));
+
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+ //Set the UID of the user we share with
+ $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ //Set the GID of the group we share with
+ $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ //Set the token of the share
+ $qb->setValue('token', $qb->createNamedParameter($share->getToken()));
+
+ //If a password is set store it
+ if ($share->getPassword() !== null) {
+ $qb->setValue('share_with', $qb->createNamedParameter($share->getPassword()));
+ }
+
+ //If an expiration date is set store it
+ if ($share->getExpirationDate() !== null) {
+ $qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime'));
+ }
+ } else {
+ throw new \Exception('invalid share type!');
+ }
+
+ // Set what is shares
+ $qb->setValue('item_type', $qb->createParameter('itemType'));
+ if ($share->getNode() instanceof \OCP\Files\File) {
+ $qb->setParameter('itemType', 'file');
+ } else {
+ $qb->setParameter('itemType', 'folder');
+ }
+
+ // Set the file id
+ $qb->setValue('item_source', $qb->createNamedParameter($share->getNode()->getId()));
+ $qb->setValue('file_source', $qb->createNamedParameter($share->getNode()->getId()));
+
+ // set the permissions
+ $qb->setValue('permissions', $qb->createNamedParameter($share->getPermissions()));
+
+ // Set who created this share
+ $qb->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy()));
+
+ // Set who is the owner of this file/folder (and this the owner of the share)
+ $qb->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner()));
+
+ // Set the file target
+ $qb->setValue('file_target', $qb->createNamedParameter($share->getTarget()));
+
+ // Set the time this share was created
+ $qb->setValue('stime', $qb->createNamedParameter(time()));
+
+ // insert the data and fetch the id of the share
+ $this->dbConn->beginTransaction();
+ $qb->execute();
+ $id = $this->dbConn->lastInsertId('*PREFIX*share');
+ $this->dbConn->commit();
+
+ // Now fetch the inserted share and create a complete share object
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
+
+ $cursor = $qb->execute();
+ $data = $cursor->fetch();
+ $cursor->closeCursor();
+
+ if ($data === false) {
+ throw new ShareNotFound();
+ }
+
+ $share = $this->createShare($data);
+ return $share;
}
/**
* Update a share
*
- * @param Share $share
- * @return Share The share object
+ * @param \OCP\Share\IShare $share
+ * @return \OCP\Share\IShare The share object
*/
- public function update(Share $share) {
- throw new \Exception();
+ public function update(\OCP\Share\IShare $share) {
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+ /*
+ * We allow updating the recipient on user shares.
+ */
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->update('share')
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
+ ->set('share_with', $qb->createNamedParameter($share->getSharedWith()))
+ ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
+ ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
+ ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
+ ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
+ ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
+ ->execute();
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->update('share')
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
+ ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
+ ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
+ ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
+ ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
+ ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
+ ->execute();
+
+ /*
+ * Update all user defined group shares
+ */
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->update('share')
+ ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
+ ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
+ ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
+ ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
+ ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
+ ->execute();
+
+ /*
+ * Now update the permissions for all children that have not set it to 0
+ */
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->update('share')
+ ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
+ ->andWhere($qb->expr()->neq('permissions', $qb->createNamedParameter(0)))
+ ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
+ ->execute();
+
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->update('share')
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
+ ->set('share_with', $qb->createNamedParameter($share->getPassword()))
+ ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
+ ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
+ ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
+ ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
+ ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
+ ->set('token', $qb->createNamedParameter($share->getToken()))
+ ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
+ ->execute();
+ }
+
+ return $share;
}
/**
- * Get all childre of this share
+ * Get all children of this share
+ * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
*
- * @param IShare $share
- * @return IShare[]
+ * @param \OCP\Share\IShare $parent
+ * @return \OCP\Share\IShare[]
*/
- private function getChildren(IShare $share) {
+ public function getChildren(\OCP\Share\IShare $parent) {
$children = [];
$qb = $this->dbConn->getQueryBuilder();
$qb->select('*')
->from('share')
- ->where($qb->expr()->eq('parent', $qb->createParameter('parent')))
- ->setParameter(':parent', $share->getId());
+ ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
+ ->andWhere(
+ $qb->expr()->in(
+ 'share_type',
+ $qb->createNamedParameter([
+ \OCP\Share::SHARE_TYPE_USER,
+ \OCP\Share::SHARE_TYPE_GROUP,
+ \OCP\Share::SHARE_TYPE_LINK,
+ ], IQueryBuilder::PARAM_INT_ARRAY)
+ )
+ )
+ ->orderBy('id');
$cursor = $qb->execute();
while($data = $cursor->fetch()) {
@@ -93,91 +281,244 @@ class DefaultShareProvider implements IShareProvider {
}
/**
- * Delete all the children of this share
+ * Delete a share
*
- * @param IShare $share
+ * @param \OCP\Share\IShare $share
*/
- protected function deleteChildren(IShare $share) {
- foreach($this->getChildren($share) as $child) {
- $this->delete($child);
+ public function delete(\OCP\Share\IShare $share) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->delete('share')
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())));
+
+ /*
+ * If the share is a group share delete all possible
+ * user defined groups shares.
+ */
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ $qb->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())));
}
+
+ $qb->execute();
}
/**
- * Delete a share
+ * Unshare a share from the recipient. If this is a group share
+ * this means we need a special entry in the share db.
*
- * @param Share $share
+ * @param \OCP\Share\IShare $share
+ * @param string $recipient UserId of recipient
* @throws BackendError
+ * @throws ProviderException
*/
- public function delete(IShare $share) {
- $this->deleteChildren($share);
-
- // Fetch share to make sure it exists
- $share = $this->getShareById($share->getId());
-
- $shareType = $share->getShareType();
- $sharedWith = '';
- if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
- $sharedWith = $share->getSharedWith()->getUID();
- } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
- $sharedWith = $share->getSharedWith()->getGID();
+ public function deleteFromSelf(\OCP\Share\IShare $share, $recipient) {
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+
+ $group = $this->groupManager->get($share->getSharedWith());
+ $user = $this->userManager->get($recipient);
+
+ if (!$group->inGroup($user)) {
+ throw new ProviderException('Recipient not in receiving group');
+ }
+
+ // Try to fetch user specific share
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
+ ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
+ ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
+ ->execute();
+
+ $data = $stmt->fetch();
+
+ /*
+ * Check if there already is a user specific group share.
+ * If there is update it (if required).
+ */
+ if ($data === false) {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $type = $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder';
+
+ //Insert new share
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
+ 'share_with' => $qb->createNamedParameter($recipient),
+ 'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
+ 'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
+ 'parent' => $qb->createNamedParameter($share->getId()),
+ 'item_type' => $qb->createNamedParameter($type),
+ 'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
+ 'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
+ 'file_target' => $qb->createNamedParameter($share->getTarget()),
+ 'permissions' => $qb->createNamedParameter(0),
+ 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
+ ])->execute();
+
+ } else if ($data['permissions'] !== 0) {
+
+ // Update existing usergroup share
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->update('share')
+ ->set('permissions', $qb->createNamedParameter(0))
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
+ ->execute();
+ }
+
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+
+ if ($share->getSharedWith() !== $recipient) {
+ throw new ProviderException('Recipient does not match');
+ }
+
+ // We can just delete user and link shares
+ $this->delete($share);
+ } else {
+ throw new ProviderException('Invalid shareType');
}
+ }
- $hookParams = [
- 'id' => $share->getId(),
- 'itemType' => $share->getPath() instanceof \OCP\Files\File ? 'file' : 'folder',
- 'itemSource' => $share->getPath()->getId(),
- 'shareType' => $shareType,
- 'shareWith' => $sharedWith,
- 'itemparent' => $share->getParent(),
- 'uidOwner' => $share->getSharedBy()->getUID(),
- 'fileSource' => $share->getPath()->getId(),
- 'fileTarget' => $share->getTarget()
- ];
+ /**
+ * @inheritdoc
+ */
+ public function move(\OCP\Share\IShare $share, $recipient) {
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+ // Just update the target
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->update('share')
+ ->set('file_target', $qb->createNamedParameter($share->getTarget()))
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
+ ->execute();
- \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
- $qb = $this->dbConn->getQueryBuilder();
- $qb->delete('share')
- ->where($qb->expr()->eq('id', $qb->createParameter('id')))
- ->setParameter(':id', $share->getId());
-
- try {
- $qb->execute();
- } catch (\Exception $e) {
- throw new BackendError();
+ // Check if there is a usergroup share
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->select('id')
+ ->from('share')
+ ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
+ ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
+ ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
+ ->setMaxResults(1)
+ ->execute();
+
+ $data = $stmt->fetch();
+ $stmt->closeCursor();
+
+ if ($data === false) {
+ // No usergroup share yet. Create one.
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
+ 'share_with' => $qb->createNamedParameter($recipient),
+ 'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
+ 'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
+ 'parent' => $qb->createNamedParameter($share->getId()),
+ 'item_type' => $qb->createNamedParameter($share->getNode() instanceof File ? 'file' : 'folder'),
+ 'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
+ 'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
+ 'file_target' => $qb->createNamedParameter($share->getTarget()),
+ 'permissions' => $qb->createNamedParameter($share->getPermissions()),
+ 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
+ ])->execute();
+ } else {
+ // Already a usergroup share. Update it.
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->update('share')
+ ->set('file_target', $qb->createNamedParameter($share->getTarget()))
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
+ ->execute();
+ }
}
- \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
+ return $share;
}
/**
- * Get all shares by the given user
+ * Get all shares by the given user. Sharetype and path can be used to filter.
*
- * @param IUser $user
+ * @param string $userId
* @param int $shareType
+ * @param \OCP\Files\File|\OCP\Files\Folder $node
+ * @param bool $reshares Also get the shares where $user is the owner instead of just the shares where $user is the initiator
+ * @param int $limit The maximum number of shares to be returned, -1 for all shares
* @param int $offset
- * @param int $limit
* @return Share[]
*/
- public function getShares(IUser $user, $shareType, $offset, $limit) {
- throw new \Exception();
+ public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share');
+
+ $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
+
+ /**
+ * Reshares for this user are shares where they are the owner.
+ */
+ if ($reshares === false) {
+ //Special case for old shares created via the web UI
+ $or1 = $qb->expr()->andX(
+ $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
+ $qb->expr()->isNull('uid_initiator')
+ );
+
+ $qb->andWhere(
+ $qb->expr()->orX(
+ $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
+ $or1
+ )
+ );
+ } else {
+ $qb->andWhere(
+ $qb->expr()->orX(
+ $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
+ $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
+ )
+ );
+ }
+
+ if ($node !== null) {
+ $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
+ }
+
+ if ($limit !== -1) {
+ $qb->setMaxResults($limit);
+ }
+
+ $qb->setFirstResult($offset);
+ $qb->orderBy('id');
+
+ $cursor = $qb->execute();
+ $shares = [];
+ while($data = $cursor->fetch()) {
+ $shares[] = $this->createShare($data);
+ }
+ $cursor->closeCursor();
+
+ return $shares;
}
/**
- * Get share by id
- *
- * @param int $id
- * @return IShare
- * @throws ShareNotFound
+ * @inheritdoc
*/
- public function getShareById($id) {
+ public function getShareById($id, $recipientId = null) {
$qb = $this->dbConn->getQueryBuilder();
$qb->select('*')
->from('share')
- ->where($qb->expr()->eq('id', $qb->createParameter('id')))
- ->setParameter(':id', $id);
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
+ ->andWhere(
+ $qb->expr()->in(
+ 'share_type',
+ $qb->createNamedParameter([
+ \OCP\Share::SHARE_TYPE_USER,
+ \OCP\Share::SHARE_TYPE_GROUP,
+ \OCP\Share::SHARE_TYPE_LINK,
+ ], IQueryBuilder::PARAM_INT_ARRAY)
+ )
+ );
$cursor = $qb->execute();
$data = $cursor->fetch();
@@ -187,7 +528,16 @@ class DefaultShareProvider implements IShareProvider {
throw new ShareNotFound();
}
- $share = $this->createShare($data);
+ try {
+ $share = $this->createShare($data);
+ } catch (InvalidShare $e) {
+ throw new ShareNotFound();
+ }
+
+ // If the recipient is set for a group share resolve to that user
+ if ($recipientId !== null && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ $share = $this->resolveGroupShare($share, $recipientId);
+ }
return $share;
}
@@ -196,79 +546,269 @@ class DefaultShareProvider implements IShareProvider {
* Get shares for a given path
*
* @param \OCP\Files\Node $path
- * @param Share[]
+ * @return \OCP\Share\IShare[]
*/
- public function getSharesByPath(\OCP\IUser $user, \OCP\Files\Node $path) {
- throw new \Exception();
+ public function getSharesByPath(Node $path) {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $cursor = $qb->select('*')
+ ->from('share')
+ ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
+ ->andWhere(
+ $qb->expr()->orX(
+ $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)),
+ $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))
+ )
+ )->execute();
+
+ $shares = [];
+ while($data = $cursor->fetch()) {
+ $shares[] = $this->createShare($data);
+ }
+ $cursor->closeCursor();
+
+ return $shares;
}
/**
- * Get shared with the given user
- *
- * @param IUser $user
- * @param int $shareType
- * @param Share
+ * @inheritdoc
*/
- public function getSharedWithMe(IUser $user, $shareType = null) {
- throw new \Exception();
+ public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
+ /** @var Share[] $shares */
+ $shares = [];
+
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
+ //Get shares directly with this user
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share');
+
+ // Order by id
+ $qb->orderBy('id');
+
+ // Set limit and offset
+ if ($limit !== -1) {
+ $qb->setMaxResults($limit);
+ }
+ $qb->setFirstResult($offset);
+
+ $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)));
+ $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
+
+ // Filter by node if provided
+ if ($node !== null) {
+ $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
+ }
+
+ $cursor = $qb->execute();
+
+ while($data = $cursor->fetch()) {
+ $shares[] = $this->createShare($data);
+ }
+ $cursor->closeCursor();
+
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
+ $user = $this->userManager->get($userId);
+ $allGroups = $this->groupManager->getUserGroups($user);
+
+ /** @var Share[] $shares2 */
+ $shares2 = [];
+
+ $start = 0;
+ while(true) {
+ $groups = array_slice($allGroups, $start, 100);
+ $start += 100;
+
+ if ($groups === []) {
+ break;
+ }
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->orderBy('id')
+ ->setFirstResult(0);
+
+ if ($limit !== -1) {
+ $qb->setMaxResults($limit - count($shares));
+ }
+
+ // Filter by node if provided
+ if ($node !== null) {
+ $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
+ }
+
+ $groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);
+
+ $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)));
+ $qb->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter(
+ $groups,
+ IQueryBuilder::PARAM_STR_ARRAY
+ )));
+
+ $cursor = $qb->execute();
+ while($data = $cursor->fetch()) {
+ if ($offset > 0) {
+ $offset--;
+ continue;
+ }
+ $shares2[] = $this->createShare($data);
+ }
+ $cursor->closeCursor();
+ }
+
+ /*
+ * Resolve all group shares to user specific shares
+ * TODO: Optmize this!
+ */
+ foreach($shares2 as $share) {
+ $shares[] = $this->resolveGroupShare($share, $userId);
+ }
+ } else {
+ throw new BackendError('Invalid backend');
+ }
+
+
+ return $shares;
}
/**
- * Get a share by token and if present verify the password
+ * Get a share by token
*
* @param string $token
- * @param string $password
- * @param Share
+ * @return \OCP\Share\IShare
+ * @throws ShareNotFound
*/
- public function getShareByToken($token, $password = null) {
- throw new \Exception();
+ public function getShareByToken($token) {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $cursor = $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)))
+ ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
+ ->execute();
+
+ $data = $cursor->fetch();
+
+ if ($data === false) {
+ throw new ShareNotFound();
+ }
+
+ try {
+ $share = $this->createShare($data);
+ } catch (InvalidShare $e) {
+ throw new ShareNotFound();
+ }
+
+ return $share;
}
/**
* Create a share object from an database row
*
* @param mixed[] $data
- * @return Share
+ * @return \OCP\Share\IShare
+ * @throws InvalidShare
*/
private function createShare($data) {
- $share = new Share();
+ $share = new Share($this->rootFolder);
$share->setId((int)$data['id'])
->setShareType((int)$data['share_type'])
->setPermissions((int)$data['permissions'])
->setTarget($data['file_target'])
- ->setShareTime((int)$data['stime'])
->setMailSend((bool)$data['mail_send']);
+ $shareTime = new \DateTime();
+ $shareTime->setTimestamp((int)$data['stime']);
+ $share->setShareTime($shareTime);
+
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
- $share->setSharedWith($this->userManager->get($data['share_with']));
+ $share->setSharedWith($data['share_with']);
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
- $share->setSharedWith($this->groupManager->get($data['share_with']));
+ $share->setSharedWith($data['share_with']);
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
$share->setPassword($data['share_with']);
$share->setToken($data['token']);
- } else {
- $share->setSharedWith($data['share_with']);
}
- $share->setSharedBy($this->userManager->get($data['uid_owner']));
+ if ($data['uid_initiator'] === null) {
+ //OLD SHARE
+ $share->setSharedBy($data['uid_owner']);
+ $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
- // TODO: getById can return an array. How to handle this properly??
- $path = $this->userFolder->getById($data['file_source']);
- $path = $path[0];
- $share->setPath($path);
-
- $owner = $path->getStorage()->getOwner('.');
- if ($owner !== false) {
- $share->setShareOwner($this->userManager->get($owner));
+ $owner = $path->getOwner();
+ $share->setShareOwner($owner->getUID());
+ } else {
+ //New share!
+ $share->setSharedBy($data['uid_initiator']);
+ $share->setShareOwner($data['uid_owner']);
}
+ $share->setNodeId((int)$data['file_source']);
+ $share->setNodeType($data['item_type']);
+
if ($data['expiration'] !== null) {
$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
$share->setExpirationDate($expiration);
}
+ $share->setProviderId($this->identifier());
+
return $share;
}
+ /**
+ * Get the node with file $id for $user
+ *
+ * @param string $user The userId
+ * @param int $id
+ * @return \OCP\Files\File|\OCP\Files\Folder
+ * @throws InvalidShare
+ */
+ private function getNode($user, $id) {
+ try {
+ $userFolder = $this->rootFolder->getUserFolder($user);
+ } catch (NotFoundException $e) {
+ throw new InvalidShare();
+ }
+
+ $nodes = $userFolder->getById($id);
+
+ if (empty($nodes)) {
+ throw new InvalidShare();
+ }
+
+ return $nodes[0];
+ }
+
+ /**
+ * Resolve a group share to a user specific share
+ * Thus if the user moved their group share make sure this is properly reflected here.
+ *
+ * @param \OCP\Share\IShare $share
+ * @param string $userId
+ * @return Share Returns the updated share if one was found else return the original share.
+ */
+ private function resolveGroupShare(\OCP\Share\IShare $share, $userId) {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $stmt = $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
+ ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
+ ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
+ ->setMaxResults(1)
+ ->execute();
+
+ $data = $stmt->fetch();
+ $stmt->closeCursor();
+
+ if ($data !== false) {
+ $share->setPermissions((int)$data['permissions']);
+ $share->setTarget($data['file_target']);
+ }
+
+ return $share;
+ }
}
diff --git a/lib/private/share20/exception/backenderror.php b/lib/private/share20/exception/backenderror.php
index 2d661533171..f15dea4a243 100644
--- a/lib/private/share20/exception/backenderror.php
+++ b/lib/private/share20/exception/backenderror.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/share20/exception/sharenotfound.php b/lib/private/share20/exception/invalidshare.php
index 0e18a96be68..c176e4424ba 100644
--- a/lib/private/share20/exception/sharenotfound.php
+++ b/lib/private/share20/exception/invalidshare.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,6 +20,6 @@
*/
namespace OC\Share20\Exception;
-class ShareNotFound extends \Exception {
+class InvalidShare extends \Exception {
}
diff --git a/lib/private/share20/exception/providerexception.php b/lib/private/share20/exception/providerexception.php
new file mode 100644
index 00000000000..a14d5266581
--- /dev/null
+++ b/lib/private/share20/exception/providerexception.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20\Exception;
+
+
+class ProviderException extends \Exception {
+
+}
+
diff --git a/lib/private/share20/ishare.php b/lib/private/share20/ishare.php
deleted file mode 100644
index a80abebd71c..00000000000
--- a/lib/private/share20/ishare.php
+++ /dev/null
@@ -1,177 +0,0 @@
-<?php
-/**
- * @author Roeland Jago Douma <rullzer@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-namespace OC\Share20;
-
-use OCP\Files\File;
-use OCP\Files\Folder;
-use OCP\Files\Node;
-use OCP\IUser;
-use OCP\IGroup;
-
-interface IShare {
-
- /**
- * Get the id of the share
- *
- * @return string
- */
- public function getId();
-
- /**
- * Set the path of this share
- *
- * @param File|Folder $path
- * @return Share The modified object
- */
- public function setPath(Node $path);
-
- /**
- * Get the path of this share for the current user
- *
- * @return File|Folder
- */
- public function getPath();
-
- /**
- * Set the shareType
- *
- * @param int $shareType
- * @return Share The modified object
- */
- public function setShareType($shareType);
-
- /**
- * Get the shareType
- *
- * @return int
- */
- public function getShareType();
-
- /**
- * Set the receiver of this share
- *
- * @param IUser|IGroup|string
- * @return Share The modified object
- */
- public function setSharedWith($sharedWith);
-
- /**
- * Get the receiver of this share
- *
- * @return IUser|IGroup|string
- */
- public function getSharedWith();
-
- /**
- * Set the permissions
- *
- * @param int $permissions
- * @return Share The modified object
- */
- public function setPermissions($permissions);
-
- /**
- * Get the share permissions
- *
- * @return int
- */
- public function getPermissions();
-
- /**
- * Set the expiration date
- *
- * @param \DateTime $expireDate
- * @return Share The modified object
- */
- public function setExpirationDate(\DateTime $expireDate);
-
- /**
- * Get the share expiration date
- *
- * @return \DateTime
- */
- public function getExpirationDate();
-
- /**
- * Get share sharer
- *
- * @return IUser|string
- */
- public function getSharedBy();
-
- /**
- * Get the original share owner (who owns the path)
- *
- * @return IUser|string
- */
- public function getShareOwner();
-
- /**
- * Set the password
- *
- * @param string $password
- *
- * @return Share The modified object
- */
- public function setPassword($password);
-
- /**
- * Is a password set for this share
- *
- * @return string
- */
- public function getPassword();
-
- /**
- * Get the token
- *
- * @return string
- */
- public function getToken();
-
- /**
- * Get the parent it
- *
- * @return int
- */
- public function getParent();
-
- /**
- * Get the target of this share
- *
- * @return string
- */
- public function getTarget();
-
- /**
- * Get the timestamp this share was created
- *
- * @return int
- */
- public function getSharetime();
-
- /**
- * Get mailSend
- *
- * @return bool
- */
- public function getMailSend();
-}
diff --git a/lib/private/share20/ishareprovider.php b/lib/private/share20/ishareprovider.php
deleted file mode 100644
index b3f4eb6868f..00000000000
--- a/lib/private/share20/ishareprovider.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-/**
- * @author Roeland Jago Douma <rullzer@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-namespace OC\Share20;
-
-use OC\Share20\Exception\ShareNotFound;
-use OC\Share20\Exception\BackendError;
-use OCP\IUser;
-
-interface IShareProvider {
-
- /**
- * Share a path
- *
- * @param Share $share
- * @return Share The share object
- */
- public function create(Share $share);
-
- /**
- * Update a share
- *
- * @param Share $share
- * @return Share The share object
- */
- public function update(Share $share);
-
- /**
- * Delete a share
- *
- * @param Share $share
- * @throws BackendError
- */
- public function delete(IShare $share);
-
- /**
- * Get all shares by the given user
- *
- * @param IUser $user
- * @param int $shareType
- * @param int $offset
- * @param int $limit
- * @return Share[]
- */
- public function getShares(IUser $user, $shareType, $offset, $limit);
-
- /**
- * Get share by id
- *
- * @param int $id
- * @return IShare
- * @throws ShareNotFound
- */
- public function getShareById($id);
-
- /**
- * Get shares for a given path
- *
- * @param \OCP\Files\Node $path
- * @param Share[]
- */
- public function getSharesByPath(\OCP\IUser $user, \OCP\Files\Node $path);
-
- /**
- * Get shared with the given user
- *
- * @param IUser $user
- * @param int $shareType
- * @param Share
- */
- public function getSharedWithMe(IUser $user, $shareType = null);
-
- /**
- * Get a share by token and if present verify the password
- *
- * @param string $token
- * @param string $password
- * @param Share
- */
- public function getShareByToken($token, $password = null);
-}
diff --git a/lib/private/share20/manager.php b/lib/private/share20/manager.php
index 52e43a9aa9f..d65fb927f9b 100644
--- a/lib/private/share20/manager.php
+++ b/lib/private/share20/manager.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -18,127 +18,791 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-namespace OC\Share20;
+namespace OC\Share20;
-use OCP\IAppConfig;
+use OCP\Files\IRootFolder;
use OCP\IUserManager;
-use OCP\IGroupManager;
-use OCP\IUser;
+use OCP\Share\IManager;
+use OCP\Share\IProviderFactory;
+use OC\Share20\Exception\BackendError;
+use OCP\IConfig;
+use OCP\IL10N;
use OCP\ILogger;
+use OCP\Security\ISecureRandom;
+use OCP\Security\IHasher;
+use OCP\Files\Mount\IMountManager;
+use OCP\IGroupManager;
+use OCP\Files\File;
use OCP\Files\Folder;
-use OC\Share20\Exception\ShareNotFound;
+use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\Exceptions\GenericShareException;
/**
* This class is the communication hub for all sharing related operations.
*/
-class Manager {
+class Manager implements IManager {
+
+ /** @var IProviderFactory */
+ private $factory;
+ /** @var ILogger */
+ private $logger;
+ /** @var IConfig */
+ private $config;
+ /** @var ISecureRandom */
+ private $secureRandom;
+ /** @var IHasher */
+ private $hasher;
+ /** @var IMountManager */
+ private $mountManager;
+ /** @var IGroupManager */
+ private $groupManager;
+ /** @var IL10N */
+ private $l;
+ /** @var IUserManager */
+ private $userManager;
+ /** @var IRootFolder */
+ private $rootFolder;
/**
- * @var IShareProvider[]
+ * Manager constructor.
+ *
+ * @param ILogger $logger
+ * @param IConfig $config
+ * @param ISecureRandom $secureRandom
+ * @param IHasher $hasher
+ * @param IMountManager $mountManager
+ * @param IGroupManager $groupManager
+ * @param IL10N $l
+ * @param IProviderFactory $factory
+ * @param IUserManager $userManager
+ * @param IRootFolder $rootFolder
*/
- private $defaultProvider;
+ public function __construct(
+ ILogger $logger,
+ IConfig $config,
+ ISecureRandom $secureRandom,
+ IHasher $hasher,
+ IMountManager $mountManager,
+ IGroupManager $groupManager,
+ IL10N $l,
+ IProviderFactory $factory,
+ IUserManager $userManager,
+ IRootFolder $rootFolder
+ ) {
+ $this->logger = $logger;
+ $this->config = $config;
+ $this->secureRandom = $secureRandom;
+ $this->hasher = $hasher;
+ $this->mountManager = $mountManager;
+ $this->groupManager = $groupManager;
+ $this->l = $l;
+ $this->factory = $factory;
+ $this->userManager = $userManager;
+ $this->rootFolder = $rootFolder;
+ }
- /** @var IUser */
- private $currentUser;
+ /**
+ * Convert from a full share id to a tuple (providerId, shareId)
+ *
+ * @param string $id
+ * @return string[]
+ */
+ private function splitFullId($id) {
+ return explode(':', $id, 2);
+ }
- /** @var IUserManager */
- private $userManager;
+ /**
+ * Verify if a password meets all requirements
+ *
+ * @param string $password
+ * @throws \Exception
+ */
+ protected function verifyPassword($password) {
+ if ($password === null) {
+ // No password is set, check if this is allowed.
+ if ($this->shareApiLinkEnforcePassword()) {
+ throw new \InvalidArgumentException('Passwords are enforced for link shares');
+ }
- /** @var IGroupManager */
- private $groupManager;
+ return;
+ }
- /** @var ILogger */
- private $logger;
+ // Let others verify the password
+ $accepted = true;
+ $message = '';
+ \OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
+ 'password' => $password,
+ 'accepted' => &$accepted,
+ 'message' => &$message
+ ]);
- /** @var IAppConfig */
- private $appConfig;
+ if (!$accepted) {
+ throw new \Exception($message);
+ }
+ }
- /** @var IFolder */
- private $userFolder;
+ /**
+ * Check for generic requirements before creating a share
+ *
+ * @param \OCP\Share\IShare $share
+ * @throws \InvalidArgumentException
+ * @throws GenericShareException
+ */
+ protected function generalCreateChecks(\OCP\Share\IShare $share) {
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+ // We expect a valid user as sharedWith for user shares
+ if (!$this->userManager->userExists($share->getSharedWith())) {
+ throw new \InvalidArgumentException('SharedWith is not a valid user');
+ }
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ // We expect a valid group as sharedWith for group shares
+ if (!$this->groupManager->groupExists($share->getSharedWith())) {
+ throw new \InvalidArgumentException('SharedWith is not a valid group');
+ }
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ if ($share->getSharedWith() !== null) {
+ throw new \InvalidArgumentException('SharedWith should be empty');
+ }
+ } else {
+ // We can't handle other types yet
+ throw new \InvalidArgumentException('unkown share type');
+ }
- public function __construct(IUser $user,
- IUserManager $userManager,
- IGroupManager $groupManager,
- ILogger $logger,
- IAppConfig $appConfig,
- Folder $userFolder,
- IShareProvider $defaultProvider) {
- $this->currentUser = $user;
- $this->userManager = $userManager;
- $this->groupManager = $groupManager;
- $this->logger = $logger;
- $this->appConfig = $appConfig;
- $this->userFolder = $userFolder;
+ // Verify the initiator of the share is set
+ if ($share->getSharedBy() === null) {
+ throw new \InvalidArgumentException('SharedBy should be set');
+ }
+
+ // Cannot share with yourself
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
+ $share->getSharedWith() === $share->getSharedBy()) {
+ throw new \InvalidArgumentException('Can\'t share with yourself');
+ }
+
+ // The path should be set
+ if ($share->getNode() === null) {
+ throw new \InvalidArgumentException('Path should be set');
+ }
+
+ // And it should be a file or a folder
+ if (!($share->getNode() instanceof \OCP\Files\File) &&
+ !($share->getNode() instanceof \OCP\Files\Folder)) {
+ throw new \InvalidArgumentException('Path should be either a file or a folder');
+ }
- // TEMP SOLUTION JUST TO GET STARTED
- $this->defaultProvider = $defaultProvider;
+ // Check if we actually have share permissions
+ if (!$share->getNode()->isShareable()) {
+ $message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getPath()]);
+ throw new GenericShareException($message_t, $message_t, 404);
+ }
+
+ // Permissions should be set
+ if ($share->getPermissions() === null) {
+ throw new \InvalidArgumentException('A share requires permissions');
+ }
+
+ // Check that we do not share with more permissions than we have
+ if ($share->getPermissions() & ~$share->getNode()->getPermissions()) {
+ $message_t = $this->l->t('Cannot increase permissions of %s', [$share->getNode()->getPath()]);
+ throw new GenericShareException($message_t, $message_t, 404);
+ }
+
+ // Check that read permissions are always set
+ if (($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
+ throw new \InvalidArgumentException('Shares need at least read permissions');
+ }
+ }
+
+ /**
+ * Validate if the expiration date fits the system settings
+ *
+ * @param \OCP\Share\IShare $share The share to validate the expiration date of
+ * @return \OCP\Share\IShare The expiration date or null if $expireDate was null and it is not required
+ * @throws GenericShareException
+ * @throws \InvalidArgumentException
+ * @throws \Exception
+ */
+ protected function validateExpirationDate(\OCP\Share\IShare $share) {
+
+ $expirationDate = $share->getExpirationDate();
+
+ if ($expirationDate !== null) {
+ //Make sure the expiration date is a date
+ $expirationDate->setTime(0, 0, 0);
+
+ $date = new \DateTime();
+ $date->setTime(0, 0, 0);
+ if ($date >= $expirationDate) {
+ $message = $this->l->t('Expiration date is in the past');
+ throw new GenericShareException($message, $message, 404);
+ }
+ }
+
+ // If we enforce the expiration date check that is does not exceed
+ if ($this->shareApiLinkDefaultExpireDateEnforced()) {
+ if ($expirationDate === null) {
+ throw new \InvalidArgumentException('Expiration date is enforced');
+ }
+
+ $date = new \DateTime();
+ $date->setTime(0, 0, 0);
+ $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
+ if ($date < $expirationDate) {
+ $message = $this->l->t('Cannot set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
+ throw new GenericShareException($message, $message, 404);
+ }
+ }
+
+ // If expiredate is empty set a default one if there is a default
+ if ($expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
+ $expirationDate = new \DateTime();
+ $expirationDate->setTime(0,0,0);
+ $expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
+ }
+
+ $accepted = true;
+ $message = '';
+ \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
+ 'expirationDate' => &$expirationDate,
+ 'accepted' => &$accepted,
+ 'message' => &$message,
+ 'passwordSet' => $share->getPassword() === null,
+ ]);
+
+ if (!$accepted) {
+ throw new \Exception($message);
+ }
+
+ $share->setExpirationDate($expirationDate);
+
+ return $expirationDate;
+ }
+
+ /**
+ * Check for pre share requirements for user shares
+ *
+ * @param \OCP\Share\IShare $share
+ * @throws \Exception
+ */
+ protected function userCreateChecks(\OCP\Share\IShare $share) {
+ // Check if we can share with group members only
+ if ($this->shareWithGroupMembersOnly()) {
+ $sharedBy = $this->userManager->get($share->getSharedBy());
+ $sharedWith = $this->userManager->get($share->getSharedWith());
+ // Verify we can share with this user
+ $groups = array_intersect(
+ $this->groupManager->getUserGroupIds($sharedBy),
+ $this->groupManager->getUserGroupIds($sharedWith)
+ );
+ if (empty($groups)) {
+ throw new \Exception('Only sharing with group members is allowed');
+ }
+ }
+
+ /*
+ * TODO: Could be costly, fix
+ *
+ * Also this is not what we want in the future.. then we want to squash identical shares.
+ */
+ $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
+ $existingShares = $provider->getSharesByPath($share->getNode());
+ foreach($existingShares as $existingShare) {
+ // Ignore if it is the same share
+ if ($existingShare->getFullId() === $share->getFullId()) {
+ continue;
+ }
+
+ // Identical share already existst
+ if ($existingShare->getSharedWith() === $share->getSharedWith()) {
+ throw new \Exception('Path already shared with this user');
+ }
+
+ // The share is already shared with this user via a group share
+ if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ $group = $this->groupManager->get($existingShare->getSharedWith());
+ $user = $this->userManager->get($share->getSharedWith());
+
+ if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
+ throw new \Exception('Path already shared with this user');
+ }
+ }
+ }
+ }
+
+ /**
+ * Check for pre share requirements for group shares
+ *
+ * @param \OCP\Share\IShare $share
+ * @throws \Exception
+ */
+ protected function groupCreateChecks(\OCP\Share\IShare $share) {
+ // Verify if the user can share with this group
+ if ($this->shareWithGroupMembersOnly()) {
+ $sharedBy = $this->userManager->get($share->getSharedBy());
+ $sharedWith = $this->groupManager->get($share->getSharedWith());
+ if (!$sharedWith->inGroup($sharedBy)) {
+ throw new \Exception('Only sharing within your own groups is allowed');
+ }
+ }
+
+ /*
+ * TODO: Could be costly, fix
+ *
+ * Also this is not what we want in the future.. then we want to squash identical shares.
+ */
+ $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
+ $existingShares = $provider->getSharesByPath($share->getNode());
+ foreach($existingShares as $existingShare) {
+ if ($existingShare->getFullId() === $share->getFullId()) {
+ continue;
+ }
+
+ if ($existingShare->getSharedWith() === $share->getSharedWith()) {
+ throw new \Exception('Path already shared with this group');
+ }
+ }
+ }
+
+ /**
+ * Check for pre share requirements for link shares
+ *
+ * @param \OCP\Share\IShare $share
+ * @throws \Exception
+ */
+ protected function linkCreateChecks(\OCP\Share\IShare $share) {
+ // Are link shares allowed?
+ if (!$this->shareApiAllowLinks()) {
+ throw new \Exception('Link sharing not allowed');
+ }
+
+ // Link shares by definition can't have share permissions
+ if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
+ throw new \InvalidArgumentException('Link shares can\'t have reshare permissions');
+ }
+
+ // We don't allow deletion on link shares
+ if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
+ throw new \InvalidArgumentException('Link shares can\'t have delete permissions');
+ }
+
+ // Check if public upload is allowed
+ if (!$this->shareApiLinkAllowPublicUpload() &&
+ ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE))) {
+ throw new \InvalidArgumentException('Public upload not allowed');
+ }
+ }
+
+ /**
+ * @param File|Folder $path
+ */
+ protected function pathCreateChecks($path) {
+ // Make sure that we do not share a path that contains a shared mountpoint
+ if ($path instanceof \OCP\Files\Folder) {
+ $mounts = $this->mountManager->findIn($path->getPath());
+ foreach($mounts as $mount) {
+ if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
+ throw new \InvalidArgumentException('Path contains files shared with you');
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if the user that is sharing can actually share
+ *
+ * @param \OCP\Share\IShare $share
+ * @return bool
+ */
+ protected function canShare(\OCP\Share\IShare $share) {
+ if (!$this->shareApiEnabled()) {
+ return false;
+ }
+
+ if ($this->sharingDisabledForUser($share->getSharedBy())) {
+ return false;
+ }
+
+ return true;
}
/**
* Share a path
- *
- * @param Share $share
+ *
+ * @param \OCP\Share\IShare $share
* @return Share The share object
+ * @throws \Exception
+ *
+ * TODO: handle link share permissions or check them
*/
- public function createShare(Share $share) {
- throw new \Exception();
+ public function createShare(\OCP\Share\IShare $share) {
+ if (!$this->canShare($share)) {
+ throw new \Exception('The Share API is disabled');
+ }
+
+ $this->generalCreateChecks($share);
+
+ //Verify share type
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+ $this->userCreateChecks($share);
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ $this->groupCreateChecks($share);
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ $this->linkCreateChecks($share);
+
+ /*
+ * For now ignore a set token.
+ */
+ $share->setToken(
+ $this->secureRandom->generate(
+ \OC\Share\Constants::TOKEN_LENGTH,
+ \OCP\Security\ISecureRandom::CHAR_LOWER.
+ \OCP\Security\ISecureRandom::CHAR_UPPER.
+ \OCP\Security\ISecureRandom::CHAR_DIGITS
+ )
+ );
+
+ //Verify the expiration date
+ $this->validateExpirationDate($share);
+
+ //Verify the password
+ $this->verifyPassword($share->getPassword());
+
+ // If a password is set. Hash it!
+ if ($share->getPassword() !== null) {
+ $share->setPassword($this->hasher->hash($share->getPassword()));
+ }
+ }
+
+ // Verify if there are any issues with the path
+ $this->pathCreateChecks($share->getNode());
+
+ // On creation of a share the owner is always the owner of the path
+ $share->setShareOwner($share->getNode()->getOwner()->getUID());
+
+ // Cannot share with the owner
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
+ $share->getSharedWith() === $share->getShareOwner()) {
+ throw new \InvalidArgumentException('Can\'t share with the share owner');
+ }
+
+ // Generate the target
+ $target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
+ $target = \OC\Files\Filesystem::normalizePath($target);
+ $share->setTarget($target);
+
+ // Pre share hook
+ $run = true;
+ $error = '';
+ $preHookData = [
+ 'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
+ 'itemSource' => $share->getNode()->getId(),
+ 'shareType' => $share->getShareType(),
+ 'uidOwner' => $share->getSharedBy(),
+ 'permissions' => $share->getPermissions(),
+ 'fileSource' => $share->getNode()->getId(),
+ 'expiration' => $share->getExpirationDate(),
+ 'token' => $share->getToken(),
+ 'itemTarget' => $share->getTarget(),
+ 'shareWith' => $share->getSharedWith(),
+ 'run' => &$run,
+ 'error' => &$error,
+ ];
+ \OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
+
+ if ($run === false) {
+ throw new \Exception($error);
+ }
+
+ $provider = $this->factory->getProviderForType($share->getShareType());
+ $share = $provider->create($share);
+
+ // Post share hook
+ $postHookData = [
+ 'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
+ 'itemSource' => $share->getNode()->getId(),
+ 'shareType' => $share->getShareType(),
+ 'uidOwner' => $share->getSharedBy(),
+ 'permissions' => $share->getPermissions(),
+ 'fileSource' => $share->getNode()->getId(),
+ 'expiration' => $share->getExpirationDate(),
+ 'token' => $share->getToken(),
+ 'id' => $share->getId(),
+ 'shareWith' => $share->getSharedWith(),
+ 'itemTarget' => $share->getTarget(),
+ 'fileTarget' => $share->getTarget(),
+ ];
+
+ \OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
+
+ return $share;
}
/**
* Update a share
*
- * @param Share $share
- * @return Share The share object
+ * @param \OCP\Share\IShare $share
+ * @return \OCP\Share\IShare The share object
+ * @throws \InvalidArgumentException
*/
- public function updateShare(Share $share) {
- throw new \Exception();
+ public function updateShare(\OCP\Share\IShare $share) {
+ $expirationDateUpdated = false;
+
+ if (!$this->canShare($share)) {
+ throw new \Exception('The Share API is disabled');
+ }
+
+ $originalShare = $this->getShareById($share->getFullId());
+
+ // We can't change the share type!
+ if ($share->getShareType() !== $originalShare->getShareType()) {
+ throw new \InvalidArgumentException('Can\'t change share type');
+ }
+
+ // We can only change the recipient on user shares
+ if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
+ $share->getShareType() !== \OCP\Share::SHARE_TYPE_USER) {
+ throw new \InvalidArgumentException('Can only update recipient on user shares');
+ }
+
+ // Cannot share with the owner
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
+ $share->getSharedWith() === $share->getShareOwner()) {
+ throw new \InvalidArgumentException('Can\'t share with the share owner');
+ }
+
+ $this->generalCreateChecks($share);
+
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+ $this->userCreateChecks($share);
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ $this->groupCreateChecks($share);
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ $this->linkCreateChecks($share);
+
+ // Password updated.
+ if ($share->getPassword() !== $originalShare->getPassword()) {
+ //Verify the password
+ $this->verifyPassword($share->getPassword());
+
+ // If a password is set. Hash it!
+ if ($share->getPassword() !== null) {
+ $share->setPassword($this->hasher->hash($share->getPassword()));
+ }
+ }
+
+ if ($share->getExpirationDate() !== $originalShare->getExpirationDate()) {
+ //Verify the expiration date
+ $this->validateExpirationDate($share);
+ $expirationDateUpdated = true;
+ }
+ }
+
+ $this->pathCreateChecks($share->getNode());
+
+ // Now update the share!
+ $provider = $this->factory->getProviderForType($share->getShareType());
+ $share = $provider->update($share);
+
+ if ($expirationDateUpdated === true) {
+ \OC_Hook::emit('OCP\Share', 'post_set_expiration_date', [
+ 'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
+ 'itemSource' => $share->getNode()->getId(),
+ 'date' => $share->getExpirationDate(),
+ 'uidOwner' => $share->getSharedBy(),
+ ]);
+ }
+
+ if ($share->getPermissions() !== $originalShare->getPermissions()) {
+ $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
+ \OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
+ 'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
+ 'itemSource' => $share->getNode()->getId(),
+ 'shareType' => $share->getShareType(),
+ 'shareWith' => $share->getSharedWith(),
+ 'uidOwner' => $share->getSharedBy(),
+ 'permissions' => $share->getPermissions(),
+ 'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
+ ));
+ }
+
+ return $share;
}
/**
- * Delete a share
+ * Delete all the children of this share
+ * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
*
- * @param Share $share
- * @throws ShareNotFound
- * @throws \OC\Share20\Exception\BackendError
+ * @param \OCP\Share\IShare $share
+ * @return \OCP\Share\IShare[] List of deleted shares
*/
- public function deleteShare(IShare $share) {
- if ($share->getId() === null) {
- throw new ShareNotFound();
+ protected function deleteChildren(\OCP\Share\IShare $share) {
+ $deletedShares = [];
+
+ $provider = $this->factory->getProviderForType($share->getShareType());
+
+ foreach ($provider->getChildren($share) as $child) {
+ $deletedChildren = $this->deleteChildren($child);
+ $deletedShares = array_merge($deletedShares, $deletedChildren);
+
+ $provider->delete($child);
+ $deletedShares[] = $child;
}
- $this->defaultProvider->delete($share);
+ return $deletedShares;
}
/**
- * Retrieve all shares by the current user
+ * Delete a share
*
- * @param int $page
- * @param int $perPage
- * @return Share[]
+ * @param \OCP\Share\IShare $share
+ * @throws ShareNotFound
*/
- public function getShares($page=0, $perPage=50) {
- throw new \Exception();
+ public function deleteShare(\OCP\Share\IShare $share) {
+ // Just to make sure we have all the info
+ $share = $this->getShareById($share->getFullId());
+
+ $formatHookParams = function(\OCP\Share\IShare $share) {
+ // Prepare hook
+ $shareType = $share->getShareType();
+ $sharedWith = '';
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
+ $sharedWith = $share->getSharedWith();
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
+ $sharedWith = $share->getSharedWith();
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
+ $sharedWith = $share->getSharedWith();
+ }
+
+ $hookParams = [
+ 'id' => $share->getId(),
+ 'itemType' => $share->getNodeType(),
+ 'itemSource' => $share->getNodeId(),
+ 'shareType' => $shareType,
+ 'shareWith' => $sharedWith,
+ 'itemparent' => $share->getParent(),
+ 'uidOwner' => $share->getSharedBy(),
+ 'fileSource' => $share->getNodeId(),
+ 'fileTarget' => $share->getTarget()
+ ];
+ return $hookParams;
+ };
+
+ $hookParams = $formatHookParams($share);
+
+ // Emit pre-hook
+ \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
+
+ // Get all children and delete them as well
+ $deletedShares = $this->deleteChildren($share);
+
+ // Do the actual delete
+ $provider = $this->factory->getProviderForType($share->getShareType());
+ $provider->delete($share);
+
+ // All the deleted shares caused by this delete
+ $deletedShares[] = $share;
+
+ //Format hook info
+ $formattedDeletedShares = array_map(function($share) use ($formatHookParams) {
+ return $formatHookParams($share);
+ }, $deletedShares);
+
+ $hookParams['deletedShares'] = $formattedDeletedShares;
+
+ // Emit post hook
+ \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
}
+
/**
- * Retrieve a share by the share id
+ * Unshare a file as the recipient.
+ * This can be different from a regular delete for example when one of
+ * the users in a groups deletes that share. But the provider should
+ * handle this.
*
- * @param string $id
- * @return Share
+ * @param \OCP\Share\IShare $share
+ * @param string $recipientId
+ */
+ public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
+ list($providerId, ) = $this->splitFullId($share->getId());
+ $provider = $this->factory->getProvider($providerId);
+
+ $provider->deleteFromSelf($share, $recipientId);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function moveShare(\OCP\Share\IShare $share, $recipientId) {
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ throw new \InvalidArgumentException('Can\'t change target of link share');
+ }
+
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
+ throw new \InvalidArgumentException('Invalid recipient');
+ }
+
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ $sharedWith = $this->groupManager->get($share->getSharedWith());
+ $recipient = $this->userManager->get($recipientId);
+ if (!$sharedWith->inGroup($recipient)) {
+ throw new \InvalidArgumentException('Invalid recipient');
+ }
+ }
+
+ list($providerId, ) = $this->splitFullId($share->getId());
+ $provider = $this->factory->getProvider($providerId);
+
+ $provider->move($share, $recipientId);
+ }
+
+ /**
+ * Get shares shared by (initiated) by the provided user.
*
- * @throws ShareNotFound
+ * @param string $userId
+ * @param int $shareType
+ * @param \OCP\Files\File|\OCP\Files\Folder $path
+ * @param bool $reshares
+ * @param int $limit The maximum number of returned results, -1 for all results
+ * @param int $offset
+ * @return \OCP\Share\IShare[]
+ */
+ public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
+ if ($path !== null &&
+ !($path instanceof \OCP\Files\File) &&
+ !($path instanceof \OCP\Files\Folder)) {
+ throw new \InvalidArgumentException('invalid path');
+ }
+
+ $provider = $this->factory->getProviderForType($shareType);
+
+ return $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
+ }
+
+ /**
+ * @inheritdoc
*/
- public function getShareById($id) {
- $share = $this->defaultProvider->getShareById($id);
+ public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
+ $provider = $this->factory->getProviderForType($shareType);
- if ($share->getSharedWith() !== $this->currentUser &&
- $share->getSharedBy() !== $this->currentUser &&
- $share->getShareOwner() !== $this->currentUser) {
+ return $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getShareById($id, $recipient = null) {
+ if ($id === null) {
throw new ShareNotFound();
}
+ list($providerId, $id) = $this->splitFullId($id);
+ $provider = $this->factory->getProvider($providerId);
+
+ $share = $provider->getShareById($id, $recipient);
+
return $share;
}
@@ -152,34 +816,55 @@ class Manager {
* @return Share[]
*/
public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
- throw new \Exception();
}
/**
- * Get all shares that are shared with the current user
+ * Get the share by token possible with password
*
- * @param int $shareType
- * @param int $page
- * @param int $perPage
+ * @param string $token
+ * @return Share
*
- * @return Share[]
+ * @throws ShareNotFound
*/
- public function getSharedWithMe($shareType = null, $page=0, $perPage=50) {
- throw new \Exception();
+ public function getShareByToken($token) {
+ $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
+
+ $share = $provider->getShareByToken($token);
+
+ //TODO check if share expired
+
+ return $share;
}
/**
- * Get the share by token possible with password
+ * Verify the password of a public share
*
- * @param string $token
+ * @param \OCP\Share\IShare $share
* @param string $password
- *
- * @return Share
- *
- * @throws ShareNotFoundException
+ * @return bool
*/
- public function getShareByToken($token, $password=null) {
- throw new \Exception();
+ public function checkPassword(\OCP\Share\IShare $share, $password) {
+ if ($share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK) {
+ //TODO maybe exception?
+ return false;
+ }
+
+ if ($password === null || $share->getPassword() === null) {
+ return false;
+ }
+
+ $newHash = '';
+ if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
+ return false;
+ }
+
+ if (!empty($newHash)) {
+ $share->setPassword($newHash);
+ $provider = $this->factory->getProviderForType($share->getShareType());
+ $provider->update($share);
+ }
+
+ return true;
}
/**
@@ -207,6 +892,117 @@ class Manager {
* @param \OCP\Files\Node $path
*/
public function getAccessList(\OCP\Files\Node $path) {
- throw new \Exception();
}
+
+ /**
+ * Create a new share
+ * @return \OCP\Share\IShare;
+ */
+ public function newShare() {
+ return new \OC\Share20\Share($this->rootFolder);
+ }
+
+ /**
+ * Is the share API enabled
+ *
+ * @return bool
+ */
+ public function shareApiEnabled() {
+ return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
+ }
+
+ /**
+ * Is public link sharing enabled
+ *
+ * @return bool
+ */
+ public function shareApiAllowLinks() {
+ return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
+ }
+
+ /**
+ * Is password on public link requires
+ *
+ * @return bool
+ */
+ public function shareApiLinkEnforcePassword() {
+ return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
+ }
+
+ /**
+ * Is default expire date enabled
+ *
+ * @return bool
+ */
+ public function shareApiLinkDefaultExpireDate() {
+ return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
+ }
+
+ /**
+ * Is default expire date enforced
+ *`
+ * @return bool
+ */
+ public function shareApiLinkDefaultExpireDateEnforced() {
+ return $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
+ }
+
+ /**
+ * Number of default expire days
+ *shareApiLinkAllowPublicUpload
+ * @return int
+ */
+ public function shareApiLinkDefaultExpireDays() {
+ return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
+ }
+
+ /**
+ * Allow public upload on link shares
+ *
+ * @return bool
+ */
+ public function shareApiLinkAllowPublicUpload() {
+ return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
+ }
+
+ /**
+ * check if user can only share with group members
+ * @return bool
+ */
+ public function shareWithGroupMembersOnly() {
+ return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
+ }
+
+
+ /**
+ * Copied from \OC_Util::isSharingDisabledForUser
+ *
+ * TODO: Deprecate fuction from OC_Util
+ *
+ * @param string $userId
+ * @return bool
+ */
+ public function sharingDisabledForUser($userId) {
+ if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
+ $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
+ $excludedGroups = json_decode($groupsList);
+ if (is_null($excludedGroups)) {
+ $excludedGroups = explode(',', $groupsList);
+ $newValue = json_encode($excludedGroups);
+ $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
+ }
+ $user = $this->userManager->get($userId);
+ $usersGroups = $this->groupManager->getUserGroupIds($user);
+ if (!empty($usersGroups)) {
+ $remainingGroups = array_diff($usersGroups, $excludedGroups);
+ // if the user is only in groups which are disabled for sharing then
+ // sharing is also disabled for the user
+ if (empty($remainingGroups)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
}
diff --git a/lib/private/share20/providerfactory.php b/lib/private/share20/providerfactory.php
new file mode 100644
index 00000000000..64147355596
--- /dev/null
+++ b/lib/private/share20/providerfactory.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20;
+
+use OCP\Share\IProviderFactory;
+use OC\Share20\Exception\ProviderException;
+use OCP\IServerContainer;
+
+/**
+ * Class ProviderFactory
+ *
+ * @package OC\Share20
+ */
+class ProviderFactory implements IProviderFactory {
+
+ /** @var IServerContainer */
+ private $serverContainer;
+ /** @var DefaultShareProvider */
+ private $defaultProvider = null;
+
+ /**
+ * IProviderFactory constructor.
+ * @param IServerContainer $serverContainer
+ */
+ public function __construct(IServerContainer $serverContainer) {
+ $this->serverContainer = $serverContainer;
+ }
+
+ /**
+ * Create the default share provider.
+ *
+ * @return DefaultShareProvider
+ */
+ protected function defaultShareProvider() {
+ if ($this->defaultProvider === null) {
+ $this->defaultProvider = new DefaultShareProvider(
+ $this->serverContainer->getDatabaseConnection(),
+ $this->serverContainer->getUserManager(),
+ $this->serverContainer->getGroupManager(),
+ $this->serverContainer->getRootFolder()
+ );
+ }
+
+ return $this->defaultProvider;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getProvider($id) {
+ if ($id === 'ocinternal') {
+ return $this->defaultShareProvider();
+ }
+
+ throw new ProviderException('No provider with id .' . $id . ' found.');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getProviderForType($shareType) {
+ //FIXME we should not report type 2
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER ||
+ $shareType === 2 ||
+ $shareType === \OCP\Share::SHARE_TYPE_GROUP ||
+ $shareType === \OCP\Share::SHARE_TYPE_LINK) {
+ return $this->defaultShareProvider();
+ }
+
+ throw new ProviderException('No share provider for share type ' . $shareType);
+ }
+}
diff --git a/lib/private/share20/share.php b/lib/private/share20/share.php
index 4200816799e..cd30f24c42e 100644
--- a/lib/private/share20/share.php
+++ b/lib/private/share20/share.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -20,23 +20,32 @@
*/
namespace OC\Share20;
+use OCP\Files\File;
+use OCP\Files\IRootFolder;
use OCP\Files\Node;
+use OCP\Files\NotFoundException;
use OCP\IUser;
use OCP\IGroup;
-class Share implements IShare {
+class Share implements \OCP\Share\IShare {
/** @var string */
private $id;
+ /** @var string */
+ private $providerId;
/** @var Node */
- private $path;
+ private $node;
+ /** @var int */
+ private $fileId;
+ /** @var string */
+ private $nodeType;
/** @var int */
private $shareType;
- /** @var IUser|IGroup|string */
+ /** @var string */
private $sharedWith;
- /** @var IUser|string */
+ /** @var string */
private $sharedBy;
- /** @var IUser|string */
+ /** @var string */
private $shareOwner;
/** @var int */
private $permissions;
@@ -50,16 +59,20 @@ class Share implements IShare {
private $parent;
/** @var string */
private $target;
- /** @var int */
+ /** @var \DateTime */
private $shareTime;
/** @var bool */
private $mailSend;
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ public function __construct(IRootFolder $rootFolder) {
+ $this->rootFolder = $rootFolder;
+ }
+
/**
- * Set the id of the share
- *
- * @param int id
- * @return Share The modified object
+ * @inheritdoc
*/
public function setId($id) {
$this->id = $id;
@@ -67,39 +80,105 @@ class Share implements IShare {
}
/**
- * Get the id of the share
- *
- * @return string
+ * @inheritdoc
*/
public function getId() {
return $this->id;
}
/**
- * Set the path of this share
- *
- * @param Node $path
- * @return Share The modified object
+ * @inheritdoc
+ */
+ public function getFullId() {
+ return $this->providerId . ':' . $this->id;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function setProviderId($id) {
+ $this->providerId = $id;
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function setNode(Node $node) {
+ $this->fileId = null;
+ $this->nodeType = null;
+ $this->node = $node;
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getNode() {
+ if ($this->node === null) {
+
+ if ($this->shareOwner === null || $this->fileId === null) {
+ throw new NotFoundException();
+ }
+
+ $userFolder = $this->rootFolder->getUserFolder($this->shareOwner);
+
+ $nodes = $userFolder->getById($this->fileId);
+ if (empty($nodes)) {
+ throw new NotFoundException();
+ }
+
+ $this->node = $nodes[0];
+ }
+
+ return $this->node;
+ }
+
+ /**
+ * @inheritdoc
*/
- public function setPath(Node $path) {
- $this->path = $path;
+ public function setNodeId($fileId) {
+ $this->node = null;
+ $this->fileId = $fileId;
return $this;
}
/**
- * Get the path of this share for the current user
- *
- * @return Node
+ * @inheritdoc
*/
- public function getPath() {
- return $this->path;
+ public function getNodeId() {
+ if ($this->fileId === null) {
+ $this->fileId = $this->getNode()->getId();
+ }
+
+ return $this->fileId;
}
/**
- * Set the shareType
- *
- * @param int $shareType
- * @return Share The modified object
+ * @inheritdoc
+ */
+ public function setNodeType($type) {
+ if ($type !== 'file' && $type !== 'folder') {
+ throw new \InvalidArgumentException();
+ }
+
+ $this->nodeType = $type;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getNodeType() {
+ if ($this->nodeType === null) {
+ $node = $this->getNode();
+ $this->nodeType = $node instanceof File ? 'file' : 'folder';
+ }
+
+ return $this->nodeType;
+ }
+
+ /**
+ * @inheritdoc
*/
public function setShareType($shareType) {
$this->shareType = $shareType;
@@ -107,39 +186,32 @@ class Share implements IShare {
}
/**
- * Get the shareType
- *
- * @return int
+ * @inheritdoc
*/
public function getShareType() {
return $this->shareType;
}
/**
- * Set the receiver of this share
- *
- * @param IUser|IGroup|string
- * @return Share The modified object
+ * @inheritdoc
*/
public function setSharedWith($sharedWith) {
+ if (!is_string($sharedWith)) {
+ throw new \InvalidArgumentException();
+ }
$this->sharedWith = $sharedWith;
return $this;
}
/**
- * Get the receiver of this share
- *
- * @return IUser|IGroup|string
+ * @inheritdoc
*/
public function getSharedWith() {
return $this->sharedWith;
}
/**
- * Set the permissions
- *
- * @param int $permissions
- * @return Share The modified object
+ * @inheritdoc
*/
public function setPermissions($permissions) {
//TODO checkes
@@ -149,21 +221,16 @@ class Share implements IShare {
}
/**
- * Get the share permissions
- *
- * @return int
+ * @inheritdoc
*/
public function getPermissions() {
return $this->permissions;
}
/**
- * Set the expiration date
- *
- * @param \DateTime $expireDate
- * @return Share The modified object
+ * @inheritdoc
*/
- public function setExpirationDate(\DateTime $expireDate) {
+ public function setExpirationDate($expireDate) {
//TODO checks
$this->expireDate = $expireDate;
@@ -171,21 +238,19 @@ class Share implements IShare {
}
/**
- * Get the share expiration date
- *
- * @return \DateTime
+ * @inheritdoc
*/
public function getExpirationDate() {
return $this->expireDate;
}
/**
- * Set the sharer of the path
- *
- * @param IUser|string $sharedBy
- * @return Share The modified object
+ * @inheritdoc
*/
public function setSharedBy($sharedBy) {
+ if (!is_string($sharedBy)) {
+ throw new \InvalidArgumentException();
+ }
//TODO checks
$this->sharedBy = $sharedBy;
@@ -193,9 +258,7 @@ class Share implements IShare {
}
/**
- * Get share sharer
- *
- * @return IUser|string
+ * @inheritdoc
*/
public function getSharedBy() {
//TODO check if set
@@ -203,13 +266,12 @@ class Share implements IShare {
}
/**
- * Set the original share owner (who owns the path)
- *
- * @param IUser|string
- *
- * @return Share The modified object
+ * @inheritdoc
*/
public function setShareOwner($shareOwner) {
+ if (!is_string($shareOwner)) {
+ throw new \InvalidArgumentException();
+ }
//TODO checks
$this->shareOwner = $shareOwner;
@@ -217,9 +279,7 @@ class Share implements IShare {
}
/**
- * Get the original share owner (who owns the path)
- *
- * @return IUser|string
+ * @inheritdoc
*/
public function getShareOwner() {
//TODO check if set
@@ -227,33 +287,22 @@ class Share implements IShare {
}
/**
- * Set the password
- *
- * @param string $password
- *
- * @return Share The modified object
+ * @inheritdoc
*/
public function setPassword($password) {
- //TODO verify
-
$this->password = $password;
return $this;
}
/**
- * Get the password
- *
- * @return string
+ * @inheritdoc
*/
public function getPassword() {
return $this->password;
}
/**
- * Set the token
- *
- * @param string $token
- * @return Share The modified object
+ * @inheritdoc
*/
public function setToken($token) {
$this->token = $token;
@@ -261,19 +310,14 @@ class Share implements IShare {
}
/**
- * Get the token
- *
- * @return string
+ * @inheritdoc
*/
public function getToken() {
return $this->token;
}
/**
- * Set the parent id of this share
- *
- * @param int $parent
- * @return Share The modified object
+ * @inheritdoc
*/
public function setParent($parent) {
$this->parent = $parent;
@@ -281,19 +325,14 @@ class Share implements IShare {
}
/**
- * Get the parent id of this share
- *
- * @return int
+ * @inheritdoc
*/
public function getParent() {
return $this->parent;
}
/**
- * Set the target of this share
- *
- * @param string target
- * @return Share The modified object
+ * @inheritdoc
*/
public function setTarget($target) {
$this->target = $target;
@@ -301,39 +340,29 @@ class Share implements IShare {
}
/**
- * Get the target of this share
- *
- * @return string
+ * @inheritdoc
*/
public function getTarget() {
return $this->target;
}
/**
- * Set the time this share was created
- *
- * @param int $shareTime
- * @return Share The modified object
+ * @inheritdoc
*/
- public function setShareTime($shareTime) {
+ public function setShareTime(\DateTime $shareTime) {
$this->shareTime = $shareTime;
return $this;
}
/**
- * Get the timestamp this share was created
- *
- * @return int
+ * @inheritdoc
*/
- public function getSharetime() {
+ public function getShareTime() {
return $this->shareTime;
}
/**
- * Set mailSend
- *
- * @param bool $mailSend
- * @return Share The modified object
+ * @inheritdoc
*/
public function setMailSend($mailSend) {
$this->mailSend = $mailSend;
@@ -341,9 +370,7 @@ class Share implements IShare {
}
/**
- * Get mailSend
- *
- * @return bool
+ * @inheritdoc
*/
public function getMailSend() {
return $this->mailSend;
diff --git a/lib/private/streamer.php b/lib/private/streamer.php
index aa819c560a1..5fffa7ac368 100644
--- a/lib/private/streamer.php
+++ b/lib/private/streamer.php
@@ -4,7 +4,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/subadmin.php b/lib/private/subadmin.php
index c96275e3b87..34dd40c22ff 100644
--- a/lib/private/subadmin.php
+++ b/lib/private/subadmin.php
@@ -1,13 +1,13 @@
<?php
/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Georg Ehrke <georg@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/systemconfig.php b/lib/private/systemconfig.php
index 94b815aebd7..9f99216fa4e 100644
--- a/lib/private/systemconfig.php
+++ b/lib/private/systemconfig.php
@@ -2,8 +2,9 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -44,12 +45,19 @@ class SystemConfig {
'objectstore' => ['arguments' => ['password' => true]],
];
+ /** @var Config */
+ private $config;
+
+ public function __construct(Config $config) {
+ $this->config = $config;
+ }
+
/**
* Lists all available config keys
* @return array an array of key names
*/
public function getKeys() {
- return \OC_Config::getKeys();
+ return $this->config->getKeys();
}
/**
@@ -59,7 +67,7 @@ class SystemConfig {
* @param mixed $value the value that should be stored
*/
public function setValue($key, $value) {
- \OC_Config::setValue($key, $value);
+ $this->config->setValue($key, $value);
}
/**
@@ -69,7 +77,7 @@ class SystemConfig {
* If value is null, the config key will be deleted
*/
public function setValues(array $configs) {
- \OC_Config::setValues($configs);
+ $this->config->setValues($configs);
}
/**
@@ -80,7 +88,7 @@ class SystemConfig {
* @return mixed the value or $default
*/
public function getValue($key, $default = '') {
- return \OC_Config::getValue($key, $default);
+ return $this->config->getValue($key, $default);
}
/**
@@ -106,7 +114,7 @@ class SystemConfig {
* @param string $key the key of the value, under which it was saved
*/
public function deleteValue($key) {
- \OC_Config::deleteKey($key);
+ $this->config->deleteKey($key);
}
/**
diff --git a/lib/private/systemtag/managerfactory.php b/lib/private/systemtag/managerfactory.php
new file mode 100644
index 00000000000..7ad4f922600
--- /dev/null
+++ b/lib/private/systemtag/managerfactory.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\SystemTag;
+
+use OCP\IServerContainer;
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ISystemTagManagerFactory;
+use OCP\SystemTag\ISystemTagObjectMapper;
+
+/**
+ * Default factory class for system tag managers
+ *
+ * @package OCP\SystemTag
+ * @since 9.0.0
+ */
+class ManagerFactory implements ISystemTagManagerFactory {
+
+ /**
+ * Server container
+ *
+ * @var IServerContainer
+ */
+ private $serverContainer;
+
+ /**
+ * Constructor for the system tag manager factory
+ *
+ * @param IServerContainer $serverContainer server container
+ */
+ public function __construct(IServerContainer $serverContainer) {
+ $this->serverContainer = $serverContainer;
+ }
+
+ /**
+ * Creates and returns an instance of the system tag manager
+ *
+ * @return ISystemTagManager
+ * @since 9.0.0
+ */
+ public function getManager() {
+ return new SystemTagManager(
+ $this->serverContainer->getDatabaseConnection(),
+ $this->serverContainer->getEventDispatcher()
+ );
+ }
+
+ /**
+ * Creates and returns an instance of the system tag object
+ * mapper
+ *
+ * @return ISystemTagObjectMapper
+ * @since 9.0.0
+ */
+ public function getObjectMapper() {
+ return new SystemTagObjectMapper(
+ $this->serverContainer->getDatabaseConnection(),
+ $this->getManager(),
+ $this->serverContainer->getEventDispatcher()
+ );
+ }
+}
diff --git a/lib/private/systemtag/systemtag.php b/lib/private/systemtag/systemtag.php
new file mode 100644
index 00000000000..559b6fdefa8
--- /dev/null
+++ b/lib/private/systemtag/systemtag.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\SystemTag;
+
+use OCP\SystemTag\ISystemTag;
+
+class SystemTag implements ISystemTag {
+
+ /**
+ * @var string
+ */
+ private $id;
+
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var bool
+ */
+ private $userVisible;
+
+ /**
+ * @var bool
+ */
+ private $userAssignable;
+
+ /**
+ * Constructor.
+ *
+ * @param string $id tag id
+ * @param string $name tag name
+ * @param bool $userVisible whether the tag is user visible
+ * @param bool $userAssignable whether the tag is user assignable
+ */
+ public function __construct($id, $name, $userVisible, $userAssignable) {
+ $this->id = $id;
+ $this->name = $name;
+ $this->userVisible = $userVisible;
+ $this->userAssignable = $userAssignable;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getId() {
+ return $this->id;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isUserVisible() {
+ return $this->userVisible;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isUserAssignable() {
+ return $this->userAssignable;
+ }
+}
diff --git a/lib/private/systemtag/systemtagmanager.php b/lib/private/systemtag/systemtagmanager.php
new file mode 100644
index 00000000000..76a60a91328
--- /dev/null
+++ b/lib/private/systemtag/systemtagmanager.php
@@ -0,0 +1,322 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\SystemTag;
+
+use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ManagerEvent;
+use OCP\SystemTag\TagAlreadyExistsException;
+use OCP\SystemTag\TagNotFoundException;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+
+class SystemTagManager implements ISystemTagManager {
+
+ const TAG_TABLE = 'systemtag';
+
+ /** @var IDBConnection */
+ protected $connection;
+
+ /** @var EventDispatcherInterface */
+ protected $dispatcher;
+
+ /**
+ * Prepared query for selecting tags directly
+ *
+ * @var \OCP\DB\QueryBuilder\IQueryBuilder
+ */
+ private $selectTagQuery;
+
+ /**
+ * Constructor.
+ *
+ * @param IDBConnection $connection database connection
+ * @param EventDispatcherInterface $dispatcher
+ */
+ public function __construct(IDBConnection $connection, EventDispatcherInterface $dispatcher) {
+ $this->connection = $connection;
+ $this->dispatcher = $dispatcher;
+
+ $query = $this->connection->getQueryBuilder();
+ $this->selectTagQuery = $query->select('*')
+ ->from(self::TAG_TABLE)
+ ->where($query->expr()->eq('name', $query->createParameter('name')))
+ ->andWhere($query->expr()->eq('visibility', $query->createParameter('visibility')))
+ ->andWhere($query->expr()->eq('editable', $query->createParameter('editable')));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTagsByIds($tagIds) {
+ if (!is_array($tagIds)) {
+ $tagIds = [$tagIds];
+ }
+
+ $tags = [];
+
+ // note: not all databases will fail if it's a string or starts with a number
+ foreach ($tagIds as $tagId) {
+ if (!is_numeric($tagId)) {
+ throw new \InvalidArgumentException('Tag id must be integer');
+ }
+ }
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from(self::TAG_TABLE)
+ ->where($query->expr()->in('id', $query->createParameter('tagids')))
+ ->addOrderBy('name', 'ASC')
+ ->addOrderBy('visibility', 'ASC')
+ ->addOrderBy('editable', 'ASC')
+ ->setParameter('tagids', $tagIds, IQueryBuilder::PARAM_INT_ARRAY);
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ $tags[$row['id']] = $this->createSystemTagFromRow($row);
+ }
+
+ $result->closeCursor();
+
+ if (count($tags) !== count($tagIds)) {
+ throw new TagNotFoundException(
+ 'Tag id(s) not found', 0, null, array_diff($tagIds, array_keys($tags))
+ );
+ }
+
+ return $tags;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAllTags($visibilityFilter = null, $nameSearchPattern = null) {
+ $tags = [];
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from(self::TAG_TABLE);
+
+ if (!is_null($visibilityFilter)) {
+ $query->andWhere($query->expr()->eq('visibility', $query->createNamedParameter((int)$visibilityFilter)));
+ }
+
+ if (!empty($nameSearchPattern)) {
+ $query->andWhere(
+ $query->expr()->like(
+ 'name',
+ $query->expr()->literal('%' . $this->connection->escapeLikeParameter($nameSearchPattern). '%')
+ )
+ );
+ }
+
+ $query
+ ->addOrderBy('name', 'ASC')
+ ->addOrderBy('visibility', 'ASC')
+ ->addOrderBy('editable', 'ASC');
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ $tags[$row['id']] = $this->createSystemTagFromRow($row);
+ }
+
+ $result->closeCursor();
+
+ return $tags;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTag($tagName, $userVisible, $userAssignable) {
+ $userVisible = (int)$userVisible;
+ $userAssignable = (int)$userAssignable;
+
+ $result = $this->selectTagQuery
+ ->setParameter('name', $tagName)
+ ->setParameter('visibility', $userVisible)
+ ->setParameter('editable', $userAssignable)
+ ->execute();
+
+ $row = $result->fetch();
+ $result->closeCursor();
+ if (!$row) {
+ throw new TagNotFoundException(
+ 'Tag ("' . $tagName . '", '. $userVisible . ', ' . $userAssignable . ') does not exist'
+ );
+ }
+
+ return $this->createSystemTagFromRow($row);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createTag($tagName, $userVisible, $userAssignable) {
+ $userVisible = (int)$userVisible;
+ $userAssignable = (int)$userAssignable;
+
+ $query = $this->connection->getQueryBuilder();
+ $query->insert(self::TAG_TABLE)
+ ->values([
+ 'name' => $query->createNamedParameter($tagName),
+ 'visibility' => $query->createNamedParameter($userVisible),
+ 'editable' => $query->createNamedParameter($userAssignable),
+ ]);
+
+ try {
+ $query->execute();
+ } catch (UniqueConstraintViolationException $e) {
+ throw new TagAlreadyExistsException(
+ 'Tag ("' . $tagName . '", '. $userVisible . ', ' . $userAssignable . ') already exists',
+ 0,
+ $e
+ );
+ }
+
+ $tagId = $query->getLastInsertId();
+
+ $tag = new SystemTag(
+ (int)$tagId,
+ $tagName,
+ (bool)$userVisible,
+ (bool)$userAssignable
+ );
+
+ $this->dispatcher->dispatch(ManagerEvent::EVENT_CREATE, new ManagerEvent(
+ ManagerEvent::EVENT_CREATE, $tag
+ ));
+
+ return $tag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function updateTag($tagId, $tagName, $userVisible, $userAssignable) {
+ $userVisible = (int)$userVisible;
+ $userAssignable = (int)$userAssignable;
+
+ try {
+ $tags = $this->getTagsByIds($tagId);
+ } catch (TagNotFoundException $e) {
+ throw new TagNotFoundException(
+ 'Tag does not exist', 0, null, [$tagId]
+ );
+ }
+
+ $beforeUpdate = array_shift($tags);
+ $afterUpdate = new SystemTag(
+ (int) $tagId,
+ $tagName,
+ (bool) $userVisible,
+ (bool) $userAssignable
+ );
+
+ $query = $this->connection->getQueryBuilder();
+ $query->update(self::TAG_TABLE)
+ ->set('name', $query->createParameter('name'))
+ ->set('visibility', $query->createParameter('visibility'))
+ ->set('editable', $query->createParameter('editable'))
+ ->where($query->expr()->eq('id', $query->createParameter('tagid')))
+ ->setParameter('name', $tagName)
+ ->setParameter('visibility', $userVisible)
+ ->setParameter('editable', $userAssignable)
+ ->setParameter('tagid', $tagId);
+
+ try {
+ if ($query->execute() === 0) {
+ throw new TagNotFoundException(
+ 'Tag does not exist', 0, null, [$tagId]
+ );
+ }
+ } catch (UniqueConstraintViolationException $e) {
+ throw new TagAlreadyExistsException(
+ 'Tag ("' . $tagName . '", '. $userVisible . ', ' . $userAssignable . ') already exists',
+ 0,
+ $e
+ );
+ }
+
+ $this->dispatcher->dispatch(ManagerEvent::EVENT_UPDATE, new ManagerEvent(
+ ManagerEvent::EVENT_UPDATE, $afterUpdate, $beforeUpdate
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteTags($tagIds) {
+ if (!is_array($tagIds)) {
+ $tagIds = [$tagIds];
+ }
+
+ $tagNotFoundException = null;
+ $tags = [];
+ try {
+ $tags = $this->getTagsByIds($tagIds);
+ } catch (TagNotFoundException $e) {
+ $tagNotFoundException = $e;
+
+ // Get existing tag objects for the hooks later
+ $existingTags = array_diff($tagIds, $tagNotFoundException->getMissingTags());
+ if (!empty($existingTags)) {
+ try {
+ $tags = $this->getTagsByIds($existingTags);
+ } catch (TagNotFoundException $e) {
+ // Ignore further errors...
+ }
+ }
+ }
+
+ // delete relationships first
+ $query = $this->connection->getQueryBuilder();
+ $query->delete(SystemTagObjectMapper::RELATION_TABLE)
+ ->where($query->expr()->in('systemtagid', $query->createParameter('tagids')))
+ ->setParameter('tagids', $tagIds, IQueryBuilder::PARAM_INT_ARRAY)
+ ->execute();
+
+ $query = $this->connection->getQueryBuilder();
+ $query->delete(self::TAG_TABLE)
+ ->where($query->expr()->in('id', $query->createParameter('tagids')))
+ ->setParameter('tagids', $tagIds, IQueryBuilder::PARAM_INT_ARRAY)
+ ->execute();
+
+ foreach ($tags as $tag) {
+ $this->dispatcher->dispatch(ManagerEvent::EVENT_DELETE, new ManagerEvent(
+ ManagerEvent::EVENT_DELETE, $tag
+ ));
+ }
+
+ if ($tagNotFoundException !== null) {
+ throw new TagNotFoundException(
+ 'Tag id(s) not found', 0, $tagNotFoundException, $tagNotFoundException->getMissingTags()
+ );
+ }
+ }
+
+ private function createSystemTagFromRow($row) {
+ return new SystemTag((int)$row['id'], $row['name'], (bool)$row['visibility'], (bool)$row['editable']);
+ }
+}
diff --git a/lib/private/systemtag/systemtagobjectmapper.php b/lib/private/systemtag/systemtagobjectmapper.php
new file mode 100644
index 00000000000..1efb4f0f6e0
--- /dev/null
+++ b/lib/private/systemtag/systemtagobjectmapper.php
@@ -0,0 +1,249 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\SystemTag;
+
+use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\SystemTag\ISystemTag;
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ISystemTagObjectMapper;
+use OCP\SystemTag\MapperEvent;
+use OCP\SystemTag\TagNotFoundException;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+
+class SystemTagObjectMapper implements ISystemTagObjectMapper {
+
+ const RELATION_TABLE = 'systemtag_object_mapping';
+
+ /** @var ISystemTagManager */
+ protected $tagManager;
+
+ /** @var IDBConnection */
+ protected $connection;
+
+ /** @var EventDispatcherInterface */
+ protected $dispatcher;
+
+ /**
+ * Constructor.
+ *
+ * @param IDBConnection $connection database connection
+ * @param ISystemTagManager $tagManager system tag manager
+ * @param EventDispatcherInterface $dispatcher
+ */
+ public function __construct(IDBConnection $connection, ISystemTagManager $tagManager, EventDispatcherInterface $dispatcher) {
+ $this->connection = $connection;
+ $this->tagManager = $tagManager;
+ $this->dispatcher = $dispatcher;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTagIdsForObjects($objIds, $objectType) {
+ if (!is_array($objIds)) {
+ $objIds = [$objIds];
+ }
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select(['systemtagid', 'objectid'])
+ ->from(self::RELATION_TABLE)
+ ->where($query->expr()->in('objectid', $query->createParameter('objectids')))
+ ->andWhere($query->expr()->eq('objecttype', $query->createParameter('objecttype')))
+ ->setParameter('objectids', $objIds, IQueryBuilder::PARAM_INT_ARRAY)
+ ->setParameter('objecttype', $objectType)
+ ->addOrderBy('objectid', 'ASC')
+ ->addOrderBy('systemtagid', 'ASC');
+
+ $mapping = [];
+ foreach ($objIds as $objId) {
+ $mapping[$objId] = [];
+ }
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ $objectId = $row['objectid'];
+ $mapping[$objectId][] = $row['systemtagid'];
+ }
+
+ $result->closeCursor();
+
+ return $mapping;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getObjectIdsForTags($tagIds, $objectType) {
+ if (!is_array($tagIds)) {
+ $tagIds = [$tagIds];
+ }
+
+ $this->assertTagsExist($tagIds);
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select($query->createFunction('DISTINCT(`objectid`)'))
+ ->from(self::RELATION_TABLE)
+ ->where($query->expr()->in('systemtagid', $query->createParameter('tagids')))
+ ->andWhere($query->expr()->eq('objecttype', $query->createParameter('objecttype')))
+ ->setParameter('tagids', $tagIds, IQueryBuilder::PARAM_INT_ARRAY)
+ ->setParameter('objecttype', $objectType);
+
+ $objectIds = [];
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ $objectIds[] = $row['objectid'];
+ }
+
+ return $objectIds;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function assignTags($objId, $objectType, $tagIds) {
+ if (!is_array($tagIds)) {
+ $tagIds = [$tagIds];
+ }
+
+ $this->assertTagsExist($tagIds);
+
+ $query = $this->connection->getQueryBuilder();
+ $query->insert(self::RELATION_TABLE)
+ ->values([
+ 'objectid' => $query->createNamedParameter($objId),
+ 'objecttype' => $query->createNamedParameter($objectType),
+ 'systemtagid' => $query->createParameter('tagid'),
+ ]);
+
+ foreach ($tagIds as $tagId) {
+ try {
+ $query->setParameter('tagid', $tagId);
+ $query->execute();
+ } catch (UniqueConstraintViolationException $e) {
+ // ignore existing relations
+ }
+ }
+
+ $this->dispatcher->dispatch(MapperEvent::EVENT_ASSIGN, new MapperEvent(
+ MapperEvent::EVENT_ASSIGN,
+ $objectType,
+ $objId,
+ $tagIds
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function unassignTags($objId, $objectType, $tagIds) {
+ if (!is_array($tagIds)) {
+ $tagIds = [$tagIds];
+ }
+
+ $this->assertTagsExist($tagIds);
+
+ $query = $this->connection->getQueryBuilder();
+ $query->delete(self::RELATION_TABLE)
+ ->where($query->expr()->eq('objectid', $query->createParameter('objectid')))
+ ->andWhere($query->expr()->eq('objecttype', $query->createParameter('objecttype')))
+ ->andWhere($query->expr()->in('systemtagid', $query->createParameter('tagids')))
+ ->setParameter('objectid', $objId)
+ ->setParameter('objecttype', $objectType)
+ ->setParameter('tagids', $tagIds, IQueryBuilder::PARAM_INT_ARRAY)
+ ->execute();
+
+ $this->dispatcher->dispatch(MapperEvent::EVENT_UNASSIGN, new MapperEvent(
+ MapperEvent::EVENT_UNASSIGN,
+ $objectType,
+ $objId,
+ $tagIds
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function haveTag($objIds, $objectType, $tagId, $all = true) {
+ $this->assertTagsExist([$tagId]);
+
+ if (!is_array($objIds)) {
+ $objIds = [$objIds];
+ }
+
+ $query = $this->connection->getQueryBuilder();
+
+ if (!$all) {
+ // If we only need one entry, we make the query lighter, by not
+ // counting the elements
+ $query->select('*')
+ ->setMaxResults(1);
+ } else {
+ $query->select($query->createFunction('COUNT(1)'));
+ }
+
+ $query->from(self::RELATION_TABLE)
+ ->where($query->expr()->in('objectid', $query->createParameter('objectids')))
+ ->andWhere($query->expr()->eq('objecttype', $query->createParameter('objecttype')))
+ ->andWhere($query->expr()->eq('systemtagid', $query->createParameter('tagid')))
+ ->setParameter('objectids', $objIds, IQueryBuilder::PARAM_INT_ARRAY)
+ ->setParameter('tagid', $tagId)
+ ->setParameter('objecttype', $objectType);
+
+ $result = $query->execute();
+ $row = $result->fetch(\PDO::FETCH_NUM);
+ $result->closeCursor();
+
+ if ($all) {
+ return ((int)$row[0] === count($objIds));
+ } else {
+ return (bool) $row;
+ }
+ }
+
+ /**
+ * Asserts that all the given tag ids exist.
+ *
+ * @param string[] $tagIds tag ids to check
+ *
+ * @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist
+ */
+ private function assertTagsExist($tagIds) {
+ $tags = $this->tagManager->getTagsByIds($tagIds);
+ if (count($tags) !== count($tagIds)) {
+ // at least one tag missing, bail out
+ $foundTagIds = array_map(
+ function(ISystemTag $tag) {
+ return $tag->getId();
+ },
+ $tags
+ );
+ $missingTagIds = array_diff($tagIds, $foundTagIds);
+ throw new TagNotFoundException(
+ 'Tags not found', 0, null, $missingTagIds
+ );
+ }
+ }
+}
diff --git a/lib/private/tagging/tag.php b/lib/private/tagging/tag.php
index 4531cae53a7..e35ac433e00 100644
--- a/lib/private/tagging/tag.php
+++ b/lib/private/tagging/tag.php
@@ -3,7 +3,7 @@
* @author Bernhard Reiter <ockham@raz.or.at>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/tagging/tagmapper.php b/lib/private/tagging/tagmapper.php
index 38ea735b102..364dbc99b4d 100644
--- a/lib/private/tagging/tagmapper.php
+++ b/lib/private/tagging/tagmapper.php
@@ -4,7 +4,7 @@
* @author Bernhard Reiter <ockham@raz.or.at>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/tagmanager.php b/lib/private/tagmanager.php
index 5e72eb41d16..a9e1cdfe076 100644
--- a/lib/private/tagmanager.php
+++ b/lib/private/tagmanager.php
@@ -5,7 +5,7 @@
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/tags.php b/lib/private/tags.php
index 09cb7618c02..cf39a9a9759 100644
--- a/lib/private/tags.php
+++ b/lib/private/tags.php
@@ -6,12 +6,12 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -41,8 +41,9 @@
namespace OC;
-use \OC\Tagging\Tag;
-use \OC\Tagging\TagMapper;
+use OC\Tagging\Tag;
+use OC\Tagging\TagMapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
class Tags implements \OCP\ITags {
@@ -215,7 +216,7 @@ class Tags implements \OCP\ITags {
$entries = array();
try {
- $conn = \OC_DB::getConnection();
+ $conn = \OC::$server->getDatabaseConnection();
$chunks = array_chunk($objIds, 900, false);
foreach ($chunks as $chunk) {
$result = $conn->executeQuery(
@@ -223,7 +224,7 @@ class Tags implements \OCP\ITags {
'FROM `' . self::RELATION_TABLE . '` r, `' . self::TAG_TABLE . '` ' .
'WHERE `categoryid` = `id` AND `uid` = ? AND r.`type` = ? AND `objid` IN (?)',
array($this->user, $this->type, $chunk),
- array(null, null, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
+ array(null, null, IQueryBuilder::PARAM_INT_ARRAY)
);
while ($row = $result->fetch()) {
$objId = (int)$row['objid'];
diff --git a/lib/private/template.php b/lib/private/template.php
index 97666f0b8dc..ae3e857a798 100644
--- a/lib/private/template.php
+++ b/lib/private/template.php
@@ -4,19 +4,20 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
* @author Brice Maron <brice@bmaron.net>
- * @author drarko <drarko@users.noreply.github.com>
* @author Frank Karlitschek <frank@owncloud.org>
+ * @author Hendrik Leppelsack <hendrik@leppelsack.de>
* @author Individual IT Services <info@individual-it.net>
* @author Jakob Sack <mail@jakobsack.de>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Raghu Nayyar <hey@raghunayyar.com>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -75,7 +76,7 @@ class OC_Template extends \OC\Template\Base {
$theme = OC_Util::getTheme();
- $requesttoken = (OC::$server->getSession() and $registerCall) ? OC_Util::callRegister() : '';
+ $requestToken = (OC::$server->getSession() && $registerCall) ? \OCP\Util::callRegister() : '';
$parts = explode('/', $app); // fix translation when app is something like core/lostpassword
$l10n = \OC::$server->getL10N($parts[0]);
@@ -88,7 +89,7 @@ class OC_Template extends \OC\Template\Base {
$this->path = $path;
$this->app = $app;
- parent::__construct($template, $requesttoken, $l10n, $themeDefaults);
+ parent::__construct($template, $requestToken, $l10n, $themeDefaults);
}
public static function initTemplateEngine($renderAs) {
@@ -119,7 +120,6 @@ class OC_Template extends \OC\Template\Base {
// avatars
if (\OC::$server->getSystemConfig()->getValue('enable_avatars', true) === true) {
- \OC_Util::addScript('avatar', null, true);
\OC_Util::addScript('jquery.avatar', null, true);
\OC_Util::addScript('placeholder', null, true);
}
@@ -143,7 +143,9 @@ class OC_Template extends \OC\Template\Base {
OC_Util::addStyle("jquery.ocdialog");
OC_Util::addScript("compatibility", null, true);
OC_Util::addScript("placeholders", null, true);
-
+ OC_Util::addScript('files/fileinfo');
+ OC_Util::addScript('files/client');
+
// Add the stuff we need always
// following logic will import all vendor libraries that are
// specified in core/js/core.json
@@ -158,7 +160,14 @@ class OC_Template extends \OC\Template\Base {
} else {
throw new \Exception('Cannot read core/js/core.json');
}
-
+
+ if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE])) {
+ // polyfill for btoa/atob for IE friends
+ OC_Util::addVendorScript('base64/base64');
+ // shim for the davclient.js library
+ \OCP\Util::addScript('files/iedavclient');
+ }
+
self::$initTemplateEngineFirstRun = false;
}
@@ -214,17 +223,17 @@ class OC_Template extends \OC\Template\Base {
$data = parent::fetchPage();
if( $this->renderAs ) {
- $page = new OC_TemplateLayout($this->renderAs, $this->app);
+ $page = new \OC\TemplateLayout($this->renderAs, $this->app);
// Add custom headers
$headers = '';
foreach(OC_Util::$headers as $header) {
- $headers .= '<'.OC_Util::sanitizeHTML($header['tag']);
+ $headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']);
foreach($header['attributes'] as $name=>$value) {
- $headers .= ' '.OC_Util::sanitizeHTML($name).'="'.OC_Util::sanitizeHTML($value).'"';
+ $headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
}
if ($header['text'] !== null) {
- $headers .= '>'.OC_Util::sanitizeHTML($header['text']).'</'.OC_Util::sanitizeHTML($header['tag']).'>';
+ $headers .= '>'.\OCP\Util::sanitizeHTML($header['text']).'</'.\OCP\Util::sanitizeHTML($header['tag']).'>';
} else {
$headers .= '/>';
}
diff --git a/lib/private/template/base.php b/lib/private/template/base.php
index a18c43bb2ca..938cca4c38d 100644
--- a/lib/private/template/base.php
+++ b/lib/private/template/base.php
@@ -7,7 +7,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -34,12 +34,13 @@ class Base {
/**
* @param string $template
+ * @param string $requestToken
* @param \OC_L10N $l10n
* @param \OC_Defaults $theme
*/
- public function __construct( $template, $requesttoken, $l10n, $theme ) {
+ public function __construct($template, $requestToken, $l10n, $theme ) {
$this->vars = array();
- $this->vars['requesttoken'] = $requesttoken;
+ $this->vars['requesttoken'] = $requestToken;
$this->l10n = $l10n;
$this->template = $template;
$this->theme = $theme;
diff --git a/lib/private/template/cssresourcelocator.php b/lib/private/template/cssresourcelocator.php
index a78b0223389..6a547931ee3 100644
--- a/lib/private/template/cssresourcelocator.php
+++ b/lib/private/template/cssresourcelocator.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/template/functions.php b/lib/private/template/functions.php
index 1c6eaa9a389..a57b3575ba9 100644
--- a/lib/private/template/functions.php
+++ b/lib/private/template/functions.php
@@ -7,11 +7,12 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,10 +31,10 @@
/**
* Prints a sanitized string
- * @param string|array $string the string which will be escaped and printed
+ * @param string $string the string which will be escaped and printed
*/
function p($string) {
- print(OC_Util::sanitizeHTML($string));
+ print(\OCP\Util::sanitizeHTML($string));
}
/**
@@ -137,16 +138,16 @@ function component($app, $file) {
}
/**
- * make OC_Helper::linkTo available as a simple function
+ * make \OCP\IURLGenerator::linkTo available as a simple function
* @param string $app app
* @param string $file file
* @param array $args array with param=>value, will be appended to the returned url
* @return string link to the file
*
- * For further information have a look at OC_Helper::linkTo
+ * For further information have a look at \OCP\IURLGenerator::linkTo
*/
function link_to( $app, $file, $args = array() ) {
- return OC_Helper::linkTo( $app, $file, $args );
+ return \OC::$server->getURLGenerator()->linkTo($app, $file, $args);
}
/**
@@ -154,30 +155,28 @@ function link_to( $app, $file, $args = array() ) {
* @return string url to the online documentation
*/
function link_to_docs($key) {
- return OC_Helper::linkToDocs($key);
+ return \OC::$server->getURLGenerator()->linkToDocs($key);
}
/**
- * make OC_Helper::imagePath available as a simple function
+ * make \OCP\IURLGenerator::imagePath available as a simple function
* @param string $app app
* @param string $image image
* @return string link to the image
*
- * For further information have a look at OC_Helper::imagePath
+ * For further information have a look at \OCP\IURLGenerator::imagePath
*/
function image_path( $app, $image ) {
- return OC_Helper::imagePath( $app, $image );
+ return \OC::$server->getURLGenerator()->imagePath( $app, $image );
}
/**
* make OC_Helper::mimetypeIcon available as a simple function
* @param string $mimetype mimetype
* @return string link to the image
- *
- * For further information have a look at OC_Helper::mimetypeIcon
*/
function mimetype_icon( $mimetype ) {
- return OC_Helper::mimetypeIcon( $mimetype );
+ return \OC::$server->getMimeTypeDetector()->mimeTypeIcon( $mimetype );
}
/**
@@ -262,7 +261,7 @@ function html_select_options($options, $selected, $params=array()) {
$label = $label[$label_name];
}
$select = in_array($value, $selected) ? ' selected="selected"' : '';
- $html .= '<option value="' . OC_Util::sanitizeHTML($value) . '"' . $select . '>' . OC_Util::sanitizeHTML($label) . '</option>'."\n";
+ $html .= '<option value="' . \OCP\Util::sanitizeHTML($value) . '"' . $select . '>' . \OCP\Util::sanitizeHTML($label) . '</option>'."\n";
}
return $html;
}
diff --git a/lib/private/template/jsresourcelocator.php b/lib/private/template/jsresourcelocator.php
index c0127a0f278..4df1ac8c7f0 100644
--- a/lib/private/template/jsresourcelocator.php
+++ b/lib/private/template/jsresourcelocator.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/template/resourcelocator.php b/lib/private/template/resourcelocator.php
index 136a40e4def..e64fce81afc 100644
--- a/lib/private/template/resourcelocator.php
+++ b/lib/private/template/resourcelocator.php
@@ -4,9 +4,9 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/template/resourcenotfoundexception.php b/lib/private/template/resourcenotfoundexception.php
index 22f8bcea059..8c7f1f14175 100644
--- a/lib/private/template/resourcenotfoundexception.php
+++ b/lib/private/template/resourcenotfoundexception.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/template/templatefilelocator.php b/lib/private/template/templatefilelocator.php
index 1fa13aed188..f8553156914 100644
--- a/lib/private/template/templatefilelocator.php
+++ b/lib/private/template/templatefilelocator.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/templatelayout.php b/lib/private/templatelayout.php
index 7d16823d2a8..bc66c0dfb1e 100644
--- a/lib/private/templatelayout.php
+++ b/lib/private/templatelayout.php
@@ -2,7 +2,6 @@
/**
* @author Adam Williamson <awilliam@redhat.com>
* @author Bart Visscher <bartv@thisnet.nl>
- * @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Clark Tomlinson <fallen013@gmail.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
@@ -12,11 +11,12 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Remco Brenninkmeijer <requist1@starmail.nl>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,6 +32,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
+namespace OC;
+
use Assetic\Asset\AssetCollection;
use Assetic\Asset\FileAsset;
use Assetic\AssetWriter;
@@ -41,14 +43,7 @@ use Assetic\Filter\CssRewriteFilter;
use Assetic\Filter\JSqueezeFilter;
use Assetic\Filter\SeparatorFilter;
-/**
- * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-class OC_TemplateLayout extends OC_Template {
+class TemplateLayout extends \OC_Template {
private static $versionHash = '';
@@ -69,7 +64,7 @@ class OC_TemplateLayout extends OC_Template {
// Decide which page we show
if($renderAs == 'user') {
parent::__construct( 'core', 'layout.user' );
- if(in_array(OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
+ if(in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
$this->assign('bodyid', 'body-settings');
}else{
$this->assign('bodyid', 'body-user');
@@ -77,15 +72,21 @@ class OC_TemplateLayout extends OC_Template {
// Update notification
if($this->config->getSystemValue('updatechecker', true) === true &&
- OC_User::isAdminUser(OC_User::getUser())) {
- $updater = new \OC\Updater(\OC::$server->getHTTPHelper(),
- \OC::$server->getConfig(), \OC::$server->getLogger());
+ \OC_User::isAdminUser(\OC_User::getUser())) {
+ $updater = new \OC\Updater(
+ \OC::$server->getHTTPHelper(),
+ \OC::$server->getConfig(),
+ \OC::$server->getIntegrityCodeChecker(),
+ \OC::$server->getLogger()
+ );
$data = $updater->check();
if(isset($data['version']) && $data['version'] != '' and $data['version'] !== Array()) {
$this->assign('updateAvailable', true);
$this->assign('updateVersion', $data['versionstring']);
- $this->assign('updateLink', $data['web']);
+ if(substr($data['web'], 0, 8) === 'https://') {
+ $this->assign('updateLink', $data['web']);
+ }
\OCP\Util::addScript('core', 'update-notification');
} else {
$this->assign('updateAvailable', false); // No update available or not an admin user
@@ -94,13 +95,18 @@ class OC_TemplateLayout extends OC_Template {
$this->assign('updateAvailable', false); // Update check is disabled
}
- // Add navigation entry
+ // Code integrity notification
+ $integrityChecker = \OC::$server->getIntegrityCodeChecker();
+ if(!$integrityChecker->hasPassedCheck()) {
+ \OCP\Util::addScript('core', 'integritycheck-failed-notification');
+ }
+ // Add navigation entry
$this->assign( 'application', '');
$this->assign( 'appid', $appId );
- $navigation = OC_App::getNavigation();
+ $navigation = \OC_App::getNavigation();
$this->assign( 'navigation', $navigation);
- $settingsNavigation = OC_App::getSettingsNavigation();
+ $settingsNavigation = \OC_App::getSettingsNavigation();
$this->assign( 'settingsnavigation', $settingsNavigation);
foreach($navigation as $entry) {
if ($entry['active']) {
@@ -115,17 +121,23 @@ class OC_TemplateLayout extends OC_Template {
break;
}
}
- $userDisplayName = OC_User::getDisplayName();
+ $userDisplayName = \OC_User::getDisplayName();
$appsMgmtActive = strpos(\OC::$server->getRequest()->getRequestUri(), \OC::$server->getURLGenerator()->linkToRoute('settings.AppSettings.viewApps')) === 0;
if ($appsMgmtActive) {
$l = \OC::$server->getL10N('lib');
$this->assign('application', $l->t('Apps'));
}
$this->assign('user_displayname', $userDisplayName);
- $this->assign('user_uid', OC_User::getUser());
+ $this->assign('user_uid', \OC_User::getUser());
$this->assign('appsmanagement_active', $appsMgmtActive);
- $this->assign('enableAvatars', $this->config->getSystemValue('enable_avatars', true));
- $this->assign('userAvatarSet', \OC_Helper::userAvatarSet(OC_User::getUser()));
+ $this->assign('enableAvatars', $this->config->getSystemValue('enable_avatars', true) === true);
+
+ if (\OC_User::getUser() === false) {
+ $this->assign('userAvatarSet', false);
+ } else {
+ $this->assign('userAvatarSet', \OC::$server->getAvatarManager()->getAvatar(\OC_User::getUser())->exists());
+ }
+
} else if ($renderAs == 'error') {
parent::__construct('core', 'layout.guest', '', false);
$this->assign('bodyid', 'body-login');
@@ -137,25 +149,28 @@ class OC_TemplateLayout extends OC_Template {
}
// Send the language to our layouts
- $this->assign('language', OC_L10N::findLanguage());
+ $this->assign('language', \OC_L10N::findLanguage());
-
- if(empty(self::$versionHash)) {
- $v = OC_App::getAppVersions();
- $v['core'] = implode('.', \OC_Util::getVersion());
- self::$versionHash = md5(implode(',', $v));
+ if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
+ if (empty(self::$versionHash)) {
+ $v = \OC_App::getAppVersions();
+ $v['core'] = implode('.', \OCP\Util::getVersion());
+ self::$versionHash = md5(implode(',', $v));
+ }
+ } else {
+ self::$versionHash = md5('not installed');
}
$useAssetPipeline = self::isAssetPipelineEnabled();
if ($useAssetPipeline) {
- $this->append( 'jsfiles', OC_Helper::linkToRoute('js_config', array('v' => self::$versionHash)));
+ $this->append( 'jsfiles', \OC::$server->getURLGenerator()->linkToRoute('js_config', ['v' => self::$versionHash]));
$this->generateAssets();
} else {
// Add the js files
- $jsFiles = self::findJavascriptFiles(OC_Util::$scripts);
+ $jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
$this->assign('jsfiles', array());
if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
- $this->append( 'jsfiles', OC_Helper::linkToRoute('js_config', array('v' => self::$versionHash)));
+ $this->append( 'jsfiles', \OC::$server->getURLGenerator()->linkToRoute('js_config', ['v' => self::$versionHash]));
}
foreach($jsFiles as $info) {
$web = $info[1];
@@ -164,7 +179,7 @@ class OC_TemplateLayout extends OC_Template {
}
// Add the css files
- $cssFiles = self::findStylesheetFiles(OC_Util::$styles);
+ $cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
$this->assign('cssfiles', array());
foreach($cssFiles as $info) {
$web = $info[1];
@@ -181,13 +196,13 @@ class OC_TemplateLayout extends OC_Template {
*/
static public function findStylesheetFiles($styles) {
// Read the selected theme from the config file
- $theme = OC_Util::getTheme();
+ $theme = \OC_Util::getTheme();
$locator = new \OC\Template\CSSResourceLocator(
- OC::$server->getLogger(),
+ \OC::$server->getLogger(),
$theme,
- array( OC::$SERVERROOT => OC::$WEBROOT ),
- array( OC::$THIRDPARTYROOT => OC::$THIRDPARTYWEBROOT ));
+ array( \OC::$SERVERROOT => \OC::$WEBROOT ),
+ array( \OC::$THIRDPARTYROOT => \OC::$THIRDPARTYWEBROOT ));
$locator->find($styles);
return $locator->getResources();
}
@@ -198,20 +213,20 @@ class OC_TemplateLayout extends OC_Template {
*/
static public function findJavascriptFiles($scripts) {
// Read the selected theme from the config file
- $theme = OC_Util::getTheme();
+ $theme = \OC_Util::getTheme();
$locator = new \OC\Template\JSResourceLocator(
- OC::$server->getLogger(),
+ \OC::$server->getLogger(),
$theme,
- array( OC::$SERVERROOT => OC::$WEBROOT ),
- array( OC::$THIRDPARTYROOT => OC::$THIRDPARTYWEBROOT ));
+ array( \OC::$SERVERROOT => \OC::$WEBROOT ),
+ array( \OC::$THIRDPARTYROOT => \OC::$THIRDPARTYWEBROOT ));
$locator->find($scripts);
return $locator->getResources();
}
public function generateAssets() {
$assetDir = \OC::$server->getConfig()->getSystemValue('assetdirectory', \OC::$SERVERROOT);
- $jsFiles = self::findJavascriptFiles(OC_Util::$scripts);
+ $jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
$jsHash = self::hashFileNames($jsFiles);
if (!file_exists("$assetDir/assets/$jsHash.js")) {
@@ -236,7 +251,7 @@ class OC_TemplateLayout extends OC_Template {
$writer->writeAsset($jsCollection);
}
- $cssFiles = self::findStylesheetFiles(OC_Util::$styles);
+ $cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
$cssHash = self::hashFileNames($cssFiles);
if (!file_exists("$assetDir/assets/$cssHash.css")) {
@@ -264,15 +279,15 @@ class OC_TemplateLayout extends OC_Template {
$writer->writeAsset($cssCollection);
}
- $this->append('jsfiles', OC_Helper::linkTo('assets', "$jsHash.js"));
- $this->append('cssfiles', OC_Helper::linkTo('assets', "$cssHash.css"));
+ $this->append('jsfiles', \OC::$server->getURLGenerator()->linkTo('assets', "$jsHash.js"));
+ $this->append('cssfiles', \OC::$server->getURLGenerator()->linkTo('assets', "$cssHash.css"));
}
/**
* Converts the absolute file path to a relative path from \OC::$SERVERROOT
* @param string $filePath Absolute path
* @return string Relative path
- * @throws Exception If $filePath is not under \OC::$SERVERROOT
+ * @throws \Exception If $filePath is not under \OC::$SERVERROOT
*/
public static function convertToRelativePath($filePath) {
$relativePath = explode(\OC::$SERVERROOT, $filePath);
diff --git a/lib/private/tempmanager.php b/lib/private/tempmanager.php
index 365d639389f..19bbaf6e78e 100644
--- a/lib/private/tempmanager.php
+++ b/lib/private/tempmanager.php
@@ -5,9 +5,9 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -213,7 +213,7 @@ class TempManager implements ITempManager {
if ($temp = $this->config->getSystemValue('tempdirectory', null)) {
$directories[] = $temp;
}
- if ($temp = ini_get('upload_tmp_dir')) {
+ if ($temp = \OC::$server->getIniWrapper()->get('upload_tmp_dir')) {
$directories[] = $temp;
}
if ($temp = getenv('TMP')) {
@@ -225,11 +225,6 @@ class TempManager implements ITempManager {
if ($temp = getenv('TMPDIR')) {
$directories[] = $temp;
}
- $temp = tempnam(__FILE__, '');
- if (file_exists($temp)) {
- unlink($temp);
- $directories[] = dirname($temp);
- }
if ($temp = sys_get_temp_dir()) {
$directories[] = $temp;
}
@@ -239,6 +234,12 @@ class TempManager implements ITempManager {
return $dir;
}
}
+
+ $temp = tempnam(dirname(__FILE__), '');
+ if (file_exists($temp)) {
+ unlink($temp);
+ return dirname($temp);
+ }
throw new \UnexpectedValueException('Unable to detect system temporary directory');
}
@@ -255,7 +256,7 @@ class TempManager implements ITempManager {
if (is_writeable($directory)) {
return true;
}
- } catch (Exception $e) {
+ } catch (\Exception $e) {
}
$this->log->warning('Temporary directory {dir} is not present or writable',
['dir' => $directory]
diff --git a/lib/private/updater.php b/lib/private/updater.php
index 1ff80863737..32264484ee3 100644
--- a/lib/private/updater.php
+++ b/lib/private/updater.php
@@ -8,13 +8,13 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Steffen Lindner <mail@steffen-lindner.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -34,6 +34,8 @@
namespace OC;
use OC\Hooks\BasicEmitter;
+use OC\IntegrityCheck\Checker;
+use OC\IntegrityCheck\Storage;
use OC_App;
use OC_Installer;
use OC_Util;
@@ -61,6 +63,9 @@ class Updater extends BasicEmitter {
/** @var IConfig */
private $config;
+ /** @var Checker */
+ private $checker;
+
/** @var bool */
private $simulateStepEnabled;
@@ -81,14 +86,17 @@ class Updater extends BasicEmitter {
/**
* @param HTTPHelper $httpHelper
* @param IConfig $config
+ * @param Checker $checker
* @param ILogger $log
*/
public function __construct(HTTPHelper $httpHelper,
IConfig $config,
+ Checker $checker,
ILogger $log = null) {
$this->httpHelper = $httpHelper;
$this->log = $log;
$this->config = $config;
+ $this->checker = $checker;
$this->simulateStepEnabled = true;
$this->updateStepEnabled = true;
}
@@ -147,7 +155,7 @@ class Updater extends BasicEmitter {
$this->config->setAppValue('core', 'installedat', microtime(true));
}
- $version = \OC_Util::getVersion();
+ $version = \OCP\Util::getVersion();
$version['installed'] = $this->config->getAppValue('core', 'installedat');
$version['updated'] = $this->config->getAppValue('core', 'lastupdatedat');
$version['updatechannel'] = \OC_Util::getChannel();
@@ -169,6 +177,8 @@ class Updater extends BasicEmitter {
$tmp['versionstring'] = (string)$data->versionstring;
$tmp['url'] = (string)$data->url;
$tmp['web'] = (string)$data->web;
+ } else {
+ libxml_clear_errors();
}
} else {
$data = [];
@@ -198,7 +208,7 @@ class Updater extends BasicEmitter {
}
$installedVersion = $this->config->getSystemValue('version', '0.0.0');
- $currentVersion = implode('.', \OC_Util::getVersion());
+ $currentVersion = implode('.', \OCP\Util::getVersion());
$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
$success = true;
@@ -246,7 +256,7 @@ class Updater extends BasicEmitter {
*/
public function isUpgradePossible($oldVersion, $newVersion, $allowedPreviousVersion) {
return (version_compare($allowedPreviousVersion, $oldVersion, '<=')
- && version_compare($oldVersion, $newVersion, '<='));
+ && (version_compare($oldVersion, $newVersion, '<=') || $this->config->getSystemValue('debug', false)));
}
/**
@@ -335,8 +345,15 @@ class Updater extends BasicEmitter {
//Invalidate update feed
$this->config->setAppValue('core', 'lastupdatedat', 0);
+ // Check for code integrity if not disabled
+ if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
+ $this->emit('\OC\Updater', 'startCheckCodeIntegrity');
+ $this->checker->runInstanceVerification();
+ $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
+ }
+
// only set the final version if everything went well
- $this->config->setSystemValue('version', implode('.', \OC_Util::getVersion()));
+ $this->config->setSystemValue('version', implode('.', \OCP\Util::getVersion()));
}
}
@@ -455,7 +472,7 @@ class Updater extends BasicEmitter {
private function checkAppsRequirements() {
$isCoreUpgrade = $this->isCodeUpgrade();
$apps = OC_App::getEnabledApps();
- $version = OC_Util::getVersion();
+ $version = \OCP\Util::getVersion();
$disabledApps = [];
foreach ($apps as $app) {
// check if the app is compatible with this version of ownCloud
@@ -492,7 +509,7 @@ class Updater extends BasicEmitter {
*/
private function isCodeUpgrade() {
$installedVersion = $this->config->getSystemValue('version', '0.0.0');
- $currentVersion = implode('.', OC_Util::getVersion());
+ $currentVersion = implode('.', \OCP\Util::getVersion());
if (version_compare($currentVersion, $installedVersion, '>')) {
return true;
}
diff --git a/lib/private/urlgenerator.php b/lib/private/urlgenerator.php
index 104cf7df596..327c0c32dfe 100644
--- a/lib/private/urlgenerator.php
+++ b/lib/private/urlgenerator.php
@@ -6,11 +6,11 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -62,6 +62,7 @@ class URLGenerator implements IURLGenerator {
* Returns a url to the given route.
*/
public function linkToRoute($route, $parameters = array()) {
+ // TODO: mock router
$urlLinkTo = \OC::$server->getRouter()->generate($route, $parameters);
return $urlLinkTo;
}
@@ -89,7 +90,7 @@ class URLGenerator implements IURLGenerator {
* Returns a url to the given app and file.
*/
public function linkTo( $app, $file, $args = array() ) {
- $frontControllerActive=($this->config->getSystemValue('front_controller_active', 'false') == 'true');
+ $frontControllerActive = (getenv('front_controller_active') === 'true');
if( $app != '' ) {
$app_path = \OC_App::getAppPath($app);
@@ -113,7 +114,7 @@ class URLGenerator implements IURLGenerator {
$urlLinkTo = \OC::$WEBROOT . '/core/' . $file;
} else {
if ($frontControllerActive && $file === 'index.php') {
- $urlLinkTo = \OC::$WEBROOT;
+ $urlLinkTo = \OC::$WEBROOT . '/';
} else {
$urlLinkTo = \OC::$WEBROOT . '/' . $file;
}
diff --git a/lib/private/user.php b/lib/private/user.php
index 74441d9175a..ae98bb9b01a 100644
--- a/lib/private/user.php
+++ b/lib/private/user.php
@@ -3,26 +3,24 @@
* @author Aldo "xoen" Giambelluca <xoen@xoen.org>
* @author Andreas Fischer <bantu@owncloud.com>
* @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Bart Visscher <bartv@thisnet.nl>
* @author Bartek Przybylski <bart.p.pl@gmail.com>
+ * @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
- * @author Dominik Schmidt <dev@dominik-schmidt.de>
* @author Florian Preinstorfer <nblock@archlinux.us>
* @author Georg Ehrke <georg@owncloud.com>
* @author Jakob Sack <mail@jakobsack.de>
- * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author shkdee <louis.traynard@m4x.org>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
- * @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -66,14 +64,6 @@ class OC_User {
return OC::$server->getUserSession();
}
- /**
- * @return \OC\User\Manager
- * @deprecated Use \OC::$server->getUserManager()
- */
- public static function getManager() {
- return OC::$server->getUserManager();
- }
-
private static $_backends = array();
private static $_usedBackends = array();
@@ -84,55 +74,17 @@ class OC_User {
private static $incognitoMode = false;
/**
- * registers backend
- *
- * @param string $backend name of the backend
- * @deprecated Add classes by calling OC_User::useBackend() with a class instance instead
- * @return bool
- *
- * Makes a list of backends that can be used by other modules
- */
- public static function registerBackend($backend) {
- self::$_backends[] = $backend;
- return true;
- }
-
- /**
- * gets available backends
- *
- * @deprecated
- * @return array an array of backends
- *
- * Returns the names of all backends.
- */
- public static function getBackends() {
- return self::$_backends;
- }
-
- /**
- * gets used backends
- *
- * @deprecated
- * @return array an array of backends
- *
- * Returns the names of all used backends.
- */
- public static function getUsedBackends() {
- return array_keys(self::$_usedBackends);
- }
-
- /**
* Adds the backend to the list of used backends
*
- * @param string|OC_User_Interface $backend default: database The backend to use for user management
+ * @param string|\OCP\UserInterface $backend default: database The backend to use for user management
* @return bool
*
* Set the User Authentication Module
*/
public static function useBackend($backend = 'database') {
- if ($backend instanceof OC_User_Interface) {
+ if ($backend instanceof \OCP\UserInterface) {
self::$_usedBackends[get_class($backend)] = $backend;
- self::getManager()->registerBackend($backend);
+ \OC::$server->getUserManager()->registerBackend($backend);
} else {
// You'll never know what happens
if (null === $backend OR !is_string($backend)) {
@@ -146,17 +98,17 @@ class OC_User {
case 'sqlite':
\OCP\Util::writeLog('core', 'Adding user backend ' . $backend . '.', \OCP\Util::DEBUG);
self::$_usedBackends[$backend] = new OC_User_Database();
- self::getManager()->registerBackend(self::$_usedBackends[$backend]);
+ \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
break;
case 'dummy':
self::$_usedBackends[$backend] = new \Test\Util\User\Dummy();
- self::getManager()->registerBackend(self::$_usedBackends[$backend]);
+ \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
break;
default:
\OCP\Util::writeLog('core', 'Adding default user backend ' . $backend . '.', \OCP\Util::DEBUG);
$className = 'OC_USER_' . strToUpper($backend);
self::$_usedBackends[$backend] = new $className();
- self::getManager()->registerBackend(self::$_usedBackends[$backend]);
+ \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
break;
}
}
@@ -168,7 +120,7 @@ class OC_User {
*/
public static function clearBackends() {
self::$_usedBackends = array();
- self::getManager()->clearBackends();
+ \OC::$server->getUserManager()->clearBackends();
}
/**
@@ -176,7 +128,7 @@ class OC_User {
*/
public static function setupBackends() {
OC_App::loadApps(array('prelogin'));
- $backends = OC_Config::getValue('user_backends', array());
+ $backends = \OC::$server->getSystemConfig()->getValue('user_backends', array());
foreach ($backends as $i => $config) {
$class = $config['class'];
$arguments = $config['arguments'];
@@ -199,42 +151,6 @@ class OC_User {
}
/**
- * Create a new user
- *
- * @param string $uid The username of the user to create
- * @param string $password The password of the new user
- * @throws Exception
- * @return bool true/false
- *
- * Creates a new user. Basic checking of username is done in OC_User
- * itself, not in its subclasses.
- *
- * Allowed characters in the username are: "a-z", "A-Z", "0-9" and "_.@-"
- * @deprecated Use \OC::$server->getUserManager()->createUser($uid, $password)
- */
- public static function createUser($uid, $password) {
- return self::getManager()->createUser($uid, $password);
- }
-
- /**
- * delete a user
- *
- * @param string $uid The username of the user to delete
- * @return bool
- *
- * Deletes a user
- * @deprecated Use \OC::$server->getUserManager()->get() and then run delete() on the return
- */
- public static function deleteUser($uid) {
- $user = self::getManager()->get($uid);
- if ($user) {
- return $user->delete();
- } else {
- return false;
- }
- }
-
- /**
* Try to login a user
*
* @param string $loginname The login name of the user to log in
@@ -244,9 +160,10 @@ class OC_User {
* Log in a user and regenerate a new session - if the password is ok
*/
public static function login($loginname, $password) {
- session_regenerate_id(true);
$result = self::getUserSession()->login($loginname, $password);
if ($result) {
+ // Refresh the token
+ \OC::$server->getCsrfTokenManager()->refreshToken();
//we need to pass the user name, which may differ from login name
$user = self::getUserSession()->getUser()->getUID();
OC_Util::setupFS($user);
@@ -343,7 +260,7 @@ class OC_User {
if (is_null($displayName)) {
$displayName = $uid;
}
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->setDisplayName($displayName);
} else {
@@ -413,7 +330,7 @@ class OC_User {
return $backend->getLogoutAttribute();
}
- return 'href="' . link_to('', 'index.php') . '?logout=true&amp;requesttoken=' . urlencode(OC_Util::callRegister()) . '"';
+ return 'href="' . link_to('', 'index.php') . '?logout=true&amp;requesttoken=' . urlencode(\OCP\Util::callRegister()) . '"';
}
/**
@@ -452,7 +369,7 @@ class OC_User {
*/
public static function getDisplayName($uid = null) {
if ($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->getDisplayName();
} else {
@@ -476,7 +393,7 @@ class OC_User {
* generates a password
*/
public static function generatePassword() {
- return \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(30);
+ return \OC::$server->getSecureRandom()->generate(30);
}
/**
@@ -490,7 +407,7 @@ class OC_User {
* Change the password of a user
*/
public static function setPassword($uid, $password, $recoveryPassword = null) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->setPassword($password, $recoveryPassword);
} else {
@@ -507,7 +424,7 @@ class OC_User {
* Check whether a specified user can change his avatar
*/
public static function canUserChangeAvatar($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->canChangeAvatar();
} else {
@@ -524,7 +441,7 @@ class OC_User {
* Check whether a specified user can change his password
*/
public static function canUserChangePassword($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->canChangePassword();
} else {
@@ -541,7 +458,7 @@ class OC_User {
* Check whether a specified user can change his display name
*/
public static function canUserChangeDisplayName($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->canChangeDisplayName();
} else {
@@ -560,7 +477,7 @@ class OC_User {
* returns the user id or false
*/
public static function checkPassword($uid, $password) {
- $manager = self::getManager();
+ $manager = \OC::$server->getUserManager();
$username = $manager->checkPassword($uid, $password);
if ($username !== false) {
return $username->getUID();
@@ -576,11 +493,11 @@ class OC_User {
* @deprecated Use \OC::$server->getUserManager->getHome()
*/
public static function getHome($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->getHome();
} else {
- return OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
+ return \OC::$server->getSystemConfig()->getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
}
}
@@ -595,7 +512,7 @@ class OC_User {
* @param integer $offset
*/
public static function getUsers($search = '', $limit = null, $offset = null) {
- $users = self::getManager()->search($search, $limit, $offset);
+ $users = \OC::$server->getUserManager()->search($search, $limit, $offset);
$uids = array();
foreach ($users as $user) {
$uids[] = $user->getUID();
@@ -616,7 +533,7 @@ class OC_User {
*/
public static function getDisplayNames($search = '', $limit = null, $offset = null) {
$displayNames = array();
- $users = self::getManager()->searchDisplayName($search, $limit, $offset);
+ $users = \OC::$server->getUserManager()->searchDisplayName($search, $limit, $offset);
foreach ($users as $user) {
$displayNames[$user->getUID()] = $user->getDisplayName();
}
@@ -630,7 +547,7 @@ class OC_User {
* @return boolean
*/
public static function userExists($uid) {
- return self::getManager()->userExists($uid);
+ return \OC::$server->getUserManager()->userExists($uid);
}
/**
@@ -639,7 +556,7 @@ class OC_User {
* @param string $uid the user to disable
*/
public static function disableUser($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
$user->setEnabled(false);
}
@@ -651,7 +568,7 @@ class OC_User {
* @param string $uid
*/
public static function enableUser($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
$user->setEnabled(true);
}
@@ -664,7 +581,7 @@ class OC_User {
* @return bool
*/
public static function isEnabled($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->isEnabled();
} else {
diff --git a/lib/private/user/backend.php b/lib/private/user/backend.php
index cda91398a84..c8e3577d112 100644
--- a/lib/private/user/backend.php
+++ b/lib/private/user/backend.php
@@ -16,7 +16,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -63,7 +63,7 @@ define('OC_USER_BACKEND_COUNT_USERS', 1 << 28);
* Abstract base class for user management. Provides methods for querying backend
* capabilities.
*/
-abstract class OC_User_Backend implements OC_User_Interface {
+abstract class OC_User_Backend implements \OCP\UserInterface {
/**
* error code for functions not provided by the user backend
*/
diff --git a/lib/private/user/database.php b/lib/private/user/database.php
index 3969b446071..22a05090b96 100644
--- a/lib/private/user/database.php
+++ b/lib/private/user/database.php
@@ -15,11 +15,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author nishiki <nishiki@yaegashi.fr>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -210,7 +210,7 @@ class OC_User_Database extends OC_User_Backend implements \OCP\IUserBackend {
$query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)');
$result = $query->execute(array($uid));
- if (OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('core', OC_DB::getErrorMessage(), \OCP\Util::ERROR);
return false;
}
@@ -266,7 +266,7 @@ class OC_User_Database extends OC_User_Backend implements \OCP\IUserBackend {
*/
public function getHome($uid) {
if ($this->userExists($uid)) {
- return OC_Config::getValue("datadirectory", OC::$SERVERROOT . "/data") . '/' . $uid;
+ return \OC::$server->getConfig()->getSystemValue("datadirectory", OC::$SERVERROOT . "/data") . '/' . $uid;
}
return false;
@@ -287,7 +287,7 @@ class OC_User_Database extends OC_User_Backend implements \OCP\IUserBackend {
public function countUsers() {
$query = OC_DB::prepare('SELECT COUNT(*) FROM `*PREFIX*users`');
$result = $query->execute();
- if (OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('core', OC_DB::getErrorMessage(), \OCP\Util::ERROR);
return false;
}
diff --git a/lib/private/user/interface.php b/lib/private/user/interface.php
index 0b36340c4f9..b487a046c72 100644
--- a/lib/private/user/interface.php
+++ b/lib/private/user/interface.php
@@ -5,10 +5,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,62 +25,8 @@
*
*/
-interface OC_User_Interface {
-
- /**
- * Check if backend implements actions
- * @param int $actions bitwise-or'ed actions
- * @return boolean
- *
- * Returns the supported actions as int to be
- * compared with \OC_User_Backend::CREATE_USER etc.
- */
- public function implementsActions($actions);
-
- /**
- * delete a user
- * @param string $uid The username of the user to delete
- * @return bool
- */
- public function deleteUser($uid);
-
- /**
- * Get a list of all users
- *
- * @param string $search
- * @param null|int $limit
- * @param null|int $offset
- * @return string[] an array of all uids
- */
- public function getUsers($search = '', $limit = null, $offset = null);
-
- /**
- * check if a user exists
- * @param string $uid the username
- * @return boolean
- */
- public function userExists($uid);
-
- /**
- * get display name of the user
- * @param string $uid user ID of the user
- * @return string display name
- */
- public function getDisplayName($uid);
-
- /**
- * Get a list of all display names and user ids.
- *
- * @param string $search
- * @param string|null $limit
- * @param string|null $offset
- * @return array an array of all displayNames (value) and the corresponding uids (key)
- */
- public function getDisplayNames($search = '', $limit = null, $offset = null);
-
- /**
- * Check if a user list is available or not
- * @return boolean if users can be listed or not
- */
- public function hasUserListings();
-}
+/**
+ * Interface OC_User_Interface
+ * @deprecated use the public \OCP\UserInterface instead
+ */
+interface OC_User_Interface extends \OCP\UserInterface {}
diff --git a/lib/private/user/loginexception.php b/lib/private/user/loginexception.php
index fcaa4d797a8..84426f7f5da 100644
--- a/lib/private/user/loginexception.php
+++ b/lib/private/user/loginexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/user/manager.php b/lib/private/user/manager.php
index 109f08f47a0..6798a7340c3 100644
--- a/lib/private/user/manager.php
+++ b/lib/private/user/manager.php
@@ -7,10 +7,11 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author RealRancor <Fisch.666@gmx.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Volkan Gezer <volkangezer@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -43,6 +44,7 @@ use OCP\IConfig;
* - postDelete(\OC\User\User $user)
* - preCreateUser(string $uid, string $password)
* - postCreateUser(\OC\User\User $user, string $password)
+ * - change(\OC\User\User $user)
*
* @package OC\User
*/
@@ -254,15 +256,19 @@ class Manager extends PublicEmitter implements IUserManager {
public function createUser($uid, $password) {
$l = \OC::$server->getL10N('lib');
// Check the name for bad characters
- // Allowed are: "a-z", "A-Z", "0-9" and "_.@-"
- if (preg_match('/[^a-zA-Z0-9 _\.@\-]/', $uid)) {
+ // Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
+ if (preg_match('/[^a-zA-Z0-9 _\.@\-\']/', $uid)) {
throw new \Exception($l->t('Only the following characters are allowed in a username:'
- . ' "a-z", "A-Z", "0-9", and "_.@-"'));
+ . ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
}
// No empty username
if (trim($uid) == '') {
throw new \Exception($l->t('A valid username must be provided'));
}
+ // No whitespace at the beginning or at the end
+ if (strlen(trim($uid, "\t\n\r\0\x0B\xe2\x80\x8b")) !== strlen(trim($uid))) {
+ throw new \Exception($l->t('Username contains whitespace at the beginning or at the end'));
+ }
// No empty password
if (trim($password) == '') {
throw new \Exception($l->t('A valid password must be provided'));
@@ -294,21 +300,47 @@ class Manager extends PublicEmitter implements IUserManager {
$userCountStatistics = array();
foreach ($this->backends as $backend) {
if ($backend->implementsActions(\OC_User_Backend::COUNT_USERS)) {
- $backendusers = $backend->countUsers();
- if($backendusers !== false) {
+ $backendUsers = $backend->countUsers();
+ if($backendUsers !== false) {
if($backend instanceof \OCP\IUserBackend) {
$name = $backend->getBackendName();
} else {
$name = get_class($backend);
}
if(isset($userCountStatistics[$name])) {
- $userCountStatistics[$name] += $backendusers;
+ $userCountStatistics[$name] += $backendUsers;
} else {
- $userCountStatistics[$name] = $backendusers;
+ $userCountStatistics[$name] = $backendUsers;
}
}
}
}
return $userCountStatistics;
}
+
+ /**
+ * The callback is executed for each user on each backend.
+ * If the callback returns false no further users will be retrieved.
+ *
+ * @param \Closure $callback
+ * @return void
+ * @since 9.0.0
+ */
+ public function callForAllUsers(\Closure $callback, $search = '') {
+ foreach($this->getBackends() as $backend) {
+ $limit = 500;
+ $offset = 0;
+ do {
+ $users = $backend->getUsers($search, $limit, $offset);
+ foreach ($users as $user) {
+ $user = $this->get($user);
+ $return = $callback($user);
+ if ($return === false) {
+ break;
+ }
+ }
+ $offset += $limit;
+ } while (count($users) >= $limit);
+ }
+ }
}
diff --git a/lib/private/user/nouserexception.php b/lib/private/user/nouserexception.php
index 09874887469..afd5c729fcf 100644
--- a/lib/private/user/nouserexception.php
+++ b/lib/private/user/nouserexception.php
@@ -2,7 +2,7 @@
/**
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/user/session.php b/lib/private/user/session.php
index baceeb43956..5402c5cf74f 100644
--- a/lib/private/user/session.php
+++ b/lib/private/user/session.php
@@ -7,11 +7,12 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -213,6 +214,7 @@ class Session implements IUserSession, Emitter {
* @throws LoginException
*/
public function login($uid, $password) {
+ $this->session->regenerateId();
$this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
$user = $this->manager->checkPassword($uid, $password);
if ($user !== false) {
@@ -243,6 +245,7 @@ class Session implements IUserSession, Emitter {
* @return bool
*/
public function loginWithCookie($uid, $currentToken) {
+ $this->session->regenerateId();
$this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
$user = $this->manager->get($uid);
if (is_null($user)) {
@@ -258,7 +261,7 @@ class Session implements IUserSession, Emitter {
}
// replace successfully used token with a new one
\OC::$server->getConfig()->deleteUserValue($uid, 'login_token', $currentToken);
- $newToken = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(32);
+ $newToken = \OC::$server->getSecureRandom()->generate(32);
\OC::$server->getConfig()->setUserValue($uid, 'login_token', $newToken, time());
$this->setMagicInCookie($user->getUID(), $newToken);
@@ -287,7 +290,7 @@ class Session implements IUserSession, Emitter {
*/
public function setMagicInCookie($username, $token) {
$secureCookie = \OC::$server->getRequest()->getServerProtocol() === 'https';
- $expires = time() + \OC_Config::getValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
+ $expires = time() + \OC::$server->getConfig()->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
setcookie("oc_username", $username, $expires, \OC::$WEBROOT, '', $secureCookie, true);
setcookie("oc_token", $token, $expires, \OC::$WEBROOT, '', $secureCookie, true);
setcookie("oc_remember_login", "1", $expires, \OC::$WEBROOT, '', $secureCookie, true);
diff --git a/lib/private/user/user.php b/lib/private/user/user.php
index 28b66d7f5ba..516c1d443c6 100644
--- a/lib/private/user/user.php
+++ b/lib/private/user/user.php
@@ -7,10 +7,10 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,61 +30,57 @@
namespace OC\User;
use OC\Hooks\Emitter;
+use OCP\IAvatarManager;
+use OCP\IImage;
+use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IConfig;
+use OCP\UserInterface;
class User implements IUser {
- /**
- * @var string $uid
- */
+ /** @var string $uid */
private $uid;
- /**
- * @var string $displayName
- */
+ /** @var string $displayName */
private $displayName;
- /**
- * @var \OC_User_Interface $backend
- */
+ /** @var UserInterface $backend */
private $backend;
- /**
- * @var bool $enabled
- */
+ /** @var bool $enabled */
private $enabled;
- /**
- * @var Emitter|Manager $emitter
- */
+ /** @var Emitter|Manager $emitter */
private $emitter;
- /**
- * @var string $home
- */
+ /** @var string $home */
private $home;
- /**
- * @var int $lastLogin
- */
+ /** @var int $lastLogin */
private $lastLogin;
- /**
- * @var \OCP\IConfig $config
- */
+ /** @var \OCP\IConfig $config */
private $config;
+ /** @var IAvatarManager */
+ private $avatarManager;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
/**
* @param string $uid
- * @param \OC_User_Interface $backend
+ * @param UserInterface $backend
* @param \OC\Hooks\Emitter $emitter
- * @param \OCP\IConfig $config
+ * @param IConfig|null $config
+ * @param IURLGenerator $urlGenerator
*/
- public function __construct($uid, $backend, $emitter = null, IConfig $config = null) {
+ public function __construct($uid, $backend, $emitter = null, IConfig $config = null, $urlGenerator = null) {
$this->uid = $uid;
$this->backend = $backend;
$this->emitter = $emitter;
$this->config = $config;
+ $this->urlGenerator = $urlGenerator;
if ($this->config) {
$enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true');
$this->enabled = ($enabled === 'true');
@@ -93,6 +89,9 @@ class User implements IUser {
$this->enabled = true;
$this->lastLogin = \OC::$server->getConfig()->getUserValue($uid, 'login', 'lastLogin', 0);
}
+ if (is_null($this->urlGenerator)) {
+ $this->urlGenerator = \OC::$server->getURLGenerator();
+ }
}
/**
@@ -105,7 +104,7 @@ class User implements IUser {
}
/**
- * get the displayname for the user, if no specific displayname is set it will fallback to the user id
+ * get the display name for the user, if no specific display name is set it will fallback to the user id
*
* @return string
*/
@@ -138,8 +137,11 @@ class User implements IUser {
public function setDisplayName($displayName) {
$displayName = trim($displayName);
if ($this->backend->implementsActions(\OC_User_Backend::SET_DISPLAYNAME) && !empty($displayName)) {
- $this->displayName = $displayName;
$result = $this->backend->setDisplayName($this->uid, $displayName);
+ if ($result) {
+ $this->displayName = $displayName;
+ $this->triggerChange();
+ }
return $result !== false;
} else {
return false;
@@ -147,6 +149,22 @@ class User implements IUser {
}
/**
+ * set the email address of the user
+ *
+ * @param string|null $mailAddress
+ * @return void
+ * @since 9.0.0
+ */
+ public function setEMailAddress($mailAddress) {
+ if($mailAddress === '') {
+ $this->config->deleteUserValue($this->uid, 'settings', 'email');
+ } else {
+ $this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
+ }
+ $this->triggerChange();
+ }
+
+ /**
* returns the timestamp of the user's last login or 0 if the user did never
* login
*
@@ -191,6 +209,9 @@ class User implements IUser {
// Delete the users entry in the storage table
\OC\Files\Cache\Storage::remove('home::' . $this->uid);
+
+ \OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
+ \OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
}
if ($this->emitter) {
@@ -306,4 +327,69 @@ class User implements IUser {
$this->config->setUserValue($this->uid, 'core', 'enabled', $enabled);
}
}
+
+ /**
+ * get the users email address
+ *
+ * @return string|null
+ * @since 9.0.0
+ */
+ public function getEMailAddress() {
+ return $this->config->getUserValue($this->uid, 'settings', 'email', null);
+ }
+
+ /**
+ * get the avatar image if it exists
+ *
+ * @param int $size
+ * @return IImage|null
+ * @since 9.0.0
+ */
+ public function getAvatarImage($size) {
+ // delay the initialization
+ if (is_null($this->avatarManager)) {
+ $this->avatarManager = \OC::$server->getAvatarManager();
+ }
+
+ $avatar = $this->avatarManager->getAvatar($this->uid);
+ $image = $avatar->get(-1);
+ if ($image) {
+ return $image;
+ }
+
+ return null;
+ }
+
+ /**
+ * get the federation cloud id
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getCloudId() {
+ $uid = $this->getUID();
+ $server = $this->urlGenerator->getAbsoluteURL('/');
+ return $uid . '@' . rtrim( $this->removeProtocolFromUrl($server), '/');
+ }
+
+ /**
+ * @param string $url
+ * @return string
+ */
+ private function removeProtocolFromUrl($url) {
+ if (strpos($url, 'https://') === 0) {
+ return substr($url, strlen('https://'));
+ } else if (strpos($url, 'http://') === 0) {
+ return substr($url, strlen('http://'));
+ }
+
+ return $url;
+ }
+
+ public function triggerChange() {
+ if ($this->emitter) {
+ $this->emitter->emit('\OC\User', 'changeUser', array($this));
+ }
+ }
+
}
diff --git a/lib/private/util.php b/lib/private/util.php
index 4c151d63639..28541eff773 100644
--- a/lib/private/util.php
+++ b/lib/private/util.php
@@ -1,6 +1,7 @@
<?php
/**
* @author Adam Williamson <awilliam@redhat.com>
+ * @author Andreas Böhler <dev@aboehler.at>
* @author Andreas Fischer <bantu@owncloud.com>
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
@@ -28,7 +29,8 @@
* @author Michael Göhler <somebody.here@gmx.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Stefan Rado <owncloud@sradonia.net>
* @author Thomas Müller <thomas.mueller@tmit.eu>
@@ -38,7 +40,7 @@
* @author Vincent Petry <pvince81@owncloud.com>
* @author Volkan Gezer <volkangezer@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -54,6 +56,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
+
+use OCP\IConfig;
+use OCP\IGroupManager;
+use OCP\IUser;
+
class OC_Util {
public static $scripts = array();
public static $styles = array();
@@ -67,7 +74,7 @@ class OC_Util {
private static function initLocalStorageRootFS() {
// mount local file backend as root
- $configDataDirectory = OC_Config::getValue("datadirectory", OC::$SERVERROOT . "/data");
+ $configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
//first set up the local "root" storage
\OC\Files\Filesystem::initMountManager();
if (!self::$rootMounted) {
@@ -145,6 +152,16 @@ class OC_Util {
return $storage;
});
+ \OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
+ if (!$mount->getOption('enable_sharing', true)) {
+ return new \OC\Files\Storage\Wrapper\PermissionsMask([
+ 'storage' => $storage,
+ 'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE
+ ]);
+ }
+ return $storage;
+ });
+
// install storage availability wrapper, before most other wrappers
\OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, $storage) {
if (!$storage->isLocal()) {
@@ -179,7 +196,7 @@ class OC_Util {
OC_Hook::emit('OC_Filesystem', 'preSetup', array('user' => $user));
//check if we are using an object storage
- $objectStore = OC_Config::getValue('objectstore');
+ $objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
if (isset($objectStore)) {
self::initObjectStoreRootFS($objectStore);
} else {
@@ -218,20 +235,21 @@ class OC_Util {
/**
* check if sharing is disabled for the current user
- *
- * @return boolean
+ * @param IConfig $config
+ * @param IGroupManager $groupManager
+ * @param IUser|null $user
+ * @return bool
*/
- public static function isSharingDisabledForUser() {
- if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
- $user = \OCP\User::getUser();
- $groupsList = \OC::$server->getAppConfig()->getValue('core', 'shareapi_exclude_groups_list', '');
+ public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
+ if ($config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
+ $groupsList = $config->getAppValue('core', 'shareapi_exclude_groups_list', '');
$excludedGroups = json_decode($groupsList);
if (is_null($excludedGroups)) {
$excludedGroups = explode(',', $groupsList);
$newValue = json_encode($excludedGroups);
- \OC::$server->getAppConfig()->setValue('core', 'shareapi_exclude_groups_list', $newValue);
+ $config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
}
- $usersGroups = \OC_Group::getUserGroups($user);
+ $usersGroups = $groupManager->getUserGroupIds($user);
if (!empty($usersGroups)) {
$remainingGroups = array_diff($usersGroups, $excludedGroups);
// if the user is only in groups which are disabled for sharing then
@@ -451,19 +469,12 @@ class OC_Util {
*/
public static function addScript($application, $file = null, $prepend = false) {
$path = OC_Util::generatePath($application, 'js', $file);
- //TODO eliminate double code
- if (!in_array($path, self::$scripts)) {
- // core js files need separate handling
- if ($application !== 'core' && $file !== null) {
- self::addTranslations($application);
- }
- if ($prepend===true) {
- array_unshift(self::$scripts, $path);
- }
- else {
- self::$scripts[] = $path;
- }
+
+ // core js files need separate handling
+ if ($application !== 'core' && $file !== null) {
+ self::addTranslations ( $application );
}
+ self::addExternalResource($application, $prepend, $path, "script");
}
/**
@@ -476,14 +487,7 @@ class OC_Util {
*/
public static function addVendorScript($application, $file = null, $prepend = false) {
$path = OC_Util::generatePath($application, 'vendor', $file);
- //TODO eliminate double code
- if (! in_array ( $path, self::$scripts )) {
- if ($prepend === true) {
- array_unshift ( self::$scripts, $path );
- } else {
- self::$scripts [] = $path;
- }
- }
+ self::addExternalResource($application, $prepend, $path, "script");
}
/**
@@ -502,14 +506,7 @@ class OC_Util {
} else {
$path = "l10n/$languageCode";
}
- //TODO eliminate double code
- if (!in_array($path, self::$scripts)) {
- if ($prepend === true) {
- array_unshift ( self::$scripts, $path );
- } else {
- self::$scripts [] = $path;
- }
- }
+ self::addExternalResource($application, $prepend, $path, "script");
}
/**
@@ -522,14 +519,7 @@ class OC_Util {
*/
public static function addStyle($application, $file = null, $prepend = false) {
$path = OC_Util::generatePath($application, 'css', $file);
- //TODO eliminate double code
- if (!in_array($path, self::$styles)) {
- if ($prepend === true) {
- array_unshift ( self::$styles, $path );
- } else {
- self::$styles[] = $path;
- }
- }
+ self::addExternalResource($application, $prepend, $path, "style");
}
/**
@@ -542,13 +532,36 @@ class OC_Util {
*/
public static function addVendorStyle($application, $file = null, $prepend = false) {
$path = OC_Util::generatePath($application, 'vendor', $file);
- //TODO eliminate double code
- if (!in_array($path, self::$styles)) {
- if ($prepend === true) {
- array_unshift ( self::$styles, $path );
- } else {
- self::$styles[] = $path;
- }
+ self::addExternalResource($application, $prepend, $path, "style");
+ }
+
+ /**
+ * add an external resource css/js file
+ *
+ * @param string $application application id
+ * @param bool $prepend prepend the file to the beginning of the list
+ * @param string $path
+ * @param string $type (script or style)
+ * @return void
+ */
+ private static function addExternalResource($application, $prepend, $path, $type = "script") {
+
+ if ($type === "style") {
+ if (!in_array($path, self::$styles)) {
+ if ($prepend === true) {
+ array_unshift ( self::$styles, $path );
+ } else {
+ self::$styles[] = $path;
+ }
+ }
+ } elseif ($type === "script") {
+ if (!in_array($path, self::$scripts)) {
+ if ($prepend === true) {
+ array_unshift ( self::$scripts, $path );
+ } else {
+ self::$scripts [] = $path;
+ }
+ }
}
}
@@ -615,6 +628,9 @@ class OC_Util {
$webServerRestart = false;
$setup = new \OC\Setup($config, \OC::$server->getIniWrapper(), \OC::$server->getL10N('lib'),
new \OC_Defaults(), \OC::$server->getLogger(), \OC::$server->getSecureRandom());
+
+ $urlGenerator = \OC::$server->getURLGenerator();
+
$availableDatabases = $setup->getSupportedDatabases();
if (empty($availableDatabases)) {
$errors[] = array(
@@ -638,13 +654,15 @@ class OC_Util {
}
// Check if config folder is writable.
- if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
- $errors[] = array(
- 'error' => $l->t('Cannot write into "config" directory'),
- 'hint' => $l->t('This can usually be fixed by '
- . '%sgiving the webserver write access to the config directory%s.',
- array('<a href="' . \OC_Helper::linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'))
- );
+ if(!OC_Helper::isReadOnlyConfigEnabled()) {
+ if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
+ $errors[] = array(
+ 'error' => $l->t('Cannot write into "config" directory'),
+ 'hint' => $l->t('This can usually be fixed by '
+ . '%sgiving the webserver write access to the config directory%s.',
+ array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'))
+ );
+ }
}
// Check if there is a writable install folder.
@@ -658,7 +676,7 @@ class OC_Util {
'hint' => $l->t('This can usually be fixed by '
. '%sgiving the webserver write access to the apps directory%s'
. ' or disabling the appstore in the config file.',
- array('<a href="' . \OC_Helper::linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'))
+ array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'))
);
}
}
@@ -673,14 +691,14 @@ class OC_Util {
'error' => $l->t('Cannot create "data" directory (%s)', array($CONFIG_DATADIRECTORY)),
'hint' => $l->t('This can usually be fixed by '
. '<a href="%s" target="_blank">giving the webserver write access to the root directory</a>.',
- array(OC_Helper::linkToDocs('admin-dir_permissions')))
+ array($urlGenerator->linkToDocs('admin-dir_permissions')))
);
}
} else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
//common hint for all file permissions error messages
$permissionsHint = $l->t('Permissions can usually be fixed by '
. '%sgiving the webserver write access to the root directory%s.',
- array('<a href="' . \OC_Helper::linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'));
+ array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'));
$errors[] = array(
'error' => 'Data directory (' . $CONFIG_DATADIRECTORY . ') not writable by ownCloud',
'hint' => $permissionsHint
@@ -842,7 +860,7 @@ class OC_Util {
public static function checkDatabaseVersion() {
$l = \OC::$server->getL10N('lib');
$errors = array();
- $dbType = \OC_Config::getValue('dbtype', 'sqlite');
+ $dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
if ($dbType === 'pgsql') {
// check PostgreSQL version
try {
@@ -858,12 +876,9 @@ class OC_Util {
}
}
} catch (\Doctrine\DBAL\DBALException $e) {
- \OCP\Util::logException('core', $e);
- $errors[] = array(
- 'error' => $l->t('Error occurred while checking PostgreSQL version'),
- 'hint' => $l->t('Please make sure you have PostgreSQL >= 9 or'
- . ' check the logs for more information about the error')
- );
+ $logger = \OC::$server->getLogger();
+ $logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
+ $logger->logException($e);
}
}
return $errors;
@@ -946,26 +961,22 @@ class OC_Util {
$parameters['redirect_url'] = $_REQUEST['redirect_url'];
}
+ $parameters['canResetPassword'] = true;
+ if (!\OC::$server->getSystemConfig()->getValue('lost_password_link')) {
+ if (isset($_REQUEST['user'])) {
+ $user = \OC::$server->getUserManager()->get($_REQUEST['user']);
+ if ($user instanceof IUser) {
+ $parameters['canResetPassword'] = $user->canChangePassword();
+ }
+ }
+ }
+
$parameters['alt_login'] = OC_App::getAlternativeLogIns();
$parameters['rememberLoginAllowed'] = self::rememberLoginAllowed();
\OC_Hook::emit('OC_Util', 'pre_displayLoginPage', array('parameters' => $parameters));
OC_Template::printGuestPage("", "login", $parameters);
}
-
- /**
- * Check if the app is enabled, redirects to home if not
- *
- * @param string $app
- * @return void
- */
- public static function checkAppEnabled($app) {
- if (!OC_App::isEnabled($app)) {
- header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php'));
- exit();
- }
- }
-
/**
* Check if the user is logged in, redirects to home if not. With
* redirect URL parameter to the request URI.
@@ -975,7 +986,7 @@ class OC_Util {
public static function checkLoggedIn() {
// Check if we are a user
if (!OC_User::isLoggedIn()) {
- header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php',
+ header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php',
[
'redirect_url' => \OC::$server->getRequest()->getRequestUri()
]
@@ -993,7 +1004,7 @@ class OC_Util {
public static function checkAdminUser() {
OC_Util::checkLoggedIn();
if (!OC_User::isAdminUser(OC_User::getUser())) {
- header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php'));
+ header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
exit();
}
}
@@ -1033,7 +1044,7 @@ class OC_Util {
}
if (!$isSubAdmin) {
- header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php'));
+ header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
exit();
}
return true;
@@ -1067,7 +1078,12 @@ class OC_Util {
break;
}
}
- $location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
+
+ if(getenv('front_controller_active') === 'true') {
+ $location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
+ } else {
+ $location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
+ }
}
}
return $location;
@@ -1090,87 +1106,31 @@ class OC_Util {
* @return string
*/
public static function getInstanceId() {
- $id = OC_Config::getValue('instanceid', null);
+ $id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
if (is_null($id)) {
// We need to guarantee at least one letter in instanceid so it can be used as the session_name
- $id = 'oc' . \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
- OC_Config::$object->setValue('instanceid', $id);
+ $id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
+ \OC::$server->getSystemConfig()->setValue('instanceid', $id);
}
return $id;
}
- protected static $obfuscatedToken;
- /**
- * Register an get/post call. Important to prevent CSRF attacks.
- *
- * @return string The encrypted CSRF token, the shared secret is appended after the `:`.
- *
- * @description
- * Creates a 'request token' (random) and stores it inside the session.
- * Ever subsequent (ajax) request must use such a valid token to succeed,
- * otherwise the request will be denied as a protection against CSRF.
- * @see OC_Util::isCallRegistered()
- */
- public static function callRegister() {
- // Use existing token if function has already been called
- if(isset(self::$obfuscatedToken)) {
- return self::$obfuscatedToken;
- }
-
- $tokenLength = 30;
-
- // Check if a token exists
- if (!\OC::$server->getSession()->exists('requesttoken')) {
- // No valid token found, generate a new one.
- $requestToken = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate($tokenLength);
- \OC::$server->getSession()->set('requesttoken', $requestToken);
- } else {
- // Valid token already exists, send it
- $requestToken = \OC::$server->getSession()->get('requesttoken');
- }
-
- // XOR the token to mitigate breach-like attacks
- $sharedSecret = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate($tokenLength);
- self::$obfuscatedToken = base64_encode($requestToken ^ $sharedSecret) .':'.$sharedSecret;
-
- return self::$obfuscatedToken;
- }
-
- /**
- * Check an ajax get/post call if the request token is valid.
- *
- * @return boolean False if request token is not set or is invalid.
- * @see OC_Util::callRegister()
- */
- public static function isCallRegistered() {
- return \OC::$server->getRequest()->passesCSRFCheck();
- }
-
- /**
- * Check an ajax get/post call if the request token is valid. Exit if not.
- *
- * @return void
- */
- public static function callCheck() {
- if (!OC_Util::isCallRegistered()) {
- exit();
- }
- }
-
/**
* Public function to sanitize HTML
*
* This function is used to sanitize HTML and should be applied on any
* string or array of strings before displaying it on a web page.
*
- * @param string|array &$value
+ * @param string|array $value
* @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
*/
- public static function sanitizeHTML(&$value) {
+ public static function sanitizeHTML($value) {
if (is_array($value)) {
- array_walk_recursive($value, 'OC_Util::sanitizeHTML');
+ $value = array_map(function($value) {
+ return self::sanitizeHTML($value);
+ }, $value);
} else {
- //Specify encoding for PHP<5.4
+ // Specify encoding for PHP<5.4
$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
}
return $value;
@@ -1230,8 +1190,12 @@ class OC_Util {
fclose($fp);
// accessing the file via http
- $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT . '/data' . $fileName);
- $content = self::getUrlContent($url);
+ $url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
+ try {
+ $content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
+ } catch (\Exception $e) {
+ $content = false;
+ }
// cleanup
@unlink($testFile);
@@ -1294,35 +1258,6 @@ class OC_Util {
}
}
-
- /**
- * Generates a cryptographic secure pseudo-random string
- *
- * @param int $length of the random string
- * @return string
- * @deprecated Use \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate($length); instead
- */
- public static function generateRandomBytes($length = 30) {
- return \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate($length, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
- }
-
- /**
- * Get URL content
- * @param string $url Url to get content
- * @throws Exception If the URL does not start with http:// or https://
- * @return string of the response or false on error
- * This function get the content of a page via curl, if curl is enabled.
- * If not, file_get_contents is used.
- * @deprecated Use \OC::$server->getHTTPClientService()->newClient()->get($url);
- */
- public static function getUrlContent($url) {
- try {
- return \OC::$server->getHTTPHelper()->getUrlContent($url);
- } catch (\Exception $e) {
- throw $e;
- }
- }
-
/**
* Checks whether the server is running on Windows
*
@@ -1357,7 +1292,7 @@ class OC_Util {
* @return string the theme
*/
public static function getTheme() {
- $theme = OC_Config::getValue("theme", '');
+ $theme = \OC::$server->getSystemConfig()->getValue("theme", '');
if ($theme === '') {
if (is_dir(OC::$SERVERROOT . '/themes/default')) {
@@ -1412,7 +1347,7 @@ class OC_Util {
}
// XCache
if (function_exists('xcache_clear_cache')) {
- if (ini_get('xcache.admin.enable_auth')) {
+ if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
\OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN);
} else {
@xcache_clear_cache(XC_TYPE_PHP, 0);
@@ -1498,14 +1433,28 @@ class OC_Util {
*
* @param \OCP\IConfig $config
* @return bool whether the core or any app needs an upgrade
+ * @throws \OC\HintException When the upgrade from the given version is not allowed
*/
public static function needUpgrade(\OCP\IConfig $config) {
if ($config->getSystemValue('installed', false)) {
$installedVersion = $config->getSystemValue('version', '0.0.0');
- $currentVersion = implode('.', OC_Util::getVersion());
+ $currentVersion = implode('.', \OCP\Util::getVersion());
$versionDiff = version_compare($currentVersion, $installedVersion);
if ($versionDiff > 0) {
return true;
+ } else if ($config->getSystemValue('debug', false) && $versionDiff < 0) {
+ // downgrade with debug
+ $installedMajor = explode('.', $installedVersion);
+ $installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
+ $currentMajor = explode('.', $currentVersion);
+ $currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
+ if ($installedMajor === $currentMajor) {
+ // Same major, allow downgrade for developers
+ return true;
+ } else {
+ // downgrade attempt, throw exception
+ throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
+ }
} else if ($versionDiff < 0) {
// downgrade attempt, throw exception
throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
diff --git a/lib/public/activity/iconsumer.php b/lib/public/activity/iconsumer.php
index 796bf1d8884..fc536fd0a56 100644
--- a/lib/public/activity/iconsumer.php
+++ b/lib/public/activity/iconsumer.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/activity/ievent.php b/lib/public/activity/ievent.php
index 184c7ae503f..9b6df9126b2 100644
--- a/lib/public/activity/ievent.php
+++ b/lib/public/activity/ievent.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/activity/iextension.php b/lib/public/activity/iextension.php
index 5d9fe3329ef..b00dbdda20a 100644
--- a/lib/public/activity/iextension.php
+++ b/lib/public/activity/iextension.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -57,8 +57,7 @@ interface IExtension {
* 'desc' => "translated string description for the setting"
* 'methods' => [self::METHOD_*],
* ]
- * @since 8.0.0
- * @changed 8.2.0 - Added support to allow limiting notifications to certain methods
+ * @since 8.0.0 - 8.2.0: Added support to allow limiting notifications to certain methods
*/
public function getNotificationTypes($languageCode);
diff --git a/lib/public/activity/imanager.php b/lib/public/activity/imanager.php
index 280babb7fa9..0b97f8a07ed 100644
--- a/lib/public/activity/imanager.php
+++ b/lib/public/activity/imanager.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -118,8 +118,7 @@ interface IManager {
* 'desc' => "translated string description for the setting"
* 'methods' => [\OCP\Activity\IExtension::METHOD_*],
* ]
- * @since 8.0.0
- * @changed 8.2.0 - Added support to allow limiting notifications to certain methods
+ * @since 8.0.0 - 8.2.0: Added support to allow limiting notifications to certain methods
*/
public function getNotificationTypes($languageCode);
diff --git a/lib/public/api.php b/lib/public/api.php
index a99a3af1c1d..4d68bef6f29 100644
--- a/lib/public/api.php
+++ b/lib/public/api.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/app.php b/lib/public/app.php
index c66d988c315..e25f025d12d 100644
--- a/lib/public/app.php
+++ b/lib/public/app.php
@@ -6,10 +6,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -82,7 +82,8 @@ class App {
* @since 4.0.0
*/
public static function setActiveNavigationEntry( $id ) {
- return \OC_App::setActiveNavigationEntry( $id );
+ \OC::$server->getNavigationManager()->setActiveEntry($id);
+ return true;
}
/**
@@ -135,9 +136,9 @@ class App {
* @param string $app
* @return void
* @since 4.0.0
+ * @deprecated 9.0.0 ownCloud core will handle disabled apps and redirects to valid URLs
*/
public static function checkAppEnabled( $app ) {
- \OC_Util::checkAppEnabled( $app );
}
/**
diff --git a/lib/public/app/iappmanager.php b/lib/public/app/iappmanager.php
index 09b6bd3f2b9..0e1e0dfbebd 100644
--- a/lib/public/app/iappmanager.php
+++ b/lib/public/app/iappmanager.php
@@ -3,8 +3,9 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/apicontroller.php b/lib/public/appframework/apicontroller.php
index 90eea47d730..64e07539de4 100644
--- a/lib/public/appframework/apicontroller.php
+++ b/lib/public/appframework/apicontroller.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/app.php b/lib/public/appframework/app.php
index bf4e14961f5..09297d91ee8 100644
--- a/lib/public/appframework/app.php
+++ b/lib/public/appframework/app.php
@@ -6,7 +6,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/controller.php b/lib/public/appframework/controller.php
index 6e2ceff93e8..c3744683300 100644
--- a/lib/public/appframework/controller.php
+++ b/lib/public/appframework/controller.php
@@ -8,7 +8,7 @@
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -72,7 +72,7 @@ abstract class Controller {
* @since 6.0.0 - parameter $appName was added in 7.0.0 - parameter $app was removed in 7.0.0
*/
public function __construct($appName,
- IRequest $request){
+ IRequest $request) {
$this->appName = $appName;
$this->request = $request;
diff --git a/lib/public/appframework/db/doesnotexistexception.php b/lib/public/appframework/db/doesnotexistexception.php
index 2cefa0fe827..9682a08d3cf 100644
--- a/lib/public/appframework/db/doesnotexistexception.php
+++ b/lib/public/appframework/db/doesnotexistexception.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/db/entity.php b/lib/public/appframework/db/entity.php
index f7beebef154..d7db4d3c5a7 100644
--- a/lib/public/appframework/db/entity.php
+++ b/lib/public/appframework/db/entity.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/db/mapper.php b/lib/public/appframework/db/mapper.php
index 2b99c99b71e..065a9f01ea1 100644
--- a/lib/public/appframework/db/mapper.php
+++ b/lib/public/appframework/db/mapper.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/db/multipleobjectsreturnedexception.php b/lib/public/appframework/db/multipleobjectsreturnedexception.php
index 988bf6bb033..b9207051826 100644
--- a/lib/public/appframework/db/multipleobjectsreturnedexception.php
+++ b/lib/public/appframework/db/multipleobjectsreturnedexception.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http.php b/lib/public/appframework/http.php
index 65b62ffd15a..e0108146db7 100644
--- a/lib/public/appframework/http.php
+++ b/lib/public/appframework/http.php
@@ -4,7 +4,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/contentsecuritypolicy.php b/lib/public/appframework/http/contentsecuritypolicy.php
index 5371d76ff22..7762ca809a2 100644
--- a/lib/public/appframework/http/contentsecuritypolicy.php
+++ b/lib/public/appframework/http/contentsecuritypolicy.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author sualko <klaus@jsxc.org>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -38,17 +38,17 @@ use OCP\AppFramework\Http;
* @package OCP\AppFramework\Http
* @since 8.1.0
*/
-class ContentSecurityPolicy {
+class ContentSecurityPolicy extends EmptyContentSecurityPolicy {
/** @var bool Whether inline JS snippets are allowed */
- private $inlineScriptAllowed = false;
+ protected $inlineScriptAllowed = false;
/**
* @var bool Whether eval in JS scripts is allowed
* TODO: Disallow per default
* @link https://github.com/owncloud/core/issues/11925
*/
- private $evalScriptAllowed = true;
+ protected $evalScriptAllowed = true;
/** @var array Domains from which scripts can get loaded */
- private $allowedScriptDomains = [
+ protected $allowedScriptDomains = [
'\'self\'',
];
/**
@@ -56,342 +56,33 @@ class ContentSecurityPolicy {
* TODO: Disallow per default
* @link https://github.com/owncloud/core/issues/13458
*/
- private $inlineStyleAllowed = true;
+ protected $inlineStyleAllowed = true;
/** @var array Domains from which CSS can get loaded */
- private $allowedStyleDomains = [
+ protected $allowedStyleDomains = [
'\'self\'',
];
/** @var array Domains from which images can get loaded */
- private $allowedImageDomains = [
+ protected $allowedImageDomains = [
'\'self\'',
'data:',
'blob:',
];
/** @var array Domains to which connections can be done */
- private $allowedConnectDomains = [
+ protected $allowedConnectDomains = [
'\'self\'',
];
/** @var array Domains from which media elements can be loaded */
- private $allowedMediaDomains = [
+ protected $allowedMediaDomains = [
'\'self\'',
];
/** @var array Domains from which object elements can be loaded */
- private $allowedObjectDomains = [];
+ protected $allowedObjectDomains = [];
/** @var array Domains from which iframes can be loaded */
- private $allowedFrameDomains = [];
+ protected $allowedFrameDomains = [];
/** @var array Domains from which fonts can be loaded */
- private $allowedFontDomains = [
+ protected $allowedFontDomains = [
'\'self\'',
];
/** @var array Domains from which web-workers and nested browsing content can load elements */
- private $allowedChildSrcDomains = [];
-
- /**
- * Whether inline JavaScript snippets are allowed or forbidden
- * @param bool $state
- * @return $this
- * @since 8.1.0
- */
- public function allowInlineScript($state = false) {
- $this->inlineScriptAllowed = $state;
- return $this;
- }
-
- /**
- * Whether eval in JavaScript is allowed or forbidden
- * @param bool $state
- * @return $this
- * @since 8.1.0
- */
- public function allowEvalScript($state = true) {
- $this->evalScriptAllowed = $state;
- return $this;
- }
-
- /**
- * Allows to execute JavaScript files from a specific domain. Use * to
- * allow JavaScript from all domains.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedScriptDomain($domain) {
- $this->allowedScriptDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed script domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowScriptDomain($domain) {
- $this->allowedScriptDomains = array_diff($this->allowedScriptDomains, [$domain]);
- return $this;
- }
-
- /**
- * Whether inline CSS snippets are allowed or forbidden
- * @param bool $state
- * @return $this
- * @since 8.1.0
- */
- public function allowInlineStyle($state = true) {
- $this->inlineStyleAllowed = $state;
- return $this;
- }
-
- /**
- * Allows to execute CSS files from a specific domain. Use * to allow
- * CSS from all domains.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedStyleDomain($domain) {
- $this->allowedStyleDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed style domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowStyleDomain($domain) {
- $this->allowedStyleDomains = array_diff($this->allowedStyleDomains, [$domain]);
- return $this;
- }
-
- /**
- * Allows using fonts from a specific domain. Use * to allow
- * fonts from all domains.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedFontDomain($domain) {
- $this->allowedFontDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed font domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowFontDomain($domain) {
- $this->allowedFontDomains = array_diff($this->allowedFontDomains, [$domain]);
- return $this;
- }
-
- /**
- * Allows embedding images from a specific domain. Use * to allow
- * images from all domains.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedImageDomain($domain) {
- $this->allowedImageDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed image domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowImageDomain($domain) {
- $this->allowedImageDomains = array_diff($this->allowedImageDomains, [$domain]);
- return $this;
- }
-
- /**
- * To which remote domains the JS connect to.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedConnectDomain($domain) {
- $this->allowedConnectDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed connect domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowConnectDomain($domain) {
- $this->allowedConnectDomains = array_diff($this->allowedConnectDomains, [$domain]);
- return $this;
- }
-
- /**
- * From which domains media elements can be embedded.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedMediaDomain($domain) {
- $this->allowedMediaDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed media domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowMediaDomain($domain) {
- $this->allowedMediaDomains = array_diff($this->allowedMediaDomains, [$domain]);
- return $this;
- }
-
- /**
- * From which domains objects such as <object>, <embed> or <applet> are executed
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedObjectDomain($domain) {
- $this->allowedObjectDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed object domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowObjectDomain($domain) {
- $this->allowedObjectDomains = array_diff($this->allowedObjectDomains, [$domain]);
- return $this;
- }
-
- /**
- * Which domains can be embedded in an iframe
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedFrameDomain($domain) {
- $this->allowedFrameDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed frame domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowFrameDomain($domain) {
- $this->allowedFrameDomains = array_diff($this->allowedFrameDomains, [$domain]);
- return $this;
- }
-
- /**
- * Domains from which web-workers and nested browsing content can load elements
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedChildSrcDomain($domain) {
- $this->allowedChildSrcDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed child src domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowChildSrcDomain($domain) {
- $this->allowedChildSrcDomains = array_diff($this->allowedChildSrcDomains, [$domain]);
- return $this;
- }
-
- /**
- * Get the generated Content-Security-Policy as a string
- * @return string
- * @since 8.1.0
- */
- public function buildPolicy() {
- $policy = "default-src 'none';";
-
- if(!empty($this->allowedScriptDomains)) {
- $policy .= 'script-src ' . implode(' ', $this->allowedScriptDomains);
- if($this->inlineScriptAllowed) {
- $policy .= ' \'unsafe-inline\'';
- }
- if($this->evalScriptAllowed) {
- $policy .= ' \'unsafe-eval\'';
- }
- $policy .= ';';
- }
-
- if(!empty($this->allowedStyleDomains)) {
- $policy .= 'style-src ' . implode(' ', $this->allowedStyleDomains);
- if($this->inlineStyleAllowed) {
- $policy .= ' \'unsafe-inline\'';
- }
- $policy .= ';';
- }
-
- if(!empty($this->allowedImageDomains)) {
- $policy .= 'img-src ' . implode(' ', $this->allowedImageDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedFontDomains)) {
- $policy .= 'font-src ' . implode(' ', $this->allowedFontDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedConnectDomains)) {
- $policy .= 'connect-src ' . implode(' ', $this->allowedConnectDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedMediaDomains)) {
- $policy .= 'media-src ' . implode(' ', $this->allowedMediaDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedObjectDomains)) {
- $policy .= 'object-src ' . implode(' ', $this->allowedObjectDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedFrameDomains)) {
- $policy .= 'frame-src ' . implode(' ', $this->allowedFrameDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedChildSrcDomains)) {
- $policy .= 'child-src ' . implode(' ', $this->allowedChildSrcDomains);
- $policy .= ';';
- }
-
- return rtrim($policy, ';');
- }
+ protected $allowedChildSrcDomains = [];
}
diff --git a/lib/public/appframework/http/datadisplayresponse.php b/lib/public/appframework/http/datadisplayresponse.php
index 2691091347a..4209c86a059 100644
--- a/lib/public/appframework/http/datadisplayresponse.php
+++ b/lib/public/appframework/http/datadisplayresponse.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/datadownloadresponse.php b/lib/public/appframework/http/datadownloadresponse.php
index 612386f9801..55ef4e6c82c 100644
--- a/lib/public/appframework/http/datadownloadresponse.php
+++ b/lib/public/appframework/http/datadownloadresponse.php
@@ -3,7 +3,7 @@
* @author Georg Ehrke <georg@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/dataresponse.php b/lib/public/appframework/http/dataresponse.php
index 555faa6ea1a..3ec4e2bdc32 100644
--- a/lib/public/appframework/http/dataresponse.php
+++ b/lib/public/appframework/http/dataresponse.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/downloadresponse.php b/lib/public/appframework/http/downloadresponse.php
index 0b9a8bcc6d8..af0d76951ca 100644
--- a/lib/public/appframework/http/downloadresponse.php
+++ b/lib/public/appframework/http/downloadresponse.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/emptycontentsecuritypolicy.php b/lib/public/appframework/http/emptycontentsecuritypolicy.php
new file mode 100644
index 00000000000..33860dcdb0f
--- /dev/null
+++ b/lib/public/appframework/http/emptycontentsecuritypolicy.php
@@ -0,0 +1,387 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author sualko <klaus@jsxc.org>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\AppFramework\Http;
+
+use OCP\AppFramework\Http;
+
+/**
+ * Class EmptyContentSecurityPolicy is a simple helper which allows applications
+ * to modify the Content-Security-Policy sent by ownCloud. Per default the policy
+ * is forbidding everything.
+ *
+ * As alternative with sane exemptions look at ContentSecurityPolicy
+ *
+ * @see \OCP\AppFramework\Http\ContentSecurityPolicy
+ * @package OCP\AppFramework\Http
+ * @since 9.0.0
+ */
+class EmptyContentSecurityPolicy {
+ /** @var bool Whether inline JS snippets are allowed */
+ protected $inlineScriptAllowed = null;
+ /**
+ * @var bool Whether eval in JS scripts is allowed
+ * TODO: Disallow per default
+ * @link https://github.com/owncloud/core/issues/11925
+ */
+ protected $evalScriptAllowed = null;
+ /** @var array Domains from which scripts can get loaded */
+ protected $allowedScriptDomains = null;
+ /**
+ * @var bool Whether inline CSS is allowed
+ * TODO: Disallow per default
+ * @link https://github.com/owncloud/core/issues/13458
+ */
+ protected $inlineStyleAllowed = null;
+ /** @var array Domains from which CSS can get loaded */
+ protected $allowedStyleDomains = null;
+ /** @var array Domains from which images can get loaded */
+ protected $allowedImageDomains = null;
+ /** @var array Domains to which connections can be done */
+ protected $allowedConnectDomains = null;
+ /** @var array Domains from which media elements can be loaded */
+ protected $allowedMediaDomains = null;
+ /** @var array Domains from which object elements can be loaded */
+ protected $allowedObjectDomains = null;
+ /** @var array Domains from which iframes can be loaded */
+ protected $allowedFrameDomains = null;
+ /** @var array Domains from which fonts can be loaded */
+ protected $allowedFontDomains = null;
+ /** @var array Domains from which web-workers and nested browsing content can load elements */
+ protected $allowedChildSrcDomains = null;
+
+ /**
+ * Whether inline JavaScript snippets are allowed or forbidden
+ * @param bool $state
+ * @return $this
+ * @since 8.1.0
+ */
+ public function allowInlineScript($state = false) {
+ $this->inlineScriptAllowed = $state;
+ return $this;
+ }
+
+ /**
+ * Whether eval in JavaScript is allowed or forbidden
+ * @param bool $state
+ * @return $this
+ * @since 8.1.0
+ */
+ public function allowEvalScript($state = true) {
+ $this->evalScriptAllowed = $state;
+ return $this;
+ }
+
+ /**
+ * Allows to execute JavaScript files from a specific domain. Use * to
+ * allow JavaScript from all domains.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedScriptDomain($domain) {
+ $this->allowedScriptDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed script domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowScriptDomain($domain) {
+ $this->allowedScriptDomains = array_diff($this->allowedScriptDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Whether inline CSS snippets are allowed or forbidden
+ * @param bool $state
+ * @return $this
+ * @since 8.1.0
+ */
+ public function allowInlineStyle($state = true) {
+ $this->inlineStyleAllowed = $state;
+ return $this;
+ }
+
+ /**
+ * Allows to execute CSS files from a specific domain. Use * to allow
+ * CSS from all domains.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedStyleDomain($domain) {
+ $this->allowedStyleDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed style domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowStyleDomain($domain) {
+ $this->allowedStyleDomains = array_diff($this->allowedStyleDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Allows using fonts from a specific domain. Use * to allow
+ * fonts from all domains.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedFontDomain($domain) {
+ $this->allowedFontDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed font domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowFontDomain($domain) {
+ $this->allowedFontDomains = array_diff($this->allowedFontDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Allows embedding images from a specific domain. Use * to allow
+ * images from all domains.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedImageDomain($domain) {
+ $this->allowedImageDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed image domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowImageDomain($domain) {
+ $this->allowedImageDomains = array_diff($this->allowedImageDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * To which remote domains the JS connect to.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedConnectDomain($domain) {
+ $this->allowedConnectDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed connect domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowConnectDomain($domain) {
+ $this->allowedConnectDomains = array_diff($this->allowedConnectDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * From which domains media elements can be embedded.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedMediaDomain($domain) {
+ $this->allowedMediaDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed media domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowMediaDomain($domain) {
+ $this->allowedMediaDomains = array_diff($this->allowedMediaDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * From which domains objects such as <object>, <embed> or <applet> are executed
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedObjectDomain($domain) {
+ $this->allowedObjectDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed object domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowObjectDomain($domain) {
+ $this->allowedObjectDomains = array_diff($this->allowedObjectDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Which domains can be embedded in an iframe
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedFrameDomain($domain) {
+ $this->allowedFrameDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed frame domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowFrameDomain($domain) {
+ $this->allowedFrameDomains = array_diff($this->allowedFrameDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Domains from which web-workers and nested browsing content can load elements
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedChildSrcDomain($domain) {
+ $this->allowedChildSrcDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed child src domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowChildSrcDomain($domain) {
+ $this->allowedChildSrcDomains = array_diff($this->allowedChildSrcDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Get the generated Content-Security-Policy as a string
+ * @return string
+ * @since 8.1.0
+ */
+ public function buildPolicy() {
+ $policy = "default-src 'none';";
+
+ if(!empty($this->allowedScriptDomains) || $this->inlineScriptAllowed || $this->evalScriptAllowed) {
+ $policy .= 'script-src ';
+ if(is_array($this->allowedScriptDomains)) {
+ $policy .= implode(' ', $this->allowedScriptDomains);
+ }
+ if($this->inlineScriptAllowed) {
+ $policy .= ' \'unsafe-inline\'';
+ }
+ if($this->evalScriptAllowed) {
+ $policy .= ' \'unsafe-eval\'';
+ }
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedStyleDomains) || $this->inlineStyleAllowed) {
+ $policy .= 'style-src ';
+ if(is_array($this->allowedStyleDomains)) {
+ $policy .= implode(' ', $this->allowedStyleDomains);
+ }
+ if($this->inlineStyleAllowed) {
+ $policy .= ' \'unsafe-inline\'';
+ }
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedImageDomains)) {
+ $policy .= 'img-src ' . implode(' ', $this->allowedImageDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedFontDomains)) {
+ $policy .= 'font-src ' . implode(' ', $this->allowedFontDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedConnectDomains)) {
+ $policy .= 'connect-src ' . implode(' ', $this->allowedConnectDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedMediaDomains)) {
+ $policy .= 'media-src ' . implode(' ', $this->allowedMediaDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedObjectDomains)) {
+ $policy .= 'object-src ' . implode(' ', $this->allowedObjectDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedFrameDomains)) {
+ $policy .= 'frame-src ' . implode(' ', $this->allowedFrameDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedChildSrcDomains)) {
+ $policy .= 'child-src ' . implode(' ', $this->allowedChildSrcDomains);
+ $policy .= ';';
+ }
+
+ return rtrim($policy, ';');
+ }
+}
diff --git a/lib/public/appframework/http/icallbackresponse.php b/lib/public/appframework/http/icallbackresponse.php
index aa238cbcac9..97de484e917 100644
--- a/lib/public/appframework/http/icallbackresponse.php
+++ b/lib/public/appframework/http/icallbackresponse.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/ioutput.php b/lib/public/appframework/http/ioutput.php
index 9a4047fe30c..f4ebc304bde 100644
--- a/lib/public/appframework/http/ioutput.php
+++ b/lib/public/appframework/http/ioutput.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/jsonresponse.php b/lib/public/appframework/http/jsonresponse.php
index 306c70327b1..89433fd23e5 100644
--- a/lib/public/appframework/http/jsonresponse.php
+++ b/lib/public/appframework/http/jsonresponse.php
@@ -6,7 +6,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/notfoundresponse.php b/lib/public/appframework/http/notfoundresponse.php
index 968df6c310c..8dcebd7cceb 100644
--- a/lib/public/appframework/http/notfoundresponse.php
+++ b/lib/public/appframework/http/notfoundresponse.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/ocsresponse.php b/lib/public/appframework/http/ocsresponse.php
index f26d219e581..da9de712c0a 100644
--- a/lib/public/appframework/http/ocsresponse.php
+++ b/lib/public/appframework/http/ocsresponse.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/redirectresponse.php b/lib/public/appframework/http/redirectresponse.php
index 41a2e48035e..7208012295f 100644
--- a/lib/public/appframework/http/redirectresponse.php
+++ b/lib/public/appframework/http/redirectresponse.php
@@ -5,7 +5,7 @@
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/response.php b/lib/public/appframework/http/response.php
index f6c9460ff15..253d58b86ff 100644
--- a/lib/public/appframework/http/response.php
+++ b/lib/public/appframework/http/response.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/streamresponse.php b/lib/public/appframework/http/streamresponse.php
index b2e0df3a75f..e9157f9ddb2 100644
--- a/lib/public/appframework/http/streamresponse.php
+++ b/lib/public/appframework/http/streamresponse.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/http/templateresponse.php b/lib/public/appframework/http/templateresponse.php
index 961903a8eab..7774d881e4d 100644
--- a/lib/public/appframework/http/templateresponse.php
+++ b/lib/public/appframework/http/templateresponse.php
@@ -5,7 +5,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/iapi.php b/lib/public/appframework/iapi.php
index 7d1d230a77f..66614328873 100644
--- a/lib/public/appframework/iapi.php
+++ b/lib/public/appframework/iapi.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/iappcontainer.php b/lib/public/appframework/iappcontainer.php
index 1cc0daf68ad..905539e735e 100644
--- a/lib/public/appframework/iappcontainer.php
+++ b/lib/public/appframework/iappcontainer.php
@@ -6,7 +6,7 @@
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/middleware.php b/lib/public/appframework/middleware.php
index 6c75a2dfc74..a39e26a2aa0 100644
--- a/lib/public/appframework/middleware.php
+++ b/lib/public/appframework/middleware.php
@@ -4,7 +4,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/ocscontroller.php b/lib/public/appframework/ocscontroller.php
index 8b04d65d8c3..b0e77c5d1ec 100644
--- a/lib/public/appframework/ocscontroller.php
+++ b/lib/public/appframework/ocscontroller.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/queryexception.php b/lib/public/appframework/queryexception.php
index c8cd0cfe9fb..62ab77dd839 100644
--- a/lib/public/appframework/queryexception.php
+++ b/lib/public/appframework/queryexception.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/utility/icontrollermethodreflector.php b/lib/public/appframework/utility/icontrollermethodreflector.php
index a3b57cf6936..b2f91fdb170 100644
--- a/lib/public/appframework/utility/icontrollermethodreflector.php
+++ b/lib/public/appframework/utility/icontrollermethodreflector.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/appframework/utility/itimefactory.php b/lib/public/appframework/utility/itimefactory.php
index 6fe2fab2557..a3333dd1949 100644
--- a/lib/public/appframework/utility/itimefactory.php
+++ b/lib/public/appframework/utility/itimefactory.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/authentication/iapachebackend.php b/lib/public/authentication/iapachebackend.php
index 51ca57788f3..f1f408cfa6d 100644
--- a/lib/public/authentication/iapachebackend.php
+++ b/lib/public/authentication/iapachebackend.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/autoloadnotallowedexception.php b/lib/public/autoloadnotallowedexception.php
index 2e6556c4a7b..f0028b7d49d 100644
--- a/lib/public/autoloadnotallowedexception.php
+++ b/lib/public/autoloadnotallowedexception.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/backgroundjob.php b/lib/public/backgroundjob.php
index 42fcf76b876..cc76506758b 100644
--- a/lib/public/backgroundjob.php
+++ b/lib/public/backgroundjob.php
@@ -6,10 +6,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -34,7 +34,6 @@
// This means that they should be used by apps instead of the internal ownCloud classes
namespace OCP;
-use \OC\BackgroundJob\JobList;
/**
* This class provides functions to register backgroundjobs in ownCloud
@@ -115,16 +114,7 @@ class BackgroundJob {
* @since 4.5.0
*/
static public function allRegularTasks() {
- $jobList = \OC::$server->getJobList();
- $allJobs = $jobList->getAll();
- $regularJobs = array();
- foreach ($allJobs as $job) {
- if ($job instanceof RegularLegacyJob) {
- $key = implode('-', $job->getArgument());
- $regularJobs[$key] = $job->getArgument();
- }
- }
- return $regularJobs;
+ return [];
}
/**
@@ -146,17 +136,7 @@ class BackgroundJob {
* @since 4.5.0
*/
public static function allQueuedTasks() {
- $jobList = \OC::$server->getJobList();
- $allJobs = $jobList->getAll();
- $queuedJobs = array();
- foreach ($allJobs as $job) {
- if ($job instanceof QueuedLegacyJob) {
- $queuedJob = $job->getArgument();
- $queuedJob['id'] = $job->getId();
- $queuedJobs[] = $queuedJob;
- }
- }
- return $queuedJobs;
+ return [];
}
/**
@@ -167,19 +147,7 @@ class BackgroundJob {
* @since 4.5.0
*/
public static function queuedTaskWhereAppIs($app) {
- $jobList = \OC::$server->getJobList();
- $allJobs = $jobList->getAll();
- $queuedJobs = array();
- foreach ($allJobs as $job) {
- if ($job instanceof QueuedLegacyJob) {
- $queuedJob = $job->getArgument();
- $queuedJob['id'] = $job->getId();
- if ($queuedJob['app'] === $app) {
- $queuedJobs[] = $queuedJob;
- }
- }
- }
- return $queuedJobs;
+ return [];
}
/**
diff --git a/lib/public/backgroundjob/ijob.php b/lib/public/backgroundjob/ijob.php
index a24a5434521..71cdee65636 100644
--- a/lib/public/backgroundjob/ijob.php
+++ b/lib/public/backgroundjob/ijob.php
@@ -1,10 +1,10 @@
<?php
/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -36,12 +36,29 @@ interface IJob {
*
* @param \OCP\BackgroundJob\IJobList $jobList The job list that manages the state of this job
* @param ILogger $logger
- * @return void
* @since 7.0.0
*/
public function execute($jobList, ILogger $logger = null);
/**
+ * @param int $id
+ * @since 7.0.0
+ */
+ public function setId($id);
+
+ /**
+ * @param int $lastRun
+ * @since 7.0.0
+ */
+ public function setLastRun($lastRun);
+
+ /**
+ * @param mixed $argument
+ * @since 7.0.0
+ */
+ public function setArgument($argument);
+
+ /**
* Get the id of the background job
* This id is determined by the job list when a job is added to the list
*
diff --git a/lib/public/backgroundjob/ijoblist.php b/lib/public/backgroundjob/ijoblist.php
index e2dc348e54d..5a76ce1ba26 100644
--- a/lib/public/backgroundjob/ijoblist.php
+++ b/lib/public/backgroundjob/ijoblist.php
@@ -1,11 +1,11 @@
<?php
/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -36,8 +36,6 @@ interface IJobList {
*
* @param \OCP\BackgroundJob\IJob|string $job
* @param mixed $argument The argument to be passed to $job->run() when the job is exectured
- * @param string $job
- * @return void
* @since 7.0.0
*/
public function add($job, $argument = null);
@@ -47,7 +45,6 @@ interface IJobList {
*
* @param \OCP\BackgroundJob\IJob|string $job
* @param mixed $argument
- * @return void
* @since 7.0.0
*/
public function remove($job, $argument = null);
@@ -67,20 +64,22 @@ interface IJobList {
*
* @return \OCP\BackgroundJob\IJob[]
* @since 7.0.0
+ * @deprecated 9.0.0 - This method is dangerous since it can cause load and
+ * memory problems when creating too many instances.
*/
public function getAll();
/**
* get the next job in the list
*
- * @return \OCP\BackgroundJob\IJob
+ * @return \OCP\BackgroundJob\IJob|null
* @since 7.0.0
*/
public function getNext();
/**
* @param int $id
- * @return \OCP\BackgroundJob\IJob
+ * @return \OCP\BackgroundJob\IJob|null
* @since 7.0.0
*/
public function getById($id);
@@ -89,7 +88,6 @@ interface IJobList {
* set the job that was last ran to the current time
*
* @param \OCP\BackgroundJob\IJob $job
- * @return void
* @since 7.0.0
*/
public function setLastJob($job);
@@ -106,7 +104,6 @@ interface IJobList {
* set the lastRun of $job to now
*
* @param \OCP\BackgroundJob\IJob $job
- * @return void
* @since 7.0.0
*/
public function setLastRun($job);
diff --git a/lib/public/capabilities/icapability.php b/lib/public/capabilities/icapability.php
index b43387aad7e..0facab6f255 100644
--- a/lib/public/capabilities/icapability.php
+++ b/lib/public/capabilities/icapability.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/command/ibus.php b/lib/public/command/ibus.php
index 796862fbcac..62b6edef4d4 100644
--- a/lib/public/command/ibus.php
+++ b/lib/public/command/ibus.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/command/icommand.php b/lib/public/command/icommand.php
index ed152f4c6c3..e53d52d2fa3 100644
--- a/lib/public/command/icommand.php
+++ b/lib/public/command/icommand.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/comments/icomment.php b/lib/public/comments/icomment.php
new file mode 100644
index 00000000000..e695b5193f2
--- /dev/null
+++ b/lib/public/comments/icomment.php
@@ -0,0 +1,234 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Comments;
+
+/**
+ * Interface IComment
+ *
+ * This class represents a comment
+ *
+ * @package OCP\Comments
+ * @since 9.0.0
+ */
+interface IComment {
+
+ /**
+ * returns the ID of the comment
+ *
+ * It may return an empty string, if the comment was not stored.
+ * It is expected that the concrete Comment implementation gives an ID
+ * by itself (e.g. after saving).
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getId();
+
+ /**
+ * sets the ID of the comment and returns itself
+ *
+ * It is only allowed to set the ID only, if the current id is an empty
+ * string (which means it is not stored in a database, storage or whatever
+ * the concrete implementation does), or vice versa. Changing a given ID is
+ * not permitted and must result in an IllegalIDChangeException.
+ *
+ * @param string $id
+ * @return IComment
+ * @throws IllegalIDChangeException
+ * @since 9.0.0
+ */
+ public function setId($id);
+
+ /**
+ * returns the parent ID of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getParentId();
+
+ /**
+ * sets the parent ID and returns itself
+ * @param string $parentId
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setParentId($parentId);
+
+ /**
+ * returns the topmost parent ID of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getTopmostParentId();
+
+
+ /**
+ * sets the topmost parent ID and returns itself
+ *
+ * @param string $id
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setTopmostParentId($id);
+
+ /**
+ * returns the number of children
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getChildrenCount();
+
+ /**
+ * sets the number of children
+ *
+ * @param int $count
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setChildrenCount($count);
+
+ /**
+ * returns the message of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getMessage();
+
+ /**
+ * sets the message of the comment and returns itself
+ *
+ * @param string $message
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setMessage($message);
+
+ /**
+ * returns the verb of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getVerb();
+
+ /**
+ * sets the verb of the comment, e.g. 'comment' or 'like'
+ *
+ * @param string $verb
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setVerb($verb);
+
+ /**
+ * returns the actor type
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getActorType();
+
+ /**
+ * returns the actor ID
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getActorId();
+
+ /**
+ * sets (overwrites) the actor type and id
+ *
+ * @param string $actorType e.g. 'users'
+ * @param string $actorId e.g. 'zombie234'
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setActor($actorType, $actorId);
+
+ /**
+ * returns the creation date of the comment.
+ *
+ * If not explicitly set, it shall default to the time of initialization.
+ *
+ * @return \DateTime
+ * @since 9.0.0
+ */
+ public function getCreationDateTime();
+
+ /**
+ * sets the creation date of the comment and returns itself
+ *
+ * @param \DateTime $dateTime
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setCreationDateTime(\DateTime $dateTime);
+
+ /**
+ * returns the date of the most recent child
+ *
+ * @return \DateTime
+ * @since 9.0.0
+ */
+ public function getLatestChildDateTime();
+
+ /**
+ * sets the date of the most recent child
+ *
+ * @param \DateTime $dateTime
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setLatestChildDateTime(\DateTime $dateTime);
+
+ /**
+ * returns the object type the comment is attached to
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getObjectType();
+
+ /**
+ * returns the object id the comment is attached to
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getObjectId();
+
+ /**
+ * sets (overwrites) the object of the comment
+ *
+ * @param string $objectType e.g. 'files'
+ * @param string $objectId e.g. '16435'
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setObject($objectType, $objectId);
+
+}
+
diff --git a/lib/public/comments/icommentsmanager.php b/lib/public/comments/icommentsmanager.php
new file mode 100644
index 00000000000..46608ca8165
--- /dev/null
+++ b/lib/public/comments/icommentsmanager.php
@@ -0,0 +1,237 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Comments;
+
+/**
+ * Interface ICommentsManager
+ *
+ * This class manages the access to comments
+ *
+ * @package OCP\Comments
+ * @since 9.0.0
+ */
+interface ICommentsManager {
+
+ /**
+ * @const DELETED_USER type and id for a user that has been deleted
+ * @see deleteReferencesOfActor
+ * @since 9.0.0
+ *
+ * To be used as replacement for user type actors in deleteReferencesOfActor().
+ *
+ * User interfaces shall show "Deleted user" as display name, if needed.
+ */
+ const DELETED_USER = 'deleted_users';
+
+ /**
+ * returns a comment instance
+ *
+ * @param string $id the ID of the comment
+ * @return IComment
+ * @throws NotFoundException
+ * @since 9.0.0
+ */
+ public function get($id);
+
+ /**
+ * returns the comment specified by the id and all it's child comments
+ *
+ * @param string $id
+ * @param int $limit max number of entries to return, 0 returns all
+ * @param int $offset the start entry
+ * @return array
+ * @since 9.0.0
+ *
+ * The return array looks like this
+ * [
+ * 'comment' => IComment, // root comment
+ * 'replies' =>
+ * [
+ * 0 =>
+ * [
+ * 'comment' => IComment,
+ * 'replies' =>
+ * [
+ * 0 =>
+ * [
+ * 'comment' => IComment,
+ * 'replies' => [ … ]
+ * ],
+ * …
+ * ]
+ * ]
+ * 1 =>
+ * [
+ * 'comment' => IComment,
+ * 'replies'=> [ … ]
+ * ],
+ * …
+ * ]
+ * ]
+ */
+ public function getTree($id, $limit = 0, $offset = 0);
+
+ /**
+ * returns comments for a specific object (e.g. a file).
+ *
+ * The sort order is always newest to oldest.
+ *
+ * @param string $objectType the object type, e.g. 'files'
+ * @param string $objectId the id of the object
+ * @param int $limit optional, number of maximum comments to be returned. if
+ * not specified, all comments are returned.
+ * @param int $offset optional, starting point
+ * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
+ * that may be returned
+ * @return IComment[]
+ * @since 9.0.0
+ */
+ public function getForObject(
+ $objectType,
+ $objectId,
+ $limit = 0,
+ $offset = 0,
+ \DateTime $notOlderThan = null
+ );
+
+ /**
+ * @param $objectType string the object type, e.g. 'files'
+ * @param $objectId string the id of the object
+ * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
+ * that may be returned
+ * @return Int
+ * @since 9.0.0
+ */
+ public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null);
+
+ /**
+ * creates a new comment and returns it. At this point of time, it is not
+ * saved in the used data storage. Use save() after setting other fields
+ * of the comment (e.g. message or verb).
+ *
+ * @param string $actorType the actor type (e.g. 'users')
+ * @param string $actorId a user id
+ * @param string $objectType the object type the comment is attached to
+ * @param string $objectId the object id the comment is attached to
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function create($actorType, $actorId, $objectType, $objectId);
+
+ /**
+ * permanently deletes the comment specified by the ID
+ *
+ * When the comment has child comments, their parent ID will be changed to
+ * the parent ID of the item that is to be deleted.
+ *
+ * @param string $id
+ * @return bool
+ * @since 9.0.0
+ */
+ public function delete($id);
+
+ /**
+ * saves the comment permanently and returns it
+ *
+ * if the supplied comment has an empty ID, a new entry comment will be
+ * saved and the instance updated with the new ID.
+ *
+ * Otherwise, an existing comment will be updated.
+ *
+ * Throws NotFoundException when a comment that is to be updated does not
+ * exist anymore at this point of time.
+ *
+ * @param IComment $comment
+ * @return bool
+ * @throws NotFoundException
+ * @since 9.0.0
+ */
+ public function save(IComment $comment);
+
+ /**
+ * removes references to specific actor (e.g. on user delete) of a comment.
+ * The comment itself must not get lost/deleted.
+ *
+ * A 'users' type actor (type and id) should get replaced by the
+ * value of the DELETED_USER constant of this interface.
+ *
+ * @param string $actorType the actor type (e.g. 'users')
+ * @param string $actorId a user id
+ * @return boolean
+ * @since 9.0.0
+ */
+ public function deleteReferencesOfActor($actorType, $actorId);
+
+ /**
+ * deletes all comments made of a specific object (e.g. on file delete)
+ *
+ * @param string $objectType the object type (e.g. 'files')
+ * @param string $objectId e.g. the file id
+ * @return boolean
+ * @since 9.0.0
+ */
+ public function deleteCommentsAtObject($objectType, $objectId);
+
+ /**
+ * sets the read marker for a given file to the specified date for the
+ * provided user
+ *
+ * @param string $objectType
+ * @param string $objectId
+ * @param \DateTime $dateTime
+ * @param \OCP\IUser $user
+ * @since 9.0.0
+ */
+ public function setReadMark($objectType, $objectId, \DateTime $dateTime, \OCP\IUser $user);
+
+ /**
+ * returns the read marker for a given file to the specified date for the
+ * provided user. It returns null, when the marker is not present, i.e.
+ * no comments were marked as read.
+ *
+ * @param string $objectType
+ * @param string $objectId
+ * @param \OCP\IUser $user
+ * @return \DateTime|null
+ * @since 9.0.0
+ */
+ public function getReadMark($objectType, $objectId, \OCP\IUser $user);
+
+ /**
+ * deletes the read markers for the specified user
+ *
+ * @param \OCP\IUser $user
+ * @return bool
+ * @since 9.0.0
+ */
+ public function deleteReadMarksFromUser(\OCP\IUser $user);
+
+ /**
+ * deletes the read markers on the specified object
+ *
+ * @param string $objectType
+ * @param string $objectId
+ * @return bool
+ * @since 9.0.0
+ */
+ public function deleteReadMarksOnObject($objectType, $objectId);
+
+}
diff --git a/lib/public/comments/icommentsmanagerfactory.php b/lib/public/comments/icommentsmanagerfactory.php
new file mode 100644
index 00000000000..2e71719019c
--- /dev/null
+++ b/lib/public/comments/icommentsmanagerfactory.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Comments;
+
+use OCP\IServerContainer;
+
+/**
+ * Interface ICommentsManagerFactory
+ *
+ * This class is responsible for instantiating and returning an ICommentsManager
+ * instance.
+ *
+ * @package OCP\Comments
+ * @since 9.0.0
+ */
+interface ICommentsManagerFactory {
+
+ /**
+ * Constructor for the comments manager factory
+ *
+ * @param IServerContainer $serverContainer server container
+ * @since 9.0.0
+ */
+ public function __construct(IServerContainer $serverContainer);
+
+ /**
+ * creates and returns an instance of the ICommentsManager
+ *
+ * @return ICommentsManager
+ * @since 9.0.0
+ */
+ public function getManager();
+}
diff --git a/lib/public/comments/illegalidchangeexception.php b/lib/public/comments/illegalidchangeexception.php
new file mode 100644
index 00000000000..df7a8e41cd9
--- /dev/null
+++ b/lib/public/comments/illegalidchangeexception.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Comments;
+
+/**
+ * Exception for illegal attempts to modify a comment ID
+ * @since 9.0.0
+ */
+class IllegalIDChangeException extends \Exception {}
diff --git a/lib/public/comments/notfoundexception.php b/lib/public/comments/notfoundexception.php
new file mode 100644
index 00000000000..51f6927346c
--- /dev/null
+++ b/lib/public/comments/notfoundexception.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Comments;
+
+/**
+ * Exception for not found entity
+ * @since 9.0.0
+ */
+class NotFoundException extends \Exception {}
diff --git a/lib/public/config.php b/lib/public/config.php
index 86e18de78e1..5b5dcb0e78e 100644
--- a/lib/public/config.php
+++ b/lib/public/config.php
@@ -9,7 +9,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/constants.php b/lib/public/constants.php
index 4d44bf24928..518fbcf7ebe 100644
--- a/lib/public/constants.php
+++ b/lib/public/constants.php
@@ -5,7 +5,7 @@
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/contacts.php b/lib/public/contacts.php
index c66d1ba2ccf..590fd9af1bd 100644
--- a/lib/public/contacts.php
+++ b/lib/public/contacts.php
@@ -2,10 +2,10 @@
/**
* @author Bart Visscher <bartv@thisnet.nl>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/contacts/imanager.php b/lib/public/contacts/imanager.php
index 4b7d0f7d40a..c6d557eaba7 100644
--- a/lib/public/contacts/imanager.php
+++ b/lib/public/contacts/imanager.php
@@ -3,10 +3,10 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/db.php b/lib/public/db.php
index 9c5f9424dcb..4706c5e95ee 100644
--- a/lib/public/db.php
+++ b/lib/public/db.php
@@ -11,7 +11,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/db/querybuilder/icompositeexpression.php b/lib/public/db/querybuilder/icompositeexpression.php
index 439c0ab20a8..c47ba1deb1e 100644
--- a/lib/public/db/querybuilder/icompositeexpression.php
+++ b/lib/public/db/querybuilder/icompositeexpression.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/db/querybuilder/iexpressionbuilder.php b/lib/public/db/querybuilder/iexpressionbuilder.php
index d719f07ebd4..a53ae3846c2 100644
--- a/lib/public/db/querybuilder/iexpressionbuilder.php
+++ b/lib/public/db/querybuilder/iexpressionbuilder.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,12 +21,40 @@
namespace OCP\DB\QueryBuilder;
+
+use Doctrine\DBAL\Query\Expression\ExpressionBuilder;
+
/**
* This class provides a wrapper around Doctrine's ExpressionBuilder
* @since 8.2.0
*/
interface IExpressionBuilder {
/**
+ * @since 9.0.0
+ */
+ const EQ = ExpressionBuilder::EQ;
+ /**
+ * @since 9.0.0
+ */
+ const NEQ = ExpressionBuilder::NEQ;
+ /**
+ * @since 9.0.0
+ */
+ const LT = ExpressionBuilder::LT;
+ /**
+ * @since 9.0.0
+ */
+ const LTE = ExpressionBuilder::LTE;
+ /**
+ * @since 9.0.0
+ */
+ const GT = ExpressionBuilder::GT;
+ /**
+ * @since 9.0.0
+ */
+ const GTE = ExpressionBuilder::GTE;
+
+ /**
* Creates a conjunction of the given boolean expressions.
*
* Example:
@@ -64,13 +92,15 @@ interface IExpressionBuilder {
* Creates a comparison expression.
*
* @param mixed $x The left expression.
- * @param string $operator One of the ExpressionBuilder::* constants.
+ * @param string $operator One of the IExpressionBuilder::* constants.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function comparison($x, $operator, $y);
+ public function comparison($x, $operator, $y, $type = null);
/**
* Creates an equality comparison expression with the given arguments.
@@ -84,11 +114,13 @@ interface IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function eq($x, $y);
+ public function eq($x, $y, $type = null);
/**
* Creates a non equality comparison expression with the given arguments.
@@ -101,11 +133,13 @@ interface IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function neq($x, $y);
+ public function neq($x, $y, $type = null);
/**
* Creates a lower-than comparison expression with the given arguments.
@@ -118,11 +152,13 @@ interface IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function lt($x, $y);
+ public function lt($x, $y, $type = null);
/**
* Creates a lower-than-equal comparison expression with the given arguments.
@@ -135,11 +171,13 @@ interface IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function lte($x, $y);
+ public function lte($x, $y, $type = null);
/**
* Creates a greater-than comparison expression with the given arguments.
@@ -152,11 +190,13 @@ interface IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function gt($x, $y);
+ public function gt($x, $y, $type = null);
/**
* Creates a greater-than-equal comparison expression with the given arguments.
@@ -169,11 +209,13 @@ interface IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function gte($x, $y);
+ public function gte($x, $y, $type = null);
/**
* Creates an IS NULL expression with the given arguments.
@@ -200,50 +242,58 @@ interface IExpressionBuilder {
*
* @param string $x Field in string format to be inspected by LIKE() comparison.
* @param mixed $y Argument to be used in LIKE() comparison.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function like($x, $y);
+ public function like($x, $y, $type = null);
/**
* Creates a NOT LIKE() comparison expression with the given arguments.
*
* @param string $x Field in string format to be inspected by NOT LIKE() comparison.
* @param mixed $y Argument to be used in NOT LIKE() comparison.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function notLike($x, $y);
+ public function notLike($x, $y, $type = null);
/**
* Creates a IN () comparison expression with the given arguments.
*
* @param string $x The field in string format to be inspected by IN() comparison.
* @param string|array $y The placeholder or the array of values to be used by IN() comparison.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function in($x, $y);
+ public function in($x, $y, $type = null);
/**
* Creates a NOT IN () comparison expression with the given arguments.
*
* @param string $x The field in string format to be inspected by NOT IN() comparison.
* @param string|array $y The placeholder or the array of values to be used by NOT IN() comparison.
+ * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
- * @since 8.2.0
+ * @since 8.2.0 - Parameter $type was added in 9.0.0
*/
- public function notIn($x, $y);
+ public function notIn($x, $y, $type = null);
/**
* Quotes a given input parameter.
*
* @param mixed $input The parameter to be quoted.
- * @param string|null $type The type of the parameter.
+ * @param mixed|null $type One of the IQueryBuilder::PARAM_* constants
*
* @return string
* @since 8.2.0
diff --git a/lib/public/db/querybuilder/iliteral.php b/lib/public/db/querybuilder/iliteral.php
index a2665e47a7d..ab1cc59229a 100644
--- a/lib/public/db/querybuilder/iliteral.php
+++ b/lib/public/db/querybuilder/iliteral.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/db/querybuilder/iparameter.php b/lib/public/db/querybuilder/iparameter.php
index ef822a9c97f..be141cea9a7 100644
--- a/lib/public/db/querybuilder/iparameter.php
+++ b/lib/public/db/querybuilder/iparameter.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/db/querybuilder/iquerybuilder.php b/lib/public/db/querybuilder/iquerybuilder.php
index 3fc07af1a47..5a020f4f6a2 100644
--- a/lib/public/db/querybuilder/iquerybuilder.php
+++ b/lib/public/db/querybuilder/iquerybuilder.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -21,11 +21,50 @@
namespace OCP\DB\QueryBuilder;
+
+use Doctrine\DBAL\Connection;
+
/**
* This class provides a wrapper around Doctrine's QueryBuilder
* @since 8.2.0
*/
interface IQueryBuilder {
+
+ /**
+ * @since 9.0.0
+ */
+ const PARAM_NULL = \PDO::PARAM_NULL;
+ /**
+ * @since 9.0.0
+ */
+ const PARAM_BOOL = \PDO::PARAM_BOOL;
+ /**
+ * @since 9.0.0
+ */
+ const PARAM_INT = \PDO::PARAM_INT;
+ /**
+ * @since 9.0.0
+ */
+ const PARAM_STR = \PDO::PARAM_STR;
+ /**
+ * @since 9.0.0
+ */
+ const PARAM_LOB = \PDO::PARAM_LOB;
+ /**
+ * @since 9.0.0
+ */
+ const PARAM_DATE = 'datetime';
+
+ /**
+ * @since 9.0.0
+ */
+ const PARAM_INT_ARRAY = Connection::PARAM_INT_ARRAY;
+ /**
+ * @since 9.0.0
+ */
+ const PARAM_STR_ARRAY = Connection::PARAM_STR_ARRAY;
+
+
/**
* Enable/disable automatic prefixing of table names with the oc_ prefix
*
@@ -239,6 +278,40 @@ interface IQueryBuilder {
public function select($select = null);
/**
+ * Specifies an item that is to be returned with a different name in the query result.
+ *
+ * <code>
+ * $qb = $conn->getQueryBuilder()
+ * ->selectAlias('u.id', 'user_id')
+ * ->from('users', 'u')
+ * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
+ * </code>
+ *
+ * @param mixed $select The selection expressions.
+ * @param string $alias The column alias used in the constructed query.
+ *
+ * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance.
+ * @since 8.2.1
+ */
+ public function selectAlias($select, $alias);
+
+ /**
+ * Specifies an item that is to be returned uniquely in the query result.
+ *
+ * <code>
+ * $qb = $conn->getQueryBuilder()
+ * ->selectDistinct('type')
+ * ->from('users');
+ * </code>
+ *
+ * @param mixed $select The selection expressions.
+ *
+ * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance.
+ * @since 9.0.0
+ */
+ public function selectDistinct($select);
+
+ /**
* Adds an item that is to be returned in the query result.
*
* <code>
@@ -778,4 +851,31 @@ interface IQueryBuilder {
* @since 8.2.0
*/
public function createFunction($call);
+
+ /**
+ * Used to get the id of the last inserted element
+ * @return int
+ * @throws \BadMethodCallException When being called before an insert query has been run.
+ * @since 9.0.0
+ */
+ public function getLastInsertId();
+
+ /**
+ * Returns the table name quoted and with database prefix as needed by the implementation
+ *
+ * @param string $table
+ * @return string
+ * @since 9.0.0
+ */
+ public function getTableName($table);
+
+ /**
+ * Returns the column name quoted and with table alias prefix as needed by the implementation
+ *
+ * @param string $column
+ * @param string $tableAlias
+ * @return string
+ * @since 9.0.0
+ */
+ public function getColumnName($column, $tableAlias = '');
}
diff --git a/lib/public/db/querybuilder/iqueryfunction.php b/lib/public/db/querybuilder/iqueryfunction.php
index 7051f2f38a3..8050bd295e4 100644
--- a/lib/public/db/querybuilder/iqueryfunction.php
+++ b/lib/public/db/querybuilder/iqueryfunction.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/defaults.php b/lib/public/defaults.php
index 723c6ecbb78..58b25d5914a 100644
--- a/lib/public/defaults.php
+++ b/lib/public/defaults.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author scolebrook <scolebrook@mac.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/diagnostics/ievent.php b/lib/public/diagnostics/ievent.php
index 733d5e4832c..a3e42ee137f 100644
--- a/lib/public/diagnostics/ievent.php
+++ b/lib/public/diagnostics/ievent.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/diagnostics/ieventlogger.php b/lib/public/diagnostics/ieventlogger.php
index c9b4653393b..34e521db10c 100644
--- a/lib/public/diagnostics/ieventlogger.php
+++ b/lib/public/diagnostics/ieventlogger.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/diagnostics/iquery.php b/lib/public/diagnostics/iquery.php
index 54853f733c9..3b4d1b4c965 100644
--- a/lib/public/diagnostics/iquery.php
+++ b/lib/public/diagnostics/iquery.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/diagnostics/iquerylogger.php b/lib/public/diagnostics/iquerylogger.php
index 4a6a0d0704b..285a85efde1 100644
--- a/lib/public/diagnostics/iquerylogger.php
+++ b/lib/public/diagnostics/iquerylogger.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/encryption/exceptions/genericencryptionexception.php b/lib/public/encryption/exceptions/genericencryptionexception.php
index c1041e81642..c1331689c7f 100644
--- a/lib/public/encryption/exceptions/genericencryptionexception.php
+++ b/lib/public/encryption/exceptions/genericencryptionexception.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/encryption/iencryptionmodule.php b/lib/public/encryption/iencryptionmodule.php
index bb4dfdcdda8..426e4ddecce 100644
--- a/lib/public/encryption/iencryptionmodule.php
+++ b/lib/public/encryption/iencryptionmodule.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/encryption/ifile.php b/lib/public/encryption/ifile.php
index 0d1381238f0..9933cb0164e 100644
--- a/lib/public/encryption/ifile.php
+++ b/lib/public/encryption/ifile.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/encryption/imanager.php b/lib/public/encryption/imanager.php
index c963c19e660..b07de0cbb4f 100644
--- a/lib/public/encryption/imanager.php
+++ b/lib/public/encryption/imanager.php
@@ -4,7 +4,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/encryption/keys/istorage.php b/lib/public/encryption/keys/istorage.php
index e206373c46a..cfac4ba58f7 100644
--- a/lib/public/encryption/keys/istorage.php
+++ b/lib/public/encryption/keys/istorage.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files.php b/lib/public/files.php
index c1dcffcbefb..f1b8a855194 100644
--- a/lib/public/files.php
+++ b/lib/public/files.php
@@ -10,7 +10,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -60,7 +60,7 @@ class Files {
* @since 5.0.0
*/
static function getMimeType( $path ) {
- return(\OC_Helper::getMimeType( $path ));
+ return \OC::$server->getMimeTypeDetector()->detect($path);
}
/**
diff --git a/lib/public/files/alreadyexistsexception.php b/lib/public/files/alreadyexistsexception.php
index 2ff231c56f4..243129cb1db 100644
--- a/lib/public/files/alreadyexistsexception.php
+++ b/lib/public/files/alreadyexistsexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/cache/icache.php b/lib/public/files/cache/icache.php
new file mode 100644
index 00000000000..4ffb298a9e2
--- /dev/null
+++ b/lib/public/files/cache/icache.php
@@ -0,0 +1,249 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files\Cache;
+
+/**
+ * Metadata cache for a storage
+ *
+ * The cache stores the metadata for all files and folders in a storage and is kept up to date trough the following mechanisms:
+ *
+ * - Scanner: scans the storage and updates the cache where needed
+ * - Watcher: checks for changes made to the filesystem outside of the ownCloud instance and rescans files and folder when a change is detected
+ * - Updater: listens to changes made to the filesystem inside of the ownCloud instance and updates the cache where needed
+ * - ChangePropagator: updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater
+ *
+ * @since 9.0.0
+ */
+interface ICache {
+ const NOT_FOUND = 0;
+ const PARTIAL = 1; //only partial data available, file not cached in the database
+ const SHALLOW = 2; //folder in cache, but not all child files are completely scanned
+ const COMPLETE = 3;
+
+ /**
+ * Get the numeric storage id for this cache's storage
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getNumericStorageId();
+
+ /**
+ * get the stored metadata of a file or folder
+ *
+ * @param string | int $file either the path of a file or folder or the file id for a file or folder
+ * @return ICacheEntry|false the cache entry or false if the file is not found in the cache
+ * @since 9.0.0
+ */
+ public function get($file);
+
+ /**
+ * get the metadata of all files stored in $folder
+ *
+ * @param string $folder
+ * @return ICacheEntry[]
+ * @since 9.0.0
+ */
+ public function getFolderContents($folder);
+
+ /**
+ * get the metadata of all files stored in $folder
+ *
+ * @param int $fileId the file id of the folder
+ * @return ICacheEntry[]
+ * @since 9.0.0
+ */
+ public function getFolderContentsById($fileId);
+
+ /**
+ * store meta data for a file or folder
+ * This will automatically call either insert or update depending on if the file exists
+ *
+ * @param string $file
+ * @param array $data
+ *
+ * @return int file id
+ * @throws \RuntimeException
+ * @since 9.0.0
+ */
+ public function put($file, array $data);
+
+ /**
+ * insert meta data for a new file or folder
+ *
+ * @param string $file
+ * @param array $data
+ *
+ * @return int file id
+ * @throws \RuntimeException
+ * @since 9.0.0
+ */
+ public function insert($file, array $data);
+
+ /**
+ * update the metadata of an existing file or folder in the cache
+ *
+ * @param int $id the fileid of the existing file or folder
+ * @param array $data [$key => $value] the metadata to update, only the fields provided in the array will be updated, non-provided values will remain unchanged
+ * @since 9.0.0
+ */
+ public function update($id, array $data);
+
+ /**
+ * get the file id for a file
+ *
+ * A file id is a numeric id for a file or folder that's unique within an owncloud instance which stays the same for the lifetime of a file
+ *
+ * File ids are easiest way for apps to store references to a file since unlike paths they are not affected by renames or sharing
+ *
+ * @param string $file
+ * @return int
+ * @since 9.0.0
+ */
+ public function getId($file);
+
+ /**
+ * get the id of the parent folder of a file
+ *
+ * @param string $file
+ * @return int
+ * @since 9.0.0
+ */
+ public function getParentId($file);
+
+ /**
+ * check if a file is available in the cache
+ *
+ * @param string $file
+ * @return bool
+ * @since 9.0.0
+ */
+ public function inCache($file);
+
+ /**
+ * remove a file or folder from the cache
+ *
+ * when removing a folder from the cache all files and folders inside the folder will be removed as well
+ *
+ * @param string $file
+ * @since 9.0.0
+ */
+ public function remove($file);
+
+ /**
+ * Move a file or folder in the cache
+ *
+ * @param string $source
+ * @param string $target
+ * @since 9.0.0
+ */
+ public function move($source, $target);
+
+ /**
+ * Move a file or folder in the cache
+ *
+ * Note that this should make sure the entries are removed from the source cache
+ *
+ * @param \OCP\Files\Cache\ICache $sourceCache
+ * @param string $sourcePath
+ * @param string $targetPath
+ * @throws \OC\DatabaseException
+ * @since 9.0.0
+ */
+ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath);
+
+ /**
+ * Get the scan status of a file
+ *
+ * - ICache::NOT_FOUND: File is not in the cache
+ * - ICache::PARTIAL: File is not stored in the cache but some incomplete data is known
+ * - ICache::SHALLOW: The folder and it's direct children are in the cache but not all sub folders are fully scanned
+ * - ICache::COMPLETE: The file or folder, with all it's children) are fully scanned
+ *
+ * @param string $file
+ *
+ * @return int ICache::NOT_FOUND, ICache::PARTIAL, ICache::SHALLOW or ICache::COMPLETE
+ * @since 9.0.0
+ */
+ public function getStatus($file);
+
+ /**
+ * search for files matching $pattern
+ *
+ * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%')
+ * @return ICacheEntry[] an array of cache entries where the name matches the search pattern
+ * @since 9.0.0
+ */
+ public function search($pattern);
+
+ /**
+ * search for files by mimetype
+ *
+ * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image')
+ * where it will search for all mimetypes in the group ('image/*')
+ * @return ICacheEntry[] an array of cache entries where the mimetype matches the search
+ * @since 9.0.0
+ */
+ public function searchByMime($mimetype);
+
+ /**
+ * Search for files by tag of a given users.
+ *
+ * Note that every user can tag files differently.
+ *
+ * @param string|int $tag name or tag id
+ * @param string $userId owner of the tags
+ * @return ICacheEntry[] file data
+ * @since 9.0.0
+ */
+ public function searchByTag($tag, $userId);
+
+ /**
+ * find a folder in the cache which has not been fully scanned
+ *
+ * If multiple incomplete folders are in the cache, the one with the highest id will be returned,
+ * use the one with the highest id gives the best result with the background scanner, since that is most
+ * likely the folder where we stopped scanning previously
+ *
+ * @return string|bool the path of the folder or false when no folder matched
+ * @since 9.0.0
+ */
+ public function getIncomplete();
+
+ /**
+ * get the path of a file on this storage by it's file id
+ *
+ * @param int $id the file id of the file or folder to search
+ * @return string|null the path of the file (relative to the storage) or null if a file with the given id does not exists within this cache
+ * @since 9.0.0
+ */
+ public function getPathById($id);
+
+ /**
+ * normalize the given path for usage in the cache
+ *
+ * @param string $path
+ * @return string
+ * @since 9.0.0
+ */
+ public function normalize($path);
+}
diff --git a/lib/public/files/cache/icacheentry.php b/lib/public/files/cache/icacheentry.php
new file mode 100644
index 00000000000..63a232c9618
--- /dev/null
+++ b/lib/public/files/cache/icacheentry.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files\Cache;
+
+/**
+ * meta data for a file or folder
+ *
+ * @since 9.0.0
+ */
+interface ICacheEntry {
+ const DIRECTORY_MIMETYPE = 'httpd/unix-directory';
+
+ /**
+ * Get the numeric id of a file
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getId();
+
+ /**
+ * Get the numeric id for the storage
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getStorageId();
+
+ /**
+ * Get the path of the file relative to the storage root
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getPath();
+
+ /**
+ * Get the file name
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getName();
+
+ /**
+ * Get the full mimetype
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getMimeType();
+
+ /**
+ * Get the first part of the mimetype
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getMimePart();
+
+ /**
+ * Get the file size in bytes
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getSize();
+
+ /**
+ * Get the last modified date as unix timestamp
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getMTime();
+
+ /**
+ * Get the last modified date on the storage as unix timestamp
+ *
+ * Note that when a file is updated we also update the mtime of all parent folders to make it visible to the user which folder has had updates most recently
+ * This can differ from the mtime on the underlying storage which usually only changes when a direct child is added, removed or renamed
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getStorageMTime();
+
+ /**
+ * Get the etag for the file
+ *
+ * An etag is used for change detection of files and folders, an etag of a file changes whenever the content of the file changes
+ * Etag for folders change whenever a file in the folder has changed
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getEtag();
+
+ /**
+ * Get the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE
+ * \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getPermissions();
+
+ /**
+ * Check if the file is encrypted
+ *
+ * @return bool
+ * @since 9.0.0
+ */
+ public function isEncrypted();
+}
diff --git a/lib/public/files/cache/ipropagator.php b/lib/public/files/cache/ipropagator.php
new file mode 100644
index 00000000000..7f7dbada532
--- /dev/null
+++ b/lib/public/files/cache/ipropagator.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files\Cache;
+
+/**
+ * Propagate etags and mtimes within the storage
+ *
+ * @since 9.0.0
+ */
+interface IPropagator {
+ /**
+ * @param string $internalPath
+ * @param int $time
+ * @return array[] all propagated cache entries
+ * @since 9.0.0
+ */
+ public function propagateChange($internalPath, $time);
+}
diff --git a/lib/public/files/cache/iscanner.php b/lib/public/files/cache/iscanner.php
new file mode 100644
index 00000000000..47e33a98bae
--- /dev/null
+++ b/lib/public/files/cache/iscanner.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files\Cache;
+
+/**
+ * Scan files from the storage and save to the cache
+ *
+ * @since 9.0.0
+ */
+interface IScanner {
+ const SCAN_RECURSIVE = true;
+ const SCAN_SHALLOW = false;
+
+ const REUSE_ETAG = 1;
+ const REUSE_SIZE = 2;
+
+ /**
+ * scan a single file and store it in the cache
+ *
+ * @param string $file
+ * @param int $reuseExisting
+ * @param int $parentId
+ * @param array | null $cacheData existing data in the cache for the file to be scanned
+ * @param bool $lock set to false to disable getting an additional read lock during scanning
+ * @return array an array of metadata of the scanned file
+ * @throws \OC\ServerNotAvailableException
+ * @throws \OCP\Lock\LockedException
+ * @since 9.0.0
+ */
+ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true);
+
+ /**
+ * scan a folder and all its children
+ *
+ * @param string $path
+ * @param bool $recursive
+ * @param int $reuse
+ * @param bool $lock set to false to disable getting an additional read lock during scanning
+ * @return array an array of the meta data of the scanned file or folder
+ * @since 9.0.0
+ */
+ public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true);
+
+ /**
+ * check if the file should be ignored when scanning
+ * NOTE: files with a '.part' extension are ignored as well!
+ * prevents unfinished put requests to be scanned
+ *
+ * @param string $file
+ * @return boolean
+ * @since 9.0.0
+ */
+ public static function isPartialFile($file);
+
+ /**
+ * walk over any folders that are not fully scanned yet and scan them
+ *
+ * @since 9.0.0
+ */
+ public function backgroundScan();
+}
+
diff --git a/lib/public/files/cache/iupdater.php b/lib/public/files/cache/iupdater.php
new file mode 100644
index 00000000000..241cd8636a1
--- /dev/null
+++ b/lib/public/files/cache/iupdater.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files\Cache;
+
+use OCP\Files\Storage\IStorage;
+
+/**
+ * Update the cache and propagate changes
+ *
+ * @since 9.0.0
+ */
+interface IUpdater {
+ /**
+ * Get the propagator for etags and mtime for the view the updater works on
+ *
+ * @return IPropagator
+ * @since 9.0.0
+ */
+ public function getPropagator();
+
+ /**
+ * Propagate etag and mtime changes for the parent folders of $path up to the root of the filesystem
+ *
+ * @param string $path the path of the file to propagate the changes for
+ * @param int|null $time the timestamp to set as mtime for the parent folders, if left out the current time is used
+ * @since 9.0.0
+ */
+ public function propagate($path, $time = null);
+
+ /**
+ * Update the cache for $path and update the size, etag and mtime of the parent folders
+ *
+ * @param string $path
+ * @param int $time
+ * @since 9.0.0
+ */
+ public function update($path, $time = null);
+
+ /**
+ * Remove $path from the cache and update the size, etag and mtime of the parent folders
+ *
+ * @param string $path
+ * @since 9.0.0
+ */
+ public function remove($path);
+
+ /**
+ * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders
+ *
+ * @param IStorage $sourceStorage
+ * @param string $source
+ * @param string $target
+ * @since 9.0.0
+ */
+ public function renameFromStorage(IStorage $sourceStorage, $source, $target);
+}
diff --git a/lib/public/files/cache/iwatcher.php b/lib/public/files/cache/iwatcher.php
new file mode 100644
index 00000000000..a61975036f8
--- /dev/null
+++ b/lib/public/files/cache/iwatcher.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files\Cache;
+
+/**
+ * check the storage backends for updates and change the cache accordingly
+ *
+ * @since 9.0.0
+ */
+interface IWatcher {
+ const CHECK_NEVER = 0; // never check the underlying filesystem for updates
+ const CHECK_ONCE = 1; // check the underlying filesystem for updates once every request for each file
+ const CHECK_ALWAYS = 2; // always check the underlying filesystem for updates
+
+ /**
+ * @param int $policy either IWatcher::CHECK_NEVER, IWatcher::CHECK_ONCE, IWatcher::CHECK_ALWAYS
+ * @since 9.0.0
+ */
+ public function setPolicy($policy);
+
+ /**
+ * @return int either IWatcher::CHECK_NEVER, IWatcher::CHECK_ONCE, IWatcher::CHECK_ALWAYS
+ * @since 9.0.0
+ */
+ public function getPolicy();
+
+ /**
+ * check $path for updates and update if needed
+ *
+ * @param string $path
+ * @param ICacheEntry|null $cachedEntry
+ * @return boolean true if path was updated
+ * @since 9.0.0
+ */
+ public function checkUpdate($path, $cachedEntry = null);
+
+ /**
+ * Update the cache for changes to $path
+ *
+ * @param string $path
+ * @param ICacheEntry $cachedData
+ * @since 9.0.0
+ */
+ public function update($path, $cachedData);
+
+ /**
+ * Check if the cache for $path needs to be updated
+ *
+ * @param string $path
+ * @param ICacheEntry $cachedData
+ * @return bool
+ * @since 9.0.0
+ */
+ public function needsUpdate($path, $cachedData);
+
+ /**
+ * remove deleted files in $path from the cache
+ *
+ * @param string $path
+ * @since 9.0.0
+ */
+ public function cleanFolder($path);
+}
diff --git a/lib/public/files/config/icachedmountinfo.php b/lib/public/files/config/icachedmountinfo.php
new file mode 100644
index 00000000000..a587427f1f2
--- /dev/null
+++ b/lib/public/files/config/icachedmountinfo.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files\Config;
+
+use OCP\Files\Node;
+use OCP\IUser;
+
+/**
+ * Holds information about a mount for a user
+ *
+ * @since 9.0.0
+ */
+interface ICachedMountInfo {
+ /**
+ * @return IUser
+ * @since 9.0.0
+ */
+ public function getUser();
+
+ /**
+ * @return int the numeric storage id of the mount
+ * @since 9.0.0
+ */
+ public function getStorageId();
+
+ /**
+ * @return int the fileid of the root of the mount
+ * @since 9.0.0
+ */
+ public function getRootId();
+
+ /**
+ * @return Node the root node of the mount
+ * @since 9.0.0
+ */
+ public function getMountPointNode();
+
+ /**
+ * @return string the mount point of the mount for the user
+ * @since 9.0.0
+ */
+ public function getMountPoint();
+}
diff --git a/lib/public/files/config/imountprovider.php b/lib/public/files/config/imountprovider.php
index 8e21e4c8650..d1498fd5f61 100644
--- a/lib/public/files/config/imountprovider.php
+++ b/lib/public/files/config/imountprovider.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/config/imountprovidercollection.php b/lib/public/files/config/imountprovidercollection.php
index a458cbf3ce7..39da61812a9 100644
--- a/lib/public/files/config/imountprovidercollection.php
+++ b/lib/public/files/config/imountprovidercollection.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -22,6 +22,7 @@
namespace OCP\Files\Config;
+use OCP\Files\Mount\IMountPoint;
use OCP\IUser;
/**
@@ -45,4 +46,12 @@ interface IMountProviderCollection {
* @since 8.0.0
*/
public function registerProvider(IMountProvider $provider);
+
+ /**
+ * Get the mount cache which can be used to search for mounts without setting up the filesystem
+ *
+ * @return IUserMountCache
+ * @since 9.0.0
+ */
+ public function getMountCache();
}
diff --git a/lib/public/files/config/iusermountcache.php b/lib/public/files/config/iusermountcache.php
new file mode 100644
index 00000000000..77f58cd8670
--- /dev/null
+++ b/lib/public/files/config/iusermountcache.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files\Config;
+
+use OCP\Files\Mount\IMountPoint;
+use OCP\IUser;
+
+/**
+ * Cache mounts points per user in the cache so we can easily look them up
+ *
+ * @since 9.0.0
+ */
+interface IUserMountCache {
+ /**
+ * Register mounts for a user to the cache
+ *
+ * @param IUser $user
+ * @param IMountPoint[] $mounts
+ * @since 9.0.0
+ */
+ public function registerMounts(IUser $user, array $mounts);
+
+ /**
+ * Get all cached mounts for a user
+ *
+ * @param IUser $user
+ * @return ICachedMountInfo[]
+ * @since 9.0.0
+ */
+ public function getMountsForUser(IUser $user);
+
+ /**
+ * Get all cached mounts by storage
+ *
+ * @param int $numericStorageId
+ * @return ICachedMountInfo[]
+ * @since 9.0.0
+ */
+ public function getMountsForStorageId($numericStorageId);
+
+ /**
+ * Get all cached mounts by root
+ *
+ * @param int $rootFileId
+ * @return ICachedMountInfo[]
+ * @since 9.0.0
+ */
+ public function getMountsForRootId($rootFileId);
+
+ /**
+ * Get all cached mounts that contain a file
+ *
+ * @param int $fileId
+ * @return ICachedMountInfo[]
+ * @since 9.0.0
+ */
+ public function getMountsForFileId($fileId);
+
+ /**
+ * Remove all cached mounts for a user
+ *
+ * @param IUser $user
+ * @since 9.0.0
+ */
+ public function removeUserMounts(IUser $user);
+
+ /**
+ * Remove all mounts for a user and storage
+ *
+ * @param $storageId
+ * @param string $userId
+ * @return mixed
+ * @since 9.0.0
+ */
+ public function removeUserStorageMount($storageId, $userId);
+
+ /**
+ * Remove all cached mounts for a storage
+ *
+ * @param $storageId
+ * @return mixed
+ * @since 9.0.0
+ */
+ public function remoteStorageMounts($storageId);
+}
diff --git a/lib/public/files/entitytoolargeexception.php b/lib/public/files/entitytoolargeexception.php
index 4dcfa77728b..8dabc08f8bb 100644
--- a/lib/public/files/entitytoolargeexception.php
+++ b/lib/public/files/entitytoolargeexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/file.php b/lib/public/files/file.php
index 839d646edb1..3acf24b9277 100644
--- a/lib/public/files/file.php
+++ b/lib/public/files/file.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/fileinfo.php b/lib/public/files/fileinfo.php
index 1af13302af0..aa4aa605d32 100644
--- a/lib/public/files/fileinfo.php
+++ b/lib/public/files/fileinfo.php
@@ -3,10 +3,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -237,4 +237,12 @@ interface FileInfo {
* @since 9.0.0
*/
public function getOwner();
+
+ /**
+ * Get the stored checksum for this file
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getChecksum();
}
diff --git a/lib/public/files/filenametoolongexception.php b/lib/public/files/filenametoolongexception.php
index 61cb8a21fb6..68fba4ad516 100644
--- a/lib/public/files/filenametoolongexception.php
+++ b/lib/public/files/filenametoolongexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/folder.php b/lib/public/files/folder.php
index 533e490634f..0644ab62034 100644
--- a/lib/public/files/folder.php
+++ b/lib/public/files/folder.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/forbiddenexception.php b/lib/public/files/forbiddenexception.php
new file mode 100644
index 00000000000..5a4f03d176d
--- /dev/null
+++ b/lib/public/files/forbiddenexception.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+// use OCP namespace for all classes that are considered public.
+// This means that they should be used by apps instead of the internal ownCloud classes
+namespace OCP\Files;
+
+/**
+ * Class ForbiddenException
+ *
+ * @package OCP\Files
+ * @since 9.0.0
+ */
+class ForbiddenException extends \Exception {
+
+ /** @var bool */
+ private $retry;
+
+ /**
+ * @param string $message
+ * @param bool $retry
+ * @param \Exception $previous previous exception for cascading
+ * @since 9.0.0
+ */
+ public function __construct($message, $retry, \Exception $previous = null) {
+ parent::__construct($message, 0, $previous);
+ $this->retry = $retry;
+ }
+
+ /**
+ * @return bool
+ * @since 9.0.0
+ */
+ public function getRetry() {
+ return (bool) $this->retry;
+ }
+}
diff --git a/lib/public/files/ihomestorage.php b/lib/public/files/ihomestorage.php
index fc9b0357578..4101545aafe 100644
--- a/lib/public/files/ihomestorage.php
+++ b/lib/public/files/ihomestorage.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/imimetypedetector.php b/lib/public/files/imimetypedetector.php
index b2b80d4570c..7d9cd606e69 100644
--- a/lib/public/files/imimetypedetector.php
+++ b/lib/public/files/imimetypedetector.php
@@ -2,7 +2,7 @@
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/imimetypeloader.php b/lib/public/files/imimetypeloader.php
index 1ff8bc1b6c1..57a6d7ba309 100644
--- a/lib/public/files/imimetypeloader.php
+++ b/lib/public/files/imimetypeloader.php
@@ -1,8 +1,8 @@
<?php
/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/invalidcharacterinpathexception.php b/lib/public/files/invalidcharacterinpathexception.php
index 52e20dfcb46..8e649b5bb62 100644
--- a/lib/public/files/invalidcharacterinpathexception.php
+++ b/lib/public/files/invalidcharacterinpathexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/invalidcontentexception.php b/lib/public/files/invalidcontentexception.php
index 6aebf367241..f25b7fef87f 100644
--- a/lib/public/files/invalidcontentexception.php
+++ b/lib/public/files/invalidcontentexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/invalidpathexception.php b/lib/public/files/invalidpathexception.php
index e86d58bde7a..ee21d7432be 100644
--- a/lib/public/files/invalidpathexception.php
+++ b/lib/public/files/invalidpathexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/irootfolder.php b/lib/public/files/irootfolder.php
index 97dc5a31e74..3b6243f7638 100644
--- a/lib/public/files/irootfolder.php
+++ b/lib/public/files/irootfolder.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/locknotacquiredexception.php b/lib/public/files/locknotacquiredexception.php
index d078ff34818..247c9f5f5cb 100644
--- a/lib/public/files/locknotacquiredexception.php
+++ b/lib/public/files/locknotacquiredexception.php
@@ -4,7 +4,7 @@
* @author Owen Winkler <a_github@midnightcircus.com>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/mount/imountmanager.php b/lib/public/files/mount/imountmanager.php
index 9a0362b12fb..9e3002a26d1 100644
--- a/lib/public/files/mount/imountmanager.php
+++ b/lib/public/files/mount/imountmanager.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/mount/imountpoint.php b/lib/public/files/mount/imountpoint.php
index 5452bcdb03a..9ce1396c1d1 100644
--- a/lib/public/files/mount/imountpoint.php
+++ b/lib/public/files/mount/imountpoint.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/node.php b/lib/public/files/node.php
index 866b9b6f61f..ee3f0cb0413 100644
--- a/lib/public/files/node.php
+++ b/lib/public/files/node.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -225,12 +225,4 @@ interface Node extends FileInfo {
* @since 6.0.0
*/
public function getName();
-
- /**
- * Get the file owner
- *
- * @since 9.0.0
- * @return string
- */
- public function getOwner();
}
diff --git a/lib/public/files/notenoughspaceexception.php b/lib/public/files/notenoughspaceexception.php
index a2cc0d6956b..4e67ac26700 100644
--- a/lib/public/files/notenoughspaceexception.php
+++ b/lib/public/files/notenoughspaceexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/notfoundexception.php b/lib/public/files/notfoundexception.php
index ae93e8d1e6d..10a3dacda44 100644
--- a/lib/public/files/notfoundexception.php
+++ b/lib/public/files/notfoundexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/notpermittedexception.php b/lib/public/files/notpermittedexception.php
index ee82ae56e51..3dcbd9e499b 100644
--- a/lib/public/files/notpermittedexception.php
+++ b/lib/public/files/notpermittedexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/objectstore/iobjectstore.php b/lib/public/files/objectstore/iobjectstore.php
index 5943731849e..78be18fb2e9 100644
--- a/lib/public/files/objectstore/iobjectstore.php
+++ b/lib/public/files/objectstore/iobjectstore.php
@@ -3,7 +3,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/reservedwordexception.php b/lib/public/files/reservedwordexception.php
index fc70c607185..6a560a563fe 100644
--- a/lib/public/files/reservedwordexception.php
+++ b/lib/public/files/reservedwordexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php
index c42a2d05bc3..1c125221449 100644
--- a/lib/public/files/storage.php
+++ b/lib/public/files/storage.php
@@ -4,11 +4,11 @@
* @author Michael Roth <michael.roth@rz.uni-augsburg.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -33,16 +33,19 @@
// use OCP namespace for all classes that are considered public.
// This means that they should be used by apps instead of the internal ownCloud classes
namespace OCP\Files;
-use OCP\Files\InvalidPathException;
+
+use OCP\Files\Storage\IStorage;
use OCP\Lock\ILockingProvider;
/**
* Provide a common interface to all different storage options
*
* All paths passed to the storage are relative to the storage and should NOT have a leading slash.
+ *
* @since 6.0.0
+ * @deprecated 9.0.0 use \OCP\Files\Storage\IStorage instead
*/
-interface Storage {
+interface Storage extends IStorage {
/**
* $parameters is a free form array with the configuration options needed to construct the storage
*
@@ -462,10 +465,4 @@ interface Storage {
* @param bool $isAvailable
*/
public function setAvailability($isAvailable);
-
- /**
- * @param $path path for which to retrieve the owner
- * @since 9.0.0
- */
- public function getOwner($path);
}
diff --git a/lib/public/files/storage/ilockingstorage.php b/lib/public/files/storage/ilockingstorage.php
new file mode 100644
index 00000000000..32cc32ffb05
--- /dev/null
+++ b/lib/public/files/storage/ilockingstorage.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files\Storage;
+
+use OCP\Lock\ILockingProvider;
+
+/**
+ * Storage backends that require explicit locking
+ *
+ * Storage backends implementing this interface do not need to implement their own locking implementation but should use the provided lockingprovider instead
+ * The implementation of the locking methods only need to map internal storage paths to "lock keys"
+ *
+ * @since 9.0.0
+ */
+interface ILockingStorage {
+ /**
+ * @param string $path The path of the file to acquire the lock for
+ * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
+ * @param \OCP\Lock\ILockingProvider $provider
+ * @throws \OCP\Lock\LockedException
+ * @since 9.0.0
+ */
+ public function acquireLock($path, $type, ILockingProvider $provider);
+
+ /**
+ * @param string $path The path of the file to acquire the lock for
+ * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
+ * @param \OCP\Lock\ILockingProvider $provider
+ * @since 9.0.0
+ */
+ public function releaseLock($path, $type, ILockingProvider $provider);
+
+ /**
+ * @param string $path The path of the file to change the lock for
+ * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
+ * @param \OCP\Lock\ILockingProvider $provider
+ * @throws \OCP\Lock\LockedException
+ * @since 9.0.0
+ */
+ public function changeLock($path, $type, ILockingProvider $provider);
+}
diff --git a/lib/public/files/storage/istorage.php b/lib/public/files/storage/istorage.php
new file mode 100644
index 00000000000..4bc5e3536dc
--- /dev/null
+++ b/lib/public/files/storage/istorage.php
@@ -0,0 +1,482 @@
+<?php
+/**
+ * @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Michael Roth <michael.roth@rz.uni-augsburg.de>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/**
+ * Public interface of ownCloud for apps to use.
+ * Files/Storage interface
+ */
+
+// use OCP namespace for all classes that are considered public.
+// This means that they should be used by apps instead of the internal ownCloud classes
+namespace OCP\Files\Storage;
+
+use OCP\Files\Cache\ICache;
+use OCP\Files\Cache\IPropagator;
+use OCP\Files\Cache\IScanner;
+use OCP\Files\Cache\IUpdater;
+use OCP\Files\Cache\IWatcher;
+use OCP\Files\InvalidPathException;
+
+/**
+ * Provide a common interface to all different storage options
+ *
+ * All paths passed to the storage are relative to the storage and should NOT have a leading slash.
+ *
+ * @since 9.0.0
+ */
+interface IStorage {
+ /**
+ * $parameters is a free form array with the configuration options needed to construct the storage
+ *
+ * @param array $parameters
+ * @since 9.0.0
+ */
+ public function __construct($parameters);
+
+ /**
+ * Get the identifier for the storage,
+ * the returned id should be the same for every storage object that is created with the same parameters
+ * and two storage objects with the same id should refer to two storages that display the same files.
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getId();
+
+ /**
+ * see http://php.net/manual/en/function.mkdir.php
+ * implementations need to implement a recursive mkdir
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function mkdir($path);
+
+ /**
+ * see http://php.net/manual/en/function.rmdir.php
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function rmdir($path);
+
+ /**
+ * see http://php.net/manual/en/function.opendir.php
+ *
+ * @param string $path
+ * @return resource|false
+ * @since 9.0.0
+ */
+ public function opendir($path);
+
+ /**
+ * see http://php.net/manual/en/function.is-dir.php
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function is_dir($path);
+
+ /**
+ * see http://php.net/manual/en/function.is-file.php
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function is_file($path);
+
+ /**
+ * see http://php.net/manual/en/function.stat.php
+ * only the following keys are required in the result: size and mtime
+ *
+ * @param string $path
+ * @return array|false
+ * @since 9.0.0
+ */
+ public function stat($path);
+
+ /**
+ * see http://php.net/manual/en/function.filetype.php
+ *
+ * @param string $path
+ * @return string|false
+ * @since 9.0.0
+ */
+ public function filetype($path);
+
+ /**
+ * see http://php.net/manual/en/function.filesize.php
+ * The result for filesize when called on a folder is required to be 0
+ *
+ * @param string $path
+ * @return int|false
+ * @since 9.0.0
+ */
+ public function filesize($path);
+
+ /**
+ * check if a file can be created in $path
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function isCreatable($path);
+
+ /**
+ * check if a file can be read
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function isReadable($path);
+
+ /**
+ * check if a file can be written to
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function isUpdatable($path);
+
+ /**
+ * check if a file can be deleted
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function isDeletable($path);
+
+ /**
+ * check if a file can be shared
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function isSharable($path);
+
+ /**
+ * get the full permissions of a path.
+ * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
+ *
+ * @param string $path
+ * @return int
+ * @since 9.0.0
+ */
+ public function getPermissions($path);
+
+ /**
+ * see http://php.net/manual/en/function.file_exists.php
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function file_exists($path);
+
+ /**
+ * see http://php.net/manual/en/function.filemtime.php
+ *
+ * @param string $path
+ * @return int|false
+ * @since 9.0.0
+ */
+ public function filemtime($path);
+
+ /**
+ * see http://php.net/manual/en/function.file_get_contents.php
+ *
+ * @param string $path
+ * @return string|false
+ * @since 9.0.0
+ */
+ public function file_get_contents($path);
+
+ /**
+ * see http://php.net/manual/en/function.file_put_contents.php
+ *
+ * @param string $path
+ * @param string $data
+ * @return bool
+ * @since 9.0.0
+ */
+ public function file_put_contents($path, $data);
+
+ /**
+ * see http://php.net/manual/en/function.unlink.php
+ *
+ * @param string $path
+ * @return bool
+ * @since 9.0.0
+ */
+ public function unlink($path);
+
+ /**
+ * see http://php.net/manual/en/function.rename.php
+ *
+ * @param string $path1
+ * @param string $path2
+ * @return bool
+ * @since 9.0.0
+ */
+ public function rename($path1, $path2);
+
+ /**
+ * see http://php.net/manual/en/function.copy.php
+ *
+ * @param string $path1
+ * @param string $path2
+ * @return bool
+ * @since 9.0.0
+ */
+ public function copy($path1, $path2);
+
+ /**
+ * see http://php.net/manual/en/function.fopen.php
+ *
+ * @param string $path
+ * @param string $mode
+ * @return resource|false
+ * @since 9.0.0
+ */
+ public function fopen($path, $mode);
+
+ /**
+ * get the mimetype for a file or folder
+ * The mimetype for a folder is required to be "httpd/unix-directory"
+ *
+ * @param string $path
+ * @return string|false
+ * @since 9.0.0
+ */
+ public function getMimeType($path);
+
+ /**
+ * see http://php.net/manual/en/function.hash-file.php
+ *
+ * @param string $type
+ * @param string $path
+ * @param bool $raw
+ * @return string|false
+ * @since 9.0.0
+ */
+ public function hash($type, $path, $raw = false);
+
+ /**
+ * see http://php.net/manual/en/function.free_space.php
+ *
+ * @param string $path
+ * @return int|false
+ * @since 9.0.0
+ */
+ public function free_space($path);
+
+ /**
+ * search for occurrences of $query in file names
+ *
+ * @param string $query
+ * @return array|false
+ * @since 9.0.0
+ */
+ public function search($query);
+
+ /**
+ * see http://php.net/manual/en/function.touch.php
+ * If the backend does not support the operation, false should be returned
+ *
+ * @param string $path
+ * @param int $mtime
+ * @return bool
+ * @since 9.0.0
+ */
+ public function touch($path, $mtime = null);
+
+ /**
+ * get the path to a local version of the file.
+ * The local version of the file can be temporary and doesn't have to be persistent across requests
+ *
+ * @param string $path
+ * @return string|false
+ * @since 9.0.0
+ */
+ public function getLocalFile($path);
+
+ /**
+ * get the path to a local version of the folder.
+ * The local version of the folder can be temporary and doesn't have to be persistent across requests
+ *
+ * @param string $path
+ * @return string|false
+ * @since 9.0.0
+ */
+ public function getLocalFolder($path);
+
+ /**
+ * check if a file or folder has been updated since $time
+ *
+ * @param string $path
+ * @param int $time
+ * @return bool
+ * @since 9.0.0
+ *
+ * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
+ * returning true for other changes in the folder is optional
+ */
+ public function hasUpdated($path, $time);
+
+ /**
+ * get the ETag for a file or folder
+ *
+ * @param string $path
+ * @return string|false
+ * @since 9.0.0
+ */
+ public function getETag($path);
+
+ /**
+ * Returns whether the storage is local, which means that files
+ * are stored on the local filesystem instead of remotely.
+ * Calling getLocalFile() for local storages should always
+ * return the local files, whereas for non-local storages
+ * it might return a temporary file.
+ *
+ * @return bool true if the files are stored locally, false otherwise
+ * @since 9.0.0
+ */
+ public function isLocal();
+
+ /**
+ * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
+ *
+ * @param string $class
+ * @return bool
+ * @since 9.0.0
+ */
+ public function instanceOfStorage($class);
+
+ /**
+ * A custom storage implementation can return an url for direct download of a give file.
+ *
+ * For now the returned array can hold the parameter url - in future more attributes might follow.
+ *
+ * @param string $path
+ * @return array|false
+ * @since 9.0.0
+ */
+ public function getDirectDownload($path);
+
+ /**
+ * @param string $path the path of the target folder
+ * @param string $fileName the name of the file itself
+ * @return void
+ * @throws InvalidPathException
+ * @since 9.0.0
+ */
+ public function verifyPath($path, $fileName);
+
+ /**
+ * @param \OCP\Files\Storage $sourceStorage
+ * @param string $sourceInternalPath
+ * @param string $targetInternalPath
+ * @return bool
+ * @since 9.0.0
+ */
+ public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath);
+
+ /**
+ * @param \OCP\Files\Storage $sourceStorage
+ * @param string $sourceInternalPath
+ * @param string $targetInternalPath
+ * @return bool
+ * @since 9.0.0
+ */
+ public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath);
+
+ /**
+ * Test a storage for availability
+ *
+ * @since 9.0.0
+ * @return bool
+ */
+ public function test();
+
+ /**
+ * @since 9.0.0
+ * @return array [ available, last_checked ]
+ */
+ public function getAvailability();
+
+ /**
+ * @since 9.0.0
+ * @param bool $isAvailable
+ */
+ public function setAvailability($isAvailable);
+
+ /**
+ * @param string $path path for which to retrieve the owner
+ * @since 9.0.0
+ */
+ public function getOwner($path);
+
+ /**
+ * @return ICache
+ * @since 9.0.0
+ */
+ public function getCache();
+
+ /**
+ * @return IPropagator
+ * @since 9.0.0
+ */
+ public function getPropagator();
+
+ /**
+ * @return IScanner
+ * @since 9.0.0
+ */
+ public function getScanner();
+
+ /**
+ * @return IUpdater
+ * @since 9.0.0
+ */
+ public function getUpdater();
+
+ /**
+ * @return IWatcher
+ * @since 9.0.0
+ */
+ public function getWatcher();
+}
diff --git a/lib/public/files/storage/istoragefactory.php b/lib/public/files/storage/istoragefactory.php
index bd9651299cf..01a05eeff12 100644
--- a/lib/public/files/storage/istoragefactory.php
+++ b/lib/public/files/storage/istoragefactory.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/storageauthexception.php b/lib/public/files/storageauthexception.php
new file mode 100644
index 00000000000..35a2907b856
--- /dev/null
+++ b/lib/public/files/storageauthexception.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Jesús Macias <jmacias@solidgear.es>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Files;
+
+/**
+ * Storage authentication exception
+ * @since 9.0.0
+ */
+class StorageAuthException extends StorageNotAvailableException {
+
+ /**
+ * StorageAuthException constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param \Exception $previous
+ * @since 9.0.0
+ */
+ public function __construct($message = '', \Exception $previous = null) {
+ $l = \OC::$server->getL10N('core');
+ parent::__construct($l->t('Storage unauthorized. %s', $message), self::STATUS_UNAUTHORIZED, $previous);
+ }
+}
diff --git a/lib/public/files/storagebadconfigexception.php b/lib/public/files/storagebadconfigexception.php
new file mode 100644
index 00000000000..1c340b18b7c
--- /dev/null
+++ b/lib/public/files/storagebadconfigexception.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @author Jesús Macias <jmacias@solidgear.es>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Files;
+
+/**
+ * Storage has bad or missing config params
+ * @since 9.0.0
+ */
+class StorageBadConfigException extends StorageNotAvailableException {
+
+ /**
+ * ExtStorageBadConfigException constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param \Exception $previous
+ * @since 9.0.0
+ */
+ public function __construct($message = '', \Exception $previous = null) {
+ $l = \OC::$server->getL10N('core');
+ parent::__construct($l->t('Storage incomplete configuration. %s', $message), self::STATUS_INCOMPLETE_CONF, $previous);
+ }
+
+}
diff --git a/lib/public/files/storageconnectionexception.php b/lib/public/files/storageconnectionexception.php
new file mode 100644
index 00000000000..8938a60265c
--- /dev/null
+++ b/lib/public/files/storageconnectionexception.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Jesús Macias <jmacias@solidgear.es>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Files;
+
+/**
+ * Storage authentication exception
+ * @since 9.0.0
+ */
+class StorageConnectionException extends StorageNotAvailableException {
+
+ /**
+ * StorageConnectionException constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param \Exception $previous
+ * @since 9.0.0
+ */
+ public function __construct($message = '', \Exception $previous = null) {
+ $l = \OC::$server->getL10N('core');
+ parent::__construct($l->t('Storage connection error. %s', $message), self::STATUS_NETWORK_ERROR, $previous);
+ }
+}
diff --git a/lib/public/files/storageinvalidexception.php b/lib/public/files/storageinvalidexception.php
index 11099c2fe03..a34ee7ae49a 100644
--- a/lib/public/files/storageinvalidexception.php
+++ b/lib/public/files/storageinvalidexception.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/files/storagenotavailableexception.php b/lib/public/files/storagenotavailableexception.php
index a6665b38ce1..f9ac79d66ec 100644
--- a/lib/public/files/storagenotavailableexception.php
+++ b/lib/public/files/storagenotavailableexception.php
@@ -1,9 +1,11 @@
<?php
/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ * @author Jesús Macias <jmacias@solidgear.es>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,11 +34,18 @@ use OC\HintException;
/**
* Storage is temporarily not available
- * @since 6.0.0
- * @changed 8.2.1 based on HintException
+ * @since 6.0.0 - since 8.2.1 based on HintException
*/
class StorageNotAvailableException extends HintException {
+ const STATUS_SUCCESS = 0;
+ const STATUS_ERROR = 1;
+ const STATUS_INDETERMINATE = 2;
+ const STATUS_INCOMPLETE_CONF = 3;
+ const STATUS_UNAUTHORIZED = 4;
+ const STATUS_TIMEOUT = 5;
+ const STATUS_NETWORK_ERROR = 6;
+
/**
* StorageNotAvailableException constructor.
*
@@ -45,7 +54,7 @@ class StorageNotAvailableException extends HintException {
* @param \Exception $previous
* @since 6.0.0
*/
- public function __construct($message = '', $code = 0, \Exception $previous = null) {
+ public function __construct($message = '', $code = self::STATUS_ERROR, \Exception $previous = null) {
$l = \OC::$server->getL10N('core');
parent::__construct($message, $l->t('Storage not available'), $code, $previous);
}
diff --git a/lib/public/files/storagetimeoutexception.php b/lib/public/files/storagetimeoutexception.php
new file mode 100644
index 00000000000..ed4d98af89b
--- /dev/null
+++ b/lib/public/files/storagetimeoutexception.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Jesús Macias <jmacias@solidgear.es>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Files;
+
+/**
+ * Storage authentication exception
+ * @since 9.0.0
+ */
+class StorageTimeoutException extends StorageNotAvailableException {
+
+ /**
+ * StorageTimeoutException constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param \Exception $previous
+ * @since 9.0.0
+ */
+ public function __construct($message = '', \Exception $previous = null) {
+ $l = \OC::$server->getL10N('core');
+ parent::__construct($l->t('Storage connection timeout. %s', $message), self::STATUS_TIMEOUT, $previous);
+ }
+}
diff --git a/lib/public/groupinterface.php b/lib/public/groupinterface.php
index 16de6bc8663..142b3dea046 100644
--- a/lib/public/groupinterface.php
+++ b/lib/public/groupinterface.php
@@ -4,7 +4,7 @@
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,9 +32,75 @@
namespace OCP;
/**
- * Interface GroupInterface
+ * TODO actually this is a IGroupBackend
*
* @package OCP
* @since 4.5.0
*/
-interface GroupInterface extends \OC_Group_Interface {}
+interface GroupInterface {
+
+ /**
+ * Check if backend implements actions
+ * @param int $actions bitwise-or'ed actions
+ * @return boolean
+ * @since 4.5.0
+ *
+ * Returns the supported actions as int to be
+ * compared with \OC_Group_Backend::CREATE_GROUP etc.
+ */
+ public function implementsActions($actions);
+
+ /**
+ * is user in group?
+ * @param string $uid uid of the user
+ * @param string $gid gid of the group
+ * @return bool
+ * @since 4.5.0
+ *
+ * Checks whether the user is member of a group or not.
+ */
+ public function inGroup($uid, $gid);
+
+ /**
+ * Get all groups a user belongs to
+ * @param string $uid Name of the user
+ * @return array an array of group names
+ * @since 4.5.0
+ *
+ * This function fetches all groups a user belongs to. It does not check
+ * if the user exists at all.
+ */
+ public function getUserGroups($uid);
+
+ /**
+ * get a list of all groups
+ * @param string $search
+ * @param int $limit
+ * @param int $offset
+ * @return array an array of group names
+ * @since 4.5.0
+ *
+ * Returns a list with all groups
+ */
+ public function getGroups($search = '', $limit = -1, $offset = 0);
+
+ /**
+ * check if a group exists
+ * @param string $gid
+ * @return bool
+ * @since 4.5.0
+ */
+ public function groupExists($gid);
+
+ /**
+ * get a list of all users in a group
+ * @param string $gid
+ * @param string $search
+ * @param int $limit
+ * @param int $offset
+ * @return array an array of user ids
+ * @since 4.5.0
+ */
+ public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0);
+
+}
diff --git a/lib/public/http/client/iclient.php b/lib/public/http/client/iclient.php
index 494ca7d419e..85db2a9ad02 100644
--- a/lib/public/http/client/iclient.php
+++ b/lib/public/http/client/iclient.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/http/client/iclientservice.php b/lib/public/http/client/iclientservice.php
index 14dfcc071b8..907aa42fd3b 100644
--- a/lib/public/http/client/iclientservice.php
+++ b/lib/public/http/client/iclientservice.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/http/client/iresponse.php b/lib/public/http/client/iresponse.php
index 18371ddbbe6..09189d77014 100644
--- a/lib/public/http/client/iresponse.php
+++ b/lib/public/http/client/iresponse.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/iaddressbook.php b/lib/public/iaddressbook.php
index f3f60ab22d7..63e7e061448 100644
--- a/lib/public/iaddressbook.php
+++ b/lib/public/iaddressbook.php
@@ -2,10 +2,10 @@
/**
* @author Bart Visscher <bartv@thisnet.nl>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/iappconfig.php b/lib/public/iappconfig.php
index d89ffd9194a..a4bcc970188 100644
--- a/lib/public/iappconfig.php
+++ b/lib/public/iappconfig.php
@@ -3,10 +3,10 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/iavatar.php b/lib/public/iavatar.php
index fc29212a599..6203d3d5576 100644
--- a/lib/public/iavatar.php
+++ b/lib/public/iavatar.php
@@ -4,9 +4,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -24,6 +25,8 @@
*/
namespace OCP;
+use OCP\Files\File;
+use OCP\Files\NotFoundException;
/**
* This class provides avatar functionality
@@ -33,9 +36,9 @@ interface IAvatar {
/**
* get the users avatar
- * @param int $size size in px of the avatar, avatars are square, defaults to 64
+ * @param int $size size in px of the avatar, avatars are square, defaults to 64, -1 can be used to not scale the image
* @return boolean|\OCP\IImage containing the avatar or false if there's no image
- * @since 6.0.0
+ * @since 6.0.0 - size of -1 was added in 9.0.0
*/
public function get($size = 64);
@@ -64,4 +67,13 @@ interface IAvatar {
* @since 6.0.0
*/
public function remove();
+
+ /**
+ * Get the file of the avatar
+ * @param int $size -1 can be used to not scale the image
+ * @return File
+ * @throws NotFoundException
+ * @since 9.0.0
+ */
+ public function getFile($size);
}
diff --git a/lib/public/iavatarmanager.php b/lib/public/iavatarmanager.php
index 5ad5bf6a364..264c4fcf051 100644
--- a/lib/public/iavatarmanager.php
+++ b/lib/public/iavatarmanager.php
@@ -3,9 +3,9 @@
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/icache.php b/lib/public/icache.php
index d7593a263c8..3319013ddfa 100644
--- a/lib/public/icache.php
+++ b/lib/public/icache.php
@@ -4,7 +4,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/icachefactory.php b/lib/public/icachefactory.php
index a030b7fc5bc..233a4f5525d 100644
--- a/lib/public/icachefactory.php
+++ b/lib/public/icachefactory.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/icertificate.php b/lib/public/icertificate.php
index 73abc030934..c3a003fbf0a 100644
--- a/lib/public/icertificate.php
+++ b/lib/public/icertificate.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/icertificatemanager.php b/lib/public/icertificatemanager.php
index b1a16d8b5ee..27eebcf0491 100644
--- a/lib/public/icertificatemanager.php
+++ b/lib/public/icertificatemanager.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -54,8 +54,18 @@ interface ICertificateManager {
/**
* Get the path to the certificate bundle for this user
*
+ * @param string $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle (since 9.0.0)
* @return string
* @since 8.0.0
*/
- public function getCertificateBundle();
+ public function getCertificateBundle($uid = '');
+
+ /**
+ * Get the full local path to the certificate bundle for this user
+ *
+ * @param string $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle
+ * @return string
+ * @since 9.0.0
+ */
+ public function getAbsoluteBundlePath($uid = '');
}
diff --git a/lib/public/iconfig.php b/lib/public/iconfig.php
index 933eef97ae1..8dac390a99c 100644
--- a/lib/public/iconfig.php
+++ b/lib/public/iconfig.php
@@ -8,7 +8,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/icontainer.php b/lib/public/icontainer.php
index 23c75aeaaf8..d23ee5ea3b5 100644
--- a/lib/public/icontainer.php
+++ b/lib/public/icontainer.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/idatetimeformatter.php b/lib/public/idatetimeformatter.php
index 77afd6930ce..e8d357ae50f 100644
--- a/lib/public/idatetimeformatter.php
+++ b/lib/public/idatetimeformatter.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/idatetimezone.php b/lib/public/idatetimezone.php
index 2334f1314b5..3df705a2413 100644
--- a/lib/public/idatetimezone.php
+++ b/lib/public/idatetimezone.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/idb.php b/lib/public/idb.php
index f3e7915d9f7..f21fedd1f54 100644
--- a/lib/public/idb.php
+++ b/lib/public/idb.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/idbconnection.php b/lib/public/idbconnection.php
index 945ca142163..c5767e65a82 100644
--- a/lib/public/idbconnection.php
+++ b/lib/public/idbconnection.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -109,6 +109,20 @@ interface IDBConnection {
public function insertIfNotExist($table, $input, array $compare = null);
/**
+ * Insert or update a row value
+ *
+ * @param string $table
+ * @param array $keys (column name => value)
+ * @param array $values (column name => value)
+ * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
+ * @return int number of new rows
+ * @throws \Doctrine\DBAL\DBALException
+ * @throws PreconditionNotMetException
+ * @since 9.0.0
+ */
+ public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []);
+
+ /**
* Start a transaction
* @since 6.0.0
*/
diff --git a/lib/public/ieventsource.php b/lib/public/ieventsource.php
index 176d5677f0a..b643d1c9da7 100644
--- a/lib/public/ieventsource.php
+++ b/lib/public/ieventsource.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/igroup.php b/lib/public/igroup.php
index b16bb94d43f..02f2ef201fd 100644
--- a/lib/public/igroup.php
+++ b/lib/public/igroup.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/igroupmanager.php b/lib/public/igroupmanager.php
index 862c77218de..7eabc8a59b0 100644
--- a/lib/public/igroupmanager.php
+++ b/lib/public/igroupmanager.php
@@ -5,8 +5,9 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -52,7 +53,7 @@ interface IGroupManager {
public function isBackendUsed($backendClass);
/**
- * @param \OCP\UserInterface $backend
+ * @param \OCP\GroupInterface $backend
* @since 8.0.0
*/
public function addBackend($backend);
@@ -93,7 +94,7 @@ interface IGroupManager {
public function search($search, $limit = null, $offset = null);
/**
- * @param \OCP\IUser $user
+ * @param \OCP\IUser|null $user
* @return \OCP\IGroup[]
* @since 8.0.0
*/
diff --git a/lib/public/ihelper.php b/lib/public/ihelper.php
index 45a078b6cbc..4ad1d5704fd 100644
--- a/lib/public/ihelper.php
+++ b/lib/public/ihelper.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/iimage.php b/lib/public/iimage.php
index 38db14db77c..db0ca0f93be 100644
--- a/lib/public/iimage.php
+++ b/lib/public/iimage.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Olivier Paroz <github@oparoz.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/il10n.php b/lib/public/il10n.php
index c6e076a21f8..f1954eeb4b9 100644
--- a/lib/public/il10n.php
+++ b/lib/public/il10n.php
@@ -5,9 +5,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -74,7 +75,7 @@ interface IL10N {
/**
* Localization
* @param string $type Type of localization
- * @param array $data parameters for this localization
+ * @param int|string $data parameters for this localization
* @param array $options currently supports following options:
* - 'width': handed into \Punic\Calendar::formatDate as second parameter
* @return string|false
diff --git a/lib/public/ilogger.php b/lib/public/ilogger.php
index 27a5d63dfdb..2a727697a6a 100644
--- a/lib/public/ilogger.php
+++ b/lib/public/ilogger.php
@@ -3,7 +3,7 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -125,6 +125,14 @@ interface ILogger {
/**
* Logs an exception very detailed
+ * An additional message can we written to the log by adding it to the
+ * context.
+ *
+ * <code>
+ * $logger->logException($ex, [
+ * 'message' => 'Exception during cron job execution'
+ * ]);
+ * </code>
*
* @param \Exception $exception
* @param array $context
diff --git a/lib/public/image.php b/lib/public/image.php
index ebcae80f8e8..4a7ffe8bc9a 100644
--- a/lib/public/image.php
+++ b/lib/public/image.php
@@ -4,7 +4,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/imemcache.php b/lib/public/imemcache.php
index 01c29903039..b5c0cef923d 100644
--- a/lib/public/imemcache.php
+++ b/lib/public/imemcache.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/imemcachettl.php b/lib/public/imemcachettl.php
new file mode 100644
index 00000000000..f2d03dcdf40
--- /dev/null
+++ b/lib/public/imemcachettl.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP;
+
+/**
+ * Interface for memcache backends that support setting ttl after the value is set
+ *
+ * @since 8.2.2
+ */
+interface IMemcacheTTL extends IMemcache {
+ /**
+ * Set the ttl for an existing value
+ *
+ * @param string $key
+ * @param int $ttl time to live in seconds
+ * @since 8.2.2
+ */
+ public function setTTL($key, $ttl);
+}
diff --git a/lib/public/inavigationmanager.php b/lib/public/inavigationmanager.php
index fe2a4cfee27..243f6ea3eea 100644
--- a/lib/public/inavigationmanager.php
+++ b/lib/public/inavigationmanager.php
@@ -6,7 +6,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/ipreview.php b/lib/public/ipreview.php
index fc81da976b9..cfcbebd8639 100644
--- a/lib/public/ipreview.php
+++ b/lib/public/ipreview.php
@@ -5,7 +5,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/irequest.php b/lib/public/irequest.php
index acfc4f3f1d0..a0040aa464d 100644
--- a/lib/public/irequest.php
+++ b/lib/public/irequest.php
@@ -7,7 +7,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -91,6 +91,7 @@ interface IRequest {
* Returns all params that were received, be it from the request
*
* (as GET or POST) or through the URL by the route
+ *
* @return array the array with all parameters
* @since 6.0.0
*/
@@ -136,6 +137,7 @@ interface IRequest {
/**
* Checks if the CSRF check was correct
+ *
* @return bool true if CSRF check passed
* @since 6.0.0
*/
@@ -144,6 +146,7 @@ interface IRequest {
/**
* Returns an ID for the request, value is not guaranteed to be unique and is mostly meant for logging
* If `mod_unique_id` is installed this value will be taken.
+ *
* @return string
* @since 8.1.0
*/
@@ -154,6 +157,7 @@ interface IRequest {
* and `forwarded_for_headers` has been configured then the IP address
* specified in this header will be returned instead.
* Do always use this instead of $_SERVER['REMOTE_ADDR']
+ *
* @return string IP address
* @since 8.1.0
*/
@@ -162,6 +166,7 @@ interface IRequest {
/**
* Returns the server protocol. It respects reverse proxy servers and load
* balancers.
+ *
* @return string Server protocol (http or https)
* @since 8.1.0
*/
@@ -176,15 +181,17 @@ interface IRequest {
public function getHttpProtocol();
/**
- * Returns the request uri, even if the website uses one or more
- * reverse proxies
- * @return string
+ * Returns the request uri, even if the website uses one or more
+ * reverse proxies
+ *
+ * @return string
* @since 8.1.0
- */
+ */
public function getRequestUri();
/**
* Get raw PathInfo from request (not urldecoded)
+ *
* @throws \Exception
* @return string Path info
* @since 8.1.0
@@ -193,6 +200,7 @@ interface IRequest {
/**
* Get PathInfo from request
+ *
* @throws \Exception
* @return string|false Path info or false when not found
* @since 8.1.0
@@ -202,6 +210,7 @@ interface IRequest {
/**
* Returns the script name, even if the website uses one or more
* reverse proxies
+ *
* @return string the script name
* @since 8.1.0
*/
@@ -209,6 +218,7 @@ interface IRequest {
/**
* Checks whether the user agent matches a given regex
+ *
* @param array $agent array of agent names
* @return bool true if at least one of the given agent matches, false otherwise
* @since 8.1.0
@@ -218,6 +228,7 @@ interface IRequest {
/**
* Returns the unverified server host from the headers without checking
* whether it is a trusted domain
+ *
* @return string Server host
* @since 8.1.0
*/
@@ -226,6 +237,7 @@ interface IRequest {
/**
* Returns the server host from the headers, or the first configured
* trusted domain if the host isn't in the trusted list
+ *
* @return string Server host
* @since 8.1.0
*/
diff --git a/lib/public/isearch.php b/lib/public/isearch.php
index f7a9b5fb55c..ec6673dabbd 100644
--- a/lib/public/isearch.php
+++ b/lib/public/isearch.php
@@ -6,7 +6,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php
index d85f812b2e7..de48daeef88 100644
--- a/lib/public/iservercontainer.php
+++ b/lib/public/iservercontainer.php
@@ -1,5 +1,6 @@
<?php
/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Björn Schießle <schiessle@owncloud.com>
@@ -9,12 +10,13 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
+ * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -40,6 +42,7 @@
// use OCP namespace for all classes that are considered public.
// This means that they should be used by apps instead of the internal ownCloud classes
namespace OCP;
+use OCP\Security\IContentSecurityPolicyManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -179,6 +182,14 @@ interface IServerContainer {
public function getSecureRandom();
/**
+ * Returns a CredentialsManager instance
+ *
+ * @return \OCP\Security\ICredentialsManager
+ * @since 9.0.0
+ */
+ public function getCredentialsManager();
+
+ /**
* Returns an instance of the db facade
* @deprecated 8.1.0 use getDatabaseConnection, will be removed in ownCloud 10
* @return \OCP\IDb
@@ -326,7 +337,7 @@ interface IServerContainer {
/**
* Get the certificate manager for the user
*
- * @param string $userId (optional) if not specified the current loggedin user is used
+ * @param string $userId (optional) if not specified the current loggedin user is used, use null to get the system certificate manager
* @return \OCP\ICertificateManager | null if $userId is null and no user is logged in
* @since 8.0.0
*/
@@ -466,8 +477,46 @@ interface IServerContainer {
/**
* Get the Notification Manager
*
- * @return \OC\Notification\IManager
- * @since 8.2.0
+ * @return \OCP\Notification\IManager
+ * @since 9.0.0
*/
public function getNotificationManager();
+
+ /**
+ * @return \OCP\Comments\ICommentsManager
+ * @since 9.0.0
+ */
+ public function getCommentsManager();
+
+ /**
+ * Returns the system-tag manager
+ *
+ * @return \OCP\SystemTag\ISystemTagManager
+ *
+ * @since 9.0.0
+ */
+ public function getSystemTagManager();
+
+ /**
+ * Returns the system-tag object mapper
+ *
+ * @return \OCP\SystemTag\ISystemTagObjectMapper
+ *
+ * @since 9.0.0
+ */
+ public function getSystemTagObjectMapper();
+
+ /**
+ * Returns the share manager
+ *
+ * @return \OCP\Share\IManager
+ * @since 9.0.0
+ */
+ public function getShareManager();
+
+ /**
+ * @return IContentSecurityPolicyManager
+ * @since 9.0.0
+ */
+ public function getContentSecurityPolicyManager();
}
diff --git a/lib/public/isession.php b/lib/public/isession.php
index aee635d7a9d..25c76906d63 100644
--- a/lib/public/isession.php
+++ b/lib/public/isession.php
@@ -1,10 +1,11 @@
<?php
/**
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -86,4 +87,12 @@ interface ISession {
*/
public function close();
+ /**
+ * Wrapper around session_regenerate_id
+ *
+ * @param bool $deleteOldSession Whether to delete the old associated session file or not.
+ * @return void
+ * @since 9.0.0
+ */
+ public function regenerateId($deleteOldSession = true);
}
diff --git a/lib/public/itagmanager.php b/lib/public/itagmanager.php
index 5ed005548d3..e6d67ddd02c 100644
--- a/lib/public/itagmanager.php
+++ b/lib/public/itagmanager.php
@@ -5,7 +5,7 @@
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/itags.php b/lib/public/itags.php
index 12dbdc1522a..cbc178c37bf 100644
--- a/lib/public/itags.php
+++ b/lib/public/itags.php
@@ -5,7 +5,7 @@
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/itempmanager.php b/lib/public/itempmanager.php
index 73e21dd0aeb..025e43d8563 100644
--- a/lib/public/itempmanager.php
+++ b/lib/public/itempmanager.php
@@ -2,9 +2,9 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/iurlgenerator.php b/lib/public/iurlgenerator.php
index 3be27d87fa1..a702ca47bfc 100644
--- a/lib/public/iurlgenerator.php
+++ b/lib/public/iurlgenerator.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/iuser.php b/lib/public/iuser.php
index 6cbcfbf2312..454d45eae76 100644
--- a/lib/public/iuser.php
+++ b/lib/public/iuser.php
@@ -5,7 +5,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -144,4 +144,38 @@ interface IUser {
* @since 8.0.0
*/
public function setEnabled($enabled);
+
+ /**
+ * get the users email address
+ *
+ * @return string|null
+ * @since 9.0.0
+ */
+ public function getEMailAddress();
+
+ /**
+ * get the avatar image if it exists
+ *
+ * @param int $size
+ * @return IImage|null
+ * @since 9.0.0
+ */
+ public function getAvatarImage($size);
+
+ /**
+ * get the federation cloud id
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getCloudId();
+
+ /**
+ * set the email address of the user
+ *
+ * @param string|null $mailAddress
+ * @return void
+ * @since 9.0.0
+ */
+ public function setEMailAddress($mailAddress);
}
diff --git a/lib/public/iuserbackend.php b/lib/public/iuserbackend.php
index 2c472596b77..5cd7945dd7a 100644
--- a/lib/public/iuserbackend.php
+++ b/lib/public/iuserbackend.php
@@ -2,7 +2,7 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/iusermanager.php b/lib/public/iusermanager.php
index e3857d6231a..057bd8e89fb 100644
--- a/lib/public/iusermanager.php
+++ b/lib/public/iusermanager.php
@@ -3,8 +3,9 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -134,4 +135,11 @@ interface IUserManager {
* @since 8.0.0
*/
public function countUsers();
+
+ /**
+ * @param \Closure $callback
+ * @return void
+ * @since 9.0.0
+ */
+ public function callForAllUsers (\Closure $callback, $search = '');
}
diff --git a/lib/public/iusersession.php b/lib/public/iusersession.php
index 2dde25634d6..2196f2c8ce0 100644
--- a/lib/public/iusersession.php
+++ b/lib/public/iusersession.php
@@ -7,7 +7,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/json.php b/lib/public/json.php
index ddb94dffdbe..fceffa0001e 100644
--- a/lib/public/json.php
+++ b/lib/public/json.php
@@ -8,7 +8,7 @@
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/l10n/ifactory.php b/lib/public/l10n/ifactory.php
index b784505a68b..264c9719639 100644
--- a/lib/public/l10n/ifactory.php
+++ b/lib/public/l10n/ifactory.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -33,4 +33,47 @@ interface IFactory {
* @since 8.2.0
*/
public function get($app, $lang = null);
+
+ /**
+ * Find the best language
+ *
+ * @param string|null $app App id or null for core
+ * @return string language If nothing works it returns 'en'
+ * @since 9.0.0
+ */
+ public function findLanguage($app = null);
+
+ /**
+ * Find all available languages for an app
+ *
+ * @param string|null $app App id or null for core
+ * @return string[] an array of available languages
+ * @since 9.0.0
+ */
+ public function findAvailableLanguages($app = null);
+
+ /**
+ * @param string|null $app App id or null for core
+ * @param string $lang
+ * @return bool
+ * @since 9.0.0
+ */
+ public function languageExists($app, $lang);
+
+ /**
+ * @param string|null $app App id or null for core
+ * @return string
+ * @since 9.0.0
+ */
+ public function setLanguageFromRequest($app = null);
+
+
+ /**
+ * Creates a function from the plural string
+ *
+ * @param string $string
+ * @return string Unique function name
+ * @since 9.0.0
+ */
+ public function createPluralFunction($string);
}
diff --git a/lib/public/lock/ilockingprovider.php b/lib/public/lock/ilockingprovider.php
index f1aa7956033..b4b579bbc7a 100644
--- a/lib/public/lock/ilockingprovider.php
+++ b/lib/public/lock/ilockingprovider.php
@@ -3,7 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/lock/lockedexception.php b/lib/public/lock/lockedexception.php
index e7071339618..d084046046e 100644
--- a/lib/public/lock/lockedexception.php
+++ b/lib/public/lock/lockedexception.php
@@ -4,7 +4,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/mail/imailer.php b/lib/public/mail/imailer.php
index ac3fe9b0e49..61eb895752b 100644
--- a/lib/public/mail/imailer.php
+++ b/lib/public/mail/imailer.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/private/notification/iaction.php b/lib/public/notification/iaction.php
index 4aed2e92517..1f4d1d5b7fe 100644
--- a/lib/private/notification/iaction.php
+++ b/lib/public/notification/iaction.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -19,30 +19,26 @@
*
*/
-namespace OC\Notification;
+namespace OCP\Notification;
/**
* Interface IAction
*
- * @package OC\Notification
- * @since 8.2.0
- *
- * DEVELOPER NOTE:
- * The notification api is experimental only in 8.2.0! Do not start using it,
- * if you can not prepare an update for the next version afterwards.
+ * @package OCP\Notification
+ * @since 9.0.0
*/
interface IAction {
/**
* @param string $label
* @return $this
* @throws \InvalidArgumentException if the label is invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setLabel($label);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getLabel();
@@ -50,18 +46,19 @@ interface IAction {
* @param string $label
* @return $this
* @throws \InvalidArgumentException if the label is invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setParsedLabel($label);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getParsedLabel();
/**
* @param $primary bool
+ * @return $this
* @throws \InvalidArgumentException if $primary is invalid
* @since 9.0.0
*/
@@ -78,31 +75,31 @@ interface IAction {
* @param string $requestType
* @return $this
* @throws \InvalidArgumentException if the link is invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setLink($link, $requestType);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getLink();
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getRequestType();
/**
* @return bool
- * @since 8.2.0
+ * @since 9.0.0
*/
public function isValid();
/**
* @return bool
- * @since 8.2.0
+ * @since 9.0.0
*/
public function isValidParsed();
}
diff --git a/lib/private/notification/iapp.php b/lib/public/notification/iapp.php
index eda66423f3a..98da265559b 100644
--- a/lib/private/notification/iapp.php
+++ b/lib/public/notification/iapp.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -19,38 +19,34 @@
*
*/
-namespace OC\Notification;
+namespace OCP\Notification;
/**
* Interface IApp
*
- * @package OC\Notification
- * @since 8.2.0
- *
- * DEVELOPER NOTE:
- * The notification api is experimental only in 8.2.0! Do not start using it,
- * if you can not prepare an update for the next version afterwards.
+ * @package OCP\Notification
+ * @since 9.0.0
*/
interface IApp {
/**
* @param INotification $notification
* @return null
* @throws \InvalidArgumentException When the notification is not valid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function notify(INotification $notification);
/**
* @param INotification $notification
* @return null
- * @since 8.2.0
+ * @since 9.0.0
*/
public function markProcessed(INotification $notification);
/**
* @param INotification $notification
* @return int
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getCount(INotification $notification);
}
diff --git a/lib/private/notification/imanager.php b/lib/public/notification/imanager.php
index f4a5fb14e31..a18af747b10 100644
--- a/lib/private/notification/imanager.php
+++ b/lib/public/notification/imanager.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -19,44 +19,48 @@
*
*/
-namespace OC\Notification;
+namespace OCP\Notification;
/**
* Interface IManager
*
- * @package OC\Notification
- * @since 8.2.0
- *
- * DEVELOPER NOTE:
- * The notification api is experimental only in 8.2.0! Do not start using it,
- * if you can not prepare an update for the next version afterwards.
+ * @package OCP\Notification
+ * @since 9.0.0
*/
interface IManager extends IApp, INotifier {
/**
* @param \Closure $service The service must implement IApp, otherwise a
* \InvalidArgumentException is thrown later
* @return null
- * @since 8.2.0
+ * @since 9.0.0
*/
public function registerApp(\Closure $service);
/**
* @param \Closure $service The service must implement INotifier, otherwise a
* \InvalidArgumentException is thrown later
+ * @param \Closure $info An array with the keys 'id' and 'name' containing
+ * the app id and the app name
* @return null
- * @since 8.2.0
+ * @since 9.0.0
+ */
+ public function registerNotifier(\Closure $service, \Closure $info);
+
+ /**
+ * @return array App ID => App Name
+ * @since 9.0.0
*/
- public function registerNotifier(\Closure $service);
+ public function listNotifiers();
/**
* @return INotification
- * @since 8.2.0
+ * @since 9.0.0
*/
public function createNotification();
/**
* @return bool
- * @since 8.2.0
+ * @since 9.0.0
*/
public function hasNotifiers();
}
diff --git a/lib/private/notification/inotification.php b/lib/public/notification/inotification.php
index a8bf5b110ab..2d8557ec64d 100644
--- a/lib/private/notification/inotification.php
+++ b/lib/public/notification/inotification.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -19,30 +19,26 @@
*
*/
-namespace OC\Notification;
+namespace OCP\Notification;
/**
* Interface INotification
*
- * @package OC\Notification
- * @since 8.2.0
- *
- * DEVELOPER NOTE:
- * The notification api is experimental only in 8.2.0! Do not start using it,
- * if you can not prepare an update for the next version afterwards.
+ * @package OCP\Notification
+ * @since 9.0.0
*/
interface INotification {
/**
* @param string $app
* @return $this
* @throws \InvalidArgumentException if the app id are invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setApp($app);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getApp();
@@ -50,48 +46,48 @@ interface INotification {
* @param string $user
* @return $this
* @throws \InvalidArgumentException if the user id are invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setUser($user);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getUser();
/**
- * @param int $timestamp
+ * @param \DateTime $dateTime
* @return $this
- * @throws \InvalidArgumentException if the timestamp are invalid
- * @since 8.2.0
+ * @throws \InvalidArgumentException if the $dateTime is invalid
+ * @since 9.0.0
*/
- public function setTimestamp($timestamp);
+ public function setDateTime(\DateTime $dateTime);
/**
- * @return int
- * @since 8.2.0
+ * @return \DateTime
+ * @since 9.0.0
*/
- public function getTimestamp();
+ public function getDateTime();
/**
* @param string $type
- * @param int $id
+ * @param string $id
* @return $this
- * @throws \InvalidArgumentException if the object type or id are invalid
- * @since 8.2.0
+ * @throws \InvalidArgumentException if the object type or id is invalid
+ * @since 9.0.0
*/
public function setObject($type, $id);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getObjectType();
/**
- * @return int
- * @since 8.2.0
+ * @return string
+ * @since 9.0.0
*/
public function getObjectId();
@@ -100,19 +96,19 @@ interface INotification {
* @param array $parameters
* @return $this
* @throws \InvalidArgumentException if the subject or parameters are invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setSubject($subject, array $parameters = []);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getSubject();
/**
* @return string[]
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getSubjectParameters();
@@ -120,13 +116,13 @@ interface INotification {
* @param string $subject
* @return $this
* @throws \InvalidArgumentException if the subject are invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setParsedSubject($subject);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getParsedSubject();
@@ -135,19 +131,19 @@ interface INotification {
* @param array $parameters
* @return $this
* @throws \InvalidArgumentException if the message or parameters are invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setMessage($message, array $parameters = []);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getMessage();
/**
* @return string[]
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getMessageParameters();
@@ -155,13 +151,13 @@ interface INotification {
* @param string $message
* @return $this
* @throws \InvalidArgumentException if the message are invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setParsedMessage($message);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getParsedMessage();
@@ -169,19 +165,19 @@ interface INotification {
* @param string $link
* @return $this
* @throws \InvalidArgumentException if the link are invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function setLink($link);
/**
* @return string
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getLink();
/**
* @return IAction
- * @since 8.2.0
+ * @since 9.0.0
*/
public function createAction();
@@ -189,13 +185,13 @@ interface INotification {
* @param IAction $action
* @return $this
* @throws \InvalidArgumentException if the action are invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function addAction(IAction $action);
/**
* @return IAction[]
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getActions();
@@ -203,25 +199,25 @@ interface INotification {
* @param IAction $action
* @return $this
* @throws \InvalidArgumentException if the action are invalid
- * @since 8.2.0
+ * @since 9.0.0
*/
public function addParsedAction(IAction $action);
/**
* @return IAction[]
- * @since 8.2.0
+ * @since 9.0.0
*/
public function getParsedActions();
/**
* @return bool
- * @since 8.2.0
+ * @since 9.0.0
*/
public function isValid();
/**
* @return bool
- * @since 8.2.0
+ * @since 9.0.0
*/
public function isValidParsed();
}
diff --git a/lib/private/notification/inotifier.php b/lib/public/notification/inotifier.php
index 22531229e3f..0d9cecc88b8 100644
--- a/lib/private/notification/inotifier.php
+++ b/lib/public/notification/inotifier.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -19,17 +19,13 @@
*
*/
-namespace OC\Notification;
+namespace OCP\Notification;
/**
* Interface INotifier
*
- * @package OC\Notification
- * @since 8.2.0
- *
- * DEVELOPER NOTE:
- * The notification api is experimental only in 8.2.0! Do not start using it,
- * if you can not prepare an update for the next version afterwards.
+ * @package OCP\Notification
+ * @since 9.0.0
*/
interface INotifier {
/**
@@ -37,7 +33,7 @@ interface INotifier {
* @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification
* @throws \InvalidArgumentException When the notification was not prepared by a notifier
- * @since 8.2.0
+ * @since 9.0.0
*/
public function prepare(INotification $notification, $languageCode);
}
diff --git a/lib/public/preconditionnotmetexception.php b/lib/public/preconditionnotmetexception.php
index 6f1b683526d..212efc08ded 100644
--- a/lib/public/preconditionnotmetexception.php
+++ b/lib/public/preconditionnotmetexception.php
@@ -2,7 +2,7 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/preview/iprovider.php b/lib/public/preview/iprovider.php
index 821cdb32fa3..8231e90f000 100644
--- a/lib/public/preview/iprovider.php
+++ b/lib/public/preview/iprovider.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/response.php b/lib/public/response.php
index 953c797824c..ff0b4d8463a 100644
--- a/lib/public/response.php
+++ b/lib/public/response.php
@@ -9,7 +9,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/route/iroute.php b/lib/public/route/iroute.php
index 4c9b4ca9b47..904cb81b0bd 100644
--- a/lib/public/route/iroute.php
+++ b/lib/public/route/iroute.php
@@ -3,9 +3,9 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/route/irouter.php b/lib/public/route/irouter.php
index 3f5b58ac416..b4573fb39f2 100644
--- a/lib/public/route/irouter.php
+++ b/lib/public/route/irouter.php
@@ -2,10 +2,12 @@
/**
* @author Bart Visscher <bartv@thisnet.nl>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -29,6 +31,7 @@ namespace OCP\Route;
*
* @package OCP\Route
* @since 7.0.0
+ * @deprecated 9.0.0
*/
interface IRouter {
@@ -37,19 +40,23 @@ interface IRouter {
*
* @return string[]
* @since 7.0.0
+ * @deprecated 9.0.0
*/
public function getRoutingFiles();
/**
* @return string
* @since 7.0.0
+ * @deprecated 9.0.0
*/
public function getCacheKey();
/**
- * loads the api routes
- * @return void
+ * Loads the routes
+ *
+ * @param null|string $app
* @since 7.0.0
+ * @deprecated 9.0.0
*/
public function loadRoutes($app = null);
@@ -59,6 +66,7 @@ interface IRouter {
* @param string $name Name of the collection to use.
* @return void
* @since 7.0.0
+ * @deprecated 9.0.0
*/
public function useCollection($name);
@@ -67,6 +75,7 @@ interface IRouter {
*
* @return string the collection name
* @since 8.0.0
+ * @deprecated 9.0.0
*/
public function getCurrentCollection();
@@ -79,6 +88,7 @@ interface IRouter {
* @param array $requirements An array of requirements for parameters (regexes)
* @return \OCP\Route\IRoute
* @since 7.0.0
+ * @deprecated 9.0.0
*/
public function create($name, $pattern, array $defaults = array(), array $requirements = array());
@@ -89,6 +99,7 @@ interface IRouter {
* @throws \Exception
* @return void
* @since 7.0.0
+ * @deprecated 9.0.0
*/
public function match($url);
@@ -96,6 +107,7 @@ interface IRouter {
* Get the url generator
*
* @since 7.0.0
+ * @deprecated 9.0.0
*/
public function getGenerator();
@@ -107,6 +119,7 @@ interface IRouter {
* @param bool $absolute
* @return string
* @since 7.0.0
+ * @deprecated 9.0.0
*/
public function generate($name, $parameters = array(), $absolute = false);
diff --git a/lib/public/sabrepluginevent.php b/lib/public/sabrepluginevent.php
index fed3237166d..b0c8257a4fb 100644
--- a/lib/public/sabrepluginevent.php
+++ b/lib/public/sabrepluginevent.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,6 +23,7 @@ namespace OCP;
use OCP\AppFramework\Http;
+use Sabre\DAV\Server;
use Symfony\Component\EventDispatcher\Event;
/**
@@ -36,12 +37,16 @@ class SabrePluginEvent extends Event {
/** @var string */
protected $message;
+ /** @var Server */
+ protected $server;
+
/**
* @since 8.2.0
*/
- public function __construct() {
+ public function __construct($server = null) {
$this->message = '';
$this->statusCode = Http::STATUS_OK;
+ $this->server = $server;
}
/**
@@ -79,4 +84,12 @@ class SabrePluginEvent extends Event {
public function getMessage() {
return $this->message;
}
+
+ /**
+ * @return null|Server
+ * @since 9.0.0
+ */
+ public function getServer() {
+ return $this->server;
+ }
}
diff --git a/lib/public/sabrepluginexception.php b/lib/public/sabrepluginexception.php
index 5dba3b90a02..2c5a799c4f7 100644
--- a/lib/public/sabrepluginexception.php
+++ b/lib/public/sabrepluginexception.php
@@ -2,7 +2,7 @@
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/search/pagedprovider.php b/lib/public/search/pagedprovider.php
index 7452bbd47bb..93289a1bde4 100644
--- a/lib/public/search/pagedprovider.php
+++ b/lib/public/search/pagedprovider.php
@@ -3,7 +3,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/search/provider.php b/lib/public/search/provider.php
index 2f2cd03eb6a..9bcbe36ef7a 100644
--- a/lib/public/search/provider.php
+++ b/lib/public/search/provider.php
@@ -6,7 +6,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/search/result.php b/lib/public/search/result.php
index 71c8b021a8e..e90c2619032 100644
--- a/lib/public/search/result.php
+++ b/lib/public/search/result.php
@@ -5,7 +5,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/security/icontentsecuritypolicymanager.php b/lib/public/security/icontentsecuritypolicymanager.php
new file mode 100644
index 00000000000..10f1efe995f
--- /dev/null
+++ b/lib/public/security/icontentsecuritypolicymanager.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Security;
+use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
+
+/**
+ * Used for Content Security Policy manipulations
+ *
+ * @package OCP\Security
+ * @since 9.0.0
+ */
+interface IContentSecurityPolicyManager {
+ /**
+ * Allows to inject something into the default content policy. This is for
+ * example useful when you're injecting Javascript code into a view belonging
+ * to another controller and cannot modify its Content-Security-Policy itself.
+ * Note that the adjustment is only applied to applications that use AppFramework
+ * controllers.
+ *
+ * To use this from your `app.php` use `\OC::$server->getContentSecurityPolicyManager()->addDefaultPolicy($policy)`,
+ * $policy has to be of type `\OCP\AppFramework\Http\ContentSecurityPolicy`.
+ *
+ * WARNING: Using this API incorrectly may make the instance more insecure.
+ * Do think twice before adding whitelisting resources. Please do also note
+ * that it is not possible to use the `disallowXYZ` functions.
+ *
+ * @param EmptyContentSecurityPolicy $policy
+ * @since 9.0.0
+ */
+ public function addDefaultPolicy(EmptyContentSecurityPolicy $policy);
+}
diff --git a/lib/public/security/icredentialsmanager.php b/lib/public/security/icredentialsmanager.php
new file mode 100644
index 00000000000..d3d076f043e
--- /dev/null
+++ b/lib/public/security/icredentialsmanager.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Security;
+
+/**
+ * Store and retrieve credentials for external services
+ *
+ * @package OCP\Security
+ * @since 8.2.0
+ */
+interface ICredentialsManager {
+
+ /**
+ * Store a set of credentials
+ *
+ * @param string|null $userId Null for system-wide credentials
+ * @param string $identifier
+ * @param mixed $credentials
+ * @since 8.2.0
+ */
+ public function store($userId, $identifier, $credentials);
+
+ /**
+ * Retrieve a set of credentials
+ *
+ * @param string|null $userId Null for system-wide credentials
+ * @param string $identifier
+ * @return mixed
+ * @since 8.2.0
+ */
+ public function retrieve($userId, $identifier);
+
+ /**
+ * Delete a set of credentials
+ *
+ * @param string|null $userId Null for system-wide credentials
+ * @param string $identifier
+ * @return int rows removed
+ * @since 8.2.0
+ */
+ public function delete($userId, $identifier);
+
+ /**
+ * Erase all credentials stored for a user
+ *
+ * @param string $userId
+ * @return int rows removed
+ * @since 8.2.0
+ */
+ public function erase($userId);
+
+}
diff --git a/lib/public/security/icrypto.php b/lib/public/security/icrypto.php
index 167baab8233..62f27017ab7 100644
--- a/lib/public/security/icrypto.php
+++ b/lib/public/security/icrypto.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/security/ihasher.php b/lib/public/security/ihasher.php
index 14229ba99c1..39ba5094b12 100644
--- a/lib/public/security/ihasher.php
+++ b/lib/public/security/ihasher.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/security/isecurerandom.php b/lib/public/security/isecurerandom.php
index 1b72e4f4377..9b346afe680 100644
--- a/lib/public/security/isecurerandom.php
+++ b/lib/public/security/isecurerandom.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -23,12 +23,12 @@
namespace OCP\Security;
/**
- * Class SecureRandom provides a layer around RandomLib to generate
- * secure random strings. For PHP 7 the native CSPRNG is used.
+ * Class SecureRandom provides a wrapper around the random_int function to generate
+ * secure random strings. For PHP 7 the native CSPRNG is used, older versions do
+ * use a fallback.
*
* Usage:
- * $rng = new \OC\Security\SecureRandom();
- * $randomString = $rng->getMediumStrengthGenerator()->generateString(30);
+ * \OC::$server->getSecureRandom()->generate(10);
*
* @package OCP\Security
* @since 8.0.0
@@ -52,6 +52,7 @@ interface ISecureRandom {
*
* @return $this
* @since 8.0.0
+ * @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int()
*/
public function getLowStrengthGenerator();
@@ -64,6 +65,7 @@ interface ISecureRandom {
*
* @return $this
* @since 8.0.0
+ * @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int()
*/
public function getMediumStrengthGenerator();
@@ -73,7 +75,6 @@ interface ISecureRandom {
* @param string $characters An optional list of characters to use if no character list is
* specified all valid base64 characters are used.
* @return string
- * @throws \Exception If the generator is not initialized.
* @since 8.0.0
*/
public function generate($length,
diff --git a/lib/public/security/stringutils.php b/lib/public/security/stringutils.php
index 4f41fcf8262..ff1e290315a 100644
--- a/lib/public/security/stringutils.php
+++ b/lib/public/security/stringutils.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -39,8 +39,9 @@ class StringUtils {
* @param string $input The input to compare against
* @return bool True if the two strings are equal, otherwise false.
* @since 8.0.0
+ * @deprecated 9.0.0 Use hash_equals
*/
public static function equals($expected, $input) {
- return \OC\Security\StringUtils::equals($expected, $input);
+ return hash_equals($expected, $input);
}
}
diff --git a/lib/public/share.php b/lib/public/share.php
index 86d1ffc9be2..e21d82bf62c 100644
--- a/lib/public/share.php
+++ b/lib/public/share.php
@@ -8,12 +8,12 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Michael Kuhn <suraia@ikkoku.de>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Sam Tuke <mail@samtuke.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/share/exceptions/genericshareexception.php b/lib/public/share/exceptions/genericshareexception.php
new file mode 100644
index 00000000000..83dfa12dbfc
--- /dev/null
+++ b/lib/public/share/exceptions/genericshareexception.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace OCP\Share\Exceptions;
+use OC\HintException;
+
+/**
+ * Class GenericEncryptionException
+ *
+ * @package OCP\Share\Exceptions
+ * @since 9.0.0
+ */
+class GenericShareException extends HintException {
+
+ /**
+ * @param string $message
+ * @param string $hint
+ * @param int $code
+ * @param \Exception $previous
+ * @since 9.0.0
+ */
+ public function __construct($message = '', $hint = '', $code = 0, \Exception $previous = null) {
+ if (empty($message)) {
+ $message = 'Unspecified share exception';
+ }
+ parent::__construct($message, $hint, $code, $previous);
+ }
+
+}
diff --git a/lib/public/share/exceptions/sharenotfound.php b/lib/public/share/exceptions/sharenotfound.php
new file mode 100644
index 00000000000..96e7c096492
--- /dev/null
+++ b/lib/public/share/exceptions/sharenotfound.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Share\Exceptions;
+
+/**
+ * Class ShareNotFound
+ *
+ * @package OCP\Share\Exceptions
+ * @since 9.0.0
+ */
+class ShareNotFound extends GenericShareException {
+
+}
diff --git a/lib/public/share/imanager.php b/lib/public/share/imanager.php
new file mode 100644
index 00000000000..4d79f97c31a
--- /dev/null
+++ b/lib/public/share/imanager.php
@@ -0,0 +1,232 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Share;
+
+use OCP\IUser;
+
+use OC\Share20\Exception\ShareNotFound;
+
+/**
+ * Interface IManager
+ *
+ * @package OCP\Share
+ * @since 9.0.0
+ */
+interface IManager {
+
+ /**
+ * Create a Share
+ *
+ * @param IShare $share
+ * @return IShare The share object
+ * @since 9.0.0
+ */
+ public function createShare(IShare $share);
+
+ /**
+ * Update a share.
+ * The target of the share can't be changed this way: use moveShare
+ * The share can't be removed this way (permission 0): use deleteShare
+ *
+ * @param IShare $share
+ * @return IShare The share object
+ * @since 9.0.0
+ */
+ public function updateShare(IShare $share);
+
+ /**
+ * Delete a share
+ *
+ * @param IShare $share
+ * @throws ShareNotFound
+ * @since 9.0.0
+ */
+ public function deleteShare(IShare $share);
+
+ /**
+ * Unshare a file as the recipient.
+ * This can be different from a regular delete for example when one of
+ * the users in a groups deletes that share. But the provider should
+ * handle this.
+ *
+ * @param IShare $share
+ * @param string $recipientId
+ * @since 9.0.0
+ */
+ public function deleteFromSelf(IShare $share, $recipientId);
+
+ /**
+ * Move the share as a recipient of the share.
+ * This is updating the share target. So where the recipient has the share mounted.
+ *
+ * @param IShare $share
+ * @param string $recipientId
+ * @return IShare
+ * @throws \InvalidArgumentException If $share is a link share or the $recipient does not match
+ * @since 9.0.0
+ */
+ public function moveShare(IShare $share, $recipientId);
+
+ /**
+ * Get shares shared by (initiated) by the provided user.
+ *
+ * @param string $userId
+ * @param int $shareType
+ * @param \OCP\Files\File|\OCP\Files\Folder $path
+ * @param bool $reshares
+ * @param int $limit The maximum number of returned results, -1 for all results
+ * @param int $offset
+ * @return IShare[]
+ * @since 9.0.0
+ */
+ public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0);
+
+ /**
+ * Get shares shared with $user.
+ * Filter by $node if provided
+ *
+ * @param string $userId
+ * @param int $shareType
+ * @param File|Folder|null $node
+ * @param int $limit The maximum number of shares returned, -1 for all
+ * @param int $offset
+ * @return IShare[]
+ * @since 9.0.0
+ */
+ public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0);
+
+ /**
+ * Retrieve a share by the share id.
+ * If the recipient is set make sure to retrieve the file for that user.
+ * This makes sure that if a user has moved/deleted a group share this
+ * is reflected.
+ *
+ * @param string $id
+ * @param IUser|null $recipient
+ * @return IShare
+ * @throws ShareNotFound
+ * @since 9.0.0
+ */
+ public function getShareById($id, $recipient = null);
+
+ /**
+ * Get the share by token possible with password
+ *
+ * @param string $token
+ * @return IShare
+ * @throws ShareNotFound
+ * @since 9.0.0
+ */
+ public function getShareByToken($token);
+
+ /**
+ * Verify the password of a public share
+ *
+ * @param IShare $share
+ * @param string $password
+ * @return bool
+ * @since 9.0.0
+ */
+ public function checkPassword(IShare $share, $password);
+
+ /**
+ * Instantiates a new share object. This is to be passed to
+ * createShare.
+ *
+ * @return IShare
+ * @since 9.0.0
+ */
+ public function newShare();
+
+ /**
+ * Is the share API enabled
+ *
+ * @return bool
+ * @since 9.0.0
+ */
+ public function shareApiEnabled();
+
+ /**
+ * Is public link sharing enabled
+ *
+ * @return bool
+ * @since 9.0.0
+ */
+ public function shareApiAllowLinks();
+
+ /**
+ * Is password on public link requires
+ *
+ * @return bool
+ * @since 9.0.0
+ */
+ public function shareApiLinkEnforcePassword();
+
+ /**
+ * Is default expire date enabled
+ *
+ * @return bool
+ * @since 9.0.0
+ */
+ public function shareApiLinkDefaultExpireDate();
+
+ /**
+ * Is default expire date enforced
+ *`
+ * @return bool
+ * @since 9.0.0
+ */
+ public function shareApiLinkDefaultExpireDateEnforced();
+
+ /**
+ * Number of default expire days
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function shareApiLinkDefaultExpireDays();
+
+ /**
+ * Allow public upload on link shares
+ *
+ * @return bool
+ * @since 9.0.0
+ */
+ public function shareApiLinkAllowPublicUpload();
+
+ /**
+ * check if user can only share with group members
+ * @return bool
+ * @since 9.0.0
+ */
+ public function shareWithGroupMembersOnly();
+
+ /**
+ * Check if sharing is disabled for the given user
+ *
+ * @param string $userId
+ * @return bool
+ * @since 9.0.0
+ */
+ public function sharingDisabledForUser($userId);
+
+}
diff --git a/lib/public/share/iproviderfactory.php b/lib/public/share/iproviderfactory.php
new file mode 100644
index 00000000000..3a8baccf33b
--- /dev/null
+++ b/lib/public/share/iproviderfactory.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Share;
+
+use OC\Share20\Exception\ProviderException;
+use OCP\IServerContainer;
+
+/**
+ * Interface IProviderFactory
+ *
+ * @package OC\Share20
+ * @since 9.0.0
+ */
+interface IProviderFactory {
+
+ /**
+ * IProviderFactory constructor.
+ * @param IServerContainer $serverContainer
+ * @since 9.0.0
+ */
+ public function __construct(IServerContainer $serverContainer);
+
+ /**
+ * @param string $id
+ * @return IShareProvider
+ * @throws ProviderException
+ * @since 9.0.0
+ */
+ public function getProvider($id);
+
+ /**
+ * @param int $shareType
+ * @return IShareProvider
+ * @throws ProviderException
+ * @since 9.0.0
+ */
+ public function getProviderForType($shareType);
+}
diff --git a/lib/public/share/ishare.php b/lib/public/share/ishare.php
new file mode 100644
index 00000000000..5054a886af5
--- /dev/null
+++ b/lib/public/share/ishare.php
@@ -0,0 +1,298 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Share;
+
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\Node;
+use OCP\Files\NotFoundException;
+
+/**
+ * Interface IShare
+ *
+ * @package OCP\Share
+ * @since 9.0.0
+ */
+interface IShare {
+
+ /**
+ * Get the internal id of the share.
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getId();
+
+ /**
+ * Get the full share id. This is the <providerid>:<internalid>.
+ * The full id is unique in the system.
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getFullId();
+
+ /**
+ * Set the node of the file/folder that is shared
+ *
+ * @param Node $node
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setNode(Node $node);
+
+ /**
+ * Get the node of the file/folder that is shared
+ *
+ * @return File|Folder
+ * @since 9.0.0
+ * @throws NotFoundException
+ */
+ public function getNode();
+
+ /**
+ * Set file id for lazy evaluation of the node
+ * @param int $fileId
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setNodeId($fileId);
+
+ /**
+ * Get the fileid of the node of this share
+ * @return int
+ * @since 9.0.0
+ * @throws NotFoundException
+ */
+ public function getNodeId();
+
+ /**
+ * Set the type of node (file/folder)
+ *
+ * @param string $type
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setNodeType($type);
+
+ /**
+ * Get the type of node (file/folder)
+ *
+ * @return string
+ * @since 9.0.0
+ * @throws NotFoundException
+ */
+ public function getNodeType();
+
+ /**
+ * Set the shareType
+ *
+ * @param int $shareType
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setShareType($shareType);
+
+ /**
+ * Get the shareType
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getShareType();
+
+ /**
+ * Set the receiver of this share.
+ *
+ * @param string $sharedWith
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setSharedWith($sharedWith);
+
+ /**
+ * Get the receiver of this share.
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getSharedWith();
+
+ /**
+ * Set the permissions.
+ * See \OCP\Constants::PERMISSION_*
+ *
+ * @param int $permissions
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setPermissions($permissions);
+
+ /**
+ * Get the share permissions
+ * See \OCP\Constants::PERMISSION_*
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getPermissions();
+
+ /**
+ * Set the expiration date
+ *
+ * @param \DateTime $expireDate
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setExpirationDate($expireDate);
+
+ /**
+ * Get the expiration date
+ *
+ * @return \DateTime
+ * @since 9.0.0
+ */
+ public function getExpirationDate();
+
+ /**
+ * Set the sharer of the path.
+ *
+ * @param string $sharedBy
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setSharedBy($sharedBy);
+
+ /**
+ * Get share sharer
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getSharedBy();
+
+ /**
+ * Set the original share owner (who owns the path that is shared)
+ *
+ * @param string $shareOwner
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setShareOwner($shareOwner);
+
+ /**
+ * Get the original share owner (who owns the path that is shared)
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getShareOwner();
+
+ /**
+ * Set the password for this share.
+ * When the share is passed to the share manager to be created
+ * or updated the password will be hashed.
+ *
+ * @param string $password
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setPassword($password);
+
+ /**
+ * Get the password of this share.
+ * If this share is obtained via a shareprovider the password is
+ * hashed.
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getPassword();
+
+ /**
+ * Set the public link token.
+ *
+ * @param string $token
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setToken($token);
+
+ /**
+ * Get the public link token.
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getToken();
+
+ /**
+ * Set the target path of this share relative to the recipients user folder.
+ *
+ * @param string $target
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setTarget($target);
+
+ /**
+ * Get the target path of this share relative to the recipients user folder.
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getTarget();
+
+ /**
+ * Set the time this share was created
+ *
+ * @param \DateTime $shareTime
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setShareTime(\DateTime $shareTime);
+
+ /**
+ * Get the timestamp this share was created
+ *
+ * @return \DateTime
+ * @since 9.0.0
+ */
+ public function getShareTime();
+
+ /**
+ * Set if the recipient is informed by mail about the share.
+ *
+ * @param bool $mailSend
+ * @return \OCP\Share\IShare The modified object
+ * @since 9.0.0
+ */
+ public function setMailSend($mailSend);
+
+ /**
+ * Get if the recipient informed by mail about the share.
+ *
+ * @return bool
+ * @since 9.0.0
+ */
+ public function getMailSend();
+}
diff --git a/lib/public/share/ishareprovider.php b/lib/public/share/ishareprovider.php
new file mode 100644
index 00000000000..25fa76369ab
--- /dev/null
+++ b/lib/public/share/ishareprovider.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Share;
+
+use OC\Share20\Exception\ShareNotFound;
+use OC\Share20\Exception\BackendError;
+use OCP\Files\Node;
+use OCP\IUser;
+
+/**
+ * Interface IShareProvider
+ *
+ * @package OCP\Share
+ * @since 9.0.0
+ */
+interface IShareProvider {
+
+ /**
+ * Return the identifier of this provider.
+ *
+ * @return string Containing only [a-zA-Z0-9]
+ * @since 9.0.0
+ */
+ public function identifier();
+
+ /**
+ * Create a share
+ *
+ * @param \OCP\Share\IShare $share
+ * @return \OCP\Share\IShare The share object
+ * @since 9.0.0
+ */
+ public function create(\OCP\Share\IShare $share);
+
+ /**
+ * Update a share
+ *
+ * @param \OCP\Share\IShare $share
+ * @return \OCP\Share\IShare The share object
+ * @since 9.0.0
+ */
+ public function update(\OCP\Share\IShare $share);
+
+ /**
+ * Delete a share
+ *
+ * @param \OCP\Share\IShare $share
+ * @since 9.0.0
+ */
+ public function delete(\OCP\Share\IShare $share);
+
+ /**
+ * Unshare a file from self as recipient.
+ * This may require special handling. If a user unshares a group
+ * share from their self then the original group share should still exist.
+ *
+ * @param \OCP\Share\IShare $share
+ * @param string $recipient UserId of the recipient
+ * @since 9.0.0
+ */
+ public function deleteFromSelf(\OCP\Share\IShare $share, $recipient);
+
+ /**
+ * Move a share as a recipient.
+ * This is updating the share target. Thus the mount point of the recipient.
+ * This may require special handling. If a user moves a group share
+ * the target should only be changed for them.
+ *
+ * @param \OCP\Share\IShare $share
+ * @param string $recipient userId of recipient
+ * @return \OCP\Share\IShare
+ * @since 9.0.0
+ */
+ public function move(\OCP\Share\IShare $share, $recipient);
+
+ /**
+ * Get all shares by the given user
+ *
+ * @param string $userId
+ * @param int $shareType
+ * @param \OCP\Files\File|\OCP\Files\Folder $node
+ * @param bool $reshares Also get the shares where $user is the owner instead of just the shares where $user is the initiator
+ * @param int $limit The maximum number of shares to be returned, -1 for all shares
+ * @param int $offset
+ * @return \OCP\Share\IShare Share[]
+ * @since 9.0.0
+ */
+ public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset);
+
+ /**
+ * Get share by id
+ *
+ * @param int $id
+ * @param string|null $recipientId
+ * @return \OCP\Share\IShare
+ * @throws ShareNotFound
+ * @since 9.0.0
+ */
+ public function getShareById($id, $recipientId = null);
+
+ /**
+ * Get shares for a given path
+ *
+ * @param \OCP\Files\Node $path
+ * @return \OCP\Share\IShare[]
+ * @since 9.0.0
+ */
+ public function getSharesByPath(\OCP\Files\Node $path);
+
+ /**
+ * Get shared with the given user
+ *
+ * @param string $userId get shares where this user is the recipient
+ * @param int $shareType
+ * @param Node|null $node
+ * @param int $limit The max number of entries returned, -1 for all
+ * @param int $offset
+ * @return \OCP\Share\IShare[]
+ * @since 9.0.0
+ */
+ public function getSharedWith($userId, $shareType, $node, $limit, $offset);
+
+ /**
+ * Get a share by token
+ *
+ * @param string $token
+ * @return \OCP\Share\IShare
+ * @throws ShareNotFound
+ * @since 9.0.0
+ */
+ public function getShareByToken($token);
+}
diff --git a/lib/public/share_backend.php b/lib/public/share_backend.php
index 35ed650b173..110403c1f49 100644
--- a/lib/public/share_backend.php
+++ b/lib/public/share_backend.php
@@ -3,9 +3,9 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/share_backend_collection.php b/lib/public/share_backend_collection.php
index 7378fd2a46d..185cf32ce3e 100644
--- a/lib/public/share_backend_collection.php
+++ b/lib/public/share_backend_collection.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/share_backend_file_dependent.php b/lib/public/share_backend_file_dependent.php
index b95e0bd84d2..64b3bf43319 100644
--- a/lib/public/share_backend_file_dependent.php
+++ b/lib/public/share_backend_file_dependent.php
@@ -3,7 +3,7 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/systemtag/isystemtag.php b/lib/public/systemtag/isystemtag.php
new file mode 100644
index 00000000000..02d02037293
--- /dev/null
+++ b/lib/public/systemtag/isystemtag.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SystemTag;
+
+/**
+ * Public interface for a system-wide tag.
+ *
+ * @since 9.0.0
+ */
+interface ISystemTag {
+
+ /**
+ * Returns the tag id
+ *
+ * @return string id
+ *
+ * @since 9.0.0
+ */
+ public function getId();
+
+ /**
+ * Returns the tag display name
+ *
+ * @return string tag display name
+ *
+ * @since 9.0.0
+ */
+ public function getName();
+
+ /**
+ * Returns whether the tag is visible for regular users
+ *
+ * @return bool true if visible, false otherwise
+ *
+ * @since 9.0.0
+ */
+ public function isUserVisible();
+
+ /**
+ * Returns whether the tag can be assigned to objects by regular users
+ *
+ * @return bool true if assignable, false otherwise
+ *
+ * @since 9.0.0
+ */
+ public function isUserAssignable();
+
+}
+
diff --git a/lib/public/systemtag/isystemtagmanager.php b/lib/public/systemtag/isystemtagmanager.php
new file mode 100644
index 00000000000..983bfd636ce
--- /dev/null
+++ b/lib/public/systemtag/isystemtagmanager.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SystemTag;
+
+/**
+ * Public interface to access and manage system-wide tags.
+ *
+ * @since 9.0.0
+ */
+interface ISystemTagManager {
+
+ /**
+ * Returns the tag objects matching the given tag ids.
+ *
+ * @param array|string $tagIds id or array of unique ids of the tag to retrieve
+ *
+ * @return \OCP\SystemTag\ISystemTag[] array of system tags with tag id as key
+ *
+ * @throws \InvalidArgumentException if at least one given tag ids is invalid (string instead of integer, etc.)
+ * @throws \OCP\SystemTag\TagNotFoundException if at least one given tag ids did no exist
+ * The message contains a json_encoded array of the ids that could not be found
+ *
+ * @since 9.0.0
+ */
+ public function getTagsByIds($tagIds);
+
+ /**
+ * Returns the tag object matching the given attributes.
+ *
+ * @param string $tagName tag name
+ * @param bool $userVisible whether the tag is visible by users
+ * @param bool $userAssignable whether the tag is assignable by users
+ *
+ * @return \OCP\SystemTag\ISystemTag system tag
+ *
+ * @throws \OCP\SystemTag\TagNotFoundException if tag does not exist
+ *
+ * @since 9.0.0
+ */
+ public function getTag($tagName, $userVisible, $userAssignable);
+
+ /**
+ * Creates the tag object using the given attributes.
+ *
+ * @param string $tagName tag name
+ * @param bool $userVisible whether the tag is visible by users
+ * @param bool $userAssignable whether the tag is assignable by users
+ *
+ * @return \OCP\SystemTag\ISystemTag system tag
+ *
+ * @throws \OCP\SystemTag\TagAlreadyExistsException if tag already exists
+ *
+ * @since 9.0.0
+ */
+ public function createTag($tagName, $userVisible, $userAssignable);
+
+ /**
+ * Returns all known tags, optionally filtered by visibility.
+ *
+ * @param bool|null $visibilityFilter filter by visibility if non-null
+ * @param string $nameSearchPattern optional search pattern for the tag name
+ *
+ * @return \OCP\SystemTag\ISystemTag[] array of system tags or empty array if none found
+ *
+ * @since 9.0.0
+ */
+ public function getAllTags($visibilityFilter = null, $nameSearchPattern = null);
+
+ /**
+ * Updates the given tag
+ *
+ * @param string $tagId tag id
+ * @param string $newName the new tag name
+ * @param bool $userVisible whether the tag is visible by users
+ * @param bool $userAssignable whether the tag is assignable by users
+ *
+ * @throws \OCP\SystemTag\TagNotFoundException if tag with the given id does not exist
+ * @throws \OCP\SystemTag\TagAlreadyExistsException if there is already another tag
+ * with the same attributes
+ *
+ * @since 9.0.0
+ */
+ public function updateTag($tagId, $newName, $userVisible, $userAssignable);
+
+ /**
+ * Delete the given tags from the database and all their relationships.
+ *
+ * @param string|array $tagIds array of tag ids
+ *
+ * @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist
+ *
+ * @since 9.0.0
+ */
+ public function deleteTags($tagIds);
+
+}
diff --git a/lib/public/systemtag/isystemtagmanagerfactory.php b/lib/public/systemtag/isystemtagmanagerfactory.php
new file mode 100644
index 00000000000..ad7467633b1
--- /dev/null
+++ b/lib/public/systemtag/isystemtagmanagerfactory.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\SystemTag;
+
+use OCP\IServerContainer;
+
+/**
+ * Interface ISystemTagManagerFactory
+ *
+ * Factory interface for system tag managers
+ *
+ * @package OCP\SystemTag
+ * @since 9.0.0
+ */
+interface ISystemTagManagerFactory {
+
+ /**
+ * Constructor for the system tag manager factory
+ *
+ * @param IServerContainer $serverContainer server container
+ * @since 9.0.0
+ */
+ public function __construct(IServerContainer $serverContainer);
+
+ /**
+ * creates and returns an instance of the system tag manager
+ *
+ * @return ISystemTagManager
+ * @since 9.0.0
+ */
+ public function getManager();
+
+ /**
+ * creates and returns an instance of the system tag object
+ * mapper
+ *
+ * @return ISystemTagObjectMapper
+ * @since 9.0.0
+ */
+ public function getObjectMapper();
+}
diff --git a/lib/public/systemtag/isystemtagobjectmapper.php b/lib/public/systemtag/isystemtagobjectmapper.php
new file mode 100644
index 00000000000..8db5cdd31aa
--- /dev/null
+++ b/lib/public/systemtag/isystemtagobjectmapper.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SystemTag;
+
+/**
+ * Public interface to access and manage system-wide tags.
+ *
+ * @since 9.0.0
+ */
+interface ISystemTagObjectMapper {
+
+ /**
+ * Get a list of tag ids for the given object ids.
+ *
+ * This returns an array that maps object id to tag ids
+ * [
+ * 1 => array('id1', 'id2'),
+ * 2 => array('id3', 'id2'),
+ * 3 => array('id5'),
+ * 4 => array()
+ * ]
+ *
+ * Untagged objects will have an empty array associated.
+ *
+ * @param string|array $objIds object ids
+ * @param string $objectType object type
+ *
+ * @return array with object id as key and an array
+ * of tag ids as value
+ *
+ * @since 9.0.0
+ */
+ public function getTagIdsForObjects($objIds, $objectType);
+
+ /**
+ * Get a list of objects tagged with $tagIds.
+ *
+ * @param string|array $tagIds Tag id or array of tag ids.
+ * @param string $objectType object type
+ *
+ * @return string[] array of object ids or empty array if none found
+ *
+ * @throws \OCP\SystemTag\TagNotFoundException if at least one of the
+ * given tags does not exist
+ *
+ * @since 9.0.0
+ */
+ public function getObjectIdsForTags($tagIds, $objectType);
+
+ /**
+ * Assign the given tags to the given object.
+ *
+ * If at least one of the given tag ids doesn't exist, none of the tags
+ * will be assigned.
+ *
+ * If the relationship already existed, fail silently.
+ *
+ * @param string $objId object id
+ * @param string $objectType object type
+ * @param string|array $tagIds tag id or array of tag ids to assign
+ *
+ * @throws \OCP\SystemTag\TagNotFoundException if at least one of the
+ * given tags does not exist
+ *
+ * @since 9.0.0
+ */
+ public function assignTags($objId, $objectType, $tagIds);
+
+ /**
+ * Unassign the given tags from the given object.
+ *
+ * If at least one of the given tag ids doesn't exist, none of the tags
+ * will be unassigned.
+ *
+ * If the relationship did not exist in the first place, fail silently.
+ *
+ * @param string $objId object id
+ * @param string $objectType object type
+ * @param string|array $tagIds tag id or array of tag ids to unassign
+ *
+ * @throws \OCP\SystemTag\TagNotFoundException if at least one of the
+ * given tags does not exist
+ *
+ * @since 9.0.0
+ */
+ public function unassignTags($objId, $objectType, $tagIds);
+
+ /**
+ * Checks whether the given objects have the given tag.
+ *
+ * @param string|array $objIds object ids
+ * @param string $objectType object type
+ * @param string $tagId tag id to check
+ * @param bool $all true to check that ALL objects have the tag assigned,
+ * false to check that at least ONE object has the tag.
+ *
+ * @return bool true if the condition set by $all is matched, false
+ * otherwise
+ *
+ * @throws \OCP\SystemTag\TagNotFoundException if the tag does not exist
+ *
+ * @since 9.0.0
+ */
+ public function haveTag($objIds, $objectType, $tagId, $all = true);
+
+}
diff --git a/lib/public/systemtag/managerevent.php b/lib/public/systemtag/managerevent.php
new file mode 100644
index 00000000000..a0429fc9f67
--- /dev/null
+++ b/lib/public/systemtag/managerevent.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SystemTag;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Class ManagerEvent
+ *
+ * @package OCP\SystemTag
+ * @since 9.0.0
+ */
+class ManagerEvent extends Event {
+
+ const EVENT_CREATE = 'OCP\SystemTag\ISystemTagManager::createTag';
+ const EVENT_UPDATE = 'OCP\SystemTag\ISystemTagManager::updateTag';
+ const EVENT_DELETE = 'OCP\SystemTag\ISystemTagManager::deleteTag';
+
+ /** @var string */
+ protected $event;
+ /** @var ISystemTag */
+ protected $tag;
+ /** @var ISystemTag */
+ protected $beforeTag;
+
+ /**
+ * DispatcherEvent constructor.
+ *
+ * @param string $event
+ * @param ISystemTag $tag
+ * @param ISystemTag $beforeTag
+ * @since 9.0.0
+ */
+ public function __construct($event, ISystemTag $tag, ISystemTag $beforeTag = null) {
+ $this->event = $event;
+ $this->tag = $tag;
+ $this->beforeTag = $beforeTag;
+ }
+
+ /**
+ * @return string
+ * @since 9.0.0
+ */
+ public function getEvent() {
+ return $this->event;
+ }
+
+ /**
+ * @return ISystemTag
+ * @since 9.0.0
+ */
+ public function getTag() {
+ return $this->tag;
+ }
+
+ /**
+ * @return ISystemTag
+ * @since 9.0.0
+ */
+ public function getTagBefore() {
+ if ($this->event !== self::EVENT_UPDATE) {
+ throw new \BadMethodCallException('getTagBefore is only available on the update Event');
+ }
+ return $this->beforeTag;
+ }
+}
diff --git a/lib/public/systemtag/mapperevent.php b/lib/public/systemtag/mapperevent.php
new file mode 100644
index 00000000000..e05a5ce09c8
--- /dev/null
+++ b/lib/public/systemtag/mapperevent.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SystemTag;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Class MapperEvent
+ *
+ * @package OCP\SystemTag
+ * @since 9.0.0
+ */
+class MapperEvent extends Event {
+
+ const EVENT_ASSIGN = 'OCP\SystemTag\ISystemTagObjectMapper::assignTags';
+ const EVENT_UNASSIGN = 'OCP\SystemTag\ISystemTagObjectMapper::unassignTags';
+
+ /** @var string */
+ protected $event;
+ /** @var string */
+ protected $objectType;
+ /** @var string */
+ protected $objectId;
+ /** @var int[] */
+ protected $tags;
+
+ /**
+ * DispatcherEvent constructor.
+ *
+ * @param string $event
+ * @param string $objectType
+ * @param string $objectId
+ * @param int[] $tags
+ * @since 9.0.0
+ */
+ public function __construct($event, $objectType, $objectId, array $tags) {
+ $this->event = $event;
+ $this->objectType = $objectType;
+ $this->objectId = $objectId;
+ $this->tags = $tags;
+ }
+
+ /**
+ * @return string
+ * @since 9.0.0
+ */
+ public function getEvent() {
+ return $this->event;
+ }
+
+ /**
+ * @return string
+ * @since 9.0.0
+ */
+ public function getObjectType() {
+ return $this->objectType;
+ }
+
+ /**
+ * @return string
+ * @since 9.0.0
+ */
+ public function getObjectId() {
+ return $this->objectId;
+ }
+
+ /**
+ * @return int[]
+ * @since 9.0.0
+ */
+ public function getTags() {
+ return $this->tags;
+ }
+}
diff --git a/lib/public/systemtag/tagalreadyexistsexception.php b/lib/public/systemtag/tagalreadyexistsexception.php
new file mode 100644
index 00000000000..5c3d86ad642
--- /dev/null
+++ b/lib/public/systemtag/tagalreadyexistsexception.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SystemTag;
+
+/**
+ * Exception when a tag already exists.
+ *
+ * @since 9.0.0
+ */
+class TagAlreadyExistsException extends \RuntimeException {}
diff --git a/lib/public/systemtag/tagnotfoundexception.php b/lib/public/systemtag/tagnotfoundexception.php
new file mode 100644
index 00000000000..12feda8f58a
--- /dev/null
+++ b/lib/public/systemtag/tagnotfoundexception.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SystemTag;
+
+/**
+ * Exception when a tag was not found.
+ *
+ * @since 9.0.0
+ */
+class TagNotFoundException extends \RuntimeException {
+
+ /** @var string[] */
+ protected $tags;
+
+ /**
+ * TagNotFoundException constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param \Exception $previous
+ * @param string[] $tags
+ * @since 9.0.0
+ */
+ public function __construct($message = '', $code = 0, \Exception $previous = null, array $tags = []) {
+ parent::__construct($message, $code, $previous);
+ $this->tags = $tags;
+ }
+
+ /**
+ * @return string[]
+ * @since 9.0.0
+ */
+ public function getMissingTags() {
+ return $this->tags;
+ }
+}
diff --git a/lib/public/template.php b/lib/public/template.php
index b308240306d..7e46745c9d8 100644
--- a/lib/public/template.php
+++ b/lib/public/template.php
@@ -7,11 +7,11 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -45,7 +45,7 @@ namespace OCP;
* @param string $image
* @return string to the image
*
- * @see OC_Helper::imagePath
+ * @see \OCP\IURLGenerator::imagePath
* @deprecated 8.0.0 Use \OCP\Template::image_path() instead
*/
function image_path( $app, $image ) {
@@ -144,7 +144,7 @@ class Template extends \OC_Template {
/**
* Make OC_Helper::imagePath available as a simple function
*
- * @see OC_Helper::imagePath
+ * @see \OCP\IURLGenerator::imagePath
*
* @param string $app
* @param string $image
diff --git a/lib/public/user.php b/lib/public/user.php
index 23f77c0a35f..825e77aef6d 100644
--- a/lib/public/user.php
+++ b/lib/public/user.php
@@ -8,10 +8,10 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/lib/public/userinterface.php b/lib/public/userinterface.php
index cf91e519813..68831dcb503 100644
--- a/lib/public/userinterface.php
+++ b/lib/public/userinterface.php
@@ -4,7 +4,7 @@
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -32,9 +32,75 @@
namespace OCP;
/**
- * Interface UserInterface
+ * TODO actually this is a IUserBackend
*
* @package OCP
* @since 4.5.0
*/
-interface UserInterface extends \OC_User_Interface {}
+interface UserInterface {
+
+ /**
+ * Check if backend implements actions
+ * @param int $actions bitwise-or'ed actions
+ * @return boolean
+ *
+ * Returns the supported actions as int to be
+ * compared with \OC_User_Backend::CREATE_USER etc.
+ * @since 4.5.0
+ */
+ public function implementsActions($actions);
+
+ /**
+ * delete a user
+ * @param string $uid The username of the user to delete
+ * @return bool
+ * @since 4.5.0
+ */
+ public function deleteUser($uid);
+
+ /**
+ * Get a list of all users
+ *
+ * @param string $search
+ * @param null|int $limit
+ * @param null|int $offset
+ * @return string[] an array of all uids
+ * @since 4.5.0
+ */
+ public function getUsers($search = '', $limit = null, $offset = null);
+
+ /**
+ * check if a user exists
+ * @param string $uid the username
+ * @return boolean
+ * @since 4.5.0
+ */
+ public function userExists($uid);
+
+ /**
+ * get display name of the user
+ * @param string $uid user ID of the user
+ * @return string display name
+ * @since 4.5.0
+ */
+ public function getDisplayName($uid);
+
+ /**
+ * Get a list of all display names and user ids.
+ *
+ * @param string $search
+ * @param string|null $limit
+ * @param string|null $offset
+ * @return array an array of all displayNames (value) and the corresponding uids (key)
+ * @since 4.5.0
+ */
+ public function getDisplayNames($search = '', $limit = null, $offset = null);
+
+ /**
+ * Check if a user list is available or not
+ * @return boolean if users can be listed or not
+ * @since 4.5.0
+ */
+ public function hasUserListings();
+
+}
diff --git a/lib/public/util.php b/lib/public/util.php
index 76b61347d46..45df62ac735 100644
--- a/lib/public/util.php
+++ b/lib/public/util.php
@@ -6,7 +6,6 @@
* @author Frank Karlitschek <frank@owncloud.org>
* @author Georg Ehrke <georg@owncloud.com>
* @author Individual IT Services <info@individual-it.net>
- * @author itheiss <ingo.theiss@i-matrixx.de>
* @author Jens-Christian Fischer <jens-christian.fischer@switch.ch>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
@@ -16,14 +15,15 @@
* @author Pellaeon Lin <nfsmwlin@gmail.com>
* @author Randolph Carter <RandolphCarter@fantasymail.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Stefan Herbrechtsmeier <stefan@herbrechtsmeier.net>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -173,7 +173,11 @@ class Util {
* @since 7.0.0
*/
public static function isSharingDisabledForUser() {
- return \OC_Util::isSharingDisabledForUser();
+ return \OC_Util::isSharingDisabledForUser(
+ \OC::$server->getConfig(),
+ \OC::$server->getGroupManager(),
+ \OC::$server->getUserSession()->getUser()
+ );
}
/**
@@ -265,7 +269,10 @@ class Util {
* @since 4.0.0 - parameter $args was added in 4.5.0
*/
public static function linkToAbsolute( $app, $file, $args = array() ) {
- return(\OC_Helper::linkToAbsolute( $app, $file, $args ));
+ $urlGenerator = \OC::$server->getURLGenerator();
+ return $urlGenerator->getAbsoluteURL(
+ $urlGenerator->linkTo($app, $file, $args)
+ );
}
/**
@@ -275,7 +282,11 @@ class Util {
* @since 4.0.0
*/
public static function linkToRemote( $service ) {
- return(\OC_Helper::linkToRemote( $service ));
+ $urlGenerator = \OC::$server->getURLGenerator();
+ $remoteBase = $urlGenerator->linkTo('', 'remote.php') . '/' . $service;
+ return $urlGenerator->getAbsoluteURL(
+ $remoteBase . (($service[strlen($service) - 1] != '/') ? '/' : '')
+ );
}
/**
@@ -298,7 +309,7 @@ class Util {
* @since 5.0.0
*/
public static function linkToRoute( $route, $parameters = array() ) {
- return \OC_Helper::linkToRoute($route, $parameters);
+ return \OC::$server->getURLGenerator()->linkToRoute($route, $parameters);
}
/**
@@ -312,7 +323,7 @@ class Util {
* @since 4.0.0 - parameter $args was added in 4.5.0
*/
public static function linkTo( $app, $file, $args = array() ) {
- return(\OC_Helper::linkTo( $app, $file, $args ));
+ return \OC::$server->getURLGenerator()->linkTo($app, $file, $args);
}
/**
@@ -357,9 +368,10 @@ class Util {
* @since 5.0.0
*/
public static function getDefaultEmailAddress($user_part) {
- $user_part = \OC_Config::getValue('mail_from_address', $user_part);
+ $config = \OC::$server->getConfig();
+ $user_part = $config->getSystemValue('mail_from_address', $user_part);
$host_name = self::getServerHostName();
- $host_name = \OC_Config::getValue('mail_domain', $host_name);
+ $host_name = $config->getSystemValue('mail_domain', $host_name);
$defaultEmailAddress = $user_part.'@'.$host_name;
$mailer = \OC::$server->getMailer();
@@ -468,21 +480,33 @@ class Util {
}
/**
+ * Cached encrypted CSRF token. Some static unit-tests of ownCloud compare
+ * multiple OC_Template elements which invoke `callRegister`. If the value
+ * would not be cached these unit-tests would fail.
+ * @var string
+ */
+ private static $token = '';
+
+ /**
* Register an get/post call. This is important to prevent CSRF attacks
- * TODO: write example
* @since 4.5.0
*/
public static function callRegister() {
- return(\OC_Util::callRegister());
+ if(self::$token === '') {
+ self::$token = \OC::$server->getCsrfTokenManager()->getToken()->getEncryptedValue();
+ }
+ return self::$token;
}
/**
* Check an ajax get/post call if the request token is valid. exit if not.
- * Todo: Write howto
* @since 4.5.0
+ * @deprecated 9.0.0 Use annotations based on the app framework.
*/
public static function callCheck() {
- \OC_Util::callCheck();
+ if (!(\OC::$server->getRequest()->passesCSRFCheck())) {
+ exit();
+ }
}
/**
@@ -492,11 +516,11 @@ class Util {
* string or array of strings before displaying it on a web page.
*
* @param string|array $value
- * @return string|array an array of sanitized strings or a single sinitized string, depends on the input parameter.
+ * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
* @since 4.5.0
*/
- public static function sanitizeHTML( $value ) {
- return(\OC_Util::sanitizeHTML($value));
+ public static function sanitizeHTML($value) {
+ return \OC_Util::sanitizeHTML($value);
}
/**
@@ -540,7 +564,7 @@ class Util {
* @deprecated 8.2.0 Use substr_replace() instead.
*/
public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') {
- return(\OC_Helper::mb_substr_replace($string, $replacement, $start, $length, $encoding));
+ return substr_replace($string, $replacement, $start, $length);
}
/**
@@ -556,7 +580,7 @@ class Util {
* @deprecated 8.2.0 Use str_replace() instead.
*/
public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) {
- return(\OC_Helper::mb_str_replace($search, $replace, $subject, $encoding, $count));
+ return str_replace($search, $replace, $subject, $count);
}
/**
@@ -623,7 +647,7 @@ class Util {
* @since 7.0.0
*/
public static function generateRandomBytes($length = 30) {
- return \OC_Util::generateRandomBytes($length);
+ return \OC::$server->getSecureRandom()->generate($length, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
}
/**
diff --git a/lib/repair/repairconfig.php b/lib/repair/repairconfig.php
deleted file mode 100644
index 66fdd47269e..00000000000
--- a/lib/repair/repairconfig.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/**
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OC\Repair;
-
-use OC\Hooks\BasicEmitter;
-use OC\RepairStep;
-use Sabre\DAV\Exception;
-
-/**
- * Class RepairConfig
- *
- * @package OC\Repair
- */
-class RepairConfig extends BasicEmitter implements RepairStep {
-
- /**
- * @return string
- */
- public function getName() {
- return 'Repair config';
- }
-
- /**
- * Updates the configuration after running an update
- */
- public function run() {
- $this->addSecret();
- $this->removePortsFromTrustedDomains();
- }
-
- /**
- * Adds a secret to config.php
- */
- private function addSecret() {
- if(\OC::$server->getConfig()->getSystemValue('secret', null) === null) {
- $secret = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(48);
- \OC::$server->getConfig()->setSystemValue('secret', $secret);
- }
- }
-
-
- /**
- * Remove ports from existing trusted domains in config.php
- */
- private function removePortsFromTrustedDomains() {
- $trustedDomains = \OC::$server->getConfig()->getSystemValue('trusted_domains', array());
- $newTrustedDomains = array();
- foreach($trustedDomains as $domain) {
- $pos = strrpos($domain, ':');
- if ($pos !== false) {
- $port = substr($domain, $pos + 1);
- if (is_numeric($port)) {
- $domain = substr($domain, 0, $pos);
- }
- }
- $newTrustedDomains[] = $domain;
- }
- \OC::$server->getConfig()->setSystemValue('trusted_domains', $newTrustedDomains);
- }
-}
diff --git a/ocs/providers.php b/ocs/providers.php
index ce818a0cb6a..7a94f65975a 100644
--- a/ocs/providers.php
+++ b/ocs/providers.php
@@ -3,10 +3,9 @@
* @author Frank Karlitschek <frank@owncloud.org>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Stefan Herbrechtsmeier <stefan@herbrechtsmeier.net>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,22 +26,33 @@ require_once '../lib/base.php';
header('Content-type: application/xml');
-$url=OCP\Util::getServerProtocol().'://'.substr(OCP\Util::getServerHost().OCP\Util::getRequestUri(), 0, -17).'ocs/v1.php/';
+$request = \OC::$server->getRequest();
-echo('
-<providers>
-<provider>
- <id>ownCloud</id>
- <location>'.$url.'</location>
- <name>ownCloud</name>
- <icon></icon>
- <termsofuse></termsofuse>
- <register></register>
- <services>
- <config ocsversion="1.7" />
- <activity ocsversion="1.7" />
- <cloud ocsversion="1.7" />
- </services>
-</provider>
-</providers>
-');
+$url = $request->getServerProtocol() . '://' . substr($request->getServerHost() . $request->getRequestUri(), 0, -17).'ocs/v1.php/';
+
+$writer = new XMLWriter();
+$writer->openURI('php://output');
+$writer->startDocument('1.0','UTF-8');
+$writer->setIndent(4);
+$writer->startElement('providers');
+$writer->startElement('provider');
+$writer->writeElement('id', 'ownCloud');
+$writer->writeElement('location', $url);
+$writer->writeElement('name', 'ownCloud');
+$writer->writeElement('icon', '');
+$writer->writeElement('termsofuse', '');
+$writer->writeElement('register', '');
+$writer->startElement('services');
+$writer->startElement('config');
+$writer->writeAttribute('ocsversion', '1.7');
+$writer->endElement();
+$writer->startElement('activity');
+$writer->writeAttribute('ocsversion', '1.7');
+$writer->endElement();
+$writer->startElement('cloud');
+$writer->writeAttribute('ocsversion', '1.7');
+$writer->endElement();
+$writer->endElement();
+$writer->endElement();
+$writer->endDocument();
+$writer->flush();
diff --git a/ocs/routes.php b/ocs/routes.php
index 4aaa1434b8b..b99aa5c7597 100644
--- a/ocs/routes.php
+++ b/ocs/routes.php
@@ -4,11 +4,11 @@
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/ocs/v1.php b/ocs/v1.php
index 0aaa5d228da..39a8f4e468f 100644
--- a/ocs/v1.php
+++ b/ocs/v1.php
@@ -8,7 +8,7 @@
* @author Tom Needham <tom@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -46,7 +46,7 @@ try {
OC_App::loadApps();
// force language as given in the http request
- \OC_L10N::setLanguageFromRequest();
+ \OC::$server->getL10NFactory()->setLanguageFromRequest();
OC::$server->getRouter()->match('/ocs'.\OC::$server->getRequest()->getRawPathInfo());
} catch (ResourceNotFoundException $e) {
diff --git a/ocs/v2.php b/ocs/v2.php
index b2e3b259727..a9fffe529b0 100644
--- a/ocs/v2.php
+++ b/ocs/v2.php
@@ -2,7 +2,7 @@
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/public.php b/public.php
index aac3c3e517b..65257f1a46e 100644
--- a/public.php
+++ b/public.php
@@ -8,7 +8,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/remote.php b/remote.php
index 0282877ca2a..26203e2df8a 100644
--- a/remote.php
+++ b/remote.php
@@ -5,11 +5,11 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -109,7 +109,7 @@ try {
}
// force language as given in the http request
- \OC_L10N::setLanguageFromRequest();
+ \OC::$server->getL10NFactory()->setLanguageFromRequest();
$file=ltrim($file, '/');
diff --git a/resources/codesigning/core.crt b/resources/codesigning/core.crt
new file mode 100644
index 00000000000..62f87c9d30c
--- /dev/null
+++ b/resources/codesigning/core.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID8TCCAdkCAhAAMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNVBAYTAlVTMQ8wDQYD
+VQQIDAZCb3N0b24xFjAUBgNVBAoMDW93bkNsb3VkIEluYy4xNTAzBgNVBAMMLG93
+bkNsb3VkIENvZGUgU2lnbmluZyBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MB4XDTE2
+MDIwMzE3NTE0OVoXDTI2MDEzMTE3NTE0OVowDzENMAsGA1UEAwwEY29yZTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPHdSljnHI+ueQd27UyWPO9n4Lqt
+bK0kdekiC3si7Mee7uXXJaGuqXJozHEZYB1LIFLdCU/itCxEk9hyLcyNzeT+nRT/
+zDuOYdbLgCj7/A5bX+u3jc29UlCYybSFchfMdvn7a0njCna4dE+73b4yEj16tS2h
+S1EUygSzgicWlJqMD3Z9Qc+zLEpdhq9oDdDB8HURi2NW4KzIraVncSH+zF1QduOh
+nERDnF8x48D3FLdTxGA0W/Kg4gYsq4NRvU6g3DJNdp4YfqRSFMmLFDCgzDuhan7D
+wgRlI9NAeHbnyoUPtrDBUceI7shIbC/i87xk9ptqV0AyFonkJtK6lWwZjNkCAwEA
+ATANBgkqhkiG9w0BAQsFAAOCAgEAAMgymqZE1YaHYlRGwvTE7gGDY3gmFOMaxQL4
+E5m0CnkBz4BdIPRsQFFdOv3l/MIWkw5ED3vUB925VpQZYFSiEuv5NbnlPaHZlIMI
+n8AV/sTP5jue3LhtAN4EM63xNBhudAT6wVsvGwOuQOx9Xv+ptO8Po7sTuNYP0CMH
+EOQN+/q8tYlSm2VW+dAlaJ+zVZwZldhVjL+lSH4E9ktWn3PmgNQeKfcnJISUbus6
+ZtsYDF/X96/Z2ZQvMXOKksgvU6XlvIxllcyebC9Bxe/h0D63GCO2tqN5CWQzIIqn
+apUynPX8BlLaaExqYGERwlUi/yOGaUVPUjEPVehviOQYgAqxlrkJk1dWeCrwUori
+CXpi+IUYkidfgiJ9F88M3ElpwqIaXp7G3/4oHBuE2u6M+L+1/vqPJeTCAWUxxpJE
+yYmM+db6D4TySFpQPENNzPS8bpR6T8w2hRumkldC42HrnyJJbpjOieTXhXzjdPvZ
+IEP9JGtkhB2du6nBF2MNAq2TqRXpcfQrQEbnQ13aV9bl+roTwwO+SOWK/wgvdOMI
+STQ0Xk0sTGlmQjPYPkibVceaWMR3sX4cNt5c33YhJys5jxHoAh42km4nN9tfykR5
+crl5lBlKjXh2GP0+omSO3x1jX4+iQPCW2TWoyKkUdLu/hGHG2w8RrTeme+kATECH
+YSu356M=
+-----END CERTIFICATE-----
diff --git a/resources/codesigning/root.crt b/resources/codesigning/root.crt
new file mode 100644
index 00000000000..cbd82898bab
--- /dev/null
+++ b/resources/codesigning/root.crt
@@ -0,0 +1,66 @@
+-----BEGIN CERTIFICATE-----
+MIIFtDCCA5ygAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx
+DzANBgNVBAgMBkJvc3RvbjEWMBQGA1UECgwNb3duQ2xvdWQgSW5jLjEtMCsGA1UE
+Awwkb3duQ2xvdWQgQ29kZSBTaWduaW5nIFJvb3QgQXV0aG9yaXR5MB4XDTE2MDIw
+MzE3NDMyNVoXDTI2MDEzMTE3NDMyNVowbTELMAkGA1UEBhMCVVMxDzANBgNVBAgM
+BkJvc3RvbjEWMBQGA1UECgwNb3duQ2xvdWQgSW5jLjE1MDMGA1UEAwwsb3duQ2xv
+dWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBBdXRob3JpdHkwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQDKMul4pWev6vtgzB73CLQPMy8nDZGbvqII
+IgukQluMeLCW0P09I+J/mCiDd99mQTtWO+/LcpOChHYJ59qQz+g9TzKlVSuFDg47
+pc+jUvTLGGEDf9cAWtzsXYXlb9z7sTln/8JAvy8ghmaR/4JWU4hM/nmgDCpeXLLJ
+NFrxKDbzPLYj53iHN+XyE9GT6sDYoQd1BIWhTsMdvMqg870Jw2yN4hKw3V7/KoI/
+Z5CAA9dP4tAmltBpMz79dmLCciqXOD8mWEWl2tSZU+/WVyPxiE19IHoJETOhSg4c
+eud4DDdFt9Ohm4owvpxxRDbvV+Ic6sWb1gJBrM7/XJDmaUObpowjx8Daof1MuoHs
+FKh6/Y7RBdVlrp/ig3htxfm9BBMqnXIxgFWDiSbjCMk0Ygvx49gKMnVoRhZ/7pla
+j5nTRdbhsjS50E9zfc53EltM27YSwNZu62QKsU4yumg8UOhOYPRLHcySvNyyMZXS
+o+Kst27oGSgurHytFS7FVG1M3UUn67zkMpnnMYhfx8dz7+tupY9e0l0kDciwvNAO
+YrnvHoEiIbJmoyYOhL2j9WErUhAb3JKTSdYC0MmjaZZPv0HwCemx+rnApcoszmFG
+woZTRAa6Q64WGxlmFq0vsgmcTNsTzlYY20Kv+ZpZOiVYonyHFkorKWdsXKZQcnYq
+dcMqYxQE6wIDAQABo2YwZDAdBgNVHQ4EFgQUfZoNPRneQ1pk9SZT9A2lpG4Hw7Mw
+HwYDVR0jBBgwFoAUcZdiBiGr+Y+OH2DrlNwK03zWH+YwEgYDVR0TAQH/BAgwBgEB
+/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAA2hoAEdbdM9
++ZA/q7UppF4BiKrSQNAQHLDwodutRY+gBYQsWpo8wLqdLvRVhlwDn3KmJEMfaDQm
+5YM+/snBkew9olCIyYw+t7xYtNhoW1et/nNNDL+Qq7uyH6g+uOMp4m3c+BMv4x5H
+EP3z7PY1qrPOVvzZu8o2iL8qpC0sXTKZy+xG/9VTYGnxCcG+V/Ua5aHOyetUttoN
+bxEcEQHHe07V+JlCPuI53hPsiGgzHv+nz/1sJV95mn9w88SHY0JO9bHp9w+mq92K
+r0Nv6Wctf7vNVmIOdRFHWOFie4+D3TpBSnB5PPQRbtf6IVEhjmcnWYBWcRGhH6cR
+4dqpuqzwVFopIFLYMeaeKGu8wZHi2YRrkFcrnqqmFI9RtBbt3eyfUQcKH7b9P4Ri
+qamb/h9sVjDM4wSQ6n+Qa2dgV28O0il35roa3qwvqySgn1wXS5CsAaeB1VWAS6/S
+v1WFt93n9LrraV4EUuu1BGXp525aVn6v+B71zN4JzYnHVE4yAb0EdOpKrlfmCCm/
+9Z90+BF2uK3QnpkyrH+LEOQoHrlAt80RZYd2Tl/K1WWNrPUlnCGXdxjVYakVRnfy
+Ud0KV4RsD93mNw/t2gU5U+SyYWU2fTJUE9qdJ4Ndw7B2DZ/5dcsu0rDV4sXkUoDY
++Dr25NoOcuqjCWRw2T3SBPSXBxjlhRTQ
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFsDCCA5igAwIBAgIJALFuk51OGp2KMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNV
+BAYTAlVTMQ8wDQYDVQQIDAZCb3N0b24xFjAUBgNVBAoMDW93bkNsb3VkIEluYy4x
+LTArBgNVBAMMJG93bkNsb3VkIENvZGUgU2lnbmluZyBSb290IEF1dGhvcml0eTAe
+Fw0xNjAyMDMxNzM5NThaFw0yNjAxMzExNzM5NThaMGUxCzAJBgNVBAYTAlVTMQ8w
+DQYDVQQIDAZCb3N0b24xFjAUBgNVBAoMDW93bkNsb3VkIEluYy4xLTArBgNVBAMM
+JG93bkNsb3VkIENvZGUgU2lnbmluZyBSb290IEF1dGhvcml0eTCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAJmTnGtGaB0cDtQPxWr2r5FyXFzJ6GIkm4Lb
+7iY/DYpIEarbRFwqDCDZ00V+PWsTBBF6qXW5W7eZ+fOOdIEGoNaDuGtIlGVjj3Dz
+TZtmcFg0euimfLNYVvYZlPPh4kS3zDRZs30AgAdgq4RHWC4qjElWcVKTwERNQ2ln
+gRFRQEv+i2DI7sEK9ZpK7B1SfJ1o1fm/kPL7bVfiYda+QKp0vOxBecDnGV+rfz4t
+DT6mBOgwAiZnwojuiigfUJxSisv3roWri+0O+0TiXglV+oUtkIRrs0etkQGWAlgn
+H4CC+sZ5N2TiGPH1hksLkXP4mymlio8/x7ax0WfcxeTZu3ok9eK5fwIQVWam6dd9
+klCqZVttKodZYspvdFfwqMlf4lPEIY+r2PIdGjUhKu4FsDhORaGj8WMYRJUR44ls
+/r2ktCB/TOsh8DW2Pi9HAgxI4mrdmvL0WMSOBFZRcSC/nTz977oi1iiB2T+s7V0Z
+Y0AHMQYiIn83MFB7rb+mVlEoLID/evVSTfUaUaO8DqcfeQN/OFM/zcJY9YHv8AlJ
+3b8CPdeX9edMnyZWNdrhOSawjAbOBIna3o66RXdeC3oWg7FuckJmy7JLtRCJ2Owu
+losRAxe0z5mQmjFzMczxCYJQ4A+4U5UZwbd/MQJg508StcOumroYqruDic/Wbc3C
+v6DupG8dAgMBAAGjYzBhMB0GA1UdDgQWBBRxl2IGIav5j44fYOuU3ArTfNYf5jAf
+BgNVHSMEGDAWgBRxl2IGIav5j44fYOuU3ArTfNYf5jAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAR6IZBOBw3KzRxvUP
++46RZYayMrdLyAgMzbDvQe7WCaeuA2UoPVL8jN7X2Lvw12Mz84+EKs1voR0OBxlY
+6muuyl0SETa2k4UtklVscMvcokG+m5aVNJ7/HHGFmKsTyJDMxSzDA/r3KRPXZOwV
+CLUVTkr5fQbIaVljA89U2p3pN/X7gNq89xi/XiszNCEIvvSscRmBGlRmx4XbjXHK
+XKO74+HiM/ahqUI792ae97jlsy9jG4OIelse3+e1KBWNsGtU90asnUHgyMXVL8gp
+ocznGvWceAhkcogUCUCXq1Rh/mKcGQdi2z0g/X+MGzfA9Ij4NQZLnNPh2UjgxCtG
+KWPUzs0t/xoCtJh1WpwqTrOUcYqFAaBa282sD/O8tX4t076aGKdbhfo6tvaOFwDU
+iRPgdMol++BFnfCld53Yivg2+S6+xo1wzuPkNjVFXHjx9vMyiov/HHKqJoBsuCwU
+7VegzM/6Cvh32lSZfUHsfynCab/7vv923KyaANWxb0QsHZSSt+mmOK3ZmC96vCEa
+55IGNckOvOGW9yCIz3Q0kEj2hoJs1bw0SkwGWs7N1TkugQjM/S7/Im1LJUxdtqQK
+Zjn+8U6U3TR1aKLYEdqHCGcVoRXKDG/S40FHxyeV/9buTI7SSvhzZfj+qasmJe1L
+Kd08UdS/im8RwbVSS1mih5hbAHg=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/resources/config/ca-bundle.crt b/resources/config/ca-bundle.crt
index 21e90911fd3..c7d2d2c997f 100644
--- a/resources/config/ca-bundle.crt
+++ b/resources/config/ca-bundle.crt
@@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Wed Oct 28 22:42:42 2015
+## Certificate data from Mozilla as of: Fri Jan 22 20:39:57 2016
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@@ -14,30 +14,10 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.25.
-## SHA1: 6d7d2f0a4fae587e7431be191a081ac1257d300a
+## SHA1: 0ab47e2f41518f8d223eab517cb799e5b071231e
##
-Equifax Secure CA
-=================
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE
-ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
-MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT
-B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB
-nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR
-fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW
-8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG
-A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE
-CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG
-A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS
-spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB
-Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961
-zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB
-BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
-70+sB3c4
------END CERTIFICATE-----
-
GlobalSign Root CA
==================
-----BEGIN CERTIFICATE-----
@@ -105,30 +85,6 @@ xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa
t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
-----END CERTIFICATE-----
-Verisign Class 4 Public Primary Certification Authority - G3
-============================================================
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
-UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
-cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
-IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
-CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
-dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
-cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg
-Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS
-tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM
-8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW
-Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX
-Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
-j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt
-mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
-fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd
-RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG
-UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
------END CERTIFICATE-----
-
Entrust.net Premium 2048 Secure Server CA
=========================================
-----BEGIN CERTIFICATE-----
@@ -695,31 +651,6 @@ nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
-----END CERTIFICATE-----
-UTN DATACorp SGC Root CA
-========================
------BEGIN CERTIFICATE-----
-MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE
-BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
-IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ
-BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa
-MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w
-HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy
-dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys
-raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo
-wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA
-9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv
-33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud
-DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9
-BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD
-LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3
-DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
-Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0
-I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx
-EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP
-DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI
------END CERTIFICATE-----
-
UTN USERFirst Hardware Root CA
==============================
-----BEGIN CERTIFICATE-----
@@ -1142,31 +1073,6 @@ vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3
oKfN5XozNmr6mis=
-----END CERTIFICATE-----
-TURKTRUST Certificate Services Provider Root 2
-==============================================
------BEGIN CERTIFICATE-----
-MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF
-bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
-MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
-QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN
-MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr
-dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G
-A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls
-acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe
-LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI
-x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g
-QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr
-5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB
-AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G
-A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt
-Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4
-Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+
-hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P
-9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5
-UrbnBEI=
------END CERTIFICATE-----
-
SwissSign Gold CA - G2
======================
-----BEGIN CERTIFICATE-----
@@ -2520,29 +2426,6 @@ iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt
+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
-----END CERTIFICATE-----
-A-Trust-nQual-03
-================
------BEGIN CERTIFICATE-----
-MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE
-Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy
-a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R
-dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw
-RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0
-ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1
-c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA
-zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n
-yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE
-SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4
-iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V
-cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV
-eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40
-ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr
-sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd
-JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS
-mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6
-ahq97BvIxYSazQ==
------END CERTIFICATE-----
-
TWCA Root Certification Authority
=================================
-----BEGIN CERTIFICATE-----
@@ -3950,3 +3833,61 @@ I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM
cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr
hkIGuUE=
-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GB CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG
+EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
+ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw
+MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD
+VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds
+b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX
+scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP
+rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk
+9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o
+Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg
+GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
+hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD
+dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0
+VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui
+HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
+Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
+-----END CERTIFICATE-----
+
+Certification Authority of WoSign G2
+====================================
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQG
+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNVBAMTJENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgx
+CzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPXJYY1kBai
+XW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgOgHzKtB0TiGsOqCR3A9Du
+W/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg9
+5k4ot+vElbGs/V6r+kHLXZ1L3PR8du9nfwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BK
+v0mUYQs4kI9dJGwlezt52eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJKoZI
+hvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8fHulwqZm46qwtyeY
+P0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G3CE4Q3RM+zD4F3LBMvzIkRfEzFg3
+TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yySrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu
++sif/a+RZQp4OBXllxcU3fngLDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS+
+7Q9LGOHSJDy7XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg=
+-----END CERTIFICATE-----
+
+CA WoSign ECC Root
+==================
+-----BEGIN CERTIFICATE-----
+MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQswCQYDVQQGEwJD
+TjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMTEkNBIFdvU2lnbiBFQ0MgUm9v
+dDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQK
+ExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZI
+zj0CAQYFK4EEACIDYgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiU
+t5v8KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES1ns2o0Iw
+QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqv3VWqP2h4syhf3R
+MluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0
+Daupn75OcsqF1NnstTJFGG+rrQIwfcf3aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYu
+a/GRspBl9JrmkO5K
+-----END CERTIFICATE-----
diff --git a/resources/config/mimetypealiases.dist.json b/resources/config/mimetypealiases.dist.json
index ed471f228e2..545d4b0c399 100644
--- a/resources/config/mimetypealiases.dist.json
+++ b/resources/config/mimetypealiases.dist.json
@@ -17,12 +17,14 @@
"application/json": "text/code",
"application/msaccess": "file",
"application/msexcel": "x-office/spreadsheet",
+ "application/msonenote": "x-office/document",
"application/mspowerpoint": "x-office/presentation",
"application/msword": "x-office/document",
"application/octet-stream": "file",
"application/postscript": "image",
"application/rss+xml": "application/xml",
"application/vnd.android.package-archive": "package/x-generic",
+ "application/vnd.lotus-wordpro": "x-office/document",
"application/vnd.ms-excel": "x-office/spreadsheet",
"application/vnd.ms-excel.addin.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-excel.sheet.binary.macroEnabled.12": "x-office/spreadsheet",
@@ -51,6 +53,8 @@
"application/vnd.openxmlformats-officedocument.spreadsheetml.template": "x-office/spreadsheet",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "x-office/document",
"application/vnd.openxmlformats-officedocument.wordprocessingml.template": "x-office/document",
+ "application/vnd.visio": "x-office/document",
+ "application/vnd.wordperfect": "x-office/document",
"application/x-7z-compressed": "package/x-generic",
"application/x-cbr": "text",
"application/x-compressed": "package/x-generic",
diff --git a/resources/config/mimetypemapping.dist.json b/resources/config/mimetypemapping.dist.json
index e26ec7038b1..d08a46bb017 100644
--- a/resources/config/mimetypemapping.dist.json
+++ b/resources/config/mimetypemapping.dist.json
@@ -76,6 +76,7 @@
"key": ["application/x-iwork-keynote-sffkey"],
"keynote": ["application/x-iwork-keynote-sffkey"],
"kra": ["application/x-krita"],
+ "lwp": ["application/vnd.lotus-wordpro"],
"m2t": ["video/mp2t"],
"m4v": ["video/mp4"],
"markdown": ["text/markdown"],
@@ -106,6 +107,7 @@
"oga": ["audio/ogg"],
"ogg": ["audio/ogg"],
"ogv": ["video/ogg"],
+ "one": ["application/msonenote"],
"opus": ["audio/ogg"],
"orf": ["image/x-dcraw"],
"otf": ["application/font-sfnt"],
@@ -154,9 +156,11 @@
"vcard": ["text/vcard"],
"vcf": ["text/vcard"],
"vob": ["video/dvd"],
+ "vsd": ["application/vnd.visio"],
"wav": ["audio/wav"],
"webm": ["video/webm"],
"woff": ["application/font-woff"],
+ "wpd": ["application/vnd.wordperfect"],
"wmv": ["video/x-ms-wmv"],
"xcf": ["application/x-gimp"],
"xla": ["application/vnd.ms-excel"],
diff --git a/settings/admin.php b/settings/admin.php
index bccb1171743..2364fb3aae0 100644
--- a/settings/admin.php
+++ b/settings/admin.php
@@ -1,6 +1,5 @@
<?php
/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
* @author Frank Karlitschek <frank@owncloud.org>
@@ -13,7 +12,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -33,11 +32,15 @@
use OC\Lock\NoopLockingProvider;
OC_Util::checkAdminUser();
-OC_App::setActiveNavigationEntry("admin");
+\OC::$server->getNavigationManager()->setActiveEntry("admin");
$template = new OC_Template('settings', 'admin', 'user');
$l = \OC::$server->getL10N('settings');
+OC_Util::addScript('settings', 'certificates');
+OC_Util::addScript('files', 'jquery.iframe-transport');
+OC_Util::addScript('files', 'jquery.fileupload');
+
$showLog = (\OC::$server->getConfig()->getSystemValue('log_type', 'owncloud') === 'owncloud');
$numEntriesToLoad = 3;
$entries = OC_Log_Owncloud::getEntries($numEntriesToLoad + 1);
@@ -52,6 +55,8 @@ if($doesLogFileExist) {
$config = \OC::$server->getConfig();
$appConfig = \OC::$server->getAppConfig();
$request = \OC::$server->getRequest();
+$certificateManager = \OC::$server->getCertificateManager(null);
+$urlGenerator = \OC::$server->getURLGenerator();
// Should we display sendmail as an option?
$template->assign('sendmail_is_available', (bool) \OC_Helper::findBinaryPath('sendmail'));
@@ -75,6 +80,7 @@ $template->assign('showLog', $showLog);
$template->assign('readOnlyConfigEnabled', OC_Helper::isReadOnlyConfigEnabled());
$template->assign('isLocaleWorking', OC_Util::isSetLocaleWorking());
$template->assign('isAnnotationsWorking', OC_Util::isAnnotationsWorking());
+$template->assign('checkForWorkingWellKnownSetup', $config->getSystemValue('check_for_working_wellknown_setup', true));
$template->assign('has_fileinfo', OC_Util::fileInfoLoaded());
$template->assign('backgroundjobs_mode', $appConfig->getValue('core', 'backgroundjobs_mode', 'ajax'));
$template->assign('cron_log', $config->getSystemValue('cron_log', true));
@@ -151,6 +157,16 @@ $template->assign('OutdatedCacheWarning', $outdatedCaches);
// add hardcoded forms from the template
$forms = OC_App::getForms('admin');
+
+if ($config->getSystemValue('enable_certificate_management', false)) {
+ $certificatesTemplate = new OC_Template('settings', 'certificates');
+ $certificatesTemplate->assign('type', 'admin');
+ $certificatesTemplate->assign('uploadRoute', 'settings.Certificate.addSystemRootCertificate');
+ $certificatesTemplate->assign('certs', $certificateManager->listCertificates());
+ $certificatesTemplate->assign('urlGenerator', $urlGenerator);
+ $forms[] = $certificatesTemplate->fetchPage();
+}
+
$formsAndMore = array();
if ($request->getServerProtocol() !== 'https' || !OC_Util::isAnnotationsWorking() ||
$suggestedOverwriteCliUrl || !OC_Util::isSetLocaleWorking() ||
@@ -210,7 +226,7 @@ $formsMap = array_map(function ($form) {
$anchor = str_replace(' ', '-', $anchor);
return array(
- 'anchor' => 'goto-' . $anchor,
+ 'anchor' => $anchor,
'section-name' => $sectionName,
'form' => $form
);
diff --git a/settings/ajax/changedisplayname.php b/settings/ajax/changedisplayname.php
deleted file mode 100644
index 380cbac43da..00000000000
--- a/settings/ajax/changedisplayname.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-/**
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author David Reagan <reagand@lanecc.edu>
- * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-// Check if we are a user
-
-OCP\JSON::callCheck();
-OC_JSON::checkLoggedIn();
-
-$l = \OC::$server->getL10N('settings');
-
-$username = isset($_POST["username"]) ? $_POST["username"] : OC_User::getUser();
-$displayName = (string)$_POST["displayName"];
-
-$userstatus = null;
-if(OC_User::isAdminUser(OC_User::getUser())) {
- $userstatus = 'admin';
-}
-
-$isUserAccessible = false;
-$subadminUserObject = \OC::$server->getUserManager()->get(\OC_User::getUser());
-$targetUserObject = \OC::$server->getUserManager()->get($username);
-if($subadminUserObject !== null && $targetUserObject !== null) {
- $isUserAccessible = \OC::$server->getGroupManager()->getSubAdmin()->isUserAccessible($subadminUserObject, $targetUserObject);
-}
-
-if($isUserAccessible) {
- $userstatus = 'subadmin';
-}
-
-if ($username === OC_User::getUser() && OC_User::canUserChangeDisplayName($username)) {
- $userstatus = 'changeOwnDisplayName';
-}
-
-if(is_null($userstatus)) {
- OC_JSON::error( array( "data" => array( "message" => $l->t("Authentication error") )));
- exit();
-}
-
-// Return Success story
-if( OC_User::setDisplayName( $username, $displayName )) {
- OC_JSON::success(array("data" => array( "message" => $l->t('Your full name has been changed.'), "username" => $username, 'displayName' => $displayName )));
-}
-else{
- OC_JSON::error(array("data" => array( "message" => $l->t("Unable to change full name"), 'displayName' => OC_User::getDisplayName($username) )));
-}
diff --git a/settings/ajax/disableapp.php b/settings/ajax/disableapp.php
index f99969d91a4..5d86168287b 100644
--- a/settings/ajax/disableapp.php
+++ b/settings/ajax/disableapp.php
@@ -4,7 +4,7 @@
* @author Kamil Domanski <kdomanski@kdemail.net>
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/ajax/enableapp.php b/settings/ajax/enableapp.php
index 581a205d6ff..57b6e919995 100644
--- a/settings/ajax/enableapp.php
+++ b/settings/ajax/enableapp.php
@@ -8,7 +8,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/ajax/installapp.php b/settings/ajax/installapp.php
index d5b1b85ecf4..96f5ad9d91c 100644
--- a/settings/ajax/installapp.php
+++ b/settings/ajax/installapp.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/ajax/navigationdetect.php b/settings/ajax/navigationdetect.php
index be410b874ee..61ec93a79b5 100644
--- a/settings/ajax/navigationdetect.php
+++ b/settings/ajax/navigationdetect.php
@@ -1,9 +1,9 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/ajax/setlanguage.php b/settings/ajax/setlanguage.php
index 158f73c230a..537a5afe958 100644
--- a/settings/ajax/setlanguage.php
+++ b/settings/ajax/setlanguage.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -31,7 +31,7 @@ OCP\JSON::callCheck();
// Get data
if( isset( $_POST['lang'] ) ) {
- $languageCodes=OC_L10N::findAvailableLanguages();
+ $languageCodes = \OC::$server->getL10NFactory()->findAvailableLanguages();
$lang = (string)$_POST['lang'];
if(array_search($lang, $languageCodes) or $lang === 'en') {
\OC::$server->getConfig()->setUserValue( OC_User::getUser(), 'core', 'lang', $lang );
diff --git a/settings/ajax/setquota.php b/settings/ajax/setquota.php
index 8e6d44c2d8d..dbdfb98bc8c 100644
--- a/settings/ajax/setquota.php
+++ b/settings/ajax/setquota.php
@@ -10,7 +10,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/ajax/togglegroups.php b/settings/ajax/togglegroups.php
index f46fa356549..8cf51ab707f 100644
--- a/settings/ajax/togglegroups.php
+++ b/settings/ajax/togglegroups.php
@@ -8,7 +8,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/ajax/togglesubadmins.php b/settings/ajax/togglesubadmins.php
index 6d6bf6d6724..afeaa1acfa0 100644
--- a/settings/ajax/togglesubadmins.php
+++ b/settings/ajax/togglesubadmins.php
@@ -3,9 +3,8 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Georg Ehrke <georg@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/ajax/uninstallapp.php b/settings/ajax/uninstallapp.php
index 82e176abc17..7ff20a1c999 100644
--- a/settings/ajax/uninstallapp.php
+++ b/settings/ajax/uninstallapp.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/ajax/updateapp.php b/settings/ajax/updateapp.php
index 5fc88290c91..8521914884f 100644
--- a/settings/ajax/updateapp.php
+++ b/settings/ajax/updateapp.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/application.php b/settings/application.php
index c876065fffa..6b581cdc06e 100644
--- a/settings/application.php
+++ b/settings/application.php
@@ -5,9 +5,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -40,6 +41,7 @@ use OC\Settings\Middleware\SubadminMiddleware;
use \OCP\AppFramework\App;
use OCP\IContainer;
use \OCP\Util;
+use OC\Server;
/**
* @package OC\Settings
@@ -106,6 +108,7 @@ class Application extends App {
$c->query('AppName'),
$c->query('Request'),
$c->query('CertificateManager'),
+ $c->query('SystemCertificateManager'),
$c->query('L10N'),
$c->query('IAppManager')
);
@@ -135,7 +138,8 @@ class Application extends App {
$c->query('Mailer'),
$c->query('DefaultMailAddress'),
$c->query('URLGenerator'),
- $c->query('OCP\\App\\IAppManager')
+ $c->query('OCP\\App\\IAppManager'),
+ $c->query('OCP\\IAvatarManager')
);
});
$container->registerService('LogSettingsController', function(IContainer $c) {
@@ -154,7 +158,8 @@ class Application extends App {
$c->query('ClientService'),
$c->query('URLGenerator'),
$c->query('Util'),
- $c->query('L10N')
+ $c->query('L10N'),
+ $c->query('Checker')
);
});
@@ -240,5 +245,13 @@ class Application extends App {
$container->registerService('CertificateManager', function(IContainer $c){
return $c->query('ServerContainer')->getCertificateManager();
});
+ $container->registerService('SystemCertificateManager', function (IContainer $c) {
+ return $c->query('ServerContainer')->getCertificateManager(null);
+ });
+ $container->registerService('Checker', function(IContainer $c) {
+ /** @var Server $server */
+ $server = $c->query('ServerContainer');
+ return $server->getIntegrityCodeChecker();
+ });
}
}
diff --git a/settings/changepassword/controller.php b/settings/changepassword/controller.php
index 695914683db..bfa599c1d04 100644
--- a/settings/changepassword/controller.php
+++ b/settings/changepassword/controller.php
@@ -1,16 +1,18 @@
<?php
/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
* @author Björn Schießle <schiessle@owncloud.com>
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Clark Tomlinson <fallen013@gmail.com>
* @author cmeh <cmeh@users.noreply.github.com>
* @author Florin Peter <github@florin-peter.de>
* @author Jakob Sack <mail@jakobsack.de>
+ * @author Lukas Reschke <lukas@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
* @author Sam Tuke <mail@samtuke.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -55,10 +57,10 @@ class Controller {
\OC_JSON::callCheck();
\OC_JSON::checkLoggedIn();
+ $l = new \OC_L10n('settings');
if (isset($_POST['username'])) {
$username = $_POST['username'];
} else {
- $l = new \OC_L10n('settings');
\OC_JSON::error(array('data' => array('message' => $l->t('No user supplied')) ));
exit();
}
@@ -78,7 +80,6 @@ class Controller {
} elseif ($isUserAccessible) {
$userstatus = 'subadmin';
} else {
- $l = new \OC_L10n('settings');
\OC_JSON::error(array('data' => array('message' => $l->t('Authentication error')) ));
exit();
}
@@ -122,7 +123,6 @@ class Controller {
$validRecoveryPassword = $keyManager->checkRecoveryPassword($recoveryPassword);
$recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser($username);
}
- $l = new \OC_L10n('settings');
if ($recoveryEnabledForUser && $recoveryPassword === '') {
\OC_JSON::error(array('data' => array(
diff --git a/settings/controller/appsettingscontroller.php b/settings/controller/appsettingscontroller.php
index bde00df062f..cc69d3130d9 100644
--- a/settings/controller/appsettingscontroller.php
+++ b/settings/controller/appsettingscontroller.php
@@ -5,7 +5,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -132,6 +132,7 @@ class AppSettingsController extends Controller {
$params = [];
$params['experimentalEnabled'] = $this->config->getSystemValue('appstore.experimental.enabled', false);
$params['category'] = $category;
+ $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true;
$this->navigationManager->setActiveEntry('core_apps');
$templateResponse = new TemplateResponse($this->appName, 'apps', $params, 'user');
@@ -158,7 +159,7 @@ class AppSettingsController extends Controller {
if($this->ocsClient->isAppStoreEnabled()) {
// apps from external repo via OCS
- $ocs = $this->ocsClient->getCategories(\OC_Util::getVersion());
+ $ocs = $this->ocsClient->getCategories(\OCP\Util::getVersion());
if ($ocs) {
foreach($ocs as $k => $v) {
$name = str_replace('ownCloud ', '', $v);
@@ -204,9 +205,10 @@ class AppSettingsController extends Controller {
}
return ($a < $b) ? -1 : 1;
});
+ $version = \OCP\Util::getVersion();
foreach($apps as $key => $app) {
if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) {
- $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], \OC_Util::getVersion());
+ $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], $version);
if(is_array($remoteAppEntry) && array_key_exists('level', $remoteAppEntry)) {
$apps[$key]['level'] = $remoteAppEntry['level'];
@@ -216,13 +218,14 @@ class AppSettingsController extends Controller {
break;
// not-installed apps
case 1:
- $apps = \OC_App::listAllApps(true, $includeUpdateInfo);
+ $apps = \OC_App::listAllApps(true, $includeUpdateInfo, $this->ocsClient);
$apps = array_filter($apps, function ($app) {
return !$app['active'];
});
+ $version = \OCP\Util::getVersion();
foreach($apps as $key => $app) {
if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) {
- $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], \OC_Util::getVersion());
+ $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], $version);
if(is_array($remoteAppEntry) && array_key_exists('level', $remoteAppEntry)) {
$apps[$key]['level'] = $remoteAppEntry['level'];
@@ -241,7 +244,7 @@ class AppSettingsController extends Controller {
default:
$filter = $this->config->getSystemValue('appstore.experimental.enabled', false) ? 'all' : 'approved';
- $apps = \OC_App::getAppstoreApps($filter, $category);
+ $apps = \OC_App::getAppstoreApps($filter, $category, $this->ocsClient);
if (!$apps) {
$apps = array();
} else {
@@ -293,6 +296,9 @@ class AppSettingsController extends Controller {
$app['canInstall'] = empty($missing);
$app['missingDependencies'] = $missing;
+ $app['missingMinOwnCloudVersion'] = !isset($app['dependencies']['owncloud']['@attributes']['min-version']);
+ $app['missingMaxOwnCloudVersion'] = !isset($app['dependencies']['owncloud']['@attributes']['max-version']);
+
return $app;
}, $apps);
@@ -307,7 +313,7 @@ class AppSettingsController extends Controller {
* @return array
*/
private function getInstalledApps($includeUpdateInfo = true) {
- $apps = \OC_App::listAllApps(true, $includeUpdateInfo);
+ $apps = \OC_App::listAllApps(true, $includeUpdateInfo, $this->ocsClient);
$apps = array_filter($apps, function ($app) {
return $app['active'];
});
diff --git a/settings/controller/certificatecontroller.php b/settings/controller/certificatecontroller.php
index e360a1053c3..6f24a69b19b 100644
--- a/settings/controller/certificatecontroller.php
+++ b/settings/controller/certificatecontroller.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -36,7 +36,9 @@ use OCP\IRequest;
*/
class CertificateController extends Controller {
/** @var ICertificateManager */
- private $certificateManager;
+ private $userCertificateManager;
+ /** @var ICertificateManager */
+ private $systemCertificateManager;
/** @var IL10N */
private $l10n;
/** @var IAppManager */
@@ -45,17 +47,20 @@ class CertificateController extends Controller {
/**
* @param string $appName
* @param IRequest $request
- * @param ICertificateManager $certificateManager
+ * @param ICertificateManager $userCertificateManager
+ * @param ICertificateManager $systemCertificateManager
* @param IL10N $l10n
* @param IAppManager $appManager
*/
public function __construct($appName,
IRequest $request,
- ICertificateManager $certificateManager,
+ ICertificateManager $userCertificateManager,
+ ICertificateManager $systemCertificateManager,
IL10N $l10n,
IAppManager $appManager) {
parent::__construct($appName, $request);
- $this->certificateManager = $certificateManager;
+ $this->userCertificateManager = $userCertificateManager;
+ $this->systemCertificateManager = $systemCertificateManager;
$this->l10n = $l10n;
$this->appManager = $appManager;
}
@@ -68,6 +73,16 @@ class CertificateController extends Controller {
* @return array
*/
public function addPersonalRootCertificate() {
+ return $this->addCertificate($this->userCertificateManager);
+ }
+
+ /**
+ * Add a new root certificate to a trust store
+ *
+ * @param ICertificateManager $certificateManager
+ * @return array
+ */
+ private function addCertificate(ICertificateManager $certificateManager) {
$headers = [];
if ($this->request->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) {
// due to upload iframe workaround, need to set content-type to text/plain
@@ -79,23 +94,23 @@ class CertificateController extends Controller {
}
$file = $this->request->getUploadedFile('rootcert_import');
- if(empty($file)) {
+ if (empty($file)) {
return new DataResponse(['message' => 'No file uploaded'], Http::STATUS_UNPROCESSABLE_ENTITY, $headers);
}
try {
- $certificate = $this->certificateManager->addCertificate(file_get_contents($file['tmp_name']), $file['name']);
+ $certificate = $certificateManager->addCertificate(file_get_contents($file['tmp_name']), $file['name']);
return new DataResponse(
[
- 'name' => $certificate->getName(),
- 'commonName' => $certificate->getCommonName(),
- 'organization' => $certificate->getOrganization(),
- 'validFrom' => $certificate->getIssueDate()->getTimestamp(),
- 'validTill' => $certificate->getExpireDate()->getTimestamp(),
- 'validFromString' => $this->l10n->l('date', $certificate->getIssueDate()),
- 'validTillString' => $this->l10n->l('date', $certificate->getExpireDate()),
- 'issuer' => $certificate->getIssuerName(),
- 'issuerOrganization' => $certificate->getIssuerOrganization(),
+ 'name' => $certificate->getName(),
+ 'commonName' => $certificate->getCommonName(),
+ 'organization' => $certificate->getOrganization(),
+ 'validFrom' => $certificate->getIssueDate()->getTimestamp(),
+ 'validTill' => $certificate->getExpireDate()->getTimestamp(),
+ 'validFromString' => $this->l10n->l('date', $certificate->getIssueDate()),
+ 'validTillString' => $this->l10n->l('date', $certificate->getExpireDate()),
+ 'issuer' => $certificate->getIssuerName(),
+ 'issuerOrganization' => $certificate->getIssuerOrganization(),
],
Http::STATUS_OK,
$headers
@@ -119,7 +134,7 @@ class CertificateController extends Controller {
return new DataResponse('Individual certificate management disabled', Http::STATUS_FORBIDDEN);
}
- $this->certificateManager->removeCertificate($certificateIdentifier);
+ $this->userCertificateManager->removeCertificate($certificateIdentifier);
return new DataResponse();
}
@@ -140,4 +155,28 @@ class CertificateController extends Controller {
return false;
}
+ /**
+ * Add a new personal root certificate to the system's trust store
+ *
+ * @return array
+ */
+ public function addSystemRootCertificate() {
+ return $this->addCertificate($this->systemCertificateManager);
+ }
+
+ /**
+ * Removes a personal root certificate from the users' trust store
+ *
+ * @param string $certificateIdentifier
+ * @return DataResponse
+ */
+ public function removeSystemRootCertificate($certificateIdentifier) {
+
+ if ($this->isCertificateImportAllowed() === false) {
+ return new DataResponse('Individual certificate management disabled', Http::STATUS_FORBIDDEN);
+ }
+
+ $this->systemCertificateManager->removeCertificate($certificateIdentifier);
+ return new DataResponse();
+ }
}
diff --git a/settings/controller/checksetupcontroller.php b/settings/controller/checksetupcontroller.php
index 491821b44c5..26194bb1180 100644
--- a/settings/controller/checksetupcontroller.php
+++ b/settings/controller/checksetupcontroller.php
@@ -3,10 +3,10 @@
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -26,8 +26,12 @@
namespace OC\Settings\Controller;
use GuzzleHttp\Exception\ClientException;
+use OC\AppFramework\Http;
+use OC\IntegrityCheck\Checker;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\DataDisplayResponse;
use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\RedirectResponse;
use OCP\Http\Client\IClientService;
use OCP\IConfig;
use OCP\IL10N;
@@ -49,6 +53,8 @@ class CheckSetupController extends Controller {
private $urlGenerator;
/** @var IL10N */
private $l10n;
+ /** @var Checker */
+ private $checker;
/**
* @param string $AppName
@@ -58,6 +64,7 @@ class CheckSetupController extends Controller {
* @param IURLGenerator $urlGenerator
* @param \OC_Util $util
* @param IL10N $l10n
+ * @param Checker $checker
*/
public function __construct($AppName,
IRequest $request,
@@ -65,13 +72,15 @@ class CheckSetupController extends Controller {
IClientService $clientService,
IURLGenerator $urlGenerator,
\OC_Util $util,
- IL10N $l10n) {
+ IL10N $l10n,
+ Checker $checker) {
parent::__construct($AppName, $request);
$this->config = $config;
$this->clientService = $clientService;
$this->util = $util;
$this->urlGenerator = $urlGenerator;
$this->l10n = $l10n;
+ $this->checker = $checker;
}
/**
@@ -248,13 +257,78 @@ class CheckSetupController extends Controller {
}
/**
+ * @return RedirectResponse
+ */
+ public function rescanFailedIntegrityCheck() {
+ $this->checker->runInstanceVerification();
+ return new RedirectResponse(
+ $this->urlGenerator->linkToRoute('settings_admin')
+ );
+ }
+
+ /**
+ * @NoCSRFRequired
+ * @return DataResponse
+ */
+ public function getFailedIntegrityCheckFiles() {
+ $completeResults = $this->checker->getResults();
+
+ if(!empty($completeResults)) {
+ $formattedTextResponse = 'Technical information
+=====================
+The following list covers which files have failed the integrity check. Please read
+the previous linked documentation to learn more about the errors and how to fix
+them.
+
+Results
+=======
+';
+ foreach($completeResults as $context => $contextResult) {
+ $formattedTextResponse .= "- $context\n";
+
+ foreach($contextResult as $category => $result) {
+ $formattedTextResponse .= "\t- $category\n";
+ if($category !== 'EXCEPTION') {
+ foreach ($result as $key => $results) {
+ $formattedTextResponse .= "\t\t- $key\n";
+ }
+ } else {
+ foreach ($result as $key => $results) {
+ $formattedTextResponse .= "\t\t- $results\n";
+ }
+ }
+
+ }
+ }
+
+ $formattedTextResponse .= '
+Raw output
+==========
+';
+ $formattedTextResponse .= print_r($completeResults, true);
+ } else {
+ $formattedTextResponse = 'No errors have been found.';
+ }
+
+
+ $response = new DataDisplayResponse(
+ $formattedTextResponse,
+ Http::STATUS_OK,
+ [
+ 'Content-Type' => 'text/plain',
+ ]
+ );
+
+ return $response;
+ }
+
+ /**
* @return DataResponse
*/
public function check() {
return new DataResponse(
[
'serverHasInternetConnection' => $this->isInternetConnectionWorking(),
- 'dataDirectoryProtected' => $this->util->isHtaccessWorking($this->config),
'isMemcacheConfigured' => $this->isMemcacheConfigured(),
'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
'isUrandomAvailable' => $this->isUrandomAvailable(),
@@ -263,7 +337,9 @@ class CheckSetupController extends Controller {
'phpSupported' => $this->isPhpSupported(),
'forwardedForHeadersWorking' => $this->forwardedForHeadersWorking(),
'reverseProxyDocs' => $this->urlGenerator->linkToDocs('admin-reverse-proxy'),
- 'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled()
+ 'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled(),
+ 'hasPassedCodeIntegrityCheck' => $this->checker->hasPassedCheck(),
+ 'codeIntegrityCheckerDocumentation' => $this->urlGenerator->linkToDocs('admin-code-integrity'),
]
);
}
diff --git a/settings/controller/encryptioncontroller.php b/settings/controller/encryptioncontroller.php
index b3515f962f4..504448a5a2c 100644
--- a/settings/controller/encryptioncontroller.php
+++ b/settings/controller/encryptioncontroller.php
@@ -3,7 +3,7 @@
* @author Björn Schießle <schiessle@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/controller/groupscontroller.php b/settings/controller/groupscontroller.php
index 93dcc7358a9..bb8e6755d41 100644
--- a/settings/controller/groupscontroller.php
+++ b/settings/controller/groupscontroller.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/controller/logsettingscontroller.php b/settings/controller/logsettingscontroller.php
index cae0d419e2b..c0c9ee04ca3 100644
--- a/settings/controller/logsettingscontroller.php
+++ b/settings/controller/logsettingscontroller.php
@@ -4,7 +4,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/controller/mailsettingscontroller.php b/settings/controller/mailsettingscontroller.php
index 885c19a919b..dbba4bd9bc0 100644
--- a/settings/controller/mailsettingscontroller.php
+++ b/settings/controller/mailsettingscontroller.php
@@ -4,7 +4,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/controller/securitysettingscontroller.php b/settings/controller/securitysettingscontroller.php
index dbc81c2dffb..d7274d6bcb2 100644
--- a/settings/controller/securitysettingscontroller.php
+++ b/settings/controller/securitysettingscontroller.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/controller/userscontroller.php b/settings/controller/userscontroller.php
index 82483a76245..17629fe924f 100644
--- a/settings/controller/userscontroller.php
+++ b/settings/controller/userscontroller.php
@@ -6,8 +6,9 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -27,7 +28,6 @@
namespace OC\Settings\Controller;
use OC\AppFramework\Http;
-use OC\Settings\Factory\SubAdminFactory;
use OC\User\User;
use OCP\App\IAppManager;
use OCP\AppFramework\Controller;
@@ -43,6 +43,7 @@ use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Mail\IMailer;
+use OCP\IAvatarManager;
/**
* @package OC\Settings\Controller
@@ -74,6 +75,8 @@ class UsersController extends Controller {
private $isEncryptionAppEnabled;
/** @var bool contains the state of the admin recovery setting */
private $isRestoreEnabled = false;
+ /** @var IAvatarManager */
+ private $avatarManager;
/**
* @param string $appName
@@ -104,7 +107,8 @@ class UsersController extends Controller {
IMailer $mailer,
$fromMailAddress,
IURLGenerator $urlGenerator,
- IAppManager $appManager) {
+ IAppManager $appManager,
+ IAvatarManager $avatarManager) {
parent::__construct($appName, $request);
$this->userManager = $userManager;
$this->groupManager = $groupManager;
@@ -117,6 +121,7 @@ class UsersController extends Controller {
$this->mailer = $mailer;
$this->fromMailAddress = $fromMailAddress;
$this->urlGenerator = $urlGenerator;
+ $this->avatarManager = $avatarManager;
// check for encryption state - TODO see formatUserForIndex
$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
@@ -164,6 +169,16 @@ class UsersController extends Controller {
$subAdminGroups[$key] = $subAdminGroup->getGID();
}
+ $displayName = $user->getEMailAddress();
+ if (is_null($displayName)) {
+ $displayName = '';
+ }
+
+ $avatarAvailable = false;
+ if ($this->config->getSystemValue('enable_avatars', true) === true) {
+ $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
+ }
+
return [
'name' => $user->getUID(),
'displayname' => $user->getDisplayName(),
@@ -173,8 +188,9 @@ class UsersController extends Controller {
'storageLocation' => $user->getHome(),
'lastLogin' => $user->getLastLogin() * 1000,
'backend' => $user->getBackendClassName(),
- 'email' => $this->config->getUserValue($user->getUID(), 'settings', 'email', ''),
+ 'email' => $displayName,
'isRestoreDisabled' => !$restorePossible,
+ 'isAvatarAvailable' => $avatarAvailable,
];
}
@@ -357,7 +373,7 @@ class UsersController extends Controller {
* Send new user mail only if a mail is set
*/
if($email !== '') {
- $this->config->setUserValue($username, 'settings', 'email', $email);
+ $user->setEMailAddress($email);
// data for the mail template
$mailData = array(
@@ -529,11 +545,7 @@ class UsersController extends Controller {
}
// delete user value if email address is empty
- if($mailAddress === '') {
- $this->config->deleteUserValue($id, 'settings', 'email');
- } else {
- $this->config->setUserValue($id, 'settings', 'email', $mailAddress);
- }
+ $user->setEMailAddress($mailAddress);
return new DataResponse(
array(
@@ -585,4 +597,58 @@ class UsersController extends Controller {
);
}
+
+ /**
+ * Set the displayName of a user
+ *
+ * @NoAdminRequired
+ * @NoSubadminRequired
+ *
+ * @param string $username
+ * @param string $displayName
+ * @return DataResponse
+ */
+ public function setDisplayName($username, $displayName) {
+ $currentUser = $this->userSession->getUser();
+
+ if ($username === null) {
+ $username = $currentUser->getUID();
+ }
+
+ $user = $this->userManager->get($username);
+
+ if ($user === null ||
+ !$user->canChangeDisplayName() ||
+ (
+ !$this->groupManager->isAdmin($currentUser->getUID()) &&
+ !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
+ $currentUser !== $user)
+ ) {
+ return new DataResponse([
+ 'status' => 'error',
+ 'data' => [
+ 'message' => $this->l10n->t('Authentication error'),
+ ],
+ ]);
+ }
+
+ if ($user->setDisplayName($displayName)) {
+ return new DataResponse([
+ 'status' => 'success',
+ 'data' => [
+ 'message' => $this->l10n->t('Your full name has been changed.'),
+ 'username' => $username,
+ 'displayName' => $displayName,
+ ],
+ ]);
+ } else {
+ return new DataResponse([
+ 'status' => 'error',
+ 'data' => [
+ 'message' => $this->l10n->t('Unable to change full name'),
+ 'displayName' => $user->getDisplayName(),
+ ],
+ ]);
+ }
+ }
}
diff --git a/settings/css/settings.css b/settings/css/settings.css
index 60ba805d3ca..9e98960a715 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -6,30 +6,62 @@ select#languageinput, select#timezone { width:15em; }
input#openid, input#webdav { width:20em; }
/* PERSONAL */
-#sslCertificate tr.expired {
- background-color: rgba(255, 0, 0, 0.5);
+
+#avatar {
+ display: inline-block;
+ float: left;
+ width: 160px;
+ padding-right: 0;
}
-#sslCertificate td {
- padding: 5px;
+#avatar .avatardiv {
+ margin-bottom: 10px;
+}
+#avatar .warning {
+ width: 100%;
+}
+#uploadavatarbutton,
+#selectavatar,
+#removeavatar {
+ width: 33px;
+ height: 33px;
+}
+.jcrop-holder {
+ z-index: 500;
+}
+#avatar #cropper {
+ float: left;
+ background-color: #fff;
+ z-index: 500;
+ position: relative;
}
-/* Sync clients */
-.clientsbox {
- padding-top: 30px;
- margin-top: -30px;
+#displaynameform,
+#lostpassword,
+#groups {
+ display: inline-block;
+ margin-bottom: 0;
+ padding-bottom: 0;
+ padding-right: 0;
+ min-width: 60%;
}
-.clientsbox h2 {
- font-weight: 300;
- font-size: 20px;
- margin: 35px 0 10px;
+#avatar,
+#passwordform {
+ margin-bottom: 0;
+ padding-bottom: 0;
}
-.clientsbox .center {
- margin-top: 10px;
+#groups {
+ overflow-wrap: break-word;
+ max-width: 75%;
}
-.clientsbox a {
- font-weight: 600;
+
+#sslCertificate tr.expired {
+ background-color: rgba(255, 0, 0, 0.5);
+}
+#sslCertificate td {
+ padding: 5px;
}
+
#displaynameerror {
display: none;
}
@@ -44,8 +76,8 @@ input#identity {
width: 17em;
}
-#avatar .warning {
- width: 350px;
+#showWizard {
+ display: inline-block;
}
.msg.success {
@@ -139,6 +171,11 @@ td.password>img,td.displayName>img, td.remove>a, td.quota>img { visibility:hidde
td.password, td.quota, td.displayName { width:12em; cursor:pointer; }
td.password>span, td.quota>span, rd.displayName>span { margin-right: 1.2em; color: #C7C7C7; }
span.usersLastLoginTooltip { white-space: nowrap; }
+
+/* dropdowns will be relative to this element */
+#userlist {
+ position: relative;
+}
#userlist .mailAddress,
#userlist .storageLocation,
#userlist .userBackend,
@@ -325,7 +362,6 @@ span.version {
}
.app-dependencies {
- margin-top: 10px;
color: #ce3702;
}
@@ -412,13 +448,13 @@ table.grid td.date{
.cronlog {
margin-left: 10px;
}
-.cronstatus {
+.status {
display: inline-block;
height: 16px;
width: 16px;
vertical-align: text-bottom;
}
-.cronstatus.success {
+.status.success {
border-radius: 50%;
}
diff --git a/settings/help.php b/settings/help.php
index aa89277d883..ce942d6ae80 100644
--- a/settings/help.php
+++ b/settings/help.php
@@ -8,8 +8,9 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -30,21 +31,21 @@ OC_Util::checkLoggedIn();
// Load the files we need
OC_Util::addStyle( "settings", "settings" );
-OC_App::setActiveNavigationEntry( "help" );
+\OC::$server->getNavigationManager()->setActiveEntry('help');
if(isset($_GET['mode']) and $_GET['mode'] === 'admin') {
- $url=OC_Helper::linkToAbsolute( 'core', 'doc/admin/index.html' );
+ $url=\OCP\Util::linkToAbsolute( 'core', 'doc/admin/index.html' );
$style1='';
$style2=' active';
}else{
- $url=OC_Helper::linkToAbsolute( 'core', 'doc/user/index.html' );
+ $url=\OCP\Util::linkToAbsolute( 'core', 'doc/user/index.html' );
$style1=' active';
$style2='';
}
-$url1=OC_Helper::linkToRoute( "settings_help" ).'?mode=user';
-$url2=OC_Helper::linkToRoute( "settings_help" ).'?mode=admin';
+$url1=\OC::$server->getURLGenerator()->linkToRoute('settings_help').'?mode=user';
+$url2=\OC::$server->getURLGenerator()->linkToRoute('settings_help').'?mode=admin';
$tmpl = new OC_Template( "settings", "help", "user" );
$tmpl->assign( "admin", OC_User::isAdminUser(OC_User::getUser()));
diff --git a/settings/js/admin.js b/settings/js/admin.js
index eb3b756bf0f..90b1de68370 100644
--- a/settings/js/admin.js
+++ b/settings/js/admin.js
@@ -168,10 +168,13 @@ $(document).ready(function(){
// run setup checks then gather error messages
$.when(
OC.SetupChecks.checkWebDAV(),
+ OC.SetupChecks.checkWellKnownUrl('/.well-known/caldav/', oc_defaults.docPlaceholderUrl, $('#postsetupchecks').data('check-wellknown') === 'true'),
+ OC.SetupChecks.checkWellKnownUrl('/.well-known/carddav/', oc_defaults.docPlaceholderUrl, $('#postsetupchecks').data('check-wellknown') === 'true'),
OC.SetupChecks.checkSetup(),
- OC.SetupChecks.checkGeneric()
- ).then(function(check1, check2, check3) {
- var messages = [].concat(check1, check2, check3);
+ OC.SetupChecks.checkGeneric(),
+ OC.SetupChecks.checkDataProtected()
+ ).then(function(check1, check2, check3, check4, check5, check6) {
+ var messages = [].concat(check1, check2, check3, check4, check5, check6);
var $el = $('#postsetupchecks');
$el.find('.loading').addClass('hidden');
diff --git a/settings/js/apps.js b/settings/js/apps.js
index 9782fafd2bd..b6f6363a992 100644
--- a/settings/js/apps.js
+++ b/settings/js/apps.js
@@ -153,6 +153,11 @@ OC.Settings.Apps = OC.Settings.Apps || {
}
app.firstExperimental = firstExperimental;
+ if (!app.preview) {
+ app.preview = OC.imagePath('core', 'default-app-icon');
+ app.previewAsIcon = true;
+ }
+
var html = template(app);
if (selector) {
selector.html(html);
@@ -176,7 +181,8 @@ OC.Settings.Apps = OC.Settings.Apps || {
// set group select properly
if(OC.Settings.Apps.isType(app, 'filesystem') || OC.Settings.Apps.isType(app, 'prelogin') ||
- OC.Settings.Apps.isType(app, 'authentication') || OC.Settings.Apps.isType(app, 'logging')) {
+ OC.Settings.Apps.isType(app, 'authentication') || OC.Settings.Apps.isType(app, 'logging') ||
+ OC.Settings.Apps.isType(app, 'prevent_group_restriction')) {
page.find(".groups-enable").hide();
page.find(".groups-enable__checkbox").attr('checked', null);
} else {
@@ -422,6 +428,11 @@ OC.Settings.Apps = OC.Settings.Apps || {
return app.name.toLowerCase().indexOf(query) !== -1;
});
+ // App ID
+ apps = apps.concat(_.filter(OC.Settings.Apps.State.apps, function (app) {
+ return app.id.toLowerCase().indexOf(query) !== -1;
+ }));
+
// App Description
apps = apps.concat(_.filter(OC.Settings.Apps.State.apps, function (app) {
return app.description.toLowerCase().indexOf(query) !== -1;
diff --git a/settings/js/certificates.js b/settings/js/certificates.js
new file mode 100644
index 00000000000..9ce9f9aa8d8
--- /dev/null
+++ b/settings/js/certificates.js
@@ -0,0 +1,69 @@
+$(document).ready(function () {
+ var type = $('#sslCertificate').data('type');
+ $('#sslCertificate').on('click', 'td.remove', function () {
+ var row = $(this).parent();
+ $.ajax(OC.generateUrl('settings/' + type + '/certificate/{certificate}', {certificate: row.data('name')}), {
+ type: 'DELETE'
+ });
+ row.remove();
+
+ if ($('#sslCertificate > tbody > tr').length === 0) {
+ $('#sslCertificate').hide();
+ }
+ return true;
+ });
+
+ $('#sslCertificate tr > td').tipsy({gravity: 'n', live: true});
+
+ $('#rootcert_import').fileupload({
+ submit: function (e, data) {
+ data.formData = _.extend(data.formData || {}, {
+ requesttoken: OC.requestToken
+ });
+ },
+ success: function (data) {
+ if (typeof data === 'string') {
+ data = $.parseJSON(data);
+ } else if (data && data.length) {
+ // fetch response from iframe
+ data = $.parseJSON(data[0].body.innerText);
+ }
+ if (!data || typeof(data) === 'string') {
+ // IE8 iframe workaround comes here instead of fail()
+ OC.Notification.showTemporary(
+ t('settings', 'An error occurred. Please upload an ASCII-encoded PEM certificate.'));
+ return;
+ }
+ var issueDate = new Date(data.validFrom * 1000);
+ var expireDate = new Date(data.validTill * 1000);
+ var now = new Date();
+ var isExpired = !(issueDate <= now && now <= expireDate);
+
+ var row = $('<tr/>');
+ row.data('name', data.name);
+ row.addClass(isExpired ? 'expired' : 'valid');
+ row.append($('<td/>').attr('title', data.organization).text(data.commonName));
+ row.append($('<td/>').attr('title', t('core,', 'Valid until {date}', {date: data.validTillString}))
+ .text(data.validTillString));
+ row.append($('<td/>').attr('title', data.issuerOrganization).text(data.issuer));
+ row.append($('<td/>').addClass('remove').append(
+ $('<img/>').attr({
+ alt: t('core', 'Delete'),
+ title: t('core', 'Delete'),
+ src: OC.imagePath('core', 'actions/delete.svg')
+ }).addClass('action')
+ ));
+
+ $('#sslCertificate tbody').append(row);
+ $('#sslCertificate').show();
+ },
+ fail: function () {
+ OC.Notification.showTemporary(
+ t('settings', 'An error occurred. Please upload an ASCII-encoded PEM certificate.'));
+ }
+ });
+
+ if ($('#sslCertificate > tbody > tr').length === 0) {
+ $('#sslCertificate').hide();
+ }
+});
diff --git a/settings/js/personal.js b/settings/js/personal.js
index 3439eba686f..65bc88d2098 100644
--- a/settings/js/personal.js
+++ b/settings/js/personal.js
@@ -70,7 +70,7 @@ function changeDisplayName () {
// Serialize the data
var post = $("#displaynameform").serialize();
// Ajax foo
- $.post('ajax/changedisplayname.php', post, function (data) {
+ $.post(OC.generateUrl('/settings/users/{id}/displayName', {id: OC.currentUser}), post, function (data) {
if (data.status === "success") {
$('#oldDisplayName').val($('#displayName').val());
// update displayName on the top right expand button
@@ -98,9 +98,9 @@ function updateAvatar (hidedefault) {
$('#header .avatardiv').addClass('avatardiv-shown');
}
$displaydiv.css({'background-color': ''});
- $displaydiv.avatar(OC.currentUser, 128, true);
+ $displaydiv.avatar(OC.currentUser, 145, true);
- $('#removeavatar').show();
+ $('#removeavatar').removeClass('hidden').addClass('inlineblock');
}
function showAvatarCropper () {
@@ -195,9 +195,9 @@ $(document).ready(function () {
$('#password-error').removeClass('inlineblock').addClass('hidden');
} else {
if (typeof(data.data) !== "undefined") {
- $('#password-error').html(data.data.message);
+ $('#password-error').text(data.data.message);
} else {
- $('#password-error').html(t('Unable to change password'));
+ $('#password-error').text(t('Unable to change password'));
}
// Hide a possible successmsg and show errormsg
$('#password-changed').removeClass('inlineblock').addClass('hidden');
@@ -226,7 +226,7 @@ $(document).ready(function () {
location.reload();
}
else {
- $('#passworderror').html(data.data.message);
+ $('#passworderror').text(data.data.message);
}
});
return false;
@@ -303,7 +303,7 @@ $(document).ready(function () {
url: OC.generateUrl('/avatar/'),
success: function () {
updateAvatar(true);
- $('#removeavatar').hide();
+ $('#removeavatar').addClass('hidden').removeClass('inlineblock');
}
});
});
@@ -327,83 +327,20 @@ $(document).ready(function () {
]
});
- // does the user have a custom avatar? if he does hide #removeavatar
- // needs to be this complicated because we can't check yet if an avatar has been loaded, because it's async
- var url = OC.generateUrl(
+ // does the user have a custom avatar? if he does show #removeavatar
+ $.get(OC.generateUrl(
'/avatar/{user}/{size}',
{user: OC.currentUser, size: 1}
- );
- $.get(url, function (result) {
- if (typeof(result) === 'object') {
- $('#removeavatar').hide();
+ ), function (result) {
+ if (typeof(result) === 'string') {
+ // Show the delete button when the avatar is custom
+ $('#removeavatar').removeClass('hidden').addClass('inlineblock');
}
});
- $('#sslCertificate').on('click', 'td.remove > img', function () {
- var row = $(this).parent().parent();
- $.ajax(OC.generateUrl('settings/personal/certificate/{certificate}', {certificate: row.data('name')}), {
- type: 'DELETE'
- });
- row.remove();
-
- if ($('#sslCertificate > tbody > tr').length === 0) {
- $('#sslCertificate').hide();
- }
- return true;
- });
-
- $('#sslCertificate tr > td').tipsy({gravity: 'n', live: true});
-
- $('#rootcert_import').fileupload({
- submit: function(e, data) {
- data.formData = _.extend(data.formData || {}, {
- requesttoken: OC.requestToken
- });
- },
- success: function (data) {
- if (typeof data === 'string') {
- data = $.parseJSON(data);
- } else if (data && data.length) {
- // fetch response from iframe
- data = $.parseJSON(data[0].body.innerText);
- }
- if (!data || typeof(data) === 'string') {
- // IE8 iframe workaround comes here instead of fail()
- OC.Notification.showTemporary(
- t('settings', 'An error occurred. Please upload an ASCII-encoded PEM certificate.'));
- return;
- }
- var issueDate = new Date(data.validFrom * 1000);
- var expireDate = new Date(data.validTill * 1000);
- var now = new Date();
- var isExpired = !(issueDate <= now && now <= expireDate);
-
- var row = $('<tr/>');
- row.data('name', data.name);
- row.addClass(isExpired? 'expired': 'valid');
- row.append($('<td/>').attr('title', data.organization).text(data.commonName));
- row.append($('<td/>').attr('title', t('core,', 'Valid until {date}', {date: data.validTillString}))
- .text(data.validTillString));
- row.append($('<td/>').attr('title', data.issuerOrganization).text(data.issuer));
- row.append($('<td/>').addClass('remove').append(
- $('<img/>').attr({
- alt: t('core', 'Delete'),
- title: t('core', 'Delete'),
- src: OC.imagePath('core', 'actions/delete.svg')
- }).addClass('action')
- ));
-
- $('#sslCertificate tbody').append(row);
- $('#sslCertificate').show();
- },
- fail: function () {
- OC.Notification.showTemporary(
- t('settings', 'An error occurred. Please upload an ASCII-encoded PEM certificate.'));
- }
- });
-
- if ($('#sslCertificate > tbody > tr').length === 0) {
- $('#sslCertificate').hide();
+ // Load the big avatar
+ if (oc_config.enable_avatars) {
+ $('#avatar .avatardiv').avatar(OC.currentUser, 145);
}
});
diff --git a/settings/js/users/users.js b/settings/js/users/users.js
index 8ce9cb6ac7c..306e3952e53 100644
--- a/settings/js/users/users.js
+++ b/settings/js/users/users.js
@@ -64,9 +64,12 @@ var UserList = {
/**
* Avatar or placeholder
*/
- if ($tr.find('div.avatardiv').length){
- $tr.find('.avatardiv').imageplaceholder(user.name, user.displayname);
- $('div.avatardiv', $tr).avatar(user.name, 32);
+ if ($tr.find('div.avatardiv').length) {
+ if (user.isAvatarAvailable === true) {
+ $('div.avatardiv', $tr).avatar(user.name, 32, undefined, undefined, undefined, user.displayname);
+ } else {
+ $('div.avatardiv', $tr).imageplaceholder(user.displayname, undefined, 32);
+ }
}
/**
@@ -256,6 +259,10 @@ var UserList = {
}
},
doSort: function() {
+ // some browsers like Chrome lose the scrolling information
+ // when messing with the list elements
+ var lastScrollTop = this.scrollArea.scrollTop();
+ var lastScrollLeft = this.scrollArea.scrollLeft();
var rows = $userListBody.find('tr').get();
rows.sort(function(a, b) {
@@ -281,6 +288,8 @@ var UserList = {
if(items.length > 0) {
$userListBody.append(items);
}
+ this.scrollArea.scrollTop(lastScrollTop);
+ this.scrollArea.scrollLeft(lastScrollLeft);
},
checkUsersToLoad: function() {
//30 shall be loaded initially, from then on always 10 upon scrolling
@@ -602,10 +611,11 @@ $(document).ready(function () {
// Implements User Search
OCA.Search.users= new UserManagementFilter(UserList, GroupList);
+ UserList.scrollArea = $('#app-content');
+
UserList.doSort();
UserList.availableGroups = $userList.data('groups');
- UserList.scrollArea = $('#app-content');
UserList.scrollArea.scroll(function(e) {UserList._onScroll(e);});
$userList.after($('<div class="loading" style="height: 200px; visibility: hidden;"></div>'));
@@ -647,7 +657,7 @@ $(document).ready(function () {
{username: uid, password: $(this).val(), recoveryPassword: recoveryPasswordVal},
function (result) {
if (result.status != 'success') {
- OC.Notification.show(t('admin', result.data.message));
+ OC.Notification.showTemporary(t('admin', result.data.message));
}
}
);
@@ -687,7 +697,7 @@ $(document).ready(function () {
$div.imageplaceholder(uid, displayName);
}
$.post(
- OC.filePath('settings', 'ajax', 'changedisplayname.php'),
+ OC.generateUrl('/settings/users/{id}/displayName', {id: uid}),
{username: uid, displayName: $(this).val()},
function (result) {
if (result && result.status==='success' && $div.length){
@@ -695,6 +705,8 @@ $(document).ready(function () {
}
}
);
+ var displayName = $input.val();
+ $tr.data('displayname', displayName);
$input.blur();
} else {
$input.blur();
@@ -702,8 +714,7 @@ $(document).ready(function () {
}
})
.blur(function () {
- var displayName = $input.val();
- $tr.data('displayname', displayName);
+ var displayName = $tr.data('displayname');
$input.replaceWith('<span>' + escapeHTML(displayName) + '</span>');
$td.find('img').show();
});
@@ -721,27 +732,24 @@ $(document).ready(function () {
.focus()
.keypress(function (event) {
if (event.keyCode === 13) {
- if ($(this).val().length > 0) {
- $input.blur();
- $.ajax({
- type: 'PUT',
- url: OC.generateUrl('/settings/users/{id}/mailAddress', {id: uid}),
- data: {
- mailAddress: $(this).val()
- }
- }).fail(function (result) {
- OC.Notification.show(result.responseJSON.data.message);
- // reset the values
- $tr.data('mailAddress', mailAddress);
- $tr.children('.mailAddress').children('span').text(mailAddress);
- });
- } else {
- $input.blur();
- }
+ $tr.data('mailAddress', $input.val());
+ $input.blur();
+ $.ajax({
+ type: 'PUT',
+ url: OC.generateUrl('/settings/users/{id}/mailAddress', {id: uid}),
+ data: {
+ mailAddress: $(this).val()
+ }
+ }).fail(function (result) {
+ OC.Notification.show(result.responseJSON.data.message);
+ // reset the values
+ $tr.data('mailAddress', mailAddress);
+ $tr.children('.mailAddress').children('span').text(mailAddress);
+ });
}
})
.blur(function () {
- var mailAddress = $input.val();
+ var mailAddress = $tr.data('mailAddress');
var $span = $('<span>').text(mailAddress);
$tr.data('mailAddress', mailAddress);
$input.replaceWith($span);
diff --git a/settings/l10n/af_ZA.js b/settings/l10n/af_ZA.js
index 0a4fa325224..509b7f2de7c 100644
--- a/settings/l10n/af_ZA.js
+++ b/settings/l10n/af_ZA.js
@@ -2,9 +2,9 @@ OC.L10N.register(
"settings",
{
"So-so password" : "So-so wagwoord",
+ "Cancel" : "Kanseleer",
"Password" : "Wagwoord",
"New password" : "Nuwe wagwoord",
- "Cancel" : "Kanseleer",
"Username" : "Gebruikersnaam"
},
"nplurals=2; plural=(n != 1);");
diff --git a/settings/l10n/af_ZA.json b/settings/l10n/af_ZA.json
index f4d95bdfe45..4cc552a2d96 100644
--- a/settings/l10n/af_ZA.json
+++ b/settings/l10n/af_ZA.json
@@ -1,8 +1,8 @@
{ "translations": {
"So-so password" : "So-so wagwoord",
+ "Cancel" : "Kanseleer",
"Password" : "Wagwoord",
"New password" : "Nuwe wagwoord",
- "Cancel" : "Kanseleer",
"Username" : "Gebruikersnaam"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/settings/l10n/ar.js b/settings/l10n/ar.js
index a4e9705f3ac..82a1090f5a8 100644
--- a/settings/l10n/ar.js
+++ b/settings/l10n/ar.js
@@ -4,11 +4,9 @@ OC.L10N.register(
"Sharing" : "مشاركة",
"Cron" : "مجدول",
"Log" : "سجل",
- "Authentication error" : "لم يتم التأكد من الشخصية بنجاح",
- "Your full name has been changed." : "اسمك الكامل تم تغييره.",
- "Unable to change full name" : "لم يتم التمكن من تغيير اسمك الكامل",
"Language changed" : "تم تغيير اللغة",
"Invalid request" : "طلب غير مفهوم",
+ "Authentication error" : "لم يتم التأكد من الشخصية بنجاح",
"Admins can't remove themself from the admin group" : "لا يستطيع المدير إزالة حسابه من مجموعة المديرين",
"Unable to add user to group %s" : "فشل إضافة المستخدم الى المجموعة %s",
"Unable to remove user from group %s" : "فشل إزالة المستخدم من المجموعة %s",
@@ -23,6 +21,8 @@ OC.L10N.register(
"test email settings" : "إعدادات البريد التجريبي",
"Email sent" : "تم ارسال البريد الالكتروني",
"Email saved" : "تم حفظ البريد الإلكتروني",
+ "Your full name has been changed." : "اسمك الكامل تم تغييره.",
+ "Unable to change full name" : "لم يتم التمكن من تغيير اسمك الكامل",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "هل أنت متأكد انك تريد إضافة \"{domain}\" كنطاق موثوق فيه.",
"Sending..." : "جاري الارسال ...",
"All" : "الكل",
@@ -36,12 +36,12 @@ OC.L10N.register(
"Updated" : "تم التحديث بنجاح",
"Uninstalling ...." : "جاري إلغاء التثبيت ...",
"Uninstall" : "ألغاء التثبيت",
+ "Delete" : "إلغاء",
"Select a profile picture" : "اختر صورة الملف الشخصي ",
"Very weak password" : "كلمة السر ضعيفة جدا",
"Weak password" : "كلمة السر ضعيفة",
"Good password" : "كلمة السر جيدة",
"Strong password" : "كلمة السر قوية",
- "Delete" : "إلغاء",
"Groups" : "مجموعات",
"undo" : "تراجع",
"never" : "بتاتا",
@@ -73,34 +73,28 @@ OC.L10N.register(
"Authentication method" : "أسلوب التطابق",
"Server address" : "عنوان الخادم",
"Port" : "المنفذ",
- "Log level" : "مستوى السجل",
"More" : "المزيد",
"Less" : "أقل",
"Version" : "إصدار",
- "by" : "من قبل",
"Documentation:" : "التوثيق",
"Uninstall App" : "أزالة تطبيق",
+ "Valid until" : "صالح حتى",
"Forum" : "منتدى",
- "Get the apps to sync your files" : "احصل على التطبيقات لمزامنة ملفاتك",
- "Show First Run Wizard again" : "ابدأ خطوات بداية التشغيل من جديد",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "تم إستهلاك <strong>%s</strong> من المتوفر <strong>%s</strong>",
+ "Profile picture" : "صورة الملف الشخصي",
+ "Upload new" : "رفع الان",
+ "Remove image" : "إزالة الصورة",
+ "Cancel" : "الغاء",
+ "Email" : "البريد الإلكترونى",
+ "Your email address" : "عنوانك البريدي",
"Password" : "كلمة المرور",
"Unable to change your password" : "لم يتم تعديل كلمة السر بنجاح",
"Current password" : "كلمات السر الحالية",
"New password" : "كلمات سر جديدة",
"Change password" : "عدل كلمة السر",
- "Email" : "البريد الإلكترونى",
- "Your email address" : "عنوانك البريدي",
- "Profile picture" : "صورة الملف الشخصي",
- "Upload new" : "رفع الان",
- "Select new from Files" : "اختر جديد من الملفات ",
- "Remove image" : "إزالة الصورة",
- "Your avatar is provided by your original account." : "صورتك الرمزية يتم توفيرها عن طريق حسابك الاصلي.",
- "Cancel" : "الغاء",
- "Choose as profile image" : "اختر صورة الملف الشخصي",
"Language" : "اللغة",
"Help translate" : "ساعد في الترجمه",
- "Valid until" : "صالح حتى",
+ "Get the apps to sync your files" : "احصل على التطبيقات لمزامنة ملفاتك",
+ "Show First Run Wizard again" : "ابدأ خطوات بداية التشغيل من جديد",
"Username" : "إسم المستخدم",
"Create" : "انشئ",
"Admin Recovery Password" : "استعادة كلمة المرور للمسؤول",
diff --git a/settings/l10n/ar.json b/settings/l10n/ar.json
index 1bd8a54f022..dd77ced97cf 100644
--- a/settings/l10n/ar.json
+++ b/settings/l10n/ar.json
@@ -2,11 +2,9 @@
"Sharing" : "مشاركة",
"Cron" : "مجدول",
"Log" : "سجل",
- "Authentication error" : "لم يتم التأكد من الشخصية بنجاح",
- "Your full name has been changed." : "اسمك الكامل تم تغييره.",
- "Unable to change full name" : "لم يتم التمكن من تغيير اسمك الكامل",
"Language changed" : "تم تغيير اللغة",
"Invalid request" : "طلب غير مفهوم",
+ "Authentication error" : "لم يتم التأكد من الشخصية بنجاح",
"Admins can't remove themself from the admin group" : "لا يستطيع المدير إزالة حسابه من مجموعة المديرين",
"Unable to add user to group %s" : "فشل إضافة المستخدم الى المجموعة %s",
"Unable to remove user from group %s" : "فشل إزالة المستخدم من المجموعة %s",
@@ -21,6 +19,8 @@
"test email settings" : "إعدادات البريد التجريبي",
"Email sent" : "تم ارسال البريد الالكتروني",
"Email saved" : "تم حفظ البريد الإلكتروني",
+ "Your full name has been changed." : "اسمك الكامل تم تغييره.",
+ "Unable to change full name" : "لم يتم التمكن من تغيير اسمك الكامل",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "هل أنت متأكد انك تريد إضافة \"{domain}\" كنطاق موثوق فيه.",
"Sending..." : "جاري الارسال ...",
"All" : "الكل",
@@ -34,12 +34,12 @@
"Updated" : "تم التحديث بنجاح",
"Uninstalling ...." : "جاري إلغاء التثبيت ...",
"Uninstall" : "ألغاء التثبيت",
+ "Delete" : "إلغاء",
"Select a profile picture" : "اختر صورة الملف الشخصي ",
"Very weak password" : "كلمة السر ضعيفة جدا",
"Weak password" : "كلمة السر ضعيفة",
"Good password" : "كلمة السر جيدة",
"Strong password" : "كلمة السر قوية",
- "Delete" : "إلغاء",
"Groups" : "مجموعات",
"undo" : "تراجع",
"never" : "بتاتا",
@@ -71,34 +71,28 @@
"Authentication method" : "أسلوب التطابق",
"Server address" : "عنوان الخادم",
"Port" : "المنفذ",
- "Log level" : "مستوى السجل",
"More" : "المزيد",
"Less" : "أقل",
"Version" : "إصدار",
- "by" : "من قبل",
"Documentation:" : "التوثيق",
"Uninstall App" : "أزالة تطبيق",
+ "Valid until" : "صالح حتى",
"Forum" : "منتدى",
- "Get the apps to sync your files" : "احصل على التطبيقات لمزامنة ملفاتك",
- "Show First Run Wizard again" : "ابدأ خطوات بداية التشغيل من جديد",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "تم إستهلاك <strong>%s</strong> من المتوفر <strong>%s</strong>",
+ "Profile picture" : "صورة الملف الشخصي",
+ "Upload new" : "رفع الان",
+ "Remove image" : "إزالة الصورة",
+ "Cancel" : "الغاء",
+ "Email" : "البريد الإلكترونى",
+ "Your email address" : "عنوانك البريدي",
"Password" : "كلمة المرور",
"Unable to change your password" : "لم يتم تعديل كلمة السر بنجاح",
"Current password" : "كلمات السر الحالية",
"New password" : "كلمات سر جديدة",
"Change password" : "عدل كلمة السر",
- "Email" : "البريد الإلكترونى",
- "Your email address" : "عنوانك البريدي",
- "Profile picture" : "صورة الملف الشخصي",
- "Upload new" : "رفع الان",
- "Select new from Files" : "اختر جديد من الملفات ",
- "Remove image" : "إزالة الصورة",
- "Your avatar is provided by your original account." : "صورتك الرمزية يتم توفيرها عن طريق حسابك الاصلي.",
- "Cancel" : "الغاء",
- "Choose as profile image" : "اختر صورة الملف الشخصي",
"Language" : "اللغة",
"Help translate" : "ساعد في الترجمه",
- "Valid until" : "صالح حتى",
+ "Get the apps to sync your files" : "احصل على التطبيقات لمزامنة ملفاتك",
+ "Show First Run Wizard again" : "ابدأ خطوات بداية التشغيل من جديد",
"Username" : "إسم المستخدم",
"Create" : "انشئ",
"Admin Recovery Password" : "استعادة كلمة المرور للمسؤول",
diff --git a/settings/l10n/ast.js b/settings/l10n/ast.js
index 56e47c9f263..50231cb8a75 100644
--- a/settings/l10n/ast.js
+++ b/settings/l10n/ast.js
@@ -6,12 +6,10 @@ OC.L10N.register(
"Cron" : "Cron",
"Log" : "Rexistru",
"Updates" : "Anovamientos",
- "Authentication error" : "Fallu d'autenticación",
- "Your full name has been changed." : "Camudóse'l nome completu.",
- "Unable to change full name" : "Nun pue camudase'l nome completu",
"Couldn't remove app." : "Nun pudo desaniciase l'aplicación.",
"Language changed" : "Camudóse la llingua",
"Invalid request" : "Solicitú inválida",
+ "Authentication error" : "Fallu d'autenticación",
"Admins can't remove themself from the admin group" : "Los alministradores nun puen desaniciase a ellos mesmos del grupu d'alministrador",
"Unable to add user to group %s" : "Nun pudo amestase l'usuariu al grupu %s",
"Unable to remove user from group %s" : "Nun pudo desaniciase al usuariu del grupu %s",
@@ -28,6 +26,8 @@ OC.L10N.register(
"Email sent" : "Corréu-e unviáu",
"You need to set your user email before being able to send test emails." : "Tienes de configurar la direición de corréu-e enantes de poder unviar mensaxes de prueba.",
"Email saved" : "Corréu-e guardáu",
+ "Your full name has been changed." : "Camudóse'l nome completu.",
+ "Unable to change full name" : "Nun pue camudase'l nome completu",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "¿De xuru que quies amestar \"{domain}\" como dominiu de confianza?",
"Add trusted domain" : "Amestar dominiu de confianza",
"Sending..." : "Unviando...",
@@ -43,14 +43,14 @@ OC.L10N.register(
"Uninstalling ...." : "Desinstalando ...",
"Error while uninstalling app" : "Fallu mientres se desinstalaba l'aplicación",
"Uninstall" : "Desinstalar",
+ "Valid until {date}" : "Válidu fasta {date}",
+ "Delete" : "Desaniciar",
"Select a profile picture" : "Esbillar una imaxe de perfil",
"Very weak password" : "Contraseña mui feble",
"Weak password" : "Contraseña feble",
"So-so password" : "Contraseña pasable",
"Good password" : "Contraseña bona",
"Strong password" : "Contraseña mui bona",
- "Valid until {date}" : "Válidu fasta {date}",
- "Delete" : "Desaniciar",
"Groups" : "Grupos",
"Unable to delete {objName}" : "Nun pue desaniciase {objName}",
"Error creating group" : "Fallu creando grupu",
@@ -65,7 +65,6 @@ OC.L10N.register(
"Error creating user" : "Fallu al crear usuariu",
"A valid password must be provided" : "Tien d'apurrise una contraseña válida",
"__language_name__" : "Asturianu",
- "SSL root certificates" : "Certificaos raíz SSL",
"Everything (fatal issues, errors, warnings, info, debug)" : "Too (Información, Avisos, Fallos, debug y problemes fatales)",
"Info, warnings, errors and fatal issues" : "Información, Avisos, Fallos y problemes fatales",
"Warnings, errors and fatal issues" : "Avisos, fallos y problemes fatales",
@@ -113,39 +112,32 @@ OC.L10N.register(
"SMTP Password" : "Contraseña SMTP",
"Test email settings" : "Probar configuración de corréu electrónicu",
"Send email" : "Unviar mensaxe",
- "Log level" : "Nivel de rexistru",
"More" : "Más",
"Less" : "Menos",
"Version" : "Versión",
- "by" : "por",
"Documentation:" : "Documentación:",
"Enable only for specific groups" : "Habilitar namái pa grupos específicos",
"Uninstall App" : "Desinstalar aplicación",
"Cheers!" : "¡Salú!",
"Forum" : "Foru",
- "Get the apps to sync your files" : "Obtener les aplicaciones pa sincronizar ficheros",
- "Desktop client" : "Cliente d'escritoriu",
- "Android app" : "Aplicación d'Android",
- "iOS app" : "Aplicación d'iOS",
- "Show First Run Wizard again" : "Amosar nuevamente l'Encontu d'execución inicial",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Usasti <strong>%s</strong> de los <strong>%s</strong> disponibles",
+ "Profile picture" : "Semeya de perfil",
+ "Upload new" : "Xubir otra",
+ "Remove image" : "Desaniciar imaxe",
+ "Cancel" : "Encaboxar",
+ "Email" : "Corréu-e",
+ "Your email address" : "Direición de corréu-e",
"Password" : "Contraseña",
"Unable to change your password" : "Nun pudo camudase la contraseña",
"Current password" : "Contraseña actual",
"New password" : "Contraseña nueva",
"Change password" : "Camudar contraseña",
- "Email" : "Corréu-e",
- "Your email address" : "Direición de corréu-e",
- "Fill in an email address to enable password recovery and receive notifications" : "Introducir una direición de corréu-e p'activar la recuperación de contraseñes y recibir notificaciones",
- "Profile picture" : "Semeya de perfil",
- "Upload new" : "Xubir otra",
- "Select new from Files" : "Esbillar otra dende Ficheros",
- "Remove image" : "Desaniciar imaxe",
- "Your avatar is provided by your original account." : "L'avatar ta proporcionáu pola to cuenta orixinal.",
- "Cancel" : "Encaboxar",
- "Choose as profile image" : "Esbillar como imaxe de perfil",
"Language" : "Llingua",
"Help translate" : "Ayúdanos nes traducciones",
+ "Get the apps to sync your files" : "Obtener les aplicaciones pa sincronizar ficheros",
+ "Desktop client" : "Cliente d'escritoriu",
+ "Android app" : "Aplicación d'Android",
+ "iOS app" : "Aplicación d'iOS",
+ "Show First Run Wizard again" : "Amosar nuevamente l'Encontu d'execución inicial",
"Username" : "Nome d'usuariu",
"Create" : "Crear",
"Admin Recovery Password" : "Recuperación de la contraseña d'alministración",
diff --git a/settings/l10n/ast.json b/settings/l10n/ast.json
index 3d976d01145..7199f8619d0 100644
--- a/settings/l10n/ast.json
+++ b/settings/l10n/ast.json
@@ -4,12 +4,10 @@
"Cron" : "Cron",
"Log" : "Rexistru",
"Updates" : "Anovamientos",
- "Authentication error" : "Fallu d'autenticación",
- "Your full name has been changed." : "Camudóse'l nome completu.",
- "Unable to change full name" : "Nun pue camudase'l nome completu",
"Couldn't remove app." : "Nun pudo desaniciase l'aplicación.",
"Language changed" : "Camudóse la llingua",
"Invalid request" : "Solicitú inválida",
+ "Authentication error" : "Fallu d'autenticación",
"Admins can't remove themself from the admin group" : "Los alministradores nun puen desaniciase a ellos mesmos del grupu d'alministrador",
"Unable to add user to group %s" : "Nun pudo amestase l'usuariu al grupu %s",
"Unable to remove user from group %s" : "Nun pudo desaniciase al usuariu del grupu %s",
@@ -26,6 +24,8 @@
"Email sent" : "Corréu-e unviáu",
"You need to set your user email before being able to send test emails." : "Tienes de configurar la direición de corréu-e enantes de poder unviar mensaxes de prueba.",
"Email saved" : "Corréu-e guardáu",
+ "Your full name has been changed." : "Camudóse'l nome completu.",
+ "Unable to change full name" : "Nun pue camudase'l nome completu",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "¿De xuru que quies amestar \"{domain}\" como dominiu de confianza?",
"Add trusted domain" : "Amestar dominiu de confianza",
"Sending..." : "Unviando...",
@@ -41,14 +41,14 @@
"Uninstalling ...." : "Desinstalando ...",
"Error while uninstalling app" : "Fallu mientres se desinstalaba l'aplicación",
"Uninstall" : "Desinstalar",
+ "Valid until {date}" : "Válidu fasta {date}",
+ "Delete" : "Desaniciar",
"Select a profile picture" : "Esbillar una imaxe de perfil",
"Very weak password" : "Contraseña mui feble",
"Weak password" : "Contraseña feble",
"So-so password" : "Contraseña pasable",
"Good password" : "Contraseña bona",
"Strong password" : "Contraseña mui bona",
- "Valid until {date}" : "Válidu fasta {date}",
- "Delete" : "Desaniciar",
"Groups" : "Grupos",
"Unable to delete {objName}" : "Nun pue desaniciase {objName}",
"Error creating group" : "Fallu creando grupu",
@@ -63,7 +63,6 @@
"Error creating user" : "Fallu al crear usuariu",
"A valid password must be provided" : "Tien d'apurrise una contraseña válida",
"__language_name__" : "Asturianu",
- "SSL root certificates" : "Certificaos raíz SSL",
"Everything (fatal issues, errors, warnings, info, debug)" : "Too (Información, Avisos, Fallos, debug y problemes fatales)",
"Info, warnings, errors and fatal issues" : "Información, Avisos, Fallos y problemes fatales",
"Warnings, errors and fatal issues" : "Avisos, fallos y problemes fatales",
@@ -111,39 +110,32 @@
"SMTP Password" : "Contraseña SMTP",
"Test email settings" : "Probar configuración de corréu electrónicu",
"Send email" : "Unviar mensaxe",
- "Log level" : "Nivel de rexistru",
"More" : "Más",
"Less" : "Menos",
"Version" : "Versión",
- "by" : "por",
"Documentation:" : "Documentación:",
"Enable only for specific groups" : "Habilitar namái pa grupos específicos",
"Uninstall App" : "Desinstalar aplicación",
"Cheers!" : "¡Salú!",
"Forum" : "Foru",
- "Get the apps to sync your files" : "Obtener les aplicaciones pa sincronizar ficheros",
- "Desktop client" : "Cliente d'escritoriu",
- "Android app" : "Aplicación d'Android",
- "iOS app" : "Aplicación d'iOS",
- "Show First Run Wizard again" : "Amosar nuevamente l'Encontu d'execución inicial",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Usasti <strong>%s</strong> de los <strong>%s</strong> disponibles",
+ "Profile picture" : "Semeya de perfil",
+ "Upload new" : "Xubir otra",
+ "Remove image" : "Desaniciar imaxe",
+ "Cancel" : "Encaboxar",
+ "Email" : "Corréu-e",
+ "Your email address" : "Direición de corréu-e",
"Password" : "Contraseña",
"Unable to change your password" : "Nun pudo camudase la contraseña",
"Current password" : "Contraseña actual",
"New password" : "Contraseña nueva",
"Change password" : "Camudar contraseña",
- "Email" : "Corréu-e",
- "Your email address" : "Direición de corréu-e",
- "Fill in an email address to enable password recovery and receive notifications" : "Introducir una direición de corréu-e p'activar la recuperación de contraseñes y recibir notificaciones",
- "Profile picture" : "Semeya de perfil",
- "Upload new" : "Xubir otra",
- "Select new from Files" : "Esbillar otra dende Ficheros",
- "Remove image" : "Desaniciar imaxe",
- "Your avatar is provided by your original account." : "L'avatar ta proporcionáu pola to cuenta orixinal.",
- "Cancel" : "Encaboxar",
- "Choose as profile image" : "Esbillar como imaxe de perfil",
"Language" : "Llingua",
"Help translate" : "Ayúdanos nes traducciones",
+ "Get the apps to sync your files" : "Obtener les aplicaciones pa sincronizar ficheros",
+ "Desktop client" : "Cliente d'escritoriu",
+ "Android app" : "Aplicación d'Android",
+ "iOS app" : "Aplicación d'iOS",
+ "Show First Run Wizard again" : "Amosar nuevamente l'Encontu d'execución inicial",
"Username" : "Nome d'usuariu",
"Create" : "Crear",
"Admin Recovery Password" : "Recuperación de la contraseña d'alministración",
diff --git a/settings/l10n/az.js b/settings/l10n/az.js
index f1c034013bb..cb9919a5d7c 100644
--- a/settings/l10n/az.js
+++ b/settings/l10n/az.js
@@ -7,12 +7,10 @@ OC.L10N.register(
"Cron" : "Cron",
"Log" : "Jurnal",
"Updates" : "Yenilənmələr",
- "Authentication error" : "Təyinat metodikası",
- "Your full name has been changed." : "Sizin tam adınız dəyişdirildi.",
- "Unable to change full name" : "Tam adı dəyişmək olmur",
"Couldn't remove app." : "Proqram təminatını silmək mümkün olmadı.",
"Language changed" : "Dil dəyişdirildi",
"Invalid request" : "Səhv müraciət",
+ "Authentication error" : "Təyinat metodikası",
"Admins can't remove themself from the admin group" : "İnzibatçılar özlərini inzibatçı qrupundan silə bilməz",
"Unable to add user to group %s" : "İstifadəçini %s qrupuna əlavə etmək mümkün olmadı",
"Unable to remove user from group %s" : "İstifadəçini %s qrupundan silmək mümkün olmadı",
@@ -44,6 +42,8 @@ OC.L10N.register(
"Invalid user" : "İstifadəçi adı yalnışdır",
"Unable to change mail address" : "Mail ünvanını dəyişmək olmur",
"Email saved" : "Məktub yadda saxlanıldı",
+ "Your full name has been changed." : "Sizin tam adınız dəyişdirildi.",
+ "Unable to change full name" : "Tam adı dəyişmək olmur",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "\"{domain}\" adını inamlı domainlər siyahısına əlavə etməyinizdən əminsinizmi?",
"Add trusted domain" : "İnamlı domainlərə əlavə et",
"Sending..." : "Göndərilir...",
@@ -61,14 +61,14 @@ OC.L10N.register(
"Uninstalling ...." : "Silinir...",
"Error while uninstalling app" : "Proqram təminatını sildikdə səhv baş verdi",
"Uninstall" : "Sil",
+ "Valid until {date}" : "Müddətədək keçərlidir {date}",
+ "Delete" : "Sil",
"Select a profile picture" : "Profil üçün şəkli seç",
"Very weak password" : "Çox asan şifrə",
"Weak password" : "Asan şifrə",
"So-so password" : "Elə-belə şifrə",
"Good password" : "Yaxşı şifrə",
"Strong password" : "Çətin şifrə",
- "Valid until {date}" : "Müddətədək keçərlidir {date}",
- "Delete" : "Sil",
"Groups" : "Qruplar",
"Unable to delete {objName}" : "{objName} silmək olmur",
"Error creating group" : "Qrup yaranmasında səhv baş verdi",
@@ -85,9 +85,8 @@ OC.L10N.register(
"A valid password must be provided" : "Düzgün şifrə daxil edilməlidir",
"A valid email must be provided" : "Düzgün email təqdim edilməlidir",
"__language_name__" : "__AZ_Azerbaijan__",
- "Sync clients" : "Müştəriləri sinxronizasiya et",
"Personal info" : "Şəxsi məlumat",
- "SSL root certificates" : "SSL root sertifikatları",
+ "Sync clients" : "Müştəriləri sinxronizasiya et",
"Everything (fatal issues, errors, warnings, info, debug)" : "Hər şey(ən pis hadisələr, səhvlər, xəbərdarlıqlar, məlmat, araşdırma səhvləri)",
"Info, warnings, errors and fatal issues" : "Məlmat, xəbərdarlıqlar, səhvlər və ən pis hadisələr",
"Warnings, errors and fatal issues" : "Xəbərdarlıqlar, səhvlər və ən pis hadisələr",
@@ -145,7 +144,6 @@ OC.L10N.register(
"Store credentials" : "Səlahiyyətləri saxla",
"Test email settings" : "Email qurmalarını test et",
"Send email" : "Email yolla",
- "Log level" : "Jurnal səviyyəsi",
"Download logfile" : "Jurnal faylını endir",
"More" : "Yenə",
"Less" : "Az",
@@ -156,51 +154,44 @@ OC.L10N.register(
"Advanced monitoring" : "İrəliləmiş monitoring",
"Version" : "Versiya",
"Developer documentation" : "Yaradıcı sənədləşməsi",
- "by" : "onunla",
- "licensed" : "Lisenziyalaşdırılıb",
"Documentation:" : "Sənədləşmə:",
"Show description …" : "Açıqlanmanı göstər ...",
"Hide description …" : "Açıqlamanı gizlət ...",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Bu proqram yüklənə bilməz ona görə ki, göstərilən asılılıqlar yerinə yetirilməyib:",
"Enable only for specific groups" : "Yalnız spesifik qruplara izin ver",
"Uninstall App" : "Proqram təminatını sil",
+ "Common Name" : "Ümumi ad",
+ "Valid until" : "Vaxtadək keçərlidir",
+ "Issued By" : "Tərəfindən yaradılıb",
+ "Valid until %s" : "Keçərlidir vaxtadək %s",
+ "Import root certificate" : "root sertifikatı import et",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Ey ora,<br><br>ancaq deyirik ki, sizin artiq %s hesabınız var.<br><br>Sizin istifadəçi adınız: %s<br>Yetkilidir: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Şərəfə!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ey ora,\n\nancaq deyirik ki, sizin artiq %s hesabınız var.\n\nizin istifadəçi adınız: %s\nYetkilidir: %s\n\n",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Fayllarınızın sinxronizasiyası üçün proqramları götürün",
- "Desktop client" : "Desktop client",
- "Android app" : "Android proqramı",
- "iOS app" : "iOS proqramı",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Əgər siz proektə dəstək vermək istəyirsinizsə\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">Təkmilləşdirməyə üzv</a>\n\t\tyada\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">söz yaymaq</a>!",
- "Show First Run Wizard again" : "İlk işəsalma sehirbazını yenidən göstər",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Siz istifadə etdiniz <strong>%s</strong> mövcud olan <strong>%s</strong>",
- "Password" : "Şifrə",
- "Unable to change your password" : "Sizin şifrəni dəyişmək mümkün olmadı",
- "Current password" : "Hazırkı şifrə",
- "New password" : "Yeni şifrə",
- "Change password" : "Şifrəni dəyiş",
+ "Profile picture" : "Profil şəkli",
+ "Upload new" : "Yenisini yüklə",
+ "Remove image" : "Şəkili sil",
+ "Cancel" : "Dayandır",
"Full name" : "Tam ad",
"No display name set" : "Ekranda adı dəsti yoxdur",
"Email" : "Email",
"Your email address" : "Sizin email ünvanı",
- "Fill in an email address to enable password recovery and receive notifications" : "Email ünvanını doldurun ki, sifrənizin bərpa edilməsini işə salasınız və məktubla xəbərdarlıqları qəbul edəsiniz.",
"No email address set" : "Email ünvanı dəsti yoxdur",
"You are member of the following groups:" : "Siz göstərilən qrupların üzvüsünüz:",
- "Profile picture" : "Profil şəkli",
- "Upload new" : "Yenisini yüklə",
- "Select new from Files" : "Fayllardan yenisini seç",
- "Remove image" : "Şəkili sil",
- "Your avatar is provided by your original account." : "Sizin avatar sizin original hesab tərəfindən təqdim edilib.",
- "Cancel" : "Dayandır",
- "Choose as profile image" : "Profayl şəklini seçin",
+ "Password" : "Şifrə",
+ "Unable to change your password" : "Sizin şifrəni dəyişmək mümkün olmadı",
+ "Current password" : "Hazırkı şifrə",
+ "New password" : "Yeni şifrə",
+ "Change password" : "Şifrəni dəyiş",
"Language" : "Dil",
"Help translate" : "Tərcüməyə kömək",
- "Common Name" : "Ümumi ad",
- "Valid until" : "Vaxtadək keçərlidir",
- "Issued By" : "Tərəfindən yaradılıb",
- "Valid until %s" : "Keçərlidir vaxtadək %s",
- "Import root certificate" : "root sertifikatı import et",
+ "Get the apps to sync your files" : "Fayllarınızın sinxronizasiyası üçün proqramları götürün",
+ "Desktop client" : "Desktop client",
+ "Android app" : "Android proqramı",
+ "iOS app" : "iOS proqramı",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Əgər siz proektə dəstək vermək istəyirsinizsə\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">Təkmilləşdirməyə üzv</a>\n\t\tyada\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">söz yaymaq</a>!",
+ "Show First Run Wizard again" : "İlk işəsalma sehirbazını yenidən göstər",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Tərəfindən yaradılıb{communityopen}ownCloud cəmiyyəti{linkclose}, {githubopen}mənbə kodları{linkclose} altında lisenziya edilib {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Depo ünvanını göstər",
"Show last log in" : "Son girişi göstər",
diff --git a/settings/l10n/az.json b/settings/l10n/az.json
index b67082c4269..b33258ac776 100644
--- a/settings/l10n/az.json
+++ b/settings/l10n/az.json
@@ -5,12 +5,10 @@
"Cron" : "Cron",
"Log" : "Jurnal",
"Updates" : "Yenilənmələr",
- "Authentication error" : "Təyinat metodikası",
- "Your full name has been changed." : "Sizin tam adınız dəyişdirildi.",
- "Unable to change full name" : "Tam adı dəyişmək olmur",
"Couldn't remove app." : "Proqram təminatını silmək mümkün olmadı.",
"Language changed" : "Dil dəyişdirildi",
"Invalid request" : "Səhv müraciət",
+ "Authentication error" : "Təyinat metodikası",
"Admins can't remove themself from the admin group" : "İnzibatçılar özlərini inzibatçı qrupundan silə bilməz",
"Unable to add user to group %s" : "İstifadəçini %s qrupuna əlavə etmək mümkün olmadı",
"Unable to remove user from group %s" : "İstifadəçini %s qrupundan silmək mümkün olmadı",
@@ -42,6 +40,8 @@
"Invalid user" : "İstifadəçi adı yalnışdır",
"Unable to change mail address" : "Mail ünvanını dəyişmək olmur",
"Email saved" : "Məktub yadda saxlanıldı",
+ "Your full name has been changed." : "Sizin tam adınız dəyişdirildi.",
+ "Unable to change full name" : "Tam adı dəyişmək olmur",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "\"{domain}\" adını inamlı domainlər siyahısına əlavə etməyinizdən əminsinizmi?",
"Add trusted domain" : "İnamlı domainlərə əlavə et",
"Sending..." : "Göndərilir...",
@@ -59,14 +59,14 @@
"Uninstalling ...." : "Silinir...",
"Error while uninstalling app" : "Proqram təminatını sildikdə səhv baş verdi",
"Uninstall" : "Sil",
+ "Valid until {date}" : "Müddətədək keçərlidir {date}",
+ "Delete" : "Sil",
"Select a profile picture" : "Profil üçün şəkli seç",
"Very weak password" : "Çox asan şifrə",
"Weak password" : "Asan şifrə",
"So-so password" : "Elə-belə şifrə",
"Good password" : "Yaxşı şifrə",
"Strong password" : "Çətin şifrə",
- "Valid until {date}" : "Müddətədək keçərlidir {date}",
- "Delete" : "Sil",
"Groups" : "Qruplar",
"Unable to delete {objName}" : "{objName} silmək olmur",
"Error creating group" : "Qrup yaranmasında səhv baş verdi",
@@ -83,9 +83,8 @@
"A valid password must be provided" : "Düzgün şifrə daxil edilməlidir",
"A valid email must be provided" : "Düzgün email təqdim edilməlidir",
"__language_name__" : "__AZ_Azerbaijan__",
- "Sync clients" : "Müştəriləri sinxronizasiya et",
"Personal info" : "Şəxsi məlumat",
- "SSL root certificates" : "SSL root sertifikatları",
+ "Sync clients" : "Müştəriləri sinxronizasiya et",
"Everything (fatal issues, errors, warnings, info, debug)" : "Hər şey(ən pis hadisələr, səhvlər, xəbərdarlıqlar, məlmat, araşdırma səhvləri)",
"Info, warnings, errors and fatal issues" : "Məlmat, xəbərdarlıqlar, səhvlər və ən pis hadisələr",
"Warnings, errors and fatal issues" : "Xəbərdarlıqlar, səhvlər və ən pis hadisələr",
@@ -143,7 +142,6 @@
"Store credentials" : "Səlahiyyətləri saxla",
"Test email settings" : "Email qurmalarını test et",
"Send email" : "Email yolla",
- "Log level" : "Jurnal səviyyəsi",
"Download logfile" : "Jurnal faylını endir",
"More" : "Yenə",
"Less" : "Az",
@@ -154,51 +152,44 @@
"Advanced monitoring" : "İrəliləmiş monitoring",
"Version" : "Versiya",
"Developer documentation" : "Yaradıcı sənədləşməsi",
- "by" : "onunla",
- "licensed" : "Lisenziyalaşdırılıb",
"Documentation:" : "Sənədləşmə:",
"Show description …" : "Açıqlanmanı göstər ...",
"Hide description …" : "Açıqlamanı gizlət ...",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Bu proqram yüklənə bilməz ona görə ki, göstərilən asılılıqlar yerinə yetirilməyib:",
"Enable only for specific groups" : "Yalnız spesifik qruplara izin ver",
"Uninstall App" : "Proqram təminatını sil",
+ "Common Name" : "Ümumi ad",
+ "Valid until" : "Vaxtadək keçərlidir",
+ "Issued By" : "Tərəfindən yaradılıb",
+ "Valid until %s" : "Keçərlidir vaxtadək %s",
+ "Import root certificate" : "root sertifikatı import et",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Ey ora,<br><br>ancaq deyirik ki, sizin artiq %s hesabınız var.<br><br>Sizin istifadəçi adınız: %s<br>Yetkilidir: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Şərəfə!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ey ora,\n\nancaq deyirik ki, sizin artiq %s hesabınız var.\n\nizin istifadəçi adınız: %s\nYetkilidir: %s\n\n",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Fayllarınızın sinxronizasiyası üçün proqramları götürün",
- "Desktop client" : "Desktop client",
- "Android app" : "Android proqramı",
- "iOS app" : "iOS proqramı",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Əgər siz proektə dəstək vermək istəyirsinizsə\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">Təkmilləşdirməyə üzv</a>\n\t\tyada\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">söz yaymaq</a>!",
- "Show First Run Wizard again" : "İlk işəsalma sehirbazını yenidən göstər",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Siz istifadə etdiniz <strong>%s</strong> mövcud olan <strong>%s</strong>",
- "Password" : "Şifrə",
- "Unable to change your password" : "Sizin şifrəni dəyişmək mümkün olmadı",
- "Current password" : "Hazırkı şifrə",
- "New password" : "Yeni şifrə",
- "Change password" : "Şifrəni dəyiş",
+ "Profile picture" : "Profil şəkli",
+ "Upload new" : "Yenisini yüklə",
+ "Remove image" : "Şəkili sil",
+ "Cancel" : "Dayandır",
"Full name" : "Tam ad",
"No display name set" : "Ekranda adı dəsti yoxdur",
"Email" : "Email",
"Your email address" : "Sizin email ünvanı",
- "Fill in an email address to enable password recovery and receive notifications" : "Email ünvanını doldurun ki, sifrənizin bərpa edilməsini işə salasınız və məktubla xəbərdarlıqları qəbul edəsiniz.",
"No email address set" : "Email ünvanı dəsti yoxdur",
"You are member of the following groups:" : "Siz göstərilən qrupların üzvüsünüz:",
- "Profile picture" : "Profil şəkli",
- "Upload new" : "Yenisini yüklə",
- "Select new from Files" : "Fayllardan yenisini seç",
- "Remove image" : "Şəkili sil",
- "Your avatar is provided by your original account." : "Sizin avatar sizin original hesab tərəfindən təqdim edilib.",
- "Cancel" : "Dayandır",
- "Choose as profile image" : "Profayl şəklini seçin",
+ "Password" : "Şifrə",
+ "Unable to change your password" : "Sizin şifrəni dəyişmək mümkün olmadı",
+ "Current password" : "Hazırkı şifrə",
+ "New password" : "Yeni şifrə",
+ "Change password" : "Şifrəni dəyiş",
"Language" : "Dil",
"Help translate" : "Tərcüməyə kömək",
- "Common Name" : "Ümumi ad",
- "Valid until" : "Vaxtadək keçərlidir",
- "Issued By" : "Tərəfindən yaradılıb",
- "Valid until %s" : "Keçərlidir vaxtadək %s",
- "Import root certificate" : "root sertifikatı import et",
+ "Get the apps to sync your files" : "Fayllarınızın sinxronizasiyası üçün proqramları götürün",
+ "Desktop client" : "Desktop client",
+ "Android app" : "Android proqramı",
+ "iOS app" : "iOS proqramı",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Əgər siz proektə dəstək vermək istəyirsinizsə\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">Təkmilləşdirməyə üzv</a>\n\t\tyada\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">söz yaymaq</a>!",
+ "Show First Run Wizard again" : "İlk işəsalma sehirbazını yenidən göstər",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Tərəfindən yaradılıb{communityopen}ownCloud cəmiyyəti{linkclose}, {githubopen}mənbə kodları{linkclose} altında lisenziya edilib {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Depo ünvanını göstər",
"Show last log in" : "Son girişi göstər",
diff --git a/settings/l10n/bg_BG.js b/settings/l10n/bg_BG.js
index caef15f4bff..4235055ec51 100644
--- a/settings/l10n/bg_BG.js
+++ b/settings/l10n/bg_BG.js
@@ -7,12 +7,10 @@ OC.L10N.register(
"Cron" : "Крон",
"Log" : "Лог",
"Updates" : "Обновления",
- "Authentication error" : "Възникна проблем с идентификацията",
- "Your full name has been changed." : "Вашето пълно име е променено.",
- "Unable to change full name" : "Неуспешна промяна на пълното име.",
"Couldn't remove app." : "Неуспешно премахване на приложението.",
"Language changed" : "Езикът е променен",
"Invalid request" : "Невалидна заявка",
+ "Authentication error" : "Възникна проблем с идентификацията",
"Admins can't remove themself from the admin group" : "Администраторите не могат да премахват себе си от групата \"admin\".",
"Unable to add user to group %s" : "Неуспешно добавяне на потребител към групата %s.",
"Unable to remove user from group %s" : "Неуспешно премахване на потребител от групата %s.",
@@ -43,6 +41,8 @@ OC.L10N.register(
"Invalid user" : "Невалиден протребител",
"Unable to change mail address" : "Неуспешна промяна на адрес на електронна поща",
"Email saved" : "Имейлът е запазен",
+ "Your full name has been changed." : "Вашето пълно име е променено.",
+ "Unable to change full name" : "Неуспешна промяна на пълното име.",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Сигурен/на ли сте, че искате \"{domain}\" да бъде добавен като сигурен домейн?",
"Add trusted domain" : "Добавяне на сигурен домейн",
"Sending..." : "Изпращане...",
@@ -60,14 +60,14 @@ OC.L10N.register(
"Uninstalling ...." : "Премахване ...",
"Error while uninstalling app" : "Грешка при премахването на приложението",
"Uninstall" : "Премахване",
+ "Valid until {date}" : "Далидна до {date}",
+ "Delete" : "Изтриване",
"Select a profile picture" : "Избиране на профилна снимка",
"Very weak password" : "Много слаба парола",
"Weak password" : "Слаба парола",
"So-so password" : "Не особено добра парола",
"Good password" : "Добра парола",
"Strong password" : "Сигурна парола",
- "Valid until {date}" : "Далидна до {date}",
- "Delete" : "Изтриване",
"Groups" : "Групи",
"Unable to delete {objName}" : "Неуспешно изтриване на {objName}.",
"Error creating group" : "Грешка при създаване на група",
@@ -84,9 +84,8 @@ OC.L10N.register(
"A valid password must be provided" : "Трябва да бъде зададена валидна парола",
"A valid email must be provided" : "Трябва да бъде зададена валидна електронна поща",
"__language_name__" : "Български",
- "Sync clients" : "Синхронизиращи клиенти",
"Personal info" : "Лична информация",
- "SSL root certificates" : "SSL root сертификати",
+ "Sync clients" : "Синхронизиращи клиенти",
"Everything (fatal issues, errors, warnings, info, debug)" : "Всичко (фатални проблеми, грешки, предупреждения, информация, дебъгване)",
"Info, warnings, errors and fatal issues" : "информация, предупреждения, грешки и фатални проблеми",
"Warnings, errors and fatal issues" : "Предупреждения, грешки и фатални проблеми",
@@ -142,7 +141,6 @@ OC.L10N.register(
"Store credentials" : "Запазвай креденциите",
"Test email settings" : "Настройки на проверяващия имейл",
"Send email" : "Изпрати имейл",
- "Log level" : "Детайли на доклада",
"Download logfile" : "Изтегли log файла",
"More" : "Още",
"Less" : "По-малко",
@@ -156,51 +154,44 @@ OC.L10N.register(
"Theming" : "Промяна на облика",
"Version" : "Версия",
"Developer documentation" : "Документация за разработчици",
- "by" : "от",
- "licensed" : "лицензирано",
"Documentation:" : "Документация:",
"Show description …" : "Покажи описание ...",
"Hide description …" : "Скрии описание ...",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Това приложение не може да бъде инсталирано, защото следните зависимости не са удовлетворени:",
"Enable only for specific groups" : "Включи само за определени групи",
"Uninstall App" : "Премахни Приложението",
+ "Common Name" : "Познато Име",
+ "Valid until" : "Валиден до",
+ "Issued By" : "Издаден От",
+ "Valid until %s" : "Валиден до %s",
+ "Import root certificate" : "Импортиране на основен сертификат",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Здрасти,<br><br>Само да ти кажа, че имаш %s профил<br><br> Потребителя ти е: %s<br>Достъпи го: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Поздрави!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Здрасти,\n\nСамо да ти кажа, че имаш %s профил.\n\nПотребителя ти е: %s\nДостъпи го: %s\n",
"Forum" : "Форум",
- "Get the apps to sync your files" : "Изтегли програми за синхронизиране на файловете ти",
- "Desktop client" : "Клиент за настолен компютър",
- "Android app" : "Андроид приложение",
- "iOS app" : "iOS приложение",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ако искаш да помогнеш на проекта:\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">присъедини се и пиши код</a>\n\t\tили\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">разпространи мълвата</a>!",
- "Show First Run Wizard again" : "Покажи Настройките за Първоначално Зареждане отново",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Използвал си <strong>%s</strong> от наличните <strong>%s</strong>.",
- "Password" : "Парола",
- "Unable to change your password" : "Неуспешна промяна на паролата.",
- "Current password" : "Текуща парола",
- "New password" : "Нова парола",
- "Change password" : "Промяна на паролата",
+ "Profile picture" : "Аватар",
+ "Upload new" : "Качи нов",
+ "Remove image" : "Премахни изображението",
+ "Cancel" : "Отказ",
"Full name" : "Пълно име",
"No display name set" : "Няма настроено екранно име",
"Email" : "Имейл",
"Your email address" : "Твоят имейл адрес",
- "Fill in an email address to enable password recovery and receive notifications" : "Въведи имейл, за да включиш функцията за възстановяване на паролата и уведомления.",
"No email address set" : "Няма настроен адрес на електронна поща",
"You are member of the following groups:" : "Ти си член на следните групи:",
- "Profile picture" : "Аватар",
- "Upload new" : "Качи нов",
- "Select new from Files" : "Избери нов от Файловете",
- "Remove image" : "Премахни изображението",
- "Your avatar is provided by your original account." : "Твоят аватар е взет от оригиналния ти профил.",
- "Cancel" : "Отказ",
- "Choose as profile image" : "Избери като аватар",
+ "Password" : "Парола",
+ "Unable to change your password" : "Неуспешна промяна на паролата.",
+ "Current password" : "Текуща парола",
+ "New password" : "Нова парола",
+ "Change password" : "Промяна на паролата",
"Language" : "Език",
"Help translate" : "Помогни с превода",
- "Common Name" : "Познато Име",
- "Valid until" : "Валиден до",
- "Issued By" : "Издаден От",
- "Valid until %s" : "Валиден до %s",
- "Import root certificate" : "Импортиране на основен сертификат",
+ "Get the apps to sync your files" : "Изтегли програми за синхронизиране на файловете ти",
+ "Desktop client" : "Клиент за настолен компютър",
+ "Android app" : "Андроид приложение",
+ "iOS app" : "iOS приложение",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ако искаш да помогнеш на проекта:\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">присъедини се и пиши код</a>\n\t\tили\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">разпространи мълвата</a>!",
+ "Show First Run Wizard again" : "Покажи Настройките за Първоначално Зареждане отново",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Разработен от {communityopen}ownCloud общността {linkclose}, {githubopen}изходящия код{linkclose} е лицензиран под {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Покажи място за запис",
"Show last log in" : "Покажи последно вписване",
diff --git a/settings/l10n/bg_BG.json b/settings/l10n/bg_BG.json
index cf4bcb5182a..cb85664c1ad 100644
--- a/settings/l10n/bg_BG.json
+++ b/settings/l10n/bg_BG.json
@@ -5,12 +5,10 @@
"Cron" : "Крон",
"Log" : "Лог",
"Updates" : "Обновления",
- "Authentication error" : "Възникна проблем с идентификацията",
- "Your full name has been changed." : "Вашето пълно име е променено.",
- "Unable to change full name" : "Неуспешна промяна на пълното име.",
"Couldn't remove app." : "Неуспешно премахване на приложението.",
"Language changed" : "Езикът е променен",
"Invalid request" : "Невалидна заявка",
+ "Authentication error" : "Възникна проблем с идентификацията",
"Admins can't remove themself from the admin group" : "Администраторите не могат да премахват себе си от групата \"admin\".",
"Unable to add user to group %s" : "Неуспешно добавяне на потребител към групата %s.",
"Unable to remove user from group %s" : "Неуспешно премахване на потребител от групата %s.",
@@ -41,6 +39,8 @@
"Invalid user" : "Невалиден протребител",
"Unable to change mail address" : "Неуспешна промяна на адрес на електронна поща",
"Email saved" : "Имейлът е запазен",
+ "Your full name has been changed." : "Вашето пълно име е променено.",
+ "Unable to change full name" : "Неуспешна промяна на пълното име.",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Сигурен/на ли сте, че искате \"{domain}\" да бъде добавен като сигурен домейн?",
"Add trusted domain" : "Добавяне на сигурен домейн",
"Sending..." : "Изпращане...",
@@ -58,14 +58,14 @@
"Uninstalling ...." : "Премахване ...",
"Error while uninstalling app" : "Грешка при премахването на приложението",
"Uninstall" : "Премахване",
+ "Valid until {date}" : "Далидна до {date}",
+ "Delete" : "Изтриване",
"Select a profile picture" : "Избиране на профилна снимка",
"Very weak password" : "Много слаба парола",
"Weak password" : "Слаба парола",
"So-so password" : "Не особено добра парола",
"Good password" : "Добра парола",
"Strong password" : "Сигурна парола",
- "Valid until {date}" : "Далидна до {date}",
- "Delete" : "Изтриване",
"Groups" : "Групи",
"Unable to delete {objName}" : "Неуспешно изтриване на {objName}.",
"Error creating group" : "Грешка при създаване на група",
@@ -82,9 +82,8 @@
"A valid password must be provided" : "Трябва да бъде зададена валидна парола",
"A valid email must be provided" : "Трябва да бъде зададена валидна електронна поща",
"__language_name__" : "Български",
- "Sync clients" : "Синхронизиращи клиенти",
"Personal info" : "Лична информация",
- "SSL root certificates" : "SSL root сертификати",
+ "Sync clients" : "Синхронизиращи клиенти",
"Everything (fatal issues, errors, warnings, info, debug)" : "Всичко (фатални проблеми, грешки, предупреждения, информация, дебъгване)",
"Info, warnings, errors and fatal issues" : "информация, предупреждения, грешки и фатални проблеми",
"Warnings, errors and fatal issues" : "Предупреждения, грешки и фатални проблеми",
@@ -140,7 +139,6 @@
"Store credentials" : "Запазвай креденциите",
"Test email settings" : "Настройки на проверяващия имейл",
"Send email" : "Изпрати имейл",
- "Log level" : "Детайли на доклада",
"Download logfile" : "Изтегли log файла",
"More" : "Още",
"Less" : "По-малко",
@@ -154,51 +152,44 @@
"Theming" : "Промяна на облика",
"Version" : "Версия",
"Developer documentation" : "Документация за разработчици",
- "by" : "от",
- "licensed" : "лицензирано",
"Documentation:" : "Документация:",
"Show description …" : "Покажи описание ...",
"Hide description …" : "Скрии описание ...",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Това приложение не може да бъде инсталирано, защото следните зависимости не са удовлетворени:",
"Enable only for specific groups" : "Включи само за определени групи",
"Uninstall App" : "Премахни Приложението",
+ "Common Name" : "Познато Име",
+ "Valid until" : "Валиден до",
+ "Issued By" : "Издаден От",
+ "Valid until %s" : "Валиден до %s",
+ "Import root certificate" : "Импортиране на основен сертификат",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Здрасти,<br><br>Само да ти кажа, че имаш %s профил<br><br> Потребителя ти е: %s<br>Достъпи го: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Поздрави!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Здрасти,\n\nСамо да ти кажа, че имаш %s профил.\n\nПотребителя ти е: %s\nДостъпи го: %s\n",
"Forum" : "Форум",
- "Get the apps to sync your files" : "Изтегли програми за синхронизиране на файловете ти",
- "Desktop client" : "Клиент за настолен компютър",
- "Android app" : "Андроид приложение",
- "iOS app" : "iOS приложение",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ако искаш да помогнеш на проекта:\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">присъедини се и пиши код</a>\n\t\tили\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">разпространи мълвата</a>!",
- "Show First Run Wizard again" : "Покажи Настройките за Първоначално Зареждане отново",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Използвал си <strong>%s</strong> от наличните <strong>%s</strong>.",
- "Password" : "Парола",
- "Unable to change your password" : "Неуспешна промяна на паролата.",
- "Current password" : "Текуща парола",
- "New password" : "Нова парола",
- "Change password" : "Промяна на паролата",
+ "Profile picture" : "Аватар",
+ "Upload new" : "Качи нов",
+ "Remove image" : "Премахни изображението",
+ "Cancel" : "Отказ",
"Full name" : "Пълно име",
"No display name set" : "Няма настроено екранно име",
"Email" : "Имейл",
"Your email address" : "Твоят имейл адрес",
- "Fill in an email address to enable password recovery and receive notifications" : "Въведи имейл, за да включиш функцията за възстановяване на паролата и уведомления.",
"No email address set" : "Няма настроен адрес на електронна поща",
"You are member of the following groups:" : "Ти си член на следните групи:",
- "Profile picture" : "Аватар",
- "Upload new" : "Качи нов",
- "Select new from Files" : "Избери нов от Файловете",
- "Remove image" : "Премахни изображението",
- "Your avatar is provided by your original account." : "Твоят аватар е взет от оригиналния ти профил.",
- "Cancel" : "Отказ",
- "Choose as profile image" : "Избери като аватар",
+ "Password" : "Парола",
+ "Unable to change your password" : "Неуспешна промяна на паролата.",
+ "Current password" : "Текуща парола",
+ "New password" : "Нова парола",
+ "Change password" : "Промяна на паролата",
"Language" : "Език",
"Help translate" : "Помогни с превода",
- "Common Name" : "Познато Име",
- "Valid until" : "Валиден до",
- "Issued By" : "Издаден От",
- "Valid until %s" : "Валиден до %s",
- "Import root certificate" : "Импортиране на основен сертификат",
+ "Get the apps to sync your files" : "Изтегли програми за синхронизиране на файловете ти",
+ "Desktop client" : "Клиент за настолен компютър",
+ "Android app" : "Андроид приложение",
+ "iOS app" : "iOS приложение",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ако искаш да помогнеш на проекта:\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">присъедини се и пиши код</a>\n\t\tили\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">разпространи мълвата</a>!",
+ "Show First Run Wizard again" : "Покажи Настройките за Първоначално Зареждане отново",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Разработен от {communityopen}ownCloud общността {linkclose}, {githubopen}изходящия код{linkclose} е лицензиран под {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Покажи място за запис",
"Show last log in" : "Покажи последно вписване",
diff --git a/settings/l10n/bn_BD.js b/settings/l10n/bn_BD.js
index b83657ea346..9701e12441e 100644
--- a/settings/l10n/bn_BD.js
+++ b/settings/l10n/bn_BD.js
@@ -3,11 +3,10 @@ OC.L10N.register(
{
"Sharing" : "ভাগাভাগিরত",
"External Storage" : "বাহ্যিক সংরক্ষণাগার",
- "Authentication error" : "অনুমোদন ঘটিত সমস্যা",
- "Your full name has been changed." : "আপনার পূর্ণ নাম পরিবর্তন করা হয়েছে।",
"Couldn't remove app." : "অ্যাপ অপসারণ করা গেলনা",
"Language changed" : "ভাষা পরিবর্তন করা হয়েছে",
"Invalid request" : "অনুরোধটি সঠিক নয়",
+ "Authentication error" : "অনুমোদন ঘটিত সমস্যা",
"Admins can't remove themself from the admin group" : "প্রশাসকবৃন্দ তাদেরকে প্রশাসক গোষ্ঠী থেকে মুছে ফেলতে পারবেন না",
"Unable to add user to group %s" : " %s গোষ্ঠীতে ব্যবহারকারী যোগ করা সম্ভব হলো না ",
"Unable to remove user from group %s" : "%s গোষ্ঠী থেকে ব্যবহারকারীকে অপসারণ করা সম্ভব হলো না",
@@ -19,6 +18,7 @@ OC.L10N.register(
"test email settings" : "ইমেইল নিয়ামকসমূহ পরীক্ষা করুন",
"Email sent" : "ই-মেইল পাঠানো হয়েছে",
"Email saved" : "ই-মেইল সংরক্ষন করা হয়েছে",
+ "Your full name has been changed." : "আপনার পূর্ণ নাম পরিবর্তন করা হয়েছে।",
"All" : "সবাই",
"Error while disabling app" : "অ্যাপ অকার্যকর করতে সমস্যা দেখা দিয়েছে ",
"Disable" : "নিষ্ক্রিয়",
@@ -27,14 +27,13 @@ OC.L10N.register(
"Updating...." : "নবায়ন করা হচ্ছে....",
"Error while updating app" : "অ্যাপ নবায়ন করতে সমস্যা দেখা দিয়েছে ",
"Updated" : "নবায়নকৃত",
- "Strong password" : "শক্তিশালী কুটশব্দ",
"Valid until {date}" : "বৈধতা বলবৎ আছে {তারিখ} অবধি ",
"Delete" : "মুছে",
+ "Strong password" : "শক্তিশালী কুটশব্দ",
"Groups" : "গোষ্ঠীসমূহ",
"undo" : "ক্রিয়া প্রত্যাহার",
"never" : "কখনোই নয়",
"__language_name__" : "__language_name__",
- "SSL root certificates" : "SSL রুট সনদপত্র",
"None" : "কোনটিই নয়",
"Login" : "প্রবেশ",
"Expire after " : "এরপর মেয়াদোত্তীর্ণ হও",
@@ -50,22 +49,20 @@ OC.L10N.register(
"More" : "বেশী",
"Less" : "কম",
"Version" : "ভার্সন",
- "by" : "কর্তৃক",
"Cheers!" : "শুভেচ্ছা!",
"Forum" : "ফোরাম",
- "Get the apps to sync your files" : "আপনার ফাইলসমূহ সিংক করতে অ্যাপস নিন",
- "Show First Run Wizard again" : "প্রথমবার চালানোর যাদুকর পূনরায় প্রদর্শন কর",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "আপনি ব্যবহার করছেন <strong>%s</strong>, সুলভ <strong>%s</strong> এর মধ্যে।",
+ "Cancel" : "বাতির",
+ "Email" : "ইমেইল",
+ "Your email address" : "আপনার ই-মেইল ঠিকানা",
"Password" : "কূটশব্দ",
"Unable to change your password" : "আপনার কূটশব্দটি পরিবর্তন করতে সক্ষম নয়",
"Current password" : "বর্তমান কূটশব্দ",
"New password" : "নতুন কূটশব্দ",
"Change password" : "কূটশব্দ পরিবর্তন করুন",
- "Email" : "ইমেইল",
- "Your email address" : "আপনার ই-মেইল ঠিকানা",
- "Cancel" : "বাতির",
"Language" : "ভাষা",
"Help translate" : "অনুবাদ করতে সহায়তা করুন",
+ "Get the apps to sync your files" : "আপনার ফাইলসমূহ সিংক করতে অ্যাপস নিন",
+ "Show First Run Wizard again" : "প্রথমবার চালানোর যাদুকর পূনরায় প্রদর্শন কর",
"Username" : "ব্যবহারকারী",
"Create" : "তৈরী কর",
"Admin Recovery Password" : "প্রশাসক পূণরূদ্ধার কুটশব্দ",
diff --git a/settings/l10n/bn_BD.json b/settings/l10n/bn_BD.json
index daa17c9fa93..c4b8e3d5bf8 100644
--- a/settings/l10n/bn_BD.json
+++ b/settings/l10n/bn_BD.json
@@ -1,11 +1,10 @@
{ "translations": {
"Sharing" : "ভাগাভাগিরত",
"External Storage" : "বাহ্যিক সংরক্ষণাগার",
- "Authentication error" : "অনুমোদন ঘটিত সমস্যা",
- "Your full name has been changed." : "আপনার পূর্ণ নাম পরিবর্তন করা হয়েছে।",
"Couldn't remove app." : "অ্যাপ অপসারণ করা গেলনা",
"Language changed" : "ভাষা পরিবর্তন করা হয়েছে",
"Invalid request" : "অনুরোধটি সঠিক নয়",
+ "Authentication error" : "অনুমোদন ঘটিত সমস্যা",
"Admins can't remove themself from the admin group" : "প্রশাসকবৃন্দ তাদেরকে প্রশাসক গোষ্ঠী থেকে মুছে ফেলতে পারবেন না",
"Unable to add user to group %s" : " %s গোষ্ঠীতে ব্যবহারকারী যোগ করা সম্ভব হলো না ",
"Unable to remove user from group %s" : "%s গোষ্ঠী থেকে ব্যবহারকারীকে অপসারণ করা সম্ভব হলো না",
@@ -17,6 +16,7 @@
"test email settings" : "ইমেইল নিয়ামকসমূহ পরীক্ষা করুন",
"Email sent" : "ই-মেইল পাঠানো হয়েছে",
"Email saved" : "ই-মেইল সংরক্ষন করা হয়েছে",
+ "Your full name has been changed." : "আপনার পূর্ণ নাম পরিবর্তন করা হয়েছে।",
"All" : "সবাই",
"Error while disabling app" : "অ্যাপ অকার্যকর করতে সমস্যা দেখা দিয়েছে ",
"Disable" : "নিষ্ক্রিয়",
@@ -25,14 +25,13 @@
"Updating...." : "নবায়ন করা হচ্ছে....",
"Error while updating app" : "অ্যাপ নবায়ন করতে সমস্যা দেখা দিয়েছে ",
"Updated" : "নবায়নকৃত",
- "Strong password" : "শক্তিশালী কুটশব্দ",
"Valid until {date}" : "বৈধতা বলবৎ আছে {তারিখ} অবধি ",
"Delete" : "মুছে",
+ "Strong password" : "শক্তিশালী কুটশব্দ",
"Groups" : "গোষ্ঠীসমূহ",
"undo" : "ক্রিয়া প্রত্যাহার",
"never" : "কখনোই নয়",
"__language_name__" : "__language_name__",
- "SSL root certificates" : "SSL রুট সনদপত্র",
"None" : "কোনটিই নয়",
"Login" : "প্রবেশ",
"Expire after " : "এরপর মেয়াদোত্তীর্ণ হও",
@@ -48,22 +47,20 @@
"More" : "বেশী",
"Less" : "কম",
"Version" : "ভার্সন",
- "by" : "কর্তৃক",
"Cheers!" : "শুভেচ্ছা!",
"Forum" : "ফোরাম",
- "Get the apps to sync your files" : "আপনার ফাইলসমূহ সিংক করতে অ্যাপস নিন",
- "Show First Run Wizard again" : "প্রথমবার চালানোর যাদুকর পূনরায় প্রদর্শন কর",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "আপনি ব্যবহার করছেন <strong>%s</strong>, সুলভ <strong>%s</strong> এর মধ্যে।",
+ "Cancel" : "বাতির",
+ "Email" : "ইমেইল",
+ "Your email address" : "আপনার ই-মেইল ঠিকানা",
"Password" : "কূটশব্দ",
"Unable to change your password" : "আপনার কূটশব্দটি পরিবর্তন করতে সক্ষম নয়",
"Current password" : "বর্তমান কূটশব্দ",
"New password" : "নতুন কূটশব্দ",
"Change password" : "কূটশব্দ পরিবর্তন করুন",
- "Email" : "ইমেইল",
- "Your email address" : "আপনার ই-মেইল ঠিকানা",
- "Cancel" : "বাতির",
"Language" : "ভাষা",
"Help translate" : "অনুবাদ করতে সহায়তা করুন",
+ "Get the apps to sync your files" : "আপনার ফাইলসমূহ সিংক করতে অ্যাপস নিন",
+ "Show First Run Wizard again" : "প্রথমবার চালানোর যাদুকর পূনরায় প্রদর্শন কর",
"Username" : "ব্যবহারকারী",
"Create" : "তৈরী কর",
"Admin Recovery Password" : "প্রশাসক পূণরূদ্ধার কুটশব্দ",
diff --git a/settings/l10n/bn_IN.js b/settings/l10n/bn_IN.js
index 7552436f21f..6891bfd9454 100644
--- a/settings/l10n/bn_IN.js
+++ b/settings/l10n/bn_IN.js
@@ -3,9 +3,8 @@ OC.L10N.register(
{
"Saved" : "সংরক্ষিত",
"Delete" : "মুছে ফেলা",
- "by" : "দ্বারা",
- "Get the apps to sync your files" : "আপনার ফাইল সিঙ্ক করার অ্যাপ পান",
"Cancel" : "বাতিল করা",
+ "Get the apps to sync your files" : "আপনার ফাইল সিঙ্ক করার অ্যাপ পান",
"Username" : "ইউজারনেম"
},
"nplurals=2; plural=(n != 1);");
diff --git a/settings/l10n/bn_IN.json b/settings/l10n/bn_IN.json
index 7ec4ea67aa4..430cec27ef6 100644
--- a/settings/l10n/bn_IN.json
+++ b/settings/l10n/bn_IN.json
@@ -1,9 +1,8 @@
{ "translations": {
"Saved" : "সংরক্ষিত",
"Delete" : "মুছে ফেলা",
- "by" : "দ্বারা",
- "Get the apps to sync your files" : "আপনার ফাইল সিঙ্ক করার অ্যাপ পান",
"Cancel" : "বাতিল করা",
+ "Get the apps to sync your files" : "আপনার ফাইল সিঙ্ক করার অ্যাপ পান",
"Username" : "ইউজারনেম"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/settings/l10n/bs.js b/settings/l10n/bs.js
index b98bc00fd6a..df59931033b 100644
--- a/settings/l10n/bs.js
+++ b/settings/l10n/bs.js
@@ -5,12 +5,10 @@ OC.L10N.register(
"Cron" : "Cron",
"Log" : "Zapisnik",
"Updates" : "Ažuriranja",
- "Authentication error" : "Grešna autentifikacije",
- "Your full name has been changed." : "Vaše puno ime je promijenjeno.",
- "Unable to change full name" : "Puno ime nije moguće promijeniti",
"Couldn't remove app." : "Nije moguće ukloniti aplikaciju.",
"Language changed" : "Jezik je promijenjen",
"Invalid request" : "Neispravan zahtjev",
+ "Authentication error" : "Grešna autentifikacije",
"Admins can't remove themself from the admin group" : "Administratori ne mogu sami sebe ukloniti iz admin grupe",
"Unable to add user to group %s" : "Dodavanje korisnika grupi %s nije moguće",
"Unable to remove user from group %s" : "Uklanjanje korisnika iz grupe %s nije moguće",
@@ -37,6 +35,8 @@ OC.L10N.register(
"Invalid user" : "Nevažeči korisnik",
"Unable to change mail address" : "Nemoguće je izmjeniti adresu e-pošte",
"Email saved" : "E-pošta je spremljena",
+ "Your full name has been changed." : "Vaše puno ime je promijenjeno.",
+ "Unable to change full name" : "Puno ime nije moguće promijeniti",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Jeste li zaista sigurni da želite dodati \"{domain}\" kao pouzdanu domenu?",
"Add trusted domain" : "Dodaj pouzdanu domenu",
"Sending..." : "Slanje...",
@@ -53,14 +53,14 @@ OC.L10N.register(
"Uninstalling ...." : "Deinstaliranje....",
"Error while uninstalling app" : "Greška pri deinstaliranju aplikacije",
"Uninstall" : "Deinstaliraj",
+ "Valid until {date}" : "Validno do {date}",
+ "Delete" : "Izbriši",
"Select a profile picture" : "Odaberi sliku profila",
"Very weak password" : "Veoma slaba lozinka",
"Weak password" : "Slaba lozinka",
"So-so password" : "Tu-i-tamo lozinka",
"Good password" : "Dobra lozinka",
"Strong password" : "Jaka lozinka",
- "Valid until {date}" : "Validno do {date}",
- "Delete" : "Izbriši",
"Groups" : "Grupe",
"Unable to delete {objName}" : "Nije moguće izbrisati {objName}",
"Error creating group" : "Greška pri kreiranju grupe",
@@ -76,7 +76,6 @@ OC.L10N.register(
"A valid password must be provided" : "Nužno je navesti valjanu lozinku",
"A valid email must be provided" : "Nužno je navesti valjanu adresu e-pošte",
"__language_name__" : "__naziv_jezika___",
- "SSL root certificates" : "SSL root certifikati",
"Everything (fatal issues, errors, warnings, info, debug)" : "Sve (fatalni problemi, greške, upozorenja, info, ispravljanje pogrešaka)",
"Info, warnings, errors and fatal issues" : "Informacije, upozorenja, greške i fatalni problemi",
"Warnings, errors and fatal issues" : "Upozorenja, greške i fatalni problemi",
@@ -128,46 +127,38 @@ OC.L10N.register(
"Store credentials" : "Spremi vjerodajnice",
"Test email settings" : "Postavke za testnu e-poštu",
"Send email" : "Pošalji e-poštu",
- "Log level" : "Razina zapisnika",
"More" : "Više",
"Less" : "Manje",
"Version" : "Verzija",
- "by" : "od strane",
- "licensed" : "licenciran",
"Documentation:" : "Dokumentacija:",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Ova aplikacija se ne može instalirati zbog slijedećih neispunjenih ovisnosti:",
"Enable only for specific groups" : "Omogućite samo za specifične grupe",
"Uninstall App" : "Deinstaliraj aplikaciju",
+ "Common Name" : "Opće Ime",
+ "Valid until" : "Validno do",
+ "Issued By" : "Izdano od",
+ "Valid until %s" : "Validno do %s",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hej,<br><br>samo da javim da sad imate %s račum.<br><br>Vaše korisničko ime: %s<br>Pristupite mu: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Cheers!",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Koristite aplikacije za sinhronizaciju svojih datoteka",
- "Desktop client" : "Desktop klijent",
- "Android app" : "Android aplikacija",
- "iOS app" : "iOS aplikacija",
- "Show First Run Wizard again" : "Opet pokažite First Run Wizard",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Iskoristili ste <strong>%s</strong> od raspoloživog <strong>%s</strong>",
+ "Profile picture" : "Slika profila",
+ "Upload new" : "Učitaj novu",
+ "Remove image" : "Ukloni sliku",
+ "Cancel" : "Odustani",
+ "Email" : "E-pošta",
+ "Your email address" : "Vaša adresa e-pošte",
"Password" : "Lozinka",
"Unable to change your password" : "Vašu lozinku nije moguće promijeniti",
"Current password" : "Trenutna lozinka",
"New password" : "Nova lozinka",
"Change password" : "Promijeni lozinku",
- "Email" : "E-pošta",
- "Your email address" : "Vaša adresa e-pošte",
- "Fill in an email address to enable password recovery and receive notifications" : "Unesite adresu e-pošte da biste omogućili oporavak lozinke i primili notifikacije",
- "Profile picture" : "Slika profila",
- "Upload new" : "Učitaj novu",
- "Select new from Files" : "Odaberi novu iz datoteka",
- "Remove image" : "Ukloni sliku",
- "Your avatar is provided by your original account." : "Vaš avatar je isporučen od strane vašeg izvornog računa.",
- "Cancel" : "Odustani",
- "Choose as profile image" : "Izaberi kao sliku profila",
"Language" : "Jezik",
"Help translate" : "Pomozi prevesti",
- "Common Name" : "Opće Ime",
- "Valid until" : "Validno do",
- "Issued By" : "Izdano od",
- "Valid until %s" : "Validno do %s",
+ "Get the apps to sync your files" : "Koristite aplikacije za sinhronizaciju svojih datoteka",
+ "Desktop client" : "Desktop klijent",
+ "Android app" : "Android aplikacija",
+ "iOS app" : "iOS aplikacija",
+ "Show First Run Wizard again" : "Opet pokažite First Run Wizard",
"Show storage location" : "Prikaži mjesto pohrane",
"Show last log in" : "Prikaži zadnju prijavu",
"Show user backend" : "Prikaži korisničku pozadinu (backend)",
diff --git a/settings/l10n/bs.json b/settings/l10n/bs.json
index 25b5ec57d41..0a2c8b12a34 100644
--- a/settings/l10n/bs.json
+++ b/settings/l10n/bs.json
@@ -3,12 +3,10 @@
"Cron" : "Cron",
"Log" : "Zapisnik",
"Updates" : "Ažuriranja",
- "Authentication error" : "Grešna autentifikacije",
- "Your full name has been changed." : "Vaše puno ime je promijenjeno.",
- "Unable to change full name" : "Puno ime nije moguće promijeniti",
"Couldn't remove app." : "Nije moguće ukloniti aplikaciju.",
"Language changed" : "Jezik je promijenjen",
"Invalid request" : "Neispravan zahtjev",
+ "Authentication error" : "Grešna autentifikacije",
"Admins can't remove themself from the admin group" : "Administratori ne mogu sami sebe ukloniti iz admin grupe",
"Unable to add user to group %s" : "Dodavanje korisnika grupi %s nije moguće",
"Unable to remove user from group %s" : "Uklanjanje korisnika iz grupe %s nije moguće",
@@ -35,6 +33,8 @@
"Invalid user" : "Nevažeči korisnik",
"Unable to change mail address" : "Nemoguće je izmjeniti adresu e-pošte",
"Email saved" : "E-pošta je spremljena",
+ "Your full name has been changed." : "Vaše puno ime je promijenjeno.",
+ "Unable to change full name" : "Puno ime nije moguće promijeniti",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Jeste li zaista sigurni da želite dodati \"{domain}\" kao pouzdanu domenu?",
"Add trusted domain" : "Dodaj pouzdanu domenu",
"Sending..." : "Slanje...",
@@ -51,14 +51,14 @@
"Uninstalling ...." : "Deinstaliranje....",
"Error while uninstalling app" : "Greška pri deinstaliranju aplikacije",
"Uninstall" : "Deinstaliraj",
+ "Valid until {date}" : "Validno do {date}",
+ "Delete" : "Izbriši",
"Select a profile picture" : "Odaberi sliku profila",
"Very weak password" : "Veoma slaba lozinka",
"Weak password" : "Slaba lozinka",
"So-so password" : "Tu-i-tamo lozinka",
"Good password" : "Dobra lozinka",
"Strong password" : "Jaka lozinka",
- "Valid until {date}" : "Validno do {date}",
- "Delete" : "Izbriši",
"Groups" : "Grupe",
"Unable to delete {objName}" : "Nije moguće izbrisati {objName}",
"Error creating group" : "Greška pri kreiranju grupe",
@@ -74,7 +74,6 @@
"A valid password must be provided" : "Nužno je navesti valjanu lozinku",
"A valid email must be provided" : "Nužno je navesti valjanu adresu e-pošte",
"__language_name__" : "__naziv_jezika___",
- "SSL root certificates" : "SSL root certifikati",
"Everything (fatal issues, errors, warnings, info, debug)" : "Sve (fatalni problemi, greške, upozorenja, info, ispravljanje pogrešaka)",
"Info, warnings, errors and fatal issues" : "Informacije, upozorenja, greške i fatalni problemi",
"Warnings, errors and fatal issues" : "Upozorenja, greške i fatalni problemi",
@@ -126,46 +125,38 @@
"Store credentials" : "Spremi vjerodajnice",
"Test email settings" : "Postavke za testnu e-poštu",
"Send email" : "Pošalji e-poštu",
- "Log level" : "Razina zapisnika",
"More" : "Više",
"Less" : "Manje",
"Version" : "Verzija",
- "by" : "od strane",
- "licensed" : "licenciran",
"Documentation:" : "Dokumentacija:",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Ova aplikacija se ne može instalirati zbog slijedećih neispunjenih ovisnosti:",
"Enable only for specific groups" : "Omogućite samo za specifične grupe",
"Uninstall App" : "Deinstaliraj aplikaciju",
+ "Common Name" : "Opće Ime",
+ "Valid until" : "Validno do",
+ "Issued By" : "Izdano od",
+ "Valid until %s" : "Validno do %s",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hej,<br><br>samo da javim da sad imate %s račum.<br><br>Vaše korisničko ime: %s<br>Pristupite mu: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Cheers!",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Koristite aplikacije za sinhronizaciju svojih datoteka",
- "Desktop client" : "Desktop klijent",
- "Android app" : "Android aplikacija",
- "iOS app" : "iOS aplikacija",
- "Show First Run Wizard again" : "Opet pokažite First Run Wizard",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Iskoristili ste <strong>%s</strong> od raspoloživog <strong>%s</strong>",
+ "Profile picture" : "Slika profila",
+ "Upload new" : "Učitaj novu",
+ "Remove image" : "Ukloni sliku",
+ "Cancel" : "Odustani",
+ "Email" : "E-pošta",
+ "Your email address" : "Vaša adresa e-pošte",
"Password" : "Lozinka",
"Unable to change your password" : "Vašu lozinku nije moguće promijeniti",
"Current password" : "Trenutna lozinka",
"New password" : "Nova lozinka",
"Change password" : "Promijeni lozinku",
- "Email" : "E-pošta",
- "Your email address" : "Vaša adresa e-pošte",
- "Fill in an email address to enable password recovery and receive notifications" : "Unesite adresu e-pošte da biste omogućili oporavak lozinke i primili notifikacije",
- "Profile picture" : "Slika profila",
- "Upload new" : "Učitaj novu",
- "Select new from Files" : "Odaberi novu iz datoteka",
- "Remove image" : "Ukloni sliku",
- "Your avatar is provided by your original account." : "Vaš avatar je isporučen od strane vašeg izvornog računa.",
- "Cancel" : "Odustani",
- "Choose as profile image" : "Izaberi kao sliku profila",
"Language" : "Jezik",
"Help translate" : "Pomozi prevesti",
- "Common Name" : "Opće Ime",
- "Valid until" : "Validno do",
- "Issued By" : "Izdano od",
- "Valid until %s" : "Validno do %s",
+ "Get the apps to sync your files" : "Koristite aplikacije za sinhronizaciju svojih datoteka",
+ "Desktop client" : "Desktop klijent",
+ "Android app" : "Android aplikacija",
+ "iOS app" : "iOS aplikacija",
+ "Show First Run Wizard again" : "Opet pokažite First Run Wizard",
"Show storage location" : "Prikaži mjesto pohrane",
"Show last log in" : "Prikaži zadnju prijavu",
"Show user backend" : "Prikaži korisničku pozadinu (backend)",
diff --git a/settings/l10n/ca.js b/settings/l10n/ca.js
index 54328d47ca7..c8757eda071 100644
--- a/settings/l10n/ca.js
+++ b/settings/l10n/ca.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Registre",
"Tips & tricks" : "Consells i trucs",
"Updates" : "Actualitzacions",
- "Authentication error" : "Error d'autenticació",
- "Your full name has been changed." : "El vostre nom complet ha canviat.",
- "Unable to change full name" : "No s'ha pogut canviar el nom complet",
"Couldn't remove app." : "No s'ha pogut eliminar l'aplicació",
"Language changed" : "S'ha canviat l'idioma",
"Invalid request" : "Sol·licitud no vàlida",
+ "Authentication error" : "Error d'autenticació",
"Admins can't remove themself from the admin group" : "Els administradors no es poden eliminar del grup admin",
"Unable to add user to group %s" : "No es pot afegir l'usuari al grup %s",
"Unable to remove user from group %s" : "No es pot eliminar l'usuari del grup %s",
@@ -50,6 +48,8 @@ OC.L10N.register(
"Invalid user" : "Usuari no vàlid",
"Unable to change mail address" : "No es pot canviar l'adreça de correu electrònic",
"Email saved" : "S'ha desat el correu electrònic",
+ "Your full name has been changed." : "El vostre nom complet ha canviat.",
+ "Unable to change full name" : "No s'ha pogut canviar el nom complet",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Esteu seguir que voleu afegir \"{domain}\" com a un domini de confiança?",
"Add trusted domain" : "Afegir domini de confiança",
"Migration in progress. Please wait until the migration is finished" : "Migració en progrés. Si us plau, espereu fins que finalitzi la migració",
@@ -72,6 +72,8 @@ OC.L10N.register(
"Uninstalling ...." : "Desintal·lant ...",
"Error while uninstalling app" : "Error en desinstal·lar l'aplicació",
"Uninstall" : "Desinstal·la",
+ "Valid until {date}" : "Vàlid fins {date}",
+ "Delete" : "Esborra",
"An error occurred: {message}" : "S'ha produït un error: {message}",
"Select a profile picture" : "Seleccioneu una imatge de perfil",
"Very weak password" : "Contrasenya massa feble",
@@ -79,8 +81,6 @@ OC.L10N.register(
"So-so password" : "Contrasenya passable",
"Good password" : "Contrasenya bona",
"Strong password" : "Contrasenya forta",
- "Valid until {date}" : "Vàlid fins {date}",
- "Delete" : "Esborra",
"Groups" : "Grups",
"Unable to delete {objName}" : "No es pot eliminar {objName}",
"Error creating group" : "Error en crear el grup",
@@ -97,9 +97,8 @@ OC.L10N.register(
"A valid password must be provided" : "Heu de facilitar una contrasenya vàlida",
"A valid email must be provided" : "S'ha de subministrar una adreça de correu electrònic vàlida",
"__language_name__" : "Català",
- "Sync clients" : "Sincronitzar clients",
"Personal info" : "Informació personal",
- "SSL root certificates" : "Certificats SSL root",
+ "Sync clients" : "Sincronitzar clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tot (problemes fatals, errors, avisos, informació, depuració)",
"Info, warnings, errors and fatal issues" : "Informació, avisos, errors i problemes fatals",
"Warnings, errors and fatal issues" : "Avisos, errors i problemes fatals",
@@ -161,7 +160,6 @@ OC.L10N.register(
"Store credentials" : "Emmagatzemar credencials",
"Test email settings" : "Prova l'arranjament del correu",
"Send email" : "Envia correu",
- "Log level" : "Nivell de registre",
"Download logfile" : "Descarregar arxiu de registre",
"More" : "Més",
"Less" : "Menys",
@@ -178,8 +176,6 @@ OC.L10N.register(
"Version" : "Versió",
"Developer documentation" : "Documentació para desenvolupadors",
"Experimental applications ahead" : "A partir d'aquest punt hi ha aplicacions experimentals",
- "by" : "per",
- "licensed" : "llicenciat/da",
"Documentation:" : "Documentació:",
"User documentation" : "Documentació d'usuari",
"Show description …" : "Mostrar descripció...",
@@ -187,6 +183,11 @@ OC.L10N.register(
"This app cannot be installed because the following dependencies are not fulfilled:" : "Aquesta aplicació no es pot instal·lar perquè les següents dependències no es compleixen:",
"Enable only for specific groups" : "Activa només per grups específics",
"Uninstall App" : "Desinstal·la l'aplicació",
+ "Common Name" : "Nom comú",
+ "Valid until" : "Valid fins",
+ "Issued By" : "Emès Per",
+ "Valid until %s" : "Vàlid fins %s",
+ "Import root certificate" : "Importa certificat root",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Què tal?,<br><br>aquest missatge és per fer-li saber que ara té uncompte %s.<br><br>El seu nom d'usuari: %s<br>Accedeixi en: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Salut!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hola, què tal?,\n\nAquest missatge és per fer-li saber que ara té un compte %s.\n\n El seu nom d'usuari: %s\nAccedeixi en: %s\n\n",
@@ -194,39 +195,29 @@ OC.L10N.register(
"Online documentation" : "Documentació en línia",
"Forum" : "Fòrum",
"Commercial support" : "Suport comercial",
- "Get the apps to sync your files" : "Obtingueu les aplicacions per sincronitzar els vostres fitxers",
- "Desktop client" : "Client d'escriptori",
- "Android app" : "aplicació para Android",
- "iOS app" : "aplicació para iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si vol recolzar el projecte\n⇥⇥<a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> unir-se al desenvolupament</a>\n⇥⇥o\n⇥⇥<a href=\"https://owncloud.org/promote\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> difondre'l !</a>!",
- "Show First Run Wizard again" : "Torna a mostrar l'assistent de primera execució",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Heu utilitzat <strong>%s</strong> d'un total disponible de <strong>%s</strong>",
- "Password" : "Contrasenya",
- "Unable to change your password" : "No s'ha pogut canviar la contrasenya",
- "Current password" : "Contrasenya actual",
- "New password" : "Contrasenya nova",
- "Change password" : "Canvia la contrasenya",
+ "Profile picture" : "Foto de perfil",
+ "Upload new" : "Puja'n una de nova",
+ "Remove image" : "Elimina imatge",
+ "Cancel" : "Cancel·la",
"Full name" : "Nom complet",
"No display name set" : "No s'ha establert cap nom para mostrar",
"Email" : "Correu electrònic",
"Your email address" : "Correu electrònic",
- "Fill in an email address to enable password recovery and receive notifications" : "Ompliu una adreça de correu per poder recuperar la contrasenya i rebre notificacions",
"No email address set" : "No s'ha establert cap adreça de correu",
"You are member of the following groups:" : "Vostè és membre dels següents grups:",
- "Profile picture" : "Foto de perfil",
- "Upload new" : "Puja'n una de nova",
- "Select new from Files" : "Selecciona'n una de nova dels fitxers",
- "Remove image" : "Elimina imatge",
- "Your avatar is provided by your original account." : "El vostre compte original proporciona l'avatar.",
- "Cancel" : "Cancel·la",
- "Choose as profile image" : "Selecciona com a imatge de perfil",
+ "Password" : "Contrasenya",
+ "Unable to change your password" : "No s'ha pogut canviar la contrasenya",
+ "Current password" : "Contrasenya actual",
+ "New password" : "Contrasenya nova",
+ "Change password" : "Canvia la contrasenya",
"Language" : "Idioma",
"Help translate" : "Ajudeu-nos amb la traducció",
- "Common Name" : "Nom comú",
- "Valid until" : "Valid fins",
- "Issued By" : "Emès Per",
- "Valid until %s" : "Vàlid fins %s",
- "Import root certificate" : "Importa certificat root",
+ "Get the apps to sync your files" : "Obtingueu les aplicacions per sincronitzar els vostres fitxers",
+ "Desktop client" : "Client d'escriptori",
+ "Android app" : "aplicació para Android",
+ "iOS app" : "aplicació para iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si vol recolzar el projecte\n⇥⇥<a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> unir-se al desenvolupament</a>\n⇥⇥o\n⇥⇥<a href=\"https://owncloud.org/promote\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> difondre'l !</a>!",
+ "Show First Run Wizard again" : "Torna a mostrar l'assistent de primera execució",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desenvolupat per la {communityopen} comunitat ownCloud comunitat{linkclose} , el {githubopen} codi font {linkclose} està llicenciat sota la {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostra la ubicació del magatzem",
"Show last log in" : "Mostrar l'últim accés",
diff --git a/settings/l10n/ca.json b/settings/l10n/ca.json
index bb758dca212..95d8e944929 100644
--- a/settings/l10n/ca.json
+++ b/settings/l10n/ca.json
@@ -10,12 +10,10 @@
"Log" : "Registre",
"Tips & tricks" : "Consells i trucs",
"Updates" : "Actualitzacions",
- "Authentication error" : "Error d'autenticació",
- "Your full name has been changed." : "El vostre nom complet ha canviat.",
- "Unable to change full name" : "No s'ha pogut canviar el nom complet",
"Couldn't remove app." : "No s'ha pogut eliminar l'aplicació",
"Language changed" : "S'ha canviat l'idioma",
"Invalid request" : "Sol·licitud no vàlida",
+ "Authentication error" : "Error d'autenticació",
"Admins can't remove themself from the admin group" : "Els administradors no es poden eliminar del grup admin",
"Unable to add user to group %s" : "No es pot afegir l'usuari al grup %s",
"Unable to remove user from group %s" : "No es pot eliminar l'usuari del grup %s",
@@ -48,6 +46,8 @@
"Invalid user" : "Usuari no vàlid",
"Unable to change mail address" : "No es pot canviar l'adreça de correu electrònic",
"Email saved" : "S'ha desat el correu electrònic",
+ "Your full name has been changed." : "El vostre nom complet ha canviat.",
+ "Unable to change full name" : "No s'ha pogut canviar el nom complet",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Esteu seguir que voleu afegir \"{domain}\" com a un domini de confiança?",
"Add trusted domain" : "Afegir domini de confiança",
"Migration in progress. Please wait until the migration is finished" : "Migració en progrés. Si us plau, espereu fins que finalitzi la migració",
@@ -70,6 +70,8 @@
"Uninstalling ...." : "Desintal·lant ...",
"Error while uninstalling app" : "Error en desinstal·lar l'aplicació",
"Uninstall" : "Desinstal·la",
+ "Valid until {date}" : "Vàlid fins {date}",
+ "Delete" : "Esborra",
"An error occurred: {message}" : "S'ha produït un error: {message}",
"Select a profile picture" : "Seleccioneu una imatge de perfil",
"Very weak password" : "Contrasenya massa feble",
@@ -77,8 +79,6 @@
"So-so password" : "Contrasenya passable",
"Good password" : "Contrasenya bona",
"Strong password" : "Contrasenya forta",
- "Valid until {date}" : "Vàlid fins {date}",
- "Delete" : "Esborra",
"Groups" : "Grups",
"Unable to delete {objName}" : "No es pot eliminar {objName}",
"Error creating group" : "Error en crear el grup",
@@ -95,9 +95,8 @@
"A valid password must be provided" : "Heu de facilitar una contrasenya vàlida",
"A valid email must be provided" : "S'ha de subministrar una adreça de correu electrònic vàlida",
"__language_name__" : "Català",
- "Sync clients" : "Sincronitzar clients",
"Personal info" : "Informació personal",
- "SSL root certificates" : "Certificats SSL root",
+ "Sync clients" : "Sincronitzar clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tot (problemes fatals, errors, avisos, informació, depuració)",
"Info, warnings, errors and fatal issues" : "Informació, avisos, errors i problemes fatals",
"Warnings, errors and fatal issues" : "Avisos, errors i problemes fatals",
@@ -159,7 +158,6 @@
"Store credentials" : "Emmagatzemar credencials",
"Test email settings" : "Prova l'arranjament del correu",
"Send email" : "Envia correu",
- "Log level" : "Nivell de registre",
"Download logfile" : "Descarregar arxiu de registre",
"More" : "Més",
"Less" : "Menys",
@@ -176,8 +174,6 @@
"Version" : "Versió",
"Developer documentation" : "Documentació para desenvolupadors",
"Experimental applications ahead" : "A partir d'aquest punt hi ha aplicacions experimentals",
- "by" : "per",
- "licensed" : "llicenciat/da",
"Documentation:" : "Documentació:",
"User documentation" : "Documentació d'usuari",
"Show description …" : "Mostrar descripció...",
@@ -185,6 +181,11 @@
"This app cannot be installed because the following dependencies are not fulfilled:" : "Aquesta aplicació no es pot instal·lar perquè les següents dependències no es compleixen:",
"Enable only for specific groups" : "Activa només per grups específics",
"Uninstall App" : "Desinstal·la l'aplicació",
+ "Common Name" : "Nom comú",
+ "Valid until" : "Valid fins",
+ "Issued By" : "Emès Per",
+ "Valid until %s" : "Vàlid fins %s",
+ "Import root certificate" : "Importa certificat root",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Què tal?,<br><br>aquest missatge és per fer-li saber que ara té uncompte %s.<br><br>El seu nom d'usuari: %s<br>Accedeixi en: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Salut!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hola, què tal?,\n\nAquest missatge és per fer-li saber que ara té un compte %s.\n\n El seu nom d'usuari: %s\nAccedeixi en: %s\n\n",
@@ -192,39 +193,29 @@
"Online documentation" : "Documentació en línia",
"Forum" : "Fòrum",
"Commercial support" : "Suport comercial",
- "Get the apps to sync your files" : "Obtingueu les aplicacions per sincronitzar els vostres fitxers",
- "Desktop client" : "Client d'escriptori",
- "Android app" : "aplicació para Android",
- "iOS app" : "aplicació para iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si vol recolzar el projecte\n⇥⇥<a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> unir-se al desenvolupament</a>\n⇥⇥o\n⇥⇥<a href=\"https://owncloud.org/promote\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> difondre'l !</a>!",
- "Show First Run Wizard again" : "Torna a mostrar l'assistent de primera execució",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Heu utilitzat <strong>%s</strong> d'un total disponible de <strong>%s</strong>",
- "Password" : "Contrasenya",
- "Unable to change your password" : "No s'ha pogut canviar la contrasenya",
- "Current password" : "Contrasenya actual",
- "New password" : "Contrasenya nova",
- "Change password" : "Canvia la contrasenya",
+ "Profile picture" : "Foto de perfil",
+ "Upload new" : "Puja'n una de nova",
+ "Remove image" : "Elimina imatge",
+ "Cancel" : "Cancel·la",
"Full name" : "Nom complet",
"No display name set" : "No s'ha establert cap nom para mostrar",
"Email" : "Correu electrònic",
"Your email address" : "Correu electrònic",
- "Fill in an email address to enable password recovery and receive notifications" : "Ompliu una adreça de correu per poder recuperar la contrasenya i rebre notificacions",
"No email address set" : "No s'ha establert cap adreça de correu",
"You are member of the following groups:" : "Vostè és membre dels següents grups:",
- "Profile picture" : "Foto de perfil",
- "Upload new" : "Puja'n una de nova",
- "Select new from Files" : "Selecciona'n una de nova dels fitxers",
- "Remove image" : "Elimina imatge",
- "Your avatar is provided by your original account." : "El vostre compte original proporciona l'avatar.",
- "Cancel" : "Cancel·la",
- "Choose as profile image" : "Selecciona com a imatge de perfil",
+ "Password" : "Contrasenya",
+ "Unable to change your password" : "No s'ha pogut canviar la contrasenya",
+ "Current password" : "Contrasenya actual",
+ "New password" : "Contrasenya nova",
+ "Change password" : "Canvia la contrasenya",
"Language" : "Idioma",
"Help translate" : "Ajudeu-nos amb la traducció",
- "Common Name" : "Nom comú",
- "Valid until" : "Valid fins",
- "Issued By" : "Emès Per",
- "Valid until %s" : "Vàlid fins %s",
- "Import root certificate" : "Importa certificat root",
+ "Get the apps to sync your files" : "Obtingueu les aplicacions per sincronitzar els vostres fitxers",
+ "Desktop client" : "Client d'escriptori",
+ "Android app" : "aplicació para Android",
+ "iOS app" : "aplicació para iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si vol recolzar el projecte\n⇥⇥<a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> unir-se al desenvolupament</a>\n⇥⇥o\n⇥⇥<a href=\"https://owncloud.org/promote\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> difondre'l !</a>!",
+ "Show First Run Wizard again" : "Torna a mostrar l'assistent de primera execució",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desenvolupat per la {communityopen} comunitat ownCloud comunitat{linkclose} , el {githubopen} codi font {linkclose} està llicenciat sota la {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostra la ubicació del magatzem",
"Show last log in" : "Mostrar l'últim accés",
diff --git a/settings/l10n/cs_CZ.js b/settings/l10n/cs_CZ.js
index fc819461f4f..9564262aa59 100644
--- a/settings/l10n/cs_CZ.js
+++ b/settings/l10n/cs_CZ.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Záznam",
"Tips & tricks" : "Tipy a triky",
"Updates" : "Aktualizace",
- "Authentication error" : "Chyba přihlášení",
- "Your full name has been changed." : "Vaše celé jméno bylo změněno.",
- "Unable to change full name" : "Nelze změnit celé jméno",
"Couldn't remove app." : "Nepodařilo se odebrat aplikaci.",
"Language changed" : "Jazyk byl změněn",
"Invalid request" : "Neplatný požadavek",
+ "Authentication error" : "Chyba přihlášení",
"Admins can't remove themself from the admin group" : "Správci se nemohou odebrat sami ze skupiny správců",
"Unable to add user to group %s" : "Nelze přidat uživatele do skupiny %s",
"Unable to remove user from group %s" : "Nelze odebrat uživatele ze skupiny %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Neplatný uživatel",
"Unable to change mail address" : "Nelze změnit emailovou adresu",
"Email saved" : "Email uložen",
+ "Your full name has been changed." : "Vaše celé jméno bylo změněno.",
+ "Unable to change full name" : "Nelze změnit celé jméno",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Jste si jisti, že chcete přidat \"{domain}\" mezi důvěryhodné domény?",
"Add trusted domain" : "Přidat důvěryhodnou doménu",
"Migration in progress. Please wait until the migration is finished" : "Migrace probíhá. Počkejte prosím než bude dokončena",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Aplikace byla povolena ale je třeba ji aktualizovat. Za 5 sekund budete přesměrování na stránku pro aktualizaci.",
"App update" : "Aktualizace aplikace",
"No apps found for \"{query}\"" : "Nebyly nalezeny žádné aplikace pro \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Došlo k chybě. Nahrajte prosím ASCII-kódovaný PEM certifikát.",
+ "Valid until {date}" : "Platný do {date}",
+ "Delete" : "Smazat",
"An error occurred: {message}" : "Nastala chyba: {message}",
"Select a profile picture" : "Vyberte profilový obrázek",
"Very weak password" : "Velmi slabé heslo",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Středně silné heslo",
"Good password" : "Dobré heslo",
"Strong password" : "Silné heslo",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Došlo k chybě. Nahrajte prosím ASCII-kódovaný PEM certifikát.",
- "Valid until {date}" : "Platný do {date}",
- "Delete" : "Smazat",
"Groups" : "Skupiny",
"Unable to delete {objName}" : "Nelze smazat {objName}",
"Error creating group" : "Chyba při vytváření skupiny",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Musíte zadat platné heslo",
"A valid email must be provided" : "Musíte zadat platný email",
"__language_name__" : "Česky",
- "Sync clients" : "Synchronizační klienti",
"Personal info" : "Osobní informace",
- "SSL root certificates" : "Kořenové certifikáty SSL",
+ "Sync clients" : "Synchronizační klienti",
"Everything (fatal issues, errors, warnings, info, debug)" : "Vše (fatální problémy, chyby, varování, informační, ladící)",
"Info, warnings, errors and fatal issues" : "Informace, varování, chyby a fatální problémy",
"Warnings, errors and fatal issues" : "Varování, chyby a fatální problémy",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Velmi doporučujeme nainstalovat požadované balíčky do systému, pro podporu jednoho z následujících národních prostředí: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Instalace mimo kořenový adresář domény a používání systémového příkazu cron může způsobit problém s generováním správné URL. Pro zabránění těmto chybám nastavte prosím správnou cestu ve svém config.php souboru v hodnotě \"overwrite.cli.url\" (Je doporučena tato: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Nebylo možné spustit službu cron v CLI. Došlo k následujícím technickým chybám:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transakční uzamykání souborů používá databázi jako uzamykací mechanismus, pro co nejlepší výkon nakonfigurujte uzamykání pomocí memcache. Více informací najdete v <a target=\"_blank\" href=\"%s\">dokumentaci ↗</a>.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Ověřte znovu prosím informace z <a target=\"_blank\" href=\"%s\">instalační příručky ↗</a> a zkontrolujte <a href=\"#log-section\">log</a> na výskyt chyb a varování.",
"All checks passed." : "Všechny testy byly úspěšné.",
"Open documentation" : "Otevřít dokumentaci",
@@ -188,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Ukládat přihlašovací údaje",
"Test email settings" : "Otestovat nastavení emailu",
"Send email" : "Odeslat email",
- "Log level" : "Úroveň zaznamenávání",
"Download logfile" : "Stáhnout soubor logu",
"More" : "Více",
"Less" : "Méně",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Soubor logu je větší než 100 MB. Jeho stažení zabere nějaký čas!",
+ "What to log" : "Co se má logovat",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Je použita databáze SQLite. Pro větší instalace doporučujeme přejít na robustnější databázi.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Obzvláště při používání klientské aplikace pro synchronizaci s desktopem není SQLite doporučeno.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Pro migraci na jinou databázi lze použít aplikaci pro příkazový řádek: 'occ db:convert-type', nebo nahlédněte do <a target=\"_blank\" href=\"%s\">dokumentace ↗</a>.",
@@ -206,17 +204,25 @@ OC.L10N.register(
"Developer documentation" : "Vývojářská dokumentace",
"Experimental applications ahead" : "Experimentální aplikace v pořadí",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentální aplikace nejsou prověřovány na bezpečnostní chyby, mohou být nestabilní a velmi se měnit. Jejich instalací můžete způsobit ztrátu dat nebo bezpečnostní problémy.",
- "by" : "sdílí",
- "licensed" : "licencováno",
+ "by %s" : "%s",
+ "%s-licensed" : "%s-licencováno",
"Documentation:" : "Dokumentace:",
"User documentation" : "Dokumentace uživatele",
"Admin documentation" : "Dokumentace pro administrátory",
"Show description …" : "Zobrazit popis ...",
"Hide description …" : "Skrýt popis ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Tato aplikace nemá přiřazenou nejnižší verzi ownCloud. Toto povede k chybě v ownCloud 11 a vyšším.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Tato aplikace nemá přiřazenou nejvyšší verzi ownCloud. Toto povede k chybě v ownCloud 11 a vyšším.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Tuto aplikaci nelze nainstalovat, protože nejsou splněny následující závislosti:",
"Enable only for specific groups" : "Povolit pouze pro vybrané skupiny",
"Uninstall App" : "Odinstalovat aplikaci",
"Enable experimental apps" : "Povolit experimentální aplikace",
+ "SSL Root Certificates" : "Kořenové certifikáty SSL",
+ "Common Name" : "Common Name",
+ "Valid until" : "Platný do",
+ "Issued By" : "Vydal",
+ "Valid until %s" : "Platný do %s",
+ "Import root certificate" : "Import kořenového certifikátu",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Ahoj,<br><br>toto je oznámení o nově vytvořeném %s účtu.<br><br>Uživatelské jméno: %s<br>Přihlásit se dá zde: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Ať slouží!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ahoj,\n\ntoto je oznámení o nově vytvořeném %s účtu.\n\nUživatelské jméno: %s\nPřihlásit se dá zde: %s\n",
@@ -225,40 +231,35 @@ OC.L10N.register(
"Forum" : "Fórum",
"Issue tracker" : "Seznam chyb",
"Commercial support" : "Placená podpora",
- "Get the apps to sync your files" : "Získat aplikace pro synchronizaci vašich souborů",
- "Desktop client" : "Aplikace pro počítač",
- "Android app" : "Aplikace pro Android",
- "iOS app" : "iOS aplikace",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Chcete-li podpořit tento projekt\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">přidejte se k jeho vývoji</a>\n\t\tnebo\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">šiřte osvětu</a>!",
- "Show First Run Wizard again" : "Znovu zobrazit průvodce prvním spuštěním",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Používáte <strong>%s</strong> z <strong>%s</strong> dostupných",
- "Password" : "Heslo",
- "Unable to change your password" : "Změna vašeho hesla se nezdařila",
- "Current password" : "Současné heslo",
- "New password" : "Nové heslo",
- "Change password" : "Změnit heslo",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Používáte <strong>%s</strong> z <strong>%s</strong>",
+ "Profile picture" : "Profilový obrázek",
+ "Upload new" : "Nahrát nový",
+ "Select from Files" : "Vybrat ze Souborů",
+ "Remove image" : "Odebrat obrázek",
+ "png or jpg, max. 20 MB" : "png nebo jpg, max. 20 MB",
+ "Picture provided by original account" : "Obrázek je poskytován původním účtem",
+ "Cancel" : "Zrušit",
+ "Choose as profile picture" : "Vybrat jako profilový obrázek",
"Full name" : "Celé jméno",
"No display name set" : "Jméno pro zobrazení nenastaveno",
"Email" : "Email",
"Your email address" : "Vaše emailová adresa",
- "Fill in an email address to enable password recovery and receive notifications" : "Zadejte emailovou adresu pro umožnění obnovy zapomenutého hesla a pro přijímání upozornění",
+ "For password recovery and notifications" : "Pro obnovení hesla a upozornění",
"No email address set" : "Emailová adresa není nastavena",
"You are member of the following groups:" : "Patříte do následujících skupin:",
- "Profile picture" : "Profilový obrázek",
- "Upload new" : "Nahrát nový",
- "Select new from Files" : "Vyberte nový ze souborů",
- "Remove image" : "Odebrat obrázek",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Buď png nebo jpg. Nejlépe čtvercový, ale budete mít možnost jej oříznout. Soubor nesmí být větší než 20 MB.",
- "Your avatar is provided by your original account." : "Váš avatar je poskytován Vaším původním účtem.",
- "Cancel" : "Zrušit",
- "Choose as profile image" : "Vybrat jako profilový obrázek",
+ "Password" : "Heslo",
+ "Unable to change your password" : "Změna vašeho hesla se nezdařila",
+ "Current password" : "Současné heslo",
+ "New password" : "Nové heslo",
+ "Change password" : "Změnit heslo",
"Language" : "Jazyk",
"Help translate" : "Pomoci s překladem",
- "Common Name" : "Common Name",
- "Valid until" : "Platný do",
- "Issued By" : "Vydal",
- "Valid until %s" : "Platný do %s",
- "Import root certificate" : "Import kořenového certifikátu",
+ "Get the apps to sync your files" : "Získat aplikace pro synchronizaci vašich souborů",
+ "Desktop client" : "Aplikace pro počítač",
+ "Android app" : "Aplikace pro Android",
+ "iOS app" : "iOS aplikace",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Chcete-li podpořit tento projekt\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">přidejte se k jeho vývoji</a>\n\t\tnebo\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">šiřte osvětu</a>!",
+ "Show First Run Wizard again" : "Znovu zobrazit průvodce prvním spuštěním",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Vyvíjeno {communityopen}komunitou ownCloud{linkclose}, {githubopen}zdrojový kód{linkclose} je licencován pod {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Cesta k datům",
"Show last log in" : "Poslední přihlášení",
diff --git a/settings/l10n/cs_CZ.json b/settings/l10n/cs_CZ.json
index 598267f3de7..6495e772c5e 100644
--- a/settings/l10n/cs_CZ.json
+++ b/settings/l10n/cs_CZ.json
@@ -10,12 +10,10 @@
"Log" : "Záznam",
"Tips & tricks" : "Tipy a triky",
"Updates" : "Aktualizace",
- "Authentication error" : "Chyba přihlášení",
- "Your full name has been changed." : "Vaše celé jméno bylo změněno.",
- "Unable to change full name" : "Nelze změnit celé jméno",
"Couldn't remove app." : "Nepodařilo se odebrat aplikaci.",
"Language changed" : "Jazyk byl změněn",
"Invalid request" : "Neplatný požadavek",
+ "Authentication error" : "Chyba přihlášení",
"Admins can't remove themself from the admin group" : "Správci se nemohou odebrat sami ze skupiny správců",
"Unable to add user to group %s" : "Nelze přidat uživatele do skupiny %s",
"Unable to remove user from group %s" : "Nelze odebrat uživatele ze skupiny %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Neplatný uživatel",
"Unable to change mail address" : "Nelze změnit emailovou adresu",
"Email saved" : "Email uložen",
+ "Your full name has been changed." : "Vaše celé jméno bylo změněno.",
+ "Unable to change full name" : "Nelze změnit celé jméno",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Jste si jisti, že chcete přidat \"{domain}\" mezi důvěryhodné domény?",
"Add trusted domain" : "Přidat důvěryhodnou doménu",
"Migration in progress. Please wait until the migration is finished" : "Migrace probíhá. Počkejte prosím než bude dokončena",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Aplikace byla povolena ale je třeba ji aktualizovat. Za 5 sekund budete přesměrování na stránku pro aktualizaci.",
"App update" : "Aktualizace aplikace",
"No apps found for \"{query}\"" : "Nebyly nalezeny žádné aplikace pro \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Došlo k chybě. Nahrajte prosím ASCII-kódovaný PEM certifikát.",
+ "Valid until {date}" : "Platný do {date}",
+ "Delete" : "Smazat",
"An error occurred: {message}" : "Nastala chyba: {message}",
"Select a profile picture" : "Vyberte profilový obrázek",
"Very weak password" : "Velmi slabé heslo",
@@ -86,9 +89,6 @@
"So-so password" : "Středně silné heslo",
"Good password" : "Dobré heslo",
"Strong password" : "Silné heslo",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Došlo k chybě. Nahrajte prosím ASCII-kódovaný PEM certifikát.",
- "Valid until {date}" : "Platný do {date}",
- "Delete" : "Smazat",
"Groups" : "Skupiny",
"Unable to delete {objName}" : "Nelze smazat {objName}",
"Error creating group" : "Chyba při vytváření skupiny",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Musíte zadat platné heslo",
"A valid email must be provided" : "Musíte zadat platný email",
"__language_name__" : "Česky",
- "Sync clients" : "Synchronizační klienti",
"Personal info" : "Osobní informace",
- "SSL root certificates" : "Kořenové certifikáty SSL",
+ "Sync clients" : "Synchronizační klienti",
"Everything (fatal issues, errors, warnings, info, debug)" : "Vše (fatální problémy, chyby, varování, informační, ladící)",
"Info, warnings, errors and fatal issues" : "Informace, varování, chyby a fatální problémy",
"Warnings, errors and fatal issues" : "Varování, chyby a fatální problémy",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Velmi doporučujeme nainstalovat požadované balíčky do systému, pro podporu jednoho z následujících národních prostředí: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Instalace mimo kořenový adresář domény a používání systémového příkazu cron může způsobit problém s generováním správné URL. Pro zabránění těmto chybám nastavte prosím správnou cestu ve svém config.php souboru v hodnotě \"overwrite.cli.url\" (Je doporučena tato: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Nebylo možné spustit službu cron v CLI. Došlo k následujícím technickým chybám:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transakční uzamykání souborů používá databázi jako uzamykací mechanismus, pro co nejlepší výkon nakonfigurujte uzamykání pomocí memcache. Více informací najdete v <a target=\"_blank\" href=\"%s\">dokumentaci ↗</a>.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Ověřte znovu prosím informace z <a target=\"_blank\" href=\"%s\">instalační příručky ↗</a> a zkontrolujte <a href=\"#log-section\">log</a> na výskyt chyb a varování.",
"All checks passed." : "Všechny testy byly úspěšné.",
"Open documentation" : "Otevřít dokumentaci",
@@ -186,11 +184,11 @@
"Store credentials" : "Ukládat přihlašovací údaje",
"Test email settings" : "Otestovat nastavení emailu",
"Send email" : "Odeslat email",
- "Log level" : "Úroveň zaznamenávání",
"Download logfile" : "Stáhnout soubor logu",
"More" : "Více",
"Less" : "Méně",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Soubor logu je větší než 100 MB. Jeho stažení zabere nějaký čas!",
+ "What to log" : "Co se má logovat",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Je použita databáze SQLite. Pro větší instalace doporučujeme přejít na robustnější databázi.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Obzvláště při používání klientské aplikace pro synchronizaci s desktopem není SQLite doporučeno.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Pro migraci na jinou databázi lze použít aplikaci pro příkazový řádek: 'occ db:convert-type', nebo nahlédněte do <a target=\"_blank\" href=\"%s\">dokumentace ↗</a>.",
@@ -204,17 +202,25 @@
"Developer documentation" : "Vývojářská dokumentace",
"Experimental applications ahead" : "Experimentální aplikace v pořadí",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentální aplikace nejsou prověřovány na bezpečnostní chyby, mohou být nestabilní a velmi se měnit. Jejich instalací můžete způsobit ztrátu dat nebo bezpečnostní problémy.",
- "by" : "sdílí",
- "licensed" : "licencováno",
+ "by %s" : "%s",
+ "%s-licensed" : "%s-licencováno",
"Documentation:" : "Dokumentace:",
"User documentation" : "Dokumentace uživatele",
"Admin documentation" : "Dokumentace pro administrátory",
"Show description …" : "Zobrazit popis ...",
"Hide description …" : "Skrýt popis ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Tato aplikace nemá přiřazenou nejnižší verzi ownCloud. Toto povede k chybě v ownCloud 11 a vyšším.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Tato aplikace nemá přiřazenou nejvyšší verzi ownCloud. Toto povede k chybě v ownCloud 11 a vyšším.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Tuto aplikaci nelze nainstalovat, protože nejsou splněny následující závislosti:",
"Enable only for specific groups" : "Povolit pouze pro vybrané skupiny",
"Uninstall App" : "Odinstalovat aplikaci",
"Enable experimental apps" : "Povolit experimentální aplikace",
+ "SSL Root Certificates" : "Kořenové certifikáty SSL",
+ "Common Name" : "Common Name",
+ "Valid until" : "Platný do",
+ "Issued By" : "Vydal",
+ "Valid until %s" : "Platný do %s",
+ "Import root certificate" : "Import kořenového certifikátu",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Ahoj,<br><br>toto je oznámení o nově vytvořeném %s účtu.<br><br>Uživatelské jméno: %s<br>Přihlásit se dá zde: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Ať slouží!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ahoj,\n\ntoto je oznámení o nově vytvořeném %s účtu.\n\nUživatelské jméno: %s\nPřihlásit se dá zde: %s\n",
@@ -223,40 +229,35 @@
"Forum" : "Fórum",
"Issue tracker" : "Seznam chyb",
"Commercial support" : "Placená podpora",
- "Get the apps to sync your files" : "Získat aplikace pro synchronizaci vašich souborů",
- "Desktop client" : "Aplikace pro počítač",
- "Android app" : "Aplikace pro Android",
- "iOS app" : "iOS aplikace",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Chcete-li podpořit tento projekt\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">přidejte se k jeho vývoji</a>\n\t\tnebo\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">šiřte osvětu</a>!",
- "Show First Run Wizard again" : "Znovu zobrazit průvodce prvním spuštěním",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Používáte <strong>%s</strong> z <strong>%s</strong> dostupných",
- "Password" : "Heslo",
- "Unable to change your password" : "Změna vašeho hesla se nezdařila",
- "Current password" : "Současné heslo",
- "New password" : "Nové heslo",
- "Change password" : "Změnit heslo",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Používáte <strong>%s</strong> z <strong>%s</strong>",
+ "Profile picture" : "Profilový obrázek",
+ "Upload new" : "Nahrát nový",
+ "Select from Files" : "Vybrat ze Souborů",
+ "Remove image" : "Odebrat obrázek",
+ "png or jpg, max. 20 MB" : "png nebo jpg, max. 20 MB",
+ "Picture provided by original account" : "Obrázek je poskytován původním účtem",
+ "Cancel" : "Zrušit",
+ "Choose as profile picture" : "Vybrat jako profilový obrázek",
"Full name" : "Celé jméno",
"No display name set" : "Jméno pro zobrazení nenastaveno",
"Email" : "Email",
"Your email address" : "Vaše emailová adresa",
- "Fill in an email address to enable password recovery and receive notifications" : "Zadejte emailovou adresu pro umožnění obnovy zapomenutého hesla a pro přijímání upozornění",
+ "For password recovery and notifications" : "Pro obnovení hesla a upozornění",
"No email address set" : "Emailová adresa není nastavena",
"You are member of the following groups:" : "Patříte do následujících skupin:",
- "Profile picture" : "Profilový obrázek",
- "Upload new" : "Nahrát nový",
- "Select new from Files" : "Vyberte nový ze souborů",
- "Remove image" : "Odebrat obrázek",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Buď png nebo jpg. Nejlépe čtvercový, ale budete mít možnost jej oříznout. Soubor nesmí být větší než 20 MB.",
- "Your avatar is provided by your original account." : "Váš avatar je poskytován Vaším původním účtem.",
- "Cancel" : "Zrušit",
- "Choose as profile image" : "Vybrat jako profilový obrázek",
+ "Password" : "Heslo",
+ "Unable to change your password" : "Změna vašeho hesla se nezdařila",
+ "Current password" : "Současné heslo",
+ "New password" : "Nové heslo",
+ "Change password" : "Změnit heslo",
"Language" : "Jazyk",
"Help translate" : "Pomoci s překladem",
- "Common Name" : "Common Name",
- "Valid until" : "Platný do",
- "Issued By" : "Vydal",
- "Valid until %s" : "Platný do %s",
- "Import root certificate" : "Import kořenového certifikátu",
+ "Get the apps to sync your files" : "Získat aplikace pro synchronizaci vašich souborů",
+ "Desktop client" : "Aplikace pro počítač",
+ "Android app" : "Aplikace pro Android",
+ "iOS app" : "iOS aplikace",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Chcete-li podpořit tento projekt\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">přidejte se k jeho vývoji</a>\n\t\tnebo\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">šiřte osvětu</a>!",
+ "Show First Run Wizard again" : "Znovu zobrazit průvodce prvním spuštěním",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Vyvíjeno {communityopen}komunitou ownCloud{linkclose}, {githubopen}zdrojový kód{linkclose} je licencován pod {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Cesta k datům",
"Show last log in" : "Poslední přihlášení",
diff --git a/settings/l10n/cy_GB.js b/settings/l10n/cy_GB.js
index 590745e735d..e4999d91b93 100644
--- a/settings/l10n/cy_GB.js
+++ b/settings/l10n/cy_GB.js
@@ -1,8 +1,8 @@
OC.L10N.register(
"settings",
{
- "Authentication error" : "Gwall dilysu",
"Invalid request" : "Cais annilys",
+ "Authentication error" : "Gwall dilysu",
"Email sent" : "Anfonwyd yr e-bost",
"Delete" : "Dileu",
"Groups" : "Grwpiau",
@@ -11,11 +11,10 @@ OC.L10N.register(
"None" : "Dim",
"Login" : "Mewngofnodi",
"Encryption" : "Amgryptiad",
- "by" : "gan",
+ "Cancel" : "Diddymu",
+ "Email" : "E-bost",
"Password" : "Cyfrinair",
"New password" : "Cyfrinair newydd",
- "Email" : "E-bost",
- "Cancel" : "Diddymu",
"Username" : "Enw defnyddiwr",
"Other" : "Arall"
},
diff --git a/settings/l10n/cy_GB.json b/settings/l10n/cy_GB.json
index 41535c5c9cf..0a8fe61beb9 100644
--- a/settings/l10n/cy_GB.json
+++ b/settings/l10n/cy_GB.json
@@ -1,6 +1,6 @@
{ "translations": {
- "Authentication error" : "Gwall dilysu",
"Invalid request" : "Cais annilys",
+ "Authentication error" : "Gwall dilysu",
"Email sent" : "Anfonwyd yr e-bost",
"Delete" : "Dileu",
"Groups" : "Grwpiau",
@@ -9,11 +9,10 @@
"None" : "Dim",
"Login" : "Mewngofnodi",
"Encryption" : "Amgryptiad",
- "by" : "gan",
+ "Cancel" : "Diddymu",
+ "Email" : "E-bost",
"Password" : "Cyfrinair",
"New password" : "Cyfrinair newydd",
- "Email" : "E-bost",
- "Cancel" : "Diddymu",
"Username" : "Enw defnyddiwr",
"Other" : "Arall"
},"pluralForm" :"nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;"
diff --git a/settings/l10n/da.js b/settings/l10n/da.js
index fd9e5734530..915127adbe4 100644
--- a/settings/l10n/da.js
+++ b/settings/l10n/da.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Log",
"Tips & tricks" : "Tips & tricks",
"Updates" : "Opdateringer",
- "Authentication error" : "Adgangsfejl",
- "Your full name has been changed." : "Dit fulde navn er blevet ændret.",
- "Unable to change full name" : "Ikke i stand til at ændre dit fulde navn",
"Couldn't remove app." : "Kunne ikke fjerne app'en.",
"Language changed" : "Sprog ændret",
"Invalid request" : "Ugyldig forespørgsel",
+ "Authentication error" : "Adgangsfejl",
"Admins can't remove themself from the admin group" : "Administratorer kan ikke fjerne dem selv fra admin gruppen",
"Unable to add user to group %s" : "Brugeren kan ikke tilføjes til gruppen %s",
"Unable to remove user from group %s" : "Brugeren kan ikke fjernes fra gruppen %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Ugyldig bruger",
"Unable to change mail address" : "Kan ikke ændre mailadresse",
"Email saved" : "E-mailadressen er gemt",
+ "Your full name has been changed." : "Dit fulde navn er blevet ændret.",
+ "Unable to change full name" : "Ikke i stand til at ændre dit fulde navn",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Sikker på at du vil tilføje \"{domain}\" som et domæne du har tiilid til?",
"Add trusted domain" : "Tilføj et domæne som du har tillid til",
"Migration in progress. Please wait until the migration is finished" : "Immigration er i gang. Vent venligst indtil overflytningen er afsluttet",
@@ -78,6 +78,9 @@ OC.L10N.register(
"Uninstalling ...." : "Afinstallerer...",
"Error while uninstalling app" : "Fejl under afinstallering af app",
"Uninstall" : "Afinstallér",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Der opstod en fejl. Upload venligst et ASCII-indkodet PEM-certifikat.",
+ "Valid until {date}" : "Gyldig indtil {date}",
+ "Delete" : "Slet",
"An error occurred: {message}" : "Der opstod en fejl:{message}",
"Select a profile picture" : "Vælg et profilbillede",
"Very weak password" : "Meget svagt kodeord",
@@ -85,9 +88,6 @@ OC.L10N.register(
"So-so password" : "Jævnt kodeord",
"Good password" : "Godt kodeord",
"Strong password" : "Stærkt kodeord",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Der opstod en fejl. Upload venligst et ASCII-indkodet PEM-certifikat.",
- "Valid until {date}" : "Gyldig indtil {date}",
- "Delete" : "Slet",
"Groups" : "Grupper",
"Unable to delete {objName}" : "Kunne ikke slette {objName}",
"Error creating group" : "Fejl ved oprettelse af gruppe",
@@ -104,9 +104,8 @@ OC.L10N.register(
"A valid password must be provided" : "En gyldig adgangskode skal angives",
"A valid email must be provided" : "Der skal angives en gyldig e-mail",
"__language_name__" : "Dansk",
- "Sync clients" : "Synkroniserings klienter",
"Personal info" : "Personlige oplysninger",
- "SSL root certificates" : "SSL-rodcertifikater",
+ "Sync clients" : "Synkroniserings klienter",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alt (alvorlige fejl, fejl, advarsler, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, advarsler, fejl og alvorlige fejl",
"Warnings, errors and fatal issues" : "Advarsler, fejl og alvorlige fejl",
@@ -132,7 +131,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Vi anbefaler kraftigt, at du installerer den krævede pakke på dit system, for at understøtte følgende lokaliteter: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Hvis din installation ikke er installeret i roden af domænet, og bruger systemets cron, så kan der være problemer med URL-oprettelsen. For at undgå disse problemer, så angiv tilvalget \"overwrite.cli.url\" i din fil config.php til webrodens sti for din installation (foreslået værdi: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Det var ikke muligt at udføre cronjobbet via kommandolinjefladen CLI. Følgende tekniske fejl fremkom:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transaktions låsning af filer bliver brugt af databasen som lås til backend, for den bedste ydelse tilrådes det at konfigurere memcache. Se <a target=\"_blank\" href=\"%s\">documentation ↗</a> for mere information",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Dobbelttjek venligst <a target=\"_blank\" href=\"%s\">, og tjek om der er fejl eller advarsler i <a href=\"#log-section\">loggen</a>.",
"All checks passed." : "Alle tjek blev bestået.",
"Open documentation" : "Åben dokumentation",
@@ -181,7 +179,6 @@ OC.L10N.register(
"Store credentials" : "Gem brugeroplysninger",
"Test email settings" : "Test e-mail-indstillinger",
"Send email" : "Send e-mail",
- "Log level" : "Log niveau",
"Download logfile" : "Hent logfil",
"More" : "Mere",
"Less" : "Mindre",
@@ -199,8 +196,6 @@ OC.L10N.register(
"Developer documentation" : "Dokumentation for udviklere",
"Experimental applications ahead" : "Kommende eksperimentale programmer",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Eksperimentale programmer er ikke undersøgt for sikkerheds problemer. Kendt for at være ustabil og stadig under intensiv udvikling. Installering af disse programmer kan medføre datatab og/eller udgøre en sikkerhedsrisiko.",
- "by" : "af",
- "licensed" : "licenseret",
"Documentation:" : "Dokumentation:",
"User documentation" : "Brugerdokumentation",
"Admin documentation" : "Admin-dokumentation",
@@ -210,6 +205,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Aktivér kun for udvalgte grupper",
"Uninstall App" : "Afinstallér app",
"Enable experimental apps" : "Aktiver eksperimentale programmer",
+ "Common Name" : "Almindeligt navn",
+ "Valid until" : "Gyldig indtil",
+ "Issued By" : "Udstedt af",
+ "Valid until %s" : "Gyldig indtil %s",
+ "Import root certificate" : "Importer rodcertifikat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hejsa,<br><br>dette er blot en besked om, at du nu har en %s-konto.<br><br>Dit brugernavn: %s<br>Tilgå den: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Hej!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hejsa,\n\ndette er blot en besked om, at du nu har en %s-konto.\n\nDit brugernavn: %s\nTilgå den: %s\n\n",
@@ -218,40 +218,29 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Problem følger",
"Commercial support" : "Kommerciel support",
- "Get the apps to sync your files" : "Hent applikationerne for at synkronisere dine filer",
- "Desktop client" : "Skrivebordsklient",
- "Android app" : "Android-app",
- "iOS app" : "iOS-app",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Hvis du vil støtte projektet, så\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">deltag i udviklingen</a>\n\t\teller\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spred budskabet</a>!",
- "Show First Run Wizard again" : "Vis guiden for første kørsel igen.",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du har brugt <strong>%s</strong> af den tilgængelige <strong>%s</strong>",
- "Password" : "Kodeord",
- "Unable to change your password" : "Ude af stand til at ændre dit kodeord",
- "Current password" : "Nuværende adgangskode",
- "New password" : "Nyt kodeord",
- "Change password" : "Skift kodeord",
+ "Profile picture" : "Profilbillede",
+ "Upload new" : "Upload nyt",
+ "Remove image" : "Fjern billede",
+ "Cancel" : "Annuller",
"Full name" : "Fulde navn",
"No display name set" : "Der er ikke angivet skærmnavn",
"Email" : "E-mail",
"Your email address" : "Din e-mailadresse",
- "Fill in an email address to enable password recovery and receive notifications" : "Angiv en e-mailadresse for at aktivere gendannelse af adgangskode og modtage notifikationer",
"No email address set" : "Der er ikke angivet e-mailadresse",
"You are member of the following groups:" : "Der er medlem af følgende grupper:",
- "Profile picture" : "Profilbillede",
- "Upload new" : "Upload nyt",
- "Select new from Files" : "Vælg nyt fra Filer",
- "Remove image" : "Fjern billede",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Enten png eller jpg. Ideelt kvadratisk men du har mulighed for at beskære det. Filen må ikke overskride maksimumgrænsen på 20 MB.",
- "Your avatar is provided by your original account." : "Din avatar kommer fra din oprindelige konto.",
- "Cancel" : "Annuller",
- "Choose as profile image" : "Vælg som profilbillede",
+ "Password" : "Kodeord",
+ "Unable to change your password" : "Ude af stand til at ændre dit kodeord",
+ "Current password" : "Nuværende adgangskode",
+ "New password" : "Nyt kodeord",
+ "Change password" : "Skift kodeord",
"Language" : "Sprog",
"Help translate" : "Hjælp med oversættelsen",
- "Common Name" : "Almindeligt navn",
- "Valid until" : "Gyldig indtil",
- "Issued By" : "Udstedt af",
- "Valid until %s" : "Gyldig indtil %s",
- "Import root certificate" : "Importer rodcertifikat",
+ "Get the apps to sync your files" : "Hent applikationerne for at synkronisere dine filer",
+ "Desktop client" : "Skrivebordsklient",
+ "Android app" : "Android-app",
+ "iOS app" : "iOS-app",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Hvis du vil støtte projektet, så\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">deltag i udviklingen</a>\n\t\teller\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spred budskabet</a>!",
+ "Show First Run Wizard again" : "Vis guiden for første kørsel igen.",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Udviklet af {communityopen}ownCloud-fællesskabet{linkclose}, {githubopen}kildekoden{linkclose} er udgivet under licensen {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Vis placering af lageret",
"Show last log in" : "Vis seneste login",
diff --git a/settings/l10n/da.json b/settings/l10n/da.json
index af6f5367a9c..003d5a03387 100644
--- a/settings/l10n/da.json
+++ b/settings/l10n/da.json
@@ -10,12 +10,10 @@
"Log" : "Log",
"Tips & tricks" : "Tips & tricks",
"Updates" : "Opdateringer",
- "Authentication error" : "Adgangsfejl",
- "Your full name has been changed." : "Dit fulde navn er blevet ændret.",
- "Unable to change full name" : "Ikke i stand til at ændre dit fulde navn",
"Couldn't remove app." : "Kunne ikke fjerne app'en.",
"Language changed" : "Sprog ændret",
"Invalid request" : "Ugyldig forespørgsel",
+ "Authentication error" : "Adgangsfejl",
"Admins can't remove themself from the admin group" : "Administratorer kan ikke fjerne dem selv fra admin gruppen",
"Unable to add user to group %s" : "Brugeren kan ikke tilføjes til gruppen %s",
"Unable to remove user from group %s" : "Brugeren kan ikke fjernes fra gruppen %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Ugyldig bruger",
"Unable to change mail address" : "Kan ikke ændre mailadresse",
"Email saved" : "E-mailadressen er gemt",
+ "Your full name has been changed." : "Dit fulde navn er blevet ændret.",
+ "Unable to change full name" : "Ikke i stand til at ændre dit fulde navn",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Sikker på at du vil tilføje \"{domain}\" som et domæne du har tiilid til?",
"Add trusted domain" : "Tilføj et domæne som du har tillid til",
"Migration in progress. Please wait until the migration is finished" : "Immigration er i gang. Vent venligst indtil overflytningen er afsluttet",
@@ -76,6 +76,9 @@
"Uninstalling ...." : "Afinstallerer...",
"Error while uninstalling app" : "Fejl under afinstallering af app",
"Uninstall" : "Afinstallér",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Der opstod en fejl. Upload venligst et ASCII-indkodet PEM-certifikat.",
+ "Valid until {date}" : "Gyldig indtil {date}",
+ "Delete" : "Slet",
"An error occurred: {message}" : "Der opstod en fejl:{message}",
"Select a profile picture" : "Vælg et profilbillede",
"Very weak password" : "Meget svagt kodeord",
@@ -83,9 +86,6 @@
"So-so password" : "Jævnt kodeord",
"Good password" : "Godt kodeord",
"Strong password" : "Stærkt kodeord",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Der opstod en fejl. Upload venligst et ASCII-indkodet PEM-certifikat.",
- "Valid until {date}" : "Gyldig indtil {date}",
- "Delete" : "Slet",
"Groups" : "Grupper",
"Unable to delete {objName}" : "Kunne ikke slette {objName}",
"Error creating group" : "Fejl ved oprettelse af gruppe",
@@ -102,9 +102,8 @@
"A valid password must be provided" : "En gyldig adgangskode skal angives",
"A valid email must be provided" : "Der skal angives en gyldig e-mail",
"__language_name__" : "Dansk",
- "Sync clients" : "Synkroniserings klienter",
"Personal info" : "Personlige oplysninger",
- "SSL root certificates" : "SSL-rodcertifikater",
+ "Sync clients" : "Synkroniserings klienter",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alt (alvorlige fejl, fejl, advarsler, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, advarsler, fejl og alvorlige fejl",
"Warnings, errors and fatal issues" : "Advarsler, fejl og alvorlige fejl",
@@ -130,7 +129,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Vi anbefaler kraftigt, at du installerer den krævede pakke på dit system, for at understøtte følgende lokaliteter: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Hvis din installation ikke er installeret i roden af domænet, og bruger systemets cron, så kan der være problemer med URL-oprettelsen. For at undgå disse problemer, så angiv tilvalget \"overwrite.cli.url\" i din fil config.php til webrodens sti for din installation (foreslået værdi: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Det var ikke muligt at udføre cronjobbet via kommandolinjefladen CLI. Følgende tekniske fejl fremkom:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transaktions låsning af filer bliver brugt af databasen som lås til backend, for den bedste ydelse tilrådes det at konfigurere memcache. Se <a target=\"_blank\" href=\"%s\">documentation ↗</a> for mere information",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Dobbelttjek venligst <a target=\"_blank\" href=\"%s\">, og tjek om der er fejl eller advarsler i <a href=\"#log-section\">loggen</a>.",
"All checks passed." : "Alle tjek blev bestået.",
"Open documentation" : "Åben dokumentation",
@@ -179,7 +177,6 @@
"Store credentials" : "Gem brugeroplysninger",
"Test email settings" : "Test e-mail-indstillinger",
"Send email" : "Send e-mail",
- "Log level" : "Log niveau",
"Download logfile" : "Hent logfil",
"More" : "Mere",
"Less" : "Mindre",
@@ -197,8 +194,6 @@
"Developer documentation" : "Dokumentation for udviklere",
"Experimental applications ahead" : "Kommende eksperimentale programmer",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Eksperimentale programmer er ikke undersøgt for sikkerheds problemer. Kendt for at være ustabil og stadig under intensiv udvikling. Installering af disse programmer kan medføre datatab og/eller udgøre en sikkerhedsrisiko.",
- "by" : "af",
- "licensed" : "licenseret",
"Documentation:" : "Dokumentation:",
"User documentation" : "Brugerdokumentation",
"Admin documentation" : "Admin-dokumentation",
@@ -208,6 +203,11 @@
"Enable only for specific groups" : "Aktivér kun for udvalgte grupper",
"Uninstall App" : "Afinstallér app",
"Enable experimental apps" : "Aktiver eksperimentale programmer",
+ "Common Name" : "Almindeligt navn",
+ "Valid until" : "Gyldig indtil",
+ "Issued By" : "Udstedt af",
+ "Valid until %s" : "Gyldig indtil %s",
+ "Import root certificate" : "Importer rodcertifikat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hejsa,<br><br>dette er blot en besked om, at du nu har en %s-konto.<br><br>Dit brugernavn: %s<br>Tilgå den: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Hej!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hejsa,\n\ndette er blot en besked om, at du nu har en %s-konto.\n\nDit brugernavn: %s\nTilgå den: %s\n\n",
@@ -216,40 +216,29 @@
"Forum" : "Forum",
"Issue tracker" : "Problem følger",
"Commercial support" : "Kommerciel support",
- "Get the apps to sync your files" : "Hent applikationerne for at synkronisere dine filer",
- "Desktop client" : "Skrivebordsklient",
- "Android app" : "Android-app",
- "iOS app" : "iOS-app",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Hvis du vil støtte projektet, så\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">deltag i udviklingen</a>\n\t\teller\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spred budskabet</a>!",
- "Show First Run Wizard again" : "Vis guiden for første kørsel igen.",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du har brugt <strong>%s</strong> af den tilgængelige <strong>%s</strong>",
- "Password" : "Kodeord",
- "Unable to change your password" : "Ude af stand til at ændre dit kodeord",
- "Current password" : "Nuværende adgangskode",
- "New password" : "Nyt kodeord",
- "Change password" : "Skift kodeord",
+ "Profile picture" : "Profilbillede",
+ "Upload new" : "Upload nyt",
+ "Remove image" : "Fjern billede",
+ "Cancel" : "Annuller",
"Full name" : "Fulde navn",
"No display name set" : "Der er ikke angivet skærmnavn",
"Email" : "E-mail",
"Your email address" : "Din e-mailadresse",
- "Fill in an email address to enable password recovery and receive notifications" : "Angiv en e-mailadresse for at aktivere gendannelse af adgangskode og modtage notifikationer",
"No email address set" : "Der er ikke angivet e-mailadresse",
"You are member of the following groups:" : "Der er medlem af følgende grupper:",
- "Profile picture" : "Profilbillede",
- "Upload new" : "Upload nyt",
- "Select new from Files" : "Vælg nyt fra Filer",
- "Remove image" : "Fjern billede",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Enten png eller jpg. Ideelt kvadratisk men du har mulighed for at beskære det. Filen må ikke overskride maksimumgrænsen på 20 MB.",
- "Your avatar is provided by your original account." : "Din avatar kommer fra din oprindelige konto.",
- "Cancel" : "Annuller",
- "Choose as profile image" : "Vælg som profilbillede",
+ "Password" : "Kodeord",
+ "Unable to change your password" : "Ude af stand til at ændre dit kodeord",
+ "Current password" : "Nuværende adgangskode",
+ "New password" : "Nyt kodeord",
+ "Change password" : "Skift kodeord",
"Language" : "Sprog",
"Help translate" : "Hjælp med oversættelsen",
- "Common Name" : "Almindeligt navn",
- "Valid until" : "Gyldig indtil",
- "Issued By" : "Udstedt af",
- "Valid until %s" : "Gyldig indtil %s",
- "Import root certificate" : "Importer rodcertifikat",
+ "Get the apps to sync your files" : "Hent applikationerne for at synkronisere dine filer",
+ "Desktop client" : "Skrivebordsklient",
+ "Android app" : "Android-app",
+ "iOS app" : "iOS-app",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Hvis du vil støtte projektet, så\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">deltag i udviklingen</a>\n\t\teller\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spred budskabet</a>!",
+ "Show First Run Wizard again" : "Vis guiden for første kørsel igen.",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Udviklet af {communityopen}ownCloud-fællesskabet{linkclose}, {githubopen}kildekoden{linkclose} er udgivet under licensen {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Vis placering af lageret",
"Show last log in" : "Vis seneste login",
diff --git a/settings/l10n/de.js b/settings/l10n/de.js
index 5d5a4d955c1..60828e238cb 100644
--- a/settings/l10n/de.js
+++ b/settings/l10n/de.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Log",
"Tips & tricks" : "Tipps & Tricks",
"Updates" : "Updates",
- "Authentication error" : "Authentifizierungsfehler",
- "Your full name has been changed." : "Dein vollständiger Name ist geändert worden.",
- "Unable to change full name" : "Der vollständige Name konnte nicht geändert werden",
"Couldn't remove app." : "Die App konnte nicht entfernt werden.",
"Language changed" : "Sprache geändert",
"Invalid request" : "Fehlerhafte Anfrage",
+ "Authentication error" : "Authentifizierungsfehler",
"Admins can't remove themself from the admin group" : "Administratoren können sich nicht selbst aus der Admin-Gruppe löschen.",
"Unable to add user to group %s" : "Der Benutzer konnte nicht zur Gruppe %s hinzugefügt werden",
"Unable to remove user from group %s" : "Der Benutzer konnte nicht aus der Gruppe %s entfernt werden",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Ungültiger Benutzer",
"Unable to change mail address" : "E-Mail-Adresse konnte nicht geändert werden",
"Email saved" : "E-Mail-Adresse gespeichert",
+ "Your full name has been changed." : "Dein vollständiger Name ist geändert worden.",
+ "Unable to change full name" : "Der vollständige Name konnte nicht geändert werden",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Bist Du wirklich sicher, dass Du „{domain}“ als vertrauenswürdige Domain hinzufügen möchtest?",
"Add trusted domain" : "Vertrauenswürdige Domain hinzufügen",
"Migration in progress. Please wait until the migration is finished" : "Migration in Arbeit. Bitte warte, bis die Migration beendet ist",
@@ -80,6 +80,10 @@ OC.L10N.register(
"Uninstall" : "Deinstallieren",
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Die App wurde aktiviert, muss aber aktualisiert werden. Du wirst in 5 Sekunden zu Aktualisierungsseite weitergeleitet",
"App update" : "App aktualisiert",
+ "No apps found for \"{query}\"" : "Es wurden keine Apps für \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Es ist ein Fehler aufgetreten. Bitte lade ein ASCII-kodiertes PEM-Zertifikat hoch.",
+ "Valid until {date}" : "Gültig bis {date}",
+ "Delete" : "Löschen",
"An error occurred: {message}" : "Ein Fehler ist aufgetreten: {message}",
"Select a profile picture" : "Wähle ein Profilbild",
"Very weak password" : "Sehr schwaches Passwort",
@@ -87,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Durchschnittliches Passwort",
"Good password" : "Gutes Passwort",
"Strong password" : "Starkes Passwort",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Es ist ein Fehler aufgetreten. Bitte lade ein ASCII-kodiertes PEM-Zertifikat hoch.",
- "Valid until {date}" : "Gültig bis {date}",
- "Delete" : "Löschen",
"Groups" : "Gruppen",
"Unable to delete {objName}" : "Löschen von {objName} nicht möglich",
"Error creating group" : "Fehler beim Erstellen der Gruppe",
@@ -106,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Es muss ein gültiges Passwort angegeben werden",
"A valid email must be provided" : "Es muss eine gültige E-Mail-Adresse angegeben werden",
"__language_name__" : "Deutsch (Persönlich)",
- "Sync clients" : "Sync-Clients",
"Personal info" : "Persönliche Informationen",
- "SSL root certificates" : "SSL-Root-Zertifikate",
+ "Sync clients" : "Sync-Clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alles (fatale Probleme, Fehler, Warnungen, Infos, Debug-Meldungen)",
"Info, warnings, errors and fatal issues" : "Infos, Warnungen, Fehler und fatale Probleme",
"Warnings, errors and fatal issues" : "Warnungen, Fehler und fatale Probleme",
@@ -136,16 +136,16 @@ OC.L10N.register(
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Bitte überprüfe noch einmal die <a target=\"_blank\" href=\"%s\">Installationsanleitungen ↗</a> und kontrolliere das <a href=\"#log-section\">Log</a> auf mögliche Fehler oder Warnungen.",
"All checks passed." : "Alle Überprüfungen bestanden.",
"Open documentation" : "Dokumentation öffnen",
- "Allow apps to use the Share API" : "Erlaubt Apps die Nutzung der Share-API",
+ "Allow apps to use the Share API" : "Apps die Benutzung der Share-API erlauben",
"Allow users to share via link" : "Benutzern erlauben, Inhalte über Links zu teilen",
"Enforce password protection" : "Passwortschutz erzwingen",
"Allow public uploads" : "Öffentliches Hochladen erlauben",
"Allow users to send mail notification for shared files" : "Benutzern erlauben, E-Mail-Benachrichtigungen für freigegebene Dateien zu senden",
- "Set default expiration date" : "Setze Ablaufdatum",
+ "Set default expiration date" : "Standardmäßiges Ablaufdatum setzen",
"Expire after " : "Ablauf nach ",
"days" : "Tagen",
"Enforce expiration date" : "Ablaufdatum erzwingen",
- "Allow resharing" : "Erlaubt erneutes Teilen",
+ "Allow resharing" : "Weiterverteilen erlauben",
"Restrict users to only share with users in their groups" : "Benutzer auf das Teilen innerhalb ihrer Gruppen beschränken",
"Allow users to send mail notification for shared files to other users" : "Benutzern erlauben, E-Mail-Benachrichtigungen für freigegebene Dateien an andere Benutzer zu senden",
"Exclude groups from sharing" : "Gruppen von Freigaben ausschließen",
@@ -181,11 +181,11 @@ OC.L10N.register(
"Store credentials" : "Anmeldeinformationen speichern",
"Test email settings" : "E-Mail-Einstellungen testen",
"Send email" : "E-Mail senden",
- "Log level" : "Loglevel",
"Download logfile" : "Logdatei herunterladen",
"More" : "Mehr",
"Less" : "Weniger",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Die Logdatei ist größer als 100 MB. Es kann etwas Zeit beanspruchen, sie herunterzuladen!",
+ "What to log" : "Was für ein Protokoll",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite wird als Datenbank verwendet. Bei größeren Installationen wird empfohlen, auf ein anderes Datenbank-Backend zu wechseln.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Insbesondere bei der Nutzung des Desktop Clients zur Dateisynchronisierung wird vom Einsatz von SQLite abgeraten.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Um zu einer anderen Datenbank zu migrieren, benutze bitte die Kommandozeile: 'occ db:convert-type', oder in die <a target=\"_blank\" href=\"%s\">Dokumentation ↗</a> schauen.",
@@ -199,8 +199,6 @@ OC.L10N.register(
"Developer documentation" : "Dokumentation für Entwickler",
"Experimental applications ahead" : "Experimentelle Apps nachfolgend",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentelle Apps sind nicht auf Sicherheitsprobleme hin überprüft, sind neu oder bekanntermaßen instabil und befinden sich in intensiver Entwicklung. Ihre Installation kann Datenverlust oder Sicherheitslücken hervorrufen.",
- "by" : "von",
- "licensed" : "Lizenziert",
"Documentation:" : "Dokumentation:",
"User documentation" : "Dokumentation für Benutzer",
"Admin documentation" : "Dokumentation für Administratoren",
@@ -210,6 +208,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Nur für bestimmte Gruppen aktivieren",
"Uninstall App" : "App deinstallieren",
"Enable experimental apps" : "Experimentelle Apps aktivieren",
+ "Common Name" : "Common Name",
+ "Valid until" : "Gültig bis",
+ "Issued By" : "Ausgestellt von:",
+ "Valid until %s" : "Gültig bis %s",
+ "Import root certificate" : "Root-Zertifikat importieren",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hallo,<br><br>hier nur kurz die Mitteilung, dass Du jetzt ein %s-Konto hast.<br><br>Dein Benutzername: %s<br>Greife darauf zu: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Noch einen schönen Tag!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hallo,\n\nhier nur kurz die Mitteilung, dass Du jetzt ein %s-Konto hast.\n\nDein Benutzername: %s\nGreife darauf zu: %s\n\n",
@@ -218,40 +221,29 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Issue Tracker",
"Commercial support" : "Kommerzieller Support",
- "Get the apps to sync your files" : "Lade die Apps zur Synchronisierung Deiner Daten herunter",
- "Desktop client" : "Desktop-Client",
- "Android app" : "Android-App",
- "iOS app" : "iOS-App",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Wenn Du das Projekt unterstützen möchtest,\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\" rel=\"noreferrer\">beteilige Dich an der Entwicklung</a>\noder\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\" rel=\"noreferrer\">hilf mit, es bekannter zu machen</a>!",
- "Show First Run Wizard again" : "Den Einrichtungsassistenten erneut anzeigen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du verwendest <strong>%s</strong> der verfügbaren <strong>%s</strong>",
- "Password" : "Passwort",
- "Unable to change your password" : "Passwort konnte nicht geändert werden",
- "Current password" : "Aktuelles Passwort",
- "New password" : "Neues Passwort",
- "Change password" : "Passwort ändern",
+ "Profile picture" : "Profilbild",
+ "Upload new" : "Neues hochladen",
+ "Remove image" : "Bild entfernen",
+ "Cancel" : "Abbrechen",
"Full name" : "Vollständiger Name",
"No display name set" : "Kein Anzeigename angegeben",
"Email" : "E-Mail",
"Your email address" : "Deine E-Mail-Adresse",
- "Fill in an email address to enable password recovery and receive notifications" : "Gib eine E-Mail-Adresse an, um eine Wiederherstellung des Passworts zu ermöglichen und Benachrichtigungen zu empfangen",
"No email address set" : "Keine E-Mail-Adresse angegeben",
"You are member of the following groups:" : "Du bist Mitglied folgender Gruppen:",
- "Profile picture" : "Profilbild",
- "Upload new" : "Neues hochladen",
- "Select new from Files" : "Neues aus den Dateien wählen",
- "Remove image" : "Bild entfernen",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Entweder png oder jpg. Im Idealfall quadratisch, aber du kannst das Bild beschneiden. Es ist nicht erlaubt die Maximalgröße von 20 MB zu überschreiten.",
- "Your avatar is provided by your original account." : "Dein Avatar wird von Deinem ursprünglichen Konto bereitgestellt.",
- "Cancel" : "Abbrechen",
- "Choose as profile image" : "Als Profilbild wählen",
+ "Password" : "Passwort",
+ "Unable to change your password" : "Passwort konnte nicht geändert werden",
+ "Current password" : "Aktuelles Passwort",
+ "New password" : "Neues Passwort",
+ "Change password" : "Passwort ändern",
"Language" : "Sprache",
"Help translate" : "Hilf bei der Übersetzung",
- "Common Name" : "Common Name",
- "Valid until" : "Gültig bis",
- "Issued By" : "Ausgestellt von:",
- "Valid until %s" : "Gültig bis %s",
- "Import root certificate" : "Root-Zertifikat importieren",
+ "Get the apps to sync your files" : "Lade die Apps zur Synchronisierung Deiner Daten herunter",
+ "Desktop client" : "Desktop-Client",
+ "Android app" : "Android-App",
+ "iOS app" : "iOS-App",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Wenn Du das Projekt unterstützen möchtest,\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\" rel=\"noreferrer\">beteilige Dich an der Entwicklung</a>\noder\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\" rel=\"noreferrer\">hilf mit, es bekannter zu machen</a>!",
+ "Show First Run Wizard again" : "Den Einrichtungsassistenten erneut anzeigen",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Entwickelt von der {communityopen}ownCloud-Community{linkclose}, der {githubopen}Quellcode{linkclose} ist unter den Bedingungen der {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} lizenziert.",
"Show storage location" : "Speicherort anzeigen",
"Show last log in" : "Letzte Anmeldung anzeigen",
diff --git a/settings/l10n/de.json b/settings/l10n/de.json
index 9bd8d36dac3..59b3720948d 100644
--- a/settings/l10n/de.json
+++ b/settings/l10n/de.json
@@ -10,12 +10,10 @@
"Log" : "Log",
"Tips & tricks" : "Tipps & Tricks",
"Updates" : "Updates",
- "Authentication error" : "Authentifizierungsfehler",
- "Your full name has been changed." : "Dein vollständiger Name ist geändert worden.",
- "Unable to change full name" : "Der vollständige Name konnte nicht geändert werden",
"Couldn't remove app." : "Die App konnte nicht entfernt werden.",
"Language changed" : "Sprache geändert",
"Invalid request" : "Fehlerhafte Anfrage",
+ "Authentication error" : "Authentifizierungsfehler",
"Admins can't remove themself from the admin group" : "Administratoren können sich nicht selbst aus der Admin-Gruppe löschen.",
"Unable to add user to group %s" : "Der Benutzer konnte nicht zur Gruppe %s hinzugefügt werden",
"Unable to remove user from group %s" : "Der Benutzer konnte nicht aus der Gruppe %s entfernt werden",
@@ -51,6 +49,8 @@
"Invalid user" : "Ungültiger Benutzer",
"Unable to change mail address" : "E-Mail-Adresse konnte nicht geändert werden",
"Email saved" : "E-Mail-Adresse gespeichert",
+ "Your full name has been changed." : "Dein vollständiger Name ist geändert worden.",
+ "Unable to change full name" : "Der vollständige Name konnte nicht geändert werden",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Bist Du wirklich sicher, dass Du „{domain}“ als vertrauenswürdige Domain hinzufügen möchtest?",
"Add trusted domain" : "Vertrauenswürdige Domain hinzufügen",
"Migration in progress. Please wait until the migration is finished" : "Migration in Arbeit. Bitte warte, bis die Migration beendet ist",
@@ -78,6 +78,10 @@
"Uninstall" : "Deinstallieren",
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Die App wurde aktiviert, muss aber aktualisiert werden. Du wirst in 5 Sekunden zu Aktualisierungsseite weitergeleitet",
"App update" : "App aktualisiert",
+ "No apps found for \"{query}\"" : "Es wurden keine Apps für \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Es ist ein Fehler aufgetreten. Bitte lade ein ASCII-kodiertes PEM-Zertifikat hoch.",
+ "Valid until {date}" : "Gültig bis {date}",
+ "Delete" : "Löschen",
"An error occurred: {message}" : "Ein Fehler ist aufgetreten: {message}",
"Select a profile picture" : "Wähle ein Profilbild",
"Very weak password" : "Sehr schwaches Passwort",
@@ -85,9 +89,6 @@
"So-so password" : "Durchschnittliches Passwort",
"Good password" : "Gutes Passwort",
"Strong password" : "Starkes Passwort",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Es ist ein Fehler aufgetreten. Bitte lade ein ASCII-kodiertes PEM-Zertifikat hoch.",
- "Valid until {date}" : "Gültig bis {date}",
- "Delete" : "Löschen",
"Groups" : "Gruppen",
"Unable to delete {objName}" : "Löschen von {objName} nicht möglich",
"Error creating group" : "Fehler beim Erstellen der Gruppe",
@@ -104,9 +105,8 @@
"A valid password must be provided" : "Es muss ein gültiges Passwort angegeben werden",
"A valid email must be provided" : "Es muss eine gültige E-Mail-Adresse angegeben werden",
"__language_name__" : "Deutsch (Persönlich)",
- "Sync clients" : "Sync-Clients",
"Personal info" : "Persönliche Informationen",
- "SSL root certificates" : "SSL-Root-Zertifikate",
+ "Sync clients" : "Sync-Clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alles (fatale Probleme, Fehler, Warnungen, Infos, Debug-Meldungen)",
"Info, warnings, errors and fatal issues" : "Infos, Warnungen, Fehler und fatale Probleme",
"Warnings, errors and fatal issues" : "Warnungen, Fehler und fatale Probleme",
@@ -134,16 +134,16 @@
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Bitte überprüfe noch einmal die <a target=\"_blank\" href=\"%s\">Installationsanleitungen ↗</a> und kontrolliere das <a href=\"#log-section\">Log</a> auf mögliche Fehler oder Warnungen.",
"All checks passed." : "Alle Überprüfungen bestanden.",
"Open documentation" : "Dokumentation öffnen",
- "Allow apps to use the Share API" : "Erlaubt Apps die Nutzung der Share-API",
+ "Allow apps to use the Share API" : "Apps die Benutzung der Share-API erlauben",
"Allow users to share via link" : "Benutzern erlauben, Inhalte über Links zu teilen",
"Enforce password protection" : "Passwortschutz erzwingen",
"Allow public uploads" : "Öffentliches Hochladen erlauben",
"Allow users to send mail notification for shared files" : "Benutzern erlauben, E-Mail-Benachrichtigungen für freigegebene Dateien zu senden",
- "Set default expiration date" : "Setze Ablaufdatum",
+ "Set default expiration date" : "Standardmäßiges Ablaufdatum setzen",
"Expire after " : "Ablauf nach ",
"days" : "Tagen",
"Enforce expiration date" : "Ablaufdatum erzwingen",
- "Allow resharing" : "Erlaubt erneutes Teilen",
+ "Allow resharing" : "Weiterverteilen erlauben",
"Restrict users to only share with users in their groups" : "Benutzer auf das Teilen innerhalb ihrer Gruppen beschränken",
"Allow users to send mail notification for shared files to other users" : "Benutzern erlauben, E-Mail-Benachrichtigungen für freigegebene Dateien an andere Benutzer zu senden",
"Exclude groups from sharing" : "Gruppen von Freigaben ausschließen",
@@ -179,11 +179,11 @@
"Store credentials" : "Anmeldeinformationen speichern",
"Test email settings" : "E-Mail-Einstellungen testen",
"Send email" : "E-Mail senden",
- "Log level" : "Loglevel",
"Download logfile" : "Logdatei herunterladen",
"More" : "Mehr",
"Less" : "Weniger",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Die Logdatei ist größer als 100 MB. Es kann etwas Zeit beanspruchen, sie herunterzuladen!",
+ "What to log" : "Was für ein Protokoll",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite wird als Datenbank verwendet. Bei größeren Installationen wird empfohlen, auf ein anderes Datenbank-Backend zu wechseln.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Insbesondere bei der Nutzung des Desktop Clients zur Dateisynchronisierung wird vom Einsatz von SQLite abgeraten.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Um zu einer anderen Datenbank zu migrieren, benutze bitte die Kommandozeile: 'occ db:convert-type', oder in die <a target=\"_blank\" href=\"%s\">Dokumentation ↗</a> schauen.",
@@ -197,8 +197,6 @@
"Developer documentation" : "Dokumentation für Entwickler",
"Experimental applications ahead" : "Experimentelle Apps nachfolgend",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentelle Apps sind nicht auf Sicherheitsprobleme hin überprüft, sind neu oder bekanntermaßen instabil und befinden sich in intensiver Entwicklung. Ihre Installation kann Datenverlust oder Sicherheitslücken hervorrufen.",
- "by" : "von",
- "licensed" : "Lizenziert",
"Documentation:" : "Dokumentation:",
"User documentation" : "Dokumentation für Benutzer",
"Admin documentation" : "Dokumentation für Administratoren",
@@ -208,6 +206,11 @@
"Enable only for specific groups" : "Nur für bestimmte Gruppen aktivieren",
"Uninstall App" : "App deinstallieren",
"Enable experimental apps" : "Experimentelle Apps aktivieren",
+ "Common Name" : "Common Name",
+ "Valid until" : "Gültig bis",
+ "Issued By" : "Ausgestellt von:",
+ "Valid until %s" : "Gültig bis %s",
+ "Import root certificate" : "Root-Zertifikat importieren",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hallo,<br><br>hier nur kurz die Mitteilung, dass Du jetzt ein %s-Konto hast.<br><br>Dein Benutzername: %s<br>Greife darauf zu: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Noch einen schönen Tag!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hallo,\n\nhier nur kurz die Mitteilung, dass Du jetzt ein %s-Konto hast.\n\nDein Benutzername: %s\nGreife darauf zu: %s\n\n",
@@ -216,40 +219,29 @@
"Forum" : "Forum",
"Issue tracker" : "Issue Tracker",
"Commercial support" : "Kommerzieller Support",
- "Get the apps to sync your files" : "Lade die Apps zur Synchronisierung Deiner Daten herunter",
- "Desktop client" : "Desktop-Client",
- "Android app" : "Android-App",
- "iOS app" : "iOS-App",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Wenn Du das Projekt unterstützen möchtest,\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\" rel=\"noreferrer\">beteilige Dich an der Entwicklung</a>\noder\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\" rel=\"noreferrer\">hilf mit, es bekannter zu machen</a>!",
- "Show First Run Wizard again" : "Den Einrichtungsassistenten erneut anzeigen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du verwendest <strong>%s</strong> der verfügbaren <strong>%s</strong>",
- "Password" : "Passwort",
- "Unable to change your password" : "Passwort konnte nicht geändert werden",
- "Current password" : "Aktuelles Passwort",
- "New password" : "Neues Passwort",
- "Change password" : "Passwort ändern",
+ "Profile picture" : "Profilbild",
+ "Upload new" : "Neues hochladen",
+ "Remove image" : "Bild entfernen",
+ "Cancel" : "Abbrechen",
"Full name" : "Vollständiger Name",
"No display name set" : "Kein Anzeigename angegeben",
"Email" : "E-Mail",
"Your email address" : "Deine E-Mail-Adresse",
- "Fill in an email address to enable password recovery and receive notifications" : "Gib eine E-Mail-Adresse an, um eine Wiederherstellung des Passworts zu ermöglichen und Benachrichtigungen zu empfangen",
"No email address set" : "Keine E-Mail-Adresse angegeben",
"You are member of the following groups:" : "Du bist Mitglied folgender Gruppen:",
- "Profile picture" : "Profilbild",
- "Upload new" : "Neues hochladen",
- "Select new from Files" : "Neues aus den Dateien wählen",
- "Remove image" : "Bild entfernen",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Entweder png oder jpg. Im Idealfall quadratisch, aber du kannst das Bild beschneiden. Es ist nicht erlaubt die Maximalgröße von 20 MB zu überschreiten.",
- "Your avatar is provided by your original account." : "Dein Avatar wird von Deinem ursprünglichen Konto bereitgestellt.",
- "Cancel" : "Abbrechen",
- "Choose as profile image" : "Als Profilbild wählen",
+ "Password" : "Passwort",
+ "Unable to change your password" : "Passwort konnte nicht geändert werden",
+ "Current password" : "Aktuelles Passwort",
+ "New password" : "Neues Passwort",
+ "Change password" : "Passwort ändern",
"Language" : "Sprache",
"Help translate" : "Hilf bei der Übersetzung",
- "Common Name" : "Common Name",
- "Valid until" : "Gültig bis",
- "Issued By" : "Ausgestellt von:",
- "Valid until %s" : "Gültig bis %s",
- "Import root certificate" : "Root-Zertifikat importieren",
+ "Get the apps to sync your files" : "Lade die Apps zur Synchronisierung Deiner Daten herunter",
+ "Desktop client" : "Desktop-Client",
+ "Android app" : "Android-App",
+ "iOS app" : "iOS-App",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Wenn Du das Projekt unterstützen möchtest,\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\" rel=\"noreferrer\">beteilige Dich an der Entwicklung</a>\noder\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\" rel=\"noreferrer\">hilf mit, es bekannter zu machen</a>!",
+ "Show First Run Wizard again" : "Den Einrichtungsassistenten erneut anzeigen",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Entwickelt von der {communityopen}ownCloud-Community{linkclose}, der {githubopen}Quellcode{linkclose} ist unter den Bedingungen der {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} lizenziert.",
"Show storage location" : "Speicherort anzeigen",
"Show last log in" : "Letzte Anmeldung anzeigen",
diff --git a/settings/l10n/de_AT.js b/settings/l10n/de_AT.js
index d1584ae9451..2f3af547bed 100644
--- a/settings/l10n/de_AT.js
+++ b/settings/l10n/de_AT.js
@@ -7,11 +7,10 @@ OC.L10N.register(
"__language_name__" : "Deutsch (Österreich)",
"Server address" : "Adresse des Servers",
"Port" : "Port",
- "by" : "von",
+ "Cancel" : "Abbrechen",
+ "Email" : "E-Mail",
"Password" : "Passwort",
"Change password" : "Passwort ändern",
- "Email" : "E-Mail",
- "Cancel" : "Abbrechen",
"Username" : "Benutzername",
"Other" : "Anderes"
},
diff --git a/settings/l10n/de_AT.json b/settings/l10n/de_AT.json
index 98ae6547481..bd2f8340856 100644
--- a/settings/l10n/de_AT.json
+++ b/settings/l10n/de_AT.json
@@ -5,11 +5,10 @@
"__language_name__" : "Deutsch (Österreich)",
"Server address" : "Adresse des Servers",
"Port" : "Port",
- "by" : "von",
+ "Cancel" : "Abbrechen",
+ "Email" : "E-Mail",
"Password" : "Passwort",
"Change password" : "Passwort ändern",
- "Email" : "E-Mail",
- "Cancel" : "Abbrechen",
"Username" : "Benutzername",
"Other" : "Anderes"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/settings/l10n/de_DE.js b/settings/l10n/de_DE.js
index fd8938d0b51..3f314c54816 100644
--- a/settings/l10n/de_DE.js
+++ b/settings/l10n/de_DE.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Log",
"Tips & tricks" : "Tipps & Tricks",
"Updates" : "Updates",
- "Authentication error" : "Authentifizierungsfehler",
- "Your full name has been changed." : "Ihr vollständiger Name ist geändert worden.",
- "Unable to change full name" : "Der vollständige Name konnte nicht geändert werden",
"Couldn't remove app." : "Die App konnte nicht entfernt werden.",
"Language changed" : "Sprache geändert",
"Invalid request" : "Ungültige Anforderung",
+ "Authentication error" : "Authentifizierungsfehler",
"Admins can't remove themself from the admin group" : "Administratoren können sich nicht selbst aus der admin-Gruppe löschen",
"Unable to add user to group %s" : "Der Benutzer konnte nicht zur Gruppe %s hinzugefügt werden",
"Unable to remove user from group %s" : "Der Benutzer konnte nicht aus der Gruppe %s entfernt werden",
@@ -51,6 +49,8 @@ OC.L10N.register(
"Invalid user" : "Ungültiger Benutzer",
"Unable to change mail address" : "E-Mail-Adresse konnte nicht geändert werden",
"Email saved" : "E-Mail-Adresse gespeichert",
+ "Your full name has been changed." : "Ihr vollständiger Name ist geändert worden.",
+ "Unable to change full name" : "Der vollständige Name konnte nicht geändert werden",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Sind Sie sich wirklich sicher, dass Sie »{domain}« als vertrauenswürdige Domain hinzufügen möchten?",
"Add trusted domain" : "Vertrauenswürdige Domain hinzufügen",
"Migration in progress. Please wait until the migration is finished" : "Migration in Arbeit. Bitte warten Sie, bis die Migration beendet ist",
@@ -76,15 +76,19 @@ OC.L10N.register(
"Uninstalling ...." : "Wird deinstalliert…",
"Error while uninstalling app" : "Fehler beim Deinstallieren der App",
"Uninstall" : "Deinstallieren",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Die App wurde aktiviert, aber sie benötigt ein Update. Sie werden zur Update Seite in 5 Sekunden weitergeleitet.",
+ "App update" : "App aktualisieren",
+ "No apps found for \"{query}\"" : "Es wurden keine Apps gefunden für \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Es ist ein Fehler aufgetreten. Bitte laden Sie ein ASCII-kodiertes PEM-Zertifikat hoch.",
+ "Valid until {date}" : "Gültig bis {date}",
+ "Delete" : "Löschen",
+ "An error occurred: {message}" : "Ein Fehler ist aufgetreten: {message}",
"Select a profile picture" : "Wählen Sie ein Profilbild",
"Very weak password" : "Sehr schwaches Passwort",
"Weak password" : "Schwaches Passwort",
"So-so password" : "Passables Passwort",
"Good password" : "Gutes Passwort",
"Strong password" : "Starkes Passwort",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Es ist ein Fehler aufgetreten. Bitte laden Sie ein ASCII-kodiertes PEM-Zertifikat hoch.",
- "Valid until {date}" : "Gültig bis {date}",
- "Delete" : "Löschen",
"Groups" : "Gruppen",
"Unable to delete {objName}" : "Löschen von {objName} nicht möglich",
"Error creating group" : "Fehler beim Erstellen der Gruppe",
@@ -101,9 +105,8 @@ OC.L10N.register(
"A valid password must be provided" : "Es muss ein gültiges Passwort angegeben werden",
"A valid email must be provided" : "Es muss eine gültige E-Mail-Adresse angegeben werden",
"__language_name__" : "Deutsch (Förmlich: Sie)",
- "Sync clients" : "Sync-Clients",
"Personal info" : "Persönliche Informationen",
- "SSL root certificates" : "SSL-Root-Zertifikate",
+ "Sync clients" : "Sync-Clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alles (fatale Probleme, Fehler, Warnungen, Infos, Fehlerdiagnose)",
"Info, warnings, errors and fatal issues" : "Infos, Warnungen, Fehler und fatale Probleme",
"Warnings, errors and fatal issues" : "Warnungen, Fehler und fatale Probleme",
@@ -128,13 +131,14 @@ OC.L10N.register(
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Wenn sich Ihre Installation nicht im Wurzelverzeichnis der Domain befindet und Cron aus dem System genutzt wird, kann es zu Fehlern bei der URL-Generierung kommen. Um dies zu verhindern, setzen Sie bitte die „overwrite.cli.url“-Option in Ihrer config.php auf das Web-Wurzelverzeichnis Ihrer Installation (Vorschlag: „%s“).",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Die Ausführung des Cron-Jobs über die Kommandozeile war nicht möglich. Die folgenden technischen Fehler sind dabei aufgetreten:",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Bitte überprüfen Sie noch einmal die <a target=\"_blank\" href=\"%s\">Installationsanleitungen ↗</a> und kontrollieren Sie das <a href=\"#log-section\">Log</a> auf mögliche Fehler oder Warnungen.",
+ "All checks passed." : "Alle checks erfolgreich gepfüft.",
"Open documentation" : "Dokumentation öffnen",
- "Allow apps to use the Share API" : "Anwendungen erlauben, die Share-API zu benutzen",
+ "Allow apps to use the Share API" : "Apps die Benutzung der Share-API erlauben",
"Allow users to share via link" : "Benutzern erlauben, Inhalte über Links zu teilen",
"Enforce password protection" : "Passwortschutz erzwingen",
"Allow public uploads" : "Öffentliches Hochladen erlauben",
"Allow users to send mail notification for shared files" : "Benutzern erlauben, E-Mail-Benachrichtigungen für freigegebene Dateien zu senden",
- "Set default expiration date" : "Standardablaufdatum einstellen",
+ "Set default expiration date" : "Standardmäßiges Ablaufdatum setzen",
"Expire after " : "Ablauf nach ",
"days" : "Tagen",
"Enforce expiration date" : "Ablaufdatum erzwingen",
@@ -150,6 +154,7 @@ OC.L10N.register(
"cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php ist als Webcron-Dienst registriert, der die cron.php alle 15 Minuten per HTTP aufruft.",
"Use system's cron service to call the cron.php file every 15 minutes." : "Benutzen Sie den systemeigenen Cron-Dienst, um die cron.php alle 15 Minuten aufzurufen.",
"Enable server-side encryption" : "Serverseitige Verschlüsselung aktivieren",
+ "Please read carefully before activating server-side encryption: " : "Bitte lesen Sie ganz genau, bevor Sie die Serverseite Verschlüsselung aktivieren:",
"Enable encryption" : "Verschlüsselung aktivieren",
"No encryption module loaded, please enable an encryption module in the app menu." : "Kein Verschlüsselungs-Modul geladen, bitte aktiviere ein Verschlüsselungs-Modul im Anwendungs-Menü.",
"Select default encryption module:" : "Standard-Verschlüsselungs-Modul auswählen:",
@@ -171,11 +176,11 @@ OC.L10N.register(
"Store credentials" : "Anmeldeinformationen speichern",
"Test email settings" : "E-Mail-Einstellungen testen",
"Send email" : "E-Mail senden",
- "Log level" : "Log-Level",
"Download logfile" : "Logdatei herunterladen",
"More" : "Mehr",
"Less" : "Weniger",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Die Logdatei ist größer als 100 MB. Es kann etwas Zeit beanspruchen, sie herunterzuladen!",
+ "What to log" : "Was geloggt wird",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite wird als Datenbank verwendet. Bei größeren Installationen wird empfohlen, auf ein anderes Datenbank-Backend zu wechseln.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Insbesondere bei der Nutzung des Desktop Clients zur Dateisynchronisierung wird vom Einsatz von SQLite abgeraten.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Um auf eine andere Datenbank zu migrieren, benutzen Sie bitte die Kommandozeile: „occ db:convert-type“ oder konsultieren Sie die <a target=\"_blank\" href=\"%s\">Dokumentation ↗</a>.",
@@ -189,8 +194,8 @@ OC.L10N.register(
"Developer documentation" : "Dokumentation für Entwickler",
"Experimental applications ahead" : "Experimentelle Apps nachfolgend",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentelle Apps sind nicht auf Sicherheitsprobleme hin überprüft, sind neu oder bekanntermaßen instabil und befinden sich in intensiver Entwicklung. Ihre Installation kann Datenverlust oder Sicherheitslücken hervorrufen.",
- "by" : "von",
- "licensed" : "Lizenziert",
+ "by %s" : "durch %s",
+ "%s-licensed" : "%s-Lizensiert",
"Documentation:" : "Dokumentation:",
"User documentation" : "Dokumentation für Benutzer",
"Admin documentation" : "Dokumentation für Administratoren",
@@ -200,6 +205,12 @@ OC.L10N.register(
"Enable only for specific groups" : "Nur für bestimmte Gruppen aktivieren",
"Uninstall App" : "App deinstallieren",
"Enable experimental apps" : "Experimentelle Apps aktivieren",
+ "SSL Root Certificates" : "SSL Root Zertifikate",
+ "Common Name" : "Common Name",
+ "Valid until" : "Gültig bis",
+ "Issued By" : "Ausgestellt von:",
+ "Valid until %s" : "Gültig bis %s",
+ "Import root certificate" : "Root-Zertifikat importieren",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hallo,<br><br>hier nur kurz die Mitteilung, dass Sie jetzt ein %s-Konto haben.<br><br>Ihr Benutzername: %s<br>Greifen Sie darauf zu: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Noch einen schönen Tag!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hallo,\n\nhier nur kurz die Mitteilung, dass Sie jetzt ein %s-Konto haben.\n\nIhr Benutzername: %s\nGreifen Sie darauf zu: %s\n\n",
@@ -208,39 +219,32 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Issue Tracker",
"Commercial support" : "Kommerzieller Support",
- "Get the apps to sync your files" : "Installieren Sie die Anwendungen, um Ihre Dateien zu synchronisieren",
- "Desktop client" : "Desktop-Client",
- "Android app" : "Android-App",
- "iOS app" : "iOS-App",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Wenn Sie das Projekt unterstützen möchten,\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\" rel=\"noreferrer\">beteiligen Sie sich an der Entwicklung</a>\noder\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\" rel=\"noreferrer\">helfen Sie mit, es bekannter zu machen</a>!",
- "Show First Run Wizard again" : "Den Einrichtungsassistenten erneut anzeigen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Sie verwenden <strong>%s</strong> der verfügbaren <strong>%s</strong>",
- "Password" : "Passwort",
- "Unable to change your password" : "Das Passwort konnte nicht geändert werden",
- "Current password" : "Aktuelles Passwort",
- "New password" : "Neues Passwort",
- "Change password" : "Passwort ändern",
+ "Profile picture" : "Profilbild",
+ "Upload new" : "Neues hochladen",
+ "Select from Files" : "Aus Dateien wählen",
+ "Remove image" : "Bild entfernen",
+ "png or jpg, max. 20 MB" : "png oder jpg, max. 20 MB",
+ "Cancel" : "Abbrechen",
+ "Choose as profile picture" : "Als Profilbild auswählen",
"Full name" : "Vollständiger Name",
"No display name set" : "Kein Anzeigename angegeben",
"Email" : "E-Mail",
"Your email address" : "Ihre E-Mail-Adresse",
- "Fill in an email address to enable password recovery and receive notifications" : "Geben Sie eine E-Mail-Adresse an, um eine Wiederherstellung des Passworts zu ermöglichen und Benachrichtigungen zu empfangen",
"No email address set" : "Keine E-Mail-Adresse angegeben",
"You are member of the following groups:" : "Sie sind Mitglied folgender Gruppen:",
- "Profile picture" : "Profilbild",
- "Upload new" : "Neues hochladen",
- "Select new from Files" : "Neues aus Dateien wählen",
- "Remove image" : "Bild entfernen",
- "Your avatar is provided by your original account." : "Ihr Avatar wird von Ihrem Ursprungskonto verwendet.",
- "Cancel" : "Abbrechen",
- "Choose as profile image" : "Als Profilbild wählen",
+ "Password" : "Passwort",
+ "Unable to change your password" : "Das Passwort konnte nicht geändert werden",
+ "Current password" : "Aktuelles Passwort",
+ "New password" : "Neues Passwort",
+ "Change password" : "Passwort ändern",
"Language" : "Sprache",
"Help translate" : "Helfen Sie bei der Übersetzung",
- "Common Name" : "Common Name",
- "Valid until" : "Gültig bis",
- "Issued By" : "Ausgestellt von:",
- "Valid until %s" : "Gültig bis %s",
- "Import root certificate" : "Root-Zertifikat importieren",
+ "Get the apps to sync your files" : "Installieren Sie die Anwendungen, um Ihre Dateien zu synchronisieren",
+ "Desktop client" : "Desktop-Client",
+ "Android app" : "Android-App",
+ "iOS app" : "iOS-App",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Wenn Sie das Projekt unterstützen möchten,\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\" rel=\"noreferrer\">beteiligen Sie sich an der Entwicklung</a>\noder\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\" rel=\"noreferrer\">helfen Sie mit, es bekannter zu machen</a>!",
+ "Show First Run Wizard again" : "Den Einrichtungsassistenten erneut anzeigen",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Entwickelt von der {communityopen}ownCloud-Community{linkclose}, der {githubopen}Quellcode{linkclose} ist unter den Bedingungen der {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} lizenziert.",
"Show storage location" : "Speicherort anzeigen",
"Show last log in" : "Letzte Anmeldung anzeigen",
diff --git a/settings/l10n/de_DE.json b/settings/l10n/de_DE.json
index 1f0adec9b56..0df74f1d602 100644
--- a/settings/l10n/de_DE.json
+++ b/settings/l10n/de_DE.json
@@ -10,12 +10,10 @@
"Log" : "Log",
"Tips & tricks" : "Tipps & Tricks",
"Updates" : "Updates",
- "Authentication error" : "Authentifizierungsfehler",
- "Your full name has been changed." : "Ihr vollständiger Name ist geändert worden.",
- "Unable to change full name" : "Der vollständige Name konnte nicht geändert werden",
"Couldn't remove app." : "Die App konnte nicht entfernt werden.",
"Language changed" : "Sprache geändert",
"Invalid request" : "Ungültige Anforderung",
+ "Authentication error" : "Authentifizierungsfehler",
"Admins can't remove themself from the admin group" : "Administratoren können sich nicht selbst aus der admin-Gruppe löschen",
"Unable to add user to group %s" : "Der Benutzer konnte nicht zur Gruppe %s hinzugefügt werden",
"Unable to remove user from group %s" : "Der Benutzer konnte nicht aus der Gruppe %s entfernt werden",
@@ -49,6 +47,8 @@
"Invalid user" : "Ungültiger Benutzer",
"Unable to change mail address" : "E-Mail-Adresse konnte nicht geändert werden",
"Email saved" : "E-Mail-Adresse gespeichert",
+ "Your full name has been changed." : "Ihr vollständiger Name ist geändert worden.",
+ "Unable to change full name" : "Der vollständige Name konnte nicht geändert werden",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Sind Sie sich wirklich sicher, dass Sie »{domain}« als vertrauenswürdige Domain hinzufügen möchten?",
"Add trusted domain" : "Vertrauenswürdige Domain hinzufügen",
"Migration in progress. Please wait until the migration is finished" : "Migration in Arbeit. Bitte warten Sie, bis die Migration beendet ist",
@@ -74,15 +74,19 @@
"Uninstalling ...." : "Wird deinstalliert…",
"Error while uninstalling app" : "Fehler beim Deinstallieren der App",
"Uninstall" : "Deinstallieren",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Die App wurde aktiviert, aber sie benötigt ein Update. Sie werden zur Update Seite in 5 Sekunden weitergeleitet.",
+ "App update" : "App aktualisieren",
+ "No apps found for \"{query}\"" : "Es wurden keine Apps gefunden für \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Es ist ein Fehler aufgetreten. Bitte laden Sie ein ASCII-kodiertes PEM-Zertifikat hoch.",
+ "Valid until {date}" : "Gültig bis {date}",
+ "Delete" : "Löschen",
+ "An error occurred: {message}" : "Ein Fehler ist aufgetreten: {message}",
"Select a profile picture" : "Wählen Sie ein Profilbild",
"Very weak password" : "Sehr schwaches Passwort",
"Weak password" : "Schwaches Passwort",
"So-so password" : "Passables Passwort",
"Good password" : "Gutes Passwort",
"Strong password" : "Starkes Passwort",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Es ist ein Fehler aufgetreten. Bitte laden Sie ein ASCII-kodiertes PEM-Zertifikat hoch.",
- "Valid until {date}" : "Gültig bis {date}",
- "Delete" : "Löschen",
"Groups" : "Gruppen",
"Unable to delete {objName}" : "Löschen von {objName} nicht möglich",
"Error creating group" : "Fehler beim Erstellen der Gruppe",
@@ -99,9 +103,8 @@
"A valid password must be provided" : "Es muss ein gültiges Passwort angegeben werden",
"A valid email must be provided" : "Es muss eine gültige E-Mail-Adresse angegeben werden",
"__language_name__" : "Deutsch (Förmlich: Sie)",
- "Sync clients" : "Sync-Clients",
"Personal info" : "Persönliche Informationen",
- "SSL root certificates" : "SSL-Root-Zertifikate",
+ "Sync clients" : "Sync-Clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alles (fatale Probleme, Fehler, Warnungen, Infos, Fehlerdiagnose)",
"Info, warnings, errors and fatal issues" : "Infos, Warnungen, Fehler und fatale Probleme",
"Warnings, errors and fatal issues" : "Warnungen, Fehler und fatale Probleme",
@@ -126,13 +129,14 @@
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Wenn sich Ihre Installation nicht im Wurzelverzeichnis der Domain befindet und Cron aus dem System genutzt wird, kann es zu Fehlern bei der URL-Generierung kommen. Um dies zu verhindern, setzen Sie bitte die „overwrite.cli.url“-Option in Ihrer config.php auf das Web-Wurzelverzeichnis Ihrer Installation (Vorschlag: „%s“).",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Die Ausführung des Cron-Jobs über die Kommandozeile war nicht möglich. Die folgenden technischen Fehler sind dabei aufgetreten:",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Bitte überprüfen Sie noch einmal die <a target=\"_blank\" href=\"%s\">Installationsanleitungen ↗</a> und kontrollieren Sie das <a href=\"#log-section\">Log</a> auf mögliche Fehler oder Warnungen.",
+ "All checks passed." : "Alle checks erfolgreich gepfüft.",
"Open documentation" : "Dokumentation öffnen",
- "Allow apps to use the Share API" : "Anwendungen erlauben, die Share-API zu benutzen",
+ "Allow apps to use the Share API" : "Apps die Benutzung der Share-API erlauben",
"Allow users to share via link" : "Benutzern erlauben, Inhalte über Links zu teilen",
"Enforce password protection" : "Passwortschutz erzwingen",
"Allow public uploads" : "Öffentliches Hochladen erlauben",
"Allow users to send mail notification for shared files" : "Benutzern erlauben, E-Mail-Benachrichtigungen für freigegebene Dateien zu senden",
- "Set default expiration date" : "Standardablaufdatum einstellen",
+ "Set default expiration date" : "Standardmäßiges Ablaufdatum setzen",
"Expire after " : "Ablauf nach ",
"days" : "Tagen",
"Enforce expiration date" : "Ablaufdatum erzwingen",
@@ -148,6 +152,7 @@
"cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php ist als Webcron-Dienst registriert, der die cron.php alle 15 Minuten per HTTP aufruft.",
"Use system's cron service to call the cron.php file every 15 minutes." : "Benutzen Sie den systemeigenen Cron-Dienst, um die cron.php alle 15 Minuten aufzurufen.",
"Enable server-side encryption" : "Serverseitige Verschlüsselung aktivieren",
+ "Please read carefully before activating server-side encryption: " : "Bitte lesen Sie ganz genau, bevor Sie die Serverseite Verschlüsselung aktivieren:",
"Enable encryption" : "Verschlüsselung aktivieren",
"No encryption module loaded, please enable an encryption module in the app menu." : "Kein Verschlüsselungs-Modul geladen, bitte aktiviere ein Verschlüsselungs-Modul im Anwendungs-Menü.",
"Select default encryption module:" : "Standard-Verschlüsselungs-Modul auswählen:",
@@ -169,11 +174,11 @@
"Store credentials" : "Anmeldeinformationen speichern",
"Test email settings" : "E-Mail-Einstellungen testen",
"Send email" : "E-Mail senden",
- "Log level" : "Log-Level",
"Download logfile" : "Logdatei herunterladen",
"More" : "Mehr",
"Less" : "Weniger",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Die Logdatei ist größer als 100 MB. Es kann etwas Zeit beanspruchen, sie herunterzuladen!",
+ "What to log" : "Was geloggt wird",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite wird als Datenbank verwendet. Bei größeren Installationen wird empfohlen, auf ein anderes Datenbank-Backend zu wechseln.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Insbesondere bei der Nutzung des Desktop Clients zur Dateisynchronisierung wird vom Einsatz von SQLite abgeraten.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Um auf eine andere Datenbank zu migrieren, benutzen Sie bitte die Kommandozeile: „occ db:convert-type“ oder konsultieren Sie die <a target=\"_blank\" href=\"%s\">Dokumentation ↗</a>.",
@@ -187,8 +192,8 @@
"Developer documentation" : "Dokumentation für Entwickler",
"Experimental applications ahead" : "Experimentelle Apps nachfolgend",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentelle Apps sind nicht auf Sicherheitsprobleme hin überprüft, sind neu oder bekanntermaßen instabil und befinden sich in intensiver Entwicklung. Ihre Installation kann Datenverlust oder Sicherheitslücken hervorrufen.",
- "by" : "von",
- "licensed" : "Lizenziert",
+ "by %s" : "durch %s",
+ "%s-licensed" : "%s-Lizensiert",
"Documentation:" : "Dokumentation:",
"User documentation" : "Dokumentation für Benutzer",
"Admin documentation" : "Dokumentation für Administratoren",
@@ -198,6 +203,12 @@
"Enable only for specific groups" : "Nur für bestimmte Gruppen aktivieren",
"Uninstall App" : "App deinstallieren",
"Enable experimental apps" : "Experimentelle Apps aktivieren",
+ "SSL Root Certificates" : "SSL Root Zertifikate",
+ "Common Name" : "Common Name",
+ "Valid until" : "Gültig bis",
+ "Issued By" : "Ausgestellt von:",
+ "Valid until %s" : "Gültig bis %s",
+ "Import root certificate" : "Root-Zertifikat importieren",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hallo,<br><br>hier nur kurz die Mitteilung, dass Sie jetzt ein %s-Konto haben.<br><br>Ihr Benutzername: %s<br>Greifen Sie darauf zu: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Noch einen schönen Tag!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hallo,\n\nhier nur kurz die Mitteilung, dass Sie jetzt ein %s-Konto haben.\n\nIhr Benutzername: %s\nGreifen Sie darauf zu: %s\n\n",
@@ -206,39 +217,32 @@
"Forum" : "Forum",
"Issue tracker" : "Issue Tracker",
"Commercial support" : "Kommerzieller Support",
- "Get the apps to sync your files" : "Installieren Sie die Anwendungen, um Ihre Dateien zu synchronisieren",
- "Desktop client" : "Desktop-Client",
- "Android app" : "Android-App",
- "iOS app" : "iOS-App",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Wenn Sie das Projekt unterstützen möchten,\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\" rel=\"noreferrer\">beteiligen Sie sich an der Entwicklung</a>\noder\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\" rel=\"noreferrer\">helfen Sie mit, es bekannter zu machen</a>!",
- "Show First Run Wizard again" : "Den Einrichtungsassistenten erneut anzeigen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Sie verwenden <strong>%s</strong> der verfügbaren <strong>%s</strong>",
- "Password" : "Passwort",
- "Unable to change your password" : "Das Passwort konnte nicht geändert werden",
- "Current password" : "Aktuelles Passwort",
- "New password" : "Neues Passwort",
- "Change password" : "Passwort ändern",
+ "Profile picture" : "Profilbild",
+ "Upload new" : "Neues hochladen",
+ "Select from Files" : "Aus Dateien wählen",
+ "Remove image" : "Bild entfernen",
+ "png or jpg, max. 20 MB" : "png oder jpg, max. 20 MB",
+ "Cancel" : "Abbrechen",
+ "Choose as profile picture" : "Als Profilbild auswählen",
"Full name" : "Vollständiger Name",
"No display name set" : "Kein Anzeigename angegeben",
"Email" : "E-Mail",
"Your email address" : "Ihre E-Mail-Adresse",
- "Fill in an email address to enable password recovery and receive notifications" : "Geben Sie eine E-Mail-Adresse an, um eine Wiederherstellung des Passworts zu ermöglichen und Benachrichtigungen zu empfangen",
"No email address set" : "Keine E-Mail-Adresse angegeben",
"You are member of the following groups:" : "Sie sind Mitglied folgender Gruppen:",
- "Profile picture" : "Profilbild",
- "Upload new" : "Neues hochladen",
- "Select new from Files" : "Neues aus Dateien wählen",
- "Remove image" : "Bild entfernen",
- "Your avatar is provided by your original account." : "Ihr Avatar wird von Ihrem Ursprungskonto verwendet.",
- "Cancel" : "Abbrechen",
- "Choose as profile image" : "Als Profilbild wählen",
+ "Password" : "Passwort",
+ "Unable to change your password" : "Das Passwort konnte nicht geändert werden",
+ "Current password" : "Aktuelles Passwort",
+ "New password" : "Neues Passwort",
+ "Change password" : "Passwort ändern",
"Language" : "Sprache",
"Help translate" : "Helfen Sie bei der Übersetzung",
- "Common Name" : "Common Name",
- "Valid until" : "Gültig bis",
- "Issued By" : "Ausgestellt von:",
- "Valid until %s" : "Gültig bis %s",
- "Import root certificate" : "Root-Zertifikat importieren",
+ "Get the apps to sync your files" : "Installieren Sie die Anwendungen, um Ihre Dateien zu synchronisieren",
+ "Desktop client" : "Desktop-Client",
+ "Android app" : "Android-App",
+ "iOS app" : "iOS-App",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Wenn Sie das Projekt unterstützen möchten,\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\" rel=\"noreferrer\">beteiligen Sie sich an der Entwicklung</a>\noder\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\" rel=\"noreferrer\">helfen Sie mit, es bekannter zu machen</a>!",
+ "Show First Run Wizard again" : "Den Einrichtungsassistenten erneut anzeigen",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Entwickelt von der {communityopen}ownCloud-Community{linkclose}, der {githubopen}Quellcode{linkclose} ist unter den Bedingungen der {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} lizenziert.",
"Show storage location" : "Speicherort anzeigen",
"Show last log in" : "Letzte Anmeldung anzeigen",
diff --git a/settings/l10n/el.js b/settings/l10n/el.js
index ab9b47b366c..948d79314f5 100644
--- a/settings/l10n/el.js
+++ b/settings/l10n/el.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Καταγραφές",
"Tips & tricks" : "Συμβουλές & τεχνάσματα",
"Updates" : "Ενημερώσεις",
- "Authentication error" : "Σφάλμα πιστοποίησης",
- "Your full name has been changed." : "Το πλήρες όνομά σας άλλαξε.",
- "Unable to change full name" : "Δεν ήταν δυνατή η αλλαγή του πλήρους ονόματός σας",
"Couldn't remove app." : "Αδυναμία αφαίρεσης εφαρμογής.",
"Language changed" : "Η γλώσσα άλλαξε",
"Invalid request" : "Μη έγκυρο αίτημα",
+ "Authentication error" : "Σφάλμα πιστοποίησης",
"Admins can't remove themself from the admin group" : "Οι διαχειριστές δεν μπορούν να αφαιρέσουν τους εαυτούς τους από την ομάδα των διαχειριστών",
"Unable to add user to group %s" : "Αδυναμία προσθήκη χρήστη στην ομάδα %s",
"Unable to remove user from group %s" : "Αδυναμία αφαίρεσης χρήστη από την ομάδα %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Μη έγκυρος χρήστης",
"Unable to change mail address" : "Αδυναμία αλλαγής διεύθυνσης αλληλογραφίας",
"Email saved" : "Το email αποθηκεύτηκε ",
+ "Your full name has been changed." : "Το πλήρες όνομά σας άλλαξε.",
+ "Unable to change full name" : "Δεν ήταν δυνατή η αλλαγή του πλήρους ονόματός σας",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Είστε πραγματικά σίγουροι ότι θέλετε να προσθέσετε το \"{domain}\" σαν αξιόπιστη περιοχή;",
"Add trusted domain" : "Προσθέστε αξιόπιστη περιοχή",
"Migration in progress. Please wait until the migration is finished" : "Μετάβαση σε εξέλιξη. Παρακαλούμε περιμένετε μέχρι να ολοκληρωθεί η μετάβαση",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Η εφαρμογή έχει ενεργοποιηθεί αλλά χρειάζεται ενημέρωση. Θα μεταφερθείτε στη σελίδα ενημέρωσης σε 5 δευτερόλεπτα.",
"App update" : "Ενημέρωση εφαρμογής",
"No apps found for \"{query}\"" : "Δεν βρέθηκαν εφαρμογές για \"{query\"}",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Προέκυψε σφάλμα. Παρακαλούμε μεταφορτώστε ένα πιστοποιητικό PEM κωδικοποιημένο κατά ASCII.",
+ "Valid until {date}" : "Έγκυρο έως {date}",
+ "Delete" : "Διαγραφή",
"An error occurred: {message}" : "Παρουσιάστηκε σφάλμα: {message}",
"Select a profile picture" : "Επιλογή εικόνας προφίλ",
"Very weak password" : "Πολύ αδύναμο συνθηματικό",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Μέτριο συνθηματικό",
"Good password" : "Καλό συνθηματικό",
"Strong password" : "Δυνατό συνθηματικό",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Προέκυψε σφάλμα. Παρακαλούμε μεταφορτώστε ένα πιστοποιητικό PEM κωδικοποιημένο κατά ASCII.",
- "Valid until {date}" : "Έγκυρο έως {date}",
- "Delete" : "Διαγραφή",
"Groups" : "Ομάδες",
"Unable to delete {objName}" : "Αδυναμία διαγραφής του {objName}",
"Error creating group" : "Σφάλμα δημιουργίας ομάδας",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Πρέπει να δοθεί έγκυρο συνθηματικό",
"A valid email must be provided" : "Πρέπει να εισαχθεί ένα έγκυρο email",
"__language_name__" : "__όνομα_γλώσσας__",
- "Sync clients" : "Συγχρονισμός πελατών",
"Personal info" : "Προσωπικές Πληροφορίες",
- "SSL root certificates" : "Πιστοποιητικά SSL root",
+ "Sync clients" : "Συγχρονισμός πελατών",
"Everything (fatal issues, errors, warnings, info, debug)" : "Όλα (καίρια ζητήματα, σφάλματα, προειδοποιήσεις, πληροφορίες, αποσφαλμάτωση)",
"Info, warnings, errors and fatal issues" : "Πληροφορίες, προειδοποιήσεις, σφάλματα και καίρια ζητήματα",
"Warnings, errors and fatal issues" : "Προειδοποιήσεις, σφάλματα και καίρια ζητήματα",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Προτείνουμε ανεπιφύλακτα να εγκαταστήσετε στο σύστημά σας τα απαιτούμενα πακέτα έτσι ώστε να υποστηρίζεται μια από τις ακόλουθες ρυθμίσεις τοποθεσίας: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Αν η εγκατάστασή σας δεν έχει γίνει στο root του τομέα και χρησιμοποιείται το cron του συστήματος, μπορεί να υπάρξουν ζητήματα με τη δημιουργία URL. Για να αποφύγετε αυτά τα προβλήματα, παρακαλώ ρυθμίστε την επιλογή \"overwrite.cli.url\" στο αρχείο config.php που βρίσκεται στη διαδρομή webroot της εγκατάστασής σας (Suggested: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Δεν ήταν δυνατή η εκτέλεση της cronjob μέσω τερματικού. Εμφανίστηκαν τα παρακάτω τεχνικά σφάλματα:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Το Transactional file locking χρησιμοποιεί τη βάση δεδομένων ως locking backend, για καλύτερες επιδόσεις συστήνουμς τη διαμόρφωση μιας memcache για το κλείδωμα. Δείτε την <a target=\"_blank\" href=\"%s\">τεκμηρίωση ↗</a> για περισσότερες πληροφορίες.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Παρακαλώ ελέγξτε ξανά <a target=\"_blank\" href=\"%s\">τους οδηγούς εγκατάστασης, καθώς επίσης και για τυχόν σφάλματα ή προειδοποιήσεις στο <a href=\"#log-section\">log</a>.",
"All checks passed." : "Όλοι οι έλεγχοι επιτυχείς.",
"Open documentation" : "Ανοιχτή τεκμηρίωση.",
@@ -188,7 +186,6 @@ OC.L10N.register(
"Store credentials" : "Διαπιστευτήρια αποθήκευσης",
"Test email settings" : "Δοκιμή ρυθμίσεων email",
"Send email" : "Αποστολή email",
- "Log level" : "Επίπεδο καταγραφής",
"Download logfile" : "Λήψη αρχείου ιστορικού",
"More" : "Περισσότερα",
"Less" : "Λιγότερα",
@@ -206,8 +203,6 @@ OC.L10N.register(
"Developer documentation" : "Τεκμηρίωση προγραμματιστή",
"Experimental applications ahead" : "Πειραματικές εφαρμογές",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Οι πειραματικές εφαρμογές δεν ελέγχονται για θέματα ασφάλειας, είναι ασταθείς και υπό συνεχή εξέλιξη. Η εγκατάσταση τους μπορεί να προκαλέσει απώλεια δεδομένων ή παραβιάσεις της ασφάλειας.",
- "by" : "από",
- "licensed" : "Άδεια",
"Documentation:" : "Τεκμηρίωση:",
"User documentation" : "Τεκμηρίωση Χρήστη",
"Admin documentation" : "Τεκμηρίωση Διαχειριστή",
@@ -217,6 +212,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Ενεργοποίηση μόνο για καθορισμένες ομάδες",
"Uninstall App" : "Απεγκατάσταση Εφαρμογής",
"Enable experimental apps" : "Ενεργοποίηση πειραματικών εφαρμογών",
+ "Common Name" : "Κοινό Όνομα",
+ "Valid until" : "Έγκυρο έως",
+ "Issued By" : "Έκδόθηκε από",
+ "Valid until %s" : "Έγκυρο έως %s",
+ "Import root certificate" : "Εισαγωγή Πιστοποιητικού Root",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Χαίρεται,<br><br>απλά σας κάνουμε γνωστό ότι διαθέτετε έναν %s λογαριασμό.<br><br>Το όνομά σας είναι: %s<br>Έχετε πρόσβαση: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Χαιρετισμούς!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Χαίρεται, \nαπλά σας κάνουμε γνωστό ότι διαθέτετε έναν %s λογαριασμό.\nΤο όνομά σας είναι: %s\nΈχετε πρόσβαση: %s\n",
@@ -225,40 +225,29 @@ OC.L10N.register(
"Forum" : "Φόρουμ",
"Issue tracker" : "Ιχνηλάτης ζητημάτων",
"Commercial support" : "Εμπορική Υποστήριξη",
- "Get the apps to sync your files" : "Λήψη της εφαρμογής για συγχρονισμό των αρχείων σας",
- "Desktop client" : "Πελάτης σταθερού υπολογιστή",
- "Android app" : "Εφαρμογή Android",
- "iOS app" : "Εφαρμογή iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Εάν θέλετε να υποστηρίξετε το έργο\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">συμμετέχετε στην ανάπτυξη</a>\n\t\tή\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">διαδόστε το μήνυμα</a>!",
- "Show First Run Wizard again" : "Προβολή Οδηγού Πρώτης Εκτέλεσης ξανά",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Χρησιμοποιήσατε <strong>%s</strong> από τα <strong>%s</strong> διαθέσιμα",
- "Password" : "Συνθηματικό",
- "Unable to change your password" : "Δεν ήταν δυνατή η αλλαγή του κωδικού πρόσβασης",
- "Current password" : "Τρέχων συνθηματικό",
- "New password" : "Νέο συνθηματικό",
- "Change password" : "Αλλαγή συνθηματικού",
+ "Profile picture" : "Φωτογραφία προφίλ",
+ "Upload new" : "Μεταφόρτωση νέου",
+ "Remove image" : "Αφαίρεση εικόνας",
+ "Cancel" : "Άκυρο",
"Full name" : "Πλήρες όνομα",
"No display name set" : "Δεν ορίστηκε όνομα",
"Email" : "Ηλεκτρονικό ταχυδρομείο",
"Your email address" : "Η διεύθυνση ηλ. ταχυδρομείου σας",
- "Fill in an email address to enable password recovery and receive notifications" : "Συμπληρώστε μια διεύθυνση email για να ενεργοποιήσετε την επαναφορά συνθηματικού και να λαμβάνετε ειδοποιήσεις",
"No email address set" : "Δεν ορίστηκε διεύθυνση email",
"You are member of the following groups:" : "Είστε μέλος των ακόλουθων ομάδων:",
- "Profile picture" : "Φωτογραφία προφίλ",
- "Upload new" : "Μεταφόρτωση νέου",
- "Select new from Files" : "Επιλογή νέου από τα Αρχεία",
- "Remove image" : "Αφαίρεση εικόνας",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Είτε png ή jpg. Ιδανικά τετράγωνη αλλά θα είστε σε θέση να την περικόψετε. Το αρχείο δεν θα πρέπει να υπερβαίνει το μέγιστο μέγεθος των 20 MB.",
- "Your avatar is provided by your original account." : "Το άβατάρ σας παρέχεται από τον αρχικό σας λογαριασμό.",
- "Cancel" : "Άκυρο",
- "Choose as profile image" : "Επιλογή εικόνας προφίλ",
+ "Password" : "Συνθηματικό",
+ "Unable to change your password" : "Δεν ήταν δυνατή η αλλαγή του κωδικού πρόσβασης",
+ "Current password" : "Τρέχων συνθηματικό",
+ "New password" : "Νέο συνθηματικό",
+ "Change password" : "Αλλαγή συνθηματικού",
"Language" : "Γλώσσα",
"Help translate" : "Βοηθήστε στη μετάφραση",
- "Common Name" : "Κοινό Όνομα",
- "Valid until" : "Έγκυρο έως",
- "Issued By" : "Έκδόθηκε από",
- "Valid until %s" : "Έγκυρο έως %s",
- "Import root certificate" : "Εισαγωγή Πιστοποιητικού Root",
+ "Get the apps to sync your files" : "Λήψη της εφαρμογής για συγχρονισμό των αρχείων σας",
+ "Desktop client" : "Πελάτης σταθερού υπολογιστή",
+ "Android app" : "Εφαρμογή Android",
+ "iOS app" : "Εφαρμογή iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Εάν θέλετε να υποστηρίξετε το έργο\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">συμμετέχετε στην ανάπτυξη</a>\n\t\tή\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">διαδόστε το μήνυμα</a>!",
+ "Show First Run Wizard again" : "Προβολή Οδηγού Πρώτης Εκτέλεσης ξανά",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Αναπτύχθηκε από την {communityopen} κοινότητα του ownCloud {linkclose}, ο {githubopen} πηγαίος κώδικας {linkclose} έχει την άδεια της {licenseopen} <abbr title = \"Affero General Public License\"> AGPL </ abbr> {linkclose}.",
"Show storage location" : "Εμφάνιση τοποθεσίας αποθήκευσης",
"Show last log in" : "Εμφάνιση τελευταίας εισόδου",
diff --git a/settings/l10n/el.json b/settings/l10n/el.json
index c355f70dd82..1db6c7d1085 100644
--- a/settings/l10n/el.json
+++ b/settings/l10n/el.json
@@ -10,12 +10,10 @@
"Log" : "Καταγραφές",
"Tips & tricks" : "Συμβουλές & τεχνάσματα",
"Updates" : "Ενημερώσεις",
- "Authentication error" : "Σφάλμα πιστοποίησης",
- "Your full name has been changed." : "Το πλήρες όνομά σας άλλαξε.",
- "Unable to change full name" : "Δεν ήταν δυνατή η αλλαγή του πλήρους ονόματός σας",
"Couldn't remove app." : "Αδυναμία αφαίρεσης εφαρμογής.",
"Language changed" : "Η γλώσσα άλλαξε",
"Invalid request" : "Μη έγκυρο αίτημα",
+ "Authentication error" : "Σφάλμα πιστοποίησης",
"Admins can't remove themself from the admin group" : "Οι διαχειριστές δεν μπορούν να αφαιρέσουν τους εαυτούς τους από την ομάδα των διαχειριστών",
"Unable to add user to group %s" : "Αδυναμία προσθήκη χρήστη στην ομάδα %s",
"Unable to remove user from group %s" : "Αδυναμία αφαίρεσης χρήστη από την ομάδα %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Μη έγκυρος χρήστης",
"Unable to change mail address" : "Αδυναμία αλλαγής διεύθυνσης αλληλογραφίας",
"Email saved" : "Το email αποθηκεύτηκε ",
+ "Your full name has been changed." : "Το πλήρες όνομά σας άλλαξε.",
+ "Unable to change full name" : "Δεν ήταν δυνατή η αλλαγή του πλήρους ονόματός σας",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Είστε πραγματικά σίγουροι ότι θέλετε να προσθέσετε το \"{domain}\" σαν αξιόπιστη περιοχή;",
"Add trusted domain" : "Προσθέστε αξιόπιστη περιοχή",
"Migration in progress. Please wait until the migration is finished" : "Μετάβαση σε εξέλιξη. Παρακαλούμε περιμένετε μέχρι να ολοκληρωθεί η μετάβαση",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Η εφαρμογή έχει ενεργοποιηθεί αλλά χρειάζεται ενημέρωση. Θα μεταφερθείτε στη σελίδα ενημέρωσης σε 5 δευτερόλεπτα.",
"App update" : "Ενημέρωση εφαρμογής",
"No apps found for \"{query}\"" : "Δεν βρέθηκαν εφαρμογές για \"{query\"}",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Προέκυψε σφάλμα. Παρακαλούμε μεταφορτώστε ένα πιστοποιητικό PEM κωδικοποιημένο κατά ASCII.",
+ "Valid until {date}" : "Έγκυρο έως {date}",
+ "Delete" : "Διαγραφή",
"An error occurred: {message}" : "Παρουσιάστηκε σφάλμα: {message}",
"Select a profile picture" : "Επιλογή εικόνας προφίλ",
"Very weak password" : "Πολύ αδύναμο συνθηματικό",
@@ -86,9 +89,6 @@
"So-so password" : "Μέτριο συνθηματικό",
"Good password" : "Καλό συνθηματικό",
"Strong password" : "Δυνατό συνθηματικό",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Προέκυψε σφάλμα. Παρακαλούμε μεταφορτώστε ένα πιστοποιητικό PEM κωδικοποιημένο κατά ASCII.",
- "Valid until {date}" : "Έγκυρο έως {date}",
- "Delete" : "Διαγραφή",
"Groups" : "Ομάδες",
"Unable to delete {objName}" : "Αδυναμία διαγραφής του {objName}",
"Error creating group" : "Σφάλμα δημιουργίας ομάδας",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Πρέπει να δοθεί έγκυρο συνθηματικό",
"A valid email must be provided" : "Πρέπει να εισαχθεί ένα έγκυρο email",
"__language_name__" : "__όνομα_γλώσσας__",
- "Sync clients" : "Συγχρονισμός πελατών",
"Personal info" : "Προσωπικές Πληροφορίες",
- "SSL root certificates" : "Πιστοποιητικά SSL root",
+ "Sync clients" : "Συγχρονισμός πελατών",
"Everything (fatal issues, errors, warnings, info, debug)" : "Όλα (καίρια ζητήματα, σφάλματα, προειδοποιήσεις, πληροφορίες, αποσφαλμάτωση)",
"Info, warnings, errors and fatal issues" : "Πληροφορίες, προειδοποιήσεις, σφάλματα και καίρια ζητήματα",
"Warnings, errors and fatal issues" : "Προειδοποιήσεις, σφάλματα και καίρια ζητήματα",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Προτείνουμε ανεπιφύλακτα να εγκαταστήσετε στο σύστημά σας τα απαιτούμενα πακέτα έτσι ώστε να υποστηρίζεται μια από τις ακόλουθες ρυθμίσεις τοποθεσίας: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Αν η εγκατάστασή σας δεν έχει γίνει στο root του τομέα και χρησιμοποιείται το cron του συστήματος, μπορεί να υπάρξουν ζητήματα με τη δημιουργία URL. Για να αποφύγετε αυτά τα προβλήματα, παρακαλώ ρυθμίστε την επιλογή \"overwrite.cli.url\" στο αρχείο config.php που βρίσκεται στη διαδρομή webroot της εγκατάστασής σας (Suggested: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Δεν ήταν δυνατή η εκτέλεση της cronjob μέσω τερματικού. Εμφανίστηκαν τα παρακάτω τεχνικά σφάλματα:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Το Transactional file locking χρησιμοποιεί τη βάση δεδομένων ως locking backend, για καλύτερες επιδόσεις συστήνουμς τη διαμόρφωση μιας memcache για το κλείδωμα. Δείτε την <a target=\"_blank\" href=\"%s\">τεκμηρίωση ↗</a> για περισσότερες πληροφορίες.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Παρακαλώ ελέγξτε ξανά <a target=\"_blank\" href=\"%s\">τους οδηγούς εγκατάστασης, καθώς επίσης και για τυχόν σφάλματα ή προειδοποιήσεις στο <a href=\"#log-section\">log</a>.",
"All checks passed." : "Όλοι οι έλεγχοι επιτυχείς.",
"Open documentation" : "Ανοιχτή τεκμηρίωση.",
@@ -186,7 +184,6 @@
"Store credentials" : "Διαπιστευτήρια αποθήκευσης",
"Test email settings" : "Δοκιμή ρυθμίσεων email",
"Send email" : "Αποστολή email",
- "Log level" : "Επίπεδο καταγραφής",
"Download logfile" : "Λήψη αρχείου ιστορικού",
"More" : "Περισσότερα",
"Less" : "Λιγότερα",
@@ -204,8 +201,6 @@
"Developer documentation" : "Τεκμηρίωση προγραμματιστή",
"Experimental applications ahead" : "Πειραματικές εφαρμογές",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Οι πειραματικές εφαρμογές δεν ελέγχονται για θέματα ασφάλειας, είναι ασταθείς και υπό συνεχή εξέλιξη. Η εγκατάσταση τους μπορεί να προκαλέσει απώλεια δεδομένων ή παραβιάσεις της ασφάλειας.",
- "by" : "από",
- "licensed" : "Άδεια",
"Documentation:" : "Τεκμηρίωση:",
"User documentation" : "Τεκμηρίωση Χρήστη",
"Admin documentation" : "Τεκμηρίωση Διαχειριστή",
@@ -215,6 +210,11 @@
"Enable only for specific groups" : "Ενεργοποίηση μόνο για καθορισμένες ομάδες",
"Uninstall App" : "Απεγκατάσταση Εφαρμογής",
"Enable experimental apps" : "Ενεργοποίηση πειραματικών εφαρμογών",
+ "Common Name" : "Κοινό Όνομα",
+ "Valid until" : "Έγκυρο έως",
+ "Issued By" : "Έκδόθηκε από",
+ "Valid until %s" : "Έγκυρο έως %s",
+ "Import root certificate" : "Εισαγωγή Πιστοποιητικού Root",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Χαίρεται,<br><br>απλά σας κάνουμε γνωστό ότι διαθέτετε έναν %s λογαριασμό.<br><br>Το όνομά σας είναι: %s<br>Έχετε πρόσβαση: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Χαιρετισμούς!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Χαίρεται, \nαπλά σας κάνουμε γνωστό ότι διαθέτετε έναν %s λογαριασμό.\nΤο όνομά σας είναι: %s\nΈχετε πρόσβαση: %s\n",
@@ -223,40 +223,29 @@
"Forum" : "Φόρουμ",
"Issue tracker" : "Ιχνηλάτης ζητημάτων",
"Commercial support" : "Εμπορική Υποστήριξη",
- "Get the apps to sync your files" : "Λήψη της εφαρμογής για συγχρονισμό των αρχείων σας",
- "Desktop client" : "Πελάτης σταθερού υπολογιστή",
- "Android app" : "Εφαρμογή Android",
- "iOS app" : "Εφαρμογή iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Εάν θέλετε να υποστηρίξετε το έργο\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">συμμετέχετε στην ανάπτυξη</a>\n\t\tή\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">διαδόστε το μήνυμα</a>!",
- "Show First Run Wizard again" : "Προβολή Οδηγού Πρώτης Εκτέλεσης ξανά",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Χρησιμοποιήσατε <strong>%s</strong> από τα <strong>%s</strong> διαθέσιμα",
- "Password" : "Συνθηματικό",
- "Unable to change your password" : "Δεν ήταν δυνατή η αλλαγή του κωδικού πρόσβασης",
- "Current password" : "Τρέχων συνθηματικό",
- "New password" : "Νέο συνθηματικό",
- "Change password" : "Αλλαγή συνθηματικού",
+ "Profile picture" : "Φωτογραφία προφίλ",
+ "Upload new" : "Μεταφόρτωση νέου",
+ "Remove image" : "Αφαίρεση εικόνας",
+ "Cancel" : "Άκυρο",
"Full name" : "Πλήρες όνομα",
"No display name set" : "Δεν ορίστηκε όνομα",
"Email" : "Ηλεκτρονικό ταχυδρομείο",
"Your email address" : "Η διεύθυνση ηλ. ταχυδρομείου σας",
- "Fill in an email address to enable password recovery and receive notifications" : "Συμπληρώστε μια διεύθυνση email για να ενεργοποιήσετε την επαναφορά συνθηματικού και να λαμβάνετε ειδοποιήσεις",
"No email address set" : "Δεν ορίστηκε διεύθυνση email",
"You are member of the following groups:" : "Είστε μέλος των ακόλουθων ομάδων:",
- "Profile picture" : "Φωτογραφία προφίλ",
- "Upload new" : "Μεταφόρτωση νέου",
- "Select new from Files" : "Επιλογή νέου από τα Αρχεία",
- "Remove image" : "Αφαίρεση εικόνας",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Είτε png ή jpg. Ιδανικά τετράγωνη αλλά θα είστε σε θέση να την περικόψετε. Το αρχείο δεν θα πρέπει να υπερβαίνει το μέγιστο μέγεθος των 20 MB.",
- "Your avatar is provided by your original account." : "Το άβατάρ σας παρέχεται από τον αρχικό σας λογαριασμό.",
- "Cancel" : "Άκυρο",
- "Choose as profile image" : "Επιλογή εικόνας προφίλ",
+ "Password" : "Συνθηματικό",
+ "Unable to change your password" : "Δεν ήταν δυνατή η αλλαγή του κωδικού πρόσβασης",
+ "Current password" : "Τρέχων συνθηματικό",
+ "New password" : "Νέο συνθηματικό",
+ "Change password" : "Αλλαγή συνθηματικού",
"Language" : "Γλώσσα",
"Help translate" : "Βοηθήστε στη μετάφραση",
- "Common Name" : "Κοινό Όνομα",
- "Valid until" : "Έγκυρο έως",
- "Issued By" : "Έκδόθηκε από",
- "Valid until %s" : "Έγκυρο έως %s",
- "Import root certificate" : "Εισαγωγή Πιστοποιητικού Root",
+ "Get the apps to sync your files" : "Λήψη της εφαρμογής για συγχρονισμό των αρχείων σας",
+ "Desktop client" : "Πελάτης σταθερού υπολογιστή",
+ "Android app" : "Εφαρμογή Android",
+ "iOS app" : "Εφαρμογή iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Εάν θέλετε να υποστηρίξετε το έργο\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">συμμετέχετε στην ανάπτυξη</a>\n\t\tή\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">διαδόστε το μήνυμα</a>!",
+ "Show First Run Wizard again" : "Προβολή Οδηγού Πρώτης Εκτέλεσης ξανά",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Αναπτύχθηκε από την {communityopen} κοινότητα του ownCloud {linkclose}, ο {githubopen} πηγαίος κώδικας {linkclose} έχει την άδεια της {licenseopen} <abbr title = \"Affero General Public License\"> AGPL </ abbr> {linkclose}.",
"Show storage location" : "Εμφάνιση τοποθεσίας αποθήκευσης",
"Show last log in" : "Εμφάνιση τελευταίας εισόδου",
diff --git a/settings/l10n/en_GB.js b/settings/l10n/en_GB.js
index 0a51d19bb6d..83ecc8e599d 100644
--- a/settings/l10n/en_GB.js
+++ b/settings/l10n/en_GB.js
@@ -10,12 +10,10 @@ OC.L10N.register(
"Log" : "Log",
"Tips & tricks" : "Tips & tricks",
"Updates" : "Updates",
- "Authentication error" : "Authentication error",
- "Your full name has been changed." : "Your full name has been changed.",
- "Unable to change full name" : "Unable to change full name",
"Couldn't remove app." : "Couldn't remove app.",
"Language changed" : "Language changed",
"Invalid request" : "Invalid request",
+ "Authentication error" : "Authentication error",
"Admins can't remove themself from the admin group" : "Admins can't remove themselves from the admin group",
"Unable to add user to group %s" : "Unable to add user to group %s",
"Unable to remove user from group %s" : "Unable to remove user from group %s",
@@ -49,6 +47,8 @@ OC.L10N.register(
"Invalid user" : "Invalid user",
"Unable to change mail address" : "Unable to change mail address",
"Email saved" : "Email saved",
+ "Your full name has been changed." : "Your full name has been changed.",
+ "Unable to change full name" : "Unable to change full name",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Are you really sure you want add \"{domain}\" as a trusted domain?",
"Add trusted domain" : "Add trusted domain",
"Migration in progress. Please wait until the migration is finished" : "Migration in progress. Please wait until the migration is finished",
@@ -73,15 +73,15 @@ OC.L10N.register(
"Uninstalling ...." : "Uninstalling...",
"Error while uninstalling app" : "Error whilst uninstalling app",
"Uninstall" : "Uninstall",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "An error occurred. Please upload an ASCII-encoded PEM certificate.",
+ "Valid until {date}" : "Valid until {date}",
+ "Delete" : "Delete",
"Select a profile picture" : "Select a profile picture",
"Very weak password" : "Very weak password",
"Weak password" : "Weak password",
"So-so password" : "So-so password",
"Good password" : "Good password",
"Strong password" : "Strong password",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "An error occurred. Please upload an ASCII-encoded PEM certificate.",
- "Valid until {date}" : "Valid until {date}",
- "Delete" : "Delete",
"Groups" : "Groups",
"Unable to delete {objName}" : "Unable to delete {objName}",
"Error creating group" : "Error creating group",
@@ -98,9 +98,8 @@ OC.L10N.register(
"A valid password must be provided" : "A valid password must be provided",
"A valid email must be provided" : "A valid email must be provided",
"__language_name__" : "English (British English)",
- "Sync clients" : "Sync clients",
"Personal info" : "Personal info",
- "SSL root certificates" : "SSL root certificates",
+ "Sync clients" : "Sync clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Everything (fatal issues, errors, warnings, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, warnings, errors and fatal issues",
"Warnings, errors and fatal issues" : "Warnings, errors and fatal issues",
@@ -167,7 +166,6 @@ OC.L10N.register(
"Store credentials" : "Store credentials",
"Test email settings" : "Test email settings",
"Send email" : "Send email",
- "Log level" : "Log level",
"Download logfile" : "Download logfile",
"More" : "More",
"Less" : "Less",
@@ -185,8 +183,6 @@ OC.L10N.register(
"Developer documentation" : "Developer documentation",
"Experimental applications ahead" : "Experimental applications ahead",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches.",
- "by" : "by",
- "licensed" : "licensed",
"Documentation:" : "Documentation:",
"User documentation" : "User documentation",
"Show description …" : "Show description …",
@@ -195,6 +191,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Enable only for specific groups",
"Uninstall App" : "Uninstall App",
"Enable experimental apps" : "Enable experimental apps",
+ "Common Name" : "Common Name",
+ "Valid until" : "Valid until",
+ "Issued By" : "Issued By",
+ "Valid until %s" : "Valid until %s",
+ "Import root certificate" : "Import root certificate",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Cheers!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n",
@@ -203,39 +204,29 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Issue tracker",
"Commercial support" : "Commercial support",
- "Get the apps to sync your files" : "Get the apps to sync your files",
- "Desktop client" : "Desktop client",
- "Android app" : "Android app",
- "iOS app" : "iOS app",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!",
- "Show First Run Wizard again" : "Show First Run Wizard again",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "You have used <strong>%s</strong> of the available <strong>%s</strong>",
- "Password" : "Password",
- "Unable to change your password" : "Unable to change your password",
- "Current password" : "Current password",
- "New password" : "New password",
- "Change password" : "Change password",
+ "Profile picture" : "Profile picture",
+ "Upload new" : "Upload new",
+ "Remove image" : "Remove image",
+ "Cancel" : "Cancel",
"Full name" : "Full name",
"No display name set" : "No display name set",
"Email" : "Email",
"Your email address" : "Your email address",
- "Fill in an email address to enable password recovery and receive notifications" : "Fill in an email address to enable password recovery and receive notifications",
"No email address set" : "No email address set",
"You are member of the following groups:" : "You are member of the following groups:",
- "Profile picture" : "Profile picture",
- "Upload new" : "Upload new",
- "Select new from Files" : "Select new from Files",
- "Remove image" : "Remove image",
- "Your avatar is provided by your original account." : "Your avatar is provided by your original account.",
- "Cancel" : "Cancel",
- "Choose as profile image" : "Choose as profile image",
+ "Password" : "Password",
+ "Unable to change your password" : "Unable to change your password",
+ "Current password" : "Current password",
+ "New password" : "New password",
+ "Change password" : "Change password",
"Language" : "Language",
"Help translate" : "Help translate",
- "Common Name" : "Common Name",
- "Valid until" : "Valid until",
- "Issued By" : "Issued By",
- "Valid until %s" : "Valid until %s",
- "Import root certificate" : "Import root certificate",
+ "Get the apps to sync your files" : "Get the apps to sync your files",
+ "Desktop client" : "Desktop client",
+ "Android app" : "Android app",
+ "iOS app" : "iOS app",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!",
+ "Show First Run Wizard again" : "Show First Run Wizard again",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public Licence\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Show storage location",
"Show last log in" : "Show last log in",
diff --git a/settings/l10n/en_GB.json b/settings/l10n/en_GB.json
index a696c3dcbc1..c4e19d4546e 100644
--- a/settings/l10n/en_GB.json
+++ b/settings/l10n/en_GB.json
@@ -8,12 +8,10 @@
"Log" : "Log",
"Tips & tricks" : "Tips & tricks",
"Updates" : "Updates",
- "Authentication error" : "Authentication error",
- "Your full name has been changed." : "Your full name has been changed.",
- "Unable to change full name" : "Unable to change full name",
"Couldn't remove app." : "Couldn't remove app.",
"Language changed" : "Language changed",
"Invalid request" : "Invalid request",
+ "Authentication error" : "Authentication error",
"Admins can't remove themself from the admin group" : "Admins can't remove themselves from the admin group",
"Unable to add user to group %s" : "Unable to add user to group %s",
"Unable to remove user from group %s" : "Unable to remove user from group %s",
@@ -47,6 +45,8 @@
"Invalid user" : "Invalid user",
"Unable to change mail address" : "Unable to change mail address",
"Email saved" : "Email saved",
+ "Your full name has been changed." : "Your full name has been changed.",
+ "Unable to change full name" : "Unable to change full name",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Are you really sure you want add \"{domain}\" as a trusted domain?",
"Add trusted domain" : "Add trusted domain",
"Migration in progress. Please wait until the migration is finished" : "Migration in progress. Please wait until the migration is finished",
@@ -71,15 +71,15 @@
"Uninstalling ...." : "Uninstalling...",
"Error while uninstalling app" : "Error whilst uninstalling app",
"Uninstall" : "Uninstall",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "An error occurred. Please upload an ASCII-encoded PEM certificate.",
+ "Valid until {date}" : "Valid until {date}",
+ "Delete" : "Delete",
"Select a profile picture" : "Select a profile picture",
"Very weak password" : "Very weak password",
"Weak password" : "Weak password",
"So-so password" : "So-so password",
"Good password" : "Good password",
"Strong password" : "Strong password",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "An error occurred. Please upload an ASCII-encoded PEM certificate.",
- "Valid until {date}" : "Valid until {date}",
- "Delete" : "Delete",
"Groups" : "Groups",
"Unable to delete {objName}" : "Unable to delete {objName}",
"Error creating group" : "Error creating group",
@@ -96,9 +96,8 @@
"A valid password must be provided" : "A valid password must be provided",
"A valid email must be provided" : "A valid email must be provided",
"__language_name__" : "English (British English)",
- "Sync clients" : "Sync clients",
"Personal info" : "Personal info",
- "SSL root certificates" : "SSL root certificates",
+ "Sync clients" : "Sync clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Everything (fatal issues, errors, warnings, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, warnings, errors and fatal issues",
"Warnings, errors and fatal issues" : "Warnings, errors and fatal issues",
@@ -165,7 +164,6 @@
"Store credentials" : "Store credentials",
"Test email settings" : "Test email settings",
"Send email" : "Send email",
- "Log level" : "Log level",
"Download logfile" : "Download logfile",
"More" : "More",
"Less" : "Less",
@@ -183,8 +181,6 @@
"Developer documentation" : "Developer documentation",
"Experimental applications ahead" : "Experimental applications ahead",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches.",
- "by" : "by",
- "licensed" : "licensed",
"Documentation:" : "Documentation:",
"User documentation" : "User documentation",
"Show description …" : "Show description …",
@@ -193,6 +189,11 @@
"Enable only for specific groups" : "Enable only for specific groups",
"Uninstall App" : "Uninstall App",
"Enable experimental apps" : "Enable experimental apps",
+ "Common Name" : "Common Name",
+ "Valid until" : "Valid until",
+ "Issued By" : "Issued By",
+ "Valid until %s" : "Valid until %s",
+ "Import root certificate" : "Import root certificate",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Cheers!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n",
@@ -201,39 +202,29 @@
"Forum" : "Forum",
"Issue tracker" : "Issue tracker",
"Commercial support" : "Commercial support",
- "Get the apps to sync your files" : "Get the apps to sync your files",
- "Desktop client" : "Desktop client",
- "Android app" : "Android app",
- "iOS app" : "iOS app",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!",
- "Show First Run Wizard again" : "Show First Run Wizard again",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "You have used <strong>%s</strong> of the available <strong>%s</strong>",
- "Password" : "Password",
- "Unable to change your password" : "Unable to change your password",
- "Current password" : "Current password",
- "New password" : "New password",
- "Change password" : "Change password",
+ "Profile picture" : "Profile picture",
+ "Upload new" : "Upload new",
+ "Remove image" : "Remove image",
+ "Cancel" : "Cancel",
"Full name" : "Full name",
"No display name set" : "No display name set",
"Email" : "Email",
"Your email address" : "Your email address",
- "Fill in an email address to enable password recovery and receive notifications" : "Fill in an email address to enable password recovery and receive notifications",
"No email address set" : "No email address set",
"You are member of the following groups:" : "You are member of the following groups:",
- "Profile picture" : "Profile picture",
- "Upload new" : "Upload new",
- "Select new from Files" : "Select new from Files",
- "Remove image" : "Remove image",
- "Your avatar is provided by your original account." : "Your avatar is provided by your original account.",
- "Cancel" : "Cancel",
- "Choose as profile image" : "Choose as profile image",
+ "Password" : "Password",
+ "Unable to change your password" : "Unable to change your password",
+ "Current password" : "Current password",
+ "New password" : "New password",
+ "Change password" : "Change password",
"Language" : "Language",
"Help translate" : "Help translate",
- "Common Name" : "Common Name",
- "Valid until" : "Valid until",
- "Issued By" : "Issued By",
- "Valid until %s" : "Valid until %s",
- "Import root certificate" : "Import root certificate",
+ "Get the apps to sync your files" : "Get the apps to sync your files",
+ "Desktop client" : "Desktop client",
+ "Android app" : "Android app",
+ "iOS app" : "iOS app",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!",
+ "Show First Run Wizard again" : "Show First Run Wizard again",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public Licence\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Show storage location",
"Show last log in" : "Show last log in",
diff --git a/settings/l10n/eo.js b/settings/l10n/eo.js
index 196fcff74d2..fce5b497b37 100644
--- a/settings/l10n/eo.js
+++ b/settings/l10n/eo.js
@@ -6,11 +6,9 @@ OC.L10N.register(
"Cron" : "Cron",
"Log" : "Protokolo",
"Updates" : "Ĝisdatigoj",
- "Authentication error" : "Aŭtentiga eraro",
- "Your full name has been changed." : "Via plena nomo ŝanĝitas.",
- "Unable to change full name" : "Ne eblis ŝanĝi la plenan nomon",
"Language changed" : "La lingvo estas ŝanĝita",
"Invalid request" : "Nevalida peto",
+ "Authentication error" : "Aŭtentiga eraro",
"Admins can't remove themself from the admin group" : "Administrantoj ne povas forigi sin mem el la administra grupo.",
"Unable to add user to group %s" : "Ne eblis aldoni la uzanton al la grupo %s",
"Unable to remove user from group %s" : "Ne eblis forigi la uzantan el la grupo %s",
@@ -21,6 +19,8 @@ OC.L10N.register(
"Saved" : "Konservita",
"Email sent" : "La retpoŝtaĵo sendiĝis",
"Email saved" : "La retpoŝtadreso konserviĝis",
+ "Your full name has been changed." : "Via plena nomo ŝanĝitas.",
+ "Unable to change full name" : "Ne eblis ŝanĝi la plenan nomon",
"Sending..." : "Sendante...",
"All" : "Ĉio",
"Please wait...." : "Bonvolu atendi...",
@@ -34,13 +34,13 @@ OC.L10N.register(
"Uninstalling ...." : "Malinstalante...",
"Error while uninstalling app" : "Eraris malinstalo de aplikaĵo",
"Uninstall" : "Malinstali",
+ "Delete" : "Forigi",
"Select a profile picture" : "Elekti profilan bildon",
"Very weak password" : "Tre malforta pasvorto",
"Weak password" : "Malforta pasvorto",
"So-so password" : "Mezaĉa pasvorto",
"Good password" : "Bona pasvorto",
"Strong password" : "Forta pasvorto",
- "Delete" : "Forigi",
"Groups" : "Grupoj",
"deleted {groupName}" : "{groupName} foriĝis",
"undo" : "malfari",
@@ -51,7 +51,6 @@ OC.L10N.register(
"Error creating user" : "Eraris kreo de uzanto",
"A valid password must be provided" : "Valida pasvorto devas proviziĝi",
"__language_name__" : "Esperanto",
- "SSL root certificates" : "Radikaj SSL-atestoj",
"Everything (fatal issues, errors, warnings, info, debug)" : "Ĉio (fatalaĵoj, eraroj, avertoj, informoj, sencimigaj mesaĝoj)",
"Info, warnings, errors and fatal issues" : "Informoj, avertoj, eraroj kaj fatalaĵoj",
"Warnings, errors and fatal issues" : "Avertoj, eraroj kaj fatalaĵoj",
@@ -79,32 +78,27 @@ OC.L10N.register(
"SMTP Username" : "SMTP-uzantonomo",
"SMTP Password" : "SMTP-pasvorto",
"Send email" : "Sendi retpoŝton",
- "Log level" : "Registronivelo",
"More" : "Pli",
"Less" : "Malpli",
"Version" : "Eldono",
- "by" : "de",
"Documentation:" : "Dokumentaro:",
"Enable only for specific groups" : "Kapabligi nur por specifajn grupojn",
"Uninstall App" : "Malinstali aplikaĵon",
"Forum" : "Forumo",
- "Get the apps to sync your files" : "Ekhavu la aplikaĵojn por sinkronigi viajn dosierojn",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Vi uzas <strong>%s</strong> el la disponeblaj <strong>%s</strong>",
+ "Profile picture" : "Profila bildo",
+ "Upload new" : "Alŝuti novan",
+ "Remove image" : "Forigi bildon",
+ "Cancel" : "Nuligi",
+ "Email" : "Retpoŝto",
+ "Your email address" : "Via retpoŝta adreso",
"Password" : "Pasvorto",
"Unable to change your password" : "Ne eblis ŝanĝi vian pasvorton",
"Current password" : "Nuna pasvorto",
"New password" : "Nova pasvorto",
"Change password" : "Ŝanĝi la pasvorton",
- "Email" : "Retpoŝto",
- "Your email address" : "Via retpoŝta adreso",
- "Profile picture" : "Profila bildo",
- "Upload new" : "Alŝuti novan",
- "Select new from Files" : "Elekti novan el dosieroj",
- "Remove image" : "Forigi bildon",
- "Cancel" : "Nuligi",
- "Choose as profile image" : "Elekti kiel profilan bildon",
"Language" : "Lingvo",
"Help translate" : "Helpu traduki",
+ "Get the apps to sync your files" : "Ekhavu la aplikaĵojn por sinkronigi viajn dosierojn",
"Username" : "Uzantonomo",
"Create" : "Krei",
"Add Group" : "Aldoni grupon",
diff --git a/settings/l10n/eo.json b/settings/l10n/eo.json
index 791dca9b499..b30702d617e 100644
--- a/settings/l10n/eo.json
+++ b/settings/l10n/eo.json
@@ -4,11 +4,9 @@
"Cron" : "Cron",
"Log" : "Protokolo",
"Updates" : "Ĝisdatigoj",
- "Authentication error" : "Aŭtentiga eraro",
- "Your full name has been changed." : "Via plena nomo ŝanĝitas.",
- "Unable to change full name" : "Ne eblis ŝanĝi la plenan nomon",
"Language changed" : "La lingvo estas ŝanĝita",
"Invalid request" : "Nevalida peto",
+ "Authentication error" : "Aŭtentiga eraro",
"Admins can't remove themself from the admin group" : "Administrantoj ne povas forigi sin mem el la administra grupo.",
"Unable to add user to group %s" : "Ne eblis aldoni la uzanton al la grupo %s",
"Unable to remove user from group %s" : "Ne eblis forigi la uzantan el la grupo %s",
@@ -19,6 +17,8 @@
"Saved" : "Konservita",
"Email sent" : "La retpoŝtaĵo sendiĝis",
"Email saved" : "La retpoŝtadreso konserviĝis",
+ "Your full name has been changed." : "Via plena nomo ŝanĝitas.",
+ "Unable to change full name" : "Ne eblis ŝanĝi la plenan nomon",
"Sending..." : "Sendante...",
"All" : "Ĉio",
"Please wait...." : "Bonvolu atendi...",
@@ -32,13 +32,13 @@
"Uninstalling ...." : "Malinstalante...",
"Error while uninstalling app" : "Eraris malinstalo de aplikaĵo",
"Uninstall" : "Malinstali",
+ "Delete" : "Forigi",
"Select a profile picture" : "Elekti profilan bildon",
"Very weak password" : "Tre malforta pasvorto",
"Weak password" : "Malforta pasvorto",
"So-so password" : "Mezaĉa pasvorto",
"Good password" : "Bona pasvorto",
"Strong password" : "Forta pasvorto",
- "Delete" : "Forigi",
"Groups" : "Grupoj",
"deleted {groupName}" : "{groupName} foriĝis",
"undo" : "malfari",
@@ -49,7 +49,6 @@
"Error creating user" : "Eraris kreo de uzanto",
"A valid password must be provided" : "Valida pasvorto devas proviziĝi",
"__language_name__" : "Esperanto",
- "SSL root certificates" : "Radikaj SSL-atestoj",
"Everything (fatal issues, errors, warnings, info, debug)" : "Ĉio (fatalaĵoj, eraroj, avertoj, informoj, sencimigaj mesaĝoj)",
"Info, warnings, errors and fatal issues" : "Informoj, avertoj, eraroj kaj fatalaĵoj",
"Warnings, errors and fatal issues" : "Avertoj, eraroj kaj fatalaĵoj",
@@ -77,32 +76,27 @@
"SMTP Username" : "SMTP-uzantonomo",
"SMTP Password" : "SMTP-pasvorto",
"Send email" : "Sendi retpoŝton",
- "Log level" : "Registronivelo",
"More" : "Pli",
"Less" : "Malpli",
"Version" : "Eldono",
- "by" : "de",
"Documentation:" : "Dokumentaro:",
"Enable only for specific groups" : "Kapabligi nur por specifajn grupojn",
"Uninstall App" : "Malinstali aplikaĵon",
"Forum" : "Forumo",
- "Get the apps to sync your files" : "Ekhavu la aplikaĵojn por sinkronigi viajn dosierojn",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Vi uzas <strong>%s</strong> el la disponeblaj <strong>%s</strong>",
+ "Profile picture" : "Profila bildo",
+ "Upload new" : "Alŝuti novan",
+ "Remove image" : "Forigi bildon",
+ "Cancel" : "Nuligi",
+ "Email" : "Retpoŝto",
+ "Your email address" : "Via retpoŝta adreso",
"Password" : "Pasvorto",
"Unable to change your password" : "Ne eblis ŝanĝi vian pasvorton",
"Current password" : "Nuna pasvorto",
"New password" : "Nova pasvorto",
"Change password" : "Ŝanĝi la pasvorton",
- "Email" : "Retpoŝto",
- "Your email address" : "Via retpoŝta adreso",
- "Profile picture" : "Profila bildo",
- "Upload new" : "Alŝuti novan",
- "Select new from Files" : "Elekti novan el dosieroj",
- "Remove image" : "Forigi bildon",
- "Cancel" : "Nuligi",
- "Choose as profile image" : "Elekti kiel profilan bildon",
"Language" : "Lingvo",
"Help translate" : "Helpu traduki",
+ "Get the apps to sync your files" : "Ekhavu la aplikaĵojn por sinkronigi viajn dosierojn",
"Username" : "Uzantonomo",
"Create" : "Krei",
"Add Group" : "Aldoni grupon",
diff --git a/settings/l10n/es.js b/settings/l10n/es.js
index 9a45c5b7457..b97a7b12793 100644
--- a/settings/l10n/es.js
+++ b/settings/l10n/es.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Registro",
"Tips & tricks" : "Sugerencias y trucos",
"Updates" : "Actualizaciones",
- "Authentication error" : "Error de autenticación",
- "Your full name has been changed." : "Se ha cambiado su nombre completo.",
- "Unable to change full name" : "No se puede cambiar el nombre completo",
"Couldn't remove app." : "No se pudo eliminar la aplicación.",
"Language changed" : "Idioma cambiado",
"Invalid request" : "Petición no válida",
+ "Authentication error" : "Error de autenticación",
"Admins can't remove themself from the admin group" : "Los administradores no se pueden eliminar a ellos mismos del grupo de administrador",
"Unable to add user to group %s" : "No se pudo añadir el usuario al grupo %s",
"Unable to remove user from group %s" : "No se pudo eliminar al usuario del grupo %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Usuario no válido",
"Unable to change mail address" : "No se pudo cambiar la dirección de correo electrónico",
"Email saved" : "Correo electrónico guardado",
+ "Your full name has been changed." : "Se ha cambiado su nombre completo.",
+ "Unable to change full name" : "No se puede cambiar el nombre completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "¿Está seguro de querer agregar \"{domain}\" como un dominio de confianza?",
"Add trusted domain" : "Agregar dominio de confianza",
"Migration in progress. Please wait until the migration is finished" : "Migración en curso. Por favor, espere hasta que la migración esté finalizada.",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "La aplicación ha sido activada pero necesita ser actualizada. Seras redirigido a la pagina de actualizariones en 5 segundos.",
"App update" : "Actualización de aplicación",
"No apps found for \"{query}\"" : "No se han encontrado aplicaciones para \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ha ocurrido un error. Por favor, cargue un certificado PEM codificado en ASCII.",
+ "Valid until {date}" : "Válido hasta {date}",
+ "Delete" : "Eliminar",
"An error occurred: {message}" : "Ocurrió un error: {message}",
"Select a profile picture" : "Seleccionar una imagen de perfil",
"Very weak password" : "Contraseña muy débil",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Contraseña pasable",
"Good password" : "Contraseña buena",
"Strong password" : "Contraseña muy buena",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ha ocurrido un error. Por favor, cargue un certificado PEM codificado en ASCII.",
- "Valid until {date}" : "Válido hasta {date}",
- "Delete" : "Eliminar",
"Groups" : "Grupos",
"Unable to delete {objName}" : "No es posible eliminar {objName}",
"Error creating group" : "Error al crear un grupo",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Se debe proporcionar una contraseña válida",
"A valid email must be provided" : "Se debe brindar una dirección de correo electrónico válida ",
"__language_name__" : "Castellano",
- "Sync clients" : "Sincronizar clientes",
"Personal info" : "Información personal",
- "SSL root certificates" : "Certificados raíz SSL",
+ "Sync clients" : "Sincronizar clientes",
"Everything (fatal issues, errors, warnings, info, debug)" : "Todo (Información, Avisos, Errores, debug y problemas fatales)",
"Info, warnings, errors and fatal issues" : "Información, Avisos, Errores y problemas fatales",
"Warnings, errors and fatal issues" : "Advertencias, errores y problemas fatales",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Es muy recomendable instalar los paquetes necesarios para poder soportar una de las siguientes configuraciones regionales: %s. ",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Si su instalación no está ubicada en la raíz del dominio y usa el cron del sistema, puede haber problemas al generarse los URL. Para evitarlos, configure la opción \"overwrite.cli.url\" en su archivo config.php para que use la ruta de la raíz del sitio web de su instalación (sugerencia: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "No fue posible ejecutar cronjob vía CLI. Han aparecido los siguientes errores técnicos:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "El fichero de bloqueo de transaciones esta usando la base de datos como mecanismo de bloqueo, para mejorar el rendimiento es recomendable usar cacheo de memoria para los bloqueos. Visita la <a target=\"_blank\" href=\"%s\">documentación ↗</a> para mas información.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Por favor revise las <a target=\"_blank\" href=\"%s\">guías de instalación ↗</a>, y compruebe los errores o avisos en el <a ref=\"#log-section\">registro</a>.",
"All checks passed." : "Ha pasado todos los controles",
"Open documentation" : "Documentación abierta",
@@ -162,7 +160,10 @@ OC.L10N.register(
"Use system's cron service to call the cron.php file every 15 minutes." : "Usar el servicio cron del sistema para llamar al archivo cron.php cada 15 minutos.",
"Enable server-side encryption" : "Habilitar cifrado en el servidor",
"Please read carefully before activating server-side encryption: " : "Por favor lea cuidadosamente antes de activar el cifrado del lado del servidor.",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "Una vez que el cifrado está habilitado, todos los archivos subidos al servidor desde ese punto en adelante se cifrarán en reposo en el servidor. Sólo será posible desactivar el cifrado en una fecha posterior si el módulo de cifrado activado soporta esa función, y todas las condiciones previas (por ejemplo, el establecimiento de una clave de recuperación) se cumplan.",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "El cifrado en sí solo no garantiza la seguridad del sistema. Por favor, consulte la documentación de ownCloud para obtener más información acerca de cómo funciona la aplicación de cifrado, y los casos de uso compatibles.",
"Be aware that encryption always increases the file size." : "Tenga presente que la encripción siempre incrementa el tamaño del archivo.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "Es siempre bueno crear copias de seguridad de sus datos, en el caso del cifrado, asegúrese de tener una copia de seguridad de las claves de cifrado junto con sus datos.",
"This is the final warning: Do you really want to enable encryption?" : "Esta es la advertencia final. ¿Realmente quiere activar el cifrado?",
"Enable encryption" : "Habilitar cifrado",
"No encryption module loaded, please enable an encryption module in the app menu." : "No se ha cargado el modulo de cifrado. Por favor habilite un modulo de cifrado en el menú de aplicaciones.",
@@ -185,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Almacenar credenciales",
"Test email settings" : "Probar configuración de correo electrónico",
"Send email" : "Enviar mensaje",
- "Log level" : "Nivel de registro",
"Download logfile" : "Descargar archivo de registro",
"More" : "Más",
"Less" : "Menos",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "El archivo de registro es mayor de 100 MB. Descargarlo puede tardar.",
+ "What to log" : "Que registrar",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Se utiliza SQLite como base de datos. Para instalaciones mas grandes se recomiende cambiar a otro sistema de base de datos. ",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "El uso de SQLite está desaconsejado especialmente cuando se usa el cliente de escritorio para sincronizar los ficheros.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Para migrar a otra base de datos use la herramienta de línea de comandos: 'occ db:convert-type', o consulte la <a target=\"_blank\" href=\"%s\">documentación ↗</a>.",
@@ -203,17 +204,23 @@ OC.L10N.register(
"Developer documentation" : "Documentación de desarrollador",
"Experimental applications ahead" : "Aplicaciones experimentales más adelante",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Las aplicaciones experimentales no están verificadas por problemas de seguridad, recientes o conocidas por ser inestables y/o bajo un fuerte desarrollo. Instalándolas pueden causar pérdida de datos o violación de seguridades.",
- "by" : "por",
- "licensed" : "licenciado",
"Documentation:" : "Documentación:",
"User documentation" : "Documentación de usuario",
"Admin documentation" : "Documentación de administrador",
"Show description …" : "Mostrar descripción…",
"Hide description …" : "Ocultar descripción…",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Esta aplicación no tiene ninguna versión mínima de ownCloud asignada. Este será un error en ownCloud 11 y posteriores.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Esta aplicación no tiene ninguna versión máxima de ownCloud asignada. Este será un error en ownCloud 11 y posteriores.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Esta aplicación no puede instalarse porque las siguientes dependencias no están cumplimentadas:",
"Enable only for specific groups" : "Activar solamente para grupos específicos",
"Uninstall App" : "Desinstalar aplicación",
"Enable experimental apps" : "Habilitar aplicaciones experimentales",
+ "SSL Root Certificates" : "Raíz de certificados SSL ",
+ "Common Name" : "Nombre común",
+ "Valid until" : "Válido hasta",
+ "Issued By" : "Emitido por",
+ "Valid until %s" : "Válido hasta %s",
+ "Import root certificate" : "Importar certificado raíz",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "¿Qué tal?,<br><br>este mensaje es para hacerle saber que ahora tiene una %s cuenta.<br><br>Su nombre de usuario: %s<br>Acceda en: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "¡Saludos!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hola, ¿qué tal?,\n\nEste mensaje es para hacerle saber que ahora tiene una cuenta %s.\n\nSu nombre de usuario: %s\nAcceda en: %s\n\n",
@@ -222,40 +229,35 @@ OC.L10N.register(
"Forum" : "Foro",
"Issue tracker" : "Seguidor de problemas:",
"Commercial support" : "Soporte Comercial",
- "Get the apps to sync your files" : "Obtener las aplicaciones para sincronizar sus archivos",
- "Desktop client" : "Cliente de escritorio",
- "Android app" : "Aplicación de Android",
- "iOS app" : "La aplicación de iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si quiere colaborar con el proyecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">participe en el desarrollo</a>\n\t\to\n\t\t¡<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">difúndalo</a>!",
- "Show First Run Wizard again" : "Mostrar nuevamente el Asistente de ejecución inicial",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ha usado <strong>%s</strong> de los <strong>%s</strong> disponibles",
- "Password" : "Contraseña",
- "Unable to change your password" : "No se ha podido cambiar su contraseña",
- "Current password" : "Contraseña actual",
- "New password" : "Nueva contraseña",
- "Change password" : "Cambiar contraseña",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Estas usando <strong>%s</strong> de <strong>%s</strong> ",
+ "Profile picture" : "Foto de perfil",
+ "Upload new" : "Subir otra",
+ "Select from Files" : "Seleccionar desde Archivos",
+ "Remove image" : "Borrar imagen",
+ "png or jpg, max. 20 MB" : "png o jpg, max. 20 MB",
+ "Picture provided by original account" : "Imagen provista por cuenta original",
+ "Cancel" : "Cancelar",
+ "Choose as profile picture" : "Seleccionar como imagen de perfil",
"Full name" : "Nombre completo",
"No display name set" : "No se ha establecido ningún nombre para mostrar",
"Email" : "Correo electrónico",
"Your email address" : "Su dirección de correo",
- "Fill in an email address to enable password recovery and receive notifications" : "Introducir una dirección de correo electrónico para activar la recuperación de contraseñas y recibir notificaciones",
+ "For password recovery and notifications" : "Para la recuperación de contraseña y notificaciones",
"No email address set" : "Ninguna dirección de correo establecida",
"You are member of the following groups:" : "Es miembro de los siguientes grupos:",
- "Profile picture" : "Foto de perfil",
- "Upload new" : "Subir otra",
- "Select new from Files" : "Seleccionar otra desde Archivos",
- "Remove image" : "Borrar imagen",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Sea en png o jpg. Preferiblemente que su forma sea cuadrada, pero tendrá la posibilidad de recortarlo. El archivo no puede exceder los 20 MB.",
- "Your avatar is provided by your original account." : "Su avatar es proporcionado por su cuenta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Seleccionar como imagen de perfil",
+ "Password" : "Contraseña",
+ "Unable to change your password" : "No se ha podido cambiar su contraseña",
+ "Current password" : "Contraseña actual",
+ "New password" : "Nueva contraseña",
+ "Change password" : "Cambiar contraseña",
"Language" : "Idioma",
"Help translate" : "Ayúdanos a traducir",
- "Common Name" : "Nombre común",
- "Valid until" : "Válido hasta",
- "Issued By" : "Emitido por",
- "Valid until %s" : "Válido hasta %s",
- "Import root certificate" : "Importar certificado raíz",
+ "Get the apps to sync your files" : "Obtener las aplicaciones para sincronizar sus archivos",
+ "Desktop client" : "Cliente de escritorio",
+ "Android app" : "Aplicación de Android",
+ "iOS app" : "La aplicación de iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si quiere colaborar con el proyecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">participe en el desarrollo</a>\n\t\to\n\t\t¡<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">difúndalo</a>!",
+ "Show First Run Wizard again" : "Mostrar nuevamente el Asistente de ejecución inicial",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desarrollado por la {communityopen}comunidad Owncloud{linkclose}, el {githubopen}código fuente{linkclose} está licenciado bajo {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostrar la ubicación del almacenamiento",
"Show last log in" : "Mostrar el último inicio de sesión",
diff --git a/settings/l10n/es.json b/settings/l10n/es.json
index 383f6cb6f8c..8ae28f02635 100644
--- a/settings/l10n/es.json
+++ b/settings/l10n/es.json
@@ -10,12 +10,10 @@
"Log" : "Registro",
"Tips & tricks" : "Sugerencias y trucos",
"Updates" : "Actualizaciones",
- "Authentication error" : "Error de autenticación",
- "Your full name has been changed." : "Se ha cambiado su nombre completo.",
- "Unable to change full name" : "No se puede cambiar el nombre completo",
"Couldn't remove app." : "No se pudo eliminar la aplicación.",
"Language changed" : "Idioma cambiado",
"Invalid request" : "Petición no válida",
+ "Authentication error" : "Error de autenticación",
"Admins can't remove themself from the admin group" : "Los administradores no se pueden eliminar a ellos mismos del grupo de administrador",
"Unable to add user to group %s" : "No se pudo añadir el usuario al grupo %s",
"Unable to remove user from group %s" : "No se pudo eliminar al usuario del grupo %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Usuario no válido",
"Unable to change mail address" : "No se pudo cambiar la dirección de correo electrónico",
"Email saved" : "Correo electrónico guardado",
+ "Your full name has been changed." : "Se ha cambiado su nombre completo.",
+ "Unable to change full name" : "No se puede cambiar el nombre completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "¿Está seguro de querer agregar \"{domain}\" como un dominio de confianza?",
"Add trusted domain" : "Agregar dominio de confianza",
"Migration in progress. Please wait until the migration is finished" : "Migración en curso. Por favor, espere hasta que la migración esté finalizada.",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "La aplicación ha sido activada pero necesita ser actualizada. Seras redirigido a la pagina de actualizariones en 5 segundos.",
"App update" : "Actualización de aplicación",
"No apps found for \"{query}\"" : "No se han encontrado aplicaciones para \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ha ocurrido un error. Por favor, cargue un certificado PEM codificado en ASCII.",
+ "Valid until {date}" : "Válido hasta {date}",
+ "Delete" : "Eliminar",
"An error occurred: {message}" : "Ocurrió un error: {message}",
"Select a profile picture" : "Seleccionar una imagen de perfil",
"Very weak password" : "Contraseña muy débil",
@@ -86,9 +89,6 @@
"So-so password" : "Contraseña pasable",
"Good password" : "Contraseña buena",
"Strong password" : "Contraseña muy buena",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ha ocurrido un error. Por favor, cargue un certificado PEM codificado en ASCII.",
- "Valid until {date}" : "Válido hasta {date}",
- "Delete" : "Eliminar",
"Groups" : "Grupos",
"Unable to delete {objName}" : "No es posible eliminar {objName}",
"Error creating group" : "Error al crear un grupo",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Se debe proporcionar una contraseña válida",
"A valid email must be provided" : "Se debe brindar una dirección de correo electrónico válida ",
"__language_name__" : "Castellano",
- "Sync clients" : "Sincronizar clientes",
"Personal info" : "Información personal",
- "SSL root certificates" : "Certificados raíz SSL",
+ "Sync clients" : "Sincronizar clientes",
"Everything (fatal issues, errors, warnings, info, debug)" : "Todo (Información, Avisos, Errores, debug y problemas fatales)",
"Info, warnings, errors and fatal issues" : "Información, Avisos, Errores y problemas fatales",
"Warnings, errors and fatal issues" : "Advertencias, errores y problemas fatales",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Es muy recomendable instalar los paquetes necesarios para poder soportar una de las siguientes configuraciones regionales: %s. ",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Si su instalación no está ubicada en la raíz del dominio y usa el cron del sistema, puede haber problemas al generarse los URL. Para evitarlos, configure la opción \"overwrite.cli.url\" en su archivo config.php para que use la ruta de la raíz del sitio web de su instalación (sugerencia: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "No fue posible ejecutar cronjob vía CLI. Han aparecido los siguientes errores técnicos:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "El fichero de bloqueo de transaciones esta usando la base de datos como mecanismo de bloqueo, para mejorar el rendimiento es recomendable usar cacheo de memoria para los bloqueos. Visita la <a target=\"_blank\" href=\"%s\">documentación ↗</a> para mas información.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Por favor revise las <a target=\"_blank\" href=\"%s\">guías de instalación ↗</a>, y compruebe los errores o avisos en el <a ref=\"#log-section\">registro</a>.",
"All checks passed." : "Ha pasado todos los controles",
"Open documentation" : "Documentación abierta",
@@ -160,7 +158,10 @@
"Use system's cron service to call the cron.php file every 15 minutes." : "Usar el servicio cron del sistema para llamar al archivo cron.php cada 15 minutos.",
"Enable server-side encryption" : "Habilitar cifrado en el servidor",
"Please read carefully before activating server-side encryption: " : "Por favor lea cuidadosamente antes de activar el cifrado del lado del servidor.",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "Una vez que el cifrado está habilitado, todos los archivos subidos al servidor desde ese punto en adelante se cifrarán en reposo en el servidor. Sólo será posible desactivar el cifrado en una fecha posterior si el módulo de cifrado activado soporta esa función, y todas las condiciones previas (por ejemplo, el establecimiento de una clave de recuperación) se cumplan.",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "El cifrado en sí solo no garantiza la seguridad del sistema. Por favor, consulte la documentación de ownCloud para obtener más información acerca de cómo funciona la aplicación de cifrado, y los casos de uso compatibles.",
"Be aware that encryption always increases the file size." : "Tenga presente que la encripción siempre incrementa el tamaño del archivo.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "Es siempre bueno crear copias de seguridad de sus datos, en el caso del cifrado, asegúrese de tener una copia de seguridad de las claves de cifrado junto con sus datos.",
"This is the final warning: Do you really want to enable encryption?" : "Esta es la advertencia final. ¿Realmente quiere activar el cifrado?",
"Enable encryption" : "Habilitar cifrado",
"No encryption module loaded, please enable an encryption module in the app menu." : "No se ha cargado el modulo de cifrado. Por favor habilite un modulo de cifrado en el menú de aplicaciones.",
@@ -183,11 +184,11 @@
"Store credentials" : "Almacenar credenciales",
"Test email settings" : "Probar configuración de correo electrónico",
"Send email" : "Enviar mensaje",
- "Log level" : "Nivel de registro",
"Download logfile" : "Descargar archivo de registro",
"More" : "Más",
"Less" : "Menos",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "El archivo de registro es mayor de 100 MB. Descargarlo puede tardar.",
+ "What to log" : "Que registrar",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Se utiliza SQLite como base de datos. Para instalaciones mas grandes se recomiende cambiar a otro sistema de base de datos. ",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "El uso de SQLite está desaconsejado especialmente cuando se usa el cliente de escritorio para sincronizar los ficheros.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Para migrar a otra base de datos use la herramienta de línea de comandos: 'occ db:convert-type', o consulte la <a target=\"_blank\" href=\"%s\">documentación ↗</a>.",
@@ -201,17 +202,23 @@
"Developer documentation" : "Documentación de desarrollador",
"Experimental applications ahead" : "Aplicaciones experimentales más adelante",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Las aplicaciones experimentales no están verificadas por problemas de seguridad, recientes o conocidas por ser inestables y/o bajo un fuerte desarrollo. Instalándolas pueden causar pérdida de datos o violación de seguridades.",
- "by" : "por",
- "licensed" : "licenciado",
"Documentation:" : "Documentación:",
"User documentation" : "Documentación de usuario",
"Admin documentation" : "Documentación de administrador",
"Show description …" : "Mostrar descripción…",
"Hide description …" : "Ocultar descripción…",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Esta aplicación no tiene ninguna versión mínima de ownCloud asignada. Este será un error en ownCloud 11 y posteriores.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Esta aplicación no tiene ninguna versión máxima de ownCloud asignada. Este será un error en ownCloud 11 y posteriores.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Esta aplicación no puede instalarse porque las siguientes dependencias no están cumplimentadas:",
"Enable only for specific groups" : "Activar solamente para grupos específicos",
"Uninstall App" : "Desinstalar aplicación",
"Enable experimental apps" : "Habilitar aplicaciones experimentales",
+ "SSL Root Certificates" : "Raíz de certificados SSL ",
+ "Common Name" : "Nombre común",
+ "Valid until" : "Válido hasta",
+ "Issued By" : "Emitido por",
+ "Valid until %s" : "Válido hasta %s",
+ "Import root certificate" : "Importar certificado raíz",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "¿Qué tal?,<br><br>este mensaje es para hacerle saber que ahora tiene una %s cuenta.<br><br>Su nombre de usuario: %s<br>Acceda en: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "¡Saludos!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hola, ¿qué tal?,\n\nEste mensaje es para hacerle saber que ahora tiene una cuenta %s.\n\nSu nombre de usuario: %s\nAcceda en: %s\n\n",
@@ -220,40 +227,35 @@
"Forum" : "Foro",
"Issue tracker" : "Seguidor de problemas:",
"Commercial support" : "Soporte Comercial",
- "Get the apps to sync your files" : "Obtener las aplicaciones para sincronizar sus archivos",
- "Desktop client" : "Cliente de escritorio",
- "Android app" : "Aplicación de Android",
- "iOS app" : "La aplicación de iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si quiere colaborar con el proyecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">participe en el desarrollo</a>\n\t\to\n\t\t¡<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">difúndalo</a>!",
- "Show First Run Wizard again" : "Mostrar nuevamente el Asistente de ejecución inicial",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ha usado <strong>%s</strong> de los <strong>%s</strong> disponibles",
- "Password" : "Contraseña",
- "Unable to change your password" : "No se ha podido cambiar su contraseña",
- "Current password" : "Contraseña actual",
- "New password" : "Nueva contraseña",
- "Change password" : "Cambiar contraseña",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Estas usando <strong>%s</strong> de <strong>%s</strong> ",
+ "Profile picture" : "Foto de perfil",
+ "Upload new" : "Subir otra",
+ "Select from Files" : "Seleccionar desde Archivos",
+ "Remove image" : "Borrar imagen",
+ "png or jpg, max. 20 MB" : "png o jpg, max. 20 MB",
+ "Picture provided by original account" : "Imagen provista por cuenta original",
+ "Cancel" : "Cancelar",
+ "Choose as profile picture" : "Seleccionar como imagen de perfil",
"Full name" : "Nombre completo",
"No display name set" : "No se ha establecido ningún nombre para mostrar",
"Email" : "Correo electrónico",
"Your email address" : "Su dirección de correo",
- "Fill in an email address to enable password recovery and receive notifications" : "Introducir una dirección de correo electrónico para activar la recuperación de contraseñas y recibir notificaciones",
+ "For password recovery and notifications" : "Para la recuperación de contraseña y notificaciones",
"No email address set" : "Ninguna dirección de correo establecida",
"You are member of the following groups:" : "Es miembro de los siguientes grupos:",
- "Profile picture" : "Foto de perfil",
- "Upload new" : "Subir otra",
- "Select new from Files" : "Seleccionar otra desde Archivos",
- "Remove image" : "Borrar imagen",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Sea en png o jpg. Preferiblemente que su forma sea cuadrada, pero tendrá la posibilidad de recortarlo. El archivo no puede exceder los 20 MB.",
- "Your avatar is provided by your original account." : "Su avatar es proporcionado por su cuenta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Seleccionar como imagen de perfil",
+ "Password" : "Contraseña",
+ "Unable to change your password" : "No se ha podido cambiar su contraseña",
+ "Current password" : "Contraseña actual",
+ "New password" : "Nueva contraseña",
+ "Change password" : "Cambiar contraseña",
"Language" : "Idioma",
"Help translate" : "Ayúdanos a traducir",
- "Common Name" : "Nombre común",
- "Valid until" : "Válido hasta",
- "Issued By" : "Emitido por",
- "Valid until %s" : "Válido hasta %s",
- "Import root certificate" : "Importar certificado raíz",
+ "Get the apps to sync your files" : "Obtener las aplicaciones para sincronizar sus archivos",
+ "Desktop client" : "Cliente de escritorio",
+ "Android app" : "Aplicación de Android",
+ "iOS app" : "La aplicación de iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si quiere colaborar con el proyecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">participe en el desarrollo</a>\n\t\to\n\t\t¡<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">difúndalo</a>!",
+ "Show First Run Wizard again" : "Mostrar nuevamente el Asistente de ejecución inicial",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desarrollado por la {communityopen}comunidad Owncloud{linkclose}, el {githubopen}código fuente{linkclose} está licenciado bajo {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostrar la ubicación del almacenamiento",
"Show last log in" : "Mostrar el último inicio de sesión",
diff --git a/settings/l10n/es_AR.js b/settings/l10n/es_AR.js
index 122422aac97..3082a4be4d2 100644
--- a/settings/l10n/es_AR.js
+++ b/settings/l10n/es_AR.js
@@ -1,16 +1,15 @@
OC.L10N.register(
"settings",
{
+ "APCu" : "APCu",
"Sharing" : "Compartiendo",
"External Storage" : "Almacenamiento externo",
"Cron" : "Cron",
"Log" : "Log",
"Updates" : "Actualizaciones",
- "Authentication error" : "Error al autenticar",
- "Your full name has been changed." : "Su nombre completo ha sido cambiado.",
- "Unable to change full name" : "Imposible cambiar el nombre completo",
"Language changed" : "Idioma cambiado",
"Invalid request" : "Pedido inválido",
+ "Authentication error" : "Error al autenticar",
"Admins can't remove themself from the admin group" : "Los administradores no se pueden quitar a si mismos del grupo administrador. ",
"Unable to add user to group %s" : "No fue posible agregar el usuario al grupo %s",
"Unable to remove user from group %s" : "No es posible borrar al usuario del grupo %s",
@@ -26,6 +25,8 @@ OC.L10N.register(
"Email sent" : "e-mail mandado",
"You need to set your user email before being able to send test emails." : "Necesita especificar el usuario de correo electrónico antes de poder enviar correos electrónicos de prueba.",
"Email saved" : "e-mail guardado",
+ "Your full name has been changed." : "Su nombre completo ha sido cambiado.",
+ "Unable to change full name" : "Imposible cambiar el nombre completo",
"Sending..." : "Enviando...",
"All" : "Todos",
"Please wait...." : "Por favor, esperá....",
@@ -36,13 +37,13 @@ OC.L10N.register(
"Updating...." : "Actualizando....",
"Error while updating app" : "Error al actualizar App",
"Updated" : "Actualizado",
+ "Delete" : "Borrar",
"Select a profile picture" : "Seleccionar una imágen de perfil",
"Very weak password" : "Contraseña muy débil.",
"Weak password" : "Contraseña débil.",
"So-so password" : "Contraseña de nivel medio. ",
"Good password" : "Buena contraseña. ",
"Strong password" : "Contraseña fuerte.",
- "Delete" : "Borrar",
"Groups" : "Grupos",
"undo" : "deshacer",
"never" : "nunca",
@@ -51,7 +52,6 @@ OC.L10N.register(
"Error creating user" : "Error creando usuario",
"A valid password must be provided" : "Debe ingresar una contraseña válida",
"__language_name__" : "Castellano (Argentina)",
- "SSL root certificates" : "certificados SSL raíz",
"Everything (fatal issues, errors, warnings, info, debug)" : "Todo (notificaciones fatales, errores, advertencias, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, advertencias, errores y notificaciones fatales",
"Warnings, errors and fatal issues" : "Advertencias, errores y notificaciones fatales",
@@ -85,37 +85,30 @@ OC.L10N.register(
"SMTP Password" : "Contraseña SMTP",
"Test email settings" : "Configuracion de correo de prueba.",
"Send email" : "Enviar correo",
- "Log level" : "Nivel de Log",
"More" : "Más",
"Less" : "Menos",
"Version" : "Versión",
- "by" : "por",
"Documentation:" : "Documentación:",
"Cheers!" : "¡Saludos!",
"Forum" : "Foro",
- "Get the apps to sync your files" : "Obtené Apps para sincronizar tus archivos",
- "Desktop client" : "Cliente de escritorio",
- "Android app" : "App para Android",
- "iOS app" : "App para iOS",
- "Show First Run Wizard again" : "Mostrar de nuevo el asistente de primera ejecución",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Usás <strong>%s</strong> de los <strong>%s</strong> disponibles",
+ "Profile picture" : "Imágen de perfil",
+ "Upload new" : "Subir nuevo",
+ "Remove image" : "Remover imagen",
+ "Cancel" : "Cancelar",
+ "Email" : "e-mail",
+ "Your email address" : "Tu dirección de e-mail",
"Password" : "Contraseña",
"Unable to change your password" : "No fue posible cambiar tu contraseña",
"Current password" : "Contraseña actual",
"New password" : "Nueva contraseña:",
"Change password" : "Cambiar contraseña",
- "Email" : "e-mail",
- "Your email address" : "Tu dirección de e-mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Rellene una direccion de correo para habilitar la recuperacion de contraseña y recibir notificaciones. ",
- "Profile picture" : "Imágen de perfil",
- "Upload new" : "Subir nuevo",
- "Select new from Files" : "Seleccionar nuevo desde archivos",
- "Remove image" : "Remover imagen",
- "Your avatar is provided by your original account." : "Su avatar es proveído por su cuenta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Elegir como imagen de perfil",
"Language" : "Idioma",
"Help translate" : "Ayudanos a traducir",
+ "Get the apps to sync your files" : "Obtené Apps para sincronizar tus archivos",
+ "Desktop client" : "Cliente de escritorio",
+ "Android app" : "App para Android",
+ "iOS app" : "App para iOS",
+ "Show First Run Wizard again" : "Mostrar de nuevo el asistente de primera ejecución",
"Username" : "Nombre de usuario",
"Create" : "Crear",
"Admin Recovery Password" : "Recuperación de contraseña de administrador",
diff --git a/settings/l10n/es_AR.json b/settings/l10n/es_AR.json
index 72e593031b8..5dc457dd30b 100644
--- a/settings/l10n/es_AR.json
+++ b/settings/l10n/es_AR.json
@@ -1,14 +1,13 @@
{ "translations": {
+ "APCu" : "APCu",
"Sharing" : "Compartiendo",
"External Storage" : "Almacenamiento externo",
"Cron" : "Cron",
"Log" : "Log",
"Updates" : "Actualizaciones",
- "Authentication error" : "Error al autenticar",
- "Your full name has been changed." : "Su nombre completo ha sido cambiado.",
- "Unable to change full name" : "Imposible cambiar el nombre completo",
"Language changed" : "Idioma cambiado",
"Invalid request" : "Pedido inválido",
+ "Authentication error" : "Error al autenticar",
"Admins can't remove themself from the admin group" : "Los administradores no se pueden quitar a si mismos del grupo administrador. ",
"Unable to add user to group %s" : "No fue posible agregar el usuario al grupo %s",
"Unable to remove user from group %s" : "No es posible borrar al usuario del grupo %s",
@@ -24,6 +23,8 @@
"Email sent" : "e-mail mandado",
"You need to set your user email before being able to send test emails." : "Necesita especificar el usuario de correo electrónico antes de poder enviar correos electrónicos de prueba.",
"Email saved" : "e-mail guardado",
+ "Your full name has been changed." : "Su nombre completo ha sido cambiado.",
+ "Unable to change full name" : "Imposible cambiar el nombre completo",
"Sending..." : "Enviando...",
"All" : "Todos",
"Please wait...." : "Por favor, esperá....",
@@ -34,13 +35,13 @@
"Updating...." : "Actualizando....",
"Error while updating app" : "Error al actualizar App",
"Updated" : "Actualizado",
+ "Delete" : "Borrar",
"Select a profile picture" : "Seleccionar una imágen de perfil",
"Very weak password" : "Contraseña muy débil.",
"Weak password" : "Contraseña débil.",
"So-so password" : "Contraseña de nivel medio. ",
"Good password" : "Buena contraseña. ",
"Strong password" : "Contraseña fuerte.",
- "Delete" : "Borrar",
"Groups" : "Grupos",
"undo" : "deshacer",
"never" : "nunca",
@@ -49,7 +50,6 @@
"Error creating user" : "Error creando usuario",
"A valid password must be provided" : "Debe ingresar una contraseña válida",
"__language_name__" : "Castellano (Argentina)",
- "SSL root certificates" : "certificados SSL raíz",
"Everything (fatal issues, errors, warnings, info, debug)" : "Todo (notificaciones fatales, errores, advertencias, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, advertencias, errores y notificaciones fatales",
"Warnings, errors and fatal issues" : "Advertencias, errores y notificaciones fatales",
@@ -83,37 +83,30 @@
"SMTP Password" : "Contraseña SMTP",
"Test email settings" : "Configuracion de correo de prueba.",
"Send email" : "Enviar correo",
- "Log level" : "Nivel de Log",
"More" : "Más",
"Less" : "Menos",
"Version" : "Versión",
- "by" : "por",
"Documentation:" : "Documentación:",
"Cheers!" : "¡Saludos!",
"Forum" : "Foro",
- "Get the apps to sync your files" : "Obtené Apps para sincronizar tus archivos",
- "Desktop client" : "Cliente de escritorio",
- "Android app" : "App para Android",
- "iOS app" : "App para iOS",
- "Show First Run Wizard again" : "Mostrar de nuevo el asistente de primera ejecución",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Usás <strong>%s</strong> de los <strong>%s</strong> disponibles",
+ "Profile picture" : "Imágen de perfil",
+ "Upload new" : "Subir nuevo",
+ "Remove image" : "Remover imagen",
+ "Cancel" : "Cancelar",
+ "Email" : "e-mail",
+ "Your email address" : "Tu dirección de e-mail",
"Password" : "Contraseña",
"Unable to change your password" : "No fue posible cambiar tu contraseña",
"Current password" : "Contraseña actual",
"New password" : "Nueva contraseña:",
"Change password" : "Cambiar contraseña",
- "Email" : "e-mail",
- "Your email address" : "Tu dirección de e-mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Rellene una direccion de correo para habilitar la recuperacion de contraseña y recibir notificaciones. ",
- "Profile picture" : "Imágen de perfil",
- "Upload new" : "Subir nuevo",
- "Select new from Files" : "Seleccionar nuevo desde archivos",
- "Remove image" : "Remover imagen",
- "Your avatar is provided by your original account." : "Su avatar es proveído por su cuenta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Elegir como imagen de perfil",
"Language" : "Idioma",
"Help translate" : "Ayudanos a traducir",
+ "Get the apps to sync your files" : "Obtené Apps para sincronizar tus archivos",
+ "Desktop client" : "Cliente de escritorio",
+ "Android app" : "App para Android",
+ "iOS app" : "App para iOS",
+ "Show First Run Wizard again" : "Mostrar de nuevo el asistente de primera ejecución",
"Username" : "Nombre de usuario",
"Create" : "Crear",
"Admin Recovery Password" : "Recuperación de contraseña de administrador",
diff --git a/settings/l10n/es_CL.js b/settings/l10n/es_CL.js
index b51f930e83a..690d3e3dcd3 100644
--- a/settings/l10n/es_CL.js
+++ b/settings/l10n/es_CL.js
@@ -1,8 +1,8 @@
OC.L10N.register(
"settings",
{
- "Password" : "Clave",
"Cancel" : "Cancelar",
+ "Password" : "Clave",
"Username" : "Usuario"
},
"nplurals=2; plural=(n != 1);");
diff --git a/settings/l10n/es_CL.json b/settings/l10n/es_CL.json
index 981c7eeb897..79f9fcc3236 100644
--- a/settings/l10n/es_CL.json
+++ b/settings/l10n/es_CL.json
@@ -1,6 +1,6 @@
{ "translations": {
- "Password" : "Clave",
"Cancel" : "Cancelar",
+ "Password" : "Clave",
"Username" : "Usuario"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/settings/l10n/es_MX.js b/settings/l10n/es_MX.js
index 3111101135b..4ccbf7835e4 100644
--- a/settings/l10n/es_MX.js
+++ b/settings/l10n/es_MX.js
@@ -5,11 +5,9 @@ OC.L10N.register(
"External Storage" : "Almacenamiento externo",
"Cron" : "Cron",
"Log" : "Registro",
- "Authentication error" : "Error de autenticación",
- "Your full name has been changed." : "Se ha cambiado su nombre completo.",
- "Unable to change full name" : "No se puede cambiar el nombre completo",
"Language changed" : "Idioma cambiado",
"Invalid request" : "Petición no válida",
+ "Authentication error" : "Error de autenticación",
"Admins can't remove themself from the admin group" : "Los administradores no se pueden eliminar a ellos mismos del grupo de administrador",
"Unable to add user to group %s" : "No se pudo añadir el usuario al grupo %s",
"Unable to remove user from group %s" : "No se pudo eliminar al usuario del grupo %s",
@@ -23,6 +21,8 @@ OC.L10N.register(
"Saved" : "Guardado",
"Email sent" : "Correo electrónico enviado",
"Email saved" : "Correo electrónico guardado",
+ "Your full name has been changed." : "Se ha cambiado su nombre completo.",
+ "Unable to change full name" : "No se puede cambiar el nombre completo",
"All" : "Todos",
"Please wait...." : "Espere, por favor....",
"Error while disabling app" : "Error mientras se desactivaba la aplicación",
@@ -32,8 +32,8 @@ OC.L10N.register(
"Updating...." : "Actualizando....",
"Error while updating app" : "Error mientras se actualizaba la aplicación",
"Updated" : "Actualizado",
- "Select a profile picture" : "Seleccionar una imagen de perfil",
"Delete" : "Eliminar",
+ "Select a profile picture" : "Seleccionar una imagen de perfil",
"Groups" : "Grupos",
"undo" : "deshacer",
"never" : "nunca",
@@ -42,7 +42,6 @@ OC.L10N.register(
"Error creating user" : "Error al crear usuario",
"A valid password must be provided" : "Se debe proporcionar una contraseña válida",
"__language_name__" : "Español (México)",
- "SSL root certificates" : "Certificados raíz SSL",
"Everything (fatal issues, errors, warnings, info, debug)" : "Todo (Información, Avisos, Errores, debug y problemas fatales)",
"Info, warnings, errors and fatal issues" : "Información, Avisos, Errores y problemas fatales",
"Warnings, errors and fatal issues" : "Advertencias, errores y problemas fatales",
@@ -62,32 +61,26 @@ OC.L10N.register(
"Encryption" : "Cifrado",
"Server address" : "Dirección del servidor",
"Port" : "Puerto",
- "Log level" : "Nivel de registro",
"More" : "Más",
"Less" : "Menos",
"Version" : "Versión",
- "by" : "por",
"Cheers!" : "¡Saludos!",
"Forum" : "Foro",
- "Get the apps to sync your files" : "Obtener las aplicaciones para sincronizar sus archivos",
- "Show First Run Wizard again" : "Mostrar nuevamente el Asistente de ejecución inicial",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ha usado <strong>%s</strong> de los <strong>%s</strong> disponibles",
+ "Profile picture" : "Foto de perfil",
+ "Upload new" : "Subir otra",
+ "Remove image" : "Borrar imagen",
+ "Cancel" : "Cancelar",
+ "Email" : "Correo electrónico",
+ "Your email address" : "Su dirección de correo",
"Password" : "Contraseña",
"Unable to change your password" : "No se ha podido cambiar su contraseña",
"Current password" : "Contraseña actual",
"New password" : "Nueva contraseña",
"Change password" : "Cambiar contraseña",
- "Email" : "Correo electrónico",
- "Your email address" : "Su dirección de correo",
- "Profile picture" : "Foto de perfil",
- "Upload new" : "Subir otra",
- "Select new from Files" : "Seleccionar otra desde Archivos",
- "Remove image" : "Borrar imagen",
- "Your avatar is provided by your original account." : "Su avatar es proporcionado por su cuenta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Seleccionar como imagen de perfil",
"Language" : "Idioma",
"Help translate" : "Ayúdanos a traducir",
+ "Get the apps to sync your files" : "Obtener las aplicaciones para sincronizar sus archivos",
+ "Show First Run Wizard again" : "Mostrar nuevamente el Asistente de ejecución inicial",
"Username" : "Nombre de usuario",
"Create" : "Crear",
"Admin Recovery Password" : "Recuperación de la contraseña de administración",
diff --git a/settings/l10n/es_MX.json b/settings/l10n/es_MX.json
index d0cd473e262..a7cfd82cf6c 100644
--- a/settings/l10n/es_MX.json
+++ b/settings/l10n/es_MX.json
@@ -3,11 +3,9 @@
"External Storage" : "Almacenamiento externo",
"Cron" : "Cron",
"Log" : "Registro",
- "Authentication error" : "Error de autenticación",
- "Your full name has been changed." : "Se ha cambiado su nombre completo.",
- "Unable to change full name" : "No se puede cambiar el nombre completo",
"Language changed" : "Idioma cambiado",
"Invalid request" : "Petición no válida",
+ "Authentication error" : "Error de autenticación",
"Admins can't remove themself from the admin group" : "Los administradores no se pueden eliminar a ellos mismos del grupo de administrador",
"Unable to add user to group %s" : "No se pudo añadir el usuario al grupo %s",
"Unable to remove user from group %s" : "No se pudo eliminar al usuario del grupo %s",
@@ -21,6 +19,8 @@
"Saved" : "Guardado",
"Email sent" : "Correo electrónico enviado",
"Email saved" : "Correo electrónico guardado",
+ "Your full name has been changed." : "Se ha cambiado su nombre completo.",
+ "Unable to change full name" : "No se puede cambiar el nombre completo",
"All" : "Todos",
"Please wait...." : "Espere, por favor....",
"Error while disabling app" : "Error mientras se desactivaba la aplicación",
@@ -30,8 +30,8 @@
"Updating...." : "Actualizando....",
"Error while updating app" : "Error mientras se actualizaba la aplicación",
"Updated" : "Actualizado",
- "Select a profile picture" : "Seleccionar una imagen de perfil",
"Delete" : "Eliminar",
+ "Select a profile picture" : "Seleccionar una imagen de perfil",
"Groups" : "Grupos",
"undo" : "deshacer",
"never" : "nunca",
@@ -40,7 +40,6 @@
"Error creating user" : "Error al crear usuario",
"A valid password must be provided" : "Se debe proporcionar una contraseña válida",
"__language_name__" : "Español (México)",
- "SSL root certificates" : "Certificados raíz SSL",
"Everything (fatal issues, errors, warnings, info, debug)" : "Todo (Información, Avisos, Errores, debug y problemas fatales)",
"Info, warnings, errors and fatal issues" : "Información, Avisos, Errores y problemas fatales",
"Warnings, errors and fatal issues" : "Advertencias, errores y problemas fatales",
@@ -60,32 +59,26 @@
"Encryption" : "Cifrado",
"Server address" : "Dirección del servidor",
"Port" : "Puerto",
- "Log level" : "Nivel de registro",
"More" : "Más",
"Less" : "Menos",
"Version" : "Versión",
- "by" : "por",
"Cheers!" : "¡Saludos!",
"Forum" : "Foro",
- "Get the apps to sync your files" : "Obtener las aplicaciones para sincronizar sus archivos",
- "Show First Run Wizard again" : "Mostrar nuevamente el Asistente de ejecución inicial",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ha usado <strong>%s</strong> de los <strong>%s</strong> disponibles",
+ "Profile picture" : "Foto de perfil",
+ "Upload new" : "Subir otra",
+ "Remove image" : "Borrar imagen",
+ "Cancel" : "Cancelar",
+ "Email" : "Correo electrónico",
+ "Your email address" : "Su dirección de correo",
"Password" : "Contraseña",
"Unable to change your password" : "No se ha podido cambiar su contraseña",
"Current password" : "Contraseña actual",
"New password" : "Nueva contraseña",
"Change password" : "Cambiar contraseña",
- "Email" : "Correo electrónico",
- "Your email address" : "Su dirección de correo",
- "Profile picture" : "Foto de perfil",
- "Upload new" : "Subir otra",
- "Select new from Files" : "Seleccionar otra desde Archivos",
- "Remove image" : "Borrar imagen",
- "Your avatar is provided by your original account." : "Su avatar es proporcionado por su cuenta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Seleccionar como imagen de perfil",
"Language" : "Idioma",
"Help translate" : "Ayúdanos a traducir",
+ "Get the apps to sync your files" : "Obtener las aplicaciones para sincronizar sus archivos",
+ "Show First Run Wizard again" : "Mostrar nuevamente el Asistente de ejecución inicial",
"Username" : "Nombre de usuario",
"Create" : "Crear",
"Admin Recovery Password" : "Recuperación de la contraseña de administración",
diff --git a/settings/l10n/et_EE.js b/settings/l10n/et_EE.js
index 67cbca7f5a3..e3e3555503b 100644
--- a/settings/l10n/et_EE.js
+++ b/settings/l10n/et_EE.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Logi",
"Tips & tricks" : "Nõuanded ja trikid",
"Updates" : "Uuendused",
- "Authentication error" : "Autentimise viga",
- "Your full name has been changed." : "Sinu täispikk nimi on muudetud.",
- "Unable to change full name" : "Täispika nime muutmine ebaõnnestus",
"Couldn't remove app." : "Ei suutnud rakendit eemaldada.",
"Language changed" : "Keel on muudetud",
"Invalid request" : "Vigane päring",
+ "Authentication error" : "Autentimise viga",
"Admins can't remove themself from the admin group" : "Administraatorid ei saa ise end admin grupist eemaldada",
"Unable to add user to group %s" : "Kasutajat ei saa lisada gruppi %s",
"Unable to remove user from group %s" : "Kasutajat ei saa eemaldada grupist %s",
@@ -46,8 +44,11 @@ OC.L10N.register(
"Invalid user" : "Vigane kasutaja",
"Unable to change mail address" : "E-posti aadressi muutmine ebaõnnestus",
"Email saved" : "Kiri on salvestatud",
+ "Your full name has been changed." : "Sinu täispikk nimi on muudetud.",
+ "Unable to change full name" : "Täispika nime muutmine ebaõnnestus",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Oled sa kindel, et soovid lisada domeeni \"{domain}\" usaldusväärseks domeeniks?",
"Add trusted domain" : "Lis ausaldusväärne domeen",
+ "Migration in progress. Please wait until the migration is finished" : "Kolimine on käimas. Palun oota, kuni see on lõpetatud",
"Migration started …" : "Kolimist on alustatud ...",
"Sending..." : "Saadan...",
"Official" : "Ametlik",
@@ -67,14 +68,15 @@ OC.L10N.register(
"Uninstalling ...." : "Eemaldan...",
"Error while uninstalling app" : "Viga rakendi eemaldamisel",
"Uninstall" : "Eemalda",
+ "App update" : "Rakenduse uuendus",
+ "Valid until {date}" : "Kehtib kuni {date}",
+ "Delete" : "Kustuta",
"Select a profile picture" : "Vali profiili pilt",
"Very weak password" : "Väga nõrk parool",
"Weak password" : "Nõrk parool",
"So-so password" : "Enam-vähem sobiv parool",
"Good password" : "Hea parool",
"Strong password" : "Väga hea parool",
- "Valid until {date}" : "Kehtib kuni {date}",
- "Delete" : "Kustuta",
"Groups" : "Grupid",
"Unable to delete {objName}" : "Ei suuda kustutada {objName}",
"Error creating group" : "Viga grupi loomisel",
@@ -90,9 +92,8 @@ OC.L10N.register(
"A valid password must be provided" : "Sisesta nõuetele vastav parool",
"A valid email must be provided" : "Sisesta kehtiv e-posti aadress",
"__language_name__" : "Eesti",
- "Sync clients" : "Klientide sünkroniseerimine",
"Personal info" : "Isiklik info",
- "SSL root certificates" : "SSL root sertifikaadid",
+ "Sync clients" : "Klientide sünkroniseerimine",
"Everything (fatal issues, errors, warnings, info, debug)" : "Kõik (tõsised probleemid, veateated, hoiatused, info, veatuvastus)",
"Info, warnings, errors and fatal issues" : "Info, hoiatused, veateted ja tõsised probleemid",
"Warnings, errors and fatal issues" : "Hoiatused, veateated ja tõsised probleemid",
@@ -149,11 +150,11 @@ OC.L10N.register(
"Store credentials" : "Säilita kasutajaandmed",
"Test email settings" : "Testi e-posti seadeid",
"Send email" : "Saada kiri",
- "Log level" : "Logi tase",
"Download logfile" : "Laadi logifail alla",
"More" : "Rohkem",
"Less" : "Vähem",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Logifail on suurem kui 100 MB. Allalaadimine võib veidi aega võtta!",
+ "What to log" : "Mida logisse sisse kanda",
"How to do backups" : "Kuidas teha varukoopiaid",
"Advanced monitoring" : "Lisavalikutega jälgimine",
"Performance tuning" : "Kiiruse seadistamine",
@@ -162,8 +163,6 @@ OC.L10N.register(
"Version" : "Versioon",
"Developer documentation" : "Arendaja dokumentatsioon",
"Experimental applications ahead" : "Ees on katsetusjärgus rakendused",
- "by" : "lisas",
- "licensed" : "litsenseeritud",
"Documentation:" : "Dokumentatsioon:",
"User documentation" : "Kasutaja dokumentatsioon",
"Admin documentation" : "Administraatori dokumentatsioon",
@@ -172,43 +171,39 @@ OC.L10N.register(
"Enable only for specific groups" : "Luba ainult kindlad grupid",
"Uninstall App" : "Eemada rakend",
"Enable experimental apps" : "Luba katsetusjärgus rakenduste kasutamine",
+ "Common Name" : "Üldnimetus",
+ "Valid until" : "Kehtib kuni",
+ "Issued By" : "isas",
+ "Valid until %s" : "Kehtib kuni %s",
+ "Import root certificate" : "Impordi root sertifikaat",
"Cheers!" : "Terekest!",
"Administrator documentation" : "Administraatori dokumentatsioon",
"Online documentation" : "Võrgus olev dokumentatsioon",
"Forum" : "Foorum",
"Issue tracker" : "Probleemide jälgija",
"Commercial support" : "Tasuline kasutajatugi",
- "Get the apps to sync your files" : "Hangi rakendusi failide sünkroniseerimiseks",
- "Desktop client" : "Töölaua klient",
- "Android app" : "Androidi rakendus",
- "iOS app" : "iOS-i rakendus",
- "Show First Run Wizard again" : "Näita veelkord Esmase Käivituse Juhendajat",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Kasutad <strong>%s</strong> saadavalolevast <strong>%s</strong>",
- "Password" : "Parool",
- "Unable to change your password" : "Sa ei saa oma parooli muuta",
- "Current password" : "Praegune parool",
- "New password" : "Uus parool",
- "Change password" : "Muuda parooli",
+ "Profile picture" : "Profiili pilt",
+ "Upload new" : "Laadi uus üles",
+ "Remove image" : "Eemalda pilt",
+ "Cancel" : "Loobu",
"Full name" : "Täielik nimi",
"No display name set" : "Näidatavat nime pole veel määratud",
"Email" : "E-post",
"Your email address" : "Sinu e-posti aadress",
- "Fill in an email address to enable password recovery and receive notifications" : "Täida e-posti aadress võimaldamaks parooli taastamist ning teadete saamist.",
"No email address set" : "E-posti aadressi pole veel määratud",
- "Profile picture" : "Profiili pilt",
- "Upload new" : "Laadi uus üles",
- "Select new from Files" : "Vali failidest uus",
- "Remove image" : "Eemalda pilt",
- "Your avatar is provided by your original account." : "Sinu avatari pakub sinu algne konto.",
- "Cancel" : "Loobu",
- "Choose as profile image" : "Vali profiilipildiks",
+ "You are member of the following groups:" : "Sa oled nende gruppide liige:",
+ "Password" : "Parool",
+ "Unable to change your password" : "Sa ei saa oma parooli muuta",
+ "Current password" : "Praegune parool",
+ "New password" : "Uus parool",
+ "Change password" : "Muuda parooli",
"Language" : "Keel",
"Help translate" : "Aita tõlkida",
- "Common Name" : "Üldnimetus",
- "Valid until" : "Kehtib kuni",
- "Issued By" : "isas",
- "Valid until %s" : "Kehtib kuni %s",
- "Import root certificate" : "Impordi root sertifikaat",
+ "Get the apps to sync your files" : "Hangi rakendusi failide sünkroniseerimiseks",
+ "Desktop client" : "Töölaua klient",
+ "Android app" : "Androidi rakendus",
+ "iOS app" : "iOS-i rakendus",
+ "Show First Run Wizard again" : "Näita veelkord Esmase Käivituse Juhendajat",
"Show storage location" : "Näita salvestusruumi asukohta",
"Show last log in" : "Viimane sisselogimine",
"Send email to new user" : "Saada uuele kasutajale e-kiri",
@@ -230,6 +225,7 @@ OC.L10N.register(
"Group Admin for" : "Grupi admin",
"Quota" : "Mahupiir",
"Storage Location" : "Mahu asukoht",
+ "User Backend" : "Kasutaja taustarakendus",
"Last Login" : "Viimane sisselogimine",
"change full name" : "Muuda täispikka nime",
"set new password" : "määra uus parool",
diff --git a/settings/l10n/et_EE.json b/settings/l10n/et_EE.json
index 2cdd0499415..7918121db67 100644
--- a/settings/l10n/et_EE.json
+++ b/settings/l10n/et_EE.json
@@ -10,12 +10,10 @@
"Log" : "Logi",
"Tips & tricks" : "Nõuanded ja trikid",
"Updates" : "Uuendused",
- "Authentication error" : "Autentimise viga",
- "Your full name has been changed." : "Sinu täispikk nimi on muudetud.",
- "Unable to change full name" : "Täispika nime muutmine ebaõnnestus",
"Couldn't remove app." : "Ei suutnud rakendit eemaldada.",
"Language changed" : "Keel on muudetud",
"Invalid request" : "Vigane päring",
+ "Authentication error" : "Autentimise viga",
"Admins can't remove themself from the admin group" : "Administraatorid ei saa ise end admin grupist eemaldada",
"Unable to add user to group %s" : "Kasutajat ei saa lisada gruppi %s",
"Unable to remove user from group %s" : "Kasutajat ei saa eemaldada grupist %s",
@@ -44,8 +42,11 @@
"Invalid user" : "Vigane kasutaja",
"Unable to change mail address" : "E-posti aadressi muutmine ebaõnnestus",
"Email saved" : "Kiri on salvestatud",
+ "Your full name has been changed." : "Sinu täispikk nimi on muudetud.",
+ "Unable to change full name" : "Täispika nime muutmine ebaõnnestus",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Oled sa kindel, et soovid lisada domeeni \"{domain}\" usaldusväärseks domeeniks?",
"Add trusted domain" : "Lis ausaldusväärne domeen",
+ "Migration in progress. Please wait until the migration is finished" : "Kolimine on käimas. Palun oota, kuni see on lõpetatud",
"Migration started …" : "Kolimist on alustatud ...",
"Sending..." : "Saadan...",
"Official" : "Ametlik",
@@ -65,14 +66,15 @@
"Uninstalling ...." : "Eemaldan...",
"Error while uninstalling app" : "Viga rakendi eemaldamisel",
"Uninstall" : "Eemalda",
+ "App update" : "Rakenduse uuendus",
+ "Valid until {date}" : "Kehtib kuni {date}",
+ "Delete" : "Kustuta",
"Select a profile picture" : "Vali profiili pilt",
"Very weak password" : "Väga nõrk parool",
"Weak password" : "Nõrk parool",
"So-so password" : "Enam-vähem sobiv parool",
"Good password" : "Hea parool",
"Strong password" : "Väga hea parool",
- "Valid until {date}" : "Kehtib kuni {date}",
- "Delete" : "Kustuta",
"Groups" : "Grupid",
"Unable to delete {objName}" : "Ei suuda kustutada {objName}",
"Error creating group" : "Viga grupi loomisel",
@@ -88,9 +90,8 @@
"A valid password must be provided" : "Sisesta nõuetele vastav parool",
"A valid email must be provided" : "Sisesta kehtiv e-posti aadress",
"__language_name__" : "Eesti",
- "Sync clients" : "Klientide sünkroniseerimine",
"Personal info" : "Isiklik info",
- "SSL root certificates" : "SSL root sertifikaadid",
+ "Sync clients" : "Klientide sünkroniseerimine",
"Everything (fatal issues, errors, warnings, info, debug)" : "Kõik (tõsised probleemid, veateated, hoiatused, info, veatuvastus)",
"Info, warnings, errors and fatal issues" : "Info, hoiatused, veateted ja tõsised probleemid",
"Warnings, errors and fatal issues" : "Hoiatused, veateated ja tõsised probleemid",
@@ -147,11 +148,11 @@
"Store credentials" : "Säilita kasutajaandmed",
"Test email settings" : "Testi e-posti seadeid",
"Send email" : "Saada kiri",
- "Log level" : "Logi tase",
"Download logfile" : "Laadi logifail alla",
"More" : "Rohkem",
"Less" : "Vähem",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Logifail on suurem kui 100 MB. Allalaadimine võib veidi aega võtta!",
+ "What to log" : "Mida logisse sisse kanda",
"How to do backups" : "Kuidas teha varukoopiaid",
"Advanced monitoring" : "Lisavalikutega jälgimine",
"Performance tuning" : "Kiiruse seadistamine",
@@ -160,8 +161,6 @@
"Version" : "Versioon",
"Developer documentation" : "Arendaja dokumentatsioon",
"Experimental applications ahead" : "Ees on katsetusjärgus rakendused",
- "by" : "lisas",
- "licensed" : "litsenseeritud",
"Documentation:" : "Dokumentatsioon:",
"User documentation" : "Kasutaja dokumentatsioon",
"Admin documentation" : "Administraatori dokumentatsioon",
@@ -170,43 +169,39 @@
"Enable only for specific groups" : "Luba ainult kindlad grupid",
"Uninstall App" : "Eemada rakend",
"Enable experimental apps" : "Luba katsetusjärgus rakenduste kasutamine",
+ "Common Name" : "Üldnimetus",
+ "Valid until" : "Kehtib kuni",
+ "Issued By" : "isas",
+ "Valid until %s" : "Kehtib kuni %s",
+ "Import root certificate" : "Impordi root sertifikaat",
"Cheers!" : "Terekest!",
"Administrator documentation" : "Administraatori dokumentatsioon",
"Online documentation" : "Võrgus olev dokumentatsioon",
"Forum" : "Foorum",
"Issue tracker" : "Probleemide jälgija",
"Commercial support" : "Tasuline kasutajatugi",
- "Get the apps to sync your files" : "Hangi rakendusi failide sünkroniseerimiseks",
- "Desktop client" : "Töölaua klient",
- "Android app" : "Androidi rakendus",
- "iOS app" : "iOS-i rakendus",
- "Show First Run Wizard again" : "Näita veelkord Esmase Käivituse Juhendajat",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Kasutad <strong>%s</strong> saadavalolevast <strong>%s</strong>",
- "Password" : "Parool",
- "Unable to change your password" : "Sa ei saa oma parooli muuta",
- "Current password" : "Praegune parool",
- "New password" : "Uus parool",
- "Change password" : "Muuda parooli",
+ "Profile picture" : "Profiili pilt",
+ "Upload new" : "Laadi uus üles",
+ "Remove image" : "Eemalda pilt",
+ "Cancel" : "Loobu",
"Full name" : "Täielik nimi",
"No display name set" : "Näidatavat nime pole veel määratud",
"Email" : "E-post",
"Your email address" : "Sinu e-posti aadress",
- "Fill in an email address to enable password recovery and receive notifications" : "Täida e-posti aadress võimaldamaks parooli taastamist ning teadete saamist.",
"No email address set" : "E-posti aadressi pole veel määratud",
- "Profile picture" : "Profiili pilt",
- "Upload new" : "Laadi uus üles",
- "Select new from Files" : "Vali failidest uus",
- "Remove image" : "Eemalda pilt",
- "Your avatar is provided by your original account." : "Sinu avatari pakub sinu algne konto.",
- "Cancel" : "Loobu",
- "Choose as profile image" : "Vali profiilipildiks",
+ "You are member of the following groups:" : "Sa oled nende gruppide liige:",
+ "Password" : "Parool",
+ "Unable to change your password" : "Sa ei saa oma parooli muuta",
+ "Current password" : "Praegune parool",
+ "New password" : "Uus parool",
+ "Change password" : "Muuda parooli",
"Language" : "Keel",
"Help translate" : "Aita tõlkida",
- "Common Name" : "Üldnimetus",
- "Valid until" : "Kehtib kuni",
- "Issued By" : "isas",
- "Valid until %s" : "Kehtib kuni %s",
- "Import root certificate" : "Impordi root sertifikaat",
+ "Get the apps to sync your files" : "Hangi rakendusi failide sünkroniseerimiseks",
+ "Desktop client" : "Töölaua klient",
+ "Android app" : "Androidi rakendus",
+ "iOS app" : "iOS-i rakendus",
+ "Show First Run Wizard again" : "Näita veelkord Esmase Käivituse Juhendajat",
"Show storage location" : "Näita salvestusruumi asukohta",
"Show last log in" : "Viimane sisselogimine",
"Send email to new user" : "Saada uuele kasutajale e-kiri",
@@ -228,6 +223,7 @@
"Group Admin for" : "Grupi admin",
"Quota" : "Mahupiir",
"Storage Location" : "Mahu asukoht",
+ "User Backend" : "Kasutaja taustarakendus",
"Last Login" : "Viimane sisselogimine",
"change full name" : "Muuda täispikka nime",
"set new password" : "määra uus parool",
diff --git a/settings/l10n/eu.js b/settings/l10n/eu.js
index 0c835b5b233..c30027c4cc6 100644
--- a/settings/l10n/eu.js
+++ b/settings/l10n/eu.js
@@ -6,12 +6,10 @@ OC.L10N.register(
"Cron" : "Cron",
"Log" : "Log",
"Updates" : "Eguneraketak",
- "Authentication error" : "Autentifikazio errorea",
- "Your full name has been changed." : "Zure izena aldatu egin da.",
- "Unable to change full name" : "Ezin izan da izena aldatu",
"Couldn't remove app." : "Ezin izan da aplikazioa ezabatu..",
"Language changed" : "Hizkuntza aldatuta",
"Invalid request" : "Baliogabeko eskaera",
+ "Authentication error" : "Autentifikazio errorea",
"Admins can't remove themself from the admin group" : "Kudeatzaileak ezin du bere burua kendu kudeatzaile taldetik",
"Unable to add user to group %s" : "Ezin izan da erabiltzailea %s taldera gehitu",
"Unable to remove user from group %s" : "Ezin izan da erabiltzailea %s taldetik ezabatu",
@@ -40,6 +38,8 @@ OC.L10N.register(
"Invalid user" : "Baliogabeko erabiiltzailea",
"Unable to change mail address" : "Ezin izan da posta helbidea aldatu",
"Email saved" : "Eposta gorde da",
+ "Your full name has been changed." : "Zure izena aldatu egin da.",
+ "Unable to change full name" : "Ezin izan da izena aldatu",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ziur zaude gehitu nahi duzula \"{domain}\" domeinu fidagarri gisa?",
"Add trusted domain" : "Gehitu domeinu fidagarria",
"Sending..." : "Bidaltzen...",
@@ -56,14 +56,14 @@ OC.L10N.register(
"Uninstalling ...." : "Desinstalatzen ...",
"Error while uninstalling app" : "Erroea izan da aplikazioa desinstalatzerakoan",
"Uninstall" : "Desinstalatu",
+ "Valid until {date}" : "{date} arte baliogarria",
+ "Delete" : "Ezabatu",
"Select a profile picture" : "Profilaren irudia aukeratu",
"Very weak password" : "Pasahitz oso ahula",
"Weak password" : "Pasahitz ahula",
"So-so password" : "Halamoduzko pasahitza",
"Good password" : "Pasahitz ona",
"Strong password" : "Pasahitz sendoa",
- "Valid until {date}" : "{date} arte baliogarria",
- "Delete" : "Ezabatu",
"Groups" : "Taldeak",
"Unable to delete {objName}" : "Ezin izan da {objName} ezabatu",
"Error creating group" : "Errore bat izan da taldea sortzean",
@@ -80,7 +80,6 @@ OC.L10N.register(
"A valid password must be provided" : "Baliozko pasahitza eman behar da",
"A valid email must be provided" : "Baliozko posta elektronikoa eman behar da",
"__language_name__" : "Euskara",
- "SSL root certificates" : "SSL erro ziurtagiriak",
"Everything (fatal issues, errors, warnings, info, debug)" : "Dena (arazo larriak, erroreak, abisuak, informazioa, arazketa)",
"Info, warnings, errors and fatal issues" : "Informazioa, abisuak, erroreak eta arazo larriak.",
"Warnings, errors and fatal issues" : "Abisuak, erroreak eta arazo larriak",
@@ -134,50 +133,42 @@ OC.L10N.register(
"Store credentials" : "Gorde kredentzialak",
"Test email settings" : "Probatu eposta ezarpenak",
"Send email" : "Bidali eposta",
- "Log level" : "Erregistro maila",
"Download logfile" : "Deskargatu log fitxategia",
"More" : "Gehiago",
"Less" : "Gutxiago",
"Version" : "Bertsioa",
- "by" : " Egilea:",
- "licensed" : "lizentziatua",
"Documentation:" : "Dokumentazioa:",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Aplikazioa ezin da instalatu hurrengo menpekotasunak betetzen ez direlako:",
"Enable only for specific groups" : "Baimendu bakarri talde espezifikoetarako",
"Uninstall App" : "Desinstalatu aplikazioa",
+ "Common Name" : "Izen arrunta",
+ "Valid until" : "Data hau arte baliogarria",
+ "Issued By" : "Honek bidalita",
+ "Valid until %s" : "%s arte baliogarria",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Kaixo,<br><br>orain %s kontu bat duzula esateko besterik ez.<br><br>Zure erabiltzailea: %s<br>Sar zaitez: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Ongi izan!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Kaixo,\n\norain %s kontu bat duzula esateko besterik ez.\n\nZure erabiltzailea: %s\nSar zaitez: %s\n\n",
"Forum" : "Foroa",
- "Get the apps to sync your files" : "Lortu aplikazioak zure fitxategiak sinkronizatzeko",
- "Desktop client" : "Mahaigaineko bezeroa",
- "Android app" : "Android aplikazioa",
- "iOS app" : "iOS aplikazioa",
- "Show First Run Wizard again" : "Erakutsi berriz Lehenengo Aldiko Morroia",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Dagoeneko <strong>%s</strong> erabili duzu eskuragarri duzun <strong>%s</strong>etatik",
+ "Profile picture" : "Profilaren irudia",
+ "Upload new" : "Igo berria",
+ "Remove image" : "Irudia ezabatu",
+ "Cancel" : "Ezeztatu",
+ "No display name set" : "Ez da bistaratze izena ezarri",
+ "Email" : "E-posta",
+ "Your email address" : "Zure e-posta",
+ "No email address set" : "Ez da eposta helbidea ezarri",
"Password" : "Pasahitza",
"Unable to change your password" : "Ezin izan da zure pasahitza aldatu",
"Current password" : "Uneko pasahitza",
"New password" : "Pasahitz berria",
"Change password" : "Aldatu pasahitza",
- "No display name set" : "Ez da bistaratze izena ezarri",
- "Email" : "E-posta",
- "Your email address" : "Zure e-posta",
- "Fill in an email address to enable password recovery and receive notifications" : "Bete ezazu eposta helbide bat pasahitza berreskuratzeko eta jakinarazpenak jasotzeko",
- "No email address set" : "Ez da eposta helbidea ezarri",
- "Profile picture" : "Profilaren irudia",
- "Upload new" : "Igo berria",
- "Select new from Files" : "Hautatu berria Fitxategietatik",
- "Remove image" : "Irudia ezabatu",
- "Your avatar is provided by your original account." : "Zure jatorrizko kontuak ezarri du zure avatar.",
- "Cancel" : "Ezeztatu",
- "Choose as profile image" : "Profil irudi bezala aukeratu",
"Language" : "Hizkuntza",
"Help translate" : "Lagundu itzultzen",
- "Common Name" : "Izen arrunta",
- "Valid until" : "Data hau arte baliogarria",
- "Issued By" : "Honek bidalita",
- "Valid until %s" : "%s arte baliogarria",
+ "Get the apps to sync your files" : "Lortu aplikazioak zure fitxategiak sinkronizatzeko",
+ "Desktop client" : "Mahaigaineko bezeroa",
+ "Android app" : "Android aplikazioa",
+ "iOS app" : "iOS aplikazioa",
+ "Show First Run Wizard again" : "Erakutsi berriz Lehenengo Aldiko Morroia",
"Show storage location" : "Erakutsi biltegiaren kokapena",
"Show last log in" : "Erakutsi azkeneko saio hasiera",
"Show user backend" : "Bistaratu erabiltzaile motorra",
diff --git a/settings/l10n/eu.json b/settings/l10n/eu.json
index 1ade6fad49c..c3d5917edb5 100644
--- a/settings/l10n/eu.json
+++ b/settings/l10n/eu.json
@@ -4,12 +4,10 @@
"Cron" : "Cron",
"Log" : "Log",
"Updates" : "Eguneraketak",
- "Authentication error" : "Autentifikazio errorea",
- "Your full name has been changed." : "Zure izena aldatu egin da.",
- "Unable to change full name" : "Ezin izan da izena aldatu",
"Couldn't remove app." : "Ezin izan da aplikazioa ezabatu..",
"Language changed" : "Hizkuntza aldatuta",
"Invalid request" : "Baliogabeko eskaera",
+ "Authentication error" : "Autentifikazio errorea",
"Admins can't remove themself from the admin group" : "Kudeatzaileak ezin du bere burua kendu kudeatzaile taldetik",
"Unable to add user to group %s" : "Ezin izan da erabiltzailea %s taldera gehitu",
"Unable to remove user from group %s" : "Ezin izan da erabiltzailea %s taldetik ezabatu",
@@ -38,6 +36,8 @@
"Invalid user" : "Baliogabeko erabiiltzailea",
"Unable to change mail address" : "Ezin izan da posta helbidea aldatu",
"Email saved" : "Eposta gorde da",
+ "Your full name has been changed." : "Zure izena aldatu egin da.",
+ "Unable to change full name" : "Ezin izan da izena aldatu",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ziur zaude gehitu nahi duzula \"{domain}\" domeinu fidagarri gisa?",
"Add trusted domain" : "Gehitu domeinu fidagarria",
"Sending..." : "Bidaltzen...",
@@ -54,14 +54,14 @@
"Uninstalling ...." : "Desinstalatzen ...",
"Error while uninstalling app" : "Erroea izan da aplikazioa desinstalatzerakoan",
"Uninstall" : "Desinstalatu",
+ "Valid until {date}" : "{date} arte baliogarria",
+ "Delete" : "Ezabatu",
"Select a profile picture" : "Profilaren irudia aukeratu",
"Very weak password" : "Pasahitz oso ahula",
"Weak password" : "Pasahitz ahula",
"So-so password" : "Halamoduzko pasahitza",
"Good password" : "Pasahitz ona",
"Strong password" : "Pasahitz sendoa",
- "Valid until {date}" : "{date} arte baliogarria",
- "Delete" : "Ezabatu",
"Groups" : "Taldeak",
"Unable to delete {objName}" : "Ezin izan da {objName} ezabatu",
"Error creating group" : "Errore bat izan da taldea sortzean",
@@ -78,7 +78,6 @@
"A valid password must be provided" : "Baliozko pasahitza eman behar da",
"A valid email must be provided" : "Baliozko posta elektronikoa eman behar da",
"__language_name__" : "Euskara",
- "SSL root certificates" : "SSL erro ziurtagiriak",
"Everything (fatal issues, errors, warnings, info, debug)" : "Dena (arazo larriak, erroreak, abisuak, informazioa, arazketa)",
"Info, warnings, errors and fatal issues" : "Informazioa, abisuak, erroreak eta arazo larriak.",
"Warnings, errors and fatal issues" : "Abisuak, erroreak eta arazo larriak",
@@ -132,50 +131,42 @@
"Store credentials" : "Gorde kredentzialak",
"Test email settings" : "Probatu eposta ezarpenak",
"Send email" : "Bidali eposta",
- "Log level" : "Erregistro maila",
"Download logfile" : "Deskargatu log fitxategia",
"More" : "Gehiago",
"Less" : "Gutxiago",
"Version" : "Bertsioa",
- "by" : " Egilea:",
- "licensed" : "lizentziatua",
"Documentation:" : "Dokumentazioa:",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Aplikazioa ezin da instalatu hurrengo menpekotasunak betetzen ez direlako:",
"Enable only for specific groups" : "Baimendu bakarri talde espezifikoetarako",
"Uninstall App" : "Desinstalatu aplikazioa",
+ "Common Name" : "Izen arrunta",
+ "Valid until" : "Data hau arte baliogarria",
+ "Issued By" : "Honek bidalita",
+ "Valid until %s" : "%s arte baliogarria",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Kaixo,<br><br>orain %s kontu bat duzula esateko besterik ez.<br><br>Zure erabiltzailea: %s<br>Sar zaitez: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Ongi izan!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Kaixo,\n\norain %s kontu bat duzula esateko besterik ez.\n\nZure erabiltzailea: %s\nSar zaitez: %s\n\n",
"Forum" : "Foroa",
- "Get the apps to sync your files" : "Lortu aplikazioak zure fitxategiak sinkronizatzeko",
- "Desktop client" : "Mahaigaineko bezeroa",
- "Android app" : "Android aplikazioa",
- "iOS app" : "iOS aplikazioa",
- "Show First Run Wizard again" : "Erakutsi berriz Lehenengo Aldiko Morroia",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Dagoeneko <strong>%s</strong> erabili duzu eskuragarri duzun <strong>%s</strong>etatik",
+ "Profile picture" : "Profilaren irudia",
+ "Upload new" : "Igo berria",
+ "Remove image" : "Irudia ezabatu",
+ "Cancel" : "Ezeztatu",
+ "No display name set" : "Ez da bistaratze izena ezarri",
+ "Email" : "E-posta",
+ "Your email address" : "Zure e-posta",
+ "No email address set" : "Ez da eposta helbidea ezarri",
"Password" : "Pasahitza",
"Unable to change your password" : "Ezin izan da zure pasahitza aldatu",
"Current password" : "Uneko pasahitza",
"New password" : "Pasahitz berria",
"Change password" : "Aldatu pasahitza",
- "No display name set" : "Ez da bistaratze izena ezarri",
- "Email" : "E-posta",
- "Your email address" : "Zure e-posta",
- "Fill in an email address to enable password recovery and receive notifications" : "Bete ezazu eposta helbide bat pasahitza berreskuratzeko eta jakinarazpenak jasotzeko",
- "No email address set" : "Ez da eposta helbidea ezarri",
- "Profile picture" : "Profilaren irudia",
- "Upload new" : "Igo berria",
- "Select new from Files" : "Hautatu berria Fitxategietatik",
- "Remove image" : "Irudia ezabatu",
- "Your avatar is provided by your original account." : "Zure jatorrizko kontuak ezarri du zure avatar.",
- "Cancel" : "Ezeztatu",
- "Choose as profile image" : "Profil irudi bezala aukeratu",
"Language" : "Hizkuntza",
"Help translate" : "Lagundu itzultzen",
- "Common Name" : "Izen arrunta",
- "Valid until" : "Data hau arte baliogarria",
- "Issued By" : "Honek bidalita",
- "Valid until %s" : "%s arte baliogarria",
+ "Get the apps to sync your files" : "Lortu aplikazioak zure fitxategiak sinkronizatzeko",
+ "Desktop client" : "Mahaigaineko bezeroa",
+ "Android app" : "Android aplikazioa",
+ "iOS app" : "iOS aplikazioa",
+ "Show First Run Wizard again" : "Erakutsi berriz Lehenengo Aldiko Morroia",
"Show storage location" : "Erakutsi biltegiaren kokapena",
"Show last log in" : "Erakutsi azkeneko saio hasiera",
"Show user backend" : "Bistaratu erabiltzaile motorra",
diff --git a/settings/l10n/fa.js b/settings/l10n/fa.js
index 3d9aba76345..57b95b124e9 100644
--- a/settings/l10n/fa.js
+++ b/settings/l10n/fa.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "کارنامه",
"Tips & tricks" : "نکات و راهنمایی‌ها",
"Updates" : "به روز رسانی ها",
- "Authentication error" : "خطا در اعتبار سنجی",
- "Your full name has been changed." : "نام کامل شما تغییر یافت",
- "Unable to change full name" : "امکان تغییر نام کامل وجود ندارد",
"Couldn't remove app." : "امکان حذف برنامه وجود ندارد.",
"Language changed" : "زبان تغییر کرد",
"Invalid request" : "درخواست نامعتبر",
+ "Authentication error" : "خطا در اعتبار سنجی",
"Admins can't remove themself from the admin group" : "مدیران نمی توانند خود را از گروه مدیریت حذف کنند",
"Unable to add user to group %s" : "امکان افزودن کاربر به گروه %s نیست",
"Unable to remove user from group %s" : "امکان حذف کاربر از گروه %s نیست",
@@ -44,6 +42,8 @@ OC.L10N.register(
"Invalid user" : "کاربر نامعتبر",
"Unable to change mail address" : "تغییر آدرس ایمیل امکان‌پذیر نیست",
"Email saved" : "ایمیل ذخیره شد",
+ "Your full name has been changed." : "نام کامل شما تغییر یافت",
+ "Unable to change full name" : "امکان تغییر نام کامل وجود ندارد",
"Add trusted domain" : "افزودن دامنه مورد اعتماد",
"Migration in progress. Please wait until the migration is finished" : "مهاجرت در حال اجراست. لطفا تا اتمام مهاجرت صبر کنید",
"Migration started …" : "مهاجرت شروع شد...",
@@ -66,6 +66,8 @@ OC.L10N.register(
"Error while uninstalling app" : "خطا در هنگام حذف برنامه....",
"Uninstall" : "حذف",
"App update" : "به روز رسانی برنامه",
+ "Valid until {date}" : "معتبر تا {date}",
+ "Delete" : "حذف",
"An error occurred: {message}" : "یک خطا رخ‌داده است: {message}",
"Select a profile picture" : "انتخاب تصویر پروفایل",
"Very weak password" : "رمز عبور بسیار ضعیف",
@@ -73,8 +75,6 @@ OC.L10N.register(
"So-so password" : "رمز عبور متوسط",
"Good password" : "رمز عبور خوب",
"Strong password" : "رمز عبور قوی",
- "Valid until {date}" : "معتبر تا {date}",
- "Delete" : "حذف",
"Groups" : "گروه ها",
"Unable to delete {objName}" : "امکان حذف {objName} وجود ندارد",
"Error creating group" : "خطا در هنگام ایجاد کروه",
@@ -91,9 +91,8 @@ OC.L10N.register(
"A valid password must be provided" : "رمز عبور صحیح باید وارد شود",
"A valid email must be provided" : "یک ایمیل معتبر باید وارد شود",
"__language_name__" : "__language_name__",
- "Sync clients" : "همگام‌سازی مشتریان",
"Personal info" : "مشخصات شخصی",
- "SSL root certificates" : "گواهی های اصلی SSL ",
+ "Sync clients" : "همگام‌سازی مشتریان",
"Everything (fatal issues, errors, warnings, info, debug)" : "همه موارد (مشکلات مهلک، خطاها، اخطارها، اطلاعات، خطایابی)",
"Info, warnings, errors and fatal issues" : "اطلاعات، اخطارها، خطاها، مشکلات اساسی",
"Warnings, errors and fatal issues" : "اخطارها، خطاها، مشکلات مهلک",
@@ -144,7 +143,6 @@ OC.L10N.register(
"SMTP Password" : "رمز عبور SMTP",
"Test email settings" : "تنظیمات ایمیل آزمایشی",
"Send email" : "ارسال ایمیل",
- "Log level" : "سطح ورود",
"Download logfile" : "دانلود فایل لاگ",
"More" : "بیش‌تر",
"Less" : "کم‌تر",
@@ -155,8 +153,6 @@ OC.L10N.register(
"Hardening and security guidance" : "راهنمای امن‌سازی",
"Version" : "نسخه",
"Developer documentation" : "مستندات توسعه‌دهندگان",
- "by" : "با",
- "licensed" : "مجوزنامه",
"Documentation:" : "مستند سازی:",
"User documentation" : "مستندات کاربر",
"Admin documentation" : "مستندات مدیر",
@@ -166,43 +162,38 @@ OC.L10N.register(
"Enable only for specific groups" : "فعال سازی تنها برای گروه های خاص",
"Uninstall App" : "حذف برنامه",
"Enable experimental apps" : "فعال‌سازی برنامه‌های آزمایشی",
+ "Common Name" : "نام مشترک",
+ "Valid until" : "متعبر تا",
+ "Issued By" : "صدور توسط",
+ "Valid until %s" : "متعبر تا %s",
+ "Import root certificate" : "وارد کردن گواهی اصلی",
"Cheers!" : "سلامتی!",
"Administrator documentation" : "مستندات مدیر",
"Online documentation" : "مستندات آنلاین",
"Forum" : "انجمن",
"Commercial support" : "پشتیبانی تجاری",
- "Get the apps to sync your files" : "برنامه ها را دریافت کنید تا فایل هایتان را همگام سازید",
- "Desktop client" : "نرم افزار دسکتاپ",
- "Android app" : "اپ اندروید",
- "iOS app" : "اپ iOS",
- "Show First Run Wizard again" : "راهبری کمکی اجرای اول را دوباره نمایش بده",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "شما استفاده کردید از <strong>%s</strong> از میزان در دسترس <strong>%s</strong>",
- "Password" : "گذرواژه",
- "Unable to change your password" : "ناتوان در تغییر گذرواژه",
- "Current password" : "گذرواژه کنونی",
- "New password" : "گذرواژه جدید",
- "Change password" : "تغییر گذر واژه",
+ "Profile picture" : "تصویر پروفایل",
+ "Upload new" : "بارگذاری جدید",
+ "Remove image" : "تصویر پاک شود",
+ "Cancel" : "منصرف شدن",
"Full name" : "نام کامل",
"No display name set" : "هیچ نام نمایشی تعیین نشده است",
"Email" : "ایمیل",
"Your email address" : "پست الکترونیکی شما",
- "Fill in an email address to enable password recovery and receive notifications" : "فیلد آدرس ایمیل را به منظور فعال‌سازی بازیابی رمزعبور در دریافت نوتیفیکیش‌ها پر کنید",
"No email address set" : "آدرس‌ایمیلی تنظیم نشده است",
"You are member of the following groups:" : "شما عضو این گروه‌ها هستید:",
- "Profile picture" : "تصویر پروفایل",
- "Upload new" : "بارگذاری جدید",
- "Select new from Files" : "انتخاب جدید از میان فایل ها",
- "Remove image" : "تصویر پاک شود",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "فایل pnd یا jpg. در حالت ایده‌آل بصورت مربع و یا شما می‌توانید آنرا برش بزنید. حجم فایل نمی‌تواند از حداکثر سایز 20MB بیشتر باشد.",
- "Cancel" : "منصرف شدن",
- "Choose as profile image" : "یک تصویر پروفایل انتخاب کنید",
+ "Password" : "گذرواژه",
+ "Unable to change your password" : "ناتوان در تغییر گذرواژه",
+ "Current password" : "گذرواژه کنونی",
+ "New password" : "گذرواژه جدید",
+ "Change password" : "تغییر گذر واژه",
"Language" : "زبان",
"Help translate" : "به ترجمه آن کمک کنید",
- "Common Name" : "نام مشترک",
- "Valid until" : "متعبر تا",
- "Issued By" : "صدور توسط",
- "Valid until %s" : "متعبر تا %s",
- "Import root certificate" : "وارد کردن گواهی اصلی",
+ "Get the apps to sync your files" : "برنامه ها را دریافت کنید تا فایل هایتان را همگام سازید",
+ "Desktop client" : "نرم افزار دسکتاپ",
+ "Android app" : "اپ اندروید",
+ "iOS app" : "اپ iOS",
+ "Show First Run Wizard again" : "راهبری کمکی اجرای اول را دوباره نمایش بده",
"Show storage location" : "نمایش محل ذخیره‌سازی",
"Show last log in" : "نمایش اخرین ورود",
"Send email to new user" : "ارسال ایمیل به کاربر جدید",
diff --git a/settings/l10n/fa.json b/settings/l10n/fa.json
index f152587d529..a4b8aec4896 100644
--- a/settings/l10n/fa.json
+++ b/settings/l10n/fa.json
@@ -10,12 +10,10 @@
"Log" : "کارنامه",
"Tips & tricks" : "نکات و راهنمایی‌ها",
"Updates" : "به روز رسانی ها",
- "Authentication error" : "خطا در اعتبار سنجی",
- "Your full name has been changed." : "نام کامل شما تغییر یافت",
- "Unable to change full name" : "امکان تغییر نام کامل وجود ندارد",
"Couldn't remove app." : "امکان حذف برنامه وجود ندارد.",
"Language changed" : "زبان تغییر کرد",
"Invalid request" : "درخواست نامعتبر",
+ "Authentication error" : "خطا در اعتبار سنجی",
"Admins can't remove themself from the admin group" : "مدیران نمی توانند خود را از گروه مدیریت حذف کنند",
"Unable to add user to group %s" : "امکان افزودن کاربر به گروه %s نیست",
"Unable to remove user from group %s" : "امکان حذف کاربر از گروه %s نیست",
@@ -42,6 +40,8 @@
"Invalid user" : "کاربر نامعتبر",
"Unable to change mail address" : "تغییر آدرس ایمیل امکان‌پذیر نیست",
"Email saved" : "ایمیل ذخیره شد",
+ "Your full name has been changed." : "نام کامل شما تغییر یافت",
+ "Unable to change full name" : "امکان تغییر نام کامل وجود ندارد",
"Add trusted domain" : "افزودن دامنه مورد اعتماد",
"Migration in progress. Please wait until the migration is finished" : "مهاجرت در حال اجراست. لطفا تا اتمام مهاجرت صبر کنید",
"Migration started …" : "مهاجرت شروع شد...",
@@ -64,6 +64,8 @@
"Error while uninstalling app" : "خطا در هنگام حذف برنامه....",
"Uninstall" : "حذف",
"App update" : "به روز رسانی برنامه",
+ "Valid until {date}" : "معتبر تا {date}",
+ "Delete" : "حذف",
"An error occurred: {message}" : "یک خطا رخ‌داده است: {message}",
"Select a profile picture" : "انتخاب تصویر پروفایل",
"Very weak password" : "رمز عبور بسیار ضعیف",
@@ -71,8 +73,6 @@
"So-so password" : "رمز عبور متوسط",
"Good password" : "رمز عبور خوب",
"Strong password" : "رمز عبور قوی",
- "Valid until {date}" : "معتبر تا {date}",
- "Delete" : "حذف",
"Groups" : "گروه ها",
"Unable to delete {objName}" : "امکان حذف {objName} وجود ندارد",
"Error creating group" : "خطا در هنگام ایجاد کروه",
@@ -89,9 +89,8 @@
"A valid password must be provided" : "رمز عبور صحیح باید وارد شود",
"A valid email must be provided" : "یک ایمیل معتبر باید وارد شود",
"__language_name__" : "__language_name__",
- "Sync clients" : "همگام‌سازی مشتریان",
"Personal info" : "مشخصات شخصی",
- "SSL root certificates" : "گواهی های اصلی SSL ",
+ "Sync clients" : "همگام‌سازی مشتریان",
"Everything (fatal issues, errors, warnings, info, debug)" : "همه موارد (مشکلات مهلک، خطاها، اخطارها، اطلاعات، خطایابی)",
"Info, warnings, errors and fatal issues" : "اطلاعات، اخطارها، خطاها، مشکلات اساسی",
"Warnings, errors and fatal issues" : "اخطارها، خطاها، مشکلات مهلک",
@@ -142,7 +141,6 @@
"SMTP Password" : "رمز عبور SMTP",
"Test email settings" : "تنظیمات ایمیل آزمایشی",
"Send email" : "ارسال ایمیل",
- "Log level" : "سطح ورود",
"Download logfile" : "دانلود فایل لاگ",
"More" : "بیش‌تر",
"Less" : "کم‌تر",
@@ -153,8 +151,6 @@
"Hardening and security guidance" : "راهنمای امن‌سازی",
"Version" : "نسخه",
"Developer documentation" : "مستندات توسعه‌دهندگان",
- "by" : "با",
- "licensed" : "مجوزنامه",
"Documentation:" : "مستند سازی:",
"User documentation" : "مستندات کاربر",
"Admin documentation" : "مستندات مدیر",
@@ -164,43 +160,38 @@
"Enable only for specific groups" : "فعال سازی تنها برای گروه های خاص",
"Uninstall App" : "حذف برنامه",
"Enable experimental apps" : "فعال‌سازی برنامه‌های آزمایشی",
+ "Common Name" : "نام مشترک",
+ "Valid until" : "متعبر تا",
+ "Issued By" : "صدور توسط",
+ "Valid until %s" : "متعبر تا %s",
+ "Import root certificate" : "وارد کردن گواهی اصلی",
"Cheers!" : "سلامتی!",
"Administrator documentation" : "مستندات مدیر",
"Online documentation" : "مستندات آنلاین",
"Forum" : "انجمن",
"Commercial support" : "پشتیبانی تجاری",
- "Get the apps to sync your files" : "برنامه ها را دریافت کنید تا فایل هایتان را همگام سازید",
- "Desktop client" : "نرم افزار دسکتاپ",
- "Android app" : "اپ اندروید",
- "iOS app" : "اپ iOS",
- "Show First Run Wizard again" : "راهبری کمکی اجرای اول را دوباره نمایش بده",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "شما استفاده کردید از <strong>%s</strong> از میزان در دسترس <strong>%s</strong>",
- "Password" : "گذرواژه",
- "Unable to change your password" : "ناتوان در تغییر گذرواژه",
- "Current password" : "گذرواژه کنونی",
- "New password" : "گذرواژه جدید",
- "Change password" : "تغییر گذر واژه",
+ "Profile picture" : "تصویر پروفایل",
+ "Upload new" : "بارگذاری جدید",
+ "Remove image" : "تصویر پاک شود",
+ "Cancel" : "منصرف شدن",
"Full name" : "نام کامل",
"No display name set" : "هیچ نام نمایشی تعیین نشده است",
"Email" : "ایمیل",
"Your email address" : "پست الکترونیکی شما",
- "Fill in an email address to enable password recovery and receive notifications" : "فیلد آدرس ایمیل را به منظور فعال‌سازی بازیابی رمزعبور در دریافت نوتیفیکیش‌ها پر کنید",
"No email address set" : "آدرس‌ایمیلی تنظیم نشده است",
"You are member of the following groups:" : "شما عضو این گروه‌ها هستید:",
- "Profile picture" : "تصویر پروفایل",
- "Upload new" : "بارگذاری جدید",
- "Select new from Files" : "انتخاب جدید از میان فایل ها",
- "Remove image" : "تصویر پاک شود",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "فایل pnd یا jpg. در حالت ایده‌آل بصورت مربع و یا شما می‌توانید آنرا برش بزنید. حجم فایل نمی‌تواند از حداکثر سایز 20MB بیشتر باشد.",
- "Cancel" : "منصرف شدن",
- "Choose as profile image" : "یک تصویر پروفایل انتخاب کنید",
+ "Password" : "گذرواژه",
+ "Unable to change your password" : "ناتوان در تغییر گذرواژه",
+ "Current password" : "گذرواژه کنونی",
+ "New password" : "گذرواژه جدید",
+ "Change password" : "تغییر گذر واژه",
"Language" : "زبان",
"Help translate" : "به ترجمه آن کمک کنید",
- "Common Name" : "نام مشترک",
- "Valid until" : "متعبر تا",
- "Issued By" : "صدور توسط",
- "Valid until %s" : "متعبر تا %s",
- "Import root certificate" : "وارد کردن گواهی اصلی",
+ "Get the apps to sync your files" : "برنامه ها را دریافت کنید تا فایل هایتان را همگام سازید",
+ "Desktop client" : "نرم افزار دسکتاپ",
+ "Android app" : "اپ اندروید",
+ "iOS app" : "اپ iOS",
+ "Show First Run Wizard again" : "راهبری کمکی اجرای اول را دوباره نمایش بده",
"Show storage location" : "نمایش محل ذخیره‌سازی",
"Show last log in" : "نمایش اخرین ورود",
"Send email to new user" : "ارسال ایمیل به کاربر جدید",
diff --git a/settings/l10n/fi_FI.js b/settings/l10n/fi_FI.js
index 0099a3f3221..5e440e19e29 100644
--- a/settings/l10n/fi_FI.js
+++ b/settings/l10n/fi_FI.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Loki",
"Tips & tricks" : "Vinkit",
"Updates" : "Päivitykset",
- "Authentication error" : "Tunnistautumisvirhe",
- "Your full name has been changed." : "Koko nimesi on muutettu.",
- "Unable to change full name" : "Koko nimen muuttaminen epäonnistui",
"Couldn't remove app." : "Sovelluksen poistaminen epäonnistui.",
"Language changed" : "Kieli on vaihdettu",
"Invalid request" : "Virheellinen pyyntö",
+ "Authentication error" : "Tunnistautumisvirhe",
"Admins can't remove themself from the admin group" : "Ylläpitäjät eivät poistaa omia tunnuksiaan ylläpitäjien ryhmästä",
"Unable to add user to group %s" : "Käyttäjän tai ryhmän %s lisääminen ei onnistu",
"Unable to remove user from group %s" : "Käyttäjän poistaminen ryhmästä %s ei onnistu",
@@ -52,6 +50,8 @@ OC.L10N.register(
"Invalid user" : "Virheellinen käyttäjä",
"Unable to change mail address" : "Sähköpostiosoitteen vaihtaminen ei onnistunut",
"Email saved" : "Sähköposti tallennettu",
+ "Your full name has been changed." : "Koko nimesi on muutettu.",
+ "Unable to change full name" : "Koko nimen muuttaminen epäonnistui",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Haluatko varmasti liittää kohteen \"{domain}\" luotetuksi toimialueeksi?",
"Add trusted domain" : "Lisää luotettu toimialue",
"Migration in progress. Please wait until the migration is finished" : "Migraatio on kesken. Odota kunnes migraatio valmistuu",
@@ -80,6 +80,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Tämä sovellus on otettu käyttöön, mutta se vaatii päivityksen. Sinut ohjataan päivityssivulle viiden sekunnin kuluttua.",
"App update" : "Sovelluspäivitys",
"No apps found for \"{query}\"" : "Haulla \"{query}\" ei löytynyt sovelluksia",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Tapahtu virhe. Lähetä ASCII-koodattu PEM-varmenne.",
+ "Valid until {date}" : "Kelvollinen {date} asti",
+ "Delete" : "Poista",
"An error occurred: {message}" : "Tapahtui virhe: {message}",
"Select a profile picture" : "Valitse profiilikuva",
"Very weak password" : "Erittäin heikko salasana",
@@ -87,9 +90,6 @@ OC.L10N.register(
"So-so password" : "Kohtalainen salasana",
"Good password" : "Hyvä salasana",
"Strong password" : "Vahva salasana",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Tapahtu virhe. Lähetä ASCII-koodattu PEM-varmenne.",
- "Valid until {date}" : "Kelvollinen {date} asti",
- "Delete" : "Poista",
"Groups" : "Ryhmät",
"Unable to delete {objName}" : "Kohteen {objName} poistaminen epäonnistui",
"Error creating group" : "Virhe ryhmää luotaessa",
@@ -106,9 +106,8 @@ OC.L10N.register(
"A valid password must be provided" : "Anna kelvollinen salasana",
"A valid email must be provided" : "Tarvitaan kelvollinen sähköpostiosoite",
"__language_name__" : "_kielen_nimi_",
- "Sync clients" : "Synkronointisovellukset",
"Personal info" : "Henkilökohtaiset tiedot",
- "SSL root certificates" : "SSL-juurivarmenteet",
+ "Sync clients" : "Synkronointisovellukset",
"Everything (fatal issues, errors, warnings, info, debug)" : "Kaikki (vakavat ongelmat, virheet, varoitukset, tiedot, vianjäljitys)",
"Info, warnings, errors and fatal issues" : "Tiedot, varoitukset, virheet ja vakavat ongelmat",
"Warnings, errors and fatal issues" : "Varoitukset, virheet ja vakavat ongelmat",
@@ -154,7 +153,9 @@ OC.L10N.register(
"Use system's cron service to call the cron.php file every 15 minutes." : "Käytä järjestelmän cron-palvelua cron.php-tiedoston kutsumista varten 15 minuutin välein.",
"Enable server-side encryption" : "Käytä palvelinpään salausta",
"Please read carefully before activating server-side encryption: " : "Lue tarkasti, ennen kuin otat palvelinpään salauksen käyttöön:",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "Salaaminen pelkästään ei takaa järjestelmän tietoturvaa. Tutustu ownCloudin dokumentaation saadaksesi lisätietoja salaussovelluksen toiminnasta ja tuetuista käyttötapauksista.",
"Be aware that encryption always increases the file size." : "Ota huomioon, että salaus kasvattaa aina tiedostojen kokoa.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "Säännöllisten varmuuskopioiden ottaminen on erittäin tärkeää. Jos olet ottanut salauksen käyttöön, huolehdi salausavainten varmuuskopioinnista.",
"This is the final warning: Do you really want to enable encryption?" : "Tämä on viimeinen varoitus: haluatko varmasti ottaa salauksen käyttöön?",
"Enable encryption" : "Käytä salausta",
"No encryption module loaded, please enable an encryption module in the app menu." : "Salausmoduulia ei ole käytössä. Ota salausmoduuli käyttöön sovellusvalikosta.",
@@ -176,11 +177,11 @@ OC.L10N.register(
"Store credentials" : "Säilytä tilitiedot",
"Test email settings" : "Testaa sähköpostiasetukset",
"Send email" : "Lähetä sähköpostiviesti",
- "Log level" : "Lokitaso",
"Download logfile" : "Lataa lokitiedosto",
"More" : "Enemmän",
"Less" : "Vähemmän",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Lokitiedosto on kooltaan yli 100 megatavua. Sen lataaminen saattaa kestää hetken.",
+ "What to log" : "Mitä kerätään lokiin",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLitea käytetään tietokantana. Suuria asennuksia varten on suositeltavaa vaihtaa muuhun tietokantaan.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Varsinkin työpöytäsovelluksen tiedostosynkronointia käyttäessä SQLiten käyttö ei ole suositeltavaa.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Käytä komentorivityökalua toiseen tietokantaan migraation yhteydessä: 'occ db:convert-type', tai <a target=\"_blank\" href=\"%s\">lue toki myös dokumentaatio ↗</a>.",
@@ -194,17 +195,25 @@ OC.L10N.register(
"Developer documentation" : "Kehittäjädokumentaatio",
"Experimental applications ahead" : "Kokeellisia sovelluksia edessä",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Kokeellisia sovelluksia ei ole tarkistettu tietoturvauhkien varalta. Sovellukset ovat uusia, ne saattavat olla epävakaita ja ovat nopean kehityksen alaisia. Kokeellisten sovellusten asentaminen saattaa aiheuttaa tietojen katoamista tai tietoturvauhkia.",
- "by" : " Kirjoittaja:",
- "licensed" : "lisensoitu",
+ "by %s" : "tekijä %s",
+ "%s-licensed" : "%s -lisensoitu",
"Documentation:" : "Ohjeistus:",
"User documentation" : "Käyttäjädokumentaatio",
"Admin documentation" : "Ylläpitäjän ohjeistus",
"Show description …" : "Näytä kuvaus…",
"Hide description …" : "Piilota kuvaus…",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Tälle sovellukselle ei ole määritelty ownCloudin vähimmäisversiota. Tämä johtaa virheeseen ownCloud 11:stä alkaen.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Tälle sovellukselle ei ole määritelty ownCloudin enimmäisversiota. Tämä johtaa virheeseen ownCloud 11:stä alkaen.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Tätä sovellusta ei voi asentaa, koska seuraavat riippuvuudet eivät täyty:",
"Enable only for specific groups" : "Salli vain tietyille ryhmille",
"Uninstall App" : "Poista sovelluksen asennus",
"Enable experimental apps" : "Käytä kokeiluasteella olevia sovelluksia",
+ "SSL Root Certificates" : "SSL-juurivarmenteet",
+ "Common Name" : "Yleinen nimi",
+ "Valid until" : "Kelvollinen",
+ "Issued By" : " Myöntänyt",
+ "Valid until %s" : "Kelvollinen %s asti",
+ "Import root certificate" : "Tuo juurivarmenne",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hei<br><br>Sinulla on nyt %s-tili.<br><br>Käyttäjätunnus: %s<br>Aloita käyttö: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Kippis!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hei\n\nSinulla on nyt %s-tili.\n\nKäyttäjätunnuksesi: %s\nAloita käyttö: %s\n\n",
@@ -213,40 +222,35 @@ OC.L10N.register(
"Forum" : "Keskustelupalsta",
"Issue tracker" : "Ongelmien seuranta",
"Commercial support" : "Kaupallinen tuki",
- "Get the apps to sync your files" : "Aseta sovellukset synkronoimaan tiedostosi",
- "Desktop client" : "Työpöytäsovellus",
- "Android app" : "Android-sovellus",
- "iOS app" : "iOS-sovellus",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Jos haluat tukea projektia, \n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">auta sovelluskehityksessä</a>\n\t\ttai\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">levitä sanaa</a>!",
- "Show First Run Wizard again" : "Näytä ensimmäisen käyttökerran avustaja uudelleen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Käytössäsi on <strong>%s</strong>/<strong>%s</strong>",
- "Password" : "Salasana",
- "Unable to change your password" : "Salasanaasi ei voitu vaihtaa",
- "Current password" : "Nykyinen salasana",
- "New password" : "Uusi salasana",
- "Change password" : "Vaihda salasana",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Käytössäsi on <strong>%s</strong>/<strong>%s</strong>",
+ "Profile picture" : "Profiilikuva",
+ "Upload new" : "Lähetä uusi",
+ "Select from Files" : "Valitse tiedostosovelluksesta",
+ "Remove image" : "Poista kuva",
+ "png or jpg, max. 20 MB" : "png tai jpg, korkeintaan 20 Mt",
+ "Picture provided by original account" : "Kuvan tarjoaa alkuperäinen tili",
+ "Cancel" : "Peru",
+ "Choose as profile picture" : "Valitse profiilikuvaksi",
"Full name" : "Koko nimi",
"No display name set" : "Näyttönimeä ei ole asetettu",
"Email" : "Sähköpostiosoite",
"Your email address" : "Sähköpostiosoitteesi",
- "Fill in an email address to enable password recovery and receive notifications" : "Anna sähköpostiosoitteesi, jotta unohdettu salasana on mahdollista palauttaa ja voit vastaanottaa ilmoituksia",
+ "For password recovery and notifications" : "Salasanan nollausta ja ilmoituksia varten",
"No email address set" : "Sähköpostiosoitetta ei ole asetettu",
"You are member of the following groups:" : "Olet jäsenenä seuraavissa ryhmissä:",
- "Profile picture" : "Profiilikuva",
- "Upload new" : "Lähetä uusi",
- "Select new from Files" : "Valitse uusi tiedostoista",
- "Remove image" : "Poista kuva",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Joko png- tai jpg-kuva. Mieluiten neliö, voit kuitenkin rajata kuvaa. Tiedosto voi olla korkeintaan 20 megatavun kokoinen.",
- "Your avatar is provided by your original account." : "Avatar-kuvasi pohjautuu alkuperäiseen tiliisi.",
- "Cancel" : "Peru",
- "Choose as profile image" : "Valitse profiilikuvaksi",
+ "Password" : "Salasana",
+ "Unable to change your password" : "Salasanaasi ei voitu vaihtaa",
+ "Current password" : "Nykyinen salasana",
+ "New password" : "Uusi salasana",
+ "Change password" : "Vaihda salasana",
"Language" : "Kieli",
"Help translate" : "Auta kääntämisessä",
- "Common Name" : "Yleinen nimi",
- "Valid until" : "Kelvollinen",
- "Issued By" : " Myöntänyt",
- "Valid until %s" : "Kelvollinen %s asti",
- "Import root certificate" : "Tuo juurivarmenne",
+ "Get the apps to sync your files" : "Aseta sovellukset synkronoimaan tiedostosi",
+ "Desktop client" : "Työpöytäsovellus",
+ "Android app" : "Android-sovellus",
+ "iOS app" : "iOS-sovellus",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Jos haluat tukea projektia, \n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">auta sovelluskehityksessä</a>\n\t\ttai\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">levitä sanaa</a>!",
+ "Show First Run Wizard again" : "Näytä ensimmäisen käyttökerran avustaja uudelleen",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Kehityksestä on vastannut {communityopen}ownCloud-yhteisö{linkclose}, {githubopen}lähdekoodi{linkclose} on {licenseopen}<abbr title=\"Affero General Public License\">AGPL-lisensoitu</abbr>{linkclose}.",
"Show storage location" : "Näytä tallennustilan sijainti",
"Show last log in" : "Näytä viimeisin sisäänkirjautuminen",
diff --git a/settings/l10n/fi_FI.json b/settings/l10n/fi_FI.json
index 8305ac79050..cb7b5a7dd1b 100644
--- a/settings/l10n/fi_FI.json
+++ b/settings/l10n/fi_FI.json
@@ -10,12 +10,10 @@
"Log" : "Loki",
"Tips & tricks" : "Vinkit",
"Updates" : "Päivitykset",
- "Authentication error" : "Tunnistautumisvirhe",
- "Your full name has been changed." : "Koko nimesi on muutettu.",
- "Unable to change full name" : "Koko nimen muuttaminen epäonnistui",
"Couldn't remove app." : "Sovelluksen poistaminen epäonnistui.",
"Language changed" : "Kieli on vaihdettu",
"Invalid request" : "Virheellinen pyyntö",
+ "Authentication error" : "Tunnistautumisvirhe",
"Admins can't remove themself from the admin group" : "Ylläpitäjät eivät poistaa omia tunnuksiaan ylläpitäjien ryhmästä",
"Unable to add user to group %s" : "Käyttäjän tai ryhmän %s lisääminen ei onnistu",
"Unable to remove user from group %s" : "Käyttäjän poistaminen ryhmästä %s ei onnistu",
@@ -50,6 +48,8 @@
"Invalid user" : "Virheellinen käyttäjä",
"Unable to change mail address" : "Sähköpostiosoitteen vaihtaminen ei onnistunut",
"Email saved" : "Sähköposti tallennettu",
+ "Your full name has been changed." : "Koko nimesi on muutettu.",
+ "Unable to change full name" : "Koko nimen muuttaminen epäonnistui",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Haluatko varmasti liittää kohteen \"{domain}\" luotetuksi toimialueeksi?",
"Add trusted domain" : "Lisää luotettu toimialue",
"Migration in progress. Please wait until the migration is finished" : "Migraatio on kesken. Odota kunnes migraatio valmistuu",
@@ -78,6 +78,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Tämä sovellus on otettu käyttöön, mutta se vaatii päivityksen. Sinut ohjataan päivityssivulle viiden sekunnin kuluttua.",
"App update" : "Sovelluspäivitys",
"No apps found for \"{query}\"" : "Haulla \"{query}\" ei löytynyt sovelluksia",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Tapahtu virhe. Lähetä ASCII-koodattu PEM-varmenne.",
+ "Valid until {date}" : "Kelvollinen {date} asti",
+ "Delete" : "Poista",
"An error occurred: {message}" : "Tapahtui virhe: {message}",
"Select a profile picture" : "Valitse profiilikuva",
"Very weak password" : "Erittäin heikko salasana",
@@ -85,9 +88,6 @@
"So-so password" : "Kohtalainen salasana",
"Good password" : "Hyvä salasana",
"Strong password" : "Vahva salasana",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Tapahtu virhe. Lähetä ASCII-koodattu PEM-varmenne.",
- "Valid until {date}" : "Kelvollinen {date} asti",
- "Delete" : "Poista",
"Groups" : "Ryhmät",
"Unable to delete {objName}" : "Kohteen {objName} poistaminen epäonnistui",
"Error creating group" : "Virhe ryhmää luotaessa",
@@ -104,9 +104,8 @@
"A valid password must be provided" : "Anna kelvollinen salasana",
"A valid email must be provided" : "Tarvitaan kelvollinen sähköpostiosoite",
"__language_name__" : "_kielen_nimi_",
- "Sync clients" : "Synkronointisovellukset",
"Personal info" : "Henkilökohtaiset tiedot",
- "SSL root certificates" : "SSL-juurivarmenteet",
+ "Sync clients" : "Synkronointisovellukset",
"Everything (fatal issues, errors, warnings, info, debug)" : "Kaikki (vakavat ongelmat, virheet, varoitukset, tiedot, vianjäljitys)",
"Info, warnings, errors and fatal issues" : "Tiedot, varoitukset, virheet ja vakavat ongelmat",
"Warnings, errors and fatal issues" : "Varoitukset, virheet ja vakavat ongelmat",
@@ -152,7 +151,9 @@
"Use system's cron service to call the cron.php file every 15 minutes." : "Käytä järjestelmän cron-palvelua cron.php-tiedoston kutsumista varten 15 minuutin välein.",
"Enable server-side encryption" : "Käytä palvelinpään salausta",
"Please read carefully before activating server-side encryption: " : "Lue tarkasti, ennen kuin otat palvelinpään salauksen käyttöön:",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "Salaaminen pelkästään ei takaa järjestelmän tietoturvaa. Tutustu ownCloudin dokumentaation saadaksesi lisätietoja salaussovelluksen toiminnasta ja tuetuista käyttötapauksista.",
"Be aware that encryption always increases the file size." : "Ota huomioon, että salaus kasvattaa aina tiedostojen kokoa.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "Säännöllisten varmuuskopioiden ottaminen on erittäin tärkeää. Jos olet ottanut salauksen käyttöön, huolehdi salausavainten varmuuskopioinnista.",
"This is the final warning: Do you really want to enable encryption?" : "Tämä on viimeinen varoitus: haluatko varmasti ottaa salauksen käyttöön?",
"Enable encryption" : "Käytä salausta",
"No encryption module loaded, please enable an encryption module in the app menu." : "Salausmoduulia ei ole käytössä. Ota salausmoduuli käyttöön sovellusvalikosta.",
@@ -174,11 +175,11 @@
"Store credentials" : "Säilytä tilitiedot",
"Test email settings" : "Testaa sähköpostiasetukset",
"Send email" : "Lähetä sähköpostiviesti",
- "Log level" : "Lokitaso",
"Download logfile" : "Lataa lokitiedosto",
"More" : "Enemmän",
"Less" : "Vähemmän",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Lokitiedosto on kooltaan yli 100 megatavua. Sen lataaminen saattaa kestää hetken.",
+ "What to log" : "Mitä kerätään lokiin",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLitea käytetään tietokantana. Suuria asennuksia varten on suositeltavaa vaihtaa muuhun tietokantaan.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Varsinkin työpöytäsovelluksen tiedostosynkronointia käyttäessä SQLiten käyttö ei ole suositeltavaa.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Käytä komentorivityökalua toiseen tietokantaan migraation yhteydessä: 'occ db:convert-type', tai <a target=\"_blank\" href=\"%s\">lue toki myös dokumentaatio ↗</a>.",
@@ -192,17 +193,25 @@
"Developer documentation" : "Kehittäjädokumentaatio",
"Experimental applications ahead" : "Kokeellisia sovelluksia edessä",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Kokeellisia sovelluksia ei ole tarkistettu tietoturvauhkien varalta. Sovellukset ovat uusia, ne saattavat olla epävakaita ja ovat nopean kehityksen alaisia. Kokeellisten sovellusten asentaminen saattaa aiheuttaa tietojen katoamista tai tietoturvauhkia.",
- "by" : " Kirjoittaja:",
- "licensed" : "lisensoitu",
+ "by %s" : "tekijä %s",
+ "%s-licensed" : "%s -lisensoitu",
"Documentation:" : "Ohjeistus:",
"User documentation" : "Käyttäjädokumentaatio",
"Admin documentation" : "Ylläpitäjän ohjeistus",
"Show description …" : "Näytä kuvaus…",
"Hide description …" : "Piilota kuvaus…",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Tälle sovellukselle ei ole määritelty ownCloudin vähimmäisversiota. Tämä johtaa virheeseen ownCloud 11:stä alkaen.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Tälle sovellukselle ei ole määritelty ownCloudin enimmäisversiota. Tämä johtaa virheeseen ownCloud 11:stä alkaen.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Tätä sovellusta ei voi asentaa, koska seuraavat riippuvuudet eivät täyty:",
"Enable only for specific groups" : "Salli vain tietyille ryhmille",
"Uninstall App" : "Poista sovelluksen asennus",
"Enable experimental apps" : "Käytä kokeiluasteella olevia sovelluksia",
+ "SSL Root Certificates" : "SSL-juurivarmenteet",
+ "Common Name" : "Yleinen nimi",
+ "Valid until" : "Kelvollinen",
+ "Issued By" : " Myöntänyt",
+ "Valid until %s" : "Kelvollinen %s asti",
+ "Import root certificate" : "Tuo juurivarmenne",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hei<br><br>Sinulla on nyt %s-tili.<br><br>Käyttäjätunnus: %s<br>Aloita käyttö: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Kippis!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hei\n\nSinulla on nyt %s-tili.\n\nKäyttäjätunnuksesi: %s\nAloita käyttö: %s\n\n",
@@ -211,40 +220,35 @@
"Forum" : "Keskustelupalsta",
"Issue tracker" : "Ongelmien seuranta",
"Commercial support" : "Kaupallinen tuki",
- "Get the apps to sync your files" : "Aseta sovellukset synkronoimaan tiedostosi",
- "Desktop client" : "Työpöytäsovellus",
- "Android app" : "Android-sovellus",
- "iOS app" : "iOS-sovellus",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Jos haluat tukea projektia, \n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">auta sovelluskehityksessä</a>\n\t\ttai\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">levitä sanaa</a>!",
- "Show First Run Wizard again" : "Näytä ensimmäisen käyttökerran avustaja uudelleen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Käytössäsi on <strong>%s</strong>/<strong>%s</strong>",
- "Password" : "Salasana",
- "Unable to change your password" : "Salasanaasi ei voitu vaihtaa",
- "Current password" : "Nykyinen salasana",
- "New password" : "Uusi salasana",
- "Change password" : "Vaihda salasana",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Käytössäsi on <strong>%s</strong>/<strong>%s</strong>",
+ "Profile picture" : "Profiilikuva",
+ "Upload new" : "Lähetä uusi",
+ "Select from Files" : "Valitse tiedostosovelluksesta",
+ "Remove image" : "Poista kuva",
+ "png or jpg, max. 20 MB" : "png tai jpg, korkeintaan 20 Mt",
+ "Picture provided by original account" : "Kuvan tarjoaa alkuperäinen tili",
+ "Cancel" : "Peru",
+ "Choose as profile picture" : "Valitse profiilikuvaksi",
"Full name" : "Koko nimi",
"No display name set" : "Näyttönimeä ei ole asetettu",
"Email" : "Sähköpostiosoite",
"Your email address" : "Sähköpostiosoitteesi",
- "Fill in an email address to enable password recovery and receive notifications" : "Anna sähköpostiosoitteesi, jotta unohdettu salasana on mahdollista palauttaa ja voit vastaanottaa ilmoituksia",
+ "For password recovery and notifications" : "Salasanan nollausta ja ilmoituksia varten",
"No email address set" : "Sähköpostiosoitetta ei ole asetettu",
"You are member of the following groups:" : "Olet jäsenenä seuraavissa ryhmissä:",
- "Profile picture" : "Profiilikuva",
- "Upload new" : "Lähetä uusi",
- "Select new from Files" : "Valitse uusi tiedostoista",
- "Remove image" : "Poista kuva",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Joko png- tai jpg-kuva. Mieluiten neliö, voit kuitenkin rajata kuvaa. Tiedosto voi olla korkeintaan 20 megatavun kokoinen.",
- "Your avatar is provided by your original account." : "Avatar-kuvasi pohjautuu alkuperäiseen tiliisi.",
- "Cancel" : "Peru",
- "Choose as profile image" : "Valitse profiilikuvaksi",
+ "Password" : "Salasana",
+ "Unable to change your password" : "Salasanaasi ei voitu vaihtaa",
+ "Current password" : "Nykyinen salasana",
+ "New password" : "Uusi salasana",
+ "Change password" : "Vaihda salasana",
"Language" : "Kieli",
"Help translate" : "Auta kääntämisessä",
- "Common Name" : "Yleinen nimi",
- "Valid until" : "Kelvollinen",
- "Issued By" : " Myöntänyt",
- "Valid until %s" : "Kelvollinen %s asti",
- "Import root certificate" : "Tuo juurivarmenne",
+ "Get the apps to sync your files" : "Aseta sovellukset synkronoimaan tiedostosi",
+ "Desktop client" : "Työpöytäsovellus",
+ "Android app" : "Android-sovellus",
+ "iOS app" : "iOS-sovellus",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Jos haluat tukea projektia, \n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">auta sovelluskehityksessä</a>\n\t\ttai\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">levitä sanaa</a>!",
+ "Show First Run Wizard again" : "Näytä ensimmäisen käyttökerran avustaja uudelleen",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Kehityksestä on vastannut {communityopen}ownCloud-yhteisö{linkclose}, {githubopen}lähdekoodi{linkclose} on {licenseopen}<abbr title=\"Affero General Public License\">AGPL-lisensoitu</abbr>{linkclose}.",
"Show storage location" : "Näytä tallennustilan sijainti",
"Show last log in" : "Näytä viimeisin sisäänkirjautuminen",
diff --git a/settings/l10n/fr.js b/settings/l10n/fr.js
index 0e67356f169..43a6ef4358e 100644
--- a/settings/l10n/fr.js
+++ b/settings/l10n/fr.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Log",
"Tips & tricks" : "Trucs et astuces",
"Updates" : "Mises à jour",
- "Authentication error" : "Erreur d'authentification",
- "Your full name has been changed." : "Votre nom complet a été modifié.",
- "Unable to change full name" : "Impossible de changer le nom complet",
"Couldn't remove app." : "Impossible de supprimer l'application.",
"Language changed" : "Langue changée",
"Invalid request" : "Requête non valide",
+ "Authentication error" : "Erreur d'authentification",
"Admins can't remove themself from the admin group" : "Les administrateurs ne peuvent pas se retirer eux-mêmes du groupe admin",
"Unable to add user to group %s" : "Impossible d'ajouter l'utilisateur au groupe %s",
"Unable to remove user from group %s" : "Impossible de supprimer l'utilisateur du groupe %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Utilisateur non valable",
"Unable to change mail address" : "Impossible de modifier l'adresse e-mail",
"Email saved" : "E-mail sauvegardé",
+ "Your full name has been changed." : "Votre nom complet a été modifié.",
+ "Unable to change full name" : "Impossible de changer le nom complet",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Êtes-vous vraiment sûr de vouloir ajouter \"{domain}\" comme domaine de confiance ?",
"Add trusted domain" : "Ajouter un domaine de confiance",
"Migration in progress. Please wait until the migration is finished" : "Migration en cours. Veuillez attendre que celle-ci se termine",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "L'application a été activée mais doit être mise à jour. Vous allez être redirigé vers la page des mises à jour dans 5 secondes.",
"App update" : "Mise à jour",
"No apps found for \"{query}\"" : "Aucune application trouvée pour \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Une erreur est survenue. Veuillez fournir un certificat PEM encodé au format ASCII.",
+ "Valid until {date}" : "Valide jusqu'au {date}",
+ "Delete" : "Supprimer",
"An error occurred: {message}" : "Une erreur est survenue : {message}",
"Select a profile picture" : "Selectionnez une photo de profil ",
"Very weak password" : "Mot de passe de très faible sécurité",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Mot de passe de sécurité tout juste acceptable",
"Good password" : "Mot de passe de sécurité suffisante",
"Strong password" : "Mot de passe de forte sécurité",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Une erreur est survenue. Veuillez fournir un certificat PEM encodé au format ASCII.",
- "Valid until {date}" : "Valide jusqu'au {date}",
- "Delete" : "Supprimer",
"Groups" : "Groupes",
"Unable to delete {objName}" : "Impossible de supprimer {objName}",
"Error creating group" : "Erreur lors de la création du groupe",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Un mot de passe valide doit être saisi",
"A valid email must be provided" : "Vous devez fournir une adresse e-mail valide",
"__language_name__" : "Français",
- "Sync clients" : "Clients de synchronisation",
"Personal info" : "Informations personnelles",
- "SSL root certificates" : "Certificats racine SSL",
+ "Sync clients" : "Clients de synchronisation",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tout (erreurs fatales, erreurs, avertissements, informations, debogage)",
"Info, warnings, errors and fatal issues" : "Informations, avertissements, erreurs et erreurs fatales",
"Warnings, errors and fatal issues" : "Avertissements, erreurs et erreurs fatales",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Nous vous recommandons d'installer sur votre système les paquets nécessaires à la prise en charge de l'un des paramètres régionaux suivants : %s",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Si votre installation n'a pas été effectuée à la racine du domaine et qu'elle utilise le cron du système, il peut y avoir des problèmes avec la génération d'URL. Pour les éviter, veuillez configurer l'option \"overwrite.cli.url\" de votre fichier config.php avec le chemin de la racine de votre installation (suggéré : \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "La tâche cron n'a pu s'exécuter via CLI. Ces erreurs techniques sont apparues :",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Le verrouillage transactionnel de fichiers utilise la base de données. Pour obtenir de meilleures performances il est recommandé d'utiliser plutôt memcache. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Consultez les <a target=\"_blank\" href=\"%s\">guides d'installation ↗</a>, et cherchez des erreurs ou avertissements dans <a href=\"#log-section\">les logs</a>.",
"All checks passed." : "Tous les tests ont réussi.",
"Open documentation" : "Voir la documentation",
@@ -188,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Enregistrer les identifiants",
"Test email settings" : "Tester les paramètres e-mail",
"Send email" : "Envoyer un e-mail",
- "Log level" : "Niveau de log",
"Download logfile" : "Télécharger le fichier de journalisation",
"More" : "Plus",
"Less" : "Moins",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "La taille du fichier journal excède 100 Mo. Le télécharger peut prendre un certain temps!",
+ "What to log" : "Ce qu'il faut journaliser",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite est actuellement utilisé comme gestionnaire de base de données. Pour des installations plus volumineuses, nous vous conseillons d'utiliser un autre gestionnaire de base de données.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "L'utilisation de SQLite est particulièrement déconseillée si vous utilisez le client de bureau pour synchroniser vos données.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Pour migrer vers un autre type de base de données, utilisez la ligne de commande : 'occ db:convert-type' ou consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a>.",
@@ -206,17 +204,25 @@ OC.L10N.register(
"Developer documentation" : "Documentation pour développeurs",
"Experimental applications ahead" : "Attention! Applications expérimentales",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Les applications expérimentales n'ont pas fait l'objet de tests de sécurité, sont encore en développement et peuvent être instables. Les installer peut causer des pertes de données ou des failles de sécurité. ",
- "by" : "par",
- "licensed" : "Sous licence",
+ "by %s" : "par %s",
+ "%s-licensed" : "Sous licence %s",
"Documentation:" : "Documentation :",
"User documentation" : "Documentation utilisateur",
"Admin documentation" : "Documentation administrateur",
"Show description …" : "Afficher la description...",
"Hide description …" : "Masquer la description",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Cette app ne spécifie pas de version d'ownCloud minimale requise. Cela provoquera une erreur dans ownCloud 11+",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Cette app ne spécifie pas de version d'ownCloud maximale requise. Cela provoquera une erreur dans ownCloud 11+",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Cette application ne peut être installée à cause de ces dépendances non satisfaites :",
"Enable only for specific groups" : "Activer uniquement pour certains groupes",
"Uninstall App" : "Désinstaller l'application",
"Enable experimental apps" : "Activer les applications expérimentales",
+ "SSL Root Certificates" : "Certificats Racine SSL",
+ "Common Name" : "Nom d'usage",
+ "Valid until" : "Valide jusqu'à",
+ "Issued By" : "Délivré par",
+ "Valid until %s" : "Valide jusqu'à %s",
+ "Import root certificate" : "Importer un certificat racine",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Bonjour,<br><br>Un compte %s a été créé pour vous.<br><br>Votre nom d'utilisateur est : %s<br>Visitez votre compte : <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "À bientôt !",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Bonjour,<br><br>Un compte %s a été créé pour vous.<br><br>Votre nom d'utilisateur est : %s<br>Visitez votre compte : %s<br><br>\n",
@@ -225,40 +231,35 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Suivi de problèmes",
"Commercial support" : "Support commercial",
- "Get the apps to sync your files" : "Obtenez les applications de synchronisation de vos fichiers",
- "Desktop client" : "Client de bureau",
- "Android app" : "Application Android",
- "iOS app" : "Application iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si vous souhaitez apporter votre support au projet\n <a href=\"https://owncloud.org/contribute\"\n target=\"_blank\" rel=\"noreferrer\">rejoignez le développement</a>\n ou\n <a href=\"https://owncloud.org/promote\"\n target=\"_blank\" rel=\"noreferrer\">faites passer le mot</a> !",
- "Show First Run Wizard again" : "Revoir la fenêtre d'accueil affichée lors de votre première connexion",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Vous utilisez <strong>%s</strong> des <strong>%s<strong> disponibles",
- "Password" : "Mot de passe",
- "Unable to change your password" : "Impossible de changer votre mot de passe",
- "Current password" : "Mot de passe actuel",
- "New password" : "Nouveau mot de passe",
- "Change password" : "Changer de mot de passe",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Vous utilisez <strong>%s</strong> des <strong>%s<strong> disponibles",
+ "Profile picture" : "Photo de profil",
+ "Upload new" : "Nouvelle depuis votre ordinateur",
+ "Select from Files" : "Sélectionner depuis les Fichiers",
+ "Remove image" : "Supprimer l'image",
+ "png or jpg, max. 20 MB" : "png ou jpg, max. 20 Mo",
+ "Picture provided by original account" : "Photo fournie par le compte original",
+ "Cancel" : "Annuler",
+ "Choose as profile picture" : "Définir comme image de profil",
"Full name" : "Nom complet",
"No display name set" : "Aucun nom d'affichage configuré",
"Email" : "Adresse e-mail",
"Your email address" : "Votre adresse e-mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Saisissez votre adresse e-mail pour permettre la réinitialisation du mot de passe et la réception des notifications",
+ "For password recovery and notifications" : "Pour la récupération de mot de passe et les notifications",
"No email address set" : "Aucune adresse e-mail configurée",
"You are member of the following groups:" : "Vous êtes membre des groupes suivants :",
- "Profile picture" : "Photo de profil",
- "Upload new" : "Nouvelle depuis votre ordinateur",
- "Select new from Files" : "Nouvelle depuis les Fichiers",
- "Remove image" : "Supprimer l'image",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Format png ou jpg de maximum 20 Mo. Idéalement carrée, mais vous pourrez la recadrer.",
- "Your avatar is provided by your original account." : "Votre avatar est fourni par votre compte original.",
- "Cancel" : "Annuler",
- "Choose as profile image" : "Choisir en tant que photo de profil ",
+ "Password" : "Mot de passe",
+ "Unable to change your password" : "Impossible de changer votre mot de passe",
+ "Current password" : "Mot de passe actuel",
+ "New password" : "Nouveau mot de passe",
+ "Change password" : "Changer de mot de passe",
"Language" : "Langue",
"Help translate" : "Aidez à traduire",
- "Common Name" : "Nom d'usage",
- "Valid until" : "Valide jusqu'à",
- "Issued By" : "Délivré par",
- "Valid until %s" : "Valide jusqu'à %s",
- "Import root certificate" : "Importer un certificat racine",
+ "Get the apps to sync your files" : "Obtenez les applications de synchronisation de vos fichiers",
+ "Desktop client" : "Client de bureau",
+ "Android app" : "Application Android",
+ "iOS app" : "Application iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si vous souhaitez apporter votre support au projet\n <a href=\"https://owncloud.org/contribute\"\n target=\"_blank\" rel=\"noreferrer\">rejoignez le développement</a>\n ou\n <a href=\"https://owncloud.org/promote\"\n target=\"_blank\" rel=\"noreferrer\">faites passer le mot</a> !",
+ "Show First Run Wizard again" : "Revoir la fenêtre d'accueil affichée lors de votre première connexion",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Développé par la {communityopen}communauté ownCloud{linkclose}, le {githubopen}code source{linkclose} est sous licence {licenseopen}<abbr lang=\"en\" title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Afficher l'emplacement du stockage",
"Show last log in" : "Montrer la dernière connexion",
diff --git a/settings/l10n/fr.json b/settings/l10n/fr.json
index c3e1d6eb176..9b5fbd02401 100644
--- a/settings/l10n/fr.json
+++ b/settings/l10n/fr.json
@@ -10,12 +10,10 @@
"Log" : "Log",
"Tips & tricks" : "Trucs et astuces",
"Updates" : "Mises à jour",
- "Authentication error" : "Erreur d'authentification",
- "Your full name has been changed." : "Votre nom complet a été modifié.",
- "Unable to change full name" : "Impossible de changer le nom complet",
"Couldn't remove app." : "Impossible de supprimer l'application.",
"Language changed" : "Langue changée",
"Invalid request" : "Requête non valide",
+ "Authentication error" : "Erreur d'authentification",
"Admins can't remove themself from the admin group" : "Les administrateurs ne peuvent pas se retirer eux-mêmes du groupe admin",
"Unable to add user to group %s" : "Impossible d'ajouter l'utilisateur au groupe %s",
"Unable to remove user from group %s" : "Impossible de supprimer l'utilisateur du groupe %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Utilisateur non valable",
"Unable to change mail address" : "Impossible de modifier l'adresse e-mail",
"Email saved" : "E-mail sauvegardé",
+ "Your full name has been changed." : "Votre nom complet a été modifié.",
+ "Unable to change full name" : "Impossible de changer le nom complet",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Êtes-vous vraiment sûr de vouloir ajouter \"{domain}\" comme domaine de confiance ?",
"Add trusted domain" : "Ajouter un domaine de confiance",
"Migration in progress. Please wait until the migration is finished" : "Migration en cours. Veuillez attendre que celle-ci se termine",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "L'application a été activée mais doit être mise à jour. Vous allez être redirigé vers la page des mises à jour dans 5 secondes.",
"App update" : "Mise à jour",
"No apps found for \"{query}\"" : "Aucune application trouvée pour \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Une erreur est survenue. Veuillez fournir un certificat PEM encodé au format ASCII.",
+ "Valid until {date}" : "Valide jusqu'au {date}",
+ "Delete" : "Supprimer",
"An error occurred: {message}" : "Une erreur est survenue : {message}",
"Select a profile picture" : "Selectionnez une photo de profil ",
"Very weak password" : "Mot de passe de très faible sécurité",
@@ -86,9 +89,6 @@
"So-so password" : "Mot de passe de sécurité tout juste acceptable",
"Good password" : "Mot de passe de sécurité suffisante",
"Strong password" : "Mot de passe de forte sécurité",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Une erreur est survenue. Veuillez fournir un certificat PEM encodé au format ASCII.",
- "Valid until {date}" : "Valide jusqu'au {date}",
- "Delete" : "Supprimer",
"Groups" : "Groupes",
"Unable to delete {objName}" : "Impossible de supprimer {objName}",
"Error creating group" : "Erreur lors de la création du groupe",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Un mot de passe valide doit être saisi",
"A valid email must be provided" : "Vous devez fournir une adresse e-mail valide",
"__language_name__" : "Français",
- "Sync clients" : "Clients de synchronisation",
"Personal info" : "Informations personnelles",
- "SSL root certificates" : "Certificats racine SSL",
+ "Sync clients" : "Clients de synchronisation",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tout (erreurs fatales, erreurs, avertissements, informations, debogage)",
"Info, warnings, errors and fatal issues" : "Informations, avertissements, erreurs et erreurs fatales",
"Warnings, errors and fatal issues" : "Avertissements, erreurs et erreurs fatales",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Nous vous recommandons d'installer sur votre système les paquets nécessaires à la prise en charge de l'un des paramètres régionaux suivants : %s",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Si votre installation n'a pas été effectuée à la racine du domaine et qu'elle utilise le cron du système, il peut y avoir des problèmes avec la génération d'URL. Pour les éviter, veuillez configurer l'option \"overwrite.cli.url\" de votre fichier config.php avec le chemin de la racine de votre installation (suggéré : \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "La tâche cron n'a pu s'exécuter via CLI. Ces erreurs techniques sont apparues :",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Le verrouillage transactionnel de fichiers utilise la base de données. Pour obtenir de meilleures performances il est recommandé d'utiliser plutôt memcache. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Consultez les <a target=\"_blank\" href=\"%s\">guides d'installation ↗</a>, et cherchez des erreurs ou avertissements dans <a href=\"#log-section\">les logs</a>.",
"All checks passed." : "Tous les tests ont réussi.",
"Open documentation" : "Voir la documentation",
@@ -186,11 +184,11 @@
"Store credentials" : "Enregistrer les identifiants",
"Test email settings" : "Tester les paramètres e-mail",
"Send email" : "Envoyer un e-mail",
- "Log level" : "Niveau de log",
"Download logfile" : "Télécharger le fichier de journalisation",
"More" : "Plus",
"Less" : "Moins",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "La taille du fichier journal excède 100 Mo. Le télécharger peut prendre un certain temps!",
+ "What to log" : "Ce qu'il faut journaliser",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite est actuellement utilisé comme gestionnaire de base de données. Pour des installations plus volumineuses, nous vous conseillons d'utiliser un autre gestionnaire de base de données.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "L'utilisation de SQLite est particulièrement déconseillée si vous utilisez le client de bureau pour synchroniser vos données.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Pour migrer vers un autre type de base de données, utilisez la ligne de commande : 'occ db:convert-type' ou consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a>.",
@@ -204,17 +202,25 @@
"Developer documentation" : "Documentation pour développeurs",
"Experimental applications ahead" : "Attention! Applications expérimentales",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Les applications expérimentales n'ont pas fait l'objet de tests de sécurité, sont encore en développement et peuvent être instables. Les installer peut causer des pertes de données ou des failles de sécurité. ",
- "by" : "par",
- "licensed" : "Sous licence",
+ "by %s" : "par %s",
+ "%s-licensed" : "Sous licence %s",
"Documentation:" : "Documentation :",
"User documentation" : "Documentation utilisateur",
"Admin documentation" : "Documentation administrateur",
"Show description …" : "Afficher la description...",
"Hide description …" : "Masquer la description",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Cette app ne spécifie pas de version d'ownCloud minimale requise. Cela provoquera une erreur dans ownCloud 11+",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Cette app ne spécifie pas de version d'ownCloud maximale requise. Cela provoquera une erreur dans ownCloud 11+",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Cette application ne peut être installée à cause de ces dépendances non satisfaites :",
"Enable only for specific groups" : "Activer uniquement pour certains groupes",
"Uninstall App" : "Désinstaller l'application",
"Enable experimental apps" : "Activer les applications expérimentales",
+ "SSL Root Certificates" : "Certificats Racine SSL",
+ "Common Name" : "Nom d'usage",
+ "Valid until" : "Valide jusqu'à",
+ "Issued By" : "Délivré par",
+ "Valid until %s" : "Valide jusqu'à %s",
+ "Import root certificate" : "Importer un certificat racine",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Bonjour,<br><br>Un compte %s a été créé pour vous.<br><br>Votre nom d'utilisateur est : %s<br>Visitez votre compte : <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "À bientôt !",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Bonjour,<br><br>Un compte %s a été créé pour vous.<br><br>Votre nom d'utilisateur est : %s<br>Visitez votre compte : %s<br><br>\n",
@@ -223,40 +229,35 @@
"Forum" : "Forum",
"Issue tracker" : "Suivi de problèmes",
"Commercial support" : "Support commercial",
- "Get the apps to sync your files" : "Obtenez les applications de synchronisation de vos fichiers",
- "Desktop client" : "Client de bureau",
- "Android app" : "Application Android",
- "iOS app" : "Application iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si vous souhaitez apporter votre support au projet\n <a href=\"https://owncloud.org/contribute\"\n target=\"_blank\" rel=\"noreferrer\">rejoignez le développement</a>\n ou\n <a href=\"https://owncloud.org/promote\"\n target=\"_blank\" rel=\"noreferrer\">faites passer le mot</a> !",
- "Show First Run Wizard again" : "Revoir la fenêtre d'accueil affichée lors de votre première connexion",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Vous utilisez <strong>%s</strong> des <strong>%s<strong> disponibles",
- "Password" : "Mot de passe",
- "Unable to change your password" : "Impossible de changer votre mot de passe",
- "Current password" : "Mot de passe actuel",
- "New password" : "Nouveau mot de passe",
- "Change password" : "Changer de mot de passe",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Vous utilisez <strong>%s</strong> des <strong>%s<strong> disponibles",
+ "Profile picture" : "Photo de profil",
+ "Upload new" : "Nouvelle depuis votre ordinateur",
+ "Select from Files" : "Sélectionner depuis les Fichiers",
+ "Remove image" : "Supprimer l'image",
+ "png or jpg, max. 20 MB" : "png ou jpg, max. 20 Mo",
+ "Picture provided by original account" : "Photo fournie par le compte original",
+ "Cancel" : "Annuler",
+ "Choose as profile picture" : "Définir comme image de profil",
"Full name" : "Nom complet",
"No display name set" : "Aucun nom d'affichage configuré",
"Email" : "Adresse e-mail",
"Your email address" : "Votre adresse e-mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Saisissez votre adresse e-mail pour permettre la réinitialisation du mot de passe et la réception des notifications",
+ "For password recovery and notifications" : "Pour la récupération de mot de passe et les notifications",
"No email address set" : "Aucune adresse e-mail configurée",
"You are member of the following groups:" : "Vous êtes membre des groupes suivants :",
- "Profile picture" : "Photo de profil",
- "Upload new" : "Nouvelle depuis votre ordinateur",
- "Select new from Files" : "Nouvelle depuis les Fichiers",
- "Remove image" : "Supprimer l'image",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Format png ou jpg de maximum 20 Mo. Idéalement carrée, mais vous pourrez la recadrer.",
- "Your avatar is provided by your original account." : "Votre avatar est fourni par votre compte original.",
- "Cancel" : "Annuler",
- "Choose as profile image" : "Choisir en tant que photo de profil ",
+ "Password" : "Mot de passe",
+ "Unable to change your password" : "Impossible de changer votre mot de passe",
+ "Current password" : "Mot de passe actuel",
+ "New password" : "Nouveau mot de passe",
+ "Change password" : "Changer de mot de passe",
"Language" : "Langue",
"Help translate" : "Aidez à traduire",
- "Common Name" : "Nom d'usage",
- "Valid until" : "Valide jusqu'à",
- "Issued By" : "Délivré par",
- "Valid until %s" : "Valide jusqu'à %s",
- "Import root certificate" : "Importer un certificat racine",
+ "Get the apps to sync your files" : "Obtenez les applications de synchronisation de vos fichiers",
+ "Desktop client" : "Client de bureau",
+ "Android app" : "Application Android",
+ "iOS app" : "Application iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Si vous souhaitez apporter votre support au projet\n <a href=\"https://owncloud.org/contribute\"\n target=\"_blank\" rel=\"noreferrer\">rejoignez le développement</a>\n ou\n <a href=\"https://owncloud.org/promote\"\n target=\"_blank\" rel=\"noreferrer\">faites passer le mot</a> !",
+ "Show First Run Wizard again" : "Revoir la fenêtre d'accueil affichée lors de votre première connexion",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Développé par la {communityopen}communauté ownCloud{linkclose}, le {githubopen}code source{linkclose} est sous licence {licenseopen}<abbr lang=\"en\" title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Afficher l'emplacement du stockage",
"Show last log in" : "Montrer la dernière connexion",
diff --git a/settings/l10n/gl.js b/settings/l10n/gl.js
index 0c03a5b06b3..64e807b9f51 100644
--- a/settings/l10n/gl.js
+++ b/settings/l10n/gl.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Rexistro",
"Tips & tricks" : "Trucos e consellos",
"Updates" : "Actualizacións",
- "Authentication error" : "Produciuse un erro de autenticación",
- "Your full name has been changed." : "O seu nome completo foi cambiado",
- "Unable to change full name" : "Non é posíbel cambiar o nome completo",
"Couldn't remove app." : "Non foi posíbel retirar a aplicación.",
"Language changed" : "O idioma cambiou",
"Invalid request" : "Petición incorrecta",
+ "Authentication error" : "Produciuse un erro de autenticación",
"Admins can't remove themself from the admin group" : "Os administradores non poden eliminarse a si mesmos do grupo admin",
"Unable to add user to group %s" : "Non é posíbel engadir o usuario ao grupo %s",
"Unable to remove user from group %s" : "Non é posíbel eliminar o usuario do grupo %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Usuario incorrecto",
"Unable to change mail address" : "Non é posíbel cambiar o enderezo de correo.",
"Email saved" : "Correo gardado",
+ "Your full name has been changed." : "O seu nome completo foi cambiado",
+ "Unable to change full name" : "Non é posíbel cambiar o nome completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Confirma que quere engadir «{domain}» como dominio de confianza?",
"Add trusted domain" : "Engadir dominio de confianza",
"Migration in progress. Please wait until the migration is finished" : "A migración está en proceso. Agarde a que remate.",
@@ -78,6 +78,9 @@ OC.L10N.register(
"Uninstalling ...." : "Desinstalando ...",
"Error while uninstalling app" : "Produciuse un erro ao desinstalar o aplicatvo",
"Uninstall" : "Desinstalar",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Produciuse un erro. Envíe un certificado PEM codificado en ASCII.",
+ "Valid until {date}" : "Válido ata {date}",
+ "Delete" : "Eliminar",
"An error occurred: {message}" : "Produciuse un erro: {message}",
"Select a profile picture" : "Seleccione unha imaxe para o perfil",
"Very weak password" : "Contrasinal moi feble",
@@ -85,9 +88,6 @@ OC.L10N.register(
"So-so password" : "Contrasinal non moi aló",
"Good password" : "Bo contrasinal",
"Strong password" : "Contrasinal forte",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Produciuse un erro. Envíe un certificado PEM codificado en ASCII.",
- "Valid until {date}" : "Válido ata {date}",
- "Delete" : "Eliminar",
"Groups" : "Grupos",
"Unable to delete {objName}" : "Non é posíbel eliminar {objName}",
"Error creating group" : "Produciuse un erro ao crear o grupo",
@@ -104,9 +104,8 @@ OC.L10N.register(
"A valid password must be provided" : "Debe fornecer un contrasinal",
"A valid email must be provided" : "Ten que fornecer un correo funcional",
"__language_name__" : "Galego",
- "Sync clients" : "Clientes de sincronización",
"Personal info" : "Información persoal",
- "SSL root certificates" : "Certificados raíz SSL",
+ "Sync clients" : "Clientes de sincronización",
"Everything (fatal issues, errors, warnings, info, debug)" : "Todo (incidencias críticas, erros, avisos, información, depuración)",
"Info, warnings, errors and fatal issues" : "Información, avisos, erros e incidencias críticas",
"Warnings, errors and fatal issues" : "Avisos, erros e incidencias críticas",
@@ -174,7 +173,6 @@ OC.L10N.register(
"Store credentials" : "Gardar as credenciais",
"Test email settings" : "Correo de proba dos axustes",
"Send email" : "Enviar o correo",
- "Log level" : "Nivel de rexistro",
"Download logfile" : "Descargar o ficheiro do rexistro",
"More" : "Máis",
"Less" : "Menos",
@@ -192,8 +190,6 @@ OC.L10N.register(
"Developer documentation" : "Documentación do desenvolvedor",
"Experimental applications ahead" : "Ante as aplicacións experimentais",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "As aplicacións experimentais, novas ou coñecidas por ser inestábeis e en forte desenvolvemento, non se lles fan comprobacións de seguridade. A súa instalación pode provocar a perda de datos o violacións de seguridade.",
- "by" : "por",
- "licensed" : "licencidado",
"Documentation:" : "Documentación:",
"User documentation" : "Documentación do usuario",
"Admin documentation" : "Documentación do administrador",
@@ -203,6 +199,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Activar só para grupos específicos",
"Uninstall App" : "Desinstalar unha aplicación",
"Enable experimental apps" : "Activar as aplicacións experimentais",
+ "Common Name" : "Nome común",
+ "Valid until" : "Válido ata",
+ "Issued By" : "Fornecido por",
+ "Valid until %s" : "Válido ata %s",
+ "Import root certificate" : "Importar o certificado raíz",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Ola,<br><br>Só facerlle saber que dispón da conta %s.<br><br>O seu nome de usuario: %s<br>Para acceder a ela: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Saúdos!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ola,\n\nSó facerlle saber que dispón da conta %s.\n\nO seu nome de usuario: %s\nPara acceder a ela: %s\n",
@@ -211,40 +212,29 @@ OC.L10N.register(
"Forum" : "Foro",
"Issue tracker" : "Seguimento de incidencias",
"Commercial support" : "Asistencia comercial",
- "Get the apps to sync your files" : "Obteña as aplicacións para sincronizar os seus ficheiros",
- "Desktop client" : "Cliente de escritorio",
- "Android app" : "Aplicación Android",
- "iOS app" : "Aplicación iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se quere axudar ao proxecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">únase ao desenvolvemento</a>\n\t\tou\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">espalle a nova</a>!",
- "Show First Run Wizard again" : "Amosar o axudante da primeira execución outra vez",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ten en uso <strong>%s</strong> do total dispoñíbel de <strong>%s</strong>",
- "Password" : "Contrasinal",
- "Unable to change your password" : "Non é posíbel cambiar o seu contrasinal",
- "Current password" : "Contrasinal actual",
- "New password" : "Novo contrasinal",
- "Change password" : "Cambiar o contrasinal",
+ "Profile picture" : "Imaxe do perfil",
+ "Upload new" : "Novo envío",
+ "Remove image" : "Retirar a imaxe",
+ "Cancel" : "Cancelar",
"Full name" : "Nome completo",
"No display name set" : "Sen nome visíbel estabelecido",
"Email" : "Correo",
"Your email address" : "O seu enderezo de correo",
- "Fill in an email address to enable password recovery and receive notifications" : "Escriba un enderezo de correo para permitir a recuperación de contrasinais e recibir notificacións",
"No email address set" : "Non hai un enderezo de correo definido",
"You are member of the following groups:" : "Vostede é membro dos seguintes grupos:",
- "Profile picture" : "Imaxe do perfil",
- "Upload new" : "Novo envío",
- "Select new from Files" : "Seleccionar outra nova desde Ficheiros",
- "Remove image" : "Retirar a imaxe",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Calquera png ou jpg. É preferíbel que sexa cadrada, mais poderá recortala. O ficheiro non pode exceder do tamaño máximo de 20MB.",
- "Your avatar is provided by your original account." : "O seu avatar é fornecido pola súa conta orixinal.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Escolla unha imaxe para o perfil",
+ "Password" : "Contrasinal",
+ "Unable to change your password" : "Non é posíbel cambiar o seu contrasinal",
+ "Current password" : "Contrasinal actual",
+ "New password" : "Novo contrasinal",
+ "Change password" : "Cambiar o contrasinal",
"Language" : "Idioma",
"Help translate" : "Axude na tradución",
- "Common Name" : "Nome común",
- "Valid until" : "Válido ata",
- "Issued By" : "Fornecido por",
- "Valid until %s" : "Válido ata %s",
- "Import root certificate" : "Importar o certificado raíz",
+ "Get the apps to sync your files" : "Obteña as aplicacións para sincronizar os seus ficheiros",
+ "Desktop client" : "Cliente de escritorio",
+ "Android app" : "Aplicación Android",
+ "iOS app" : "Aplicación iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se quere axudar ao proxecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">únase ao desenvolvemento</a>\n\t\tou\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">espalle a nova</a>!",
+ "Show First Run Wizard again" : "Amosar o axudante da primeira execución outra vez",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desenvolvido pola {communityopen}comunidade ownCloud{linkclose}, o {githubopen}código fonte{linkclose} está licenciado baixo a {licenseopen}<abbr title=\"Licencia Pública Xeral Affero\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Amosar a localización do almacenamento",
"Show last log in" : "Amosar a última conexión",
diff --git a/settings/l10n/gl.json b/settings/l10n/gl.json
index f2e924ac772..ced735b4d64 100644
--- a/settings/l10n/gl.json
+++ b/settings/l10n/gl.json
@@ -10,12 +10,10 @@
"Log" : "Rexistro",
"Tips & tricks" : "Trucos e consellos",
"Updates" : "Actualizacións",
- "Authentication error" : "Produciuse un erro de autenticación",
- "Your full name has been changed." : "O seu nome completo foi cambiado",
- "Unable to change full name" : "Non é posíbel cambiar o nome completo",
"Couldn't remove app." : "Non foi posíbel retirar a aplicación.",
"Language changed" : "O idioma cambiou",
"Invalid request" : "Petición incorrecta",
+ "Authentication error" : "Produciuse un erro de autenticación",
"Admins can't remove themself from the admin group" : "Os administradores non poden eliminarse a si mesmos do grupo admin",
"Unable to add user to group %s" : "Non é posíbel engadir o usuario ao grupo %s",
"Unable to remove user from group %s" : "Non é posíbel eliminar o usuario do grupo %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Usuario incorrecto",
"Unable to change mail address" : "Non é posíbel cambiar o enderezo de correo.",
"Email saved" : "Correo gardado",
+ "Your full name has been changed." : "O seu nome completo foi cambiado",
+ "Unable to change full name" : "Non é posíbel cambiar o nome completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Confirma que quere engadir «{domain}» como dominio de confianza?",
"Add trusted domain" : "Engadir dominio de confianza",
"Migration in progress. Please wait until the migration is finished" : "A migración está en proceso. Agarde a que remate.",
@@ -76,6 +76,9 @@
"Uninstalling ...." : "Desinstalando ...",
"Error while uninstalling app" : "Produciuse un erro ao desinstalar o aplicatvo",
"Uninstall" : "Desinstalar",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Produciuse un erro. Envíe un certificado PEM codificado en ASCII.",
+ "Valid until {date}" : "Válido ata {date}",
+ "Delete" : "Eliminar",
"An error occurred: {message}" : "Produciuse un erro: {message}",
"Select a profile picture" : "Seleccione unha imaxe para o perfil",
"Very weak password" : "Contrasinal moi feble",
@@ -83,9 +86,6 @@
"So-so password" : "Contrasinal non moi aló",
"Good password" : "Bo contrasinal",
"Strong password" : "Contrasinal forte",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Produciuse un erro. Envíe un certificado PEM codificado en ASCII.",
- "Valid until {date}" : "Válido ata {date}",
- "Delete" : "Eliminar",
"Groups" : "Grupos",
"Unable to delete {objName}" : "Non é posíbel eliminar {objName}",
"Error creating group" : "Produciuse un erro ao crear o grupo",
@@ -102,9 +102,8 @@
"A valid password must be provided" : "Debe fornecer un contrasinal",
"A valid email must be provided" : "Ten que fornecer un correo funcional",
"__language_name__" : "Galego",
- "Sync clients" : "Clientes de sincronización",
"Personal info" : "Información persoal",
- "SSL root certificates" : "Certificados raíz SSL",
+ "Sync clients" : "Clientes de sincronización",
"Everything (fatal issues, errors, warnings, info, debug)" : "Todo (incidencias críticas, erros, avisos, información, depuración)",
"Info, warnings, errors and fatal issues" : "Información, avisos, erros e incidencias críticas",
"Warnings, errors and fatal issues" : "Avisos, erros e incidencias críticas",
@@ -172,7 +171,6 @@
"Store credentials" : "Gardar as credenciais",
"Test email settings" : "Correo de proba dos axustes",
"Send email" : "Enviar o correo",
- "Log level" : "Nivel de rexistro",
"Download logfile" : "Descargar o ficheiro do rexistro",
"More" : "Máis",
"Less" : "Menos",
@@ -190,8 +188,6 @@
"Developer documentation" : "Documentación do desenvolvedor",
"Experimental applications ahead" : "Ante as aplicacións experimentais",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "As aplicacións experimentais, novas ou coñecidas por ser inestábeis e en forte desenvolvemento, non se lles fan comprobacións de seguridade. A súa instalación pode provocar a perda de datos o violacións de seguridade.",
- "by" : "por",
- "licensed" : "licencidado",
"Documentation:" : "Documentación:",
"User documentation" : "Documentación do usuario",
"Admin documentation" : "Documentación do administrador",
@@ -201,6 +197,11 @@
"Enable only for specific groups" : "Activar só para grupos específicos",
"Uninstall App" : "Desinstalar unha aplicación",
"Enable experimental apps" : "Activar as aplicacións experimentais",
+ "Common Name" : "Nome común",
+ "Valid until" : "Válido ata",
+ "Issued By" : "Fornecido por",
+ "Valid until %s" : "Válido ata %s",
+ "Import root certificate" : "Importar o certificado raíz",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Ola,<br><br>Só facerlle saber que dispón da conta %s.<br><br>O seu nome de usuario: %s<br>Para acceder a ela: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Saúdos!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ola,\n\nSó facerlle saber que dispón da conta %s.\n\nO seu nome de usuario: %s\nPara acceder a ela: %s\n",
@@ -209,40 +210,29 @@
"Forum" : "Foro",
"Issue tracker" : "Seguimento de incidencias",
"Commercial support" : "Asistencia comercial",
- "Get the apps to sync your files" : "Obteña as aplicacións para sincronizar os seus ficheiros",
- "Desktop client" : "Cliente de escritorio",
- "Android app" : "Aplicación Android",
- "iOS app" : "Aplicación iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se quere axudar ao proxecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">únase ao desenvolvemento</a>\n\t\tou\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">espalle a nova</a>!",
- "Show First Run Wizard again" : "Amosar o axudante da primeira execución outra vez",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ten en uso <strong>%s</strong> do total dispoñíbel de <strong>%s</strong>",
- "Password" : "Contrasinal",
- "Unable to change your password" : "Non é posíbel cambiar o seu contrasinal",
- "Current password" : "Contrasinal actual",
- "New password" : "Novo contrasinal",
- "Change password" : "Cambiar o contrasinal",
+ "Profile picture" : "Imaxe do perfil",
+ "Upload new" : "Novo envío",
+ "Remove image" : "Retirar a imaxe",
+ "Cancel" : "Cancelar",
"Full name" : "Nome completo",
"No display name set" : "Sen nome visíbel estabelecido",
"Email" : "Correo",
"Your email address" : "O seu enderezo de correo",
- "Fill in an email address to enable password recovery and receive notifications" : "Escriba un enderezo de correo para permitir a recuperación de contrasinais e recibir notificacións",
"No email address set" : "Non hai un enderezo de correo definido",
"You are member of the following groups:" : "Vostede é membro dos seguintes grupos:",
- "Profile picture" : "Imaxe do perfil",
- "Upload new" : "Novo envío",
- "Select new from Files" : "Seleccionar outra nova desde Ficheiros",
- "Remove image" : "Retirar a imaxe",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Calquera png ou jpg. É preferíbel que sexa cadrada, mais poderá recortala. O ficheiro non pode exceder do tamaño máximo de 20MB.",
- "Your avatar is provided by your original account." : "O seu avatar é fornecido pola súa conta orixinal.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Escolla unha imaxe para o perfil",
+ "Password" : "Contrasinal",
+ "Unable to change your password" : "Non é posíbel cambiar o seu contrasinal",
+ "Current password" : "Contrasinal actual",
+ "New password" : "Novo contrasinal",
+ "Change password" : "Cambiar o contrasinal",
"Language" : "Idioma",
"Help translate" : "Axude na tradución",
- "Common Name" : "Nome común",
- "Valid until" : "Válido ata",
- "Issued By" : "Fornecido por",
- "Valid until %s" : "Válido ata %s",
- "Import root certificate" : "Importar o certificado raíz",
+ "Get the apps to sync your files" : "Obteña as aplicacións para sincronizar os seus ficheiros",
+ "Desktop client" : "Cliente de escritorio",
+ "Android app" : "Aplicación Android",
+ "iOS app" : "Aplicación iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se quere axudar ao proxecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">únase ao desenvolvemento</a>\n\t\tou\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">espalle a nova</a>!",
+ "Show First Run Wizard again" : "Amosar o axudante da primeira execución outra vez",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desenvolvido pola {communityopen}comunidade ownCloud{linkclose}, o {githubopen}código fonte{linkclose} está licenciado baixo a {licenseopen}<abbr title=\"Licencia Pública Xeral Affero\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Amosar a localización do almacenamento",
"Show last log in" : "Amosar a última conexión",
diff --git a/settings/l10n/he.js b/settings/l10n/he.js
index 435f04cedd0..78abe0c4d3d 100644
--- a/settings/l10n/he.js
+++ b/settings/l10n/he.js
@@ -1,75 +1,293 @@
OC.L10N.register(
"settings",
{
+ "APCu" : "APCu",
+ "Redis" : "Redis",
+ "Security & setup warnings" : "הזהרות אבטחה והתקנה",
"Sharing" : "שיתוף",
+ "Server-side encryption" : "הצפנת צד שרת",
"External Storage" : "אחסון חיצוני",
"Cron" : "Cron",
+ "Email server" : "שרת דואר אלקטרוני",
"Log" : "יומן",
- "Authentication error" : "שגיאת הזדהות",
+ "Tips & tricks" : "עצות ותחבולות",
+ "Updates" : "עדכונים",
+ "Couldn't remove app." : "לא ניתן להסיר את היישום.",
"Language changed" : "שפה השתנתה",
"Invalid request" : "בקשה לא חוקית",
+ "Authentication error" : "שגיאת הזדהות",
"Admins can't remove themself from the admin group" : "מנהלים לא יכולים להסיר את עצמם מקבוצת המנהלים",
"Unable to add user to group %s" : "לא ניתן להוסיף משתמש לקבוצה %s",
"Unable to remove user from group %s" : "לא ניתן להסיר משתמש מהקבוצה %s",
"Couldn't update app." : "לא ניתן לעדכן את היישום.",
+ "Wrong password" : "סיסמא שגוייה",
+ "No user supplied" : "לא סופק שם משתמש",
+ "Please provide an admin recovery password, otherwise all user data will be lost" : "יש לספק את סיסמת המנהל לשחזור, אחרת כל מידע המשתמש יאבד",
+ "Wrong admin recovery password. Please check the password and try again." : "סיסמת המנהל לשחזור שגוייה. יש לבדוק את הסיסמא ולנסות שוב.",
+ "Backend doesn't support password change, but the user's encryption key was successfully updated." : "צד אחורי לא תומך בשינוי סיסמא, אך מפתח הצפנה של המשתמש עודכנה בהצלחה.",
+ "Unable to change password" : "לא ניתן לשנות את הסיסמא",
+ "Enabled" : "מופעל",
+ "Not enabled" : "לא מופעל",
+ "installing and updating apps via the app store or Federated Cloud Sharing" : "התקנה ועדכון היישום דרך חנות היישומים או ענן שיתוף מאוגד",
+ "Federated Cloud Sharing" : "ענן שיתוף מאוגד",
+ "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL משתמש בגרסה %s ישנה (%s). יש לעדכן את מערכת ההפעלה או שתכונות כדוגמת %s לא יעבדו באופן מהימן.",
+ "A problem occurred, please check your log files (Error: %s)" : "אירעה בעיה, יש לבדוק את לוג הקבצים (שגיאה: %s)",
+ "Migration Completed" : "המרה הושלמה",
+ "Group already exists." : "קבוצה כבר קיימת.",
+ "Unable to add group." : "לא ניתן להוסיף קבוצה.",
+ "Unable to delete group." : "לא ניתן למחוק קבוצה.",
+ "log-level out of allowed range" : "גודל הלוג מעבר לרמה המותרת",
"Saved" : "נשמר",
- "Email sent" : "הודעת הדוא״ל נשלחה",
- "Email saved" : "הדוא״ל נשמר",
+ "test email settings" : "בדיקת הגדרות דואר אלקטרוני",
+ "A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "בעיה אירעה בשליחת הדואר האלקטרוני. יש לשנות את ההגדרות שלך. (שגיאה: %s)",
+ "Email sent" : "הודעת הדואר האלקטרוני נשלחה",
+ "You need to set your user email before being able to send test emails." : "יש להגדיר כתובת דואר אלקטרוני לפני שניתן יהיה לשלוח דואר אלקטרוני לבדיקה.",
+ "Invalid mail address" : "כתובת דואר אלקטרוני לא חוקית",
+ "A user with that name already exists." : "משתמש בשם זה כבר קיים.",
+ "Unable to create user." : "לא ניתן ליצור משתמש.",
+ "Your %s account was created" : "חשבון %s שלך נוצר",
+ "Unable to delete user." : "לא ניתן למחוק משתמש.",
+ "Forbidden" : "חסום",
+ "Invalid user" : "שם משתמש לא חוקי",
+ "Unable to change mail address" : "לא ניתן לשנות כתובת דואר אלקטרוני",
+ "Email saved" : "הדואר האלקטרוני נשמר",
+ "Your full name has been changed." : "השם המלא שלך הוחלף",
+ "Unable to change full name" : "לא ניתן לשנות שם מלא",
+ "Are you really sure you want add \"{domain}\" as trusted domain?" : "האם באמת להוסיף \"{domain}\" כשם מתחם מהימן?",
+ "Add trusted domain" : "הוספת שם מתחם מהימן",
+ "Migration in progress. Please wait until the migration is finished" : "המרה בביצוע. יש להמתין עד סיום ההמרה",
+ "Migration started …" : "המרה החלה...",
+ "Sending..." : "שולח...",
+ "Official" : "רישמי",
+ "Approved" : "מאושר",
+ "Experimental" : "ניסיוני",
"All" : "הכל",
+ "No apps found for your version" : "לא נמצאו יישומים לגרסה שלך",
+ "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "יישומים רישמיים מפותחים על ידי קהילת ownCloud. הם מציעים פונקיונאליות, התאמה ל- ownCloud ומוכנים לשימוש כבד.",
+ "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "יישומים מאושרים מפותחים על ידי מפתחים מהימנים ועברו בדיקת הבטחה ראשונית. הם נשמרים באופן פעיל במאגר קוד פתוח והמתזקים שלהם מייעדים אותם לשימוש מזדמן ורגיל.",
+ "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "יישום זה לא נבדק לבעיות אבטחה והוא חדש או ידוע כלא יציב. התקנת יישום זה הנה על אחריותך בלבד.",
+ "Update to %s" : "עדכון ל- %s",
"Please wait...." : "נא להמתין…",
- "Disable" : "בטל",
+ "Error while disabling app" : "אירעה שגיאה בעת נטרול היישום",
+ "Disable" : "ניטרול",
"Enable" : "הפעלה",
+ "Error while enabling app" : "שגיאה בעת הפעלת יישום",
"Updating...." : "מתבצע עדכון…",
"Error while updating app" : "אירעה שגיאה בעת עדכון היישום",
"Updated" : "מעודכן",
+ "Uninstalling ...." : "מסיר התקנה...",
+ "Error while uninstalling app" : "אירעה שגיאה בעת הסרת היישום",
+ "Uninstall" : "הסרת התקנה",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "היישום הופעל אך יש לעדכן אותו. בעוד 5 שניות הדף ינותב לעמוד העדכון.",
+ "App update" : "עדכון יישום",
+ "No apps found for \"{query}\"" : "לא נמצא יישום עבור \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "אירעה שגיאה. יש להעלות תעודת ASCII-encoded PEM.",
+ "Valid until {date}" : "בתוקף עד ל- {date}",
"Delete" : "מחיקה",
+ "An error occurred: {message}" : "אירעה שגיאה: {message}",
+ "Select a profile picture" : "יש לבחור תמונת פרופיל",
+ "Very weak password" : "סיסמא מאוד חלשה",
+ "Weak password" : "סיסמא חלשה",
+ "So-so password" : "סיסמא ככה-ככה",
+ "Good password" : "סיסמא טובה",
+ "Strong password" : "סיסמא חזקה",
"Groups" : "קבוצות",
+ "Unable to delete {objName}" : "לא ניתן למחיקה {objName}",
+ "Error creating group" : "שגיאה בעת יצירת קבוצה",
+ "A valid group name must be provided" : "יש לספק שם קבוצה תקני",
+ "deleted {groupName}" : "נמחק {groupName}",
"undo" : "ביטול",
+ "no group" : "אין קבוצה",
"never" : "לעולם לא",
+ "deleted {userName}" : "נמחק {userName}",
"add group" : "הוספת קבוצה",
+ "Changing the password will result in data loss, because data recovery is not available for this user" : "שינוי הסיסמא יגרום איבוד מידע, וזאת בגלל ששחזור מידע אינו זמין למשתמש זה",
"A valid username must be provided" : "יש לספק שם משתמש תקני",
"Error creating user" : "יצירת המשתמש נכשלה",
- "A valid password must be provided" : "יש לספק ססמה תקנית",
+ "A valid password must be provided" : "יש לספק סיסמא תקנית",
+ "A valid email must be provided" : "יש לספק כתובת דואר אלקטרוני תקנית",
"__language_name__" : "עברית",
- "SSL root certificates" : "שורש אישורי אבטחת SSL ",
+ "Personal info" : "מידע אישי",
+ "Sync clients" : "סנכרון לקוחות",
+ "Everything (fatal issues, errors, warnings, info, debug)" : "הכול (נושאים חמורים, שגיאות, אזהרות, מידע, ניפוי שגיאות)",
+ "Info, warnings, errors and fatal issues" : "מידע, אזהרות, שגיאות ונושאים חמורים",
+ "Warnings, errors and fatal issues" : "אזהרות, שגיאות ונושאים חמורים",
+ "Errors and fatal issues" : "שגיאות ונושאים חמורים",
+ "Fatal issues only" : "נושאים חמורים בלבד",
"None" : "כלום",
"Login" : "התחברות",
+ "Plain" : "רגיל",
+ "NT LAN Manager" : "מנהל רשת NT",
+ "SSL" : "SSL",
+ "TLS" : "TLS",
+ "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response.",
+ "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "יש לבדוק את <a target=\"_blank\" href=\"%s\">מסמכי ההתקנה ↗</a> בהערות הגדרת php ובהגדרות php של התקנת השרת שלך, בעיקר כאשר משתמשים ב- php-fpm.",
+ "The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "תצורת קריאה בלבד הופעלה. תצורה זו מונעת קביעת מספר הגדרות באמצעות ממשק האינטרנט. יתר על כן, יש צורך להגדיר ההרשאות כתיבה באופן ידני לכל עדכון.",
+ "PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible." : "PHP מוגדר ככל הנראה להפשיט בלוקי קוד. מצב זה יגרום למספר יישומי ליבה להיות לא נגישים.",
+ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "זה ככל הנראה נגרם על ידי מאיץ/מטמון כמו Zend OPcache או eAccelerator.",
+ "Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "השרת רץ על גבי חלונות של מיקוסופט. אנו ממליצים בחום על לינוקס לחווית משתמש מיטבית.",
+ "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "%1$s מתחת לגרסה %2$s מותקנת, מסיבות יציבות וביצועים אנו ממליצים לעדכן לגרסה חדשה יותר גרסה %1$s.",
+ "The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "מודול ה- PHP מסוג 'fileinfo' חסר. אנו ממליצים בחום לאפשר מודול זה כדי לקבל תוצאות מיטביות עם גילוי mime-type.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "נעילת קובץ Transactional מנוטרלת, זה עלול להוביל לבעיות עם race conditions. יש לאפשר 'filelocking.enabled' בקובץ config.php כדי למנוע בעיות אלו. ראו <a target=\"_blank\" href=\"%s\">מסמכים אלו ↗</a> למידע נוסף.",
+ "System locale can not be set to a one which supports UTF-8." : "הגדרות שפה לא יכולות להקבע ככאלה שתומכות ב- UTF-8.",
+ "This means that there might be problems with certain characters in file names." : "משמעות הדבר היא כי ייתכן שיש בעיות עם תוים מסוימים בשמות קבצים.",
+ "We strongly suggest installing the required packages on your system to support one of the following locales: %s." : " אנו ממליצים בחום להתקין את החבילות הנדרשות במערכת שלך כדי לתמוך באחת מהגדרות השפה הבאות: %s.",
+ "If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "אם המערכת שלך לא מותקנת על נתיב הבסיס של שם התחום ומשתמשת במערכת cron, עלולות להיות בעיות עם יצירת כתובות האינטרנט. למניעת בעיות אלו, יש לקבוע את האופציה \"overwrite.cli.url\" בקובץ ה- config.php לנתיב הבסיסי של ההתקנה שלך (הציעו: \"%s \")",
+ "It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "לא ניתן היה להפעיל את cronjob דרך CLI. השגיאות הבאות נצפתו:",
+ "Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "יש לבדוק בשבע עיניים את ה- <a target=\"_blank\" href=\"%s\">מדריכי ההתקנה ↗</a>, ולחפש אחר כל שגיאה או הזהרה ב- <a href=\"#log-section\">לוג</a>.",
+ "All checks passed." : "כל הבדיקות עברו",
+ "Open documentation" : "תיעוד פתוח",
"Allow apps to use the Share API" : "לאפשר ליישום להשתמש ב־API השיתוף",
+ "Allow users to share via link" : "אפשר למשתמשים לשתף באמצעות קישור",
+ "Enforce password protection" : "חייב הגנת סיסמא",
+ "Allow public uploads" : "אפשר העלאות ציבוריות",
+ "Allow users to send mail notification for shared files" : "אפשר למשתמשים לשלוח הודעות דואר אלקטרוני לשיתוף קבצים",
+ "Set default expiration date" : "הגדרת תאריך תפוגה ברירת מחדל",
+ "Expire after " : "פג אחרי",
+ "days" : "ימים",
+ "Enforce expiration date" : "חייב תאריך תפוגה",
"Allow resharing" : "לאפשר שיתוף מחדש",
+ "Restrict users to only share with users in their groups" : "הגבלת משתמשים לשתף רק עם משתמשים בקבוצה שלהם",
+ "Allow users to send mail notification for shared files to other users" : "אפשר למשתמשים לשלוח הודעות דואר אלקטרוני לשיתוף קבצים למשתמשים אחרים",
+ "Exclude groups from sharing" : "מניעת קבוצות משיתוף",
+ "These groups will still be able to receive shares, but not to initiate them." : "קבוצות אלו עדיין יוכלו לקבל שיתופים, אך לא לשתף בעצמם.",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "אפשר השלמה אוטומטית של שמות משתמש בתפריט שיתוף. אם תכונה זו מנוטרלת יש להכניס שם משתמש מלא.",
+ "Last cron job execution: %s." : "פעילות cron job אחרונה: %s.",
+ "Last cron job execution: %s. Something seems wrong." : "פעילות cron job אחרונה: %s. משהו נראה שגוי.",
+ "Cron was not executed yet!" : "Cron עדיין לא בוצע!",
"Execute one task with each page loaded" : "יש להפעיל משימה אחת עם כל עמוד שנטען",
+ "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php רשום בשירות webcron לקרוא ל- cron.php בכל 15 דקות באמצעות http.",
+ "Use system's cron service to call the cron.php file every 15 minutes." : "ניתן להשתמש בשירות cron לקרוא לקובץ cron.php בכל 15 דקות.",
+ "Enable server-side encryption" : "הפעלת הצפנה בצד שרת",
+ "Please read carefully before activating server-side encryption: " : "יש לקרוא בתשומת לב רבה לפני שמפעילים הצפנת צד שרת:",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "ברגע שהצפנה מופעלת, כל הקבצים שיועלו לשרת מרגע זה יהיו מוצפנים בשרת. ניתן יהיה לנטרל את ההצפנה בעתיד רק אם מודול ההצפנה תומך בפונקציה זו, וכל התנאים המוקדמים (דהיינו הגדרת מפתח השחזור) מתקיימים.",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "הצפנה בלבד אינה מבטיחה את אבטחת המערכת. יש לקרוא את מסמכי ה- ownCloud למידע נוסף איך יישום ההצפנה עובד, ואפשרויות השימוש הנתמכות.",
+ "Be aware that encryption always increases the file size." : "תשומת לב לכך שהצפנה בהכרח מגדילה את גודל הקובץ.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "תמיד טוב ליצור גיבוי קבוע למידע , במקרה של הצפנה יש לוודא שגם מפתחות ההצפנה מגובים עם המידע שלך.",
+ "This is the final warning: Do you really want to enable encryption?" : "זו הזהרה אחרונה: האם באמת ברצונך להפעיל הצפנה?",
+ "Enable encryption" : "אפשר הצפנה",
+ "No encryption module loaded, please enable an encryption module in the app menu." : "לא נמצא מודול הצפנה, יש לאפשר מודול הצפנה בתפריט היישומים.",
+ "Select default encryption module:" : "יש לבחור מודול הצפנת ברירת מחדל:",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run 'occ encryption:migrate'" : "יש להמיר את מפתחות ההצפנה שלך בממערכת ההצפנה הישנה (ownCloud <= 8.0) למערכת החדשה. יש לאפשר את \"מודול הצפנה ברירת מחדש\" ולהריץ 'occ encryption:migrate'",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : "יש להמיר את מפתחות ההצפנה שלך בממערכת ההצפנה הישנה (ownCloud <= 8.0) למערכת החדשה.",
+ "Start migration" : "התחלת המרה",
+ "This is used for sending out notifications." : "משתמשים בזה כדי לשלוח הודעות.",
+ "Send mode" : "מצב שליחה",
"Encryption" : "הצפנה",
+ "From address" : "מכתובת",
+ "mail" : "mail",
+ "Authentication method" : "שיטת אימות",
+ "Authentication required" : "נדרש אימות",
"Server address" : "כתובת שרת",
- "Port" : "פורט",
+ "Port" : "שער",
"Credentials" : "פרטי גישה",
- "Log level" : "רמת הדיווח",
+ "SMTP Username" : "שם משתמש SMTP ",
+ "SMTP Password" : "סיסמת SMTP",
+ "Store credentials" : "שמירת אישורים",
+ "Test email settings" : "בדיקת הגדרות דואר אלקטרוני",
+ "Send email" : "שליחת דואר אלקטרוני",
+ "Download logfile" : "הורדת קובץ לוג",
"More" : "יותר",
"Less" : "פחות",
- "Version" : "גרסא",
- "by" : "על ידי",
+ "The logfile is bigger than 100 MB. Downloading it may take some time!" : "קובץ הלוג גדול מ- 100 מגה-בייט. הורדה עלולה לקחת זמן רב!",
+ "What to log" : "מה לנטר בלוג",
+ "SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "המערכת משתמשת ב- SQLite כמסד נתונים. להתקנות גדולות אנו ממליצים לעבור למסדי נתונים צד אחורי אחרים.",
+ "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "במיוחד כאשר משתמשים במחשב שולחני לסנכרון קבצים השימוש ב SQLite אינו מומלץ.",
+ "To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "לצורך מעבר למסד נתונים אחר ניתן להשתמש בכלי שורת הפעולה: 'occ db:convert-type', או להסתכל ב- <a target=\"_blank\" href=\"%s\">מסמכים הבאים ↗</a>.",
+ "How to do backups" : "איך לבצע גיבויים",
+ "Advanced monitoring" : "ניטור מתקדם",
+ "Performance tuning" : "כוונון ביצועים",
+ "Improving the config.php" : "שיפור קובץ config.php",
+ "Theming" : "ערכת נושא",
+ "Hardening and security guidance" : "הדרכת הקשחה ואבטחה",
+ "Version" : "גרסה",
+ "Developer documentation" : "תיעוד מפתח",
+ "Experimental applications ahead" : "ישומים ניסיוניים לפנים",
+ "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "יישומים ניסיוניים לא נבדקו לבעיות אבטחה, חדשים או ידועים כלא יציבים ותחת פיתוח כבד. התקנה שלהם עלולה להוביל לאיבוד מידע או לפרצות אבטחה.",
+ "by %s" : "על ידי %s",
+ "%s-licensed" : "%s-בעל רישיון",
+ "Documentation:" : "תיעוד",
+ "User documentation" : "תיעוד משתמש",
+ "Admin documentation" : "תיעוד מנהל",
+ "Show description …" : "הצגת תיאור ...",
+ "Hide description …" : "הסתרת תיאור ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "ליישום זה לא הוקצתה גרסה מינמלית של ownCloud. מצב זה יהיה שגוי בגרסה 11 או מאוחרת יותר של ownCloud.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "ליישום זה לא הוקצתה גרסה מקסימלית של ownCloud. מצב זה יהיה שגוי בגרסה 11 או מאוחרת יותר של ownCloud.",
+ "This app cannot be installed because the following dependencies are not fulfilled:" : "לא ניתן להתקין את יישום זה כיוון שייחסי התלות הבאים לא התקיימו:",
+ "Enable only for specific groups" : "אפשר רק לקבוצות מסויימות",
+ "Uninstall App" : "הסרת יישום",
+ "Enable experimental apps" : "אפשר יישומים ניסיוניים",
+ "SSL Root Certificates" : "אישורי אבטחת SSL לנתיב יסוד",
+ "Common Name" : "שם משותף",
+ "Valid until" : "בתוקף עד",
+ "Issued By" : "הוצא על ידי",
+ "Valid until %s" : "בתוקף עד %s",
+ "Import root certificate" : "יבוא אישור אבטחה לנתיב יסוד",
+ "Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "שלום,<br><br>רק רצינו להודיע שעכשיו יש לך %s חשבון.<br><br>Your שם משתמש: %s<br>כניסה: <a href=\"%s\">%s</a><br><br>",
+ "Cheers!" : "לחיים!",
+ "Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "שלום,\n\nרק רצינו להודיע שעכשיו יש לך %s חשבון.\n\nשם המשתמש שלך: %s\nכניסה: %s\n\n",
+ "Administrator documentation" : "תיעוד מנהל",
+ "Online documentation" : "תיעוד מקוון",
"Forum" : "פורום",
- "Get the apps to sync your files" : "השג את האפליקציות על מנת לסנכרן את הקבצים שלך",
- "Show First Run Wizard again" : "הצגת אשף ההפעלה הראשונית שוב",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "השתמשת ב־<strong>%s</strong> מתוך <strong>%s</strong> הזמינים לך",
- "Password" : "סיסמא",
- "Unable to change your password" : "לא ניתן לשנות את הססמה שלך",
- "Current password" : "ססמה נוכחית",
- "New password" : "ססמה חדשה",
- "Change password" : "שינוי ססמה",
- "Email" : "דואר אלקטרוני",
- "Your email address" : "כתובת הדוא״ל שלך",
+ "Issue tracker" : "מעקב בעיות",
+ "Commercial support" : "תמיכה מסחרית",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "הנך משתמש ב- <strong>%s</strong> מתוך <strong>%s</strong>",
"Profile picture" : "תמונת פרופיל",
+ "Upload new" : "העלאת חדש",
+ "Select from Files" : "בחירה מתוך קבצים",
+ "Remove image" : "הסרת תמונה",
+ "png or jpg, max. 20 MB" : "png או jpg, מקסימום 20 מגה-בייט",
+ "Picture provided by original account" : "תמונה סופקה על ידי חשבון מקור",
"Cancel" : "ביטול",
- "Language" : "פה",
+ "Choose as profile picture" : "יש לבחור כתמונת פרופיל",
+ "Full name" : "שם מלא",
+ "No display name set" : "לא נקבע שם תצוגה",
+ "Email" : "דואר אלקטרוני",
+ "Your email address" : "כתובת הדואר האלקטרוני שלך",
+ "For password recovery and notifications" : "לשחזור סיסמא והודעות",
+ "No email address set" : "לא נקבעה כתובת דואר אלקטרוני",
+ "You are member of the following groups:" : "הקבוצות הבאות כוללות אותך:",
+ "Password" : "סיסמא",
+ "Unable to change your password" : "לא ניתן לשנות את הסיסמא שלך",
+ "Current password" : "סיסמא נוכחית",
+ "New password" : "סיסמא חדשה",
+ "Change password" : "שינוי סיסמא",
+ "Language" : "שפה",
"Help translate" : "עזרה בתרגום",
+ "Get the apps to sync your files" : "קבלת היישומים לסנכרון הקבצים שלך",
+ "Desktop client" : "מחשב אישי",
+ "Android app" : "יישום אנדרואיד",
+ "iOS app" : "יישום אייפון",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "אם ברצונך לתמוך בפרויקט\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ניתן להצטרך לפיתוח</a>\n\t\tאו\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">להפיץ את הבשורה</a>!",
+ "Show First Run Wizard again" : "הצגת אשף ההפעלה הראשונית שוב",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "פיתוח על ידי {open}קהילת ownCloud community{linkclose}, {githubopen}קוד המקור{linkclose} ברישיון תחת ה- {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
+ "Show storage location" : "הצגת מיקום אחסון",
+ "Show last log in" : "הצגת כניסה אחרונה",
+ "Show user backend" : "הצגת צד אחורי למשתמש",
+ "Send email to new user" : "שליחת דואר אלקטרוני למשתמש חדש",
+ "Show email address" : "הצגת כתובת דואר אלקטרוני",
"Username" : "שם משתמש",
+ "E-Mail" : "דואר אלקטרוני",
"Create" : "יצירה",
- "Admin Recovery Password" : "ססמת השחזור של המנהל",
+ "Admin Recovery Password" : "סיסמת השחזור של המנהל",
+ "Enter the recovery password in order to recover the users files during password change" : "יש להכניס את סיסמת השחזור לצורך שחזור של קבצי המשתמש במהלך החלפת סיסמא",
+ "Add Group" : "הוספת קבוצה",
"Group" : "קבוצה",
- "Default Quota" : "מכסת בררת המחדל",
+ "Everyone" : "כולם",
+ "Admins" : "מנהלים",
+ "Default Quota" : "מכסת ברירת המחדל",
+ "Please enter storage quota (ex: \"512 MB\" or \"12 GB\")" : "יש להכניס מכסת אחסון (לדוגמא: \"512 MB\" or \"12 GB\")",
"Unlimited" : "ללא הגבלה",
"Other" : "אחר",
+ "Full Name" : "שם מלא",
+ "Group Admin for" : "קבוצת ניהול עבור",
"Quota" : "מכסה",
- "set new password" : "הגדרת ססמה חדשה",
- "Default" : "בררת מחדל"
+ "Storage Location" : "מיקום אחסון",
+ "User Backend" : "צד אחורי משתמש",
+ "Last Login" : "התחברות אחרונה",
+ "change full name" : "שינוי שם מלא",
+ "set new password" : "הגדרת סיסמא חדשה",
+ "change email address" : "שינוי כתובת דואר אלקטרוני",
+ "Default" : "ברירת מחדל"
},
"nplurals=2; plural=(n != 1);");
diff --git a/settings/l10n/he.json b/settings/l10n/he.json
index 4df3810dec3..e4a4154e8c1 100644
--- a/settings/l10n/he.json
+++ b/settings/l10n/he.json
@@ -1,73 +1,291 @@
{ "translations": {
+ "APCu" : "APCu",
+ "Redis" : "Redis",
+ "Security & setup warnings" : "הזהרות אבטחה והתקנה",
"Sharing" : "שיתוף",
+ "Server-side encryption" : "הצפנת צד שרת",
"External Storage" : "אחסון חיצוני",
"Cron" : "Cron",
+ "Email server" : "שרת דואר אלקטרוני",
"Log" : "יומן",
- "Authentication error" : "שגיאת הזדהות",
+ "Tips & tricks" : "עצות ותחבולות",
+ "Updates" : "עדכונים",
+ "Couldn't remove app." : "לא ניתן להסיר את היישום.",
"Language changed" : "שפה השתנתה",
"Invalid request" : "בקשה לא חוקית",
+ "Authentication error" : "שגיאת הזדהות",
"Admins can't remove themself from the admin group" : "מנהלים לא יכולים להסיר את עצמם מקבוצת המנהלים",
"Unable to add user to group %s" : "לא ניתן להוסיף משתמש לקבוצה %s",
"Unable to remove user from group %s" : "לא ניתן להסיר משתמש מהקבוצה %s",
"Couldn't update app." : "לא ניתן לעדכן את היישום.",
+ "Wrong password" : "סיסמא שגוייה",
+ "No user supplied" : "לא סופק שם משתמש",
+ "Please provide an admin recovery password, otherwise all user data will be lost" : "יש לספק את סיסמת המנהל לשחזור, אחרת כל מידע המשתמש יאבד",
+ "Wrong admin recovery password. Please check the password and try again." : "סיסמת המנהל לשחזור שגוייה. יש לבדוק את הסיסמא ולנסות שוב.",
+ "Backend doesn't support password change, but the user's encryption key was successfully updated." : "צד אחורי לא תומך בשינוי סיסמא, אך מפתח הצפנה של המשתמש עודכנה בהצלחה.",
+ "Unable to change password" : "לא ניתן לשנות את הסיסמא",
+ "Enabled" : "מופעל",
+ "Not enabled" : "לא מופעל",
+ "installing and updating apps via the app store or Federated Cloud Sharing" : "התקנה ועדכון היישום דרך חנות היישומים או ענן שיתוף מאוגד",
+ "Federated Cloud Sharing" : "ענן שיתוף מאוגד",
+ "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL משתמש בגרסה %s ישנה (%s). יש לעדכן את מערכת ההפעלה או שתכונות כדוגמת %s לא יעבדו באופן מהימן.",
+ "A problem occurred, please check your log files (Error: %s)" : "אירעה בעיה, יש לבדוק את לוג הקבצים (שגיאה: %s)",
+ "Migration Completed" : "המרה הושלמה",
+ "Group already exists." : "קבוצה כבר קיימת.",
+ "Unable to add group." : "לא ניתן להוסיף קבוצה.",
+ "Unable to delete group." : "לא ניתן למחוק קבוצה.",
+ "log-level out of allowed range" : "גודל הלוג מעבר לרמה המותרת",
"Saved" : "נשמר",
- "Email sent" : "הודעת הדוא״ל נשלחה",
- "Email saved" : "הדוא״ל נשמר",
+ "test email settings" : "בדיקת הגדרות דואר אלקטרוני",
+ "A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "בעיה אירעה בשליחת הדואר האלקטרוני. יש לשנות את ההגדרות שלך. (שגיאה: %s)",
+ "Email sent" : "הודעת הדואר האלקטרוני נשלחה",
+ "You need to set your user email before being able to send test emails." : "יש להגדיר כתובת דואר אלקטרוני לפני שניתן יהיה לשלוח דואר אלקטרוני לבדיקה.",
+ "Invalid mail address" : "כתובת דואר אלקטרוני לא חוקית",
+ "A user with that name already exists." : "משתמש בשם זה כבר קיים.",
+ "Unable to create user." : "לא ניתן ליצור משתמש.",
+ "Your %s account was created" : "חשבון %s שלך נוצר",
+ "Unable to delete user." : "לא ניתן למחוק משתמש.",
+ "Forbidden" : "חסום",
+ "Invalid user" : "שם משתמש לא חוקי",
+ "Unable to change mail address" : "לא ניתן לשנות כתובת דואר אלקטרוני",
+ "Email saved" : "הדואר האלקטרוני נשמר",
+ "Your full name has been changed." : "השם המלא שלך הוחלף",
+ "Unable to change full name" : "לא ניתן לשנות שם מלא",
+ "Are you really sure you want add \"{domain}\" as trusted domain?" : "האם באמת להוסיף \"{domain}\" כשם מתחם מהימן?",
+ "Add trusted domain" : "הוספת שם מתחם מהימן",
+ "Migration in progress. Please wait until the migration is finished" : "המרה בביצוע. יש להמתין עד סיום ההמרה",
+ "Migration started …" : "המרה החלה...",
+ "Sending..." : "שולח...",
+ "Official" : "רישמי",
+ "Approved" : "מאושר",
+ "Experimental" : "ניסיוני",
"All" : "הכל",
+ "No apps found for your version" : "לא נמצאו יישומים לגרסה שלך",
+ "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "יישומים רישמיים מפותחים על ידי קהילת ownCloud. הם מציעים פונקיונאליות, התאמה ל- ownCloud ומוכנים לשימוש כבד.",
+ "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "יישומים מאושרים מפותחים על ידי מפתחים מהימנים ועברו בדיקת הבטחה ראשונית. הם נשמרים באופן פעיל במאגר קוד פתוח והמתזקים שלהם מייעדים אותם לשימוש מזדמן ורגיל.",
+ "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "יישום זה לא נבדק לבעיות אבטחה והוא חדש או ידוע כלא יציב. התקנת יישום זה הנה על אחריותך בלבד.",
+ "Update to %s" : "עדכון ל- %s",
"Please wait...." : "נא להמתין…",
- "Disable" : "בטל",
+ "Error while disabling app" : "אירעה שגיאה בעת נטרול היישום",
+ "Disable" : "ניטרול",
"Enable" : "הפעלה",
+ "Error while enabling app" : "שגיאה בעת הפעלת יישום",
"Updating...." : "מתבצע עדכון…",
"Error while updating app" : "אירעה שגיאה בעת עדכון היישום",
"Updated" : "מעודכן",
+ "Uninstalling ...." : "מסיר התקנה...",
+ "Error while uninstalling app" : "אירעה שגיאה בעת הסרת היישום",
+ "Uninstall" : "הסרת התקנה",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "היישום הופעל אך יש לעדכן אותו. בעוד 5 שניות הדף ינותב לעמוד העדכון.",
+ "App update" : "עדכון יישום",
+ "No apps found for \"{query}\"" : "לא נמצא יישום עבור \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "אירעה שגיאה. יש להעלות תעודת ASCII-encoded PEM.",
+ "Valid until {date}" : "בתוקף עד ל- {date}",
"Delete" : "מחיקה",
+ "An error occurred: {message}" : "אירעה שגיאה: {message}",
+ "Select a profile picture" : "יש לבחור תמונת פרופיל",
+ "Very weak password" : "סיסמא מאוד חלשה",
+ "Weak password" : "סיסמא חלשה",
+ "So-so password" : "סיסמא ככה-ככה",
+ "Good password" : "סיסמא טובה",
+ "Strong password" : "סיסמא חזקה",
"Groups" : "קבוצות",
+ "Unable to delete {objName}" : "לא ניתן למחיקה {objName}",
+ "Error creating group" : "שגיאה בעת יצירת קבוצה",
+ "A valid group name must be provided" : "יש לספק שם קבוצה תקני",
+ "deleted {groupName}" : "נמחק {groupName}",
"undo" : "ביטול",
+ "no group" : "אין קבוצה",
"never" : "לעולם לא",
+ "deleted {userName}" : "נמחק {userName}",
"add group" : "הוספת קבוצה",
+ "Changing the password will result in data loss, because data recovery is not available for this user" : "שינוי הסיסמא יגרום איבוד מידע, וזאת בגלל ששחזור מידע אינו זמין למשתמש זה",
"A valid username must be provided" : "יש לספק שם משתמש תקני",
"Error creating user" : "יצירת המשתמש נכשלה",
- "A valid password must be provided" : "יש לספק ססמה תקנית",
+ "A valid password must be provided" : "יש לספק סיסמא תקנית",
+ "A valid email must be provided" : "יש לספק כתובת דואר אלקטרוני תקנית",
"__language_name__" : "עברית",
- "SSL root certificates" : "שורש אישורי אבטחת SSL ",
+ "Personal info" : "מידע אישי",
+ "Sync clients" : "סנכרון לקוחות",
+ "Everything (fatal issues, errors, warnings, info, debug)" : "הכול (נושאים חמורים, שגיאות, אזהרות, מידע, ניפוי שגיאות)",
+ "Info, warnings, errors and fatal issues" : "מידע, אזהרות, שגיאות ונושאים חמורים",
+ "Warnings, errors and fatal issues" : "אזהרות, שגיאות ונושאים חמורים",
+ "Errors and fatal issues" : "שגיאות ונושאים חמורים",
+ "Fatal issues only" : "נושאים חמורים בלבד",
"None" : "כלום",
"Login" : "התחברות",
+ "Plain" : "רגיל",
+ "NT LAN Manager" : "מנהל רשת NT",
+ "SSL" : "SSL",
+ "TLS" : "TLS",
+ "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response.",
+ "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "יש לבדוק את <a target=\"_blank\" href=\"%s\">מסמכי ההתקנה ↗</a> בהערות הגדרת php ובהגדרות php של התקנת השרת שלך, בעיקר כאשר משתמשים ב- php-fpm.",
+ "The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "תצורת קריאה בלבד הופעלה. תצורה זו מונעת קביעת מספר הגדרות באמצעות ממשק האינטרנט. יתר על כן, יש צורך להגדיר ההרשאות כתיבה באופן ידני לכל עדכון.",
+ "PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible." : "PHP מוגדר ככל הנראה להפשיט בלוקי קוד. מצב זה יגרום למספר יישומי ליבה להיות לא נגישים.",
+ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "זה ככל הנראה נגרם על ידי מאיץ/מטמון כמו Zend OPcache או eAccelerator.",
+ "Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "השרת רץ על גבי חלונות של מיקוסופט. אנו ממליצים בחום על לינוקס לחווית משתמש מיטבית.",
+ "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "%1$s מתחת לגרסה %2$s מותקנת, מסיבות יציבות וביצועים אנו ממליצים לעדכן לגרסה חדשה יותר גרסה %1$s.",
+ "The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "מודול ה- PHP מסוג 'fileinfo' חסר. אנו ממליצים בחום לאפשר מודול זה כדי לקבל תוצאות מיטביות עם גילוי mime-type.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "נעילת קובץ Transactional מנוטרלת, זה עלול להוביל לבעיות עם race conditions. יש לאפשר 'filelocking.enabled' בקובץ config.php כדי למנוע בעיות אלו. ראו <a target=\"_blank\" href=\"%s\">מסמכים אלו ↗</a> למידע נוסף.",
+ "System locale can not be set to a one which supports UTF-8." : "הגדרות שפה לא יכולות להקבע ככאלה שתומכות ב- UTF-8.",
+ "This means that there might be problems with certain characters in file names." : "משמעות הדבר היא כי ייתכן שיש בעיות עם תוים מסוימים בשמות קבצים.",
+ "We strongly suggest installing the required packages on your system to support one of the following locales: %s." : " אנו ממליצים בחום להתקין את החבילות הנדרשות במערכת שלך כדי לתמוך באחת מהגדרות השפה הבאות: %s.",
+ "If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "אם המערכת שלך לא מותקנת על נתיב הבסיס של שם התחום ומשתמשת במערכת cron, עלולות להיות בעיות עם יצירת כתובות האינטרנט. למניעת בעיות אלו, יש לקבוע את האופציה \"overwrite.cli.url\" בקובץ ה- config.php לנתיב הבסיסי של ההתקנה שלך (הציעו: \"%s \")",
+ "It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "לא ניתן היה להפעיל את cronjob דרך CLI. השגיאות הבאות נצפתו:",
+ "Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "יש לבדוק בשבע עיניים את ה- <a target=\"_blank\" href=\"%s\">מדריכי ההתקנה ↗</a>, ולחפש אחר כל שגיאה או הזהרה ב- <a href=\"#log-section\">לוג</a>.",
+ "All checks passed." : "כל הבדיקות עברו",
+ "Open documentation" : "תיעוד פתוח",
"Allow apps to use the Share API" : "לאפשר ליישום להשתמש ב־API השיתוף",
+ "Allow users to share via link" : "אפשר למשתמשים לשתף באמצעות קישור",
+ "Enforce password protection" : "חייב הגנת סיסמא",
+ "Allow public uploads" : "אפשר העלאות ציבוריות",
+ "Allow users to send mail notification for shared files" : "אפשר למשתמשים לשלוח הודעות דואר אלקטרוני לשיתוף קבצים",
+ "Set default expiration date" : "הגדרת תאריך תפוגה ברירת מחדל",
+ "Expire after " : "פג אחרי",
+ "days" : "ימים",
+ "Enforce expiration date" : "חייב תאריך תפוגה",
"Allow resharing" : "לאפשר שיתוף מחדש",
+ "Restrict users to only share with users in their groups" : "הגבלת משתמשים לשתף רק עם משתמשים בקבוצה שלהם",
+ "Allow users to send mail notification for shared files to other users" : "אפשר למשתמשים לשלוח הודעות דואר אלקטרוני לשיתוף קבצים למשתמשים אחרים",
+ "Exclude groups from sharing" : "מניעת קבוצות משיתוף",
+ "These groups will still be able to receive shares, but not to initiate them." : "קבוצות אלו עדיין יוכלו לקבל שיתופים, אך לא לשתף בעצמם.",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "אפשר השלמה אוטומטית של שמות משתמש בתפריט שיתוף. אם תכונה זו מנוטרלת יש להכניס שם משתמש מלא.",
+ "Last cron job execution: %s." : "פעילות cron job אחרונה: %s.",
+ "Last cron job execution: %s. Something seems wrong." : "פעילות cron job אחרונה: %s. משהו נראה שגוי.",
+ "Cron was not executed yet!" : "Cron עדיין לא בוצע!",
"Execute one task with each page loaded" : "יש להפעיל משימה אחת עם כל עמוד שנטען",
+ "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php רשום בשירות webcron לקרוא ל- cron.php בכל 15 דקות באמצעות http.",
+ "Use system's cron service to call the cron.php file every 15 minutes." : "ניתן להשתמש בשירות cron לקרוא לקובץ cron.php בכל 15 דקות.",
+ "Enable server-side encryption" : "הפעלת הצפנה בצד שרת",
+ "Please read carefully before activating server-side encryption: " : "יש לקרוא בתשומת לב רבה לפני שמפעילים הצפנת צד שרת:",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "ברגע שהצפנה מופעלת, כל הקבצים שיועלו לשרת מרגע זה יהיו מוצפנים בשרת. ניתן יהיה לנטרל את ההצפנה בעתיד רק אם מודול ההצפנה תומך בפונקציה זו, וכל התנאים המוקדמים (דהיינו הגדרת מפתח השחזור) מתקיימים.",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "הצפנה בלבד אינה מבטיחה את אבטחת המערכת. יש לקרוא את מסמכי ה- ownCloud למידע נוסף איך יישום ההצפנה עובד, ואפשרויות השימוש הנתמכות.",
+ "Be aware that encryption always increases the file size." : "תשומת לב לכך שהצפנה בהכרח מגדילה את גודל הקובץ.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "תמיד טוב ליצור גיבוי קבוע למידע , במקרה של הצפנה יש לוודא שגם מפתחות ההצפנה מגובים עם המידע שלך.",
+ "This is the final warning: Do you really want to enable encryption?" : "זו הזהרה אחרונה: האם באמת ברצונך להפעיל הצפנה?",
+ "Enable encryption" : "אפשר הצפנה",
+ "No encryption module loaded, please enable an encryption module in the app menu." : "לא נמצא מודול הצפנה, יש לאפשר מודול הצפנה בתפריט היישומים.",
+ "Select default encryption module:" : "יש לבחור מודול הצפנת ברירת מחדל:",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run 'occ encryption:migrate'" : "יש להמיר את מפתחות ההצפנה שלך בממערכת ההצפנה הישנה (ownCloud <= 8.0) למערכת החדשה. יש לאפשר את \"מודול הצפנה ברירת מחדש\" ולהריץ 'occ encryption:migrate'",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : "יש להמיר את מפתחות ההצפנה שלך בממערכת ההצפנה הישנה (ownCloud <= 8.0) למערכת החדשה.",
+ "Start migration" : "התחלת המרה",
+ "This is used for sending out notifications." : "משתמשים בזה כדי לשלוח הודעות.",
+ "Send mode" : "מצב שליחה",
"Encryption" : "הצפנה",
+ "From address" : "מכתובת",
+ "mail" : "mail",
+ "Authentication method" : "שיטת אימות",
+ "Authentication required" : "נדרש אימות",
"Server address" : "כתובת שרת",
- "Port" : "פורט",
+ "Port" : "שער",
"Credentials" : "פרטי גישה",
- "Log level" : "רמת הדיווח",
+ "SMTP Username" : "שם משתמש SMTP ",
+ "SMTP Password" : "סיסמת SMTP",
+ "Store credentials" : "שמירת אישורים",
+ "Test email settings" : "בדיקת הגדרות דואר אלקטרוני",
+ "Send email" : "שליחת דואר אלקטרוני",
+ "Download logfile" : "הורדת קובץ לוג",
"More" : "יותר",
"Less" : "פחות",
- "Version" : "גרסא",
- "by" : "על ידי",
+ "The logfile is bigger than 100 MB. Downloading it may take some time!" : "קובץ הלוג גדול מ- 100 מגה-בייט. הורדה עלולה לקחת זמן רב!",
+ "What to log" : "מה לנטר בלוג",
+ "SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "המערכת משתמשת ב- SQLite כמסד נתונים. להתקנות גדולות אנו ממליצים לעבור למסדי נתונים צד אחורי אחרים.",
+ "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "במיוחד כאשר משתמשים במחשב שולחני לסנכרון קבצים השימוש ב SQLite אינו מומלץ.",
+ "To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "לצורך מעבר למסד נתונים אחר ניתן להשתמש בכלי שורת הפעולה: 'occ db:convert-type', או להסתכל ב- <a target=\"_blank\" href=\"%s\">מסמכים הבאים ↗</a>.",
+ "How to do backups" : "איך לבצע גיבויים",
+ "Advanced monitoring" : "ניטור מתקדם",
+ "Performance tuning" : "כוונון ביצועים",
+ "Improving the config.php" : "שיפור קובץ config.php",
+ "Theming" : "ערכת נושא",
+ "Hardening and security guidance" : "הדרכת הקשחה ואבטחה",
+ "Version" : "גרסה",
+ "Developer documentation" : "תיעוד מפתח",
+ "Experimental applications ahead" : "ישומים ניסיוניים לפנים",
+ "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "יישומים ניסיוניים לא נבדקו לבעיות אבטחה, חדשים או ידועים כלא יציבים ותחת פיתוח כבד. התקנה שלהם עלולה להוביל לאיבוד מידע או לפרצות אבטחה.",
+ "by %s" : "על ידי %s",
+ "%s-licensed" : "%s-בעל רישיון",
+ "Documentation:" : "תיעוד",
+ "User documentation" : "תיעוד משתמש",
+ "Admin documentation" : "תיעוד מנהל",
+ "Show description …" : "הצגת תיאור ...",
+ "Hide description …" : "הסתרת תיאור ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "ליישום זה לא הוקצתה גרסה מינמלית של ownCloud. מצב זה יהיה שגוי בגרסה 11 או מאוחרת יותר של ownCloud.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "ליישום זה לא הוקצתה גרסה מקסימלית של ownCloud. מצב זה יהיה שגוי בגרסה 11 או מאוחרת יותר של ownCloud.",
+ "This app cannot be installed because the following dependencies are not fulfilled:" : "לא ניתן להתקין את יישום זה כיוון שייחסי התלות הבאים לא התקיימו:",
+ "Enable only for specific groups" : "אפשר רק לקבוצות מסויימות",
+ "Uninstall App" : "הסרת יישום",
+ "Enable experimental apps" : "אפשר יישומים ניסיוניים",
+ "SSL Root Certificates" : "אישורי אבטחת SSL לנתיב יסוד",
+ "Common Name" : "שם משותף",
+ "Valid until" : "בתוקף עד",
+ "Issued By" : "הוצא על ידי",
+ "Valid until %s" : "בתוקף עד %s",
+ "Import root certificate" : "יבוא אישור אבטחה לנתיב יסוד",
+ "Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "שלום,<br><br>רק רצינו להודיע שעכשיו יש לך %s חשבון.<br><br>Your שם משתמש: %s<br>כניסה: <a href=\"%s\">%s</a><br><br>",
+ "Cheers!" : "לחיים!",
+ "Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "שלום,\n\nרק רצינו להודיע שעכשיו יש לך %s חשבון.\n\nשם המשתמש שלך: %s\nכניסה: %s\n\n",
+ "Administrator documentation" : "תיעוד מנהל",
+ "Online documentation" : "תיעוד מקוון",
"Forum" : "פורום",
- "Get the apps to sync your files" : "השג את האפליקציות על מנת לסנכרן את הקבצים שלך",
- "Show First Run Wizard again" : "הצגת אשף ההפעלה הראשונית שוב",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "השתמשת ב־<strong>%s</strong> מתוך <strong>%s</strong> הזמינים לך",
- "Password" : "סיסמא",
- "Unable to change your password" : "לא ניתן לשנות את הססמה שלך",
- "Current password" : "ססמה נוכחית",
- "New password" : "ססמה חדשה",
- "Change password" : "שינוי ססמה",
- "Email" : "דואר אלקטרוני",
- "Your email address" : "כתובת הדוא״ל שלך",
+ "Issue tracker" : "מעקב בעיות",
+ "Commercial support" : "תמיכה מסחרית",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "הנך משתמש ב- <strong>%s</strong> מתוך <strong>%s</strong>",
"Profile picture" : "תמונת פרופיל",
+ "Upload new" : "העלאת חדש",
+ "Select from Files" : "בחירה מתוך קבצים",
+ "Remove image" : "הסרת תמונה",
+ "png or jpg, max. 20 MB" : "png או jpg, מקסימום 20 מגה-בייט",
+ "Picture provided by original account" : "תמונה סופקה על ידי חשבון מקור",
"Cancel" : "ביטול",
- "Language" : "פה",
+ "Choose as profile picture" : "יש לבחור כתמונת פרופיל",
+ "Full name" : "שם מלא",
+ "No display name set" : "לא נקבע שם תצוגה",
+ "Email" : "דואר אלקטרוני",
+ "Your email address" : "כתובת הדואר האלקטרוני שלך",
+ "For password recovery and notifications" : "לשחזור סיסמא והודעות",
+ "No email address set" : "לא נקבעה כתובת דואר אלקטרוני",
+ "You are member of the following groups:" : "הקבוצות הבאות כוללות אותך:",
+ "Password" : "סיסמא",
+ "Unable to change your password" : "לא ניתן לשנות את הסיסמא שלך",
+ "Current password" : "סיסמא נוכחית",
+ "New password" : "סיסמא חדשה",
+ "Change password" : "שינוי סיסמא",
+ "Language" : "שפה",
"Help translate" : "עזרה בתרגום",
+ "Get the apps to sync your files" : "קבלת היישומים לסנכרון הקבצים שלך",
+ "Desktop client" : "מחשב אישי",
+ "Android app" : "יישום אנדרואיד",
+ "iOS app" : "יישום אייפון",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "אם ברצונך לתמוך בפרויקט\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ניתן להצטרך לפיתוח</a>\n\t\tאו\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">להפיץ את הבשורה</a>!",
+ "Show First Run Wizard again" : "הצגת אשף ההפעלה הראשונית שוב",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "פיתוח על ידי {open}קהילת ownCloud community{linkclose}, {githubopen}קוד המקור{linkclose} ברישיון תחת ה- {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
+ "Show storage location" : "הצגת מיקום אחסון",
+ "Show last log in" : "הצגת כניסה אחרונה",
+ "Show user backend" : "הצגת צד אחורי למשתמש",
+ "Send email to new user" : "שליחת דואר אלקטרוני למשתמש חדש",
+ "Show email address" : "הצגת כתובת דואר אלקטרוני",
"Username" : "שם משתמש",
+ "E-Mail" : "דואר אלקטרוני",
"Create" : "יצירה",
- "Admin Recovery Password" : "ססמת השחזור של המנהל",
+ "Admin Recovery Password" : "סיסמת השחזור של המנהל",
+ "Enter the recovery password in order to recover the users files during password change" : "יש להכניס את סיסמת השחזור לצורך שחזור של קבצי המשתמש במהלך החלפת סיסמא",
+ "Add Group" : "הוספת קבוצה",
"Group" : "קבוצה",
- "Default Quota" : "מכסת בררת המחדל",
+ "Everyone" : "כולם",
+ "Admins" : "מנהלים",
+ "Default Quota" : "מכסת ברירת המחדל",
+ "Please enter storage quota (ex: \"512 MB\" or \"12 GB\")" : "יש להכניס מכסת אחסון (לדוגמא: \"512 MB\" or \"12 GB\")",
"Unlimited" : "ללא הגבלה",
"Other" : "אחר",
+ "Full Name" : "שם מלא",
+ "Group Admin for" : "קבוצת ניהול עבור",
"Quota" : "מכסה",
- "set new password" : "הגדרת ססמה חדשה",
- "Default" : "בררת מחדל"
+ "Storage Location" : "מיקום אחסון",
+ "User Backend" : "צד אחורי משתמש",
+ "Last Login" : "התחברות אחרונה",
+ "change full name" : "שינוי שם מלא",
+ "set new password" : "הגדרת סיסמא חדשה",
+ "change email address" : "שינוי כתובת דואר אלקטרוני",
+ "Default" : "ברירת מחדל"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/settings/l10n/hi.js b/settings/l10n/hi.js
index 2925a7e0fc0..715292b3dc8 100644
--- a/settings/l10n/hi.js
+++ b/settings/l10n/hi.js
@@ -3,9 +3,9 @@ OC.L10N.register(
{
"Email sent" : "ईमेल भेज दिया गया है ",
"More" : "और अधिक",
+ "Cancel" : "रद्द करें ",
"Password" : "पासवर्ड",
"New password" : "नया पासवर्ड",
- "Cancel" : "रद्द करें ",
"Username" : "प्रयोक्ता का नाम"
},
"nplurals=2; plural=(n != 1);");
diff --git a/settings/l10n/hi.json b/settings/l10n/hi.json
index b607c019c6f..c06462a29d9 100644
--- a/settings/l10n/hi.json
+++ b/settings/l10n/hi.json
@@ -1,9 +1,9 @@
{ "translations": {
"Email sent" : "ईमेल भेज दिया गया है ",
"More" : "और अधिक",
+ "Cancel" : "रद्द करें ",
"Password" : "पासवर्ड",
"New password" : "नया पासवर्ड",
- "Cancel" : "रद्द करें ",
"Username" : "प्रयोक्ता का नाम"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/settings/l10n/hr.js b/settings/l10n/hr.js
index e32b8aa6608..517e5db5269 100644
--- a/settings/l10n/hr.js
+++ b/settings/l10n/hr.js
@@ -6,12 +6,10 @@ OC.L10N.register(
"Cron" : "Cron",
"Log" : "Zapisnik",
"Updates" : "nadogradnje",
- "Authentication error" : "Pogrešna autentikacija",
- "Your full name has been changed." : "Vaše puno ime je promijenjeno.",
- "Unable to change full name" : "Puno ime nije moguće promijeniti.",
"Couldn't remove app." : "Nije moguće ukloniti app.",
"Language changed" : "Promjena jezika",
"Invalid request" : "Zahtjev neispravan",
+ "Authentication error" : "Pogrešna autentikacija",
"Admins can't remove themself from the admin group" : "Administratori ne mogu sami sebe ukloniti iz admin grupe",
"Unable to add user to group %s" : "Dodavanje korisnika grupi %s nije moguće",
"Unable to remove user from group %s" : "Uklanjanje korisnika iz grupe %s nije moguće",
@@ -27,6 +25,8 @@ OC.L10N.register(
"Email sent" : "E-pošta je poslana",
"You need to set your user email before being able to send test emails." : "Prije nego li ste u mogućnosti slati testnu e-poštu trebate postaviti svoj korisnički email.",
"Email saved" : "E-pošta spremljena",
+ "Your full name has been changed." : "Vaše puno ime je promijenjeno.",
+ "Unable to change full name" : "Puno ime nije moguće promijeniti.",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Jeste li doista sigurni da želite dodati \"{domain}\" kao pouzdanu domenu?",
"Add trusted domain" : "Dodajte pouzdanu domenu",
"Sending..." : "Slanje...",
@@ -42,14 +42,14 @@ OC.L10N.register(
"Uninstalling ...." : "Deinstaliranje....",
"Error while uninstalling app" : "Pogreška pri deinstaliranju app",
"Uninstall" : "Deinstalirajte",
+ "Valid until {date}" : "Valid until {date}",
+ "Delete" : "Izbrišite",
"Select a profile picture" : "Odaberite sliku profila",
"Very weak password" : "Lozinka vrlo slaba",
"Weak password" : "Lozinka slaba",
"So-so password" : "Lozinka tako-tako",
"Good password" : "Lozinka dobra",
"Strong password" : "Lozinka snažna",
- "Valid until {date}" : "Valid until {date}",
- "Delete" : "Izbrišite",
"Groups" : "Grupe",
"Unable to delete {objName}" : "Nije moguće izbrisati {objName}",
"Error creating group" : "Pogrešno kreiranje grupe",
@@ -63,7 +63,6 @@ OC.L10N.register(
"Error creating user" : "Pogrešno kreiranje korisnika",
"A valid password must be provided" : "Nužno je navesti valjanu lozinku",
"__language_name__" : "__jezik_naziv___",
- "SSL root certificates" : "SSL Root certifikati",
"Everything (fatal issues, errors, warnings, info, debug)" : "Sve (kobni problemi, pogreške, upozorenja, ispravljanje pogrešaka)",
"Info, warnings, errors and fatal issues" : "Informacije, upozorenja, pogreške i kobni problemi",
"Warnings, errors and fatal issues" : "Upozorenja, pogreške i kobni problemi",
@@ -111,40 +110,33 @@ OC.L10N.register(
"SMTP Password" : "Lozinka SMPT",
"Test email settings" : "Postavke za testnu e-poštu",
"Send email" : "Pošaljite e-poštu",
- "Log level" : "Razina zapisnika",
"More" : "Više",
"Less" : "Manje",
"Version" : "Verzija",
- "by" : "od strane",
"Documentation:" : "Dokumentacija:",
"Enable only for specific groups" : "Omogućite samo za specifične grupe",
"Uninstall App" : "Deinstalirajte app",
+ "Common Name" : "Common Name",
+ "Valid until" : "Valid until",
+ "Issued By" : "Issued By",
+ "Valid until %s" : "Valid until %s",
"Cheers!" : "Cheers!",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Koristite aplikacije za sinkronizaciju svojih datoteka",
- "Show First Run Wizard again" : "Opet pokažite First Run Wizard",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Iskoristili ste <strong>%s</strong> od raspoloživog <strong>%s</strong>",
+ "Profile picture" : "Slika profila",
+ "Upload new" : "Učitajte novu",
+ "Remove image" : "Uklonite sliku",
+ "Cancel" : "Odustanite",
+ "Email" : "E-pošta",
+ "Your email address" : "Vaša adresa e-pošte",
"Password" : "Lozinka",
"Unable to change your password" : "Vašu lozinku nije moguće promijeniti",
"Current password" : "Trenutna lozinka",
"New password" : "Nova lozinka",
"Change password" : "Promijenite lozinku",
- "Email" : "E-pošta",
- "Your email address" : "Vaša adresa e-pošte",
- "Fill in an email address to enable password recovery and receive notifications" : "Unesite adresu e-pošte da biste omogućili oporavak lozinke i primili notifikacije",
- "Profile picture" : "Slika profila",
- "Upload new" : "Učitajte novu",
- "Select new from Files" : "Odaberite novu iz datoteka",
- "Remove image" : "Uklonite sliku",
- "Your avatar is provided by your original account." : "Vaš avatar je isporučen od strane vašeg izvornog računa",
- "Cancel" : "Odustanite",
- "Choose as profile image" : "Odaberite kao sliku profila",
"Language" : "Jezik",
"Help translate" : "Pomozite prevesti",
- "Common Name" : "Common Name",
- "Valid until" : "Valid until",
- "Issued By" : "Issued By",
- "Valid until %s" : "Valid until %s",
+ "Get the apps to sync your files" : "Koristite aplikacije za sinkronizaciju svojih datoteka",
+ "Show First Run Wizard again" : "Opet pokažite First Run Wizard",
"Show storage location" : "Prikaži mjesto pohrane",
"Show last log in" : "Prikaži zadnje spajanje",
"Username" : "Korisničko ime",
diff --git a/settings/l10n/hr.json b/settings/l10n/hr.json
index 6cee1ef82aa..44aacb82834 100644
--- a/settings/l10n/hr.json
+++ b/settings/l10n/hr.json
@@ -4,12 +4,10 @@
"Cron" : "Cron",
"Log" : "Zapisnik",
"Updates" : "nadogradnje",
- "Authentication error" : "Pogrešna autentikacija",
- "Your full name has been changed." : "Vaše puno ime je promijenjeno.",
- "Unable to change full name" : "Puno ime nije moguće promijeniti.",
"Couldn't remove app." : "Nije moguće ukloniti app.",
"Language changed" : "Promjena jezika",
"Invalid request" : "Zahtjev neispravan",
+ "Authentication error" : "Pogrešna autentikacija",
"Admins can't remove themself from the admin group" : "Administratori ne mogu sami sebe ukloniti iz admin grupe",
"Unable to add user to group %s" : "Dodavanje korisnika grupi %s nije moguće",
"Unable to remove user from group %s" : "Uklanjanje korisnika iz grupe %s nije moguće",
@@ -25,6 +23,8 @@
"Email sent" : "E-pošta je poslana",
"You need to set your user email before being able to send test emails." : "Prije nego li ste u mogućnosti slati testnu e-poštu trebate postaviti svoj korisnički email.",
"Email saved" : "E-pošta spremljena",
+ "Your full name has been changed." : "Vaše puno ime je promijenjeno.",
+ "Unable to change full name" : "Puno ime nije moguće promijeniti.",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Jeste li doista sigurni da želite dodati \"{domain}\" kao pouzdanu domenu?",
"Add trusted domain" : "Dodajte pouzdanu domenu",
"Sending..." : "Slanje...",
@@ -40,14 +40,14 @@
"Uninstalling ...." : "Deinstaliranje....",
"Error while uninstalling app" : "Pogreška pri deinstaliranju app",
"Uninstall" : "Deinstalirajte",
+ "Valid until {date}" : "Valid until {date}",
+ "Delete" : "Izbrišite",
"Select a profile picture" : "Odaberite sliku profila",
"Very weak password" : "Lozinka vrlo slaba",
"Weak password" : "Lozinka slaba",
"So-so password" : "Lozinka tako-tako",
"Good password" : "Lozinka dobra",
"Strong password" : "Lozinka snažna",
- "Valid until {date}" : "Valid until {date}",
- "Delete" : "Izbrišite",
"Groups" : "Grupe",
"Unable to delete {objName}" : "Nije moguće izbrisati {objName}",
"Error creating group" : "Pogrešno kreiranje grupe",
@@ -61,7 +61,6 @@
"Error creating user" : "Pogrešno kreiranje korisnika",
"A valid password must be provided" : "Nužno je navesti valjanu lozinku",
"__language_name__" : "__jezik_naziv___",
- "SSL root certificates" : "SSL Root certifikati",
"Everything (fatal issues, errors, warnings, info, debug)" : "Sve (kobni problemi, pogreške, upozorenja, ispravljanje pogrešaka)",
"Info, warnings, errors and fatal issues" : "Informacije, upozorenja, pogreške i kobni problemi",
"Warnings, errors and fatal issues" : "Upozorenja, pogreške i kobni problemi",
@@ -109,40 +108,33 @@
"SMTP Password" : "Lozinka SMPT",
"Test email settings" : "Postavke za testnu e-poštu",
"Send email" : "Pošaljite e-poštu",
- "Log level" : "Razina zapisnika",
"More" : "Više",
"Less" : "Manje",
"Version" : "Verzija",
- "by" : "od strane",
"Documentation:" : "Dokumentacija:",
"Enable only for specific groups" : "Omogućite samo za specifične grupe",
"Uninstall App" : "Deinstalirajte app",
+ "Common Name" : "Common Name",
+ "Valid until" : "Valid until",
+ "Issued By" : "Issued By",
+ "Valid until %s" : "Valid until %s",
"Cheers!" : "Cheers!",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Koristite aplikacije za sinkronizaciju svojih datoteka",
- "Show First Run Wizard again" : "Opet pokažite First Run Wizard",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Iskoristili ste <strong>%s</strong> od raspoloživog <strong>%s</strong>",
+ "Profile picture" : "Slika profila",
+ "Upload new" : "Učitajte novu",
+ "Remove image" : "Uklonite sliku",
+ "Cancel" : "Odustanite",
+ "Email" : "E-pošta",
+ "Your email address" : "Vaša adresa e-pošte",
"Password" : "Lozinka",
"Unable to change your password" : "Vašu lozinku nije moguće promijeniti",
"Current password" : "Trenutna lozinka",
"New password" : "Nova lozinka",
"Change password" : "Promijenite lozinku",
- "Email" : "E-pošta",
- "Your email address" : "Vaša adresa e-pošte",
- "Fill in an email address to enable password recovery and receive notifications" : "Unesite adresu e-pošte da biste omogućili oporavak lozinke i primili notifikacije",
- "Profile picture" : "Slika profila",
- "Upload new" : "Učitajte novu",
- "Select new from Files" : "Odaberite novu iz datoteka",
- "Remove image" : "Uklonite sliku",
- "Your avatar is provided by your original account." : "Vaš avatar je isporučen od strane vašeg izvornog računa",
- "Cancel" : "Odustanite",
- "Choose as profile image" : "Odaberite kao sliku profila",
"Language" : "Jezik",
"Help translate" : "Pomozite prevesti",
- "Common Name" : "Common Name",
- "Valid until" : "Valid until",
- "Issued By" : "Issued By",
- "Valid until %s" : "Valid until %s",
+ "Get the apps to sync your files" : "Koristite aplikacije za sinkronizaciju svojih datoteka",
+ "Show First Run Wizard again" : "Opet pokažite First Run Wizard",
"Show storage location" : "Prikaži mjesto pohrane",
"Show last log in" : "Prikaži zadnje spajanje",
"Username" : "Korisničko ime",
diff --git a/settings/l10n/hu_HU.js b/settings/l10n/hu_HU.js
index 2cbcb3e822a..c4f92e2840a 100644
--- a/settings/l10n/hu_HU.js
+++ b/settings/l10n/hu_HU.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Naplózás",
"Tips & tricks" : "Tippek és trükkök",
"Updates" : "Frissítések",
- "Authentication error" : "Azonosítási hiba",
- "Your full name has been changed." : "Az Ön teljes nevét módosítottuk.",
- "Unable to change full name" : "Nem sikerült megváltoztatni a teljes nevét",
"Couldn't remove app." : "Az alkalmazást nem sikerült eltávolítani.",
"Language changed" : "A nyelv megváltozott",
"Invalid request" : "Érvénytelen kérés",
+ "Authentication error" : "Azonosítási hiba",
"Admins can't remove themself from the admin group" : "Adminisztrátorok nem távolíthatják el magukat az admin csoportból.",
"Unable to add user to group %s" : "A felhasználó nem adható hozzá ehhez a csoporthoz: %s",
"Unable to remove user from group %s" : "A felhasználó nem távolítható el ebből a csoportból: %s",
@@ -37,6 +35,7 @@ OC.L10N.register(
"Group already exists." : "A csoport már létezik.",
"Unable to add group." : "Nem lehet létrehozni a csoportot.",
"Unable to delete group." : "Nem lehet törölni a csoportot.",
+ "log-level out of allowed range" : "A naplózási szint a megengedett terjedelmen kívül van.",
"Saved" : "Elmentve",
"test email settings" : "e-mail beállítások ellenőrzése",
"A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "Hiba történt az e-mail küldésekor. Kérjük ellenőrizd a beállításokat! (Hiba: %s)",
@@ -51,6 +50,8 @@ OC.L10N.register(
"Invalid user" : "Érvénytelen felhasználó",
"Unable to change mail address" : "Nem lehet megváltoztatni az e-mail címet",
"Email saved" : "E-mail elmentve!",
+ "Your full name has been changed." : "Az Ön teljes nevét módosítottuk.",
+ "Unable to change full name" : "Nem sikerült megváltoztatni a teljes nevét",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Biztos abban, hogy hozzá akarja adni \"{domain}\"-t a megbízható tartományokhoz?",
"Add trusted domain" : "Megbízható tartomány hozzáadása",
"Migration in progress. Please wait until the migration is finished" : "Migráció folyamatban. Kérjük várj, míg a migráció befejeződik.",
@@ -61,6 +62,7 @@ OC.L10N.register(
"Experimental" : "Kísérleti",
"All" : "Mind",
"No apps found for your version" : "Nem található alkalmazás a verziód számára",
+ "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "A hivatalos alkalmazásokat az ownCloud közösségen belül fejlesztik. \nAz általuk nyújtott központi ownCloud funkciók készen állnak a produktív használatra.",
"This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "Ez az alkalmazás még nincs biztonságilag ellenőrizve és vagy új, vagy ismert instabil. Telepítés csak saját felelősségre!",
"Update to %s" : "Frissítés erre: %s",
"Please wait...." : "Kérjük várj...",
@@ -75,6 +77,10 @@ OC.L10N.register(
"Error while uninstalling app" : "Hiba történt az alkalmazás eltávolítása közben",
"Uninstall" : "Eltávolítás",
"App update" : "Alkalmazás frissítése",
+ "No apps found for \"{query}\"" : "Nem található alkalmazás a „{query}” lekérdezésre.",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Hiba történt! Kérem töltsön fel egy, ASCII karakterekkel kódolt PEM tanusítványt!",
+ "Valid until {date}" : "Érvényes: {date}",
+ "Delete" : "Törlés",
"An error occurred: {message}" : "Hiba történt: {message}",
"Select a profile picture" : "Válasszon profilképet!",
"Very weak password" : "Nagyon gyenge jelszó",
@@ -82,8 +88,6 @@ OC.L10N.register(
"So-so password" : "Nem túl jó jelszó",
"Good password" : "Jó jelszó",
"Strong password" : "Erős jelszó",
- "Valid until {date}" : "Érvényes: {date}",
- "Delete" : "Törlés",
"Groups" : "Csoportok",
"Unable to delete {objName}" : "Ezt nem sikerült törölni: {objName}",
"Error creating group" : "Hiba történt a csoport létrehozása közben",
@@ -94,14 +98,14 @@ OC.L10N.register(
"never" : "soha",
"deleted {userName}" : "törölve: {userName}",
"add group" : "csoport hozzáadása",
+ "Changing the password will result in data loss, because data recovery is not available for this user" : "A jelszó megváltoztatása adatvesztéssel jár, mert lehetséges az adatok visszaállítása ennek a felhasználónak",
"A valid username must be provided" : "Érvényes felhasználónevet kell megadnia",
"Error creating user" : "A felhasználó nem hozható létre",
"A valid password must be provided" : "Érvényes jelszót kell megadnia",
"A valid email must be provided" : "Érvényes e-mail címet kell megadni",
"__language_name__" : "__language_name__",
- "Sync clients" : "Szinkronizáló kliensek",
"Personal info" : "Személyes információk",
- "SSL root certificates" : "SSL tanúsítványok",
+ "Sync clients" : "Szinkronizáló kliensek",
"Everything (fatal issues, errors, warnings, info, debug)" : "Minden (végzetes hibák, hibák, figyelmeztetések, információk, hibakeresési üzenetek)",
"Info, warnings, errors and fatal issues" : "Információk, figyelmeztetések, hibák és végzetes hibák",
"Warnings, errors and fatal issues" : "Figyelmeztetések, hibák és végzetes hibák",
@@ -149,6 +153,7 @@ OC.L10N.register(
"Use system's cron service to call the cron.php file every 15 minutes." : "A rendszer cron szolgáltatását használjuk, mely a cron.php állományt futtatja le 15 percenként.",
"Enable server-side encryption" : "Szerveroldali titkosítás engedélyezése",
"Please read carefully before activating server-side encryption: " : "Kérjük, ezt olvasd el figyelmesen mielőtt engedélyezed a szerveroldali titkosítást:",
+ "Be aware that encryption always increases the file size." : "Ügyeljen arra, hogy a titkosítás mindig megnöveli a fájl méretét!",
"This is the final warning: Do you really want to enable encryption?" : "Ez az utolsó figyelmeztetés: Biztosan szeretnéd engedélyezni a titkosítást?",
"Enable encryption" : "Titkosítás engedélyezése",
"No encryption module loaded, please enable an encryption module in the app menu." : "Nincs titkosítási modul betöltve, kérjük engedélyezd a titkosítási modult az alkalmazások menüben.",
@@ -171,11 +176,11 @@ OC.L10N.register(
"Store credentials" : "Azonosítók eltárolása",
"Test email settings" : "Az e-mail beállítások ellenőrzése",
"Send email" : "E-mail küldése",
- "Log level" : "Naplózási szint",
"Download logfile" : "Naplófájl letöltése",
"More" : "Több",
"Less" : "Kevesebb",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "A naplófájl 100MB-nál nagyobb. A letöltése hosszabb időt vehet igénybe.",
+ "What to log" : "Mit naplózzon",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Adatbázisként az SQLite-ot fogjuk használni. Nagyobb telepítések esetén javasoljuk, hogy váltson másik adatbázis háttérkiszolgálóra",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Amikor az asztali klienset használja fálj szinkronizációra, akkor az SQLite használata nem ajánlott.",
"How to do backups" : "Hogyan csináljunk biztonsági mentéseket",
@@ -188,17 +193,23 @@ OC.L10N.register(
"Developer documentation" : "Fejlesztői dokumentáció",
"Experimental applications ahead" : "Kísérleti alkalmazások előre",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "A kísérleti applikációk nincsenek biztonsági ellenőrizve, ismert vagy ismeretlen hibák lehetnek bennük és aktív fejlesztés alatt állnak. A telepítésük adatvesztéshez vezethet, vagy biztonsági kockázata lehet.",
- "by" : "közreadta:",
- "licensed" : "licencelt",
"Documentation:" : "Dokumentációk:",
"User documentation" : "Felhasználói dokumentáció",
"Admin documentation" : "Adminisztrátori dokumentáció",
"Show description …" : "Leírás megjelenítése ...",
"Hide description …" : "Leírás elrejtése ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Ennek az alkalmazásnak nincs minimális ownCloud verzió megadva. Ez hibát okoz majd az ownCloud 11-es és későbbi verziókban.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Ennek az alkalmazásnak nincs maximális ownCloud verzió megadva. Ez hibát okoz majd az ownCloud 11-es és későbbi verziókban.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Ezt az applikációt nem lehet telepíteni, mert a következő függőségek hiányoznak:",
"Enable only for specific groups" : "Csak bizonyos csoportok számára tegyük elérhetővé",
"Uninstall App" : "Alkalmazás eltávolítása",
"Enable experimental apps" : "Kísérleti alkalmazások engedélyezése",
+ "SSL Root Certificates" : "SSL Root tanusítványok",
+ "Common Name" : "Általános Név",
+ "Valid until" : "Érvényes",
+ "Issued By" : "Kiadta",
+ "Valid until %s" : "Érvényes: %s",
+ "Import root certificate" : "Gyökértanúsítvány importálása",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Üdv!<br><br>Értesítünk, hogy van egy %s fiókja.<br><br>Felhasználónév: %s<br>Hozzáférés: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Üdv.",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Üdv!\n\nÉrtesítünk, hogy van egy %s fiókja.\n\nFelhasználónév: %s\nHozzáférés: %s\n\n",
@@ -207,40 +218,32 @@ OC.L10N.register(
"Forum" : "Fórum",
"Issue tracker" : "Hibabejelentések",
"Commercial support" : "Kereskedelmi támogatás",
- "Get the apps to sync your files" : "Töltse le az állományok szinkronizációjához szükséges programokat!",
- "Desktop client" : "Asztali kliens",
- "Android app" : "Android applikáció",
- "iOS app" : "IOS applikáció",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ha segíteni szeretnéd a projektet\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">csatlakozz a fejlesztéshez</a>\n\t\tvagy\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">hirdesd az igét</a>!",
- "Show First Run Wizard again" : "Nézzük meg újra az első bejelentkezéskori segítséget!",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Az Ön tárterület-felhasználása jelenleg: <strong>%s</strong>. Maximálisan ennyi áll rendelkezésére: <strong>%s</strong>",
- "Password" : "Jelszó",
- "Unable to change your password" : "A jelszó nem változtatható meg",
- "Current password" : "A jelenlegi jelszó",
- "New password" : "Az új jelszó",
- "Change password" : "A jelszó megváltoztatása",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Jelenleg használt: <strong>%s</strong>, maximálisan elérhető: <strong>%s</strong>",
+ "Profile picture" : "Profilkép",
+ "Upload new" : "Új feltöltése",
+ "Remove image" : "A kép eltávolítása",
+ "png or jpg, max. 20 MB" : "png vagy jpg, max. 20 MB",
+ "Cancel" : "Mégsem",
+ "Choose as profile picture" : "Kiválasztás profil képként",
"Full name" : "Teljes név",
"No display name set" : "Nincs megjelenítési név beállítva",
"Email" : "E-mail",
"Your email address" : "Az Ön e-mail címe",
- "Fill in an email address to enable password recovery and receive notifications" : "Adja meg az e-mail címét, hogy vissza tudja állítani a jelszavát, illetve, hogy rendszeres jelentéseket kaphasson!",
"No email address set" : "Nincs e-mail cím beállítva",
"You are member of the following groups:" : "Tagja vagy a következő csoport(ok)nak:",
- "Profile picture" : "Profilkép",
- "Upload new" : "Új feltöltése",
- "Select new from Files" : "Új kiválasztása a Fájlokból",
- "Remove image" : "A kép eltávolítása",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Csak png vagy jpg lehet. Ideális esetben négyzet alakú, de lehetőséged lesz vágni. A fájl nem haladhatja meg a 20 MB-os méretet.",
- "Your avatar is provided by your original account." : "A kép az eredeti bejelentkezési adatai alapján lett beállítva.",
- "Cancel" : "Mégsem",
- "Choose as profile image" : "Válasszuk ki profilképnek",
+ "Password" : "Jelszó",
+ "Unable to change your password" : "A jelszó nem változtatható meg",
+ "Current password" : "A jelenlegi jelszó",
+ "New password" : "Az új jelszó",
+ "Change password" : "A jelszó megváltoztatása",
"Language" : "Nyelv",
"Help translate" : "Segítsen a fordításban!",
- "Common Name" : "Általános Név",
- "Valid until" : "Érvényes",
- "Issued By" : "Kiadta",
- "Valid until %s" : "Érvényes: %s",
- "Import root certificate" : "Gyökértanúsítvány importálása",
+ "Get the apps to sync your files" : "Töltse le az állományok szinkronizációjához szükséges programokat!",
+ "Desktop client" : "Asztali kliens",
+ "Android app" : "Android applikáció",
+ "iOS app" : "IOS applikáció",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ha segíteni szeretnéd a projektet\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">csatlakozz a fejlesztéshez</a>\n\t\tvagy\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">hirdesd az igét</a>!",
+ "Show First Run Wizard again" : "Nézzük meg újra az első bejelentkezéskori segítséget!",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "{communityopen}ownCloud közösség{linkclose} fejleszti, a {githubopen}forráskód{linkclose} {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} licenc alatt licencelve.",
"Show storage location" : "Háttértároló helyének mutatása",
"Show last log in" : "Utolsó bejelentkezés megjelenítése",
diff --git a/settings/l10n/hu_HU.json b/settings/l10n/hu_HU.json
index 44bebd90c4d..73547b4ca48 100644
--- a/settings/l10n/hu_HU.json
+++ b/settings/l10n/hu_HU.json
@@ -10,12 +10,10 @@
"Log" : "Naplózás",
"Tips & tricks" : "Tippek és trükkök",
"Updates" : "Frissítések",
- "Authentication error" : "Azonosítási hiba",
- "Your full name has been changed." : "Az Ön teljes nevét módosítottuk.",
- "Unable to change full name" : "Nem sikerült megváltoztatni a teljes nevét",
"Couldn't remove app." : "Az alkalmazást nem sikerült eltávolítani.",
"Language changed" : "A nyelv megváltozott",
"Invalid request" : "Érvénytelen kérés",
+ "Authentication error" : "Azonosítási hiba",
"Admins can't remove themself from the admin group" : "Adminisztrátorok nem távolíthatják el magukat az admin csoportból.",
"Unable to add user to group %s" : "A felhasználó nem adható hozzá ehhez a csoporthoz: %s",
"Unable to remove user from group %s" : "A felhasználó nem távolítható el ebből a csoportból: %s",
@@ -35,6 +33,7 @@
"Group already exists." : "A csoport már létezik.",
"Unable to add group." : "Nem lehet létrehozni a csoportot.",
"Unable to delete group." : "Nem lehet törölni a csoportot.",
+ "log-level out of allowed range" : "A naplózási szint a megengedett terjedelmen kívül van.",
"Saved" : "Elmentve",
"test email settings" : "e-mail beállítások ellenőrzése",
"A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "Hiba történt az e-mail küldésekor. Kérjük ellenőrizd a beállításokat! (Hiba: %s)",
@@ -49,6 +48,8 @@
"Invalid user" : "Érvénytelen felhasználó",
"Unable to change mail address" : "Nem lehet megváltoztatni az e-mail címet",
"Email saved" : "E-mail elmentve!",
+ "Your full name has been changed." : "Az Ön teljes nevét módosítottuk.",
+ "Unable to change full name" : "Nem sikerült megváltoztatni a teljes nevét",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Biztos abban, hogy hozzá akarja adni \"{domain}\"-t a megbízható tartományokhoz?",
"Add trusted domain" : "Megbízható tartomány hozzáadása",
"Migration in progress. Please wait until the migration is finished" : "Migráció folyamatban. Kérjük várj, míg a migráció befejeződik.",
@@ -59,6 +60,7 @@
"Experimental" : "Kísérleti",
"All" : "Mind",
"No apps found for your version" : "Nem található alkalmazás a verziód számára",
+ "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "A hivatalos alkalmazásokat az ownCloud közösségen belül fejlesztik. \nAz általuk nyújtott központi ownCloud funkciók készen állnak a produktív használatra.",
"This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "Ez az alkalmazás még nincs biztonságilag ellenőrizve és vagy új, vagy ismert instabil. Telepítés csak saját felelősségre!",
"Update to %s" : "Frissítés erre: %s",
"Please wait...." : "Kérjük várj...",
@@ -73,6 +75,10 @@
"Error while uninstalling app" : "Hiba történt az alkalmazás eltávolítása közben",
"Uninstall" : "Eltávolítás",
"App update" : "Alkalmazás frissítése",
+ "No apps found for \"{query}\"" : "Nem található alkalmazás a „{query}” lekérdezésre.",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Hiba történt! Kérem töltsön fel egy, ASCII karakterekkel kódolt PEM tanusítványt!",
+ "Valid until {date}" : "Érvényes: {date}",
+ "Delete" : "Törlés",
"An error occurred: {message}" : "Hiba történt: {message}",
"Select a profile picture" : "Válasszon profilképet!",
"Very weak password" : "Nagyon gyenge jelszó",
@@ -80,8 +86,6 @@
"So-so password" : "Nem túl jó jelszó",
"Good password" : "Jó jelszó",
"Strong password" : "Erős jelszó",
- "Valid until {date}" : "Érvényes: {date}",
- "Delete" : "Törlés",
"Groups" : "Csoportok",
"Unable to delete {objName}" : "Ezt nem sikerült törölni: {objName}",
"Error creating group" : "Hiba történt a csoport létrehozása közben",
@@ -92,14 +96,14 @@
"never" : "soha",
"deleted {userName}" : "törölve: {userName}",
"add group" : "csoport hozzáadása",
+ "Changing the password will result in data loss, because data recovery is not available for this user" : "A jelszó megváltoztatása adatvesztéssel jár, mert lehetséges az adatok visszaállítása ennek a felhasználónak",
"A valid username must be provided" : "Érvényes felhasználónevet kell megadnia",
"Error creating user" : "A felhasználó nem hozható létre",
"A valid password must be provided" : "Érvényes jelszót kell megadnia",
"A valid email must be provided" : "Érvényes e-mail címet kell megadni",
"__language_name__" : "__language_name__",
- "Sync clients" : "Szinkronizáló kliensek",
"Personal info" : "Személyes információk",
- "SSL root certificates" : "SSL tanúsítványok",
+ "Sync clients" : "Szinkronizáló kliensek",
"Everything (fatal issues, errors, warnings, info, debug)" : "Minden (végzetes hibák, hibák, figyelmeztetések, információk, hibakeresési üzenetek)",
"Info, warnings, errors and fatal issues" : "Információk, figyelmeztetések, hibák és végzetes hibák",
"Warnings, errors and fatal issues" : "Figyelmeztetések, hibák és végzetes hibák",
@@ -147,6 +151,7 @@
"Use system's cron service to call the cron.php file every 15 minutes." : "A rendszer cron szolgáltatását használjuk, mely a cron.php állományt futtatja le 15 percenként.",
"Enable server-side encryption" : "Szerveroldali titkosítás engedélyezése",
"Please read carefully before activating server-side encryption: " : "Kérjük, ezt olvasd el figyelmesen mielőtt engedélyezed a szerveroldali titkosítást:",
+ "Be aware that encryption always increases the file size." : "Ügyeljen arra, hogy a titkosítás mindig megnöveli a fájl méretét!",
"This is the final warning: Do you really want to enable encryption?" : "Ez az utolsó figyelmeztetés: Biztosan szeretnéd engedélyezni a titkosítást?",
"Enable encryption" : "Titkosítás engedélyezése",
"No encryption module loaded, please enable an encryption module in the app menu." : "Nincs titkosítási modul betöltve, kérjük engedélyezd a titkosítási modult az alkalmazások menüben.",
@@ -169,11 +174,11 @@
"Store credentials" : "Azonosítók eltárolása",
"Test email settings" : "Az e-mail beállítások ellenőrzése",
"Send email" : "E-mail küldése",
- "Log level" : "Naplózási szint",
"Download logfile" : "Naplófájl letöltése",
"More" : "Több",
"Less" : "Kevesebb",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "A naplófájl 100MB-nál nagyobb. A letöltése hosszabb időt vehet igénybe.",
+ "What to log" : "Mit naplózzon",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Adatbázisként az SQLite-ot fogjuk használni. Nagyobb telepítések esetén javasoljuk, hogy váltson másik adatbázis háttérkiszolgálóra",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Amikor az asztali klienset használja fálj szinkronizációra, akkor az SQLite használata nem ajánlott.",
"How to do backups" : "Hogyan csináljunk biztonsági mentéseket",
@@ -186,17 +191,23 @@
"Developer documentation" : "Fejlesztői dokumentáció",
"Experimental applications ahead" : "Kísérleti alkalmazások előre",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "A kísérleti applikációk nincsenek biztonsági ellenőrizve, ismert vagy ismeretlen hibák lehetnek bennük és aktív fejlesztés alatt állnak. A telepítésük adatvesztéshez vezethet, vagy biztonsági kockázata lehet.",
- "by" : "közreadta:",
- "licensed" : "licencelt",
"Documentation:" : "Dokumentációk:",
"User documentation" : "Felhasználói dokumentáció",
"Admin documentation" : "Adminisztrátori dokumentáció",
"Show description …" : "Leírás megjelenítése ...",
"Hide description …" : "Leírás elrejtése ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Ennek az alkalmazásnak nincs minimális ownCloud verzió megadva. Ez hibát okoz majd az ownCloud 11-es és későbbi verziókban.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Ennek az alkalmazásnak nincs maximális ownCloud verzió megadva. Ez hibát okoz majd az ownCloud 11-es és későbbi verziókban.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Ezt az applikációt nem lehet telepíteni, mert a következő függőségek hiányoznak:",
"Enable only for specific groups" : "Csak bizonyos csoportok számára tegyük elérhetővé",
"Uninstall App" : "Alkalmazás eltávolítása",
"Enable experimental apps" : "Kísérleti alkalmazások engedélyezése",
+ "SSL Root Certificates" : "SSL Root tanusítványok",
+ "Common Name" : "Általános Név",
+ "Valid until" : "Érvényes",
+ "Issued By" : "Kiadta",
+ "Valid until %s" : "Érvényes: %s",
+ "Import root certificate" : "Gyökértanúsítvány importálása",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Üdv!<br><br>Értesítünk, hogy van egy %s fiókja.<br><br>Felhasználónév: %s<br>Hozzáférés: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Üdv.",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Üdv!\n\nÉrtesítünk, hogy van egy %s fiókja.\n\nFelhasználónév: %s\nHozzáférés: %s\n\n",
@@ -205,40 +216,32 @@
"Forum" : "Fórum",
"Issue tracker" : "Hibabejelentések",
"Commercial support" : "Kereskedelmi támogatás",
- "Get the apps to sync your files" : "Töltse le az állományok szinkronizációjához szükséges programokat!",
- "Desktop client" : "Asztali kliens",
- "Android app" : "Android applikáció",
- "iOS app" : "IOS applikáció",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ha segíteni szeretnéd a projektet\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">csatlakozz a fejlesztéshez</a>\n\t\tvagy\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">hirdesd az igét</a>!",
- "Show First Run Wizard again" : "Nézzük meg újra az első bejelentkezéskori segítséget!",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Az Ön tárterület-felhasználása jelenleg: <strong>%s</strong>. Maximálisan ennyi áll rendelkezésére: <strong>%s</strong>",
- "Password" : "Jelszó",
- "Unable to change your password" : "A jelszó nem változtatható meg",
- "Current password" : "A jelenlegi jelszó",
- "New password" : "Az új jelszó",
- "Change password" : "A jelszó megváltoztatása",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Jelenleg használt: <strong>%s</strong>, maximálisan elérhető: <strong>%s</strong>",
+ "Profile picture" : "Profilkép",
+ "Upload new" : "Új feltöltése",
+ "Remove image" : "A kép eltávolítása",
+ "png or jpg, max. 20 MB" : "png vagy jpg, max. 20 MB",
+ "Cancel" : "Mégsem",
+ "Choose as profile picture" : "Kiválasztás profil képként",
"Full name" : "Teljes név",
"No display name set" : "Nincs megjelenítési név beállítva",
"Email" : "E-mail",
"Your email address" : "Az Ön e-mail címe",
- "Fill in an email address to enable password recovery and receive notifications" : "Adja meg az e-mail címét, hogy vissza tudja állítani a jelszavát, illetve, hogy rendszeres jelentéseket kaphasson!",
"No email address set" : "Nincs e-mail cím beállítva",
"You are member of the following groups:" : "Tagja vagy a következő csoport(ok)nak:",
- "Profile picture" : "Profilkép",
- "Upload new" : "Új feltöltése",
- "Select new from Files" : "Új kiválasztása a Fájlokból",
- "Remove image" : "A kép eltávolítása",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Csak png vagy jpg lehet. Ideális esetben négyzet alakú, de lehetőséged lesz vágni. A fájl nem haladhatja meg a 20 MB-os méretet.",
- "Your avatar is provided by your original account." : "A kép az eredeti bejelentkezési adatai alapján lett beállítva.",
- "Cancel" : "Mégsem",
- "Choose as profile image" : "Válasszuk ki profilképnek",
+ "Password" : "Jelszó",
+ "Unable to change your password" : "A jelszó nem változtatható meg",
+ "Current password" : "A jelenlegi jelszó",
+ "New password" : "Az új jelszó",
+ "Change password" : "A jelszó megváltoztatása",
"Language" : "Nyelv",
"Help translate" : "Segítsen a fordításban!",
- "Common Name" : "Általános Név",
- "Valid until" : "Érvényes",
- "Issued By" : "Kiadta",
- "Valid until %s" : "Érvényes: %s",
- "Import root certificate" : "Gyökértanúsítvány importálása",
+ "Get the apps to sync your files" : "Töltse le az állományok szinkronizációjához szükséges programokat!",
+ "Desktop client" : "Asztali kliens",
+ "Android app" : "Android applikáció",
+ "iOS app" : "IOS applikáció",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ha segíteni szeretnéd a projektet\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">csatlakozz a fejlesztéshez</a>\n\t\tvagy\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">hirdesd az igét</a>!",
+ "Show First Run Wizard again" : "Nézzük meg újra az első bejelentkezéskori segítséget!",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "{communityopen}ownCloud közösség{linkclose} fejleszti, a {githubopen}forráskód{linkclose} {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} licenc alatt licencelve.",
"Show storage location" : "Háttértároló helyének mutatása",
"Show last log in" : "Utolsó bejelentkezés megjelenítése",
diff --git a/settings/l10n/hy.js b/settings/l10n/hy.js
index bc0e467826b..25c6ad4b587 100644
--- a/settings/l10n/hy.js
+++ b/settings/l10n/hy.js
@@ -2,21 +2,22 @@ OC.L10N.register(
"settings",
{
"Language changed" : "Լեզուն փոխվեց",
+ "Delete" : "Ջնջել",
"Very weak password" : "Շատ թույլ գաղտնաբառ",
"Weak password" : "Թույլ գաղտնաբառ",
"Good password" : "Լավ գաղտնաբառ",
- "Delete" : "Ջնջել",
"Groups" : "Խմբեր",
"never" : "երբեք",
"add group" : "խումբ ավելացնել",
"SSL" : "SSL",
"TLS" : "TLS",
+ "Cancel" : "Չեղարկել",
+ "Email" : "Էլ. հասցե",
"Password" : "Գաղտնաբառ",
"New password" : "Նոր գաղտնաբառ",
- "Email" : "Էլ. հասցե",
- "Cancel" : "Չեղարկել",
"Language" : "Լեզու",
"Help translate" : "Օգնել թարգմանել",
+ "Username" : "Օգտանուն",
"Group" : "Խումբ",
"Other" : "Այլ"
},
diff --git a/settings/l10n/hy.json b/settings/l10n/hy.json
index 26cfdf5c9a7..7fddfe1a132 100644
--- a/settings/l10n/hy.json
+++ b/settings/l10n/hy.json
@@ -1,20 +1,21 @@
{ "translations": {
"Language changed" : "Լեզուն փոխվեց",
+ "Delete" : "Ջնջել",
"Very weak password" : "Շատ թույլ գաղտնաբառ",
"Weak password" : "Թույլ գաղտնաբառ",
"Good password" : "Լավ գաղտնաբառ",
- "Delete" : "Ջնջել",
"Groups" : "Խմբեր",
"never" : "երբեք",
"add group" : "խումբ ավելացնել",
"SSL" : "SSL",
"TLS" : "TLS",
+ "Cancel" : "Չեղարկել",
+ "Email" : "Էլ. հասցե",
"Password" : "Գաղտնաբառ",
"New password" : "Նոր գաղտնաբառ",
- "Email" : "Էլ. հասցե",
- "Cancel" : "Չեղարկել",
"Language" : "Լեզու",
"Help translate" : "Օգնել թարգմանել",
+ "Username" : "Օգտանուն",
"Group" : "Խումբ",
"Other" : "Այլ"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/settings/l10n/ia.js b/settings/l10n/ia.js
index 0c06c89fc7b..a4d027b7b37 100644
--- a/settings/l10n/ia.js
+++ b/settings/l10n/ia.js
@@ -9,30 +9,29 @@ OC.L10N.register(
"Saved" : "Salveguardate",
"Email sent" : "Message de e-posta inviate",
"All" : "Omne",
+ "Delete" : "Deler",
"Very weak password" : "Contrasigno multo debile",
"Weak password" : "Contrasigno debile",
"So-so password" : "Contrasigno passabile",
"Good password" : "Contrasigno bon",
"Strong password" : "Contrasigno forte",
- "Delete" : "Deler",
"Groups" : "Gruppos",
"never" : "nunquam",
"__language_name__" : "Interlingua",
"More" : "Plus",
- "by" : "per",
"Cheers!" : "Acclamationes!",
- "Get the apps to sync your files" : "Obtene le apps (applicationes) pro synchronizar tu files",
+ "Profile picture" : "Imagine de profilo",
+ "Cancel" : "Cancellar",
+ "Email" : "E-posta",
+ "Your email address" : "Tu adresse de e-posta",
"Password" : "Contrasigno",
"Unable to change your password" : "Non pote cambiar tu contrasigno",
"Current password" : "Contrasigno currente",
"New password" : "Nove contrasigno",
"Change password" : "Cambiar contrasigno",
- "Email" : "E-posta",
- "Your email address" : "Tu adresse de e-posta",
- "Profile picture" : "Imagine de profilo",
- "Cancel" : "Cancellar",
"Language" : "Linguage",
"Help translate" : "Adjuta a traducer",
+ "Get the apps to sync your files" : "Obtene le apps (applicationes) pro synchronizar tu files",
"Username" : "Nomine de usator",
"Create" : "Crear",
"Group" : "Gruppo",
diff --git a/settings/l10n/ia.json b/settings/l10n/ia.json
index 2b7a5222aca..562106ffda5 100644
--- a/settings/l10n/ia.json
+++ b/settings/l10n/ia.json
@@ -7,30 +7,29 @@
"Saved" : "Salveguardate",
"Email sent" : "Message de e-posta inviate",
"All" : "Omne",
+ "Delete" : "Deler",
"Very weak password" : "Contrasigno multo debile",
"Weak password" : "Contrasigno debile",
"So-so password" : "Contrasigno passabile",
"Good password" : "Contrasigno bon",
"Strong password" : "Contrasigno forte",
- "Delete" : "Deler",
"Groups" : "Gruppos",
"never" : "nunquam",
"__language_name__" : "Interlingua",
"More" : "Plus",
- "by" : "per",
"Cheers!" : "Acclamationes!",
- "Get the apps to sync your files" : "Obtene le apps (applicationes) pro synchronizar tu files",
+ "Profile picture" : "Imagine de profilo",
+ "Cancel" : "Cancellar",
+ "Email" : "E-posta",
+ "Your email address" : "Tu adresse de e-posta",
"Password" : "Contrasigno",
"Unable to change your password" : "Non pote cambiar tu contrasigno",
"Current password" : "Contrasigno currente",
"New password" : "Nove contrasigno",
"Change password" : "Cambiar contrasigno",
- "Email" : "E-posta",
- "Your email address" : "Tu adresse de e-posta",
- "Profile picture" : "Imagine de profilo",
- "Cancel" : "Cancellar",
"Language" : "Linguage",
"Help translate" : "Adjuta a traducer",
+ "Get the apps to sync your files" : "Obtene le apps (applicationes) pro synchronizar tu files",
"Username" : "Nomine de usator",
"Create" : "Crear",
"Group" : "Gruppo",
diff --git a/settings/l10n/id.js b/settings/l10n/id.js
index d03f1b74453..adb32bca220 100644
--- a/settings/l10n/id.js
+++ b/settings/l10n/id.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Log",
"Tips & tricks" : "Tips & trik",
"Updates" : "Pembaruan",
- "Authentication error" : "Terjadi kesalahan saat otentikasi",
- "Your full name has been changed." : "Nama lengkap Anda telah diubah",
- "Unable to change full name" : "Tidak dapat mengubah nama lengkap",
"Couldn't remove app." : "Tidak dapat menghapus aplikasi.",
"Language changed" : "Bahasa telah diubah",
"Invalid request" : "Permintaan tidak valid",
+ "Authentication error" : "Terjadi kesalahan saat otentikasi",
"Admins can't remove themself from the admin group" : "Admin tidak dapat menghapus dirinya sendiri dari grup admin",
"Unable to add user to group %s" : "Tidak dapat menambahkan pengguna ke grup %s",
"Unable to remove user from group %s" : "Tidak dapat menghapus pengguna dari grup %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Pengguna salah",
"Unable to change mail address" : "Tidak dapat mengubah alamat email",
"Email saved" : "Email disimpan",
+ "Your full name has been changed." : "Nama lengkap Anda telah diubah",
+ "Unable to change full name" : "Tidak dapat mengubah nama lengkap",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Apakah Anda yakin ingin menambahkan \"{domain}\" sebagai domain terpercaya?",
"Add trusted domain" : "Tambah domain terpercaya",
"Migration in progress. Please wait until the migration is finished" : "Migrasi sedang dalam proses. Mohon tunggu sampai migrasi selesai.",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Aplikasi sudah diaktifkan tetapi perlu diperbarui. Anda akan dialihkan ke halaman pembaruan dalam 5 detik.",
"App update" : "Pembaruan Aplikasi",
"No apps found for \"{query}\"" : "Tidak ada aplikasi yang ditemukan untuk \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Terjadi kesalahan. Mohon unggah sertifikat PEM terenkode-ASCII.",
+ "Valid until {date}" : "Berlaku sampai {date}",
+ "Delete" : "Hapus",
"An error occurred: {message}" : "Sebuah kesalahan yang muncul: {message}",
"Select a profile picture" : "Pilih foto profil",
"Very weak password" : "Sandi sangat lemah",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Sandi lumayan",
"Good password" : "Sandi baik",
"Strong password" : "Sandi kuat",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Terjadi kesalahan. Mohon unggah sertifikat PEM terenkode-ASCII.",
- "Valid until {date}" : "Berlaku sampai {date}",
- "Delete" : "Hapus",
"Groups" : "Grup",
"Unable to delete {objName}" : "Tidak dapat menghapus {objName}",
"Error creating group" : "Terjadi kesalahan saat membuat grup",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Harus memberikan sandi yang benar",
"A valid email must be provided" : "Email yang benar harus diberikan",
"__language_name__" : "__language_name__",
- "Sync clients" : "Klien sync",
"Personal info" : "Info pribadi",
- "SSL root certificates" : "Sertifikat root SSL",
+ "Sync clients" : "Klien sync",
"Everything (fatal issues, errors, warnings, info, debug)" : "Semuanya (Masalah fatal, kesalahan, peringatan, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, peringatan, kesalahan dan masalah fatal",
"Warnings, errors and fatal issues" : "Peringatan, kesalahan dan masalah fatal",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Kamu sangat menyarankan untuk menginstal paket-paket yang dibutuhkan pada sistem agar mendukung lokal berikut: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Jika instalasi Anda tidak di root domain dan menggunakan sistem cron, hal tersebut dapat menyebabkan masalah dengan pembuatan URL. Untuk mencegah masalah tersebut, mohon atur opsi \"overwrite.cli.url\" pada berkas config.php Anda ke jalur lokasi webroot instalasi Anda (Disarankan: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Tidak mungkin untuk mengeksekusi cronjob via CLI. Kesalahan teknis berikut muncul:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transaksi penguncian berkas menggunakan basis data sebagai backend penguncian, untuk mendapatkan kinerja terbaik, disarankan mengkonfigurasi memcache sebagai penguncian. Baca <a target=\"_blank\" href=\"%s\">dokumentasi ↗</a> untuk informasi lebih lanjut.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Mohon periksa dua kali <a target=\"_blank\" href=\"%s\">panduan instalasi ↗</a>, dan periksa segala kesalahan atau peringatan pada <a href=\"#log-section\">log</a>.",
"All checks passed." : "Semua pemeriksaan lulus.",
"Open documentation" : "Buka dokumentasi",
@@ -188,7 +186,6 @@ OC.L10N.register(
"Store credentials" : "Simpan kredensial",
"Test email settings" : "Pengaturan email percobaan",
"Send email" : "Kirim email",
- "Log level" : "Level log",
"Download logfile" : "Unduh berkas log",
"More" : "Lainnya",
"Less" : "Ciutkan",
@@ -206,8 +203,6 @@ OC.L10N.register(
"Developer documentation" : "Dokumentasi pengembang",
"Experimental applications ahead" : "Aplikasi percobaan terdepan",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Aplikasi percobaan belum diperiksa untuk masalah keamanan, baru atau dikenal tidak stabil dan dalam proses pengembangan. Menginstalnya dapat menyebabkan kehilangan data atau penerobosan keamanan.",
- "by" : "oleh",
- "licensed" : "dilisensikan",
"Documentation:" : "Dokumentasi:",
"User documentation" : "Dokumentasi pengguna.",
"Admin documentation" : "Dokumentasi admin",
@@ -217,6 +212,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Aktifkan hanya untuk grup tertentu",
"Uninstall App" : "Copot aplikasi",
"Enable experimental apps" : "Aktifkan aplikasi percobaan",
+ "Common Name" : "Nama umum",
+ "Valid until" : "Berlaku sampai",
+ "Issued By" : "Diterbitkan oleh",
+ "Valid until %s" : "Berlaku sampai %s",
+ "Import root certificate" : "Impor sertifikat root",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hai,<br><br>sekedar memberi tahu bahwa Andaa sekarang memiliki akun %s.<br><br>Nama Pengguna Anda: %s<br>Akses di: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Horee!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hai,\n\nsekedar memberi tahu bahwa Andaa sekarang memiliki akun %s.\n\nNama Pengguna Anda: %s\nAkses di: %s\n",
@@ -225,40 +225,29 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Pelacak masalah",
"Commercial support" : "Dukungan komersial",
- "Get the apps to sync your files" : "Dapatkan aplikasi untuk sinkronisasi berkas Anda",
- "Desktop client" : "Klien desktop",
- "Android app" : "Aplikasi Android",
- "iOS app" : "Aplikasi iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Jika Anda ingin mendukung proyek ini\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">bergabunglah dalam pengembangan</a>\n\t\tatau\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">promosikan</a>!",
- "Show First Run Wizard again" : "Tampilkan Penuntun Konfigurasi Awal",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Anda telah menggunakan <strong>%s</strong> dari total <strong>%s</strong>",
- "Password" : "Sandi",
- "Unable to change your password" : "Gagal mengubah sandi Anda",
- "Current password" : "Sandi saat ini",
- "New password" : "Sandi baru",
- "Change password" : "Ubah sandi",
+ "Profile picture" : "Foto profil",
+ "Upload new" : "Unggah baru",
+ "Remove image" : "Hapus gambar",
+ "Cancel" : "Batal",
"Full name" : "Nama lengkap",
"No display name set" : "Nama tampilan tidak diatur",
"Email" : "Email",
"Your email address" : "Alamat email Anda",
- "Fill in an email address to enable password recovery and receive notifications" : "Isikan alamat email untuk mengaktifkan pemulihan sandi dan menerima notifikasi",
"No email address set" : "Alamat email tidak diatur",
"You are member of the following groups:" : "Anda adalah anggota dari grup berikut:",
- "Profile picture" : "Foto profil",
- "Upload new" : "Unggah baru",
- "Select new from Files" : "Pilih baru dari Berkas",
- "Remove image" : "Hapus gambar",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Boleh png atau jpg. Idealnya berbentuk persegi tetapi Anda dapat memotongnya. Berkas tidak diizinkan melebihi ukuran 20 MB.",
- "Your avatar is provided by your original account." : "Avatar disediakan oleh akun asli Anda.",
- "Cancel" : "Batal",
- "Choose as profile image" : "Pilih sebagai gambar profil",
+ "Password" : "Sandi",
+ "Unable to change your password" : "Gagal mengubah sandi Anda",
+ "Current password" : "Sandi saat ini",
+ "New password" : "Sandi baru",
+ "Change password" : "Ubah sandi",
"Language" : "Bahasa",
"Help translate" : "Bantu menerjemahkan",
- "Common Name" : "Nama umum",
- "Valid until" : "Berlaku sampai",
- "Issued By" : "Diterbitkan oleh",
- "Valid until %s" : "Berlaku sampai %s",
- "Import root certificate" : "Impor sertifikat root",
+ "Get the apps to sync your files" : "Dapatkan aplikasi untuk sinkronisasi berkas Anda",
+ "Desktop client" : "Klien desktop",
+ "Android app" : "Aplikasi Android",
+ "iOS app" : "Aplikasi iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Jika Anda ingin mendukung proyek ini\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">bergabunglah dalam pengembangan</a>\n\t\tatau\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">promosikan</a>!",
+ "Show First Run Wizard again" : "Tampilkan Penuntun Konfigurasi Awal",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Dikembangkan oleh {communityopen}komunitas ownCloud{linkclose}, {githubopen}kode sumber{linkclose} dilisensikan dibawah {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Tampilkan kolasi penyimpanan",
"Show last log in" : "Tampilkan masuk terakhir",
diff --git a/settings/l10n/id.json b/settings/l10n/id.json
index c0d63bd9dce..8290782a737 100644
--- a/settings/l10n/id.json
+++ b/settings/l10n/id.json
@@ -10,12 +10,10 @@
"Log" : "Log",
"Tips & tricks" : "Tips & trik",
"Updates" : "Pembaruan",
- "Authentication error" : "Terjadi kesalahan saat otentikasi",
- "Your full name has been changed." : "Nama lengkap Anda telah diubah",
- "Unable to change full name" : "Tidak dapat mengubah nama lengkap",
"Couldn't remove app." : "Tidak dapat menghapus aplikasi.",
"Language changed" : "Bahasa telah diubah",
"Invalid request" : "Permintaan tidak valid",
+ "Authentication error" : "Terjadi kesalahan saat otentikasi",
"Admins can't remove themself from the admin group" : "Admin tidak dapat menghapus dirinya sendiri dari grup admin",
"Unable to add user to group %s" : "Tidak dapat menambahkan pengguna ke grup %s",
"Unable to remove user from group %s" : "Tidak dapat menghapus pengguna dari grup %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Pengguna salah",
"Unable to change mail address" : "Tidak dapat mengubah alamat email",
"Email saved" : "Email disimpan",
+ "Your full name has been changed." : "Nama lengkap Anda telah diubah",
+ "Unable to change full name" : "Tidak dapat mengubah nama lengkap",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Apakah Anda yakin ingin menambahkan \"{domain}\" sebagai domain terpercaya?",
"Add trusted domain" : "Tambah domain terpercaya",
"Migration in progress. Please wait until the migration is finished" : "Migrasi sedang dalam proses. Mohon tunggu sampai migrasi selesai.",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Aplikasi sudah diaktifkan tetapi perlu diperbarui. Anda akan dialihkan ke halaman pembaruan dalam 5 detik.",
"App update" : "Pembaruan Aplikasi",
"No apps found for \"{query}\"" : "Tidak ada aplikasi yang ditemukan untuk \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Terjadi kesalahan. Mohon unggah sertifikat PEM terenkode-ASCII.",
+ "Valid until {date}" : "Berlaku sampai {date}",
+ "Delete" : "Hapus",
"An error occurred: {message}" : "Sebuah kesalahan yang muncul: {message}",
"Select a profile picture" : "Pilih foto profil",
"Very weak password" : "Sandi sangat lemah",
@@ -86,9 +89,6 @@
"So-so password" : "Sandi lumayan",
"Good password" : "Sandi baik",
"Strong password" : "Sandi kuat",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Terjadi kesalahan. Mohon unggah sertifikat PEM terenkode-ASCII.",
- "Valid until {date}" : "Berlaku sampai {date}",
- "Delete" : "Hapus",
"Groups" : "Grup",
"Unable to delete {objName}" : "Tidak dapat menghapus {objName}",
"Error creating group" : "Terjadi kesalahan saat membuat grup",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Harus memberikan sandi yang benar",
"A valid email must be provided" : "Email yang benar harus diberikan",
"__language_name__" : "__language_name__",
- "Sync clients" : "Klien sync",
"Personal info" : "Info pribadi",
- "SSL root certificates" : "Sertifikat root SSL",
+ "Sync clients" : "Klien sync",
"Everything (fatal issues, errors, warnings, info, debug)" : "Semuanya (Masalah fatal, kesalahan, peringatan, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, peringatan, kesalahan dan masalah fatal",
"Warnings, errors and fatal issues" : "Peringatan, kesalahan dan masalah fatal",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Kamu sangat menyarankan untuk menginstal paket-paket yang dibutuhkan pada sistem agar mendukung lokal berikut: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Jika instalasi Anda tidak di root domain dan menggunakan sistem cron, hal tersebut dapat menyebabkan masalah dengan pembuatan URL. Untuk mencegah masalah tersebut, mohon atur opsi \"overwrite.cli.url\" pada berkas config.php Anda ke jalur lokasi webroot instalasi Anda (Disarankan: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Tidak mungkin untuk mengeksekusi cronjob via CLI. Kesalahan teknis berikut muncul:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transaksi penguncian berkas menggunakan basis data sebagai backend penguncian, untuk mendapatkan kinerja terbaik, disarankan mengkonfigurasi memcache sebagai penguncian. Baca <a target=\"_blank\" href=\"%s\">dokumentasi ↗</a> untuk informasi lebih lanjut.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Mohon periksa dua kali <a target=\"_blank\" href=\"%s\">panduan instalasi ↗</a>, dan periksa segala kesalahan atau peringatan pada <a href=\"#log-section\">log</a>.",
"All checks passed." : "Semua pemeriksaan lulus.",
"Open documentation" : "Buka dokumentasi",
@@ -186,7 +184,6 @@
"Store credentials" : "Simpan kredensial",
"Test email settings" : "Pengaturan email percobaan",
"Send email" : "Kirim email",
- "Log level" : "Level log",
"Download logfile" : "Unduh berkas log",
"More" : "Lainnya",
"Less" : "Ciutkan",
@@ -204,8 +201,6 @@
"Developer documentation" : "Dokumentasi pengembang",
"Experimental applications ahead" : "Aplikasi percobaan terdepan",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Aplikasi percobaan belum diperiksa untuk masalah keamanan, baru atau dikenal tidak stabil dan dalam proses pengembangan. Menginstalnya dapat menyebabkan kehilangan data atau penerobosan keamanan.",
- "by" : "oleh",
- "licensed" : "dilisensikan",
"Documentation:" : "Dokumentasi:",
"User documentation" : "Dokumentasi pengguna.",
"Admin documentation" : "Dokumentasi admin",
@@ -215,6 +210,11 @@
"Enable only for specific groups" : "Aktifkan hanya untuk grup tertentu",
"Uninstall App" : "Copot aplikasi",
"Enable experimental apps" : "Aktifkan aplikasi percobaan",
+ "Common Name" : "Nama umum",
+ "Valid until" : "Berlaku sampai",
+ "Issued By" : "Diterbitkan oleh",
+ "Valid until %s" : "Berlaku sampai %s",
+ "Import root certificate" : "Impor sertifikat root",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hai,<br><br>sekedar memberi tahu bahwa Andaa sekarang memiliki akun %s.<br><br>Nama Pengguna Anda: %s<br>Akses di: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Horee!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hai,\n\nsekedar memberi tahu bahwa Andaa sekarang memiliki akun %s.\n\nNama Pengguna Anda: %s\nAkses di: %s\n",
@@ -223,40 +223,29 @@
"Forum" : "Forum",
"Issue tracker" : "Pelacak masalah",
"Commercial support" : "Dukungan komersial",
- "Get the apps to sync your files" : "Dapatkan aplikasi untuk sinkronisasi berkas Anda",
- "Desktop client" : "Klien desktop",
- "Android app" : "Aplikasi Android",
- "iOS app" : "Aplikasi iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Jika Anda ingin mendukung proyek ini\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">bergabunglah dalam pengembangan</a>\n\t\tatau\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">promosikan</a>!",
- "Show First Run Wizard again" : "Tampilkan Penuntun Konfigurasi Awal",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Anda telah menggunakan <strong>%s</strong> dari total <strong>%s</strong>",
- "Password" : "Sandi",
- "Unable to change your password" : "Gagal mengubah sandi Anda",
- "Current password" : "Sandi saat ini",
- "New password" : "Sandi baru",
- "Change password" : "Ubah sandi",
+ "Profile picture" : "Foto profil",
+ "Upload new" : "Unggah baru",
+ "Remove image" : "Hapus gambar",
+ "Cancel" : "Batal",
"Full name" : "Nama lengkap",
"No display name set" : "Nama tampilan tidak diatur",
"Email" : "Email",
"Your email address" : "Alamat email Anda",
- "Fill in an email address to enable password recovery and receive notifications" : "Isikan alamat email untuk mengaktifkan pemulihan sandi dan menerima notifikasi",
"No email address set" : "Alamat email tidak diatur",
"You are member of the following groups:" : "Anda adalah anggota dari grup berikut:",
- "Profile picture" : "Foto profil",
- "Upload new" : "Unggah baru",
- "Select new from Files" : "Pilih baru dari Berkas",
- "Remove image" : "Hapus gambar",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Boleh png atau jpg. Idealnya berbentuk persegi tetapi Anda dapat memotongnya. Berkas tidak diizinkan melebihi ukuran 20 MB.",
- "Your avatar is provided by your original account." : "Avatar disediakan oleh akun asli Anda.",
- "Cancel" : "Batal",
- "Choose as profile image" : "Pilih sebagai gambar profil",
+ "Password" : "Sandi",
+ "Unable to change your password" : "Gagal mengubah sandi Anda",
+ "Current password" : "Sandi saat ini",
+ "New password" : "Sandi baru",
+ "Change password" : "Ubah sandi",
"Language" : "Bahasa",
"Help translate" : "Bantu menerjemahkan",
- "Common Name" : "Nama umum",
- "Valid until" : "Berlaku sampai",
- "Issued By" : "Diterbitkan oleh",
- "Valid until %s" : "Berlaku sampai %s",
- "Import root certificate" : "Impor sertifikat root",
+ "Get the apps to sync your files" : "Dapatkan aplikasi untuk sinkronisasi berkas Anda",
+ "Desktop client" : "Klien desktop",
+ "Android app" : "Aplikasi Android",
+ "iOS app" : "Aplikasi iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Jika Anda ingin mendukung proyek ini\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">bergabunglah dalam pengembangan</a>\n\t\tatau\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">promosikan</a>!",
+ "Show First Run Wizard again" : "Tampilkan Penuntun Konfigurasi Awal",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Dikembangkan oleh {communityopen}komunitas ownCloud{linkclose}, {githubopen}kode sumber{linkclose} dilisensikan dibawah {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Tampilkan kolasi penyimpanan",
"Show last log in" : "Tampilkan masuk terakhir",
diff --git a/settings/l10n/is.js b/settings/l10n/is.js
index 994011a098e..9acdfe428fd 100644
--- a/settings/l10n/is.js
+++ b/settings/l10n/is.js
@@ -2,31 +2,31 @@ OC.L10N.register(
"settings",
{
"External Storage" : "Ytri gagnageymsla",
- "Authentication error" : "Villa við auðkenningu",
"Language changed" : "Tungumáli breytt",
"Invalid request" : "Ógild fyrirspurn",
+ "Authentication error" : "Villa við auðkenningu",
"Admins can't remove themself from the admin group" : "Stjórnendur geta ekki fjarlægt sjálfa sig úr stjórnendahóp",
"Unable to add user to group %s" : "Ekki tókst að bæta notenda við hópinn %s",
"Unable to remove user from group %s" : "Ekki tókst að fjarlægja notanda úr hópnum %s",
"Saved" : "Vistað",
"Email sent" : "Tölvupóstur sendur",
"Email saved" : "Netfang vistað",
+ "All" : "Allt",
"Please wait...." : "Andartak....",
"Disable" : "Gera óvirkt",
"Enable" : "Virkja",
"Updating...." : "Uppfæri...",
"Updated" : "Uppfært",
+ "Delete" : "Eyða",
"Very weak password" : "Mjög veikt lykilorð",
"Weak password" : "Veikt lykilorð",
"So-so password" : "Svo-svo lykilorð",
"Good password" : "Gott lykilorð",
"Strong password" : "Sterkt lykilorð",
- "Delete" : "Eyða",
"Groups" : "Hópar",
"undo" : "afturkalla",
"never" : "aldrei",
"__language_name__" : "__nafn_tungumáls__",
- "SSL root certificates" : "SSL rótar skilríki",
"None" : "Ekkert",
"Encryption" : "Dulkóðun",
"Server address" : "Host nafn netþjóns",
@@ -34,18 +34,16 @@ OC.L10N.register(
"Less" : "Minna",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Sérstaklega þegar tölvu forrit er notað til samræmingar þá er ekki mælt með notkunn SQLite.",
"Version" : "Útgáfa",
- "by" : "af",
"Cheers!" : "Skál!",
"Forum" : "Vefspjall",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Þú hefur notað <strong>%s</strong> af tiltæku <strong>%s</strong>",
+ "Cancel" : "Hætta við",
+ "Email" : "Netfang",
+ "Your email address" : "Netfangið þitt",
"Password" : "Lykilorð",
"Unable to change your password" : "Ekki tókst að breyta lykilorðinu þínu",
"Current password" : "Núverandi lykilorð",
"New password" : "Nýtt lykilorð",
"Change password" : "Breyta lykilorði",
- "Email" : "Netfang",
- "Your email address" : "Netfangið þitt",
- "Cancel" : "Hætta við",
"Language" : "Tungumál",
"Help translate" : "Hjálpa við þýðingu",
"Username" : "Notendanafn",
diff --git a/settings/l10n/is.json b/settings/l10n/is.json
index 5e2507a5499..37f481341ce 100644
--- a/settings/l10n/is.json
+++ b/settings/l10n/is.json
@@ -1,30 +1,30 @@
{ "translations": {
"External Storage" : "Ytri gagnageymsla",
- "Authentication error" : "Villa við auðkenningu",
"Language changed" : "Tungumáli breytt",
"Invalid request" : "Ógild fyrirspurn",
+ "Authentication error" : "Villa við auðkenningu",
"Admins can't remove themself from the admin group" : "Stjórnendur geta ekki fjarlægt sjálfa sig úr stjórnendahóp",
"Unable to add user to group %s" : "Ekki tókst að bæta notenda við hópinn %s",
"Unable to remove user from group %s" : "Ekki tókst að fjarlægja notanda úr hópnum %s",
"Saved" : "Vistað",
"Email sent" : "Tölvupóstur sendur",
"Email saved" : "Netfang vistað",
+ "All" : "Allt",
"Please wait...." : "Andartak....",
"Disable" : "Gera óvirkt",
"Enable" : "Virkja",
"Updating...." : "Uppfæri...",
"Updated" : "Uppfært",
+ "Delete" : "Eyða",
"Very weak password" : "Mjög veikt lykilorð",
"Weak password" : "Veikt lykilorð",
"So-so password" : "Svo-svo lykilorð",
"Good password" : "Gott lykilorð",
"Strong password" : "Sterkt lykilorð",
- "Delete" : "Eyða",
"Groups" : "Hópar",
"undo" : "afturkalla",
"never" : "aldrei",
"__language_name__" : "__nafn_tungumáls__",
- "SSL root certificates" : "SSL rótar skilríki",
"None" : "Ekkert",
"Encryption" : "Dulkóðun",
"Server address" : "Host nafn netþjóns",
@@ -32,18 +32,16 @@
"Less" : "Minna",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Sérstaklega þegar tölvu forrit er notað til samræmingar þá er ekki mælt með notkunn SQLite.",
"Version" : "Útgáfa",
- "by" : "af",
"Cheers!" : "Skál!",
"Forum" : "Vefspjall",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Þú hefur notað <strong>%s</strong> af tiltæku <strong>%s</strong>",
+ "Cancel" : "Hætta við",
+ "Email" : "Netfang",
+ "Your email address" : "Netfangið þitt",
"Password" : "Lykilorð",
"Unable to change your password" : "Ekki tókst að breyta lykilorðinu þínu",
"Current password" : "Núverandi lykilorð",
"New password" : "Nýtt lykilorð",
"Change password" : "Breyta lykilorði",
- "Email" : "Netfang",
- "Your email address" : "Netfangið þitt",
- "Cancel" : "Hætta við",
"Language" : "Tungumál",
"Help translate" : "Hjálpa við þýðingu",
"Username" : "Notendanafn",
diff --git a/settings/l10n/it.js b/settings/l10n/it.js
index 38684a67272..0dcefd70b9e 100644
--- a/settings/l10n/it.js
+++ b/settings/l10n/it.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Log",
"Tips & tricks" : "Suggerimenti e trucchi",
"Updates" : "Aggiornamenti",
- "Authentication error" : "Errore di autenticazione",
- "Your full name has been changed." : "Il tuo nome completo è stato cambiato.",
- "Unable to change full name" : "Impossibile cambiare il nome completo",
"Couldn't remove app." : "Impossibile rimuovere l'applicazione.",
"Language changed" : "Lingua modificata",
"Invalid request" : "Richiesta non valida",
+ "Authentication error" : "Errore di autenticazione",
"Admins can't remove themself from the admin group" : "Gli amministratori non possono rimuovere se stessi dal gruppo di amministrazione",
"Unable to add user to group %s" : "Impossibile aggiungere l'utente al gruppo %s",
"Unable to remove user from group %s" : "Impossibile rimuovere l'utente dal gruppo %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Utente non valido",
"Unable to change mail address" : "Impossibile cambiare l'indirizzo di posta",
"Email saved" : "Email salvata",
+ "Your full name has been changed." : "Il tuo nome completo è stato cambiato.",
+ "Unable to change full name" : "Impossibile cambiare il nome completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Sei sicuro di voler aggiungere \"{domain}\" come dominio attendibile?",
"Add trusted domain" : "Aggiungi dominio attendibile",
"Migration in progress. Please wait until the migration is finished" : "Migrazione in corso. Attendi fino al completamento della migrazione",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "L'applicazione è stata abilitata, ma deve essere aggiornata. Sarai rediretto alla pagina di aggiornamento in 5 secondi.",
"App update" : "Aggiornamento applicazione",
"No apps found for \"{query}\"" : "Nessuna applicazione trovata per \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Si è verificato un errore. Carica un certificato PEM codificato in ASCII.",
+ "Valid until {date}" : "Valido fino al {date}",
+ "Delete" : "Elimina",
"An error occurred: {message}" : "Si è verificato un errore: {message}",
"Select a profile picture" : "Seleziona un'immagine del profilo",
"Very weak password" : "Password molto debole",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Password così-così",
"Good password" : "Password buona",
"Strong password" : "Password forte",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Si è verificato un errore. Carica un certificato PEM codificato in ASCII.",
- "Valid until {date}" : "Valido fino al {date}",
- "Delete" : "Elimina",
"Groups" : "Gruppi",
"Unable to delete {objName}" : "Impossibile eliminare {objName}",
"Error creating group" : "Errore durante la creazione del gruppo",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Deve essere fornita una password valida",
"A valid email must be provided" : "Deve essere fornito un indirizzo email valido",
"__language_name__" : "Italiano",
- "Sync clients" : "Client di sincronizzazione",
"Personal info" : "Informazioni personali",
- "SSL root certificates" : "Certificati SSL radice",
+ "Sync clients" : "Client di sincronizzazione",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tutto (problemi gravi, errori, avvisi, informazioni, debug)",
"Info, warnings, errors and fatal issues" : "Informazioni, avvisi, errori e problemi gravi",
"Warnings, errors and fatal issues" : "Avvisi, errori e problemi gravi",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Consigliamo vivamente di installare i pacchetti richiesti sul tuo sistema per supportare una delle localizzazioni seguenti: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se la tua installazione non si trova nella radice del dominio e utilizza il cron di sistema, potrebbero esserci problemi con la generazione degli URL. Per evitare questi problemi, imposta l'opzione \"overwrite.cli.url\" nel file config.php al percorso della radice del sito della tua installazione (Consigliato: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Non è stato possibile eseguire il job di cron tramite CLI. Sono apparsi i seguenti errori tecnici:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Il blocco del file transazionale sta utilizzando il database come motore di blocco, per avere prestazioni migliori, è consigliato configurare una cache di memoria per il blocco. Vedi la <a target=\"_blank\" href=\"%s\">documentazione ↗</a> per ulteriori informazioni.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Leggi attentamente le <a target=\"_blank\" href=\"%s\">guide d'installazione ↗</a>, e controlla gli errori o gli avvisi nel <a href=\"#log-section\">log</a>.",
"All checks passed." : "Tutti i controlli passati.",
"Open documentation" : "Apri la documentazione",
@@ -188,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Memorizza le credenziali",
"Test email settings" : "Prova impostazioni email",
"Send email" : "Invia email",
- "Log level" : "Livello di log",
"Download logfile" : "Scarica file di log",
"More" : "Altro",
"Less" : "Meno",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Il file di log è più grande di 100MB. Scaricarlo potrebbe richiedere del tempo!",
+ "What to log" : "Cosa registrare",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite è utilizzato come database. Per installazioni più grandi consigliamo di passare a un motore di database diverso.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "In particolar modo, quando si utilizza il client desktop per la sincronizzazione dei file, l'uso di SQLite è sconsigliato.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Per migrare a un altro database, usa lo strumento da riga di comando: 'occ db:convert-type', o leggi la <a target=\"_blank\" href=\"%s\">documentazione ↗</a>.",
@@ -206,17 +204,25 @@ OC.L10N.register(
"Developer documentation" : "Documentazione dello sviluppatore",
"Experimental applications ahead" : "Prima le applicazioni sperimentali",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Le applicazioni sperimentali non sono sottoposte a controlli di sicurezza, sono nuove o notoriamente instabili e sotto sviluppo intensivo. La loro installazione può causare perdite di dati o problemi di sicurezza.",
- "by" : "di",
- "licensed" : "sotto licenza",
+ "by %s" : "di %s",
+ "%s-licensed" : "sotto licenza %s",
"Documentation:" : "Documentazione:",
"User documentation" : "Documentazione utente",
"Admin documentation" : "Documentazione di amministrazione",
"Show description …" : "Mostra descrizione...",
"Hide description …" : "Nascondi descrizione...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Questa applicazione non ha una versione minima di ownCloud assegnata. Ciò costituirà un errore in ownCloud 11 e successive.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Questa applicazione non ha una versione massima di ownCloud assegnata. Ciò costituirà un errore in ownCloud 11 e successive.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Questa applicazione non può essere installata perché le seguenti dipendenze non sono soddisfatte:",
"Enable only for specific groups" : "Abilita solo per gruppi specifici",
"Uninstall App" : "Disinstalla applicazione",
"Enable experimental apps" : "Abilita le applicazioni sperimentali",
+ "SSL Root Certificates" : "Certificati radice SSL",
+ "Common Name" : "Nome comune",
+ "Valid until" : "Valido fino al",
+ "Issued By" : "Emesso da",
+ "Valid until %s" : "Valido fino al %s",
+ "Import root certificate" : "Importa certificato radice",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Ciao,<br><br>volevo informarti che ora hai un account %s.<br><br>Il tuo nome utente: %s<br>Accedi: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Saluti!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ciao,\n\nvolevo informarti che ora hai un account %s.\n\nIl tuo nome utente: %s\nAccedi: %s\n\n",
@@ -225,40 +231,35 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Sistema di tracciamento dei problemi",
"Commercial support" : "Supporto commerciale",
- "Get the apps to sync your files" : "Scarica le applicazioni per sincronizzare i tuoi file",
- "Desktop client" : "Client desktop",
- "Android app" : "Applicazione Android",
- "iOS app" : "Applicazione iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se vuoi supportare il progetto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">diventa uno sviluppatore</a>\n\t\to\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">diffondi il verbo</a>!",
- "Show First Run Wizard again" : "Mostra nuovamente la procedura di primo avvio",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Hai utilizzato <strong>%s</strong> dei <strong>%s</strong> disponibili",
- "Password" : "Password",
- "Unable to change your password" : "Modifica password non riuscita",
- "Current password" : "Password attuale",
- "New password" : "Nuova password",
- "Change password" : "Modifica password",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Stai utilizzando <strong>%s</strong> di <strong>%s</strong>",
+ "Profile picture" : "Immagine del profilo",
+ "Upload new" : "Carica nuova",
+ "Select from Files" : "Seleziona da file",
+ "Remove image" : "Rimuovi immagine",
+ "png or jpg, max. 20 MB" : "png o jpg, max. 20 MB",
+ "Picture provided by original account" : "Immagine fornita dall'account originale",
+ "Cancel" : "Annulla",
+ "Choose as profile picture" : "Scegli come immagine del profilo",
"Full name" : "Nome completo",
"No display name set" : "Nome visualizzato non impostato",
"Email" : "Posta elettronica",
"Your email address" : "Il tuo indirizzo email",
- "Fill in an email address to enable password recovery and receive notifications" : "Inserisci il tuo indirizzo di posta per abilitare il ripristino della password e ricevere notifiche",
+ "For password recovery and notifications" : "Per il ripristino della password e per le notifiche",
"No email address set" : "Nessun indirizzo email impostato",
"You are member of the following groups:" : "Sei membro dei seguenti gruppi:",
- "Profile picture" : "Immagine del profilo",
- "Upload new" : "Carica nuova",
- "Select new from Files" : "Seleziona nuova da file",
- "Remove image" : "Rimuovi immagine",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Sia png che jpg. Preferibilmente quadrata, ma potrai ritagliarla. Il file non può superare la dimensione massima di 20 MB.",
- "Your avatar is provided by your original account." : "Il tuo avatar è ottenuto dal tuo account originale.",
- "Cancel" : "Annulla",
- "Choose as profile image" : "Scegli come immagine del profilo",
+ "Password" : "Password",
+ "Unable to change your password" : "Modifica password non riuscita",
+ "Current password" : "Password attuale",
+ "New password" : "Nuova password",
+ "Change password" : "Modifica password",
"Language" : "Lingua",
"Help translate" : "Migliora la traduzione",
- "Common Name" : "Nome comune",
- "Valid until" : "Valido fino al",
- "Issued By" : "Emesso da",
- "Valid until %s" : "Valido fino al %s",
- "Import root certificate" : "Importa certificato radice",
+ "Get the apps to sync your files" : "Scarica le applicazioni per sincronizzare i tuoi file",
+ "Desktop client" : "Client desktop",
+ "Android app" : "Applicazione Android",
+ "iOS app" : "Applicazione iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se vuoi supportare il progetto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">diventa uno sviluppatore</a>\n\t\to\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">diffondi il verbo</a>!",
+ "Show First Run Wizard again" : "Mostra nuovamente la procedura di primo avvio",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Sviluppato dalla {communityopen}comunità di ownCloud{linkclose}, il {githubopen}codice sorgente{linkclose} è rilasciato nei termini della licenza {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostra posizione di archiviazione",
"Show last log in" : "Mostra ultimo accesso",
diff --git a/settings/l10n/it.json b/settings/l10n/it.json
index 11f65d07d22..41e74021a28 100644
--- a/settings/l10n/it.json
+++ b/settings/l10n/it.json
@@ -10,12 +10,10 @@
"Log" : "Log",
"Tips & tricks" : "Suggerimenti e trucchi",
"Updates" : "Aggiornamenti",
- "Authentication error" : "Errore di autenticazione",
- "Your full name has been changed." : "Il tuo nome completo è stato cambiato.",
- "Unable to change full name" : "Impossibile cambiare il nome completo",
"Couldn't remove app." : "Impossibile rimuovere l'applicazione.",
"Language changed" : "Lingua modificata",
"Invalid request" : "Richiesta non valida",
+ "Authentication error" : "Errore di autenticazione",
"Admins can't remove themself from the admin group" : "Gli amministratori non possono rimuovere se stessi dal gruppo di amministrazione",
"Unable to add user to group %s" : "Impossibile aggiungere l'utente al gruppo %s",
"Unable to remove user from group %s" : "Impossibile rimuovere l'utente dal gruppo %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Utente non valido",
"Unable to change mail address" : "Impossibile cambiare l'indirizzo di posta",
"Email saved" : "Email salvata",
+ "Your full name has been changed." : "Il tuo nome completo è stato cambiato.",
+ "Unable to change full name" : "Impossibile cambiare il nome completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Sei sicuro di voler aggiungere \"{domain}\" come dominio attendibile?",
"Add trusted domain" : "Aggiungi dominio attendibile",
"Migration in progress. Please wait until the migration is finished" : "Migrazione in corso. Attendi fino al completamento della migrazione",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "L'applicazione è stata abilitata, ma deve essere aggiornata. Sarai rediretto alla pagina di aggiornamento in 5 secondi.",
"App update" : "Aggiornamento applicazione",
"No apps found for \"{query}\"" : "Nessuna applicazione trovata per \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Si è verificato un errore. Carica un certificato PEM codificato in ASCII.",
+ "Valid until {date}" : "Valido fino al {date}",
+ "Delete" : "Elimina",
"An error occurred: {message}" : "Si è verificato un errore: {message}",
"Select a profile picture" : "Seleziona un'immagine del profilo",
"Very weak password" : "Password molto debole",
@@ -86,9 +89,6 @@
"So-so password" : "Password così-così",
"Good password" : "Password buona",
"Strong password" : "Password forte",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Si è verificato un errore. Carica un certificato PEM codificato in ASCII.",
- "Valid until {date}" : "Valido fino al {date}",
- "Delete" : "Elimina",
"Groups" : "Gruppi",
"Unable to delete {objName}" : "Impossibile eliminare {objName}",
"Error creating group" : "Errore durante la creazione del gruppo",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Deve essere fornita una password valida",
"A valid email must be provided" : "Deve essere fornito un indirizzo email valido",
"__language_name__" : "Italiano",
- "Sync clients" : "Client di sincronizzazione",
"Personal info" : "Informazioni personali",
- "SSL root certificates" : "Certificati SSL radice",
+ "Sync clients" : "Client di sincronizzazione",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tutto (problemi gravi, errori, avvisi, informazioni, debug)",
"Info, warnings, errors and fatal issues" : "Informazioni, avvisi, errori e problemi gravi",
"Warnings, errors and fatal issues" : "Avvisi, errori e problemi gravi",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Consigliamo vivamente di installare i pacchetti richiesti sul tuo sistema per supportare una delle localizzazioni seguenti: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se la tua installazione non si trova nella radice del dominio e utilizza il cron di sistema, potrebbero esserci problemi con la generazione degli URL. Per evitare questi problemi, imposta l'opzione \"overwrite.cli.url\" nel file config.php al percorso della radice del sito della tua installazione (Consigliato: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Non è stato possibile eseguire il job di cron tramite CLI. Sono apparsi i seguenti errori tecnici:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Il blocco del file transazionale sta utilizzando il database come motore di blocco, per avere prestazioni migliori, è consigliato configurare una cache di memoria per il blocco. Vedi la <a target=\"_blank\" href=\"%s\">documentazione ↗</a> per ulteriori informazioni.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Leggi attentamente le <a target=\"_blank\" href=\"%s\">guide d'installazione ↗</a>, e controlla gli errori o gli avvisi nel <a href=\"#log-section\">log</a>.",
"All checks passed." : "Tutti i controlli passati.",
"Open documentation" : "Apri la documentazione",
@@ -186,11 +184,11 @@
"Store credentials" : "Memorizza le credenziali",
"Test email settings" : "Prova impostazioni email",
"Send email" : "Invia email",
- "Log level" : "Livello di log",
"Download logfile" : "Scarica file di log",
"More" : "Altro",
"Less" : "Meno",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Il file di log è più grande di 100MB. Scaricarlo potrebbe richiedere del tempo!",
+ "What to log" : "Cosa registrare",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite è utilizzato come database. Per installazioni più grandi consigliamo di passare a un motore di database diverso.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "In particolar modo, quando si utilizza il client desktop per la sincronizzazione dei file, l'uso di SQLite è sconsigliato.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Per migrare a un altro database, usa lo strumento da riga di comando: 'occ db:convert-type', o leggi la <a target=\"_blank\" href=\"%s\">documentazione ↗</a>.",
@@ -204,17 +202,25 @@
"Developer documentation" : "Documentazione dello sviluppatore",
"Experimental applications ahead" : "Prima le applicazioni sperimentali",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Le applicazioni sperimentali non sono sottoposte a controlli di sicurezza, sono nuove o notoriamente instabili e sotto sviluppo intensivo. La loro installazione può causare perdite di dati o problemi di sicurezza.",
- "by" : "di",
- "licensed" : "sotto licenza",
+ "by %s" : "di %s",
+ "%s-licensed" : "sotto licenza %s",
"Documentation:" : "Documentazione:",
"User documentation" : "Documentazione utente",
"Admin documentation" : "Documentazione di amministrazione",
"Show description …" : "Mostra descrizione...",
"Hide description …" : "Nascondi descrizione...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Questa applicazione non ha una versione minima di ownCloud assegnata. Ciò costituirà un errore in ownCloud 11 e successive.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Questa applicazione non ha una versione massima di ownCloud assegnata. Ciò costituirà un errore in ownCloud 11 e successive.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Questa applicazione non può essere installata perché le seguenti dipendenze non sono soddisfatte:",
"Enable only for specific groups" : "Abilita solo per gruppi specifici",
"Uninstall App" : "Disinstalla applicazione",
"Enable experimental apps" : "Abilita le applicazioni sperimentali",
+ "SSL Root Certificates" : "Certificati radice SSL",
+ "Common Name" : "Nome comune",
+ "Valid until" : "Valido fino al",
+ "Issued By" : "Emesso da",
+ "Valid until %s" : "Valido fino al %s",
+ "Import root certificate" : "Importa certificato radice",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Ciao,<br><br>volevo informarti che ora hai un account %s.<br><br>Il tuo nome utente: %s<br>Accedi: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Saluti!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ciao,\n\nvolevo informarti che ora hai un account %s.\n\nIl tuo nome utente: %s\nAccedi: %s\n\n",
@@ -223,40 +229,35 @@
"Forum" : "Forum",
"Issue tracker" : "Sistema di tracciamento dei problemi",
"Commercial support" : "Supporto commerciale",
- "Get the apps to sync your files" : "Scarica le applicazioni per sincronizzare i tuoi file",
- "Desktop client" : "Client desktop",
- "Android app" : "Applicazione Android",
- "iOS app" : "Applicazione iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se vuoi supportare il progetto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">diventa uno sviluppatore</a>\n\t\to\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">diffondi il verbo</a>!",
- "Show First Run Wizard again" : "Mostra nuovamente la procedura di primo avvio",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Hai utilizzato <strong>%s</strong> dei <strong>%s</strong> disponibili",
- "Password" : "Password",
- "Unable to change your password" : "Modifica password non riuscita",
- "Current password" : "Password attuale",
- "New password" : "Nuova password",
- "Change password" : "Modifica password",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Stai utilizzando <strong>%s</strong> di <strong>%s</strong>",
+ "Profile picture" : "Immagine del profilo",
+ "Upload new" : "Carica nuova",
+ "Select from Files" : "Seleziona da file",
+ "Remove image" : "Rimuovi immagine",
+ "png or jpg, max. 20 MB" : "png o jpg, max. 20 MB",
+ "Picture provided by original account" : "Immagine fornita dall'account originale",
+ "Cancel" : "Annulla",
+ "Choose as profile picture" : "Scegli come immagine del profilo",
"Full name" : "Nome completo",
"No display name set" : "Nome visualizzato non impostato",
"Email" : "Posta elettronica",
"Your email address" : "Il tuo indirizzo email",
- "Fill in an email address to enable password recovery and receive notifications" : "Inserisci il tuo indirizzo di posta per abilitare il ripristino della password e ricevere notifiche",
+ "For password recovery and notifications" : "Per il ripristino della password e per le notifiche",
"No email address set" : "Nessun indirizzo email impostato",
"You are member of the following groups:" : "Sei membro dei seguenti gruppi:",
- "Profile picture" : "Immagine del profilo",
- "Upload new" : "Carica nuova",
- "Select new from Files" : "Seleziona nuova da file",
- "Remove image" : "Rimuovi immagine",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Sia png che jpg. Preferibilmente quadrata, ma potrai ritagliarla. Il file non può superare la dimensione massima di 20 MB.",
- "Your avatar is provided by your original account." : "Il tuo avatar è ottenuto dal tuo account originale.",
- "Cancel" : "Annulla",
- "Choose as profile image" : "Scegli come immagine del profilo",
+ "Password" : "Password",
+ "Unable to change your password" : "Modifica password non riuscita",
+ "Current password" : "Password attuale",
+ "New password" : "Nuova password",
+ "Change password" : "Modifica password",
"Language" : "Lingua",
"Help translate" : "Migliora la traduzione",
- "Common Name" : "Nome comune",
- "Valid until" : "Valido fino al",
- "Issued By" : "Emesso da",
- "Valid until %s" : "Valido fino al %s",
- "Import root certificate" : "Importa certificato radice",
+ "Get the apps to sync your files" : "Scarica le applicazioni per sincronizzare i tuoi file",
+ "Desktop client" : "Client desktop",
+ "Android app" : "Applicazione Android",
+ "iOS app" : "Applicazione iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se vuoi supportare il progetto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">diventa uno sviluppatore</a>\n\t\to\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">diffondi il verbo</a>!",
+ "Show First Run Wizard again" : "Mostra nuovamente la procedura di primo avvio",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Sviluppato dalla {communityopen}comunità di ownCloud{linkclose}, il {githubopen}codice sorgente{linkclose} è rilasciato nei termini della licenza {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostra posizione di archiviazione",
"Show last log in" : "Mostra ultimo accesso",
diff --git a/settings/l10n/ja.js b/settings/l10n/ja.js
index a1827392f86..2d092c302d1 100644
--- a/settings/l10n/ja.js
+++ b/settings/l10n/ja.js
@@ -12,17 +12,15 @@ OC.L10N.register(
"Log" : "ログ",
"Tips & tricks" : "ヒントとコツ",
"Updates" : "アップデート",
- "Authentication error" : "認証エラー",
- "Your full name has been changed." : "名前を変更しました。",
- "Unable to change full name" : "名前を変更できません",
"Couldn't remove app." : "アプリが削除できませんでした。",
"Language changed" : "言語が変更されました",
"Invalid request" : "不正なリクエスト",
+ "Authentication error" : "認証エラー",
"Admins can't remove themself from the admin group" : "管理者は自身を管理者グループから削除できません。",
"Unable to add user to group %s" : "ユーザーをグループ %s に追加できません",
"Unable to remove user from group %s" : "ユーザーをグループ %s から削除できません",
"Couldn't update app." : "アプリをアップデートできませんでした。",
- "Wrong password" : "無効なパスワード",
+ "Wrong password" : "パスワードが間違っています",
"No user supplied" : "ユーザーが指定されていません",
"Please provide an admin recovery password, otherwise all user data will be lost" : "リカバリ用の管理者パスワードを入力してください。そうでない場合は、全ユーザーのデータが失われます。",
"Wrong admin recovery password. Please check the password and try again." : "リカバリ用の管理者パスワードが間違っています。パスワードを確認して再度実行してください。",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "無効なユーザー",
"Unable to change mail address" : "メールアドレスを変更できません",
"Email saved" : "メールアドレスを保存しました",
+ "Your full name has been changed." : "名前を変更しました。",
+ "Unable to change full name" : "名前を変更できません",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "\"{domain}\" を信頼するドメインに追加してもよろしいでしょうか?",
"Add trusted domain" : "信頼するドメイン名に追加",
"Migration in progress. Please wait until the migration is finished" : "移行の処理中です。移行が完了するまでお待ちください。",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "アプリは有効ですが、更新が必要です。5秒後に更新ページにリダイレクトします。",
"App update" : "アプリのアップデート",
"No apps found for \"{query}\"" : "\"{query}\" に対応するアプリはありません",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "エラーが発生しました。ASCIIコードのPEM証明書をアップロードしてください。",
+ "Valid until {date}" : "{date} まで有効",
+ "Delete" : "削除",
"An error occurred: {message}" : "エラーが発生しました: {message}",
"Select a profile picture" : "プロファイル画像を選択",
"Very weak password" : "非常に弱いパスワード",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "まずまずのパスワード",
"Good password" : "良好なパスワード",
"Strong password" : "強いパスワード",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "エラーが発生しました。ASCIIコードのPEM証明書をアップロードしてください。",
- "Valid until {date}" : "{date} まで有効",
- "Delete" : "削除",
"Groups" : "グループ",
"Unable to delete {objName}" : "{objName} を削除できません",
"Error creating group" : "グループの作成エラー",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "有効なパスワードを指定する必要があります",
"A valid email must be provided" : "有効なメールアドレスを指定する必要があります",
"__language_name__" : "Japanese (日本語)",
- "Sync clients" : "同期用クライアント",
"Personal info" : "個人情報",
- "SSL root certificates" : "SSLルート証明書",
+ "Sync clients" : "同期用クライアント",
"Everything (fatal issues, errors, warnings, info, debug)" : "すべて (致命的な問題、エラー、警告、情報、デバッグ)",
"Info, warnings, errors and fatal issues" : "情報、警告、エラー、致命的な問題",
"Warnings, errors and fatal issues" : "警告、エラー、致命的な問題",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "次のロケールをサポートするには、システムに必要なパッケージをインストールすることを強くおすすめします: %s。",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "URLがドメインのルート(/)で終わっていない場合で、システムのcronを利用している場合は、URLの生成に問題が発生します。その場合は、config.php ファイルの中の \"overwrite.cli.url\" オプションをインストールしたwebrootのパスに設定してください。(推奨: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "CLI から cronジョブを実行することができませんでした。次の技術的なエラーが発生しています:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "トランザクションファイルのロックは、データベースを使用してバックエンドのロックをしています。最高のパフォーマンスのためには、ロック用に memcache を設定することをお勧めします。詳細については、<a target=\"_blank\" href=\"%s\">ドキュメント↗ </a>を参照してください。",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "<a target=\"_blank\" href=\"%s\">インストールガイド ↗</a>をもう一度チェックして、<a href=\"#log-section\">ログ</a> にあるエラーまたは警告について確認してください。",
"All checks passed." : "すべてのチェックに合格しました。",
"Open documentation" : "ドキュメントを開く",
@@ -158,7 +156,7 @@ OC.L10N.register(
"Last cron job execution: %s. Something seems wrong." : "最終cronジョブ実行: %s 何らかの問題があります。",
"Cron was not executed yet!" : "cronはまだ実行されていません!",
"Execute one task with each page loaded" : "各ページの読み込み時にタスクを実行します。",
- "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.phpは、HTTP経由で15分ごとにcron.phpを実行するようwebcronサービスに登録されています。",
+ "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.phpは、HTTP経由で15分ごとにcron.phpを実行するようwebcronサービスに登録されます。",
"Use system's cron service to call the cron.php file every 15 minutes." : "システムのcronサービスを利用して、15分間隔でcron.phpファイルを実行します。",
"Enable server-side encryption" : "サーバーサイド暗号化を有効にする",
"Please read carefully before activating server-side encryption: " : "サーバーサイド暗号化を有効にする前によくお読みください:",
@@ -177,7 +175,7 @@ OC.L10N.register(
"Send mode" : "送信モード",
"Encryption" : "暗号化",
"From address" : "送信元アドレス",
- "mail" : "メール",
+ "mail" : "mail",
"Authentication method" : "認証方法",
"Authentication required" : "認証を必要とする",
"Server address" : "サーバーアドレス",
@@ -188,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "資格情報を保存",
"Test email settings" : "メール設定のテスト",
"Send email" : "メールを送信",
- "Log level" : "ログレベル",
"Download logfile" : "ログファイルのダウンロード",
"More" : "もっと見る",
"Less" : "閉じる",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "ログファイルが100MB以上あります。ダウンロードに時間がかかります!",
+ "What to log" : "ログ出力対象",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLiteがデータベースとして使用されています。大規模な運用では別のデータベースに切り替えることをお勧めします。",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "特にデスクトップクライアントをファイル同期に使用する場合,SQLiteは非推奨です.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "他のデータベースに移行する場合はコマンドラインツール: 'occ db:convert-type' を使ってください。 <a target=\"_blank\" href=\"%s\">ドキュメント ↗</a>を参照してください。",
@@ -206,17 +204,23 @@ OC.L10N.register(
"Developer documentation" : "開発者ドキュメント",
"Experimental applications ahead" : "実験的なアプリケーションを試す",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "実験的なアプリは、脆弱性についてチェックされていませんし、不安定であったり、激しく開発中です。それらをインストールすると、データの損失やセキュリティ侵害を引き起こす可能性があります。",
- "by" : "by",
- "licensed" : "ライセンス",
"Documentation:" : "ドキュメント:",
"User documentation" : "ユーザードキュメント",
"Admin documentation" : "管理者ドキュメント",
"Show description …" : "説明を表示 ...",
"Hide description …" : "説明を隠す ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "このアプリはownCloudの最小バージョンが指定されていません.ownCloud 11 以降でエラーが発生する可能性があります.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "このアプリはownCloudの最大バージョンが指定されていません.ownCloud 11 以降でエラーが発生する可能性があります.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "次の依存関係が満たされないためこのアプリをインストールできません:",
"Enable only for specific groups" : "特定のグループのみ有効に",
"Uninstall App" : "アプリをアンインストール",
"Enable experimental apps" : "実験的なアプリを有効にする",
+ "SSL Root Certificates" : "SSLルート証明書",
+ "Common Name" : "コモンネーム",
+ "Valid until" : "有効期限",
+ "Issued By" : "発行元",
+ "Valid until %s" : "%s まで有効",
+ "Import root certificate" : "ルート証明書をインポート",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "こんにちは、<br><br>あなたのアカウント %s が利用可能になったことをお知らせします。<br><br>ユーザー名: %s<br>以下のURLからアクセス: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "それでは!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "こんにちは、\n\nあなたのアカウント %s が利用可能になったことをお知らせします。\n\nユーザー名: %s\n接続URL: %s\n\n",
@@ -225,40 +229,33 @@ OC.L10N.register(
"Forum" : "フォーラム",
"Issue tracker" : "イシュートラッカー",
"Commercial support" : "商用サポート",
- "Get the apps to sync your files" : "ファイルを同期するアプリを取得しましょう",
- "Desktop client" : "デスクトップクライアント",
- "Android app" : "Androidアプリ",
- "iOS app" : "iOSアプリ",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "プロジェクトをサポートしていただける場合は、\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\">開発に参加する</a>か、\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\">プロジェクトを広く伝えてください</a>!",
- "Show First Run Wizard again" : "初回ウィザードを再表示する",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "現在 <strong>%s</strong> / <strong>%s</strong> を使用しています",
- "Password" : "パスワード",
- "Unable to change your password" : "パスワードを変更することができません",
- "Current password" : "現在のパスワード",
- "New password" : "新しいパスワード",
- "Change password" : "パスワードを変更",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "<strong>%s</strong> / <strong>%s</strong> が現在使用中です",
+ "Profile picture" : "プロフィール画像",
+ "Upload new" : "新たにアップロード",
+ "Select from Files" : "ファイルから選択",
+ "Remove image" : "画像を削除",
+ "png or jpg, max. 20 MB" : "png もしくは jpg, 最大.20MB",
+ "Cancel" : "キャンセル",
+ "Choose as profile picture" : "プロファイル画像として選択",
"Full name" : "氏名",
"No display name set" : "表示名が未設定",
"Email" : "メール",
"Your email address" : "あなたのメールアドレス",
- "Fill in an email address to enable password recovery and receive notifications" : "パスワードの回復を有効にし、通知を受け取るにはメールアドレスを入力してください",
"No email address set" : "メールアドレスが設定されていません",
"You are member of the following groups:" : "以下のグループのメンバーです:",
- "Profile picture" : "プロフィール画像",
- "Upload new" : "新たにアップロード",
- "Select new from Files" : "新しいファイルを選択",
- "Remove image" : "画像を削除",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "pngまたはjpg形式。正方形が理想ですが、切り取って加工することもできます。ファイルは最大20MBを超えないようにしてください。",
- "Your avatar is provided by your original account." : "あなたのアバターは、あなたのオリジナルのアカウントで提供されています。",
- "Cancel" : "キャンセル",
- "Choose as profile image" : "プロファイル画像として選択",
+ "Password" : "パスワード",
+ "Unable to change your password" : "パスワードを変更することができません",
+ "Current password" : "現在のパスワード",
+ "New password" : "新しいパスワード",
+ "Change password" : "パスワードを変更",
"Language" : "言語",
"Help translate" : "翻訳に協力する",
- "Common Name" : "コモンネーム",
- "Valid until" : "有効期限",
- "Issued By" : "発行元",
- "Valid until %s" : "%s まで有効",
- "Import root certificate" : "ルート証明書をインポート",
+ "Get the apps to sync your files" : "ファイルを同期するアプリを取得しましょう",
+ "Desktop client" : "デスクトップクライアント",
+ "Android app" : "Androidアプリ",
+ "iOS app" : "iOSアプリ",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "プロジェクトをサポートしていただける場合は、\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\">開発に参加する</a>か、\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\">プロジェクトを広く伝えてください</a>!",
+ "Show First Run Wizard again" : "初回ウィザードを再表示する",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : " {communityopen}ownCloud community{linkclose} によって開発されています。{githubopen}ソースコード{linkclose} は {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} によってライセンスされます。",
"Show storage location" : "データの保存場所を表示",
"Show last log in" : "最終ログインを表示",
diff --git a/settings/l10n/ja.json b/settings/l10n/ja.json
index a2597c026fe..996a53df9c5 100644
--- a/settings/l10n/ja.json
+++ b/settings/l10n/ja.json
@@ -10,17 +10,15 @@
"Log" : "ログ",
"Tips & tricks" : "ヒントとコツ",
"Updates" : "アップデート",
- "Authentication error" : "認証エラー",
- "Your full name has been changed." : "名前を変更しました。",
- "Unable to change full name" : "名前を変更できません",
"Couldn't remove app." : "アプリが削除できませんでした。",
"Language changed" : "言語が変更されました",
"Invalid request" : "不正なリクエスト",
+ "Authentication error" : "認証エラー",
"Admins can't remove themself from the admin group" : "管理者は自身を管理者グループから削除できません。",
"Unable to add user to group %s" : "ユーザーをグループ %s に追加できません",
"Unable to remove user from group %s" : "ユーザーをグループ %s から削除できません",
"Couldn't update app." : "アプリをアップデートできませんでした。",
- "Wrong password" : "無効なパスワード",
+ "Wrong password" : "パスワードが間違っています",
"No user supplied" : "ユーザーが指定されていません",
"Please provide an admin recovery password, otherwise all user data will be lost" : "リカバリ用の管理者パスワードを入力してください。そうでない場合は、全ユーザーのデータが失われます。",
"Wrong admin recovery password. Please check the password and try again." : "リカバリ用の管理者パスワードが間違っています。パスワードを確認して再度実行してください。",
@@ -51,6 +49,8 @@
"Invalid user" : "無効なユーザー",
"Unable to change mail address" : "メールアドレスを変更できません",
"Email saved" : "メールアドレスを保存しました",
+ "Your full name has been changed." : "名前を変更しました。",
+ "Unable to change full name" : "名前を変更できません",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "\"{domain}\" を信頼するドメインに追加してもよろしいでしょうか?",
"Add trusted domain" : "信頼するドメイン名に追加",
"Migration in progress. Please wait until the migration is finished" : "移行の処理中です。移行が完了するまでお待ちください。",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "アプリは有効ですが、更新が必要です。5秒後に更新ページにリダイレクトします。",
"App update" : "アプリのアップデート",
"No apps found for \"{query}\"" : "\"{query}\" に対応するアプリはありません",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "エラーが発生しました。ASCIIコードのPEM証明書をアップロードしてください。",
+ "Valid until {date}" : "{date} まで有効",
+ "Delete" : "削除",
"An error occurred: {message}" : "エラーが発生しました: {message}",
"Select a profile picture" : "プロファイル画像を選択",
"Very weak password" : "非常に弱いパスワード",
@@ -86,9 +89,6 @@
"So-so password" : "まずまずのパスワード",
"Good password" : "良好なパスワード",
"Strong password" : "強いパスワード",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "エラーが発生しました。ASCIIコードのPEM証明書をアップロードしてください。",
- "Valid until {date}" : "{date} まで有効",
- "Delete" : "削除",
"Groups" : "グループ",
"Unable to delete {objName}" : "{objName} を削除できません",
"Error creating group" : "グループの作成エラー",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "有効なパスワードを指定する必要があります",
"A valid email must be provided" : "有効なメールアドレスを指定する必要があります",
"__language_name__" : "Japanese (日本語)",
- "Sync clients" : "同期用クライアント",
"Personal info" : "個人情報",
- "SSL root certificates" : "SSLルート証明書",
+ "Sync clients" : "同期用クライアント",
"Everything (fatal issues, errors, warnings, info, debug)" : "すべて (致命的な問題、エラー、警告、情報、デバッグ)",
"Info, warnings, errors and fatal issues" : "情報、警告、エラー、致命的な問題",
"Warnings, errors and fatal issues" : "警告、エラー、致命的な問題",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "次のロケールをサポートするには、システムに必要なパッケージをインストールすることを強くおすすめします: %s。",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "URLがドメインのルート(/)で終わっていない場合で、システムのcronを利用している場合は、URLの生成に問題が発生します。その場合は、config.php ファイルの中の \"overwrite.cli.url\" オプションをインストールしたwebrootのパスに設定してください。(推奨: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "CLI から cronジョブを実行することができませんでした。次の技術的なエラーが発生しています:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "トランザクションファイルのロックは、データベースを使用してバックエンドのロックをしています。最高のパフォーマンスのためには、ロック用に memcache を設定することをお勧めします。詳細については、<a target=\"_blank\" href=\"%s\">ドキュメント↗ </a>を参照してください。",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "<a target=\"_blank\" href=\"%s\">インストールガイド ↗</a>をもう一度チェックして、<a href=\"#log-section\">ログ</a> にあるエラーまたは警告について確認してください。",
"All checks passed." : "すべてのチェックに合格しました。",
"Open documentation" : "ドキュメントを開く",
@@ -156,7 +154,7 @@
"Last cron job execution: %s. Something seems wrong." : "最終cronジョブ実行: %s 何らかの問題があります。",
"Cron was not executed yet!" : "cronはまだ実行されていません!",
"Execute one task with each page loaded" : "各ページの読み込み時にタスクを実行します。",
- "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.phpは、HTTP経由で15分ごとにcron.phpを実行するようwebcronサービスに登録されています。",
+ "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.phpは、HTTP経由で15分ごとにcron.phpを実行するようwebcronサービスに登録されます。",
"Use system's cron service to call the cron.php file every 15 minutes." : "システムのcronサービスを利用して、15分間隔でcron.phpファイルを実行します。",
"Enable server-side encryption" : "サーバーサイド暗号化を有効にする",
"Please read carefully before activating server-side encryption: " : "サーバーサイド暗号化を有効にする前によくお読みください:",
@@ -175,7 +173,7 @@
"Send mode" : "送信モード",
"Encryption" : "暗号化",
"From address" : "送信元アドレス",
- "mail" : "メール",
+ "mail" : "mail",
"Authentication method" : "認証方法",
"Authentication required" : "認証を必要とする",
"Server address" : "サーバーアドレス",
@@ -186,11 +184,11 @@
"Store credentials" : "資格情報を保存",
"Test email settings" : "メール設定のテスト",
"Send email" : "メールを送信",
- "Log level" : "ログレベル",
"Download logfile" : "ログファイルのダウンロード",
"More" : "もっと見る",
"Less" : "閉じる",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "ログファイルが100MB以上あります。ダウンロードに時間がかかります!",
+ "What to log" : "ログ出力対象",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLiteがデータベースとして使用されています。大規模な運用では別のデータベースに切り替えることをお勧めします。",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "特にデスクトップクライアントをファイル同期に使用する場合,SQLiteは非推奨です.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "他のデータベースに移行する場合はコマンドラインツール: 'occ db:convert-type' を使ってください。 <a target=\"_blank\" href=\"%s\">ドキュメント ↗</a>を参照してください。",
@@ -204,17 +202,23 @@
"Developer documentation" : "開発者ドキュメント",
"Experimental applications ahead" : "実験的なアプリケーションを試す",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "実験的なアプリは、脆弱性についてチェックされていませんし、不安定であったり、激しく開発中です。それらをインストールすると、データの損失やセキュリティ侵害を引き起こす可能性があります。",
- "by" : "by",
- "licensed" : "ライセンス",
"Documentation:" : "ドキュメント:",
"User documentation" : "ユーザードキュメント",
"Admin documentation" : "管理者ドキュメント",
"Show description …" : "説明を表示 ...",
"Hide description …" : "説明を隠す ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "このアプリはownCloudの最小バージョンが指定されていません.ownCloud 11 以降でエラーが発生する可能性があります.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "このアプリはownCloudの最大バージョンが指定されていません.ownCloud 11 以降でエラーが発生する可能性があります.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "次の依存関係が満たされないためこのアプリをインストールできません:",
"Enable only for specific groups" : "特定のグループのみ有効に",
"Uninstall App" : "アプリをアンインストール",
"Enable experimental apps" : "実験的なアプリを有効にする",
+ "SSL Root Certificates" : "SSLルート証明書",
+ "Common Name" : "コモンネーム",
+ "Valid until" : "有効期限",
+ "Issued By" : "発行元",
+ "Valid until %s" : "%s まで有効",
+ "Import root certificate" : "ルート証明書をインポート",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "こんにちは、<br><br>あなたのアカウント %s が利用可能になったことをお知らせします。<br><br>ユーザー名: %s<br>以下のURLからアクセス: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "それでは!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "こんにちは、\n\nあなたのアカウント %s が利用可能になったことをお知らせします。\n\nユーザー名: %s\n接続URL: %s\n\n",
@@ -223,40 +227,33 @@
"Forum" : "フォーラム",
"Issue tracker" : "イシュートラッカー",
"Commercial support" : "商用サポート",
- "Get the apps to sync your files" : "ファイルを同期するアプリを取得しましょう",
- "Desktop client" : "デスクトップクライアント",
- "Android app" : "Androidアプリ",
- "iOS app" : "iOSアプリ",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "プロジェクトをサポートしていただける場合は、\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\">開発に参加する</a>か、\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\">プロジェクトを広く伝えてください</a>!",
- "Show First Run Wizard again" : "初回ウィザードを再表示する",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "現在 <strong>%s</strong> / <strong>%s</strong> を使用しています",
- "Password" : "パスワード",
- "Unable to change your password" : "パスワードを変更することができません",
- "Current password" : "現在のパスワード",
- "New password" : "新しいパスワード",
- "Change password" : "パスワードを変更",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "<strong>%s</strong> / <strong>%s</strong> が現在使用中です",
+ "Profile picture" : "プロフィール画像",
+ "Upload new" : "新たにアップロード",
+ "Select from Files" : "ファイルから選択",
+ "Remove image" : "画像を削除",
+ "png or jpg, max. 20 MB" : "png もしくは jpg, 最大.20MB",
+ "Cancel" : "キャンセル",
+ "Choose as profile picture" : "プロファイル画像として選択",
"Full name" : "氏名",
"No display name set" : "表示名が未設定",
"Email" : "メール",
"Your email address" : "あなたのメールアドレス",
- "Fill in an email address to enable password recovery and receive notifications" : "パスワードの回復を有効にし、通知を受け取るにはメールアドレスを入力してください",
"No email address set" : "メールアドレスが設定されていません",
"You are member of the following groups:" : "以下のグループのメンバーです:",
- "Profile picture" : "プロフィール画像",
- "Upload new" : "新たにアップロード",
- "Select new from Files" : "新しいファイルを選択",
- "Remove image" : "画像を削除",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "pngまたはjpg形式。正方形が理想ですが、切り取って加工することもできます。ファイルは最大20MBを超えないようにしてください。",
- "Your avatar is provided by your original account." : "あなたのアバターは、あなたのオリジナルのアカウントで提供されています。",
- "Cancel" : "キャンセル",
- "Choose as profile image" : "プロファイル画像として選択",
+ "Password" : "パスワード",
+ "Unable to change your password" : "パスワードを変更することができません",
+ "Current password" : "現在のパスワード",
+ "New password" : "新しいパスワード",
+ "Change password" : "パスワードを変更",
"Language" : "言語",
"Help translate" : "翻訳に協力する",
- "Common Name" : "コモンネーム",
- "Valid until" : "有効期限",
- "Issued By" : "発行元",
- "Valid until %s" : "%s まで有効",
- "Import root certificate" : "ルート証明書をインポート",
+ "Get the apps to sync your files" : "ファイルを同期するアプリを取得しましょう",
+ "Desktop client" : "デスクトップクライアント",
+ "Android app" : "Androidアプリ",
+ "iOS app" : "iOSアプリ",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "プロジェクトをサポートしていただける場合は、\n<a href=\"https://owncloud.org/contribute\"\ntarget=\"_blank\">開発に参加する</a>か、\n<a href=\"https://owncloud.org/promote\"\ntarget=\"_blank\">プロジェクトを広く伝えてください</a>!",
+ "Show First Run Wizard again" : "初回ウィザードを再表示する",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : " {communityopen}ownCloud community{linkclose} によって開発されています。{githubopen}ソースコード{linkclose} は {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} によってライセンスされます。",
"Show storage location" : "データの保存場所を表示",
"Show last log in" : "最終ログインを表示",
diff --git a/settings/l10n/ka_GE.js b/settings/l10n/ka_GE.js
index ef91923ae2d..91d02aa0395 100644
--- a/settings/l10n/ka_GE.js
+++ b/settings/l10n/ka_GE.js
@@ -5,9 +5,9 @@ OC.L10N.register(
"External Storage" : "ექსტერნალ საცავი",
"Cron" : "Cron–ი",
"Log" : "ლოგი",
- "Authentication error" : "ავთენტიფიკაციის შეცდომა",
"Language changed" : "ენა შეცვლილია",
"Invalid request" : "არასწორი მოთხოვნა",
+ "Authentication error" : "ავთენტიფიკაციის შეცდომა",
"Admins can't remove themself from the admin group" : "ადმინისტრატორებს არ შეუძლიათ საკუთარი თავის წაშლა ადმინ ჯგუფიდან",
"Unable to add user to group %s" : "მომხმარებლის დამატება ვერ მოხეხდა ჯგუფში %s",
"Unable to remove user from group %s" : "მომხმარებლის წაშლა ვერ მოხეხდა ჯგუფიდან %s",
@@ -30,7 +30,6 @@ OC.L10N.register(
"Error creating user" : "შეცდომა მომხმარებლის შექმნისას",
"A valid password must be provided" : "უნდა მიუთითოთ არსებული პაროლი",
"__language_name__" : "__language_name__",
- "SSL root certificates" : "SSL root სერთიფიკატები",
"None" : "არა",
"Login" : "ლოგინი",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "PHP მოდული 'fileinfo' არ არსებობს. ჩვენ გირჩევთ რომ აუცილებლად ჩართოთ ეს მოდული, რომ მიიღოთ კარგი შედეგები mime-type–ს აღმოჩენისას.",
@@ -41,25 +40,22 @@ OC.L10N.register(
"Server address" : "სერვერის მისამართი",
"Port" : "პორტი",
"Credentials" : "იუზერ/პაროლი",
- "Log level" : "ლოგირების დონე",
"More" : "უფრო მეტი",
"Less" : "უფრო ნაკლები",
"Version" : "ვერსია",
- "by" : "მიერ",
"Forum" : "ფორუმი",
- "Get the apps to sync your files" : "აპლიკაცია ფაილების სინქრონიზაციისთვის",
- "Show First Run Wizard again" : "მაჩვენე თავიდან გაშვებული ვიზარდი",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "თქვენ გამოყენებული გაქვთ <strong>%s</strong> –ი –<strong>%s<strong>–დან",
+ "Cancel" : "უარყოფა",
+ "Email" : "იმეილი",
+ "Your email address" : "თქვენი იმეილ მისამართი",
"Password" : "პაროლი",
"Unable to change your password" : "თქვენი პაროლი არ შეიცვალა",
"Current password" : "მიმდინარე პაროლი",
"New password" : "ახალი პაროლი",
"Change password" : "პაროლის შეცვლა",
- "Email" : "იმეილი",
- "Your email address" : "თქვენი იმეილ მისამართი",
- "Cancel" : "უარყოფა",
"Language" : "ენა",
"Help translate" : "თარგმნის დახმარება",
+ "Get the apps to sync your files" : "აპლიკაცია ფაილების სინქრონიზაციისთვის",
+ "Show First Run Wizard again" : "მაჩვენე თავიდან გაშვებული ვიზარდი",
"Username" : "მომხმარებლის სახელი",
"Create" : "შექმნა",
"Default Quota" : "საწყისი ქვოტა",
diff --git a/settings/l10n/ka_GE.json b/settings/l10n/ka_GE.json
index e3414ed1996..8c3c322d0dd 100644
--- a/settings/l10n/ka_GE.json
+++ b/settings/l10n/ka_GE.json
@@ -3,9 +3,9 @@
"External Storage" : "ექსტერნალ საცავი",
"Cron" : "Cron–ი",
"Log" : "ლოგი",
- "Authentication error" : "ავთენტიფიკაციის შეცდომა",
"Language changed" : "ენა შეცვლილია",
"Invalid request" : "არასწორი მოთხოვნა",
+ "Authentication error" : "ავთენტიფიკაციის შეცდომა",
"Admins can't remove themself from the admin group" : "ადმინისტრატორებს არ შეუძლიათ საკუთარი თავის წაშლა ადმინ ჯგუფიდან",
"Unable to add user to group %s" : "მომხმარებლის დამატება ვერ მოხეხდა ჯგუფში %s",
"Unable to remove user from group %s" : "მომხმარებლის წაშლა ვერ მოხეხდა ჯგუფიდან %s",
@@ -28,7 +28,6 @@
"Error creating user" : "შეცდომა მომხმარებლის შექმნისას",
"A valid password must be provided" : "უნდა მიუთითოთ არსებული პაროლი",
"__language_name__" : "__language_name__",
- "SSL root certificates" : "SSL root სერთიფიკატები",
"None" : "არა",
"Login" : "ლოგინი",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "PHP მოდული 'fileinfo' არ არსებობს. ჩვენ გირჩევთ რომ აუცილებლად ჩართოთ ეს მოდული, რომ მიიღოთ კარგი შედეგები mime-type–ს აღმოჩენისას.",
@@ -39,25 +38,22 @@
"Server address" : "სერვერის მისამართი",
"Port" : "პორტი",
"Credentials" : "იუზერ/პაროლი",
- "Log level" : "ლოგირების დონე",
"More" : "უფრო მეტი",
"Less" : "უფრო ნაკლები",
"Version" : "ვერსია",
- "by" : "მიერ",
"Forum" : "ფორუმი",
- "Get the apps to sync your files" : "აპლიკაცია ფაილების სინქრონიზაციისთვის",
- "Show First Run Wizard again" : "მაჩვენე თავიდან გაშვებული ვიზარდი",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "თქვენ გამოყენებული გაქვთ <strong>%s</strong> –ი –<strong>%s<strong>–დან",
+ "Cancel" : "უარყოფა",
+ "Email" : "იმეილი",
+ "Your email address" : "თქვენი იმეილ მისამართი",
"Password" : "პაროლი",
"Unable to change your password" : "თქვენი პაროლი არ შეიცვალა",
"Current password" : "მიმდინარე პაროლი",
"New password" : "ახალი პაროლი",
"Change password" : "პაროლის შეცვლა",
- "Email" : "იმეილი",
- "Your email address" : "თქვენი იმეილ მისამართი",
- "Cancel" : "უარყოფა",
"Language" : "ენა",
"Help translate" : "თარგმნის დახმარება",
+ "Get the apps to sync your files" : "აპლიკაცია ფაილების სინქრონიზაციისთვის",
+ "Show First Run Wizard again" : "მაჩვენე თავიდან გაშვებული ვიზარდი",
"Username" : "მომხმარებლის სახელი",
"Create" : "შექმნა",
"Default Quota" : "საწყისი ქვოტა",
diff --git a/settings/l10n/km.js b/settings/l10n/km.js
index 862763507a0..fce466a0cae 100644
--- a/settings/l10n/km.js
+++ b/settings/l10n/km.js
@@ -5,9 +5,9 @@ OC.L10N.register(
"External Storage" : "ឃ្លាំងផ្ទុក​ខាងក្រៅ",
"Cron" : "Cron",
"Log" : "Log",
- "Authentication error" : "កំហុស​ការ​ផ្ទៀង​ផ្ទាត់​ភាព​ត្រឹម​ត្រូវ",
"Language changed" : "បាន​ប្ដូរ​ភាសា",
"Invalid request" : "សំណើ​មិន​ត្រឹម​ត្រូវ",
+ "Authentication error" : "កំហុស​ការ​ផ្ទៀង​ផ្ទាត់​ភាព​ត្រឹម​ត្រូវ",
"Admins can't remove themself from the admin group" : "អ្នក​គ្រប់​គ្រង​មិន​អាច​លុប​ខ្លួន​ឯង​ចេញ​ពី​ក្រុម​អ្នក​គ្រប់​គ្រង​ឡើយ",
"Unable to add user to group %s" : "មិន​អាច​បន្ថែម​អ្នក​ប្រើ​ទៅ​ក្រុម %s",
"Unable to remove user from group %s" : "មិន​អាច​ដក​អ្នក​ប្រើ​ចេញ​ពី​ក្រុម​ %s",
@@ -28,13 +28,13 @@ OC.L10N.register(
"Updating...." : "កំពុង​ធ្វើ​បច្ចុប្បន្នភាព....",
"Error while updating app" : "មាន​កំហុស​ពេល​ធ្វើ​បច្ចុប្បន្នភាព​កម្មវិធី",
"Updated" : "បាន​ធ្វើ​បច្ចុប្បន្នភាព",
+ "Delete" : "លុប",
"Select a profile picture" : "ជ្រើស​រូបភាព​ប្រវត្តិរូប",
"Very weak password" : "ពាក្យ​សម្ងាត់​ខ្សោយ​ណាស់",
"Weak password" : "ពាក្យ​សម្ងាត់​ខ្សោយ",
"So-so password" : "ពាក្យ​សម្ងាត់​ធម្មតា",
"Good password" : "ពាក្យ​សម្ងាត់​ល្អ",
"Strong password" : "ពាក្យ​សម្ងាត់​ខ្លាំង",
- "Delete" : "លុប",
"Groups" : "ក្រុ",
"undo" : "មិន​ធ្វើ​វិញ",
"never" : "មិនដែរ",
@@ -56,29 +56,25 @@ OC.L10N.register(
"Server address" : "អាសយដ្ឋាន​ម៉ាស៊ីន​បម្រើ",
"Port" : "ច្រក",
"Send email" : "ផ្ញើ​អ៊ីមែល",
- "Log level" : "កម្រិត Log",
"More" : "ច្រើន​ទៀត",
"Less" : "តិច",
"Version" : "កំណែ",
- "by" : "ដោយ",
"Forum" : "វេទិកាពិភាក្សា",
- "Get the apps to sync your files" : "ដាក់​អោយកម្មវិធីផ្សេងៗ ​ធ្វើសមកាលកម្ម​ឯកសារ​អ្នក",
- "Show First Run Wizard again" : "បង្ហាញ First Run Wizard ម្តង​ទៀត",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "អ្នក​បាន​ប្រើ <strong>%s</strong> ក្នុង​ចំណោម​ចំនួន​មាន <strong>%s</strong>",
+ "Profile picture" : "រូបភាព​ប្រវត្តិរូប",
+ "Upload new" : "ផ្ទុកឡើង​ថ្មី",
+ "Remove image" : "ដក​រូបភាព​ចេញ",
+ "Cancel" : "លើកលែង",
+ "Email" : "អ៊ីមែល",
+ "Your email address" : "អ៊ីម៉ែល​របស់​អ្នក",
"Password" : "ពាក្យសម្ងាត់",
"Unable to change your password" : "មិន​អាច​ប្ដូរ​ពាក្យ​សម្ងាត់​របស់​អ្នក​បាន​ទេ",
"Current password" : "ពាក្យសម្ងាត់​បច្ចុប្បន្ន",
"New password" : "ពាក្យ​សម្ងាត់​ថ្មី",
"Change password" : "ប្តូរ​ពាក្យសម្ងាត់",
- "Email" : "អ៊ីមែល",
- "Your email address" : "អ៊ីម៉ែល​របស់​អ្នក",
- "Profile picture" : "រូបភាព​ប្រវត្តិរូប",
- "Upload new" : "ផ្ទុកឡើង​ថ្មី",
- "Select new from Files" : "ជ្រើស​ថ្មី​ពី​ឯកសារ",
- "Remove image" : "ដក​រូបភាព​ចេញ",
- "Cancel" : "លើកលែង",
"Language" : "ភាសា",
"Help translate" : "ជួយ​បក​ប្រែ",
+ "Get the apps to sync your files" : "ដាក់​អោយកម្មវិធីផ្សេងៗ ​ធ្វើសមកាលកម្ម​ឯកសារ​អ្នក",
+ "Show First Run Wizard again" : "បង្ហាញ First Run Wizard ម្តង​ទៀត",
"Username" : "ឈ្មោះ​អ្នកប្រើ",
"Create" : "បង្កើត",
"Admin Recovery Password" : "ការ​ស្វែង​រក​ពាក្យ​សម្ងាត់របស់ប្រធាន​វេបសាយ",
diff --git a/settings/l10n/km.json b/settings/l10n/km.json
index 3ba4b0784ee..3b158de7505 100644
--- a/settings/l10n/km.json
+++ b/settings/l10n/km.json
@@ -3,9 +3,9 @@
"External Storage" : "ឃ្លាំងផ្ទុក​ខាងក្រៅ",
"Cron" : "Cron",
"Log" : "Log",
- "Authentication error" : "កំហុស​ការ​ផ្ទៀង​ផ្ទាត់​ភាព​ត្រឹម​ត្រូវ",
"Language changed" : "បាន​ប្ដូរ​ភាសា",
"Invalid request" : "សំណើ​មិន​ត្រឹម​ត្រូវ",
+ "Authentication error" : "កំហុស​ការ​ផ្ទៀង​ផ្ទាត់​ភាព​ត្រឹម​ត្រូវ",
"Admins can't remove themself from the admin group" : "អ្នក​គ្រប់​គ្រង​មិន​អាច​លុប​ខ្លួន​ឯង​ចេញ​ពី​ក្រុម​អ្នក​គ្រប់​គ្រង​ឡើយ",
"Unable to add user to group %s" : "មិន​អាច​បន្ថែម​អ្នក​ប្រើ​ទៅ​ក្រុម %s",
"Unable to remove user from group %s" : "មិន​អាច​ដក​អ្នក​ប្រើ​ចេញ​ពី​ក្រុម​ %s",
@@ -26,13 +26,13 @@
"Updating...." : "កំពុង​ធ្វើ​បច្ចុប្បន្នភាព....",
"Error while updating app" : "មាន​កំហុស​ពេល​ធ្វើ​បច្ចុប្បន្នភាព​កម្មវិធី",
"Updated" : "បាន​ធ្វើ​បច្ចុប្បន្នភាព",
+ "Delete" : "លុប",
"Select a profile picture" : "ជ្រើស​រូបភាព​ប្រវត្តិរូប",
"Very weak password" : "ពាក្យ​សម្ងាត់​ខ្សោយ​ណាស់",
"Weak password" : "ពាក្យ​សម្ងាត់​ខ្សោយ",
"So-so password" : "ពាក្យ​សម្ងាត់​ធម្មតា",
"Good password" : "ពាក្យ​សម្ងាត់​ល្អ",
"Strong password" : "ពាក្យ​សម្ងាត់​ខ្លាំង",
- "Delete" : "លុប",
"Groups" : "ក្រុ",
"undo" : "មិន​ធ្វើ​វិញ",
"never" : "មិនដែរ",
@@ -54,29 +54,25 @@
"Server address" : "អាសយដ្ឋាន​ម៉ាស៊ីន​បម្រើ",
"Port" : "ច្រក",
"Send email" : "ផ្ញើ​អ៊ីមែល",
- "Log level" : "កម្រិត Log",
"More" : "ច្រើន​ទៀត",
"Less" : "តិច",
"Version" : "កំណែ",
- "by" : "ដោយ",
"Forum" : "វេទិកាពិភាក្សា",
- "Get the apps to sync your files" : "ដាក់​អោយកម្មវិធីផ្សេងៗ ​ធ្វើសមកាលកម្ម​ឯកសារ​អ្នក",
- "Show First Run Wizard again" : "បង្ហាញ First Run Wizard ម្តង​ទៀត",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "អ្នក​បាន​ប្រើ <strong>%s</strong> ក្នុង​ចំណោម​ចំនួន​មាន <strong>%s</strong>",
+ "Profile picture" : "រូបភាព​ប្រវត្តិរូប",
+ "Upload new" : "ផ្ទុកឡើង​ថ្មី",
+ "Remove image" : "ដក​រូបភាព​ចេញ",
+ "Cancel" : "លើកលែង",
+ "Email" : "អ៊ីមែល",
+ "Your email address" : "អ៊ីម៉ែល​របស់​អ្នក",
"Password" : "ពាក្យសម្ងាត់",
"Unable to change your password" : "មិន​អាច​ប្ដូរ​ពាក្យ​សម្ងាត់​របស់​អ្នក​បាន​ទេ",
"Current password" : "ពាក្យសម្ងាត់​បច្ចុប្បន្ន",
"New password" : "ពាក្យ​សម្ងាត់​ថ្មី",
"Change password" : "ប្តូរ​ពាក្យសម្ងាត់",
- "Email" : "អ៊ីមែល",
- "Your email address" : "អ៊ីម៉ែល​របស់​អ្នក",
- "Profile picture" : "រូបភាព​ប្រវត្តិរូប",
- "Upload new" : "ផ្ទុកឡើង​ថ្មី",
- "Select new from Files" : "ជ្រើស​ថ្មី​ពី​ឯកសារ",
- "Remove image" : "ដក​រូបភាព​ចេញ",
- "Cancel" : "លើកលែង",
"Language" : "ភាសា",
"Help translate" : "ជួយ​បក​ប្រែ",
+ "Get the apps to sync your files" : "ដាក់​អោយកម្មវិធីផ្សេងៗ ​ធ្វើសមកាលកម្ម​ឯកសារ​អ្នក",
+ "Show First Run Wizard again" : "បង្ហាញ First Run Wizard ម្តង​ទៀត",
"Username" : "ឈ្មោះ​អ្នកប្រើ",
"Create" : "បង្កើត",
"Admin Recovery Password" : "ការ​ស្វែង​រក​ពាក្យ​សម្ងាត់របស់ប្រធាន​វេបសាយ",
diff --git a/settings/l10n/kn.js b/settings/l10n/kn.js
index f70cb0b3ce8..e430be090bb 100644
--- a/settings/l10n/kn.js
+++ b/settings/l10n/kn.js
@@ -3,12 +3,10 @@ OC.L10N.register(
{
"Sharing" : "ಹಂಚಿಕೆ",
"Log" : "ಹಿನ್ನೆಲೆಯ ದಾಖಲೆ",
- "Authentication error" : "ದೃಢೀಕರಣ ದೋಷ",
- "Your full name has been changed." : "ನಿಮ್ಮ ಪೂರ್ಣ ಹೆಸರನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ.",
- "Unable to change full name" : "ಪೂರ್ಣ ಹೆಸರನ್ನು ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ",
"Couldn't remove app." : "ಅಳಿಸುವಾಗ ಏನೊ ಲೋಪವಾಗಿದೆ",
"Language changed" : "ಭಾಷೆಯನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ",
"Invalid request" : "ಅಮಾನ್ಯ ಕೋರಿಕೆ",
+ "Authentication error" : "ದೃಢೀಕರಣ ದೋಷ",
"Admins can't remove themself from the admin group" : "ನಿರ್ವಾಹಕರು ನಿರ್ವಹಣೆ ಗುಂಪಿನಿಂದ ತಮ್ಮನ್ನೇ ತಾವು ತೆಗೆದುಹಾಕಿಕೊಳ್ಳಲು ಸಾಧ್ಯವಿಲ್ಲ",
"Unable to add user to group %s" : "%s ಗುಂಪಿಗೆ ಹೂಸ ಬಳಕೆದಾರನನ್ನು ಸೇರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
"Unable to remove user from group %s" : "%s ಗುಂಪು ಬಳಕೆದಾರ ತೆಗೆದುಹಾಕಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ",
@@ -33,6 +31,8 @@ OC.L10N.register(
"Invalid user" : "ಅಮಾನ್ಯ ಬಳಕೆದಾರ",
"Unable to change mail address" : "ಇ-ಅಂಚೆ ವಿಳಾಸ ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
"Email saved" : "ಇ-ಅಂಚೆಯನ್ನು ಉಳಿಸಿದೆ",
+ "Your full name has been changed." : "ನಿಮ್ಮ ಪೂರ್ಣ ಹೆಸರನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ.",
+ "Unable to change full name" : "ಪೂರ್ಣ ಹೆಸರನ್ನು ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ",
"Sending..." : "ಕಳುಹಿಸಲಾಗುತ್ತಿದೆ ...",
"All" : "ಎಲ್ಲಾ",
"Please wait...." : "ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ ....",
@@ -46,14 +46,14 @@ OC.L10N.register(
"Uninstalling ...." : "ಅಳಿಸಿಹಾಕುವುದು ...",
"Error while uninstalling app" : "ಅಳಿಸುವಾಗ ಏನೊ ಲೋಪವಾಗಿದೆ",
"Uninstall" : "ಅಳಿಸಿ",
+ "Valid until {date}" : "{date} ವರೆಗೆ ಚಾಲ್ತಿಯಲ್ಲಿರುತ್ತದೆ",
+ "Delete" : "ಅಳಿಸಿ",
"Select a profile picture" : "ಸಂಕ್ಷಿಪ್ತ ವ್ಯಕ್ತಿಚಿತ್ರ ಒಂದನ್ನು ಆಯ್ಕೆ ಮಾಡಿ",
"Very weak password" : "ಅತೀ ದುರ್ಬಲ ಗುಪ್ತಪದ",
"Weak password" : "ದುರ್ಬಲ ಗುಪ್ತಪದ",
"So-so password" : "ಊಹಿಸಬಹುದಾದ ಗುಪ್ತಪದ",
"Good password" : "ಉತ್ತಮ ಗುಪ್ತಪದ",
"Strong password" : "ಪ್ರಬಲ ಗುಪ್ತಪದ",
- "Valid until {date}" : "{date} ವರೆಗೆ ಚಾಲ್ತಿಯಲ್ಲಿರುತ್ತದೆ",
- "Delete" : "ಅಳಿಸಿ",
"Groups" : "ಗುಂಪುಗಳು",
"Unable to delete {objName}" : "{objName} ಅಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ ",
"Error creating group" : "ಗುಂಪುನ್ನು ರಚಿಸುವಾಗ ದೋಷವಾಗಿದೆ",
@@ -92,7 +92,6 @@ OC.L10N.register(
"SMTP Password" : "SMTP ಗುಪ್ತ ಪದ",
"Test email settings" : "ಪರೀರ್ಕ್ಷಾತ ಇ-ಅಂಚೆಯ ಆಯ್ಕೇ",
"Send email" : "ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸಿ",
- "Log level" : "ಹಿನ್ನೆಲೆಯ ದಾಖಲೆಯ ಮಟ್ಟದ",
"More" : "ಇನ್ನಷ್ಟು",
"Less" : "ಕಡಿಮೆ",
"Version" : "ಆವೃತ್ತಿ",
@@ -101,14 +100,14 @@ OC.L10N.register(
"Uninstall App" : "ಅಳಿಸಿ",
"Cheers!" : "ಆನಂದಿಸಿ !",
"Forum" : "ವೇದಿಕೆ",
+ "Cancel" : "ರದ್ದು",
+ "Email" : "ಇ-ಅಂಚೆ",
+ "Your email address" : "ನಿಮ್ಮ ಇ-ಅಂಚೆ ವಿಳಾಸ",
"Password" : "ಗುಪ್ತ ಪದ",
"Unable to change your password" : "ನಿನ್ನ ಗುಪ್ತಪದವನ್ನು ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
"Current password" : "ಪ್ರಸ್ತುತ ಗುಪ್ತಪದ",
"New password" : "ಹೊಸ ಗುಪ್ತಪದ",
"Change password" : "ಗುಪ್ತ ಪದವನ್ನು ಬದಲಾಯಿಸಿ",
- "Email" : "ಇ-ಅಂಚೆ",
- "Your email address" : "ನಿಮ್ಮ ಇ-ಅಂಚೆ ವಿಳಾಸ",
- "Cancel" : "ರದ್ದು",
"Language" : "ಭಾಷೆ",
"Help translate" : "ಭಾಷಾಂತರಿಸಲು ಸಹಾಯ ಮಾಡಿ",
"Username" : "ಬಳಕೆಯ ಹೆಸರು",
diff --git a/settings/l10n/kn.json b/settings/l10n/kn.json
index 54d5df31bc9..890d9cc994d 100644
--- a/settings/l10n/kn.json
+++ b/settings/l10n/kn.json
@@ -1,12 +1,10 @@
{ "translations": {
"Sharing" : "ಹಂಚಿಕೆ",
"Log" : "ಹಿನ್ನೆಲೆಯ ದಾಖಲೆ",
- "Authentication error" : "ದೃಢೀಕರಣ ದೋಷ",
- "Your full name has been changed." : "ನಿಮ್ಮ ಪೂರ್ಣ ಹೆಸರನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ.",
- "Unable to change full name" : "ಪೂರ್ಣ ಹೆಸರನ್ನು ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ",
"Couldn't remove app." : "ಅಳಿಸುವಾಗ ಏನೊ ಲೋಪವಾಗಿದೆ",
"Language changed" : "ಭಾಷೆಯನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ",
"Invalid request" : "ಅಮಾನ್ಯ ಕೋರಿಕೆ",
+ "Authentication error" : "ದೃಢೀಕರಣ ದೋಷ",
"Admins can't remove themself from the admin group" : "ನಿರ್ವಾಹಕರು ನಿರ್ವಹಣೆ ಗುಂಪಿನಿಂದ ತಮ್ಮನ್ನೇ ತಾವು ತೆಗೆದುಹಾಕಿಕೊಳ್ಳಲು ಸಾಧ್ಯವಿಲ್ಲ",
"Unable to add user to group %s" : "%s ಗುಂಪಿಗೆ ಹೂಸ ಬಳಕೆದಾರನನ್ನು ಸೇರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
"Unable to remove user from group %s" : "%s ಗುಂಪು ಬಳಕೆದಾರ ತೆಗೆದುಹಾಕಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ",
@@ -31,6 +29,8 @@
"Invalid user" : "ಅಮಾನ್ಯ ಬಳಕೆದಾರ",
"Unable to change mail address" : "ಇ-ಅಂಚೆ ವಿಳಾಸ ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
"Email saved" : "ಇ-ಅಂಚೆಯನ್ನು ಉಳಿಸಿದೆ",
+ "Your full name has been changed." : "ನಿಮ್ಮ ಪೂರ್ಣ ಹೆಸರನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ.",
+ "Unable to change full name" : "ಪೂರ್ಣ ಹೆಸರನ್ನು ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ",
"Sending..." : "ಕಳುಹಿಸಲಾಗುತ್ತಿದೆ ...",
"All" : "ಎಲ್ಲಾ",
"Please wait...." : "ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ ....",
@@ -44,14 +44,14 @@
"Uninstalling ...." : "ಅಳಿಸಿಹಾಕುವುದು ...",
"Error while uninstalling app" : "ಅಳಿಸುವಾಗ ಏನೊ ಲೋಪವಾಗಿದೆ",
"Uninstall" : "ಅಳಿಸಿ",
+ "Valid until {date}" : "{date} ವರೆಗೆ ಚಾಲ್ತಿಯಲ್ಲಿರುತ್ತದೆ",
+ "Delete" : "ಅಳಿಸಿ",
"Select a profile picture" : "ಸಂಕ್ಷಿಪ್ತ ವ್ಯಕ್ತಿಚಿತ್ರ ಒಂದನ್ನು ಆಯ್ಕೆ ಮಾಡಿ",
"Very weak password" : "ಅತೀ ದುರ್ಬಲ ಗುಪ್ತಪದ",
"Weak password" : "ದುರ್ಬಲ ಗುಪ್ತಪದ",
"So-so password" : "ಊಹಿಸಬಹುದಾದ ಗುಪ್ತಪದ",
"Good password" : "ಉತ್ತಮ ಗುಪ್ತಪದ",
"Strong password" : "ಪ್ರಬಲ ಗುಪ್ತಪದ",
- "Valid until {date}" : "{date} ವರೆಗೆ ಚಾಲ್ತಿಯಲ್ಲಿರುತ್ತದೆ",
- "Delete" : "ಅಳಿಸಿ",
"Groups" : "ಗುಂಪುಗಳು",
"Unable to delete {objName}" : "{objName} ಅಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ ",
"Error creating group" : "ಗುಂಪುನ್ನು ರಚಿಸುವಾಗ ದೋಷವಾಗಿದೆ",
@@ -90,7 +90,6 @@
"SMTP Password" : "SMTP ಗುಪ್ತ ಪದ",
"Test email settings" : "ಪರೀರ್ಕ್ಷಾತ ಇ-ಅಂಚೆಯ ಆಯ್ಕೇ",
"Send email" : "ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸಿ",
- "Log level" : "ಹಿನ್ನೆಲೆಯ ದಾಖಲೆಯ ಮಟ್ಟದ",
"More" : "ಇನ್ನಷ್ಟು",
"Less" : "ಕಡಿಮೆ",
"Version" : "ಆವೃತ್ತಿ",
@@ -99,14 +98,14 @@
"Uninstall App" : "ಅಳಿಸಿ",
"Cheers!" : "ಆನಂದಿಸಿ !",
"Forum" : "ವೇದಿಕೆ",
+ "Cancel" : "ರದ್ದು",
+ "Email" : "ಇ-ಅಂಚೆ",
+ "Your email address" : "ನಿಮ್ಮ ಇ-ಅಂಚೆ ವಿಳಾಸ",
"Password" : "ಗುಪ್ತ ಪದ",
"Unable to change your password" : "ನಿನ್ನ ಗುಪ್ತಪದವನ್ನು ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ",
"Current password" : "ಪ್ರಸ್ತುತ ಗುಪ್ತಪದ",
"New password" : "ಹೊಸ ಗುಪ್ತಪದ",
"Change password" : "ಗುಪ್ತ ಪದವನ್ನು ಬದಲಾಯಿಸಿ",
- "Email" : "ಇ-ಅಂಚೆ",
- "Your email address" : "ನಿಮ್ಮ ಇ-ಅಂಚೆ ವಿಳಾಸ",
- "Cancel" : "ರದ್ದು",
"Language" : "ಭಾಷೆ",
"Help translate" : "ಭಾಷಾಂತರಿಸಲು ಸಹಾಯ ಮಾಡಿ",
"Username" : "ಬಳಕೆಯ ಹೆಸರು",
diff --git a/settings/l10n/ko.js b/settings/l10n/ko.js
index bba866b2d35..8af97173061 100644
--- a/settings/l10n/ko.js
+++ b/settings/l10n/ko.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "로그",
"Tips & tricks" : "팁과 추가 정보",
"Updates" : "업데이트",
- "Authentication error" : "인증 오류",
- "Your full name has been changed." : "전체 이름이 변경되었습니다.",
- "Unable to change full name" : "전체 이름을 변경할 수 없음",
"Couldn't remove app." : "앱을 삭제할 수 없습니다.",
"Language changed" : "언어가 변경됨",
"Invalid request" : "잘못된 요청",
+ "Authentication error" : "인증 오류",
"Admins can't remove themself from the admin group" : "관리자 자신을 관리자 그룹에서 삭제할 수 없음",
"Unable to add user to group %s" : "그룹 %s에 사용자를 추가할 수 없음",
"Unable to remove user from group %s" : "그룹 %s에서 사용자를 삭제할 수 없음",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "잘못된 사용자",
"Unable to change mail address" : "이메일 주소를 변경할 수 없음",
"Email saved" : "이메일 저장됨",
+ "Your full name has been changed." : "전체 이름이 변경되었습니다.",
+ "Unable to change full name" : "전체 이름을 변경할 수 없음",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "신뢰할 수 있는 도메인 목록에 \"{domain}\"을(를) 추가하시겠습니까?",
"Add trusted domain" : "신뢰할 수 있는 도메인 추가",
"Migration in progress. Please wait until the migration is finished" : "이전 작업 중입니다. 작업이 완료될 때까지 기다려 주십시오",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "앱이 활성화되었지만, 앱을 업데이트해야 합니다. 5초 후 앱 업데이트 페이지로 넘어갑니다.",
"App update" : "앱 업데이트",
"No apps found for \"{query}\"" : "\"{query}\"에 해당하는 앱을 찾을 수 없음",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "오류가 발생했습니다. ASCII로 인코딩된 PEM 인증서를 업로드하십시오.",
+ "Valid until {date}" : "{date}까지 유효함",
+ "Delete" : "삭제",
"An error occurred: {message}" : "오류 발생: {message}",
"Select a profile picture" : "프로필 사진 선택",
"Very weak password" : "매우 약한 암호",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "그저 그런 암호",
"Good password" : "좋은 암호",
"Strong password" : "강력한 암호",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "오류가 발생했습니다. ASCII로 인코딩된 PEM 인증서를 업로드하십시오.",
- "Valid until {date}" : "{date}까지 유효함",
- "Delete" : "삭제",
"Groups" : "그룹",
"Unable to delete {objName}" : "{objName}을(를) 삭제할 수 없음",
"Error creating group" : "그룹을 생성하는 중 오류가 발생했습니다",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "올바른 암호를 입력해야 함",
"A valid email must be provided" : "올바른 이메일 주소를 입력해야 함",
"__language_name__" : "한국어",
- "Sync clients" : "동기화 클라이언트",
"Personal info" : "개인 정보",
- "SSL root certificates" : "SSL 루트 인증서",
+ "Sync clients" : "동기화 클라이언트",
"Everything (fatal issues, errors, warnings, info, debug)" : "모두 (치명적 문제, 오류, 경고, 정보, 디버그)",
"Info, warnings, errors and fatal issues" : "정보, 경고, 오류, 치명적 문제",
"Warnings, errors and fatal issues" : "경고, 오류, 치명적 문제",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "다음 중 하나 이상의 로캘을 지원하기 위하여 필요한 패키지를 시스템에 설치하는 것을 추천합니다: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "도메인의 루트 디렉터리 아래에 설치되어 있지 않고 시스템 cron을 사용한다면 URL 생성에 문제가 발생할 수도 있습니다. 이 문제를 해결하려면 설치본의 웹 루트 경로에 있는 config.php 파일의 \"overwrite.cli.url\" 옵션을 변경하십시오(제안: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "CLI로 cronjob을 실행할 수 없었습니다. 다음 기술적 오류가 발생했습니다:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "잠금 백엔드로 데이터베이스를 사용하고 있으므로 트랜잭션 기반 파일 잠금을 사용합니다. 더 좋은 성능을 내려면 memcache 기반 잠금 사용을 추천합니다. 더 많은 정보를 보려면 <a target=\"_blank\" href=\"%s\">문서 ↗</a>를 참고하십시오.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "<a target=\"_blank\" href=\"%s\">설치 가이드 ↗</a>를 다시 확인하시고 <a href=\"#log-section\">로그</a>의 오류 및 경고를 확인하십시오.",
"All checks passed." : "모든 검사를 통과했습니다.",
"Open documentation" : "문서 열기",
@@ -188,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "인증 정보 저장",
"Test email settings" : "이메일 설정 시험",
"Send email" : "이메일 보내기",
- "Log level" : "로그 단계",
"Download logfile" : "로그 파일 다운로드",
"More" : "더 중요함",
"Less" : "덜 중요함",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "로그 파일이 100MB보다 큽니다. 다운로드하는 데 시간이 걸릴 수 있습니다!",
+ "What to log" : "남길 로그",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "데이터베이스로 SQLite를 사용하고 있습니다. 대규모의 파일을 관리하려고 한다면 다른 데이터베이스 백엔드로 전환할 것을 권장합니다.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "특히 파일 동기화를 위해 데스크톱 클라이언트를 사용할 예정이면, SQLite를 사용하지 않는 것이 좋습니다.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "다른 데이터베이스로 이전하려면 다음 명령을 사용하십시오: 'occ db:convert-type' 다른 명령을 알아보려면 <a target=\"_blank\" href=\"%s\">문서 ↗</a>를 참고하십시오.",
@@ -206,8 +204,6 @@ OC.L10N.register(
"Developer documentation" : "개발자 문서",
"Experimental applications ahead" : "실험적인 앱 사용 예정",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "실험적인 앱은 보안 문제 검사를 통과하지 않았으며, 아직 새롭거나, 불안정하거나, 개발 중일 수도 있습니다. 이러한 앱을 설치하면 데이터 손실 및 보안 문제가 발생할 수도 있습니다.",
- "by" : "작성:",
- "licensed" : "라이선스:",
"Documentation:" : "문서:",
"User documentation" : "사용자 문서",
"Admin documentation" : "관리 문서",
@@ -217,6 +213,11 @@ OC.L10N.register(
"Enable only for specific groups" : "특정 그룹에만 허용",
"Uninstall App" : "앱 제거",
"Enable experimental apps" : "실험적인 앱 사용",
+ "Common Name" : "공통 이름",
+ "Valid until" : "만료 기간:",
+ "Issued By" : "발급자:",
+ "Valid until %s" : "%s까지 유효함",
+ "Import root certificate" : "루트 인증서 가져오기",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "안녕하세요.<br><br>%s 계정을 사용할 수 있음을 알려 드립니다.<br><br>사용자 이름: %s<br>접근 링크: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "감사합니다!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "안녕하세요.\n\n%s 계정을 사용할 수 있음을 알려 드립니다.\n\n사용자 이름: %s\n접근 링크: %s\n\n",
@@ -225,40 +226,30 @@ OC.L10N.register(
"Forum" : "포럼",
"Issue tracker" : "이슈 트래커",
"Commercial support" : "상용 지원",
- "Get the apps to sync your files" : "파일 동기화 앱 가져오기",
- "Desktop client" : "데스크톱 클라이언트",
- "Android app" : "Android 앱",
- "iOS app" : "iOS 앱",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "프로젝트를 지원하려면\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">개발에 참여하거나</a>\n\t\t\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">널리 알려 주십시오</a>!",
- "Show First Run Wizard again" : "첫 실행 마법사 다시 보이기",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "현재 공간 중 <strong>%s</strong>/<strong>%s</strong>을(를) 사용 중입니다",
- "Password" : "암호",
- "Unable to change your password" : "암호를 변경할 수 없음",
- "Current password" : "현재 암호",
- "New password" : "새 암호",
- "Change password" : "암호 변경",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "현재 <strong>%s</strong> / <strong>%s</strong>을(를) 사용중입니다.",
+ "Profile picture" : "프로필 사진",
+ "Upload new" : "새로 업로드",
+ "Remove image" : "그림 삭제",
+ "Cancel" : "취소",
"Full name" : "전체 이름",
"No display name set" : "표시 이름이 설정되지 않음",
"Email" : "이메일",
"Your email address" : "이메일 주소",
- "Fill in an email address to enable password recovery and receive notifications" : "이메일 주소를 입력하면 암호 찾기 및 알림 수신이 가능합니다",
"No email address set" : "이메일 주소가 설정되지 않음",
"You are member of the following groups:" : "다음 그룹의 구성원입니다:",
- "Profile picture" : "프로필 사진",
- "Upload new" : "새로 업로드",
- "Select new from Files" : "파일에서 선택",
- "Remove image" : "그림 삭제",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "PNG나 JPG 파일입니다. 정사각형을 사용하는 것이 가장 좋지만 잘라낼 수 있습니다. 파일 최대 크기는 20MB입니다.",
- "Your avatar is provided by your original account." : "원본 계정의 아바타를 사용합니다.",
- "Cancel" : "취소",
- "Choose as profile image" : "프로필 이미지로 사용",
+ "Password" : "암호",
+ "Unable to change your password" : "암호를 변경할 수 없음",
+ "Current password" : "현재 암호",
+ "New password" : "새 암호",
+ "Change password" : "암호 변경",
"Language" : "언어",
"Help translate" : "번역 돕기",
- "Common Name" : "공통 이름",
- "Valid until" : "만료 기간:",
- "Issued By" : "발급자:",
- "Valid until %s" : "%s까지 유효함",
- "Import root certificate" : "루트 인증서 가져오기",
+ "Get the apps to sync your files" : "파일 동기화 앱 가져오기",
+ "Desktop client" : "데스크톱 클라이언트",
+ "Android app" : "Android 앱",
+ "iOS app" : "iOS 앱",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "프로젝트를 지원하려면\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">개발에 참여하거나</a>\n\t\t\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">널리 알려 주십시오</a>!",
+ "Show First Run Wizard again" : "첫 실행 마법사 다시 보이기",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "{communityopen}ownCloud 커뮤니티{linkclose}에서 개발함. {githubopen}원본 코드{linkclose}는 {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} 라이선스로 배포됩니다.",
"Show storage location" : "저장소 위치 보이기",
"Show last log in" : "마지막 로그인 시간 보이기",
diff --git a/settings/l10n/ko.json b/settings/l10n/ko.json
index 7dc626b7702..a05536c814b 100644
--- a/settings/l10n/ko.json
+++ b/settings/l10n/ko.json
@@ -10,12 +10,10 @@
"Log" : "로그",
"Tips & tricks" : "팁과 추가 정보",
"Updates" : "업데이트",
- "Authentication error" : "인증 오류",
- "Your full name has been changed." : "전체 이름이 변경되었습니다.",
- "Unable to change full name" : "전체 이름을 변경할 수 없음",
"Couldn't remove app." : "앱을 삭제할 수 없습니다.",
"Language changed" : "언어가 변경됨",
"Invalid request" : "잘못된 요청",
+ "Authentication error" : "인증 오류",
"Admins can't remove themself from the admin group" : "관리자 자신을 관리자 그룹에서 삭제할 수 없음",
"Unable to add user to group %s" : "그룹 %s에 사용자를 추가할 수 없음",
"Unable to remove user from group %s" : "그룹 %s에서 사용자를 삭제할 수 없음",
@@ -51,6 +49,8 @@
"Invalid user" : "잘못된 사용자",
"Unable to change mail address" : "이메일 주소를 변경할 수 없음",
"Email saved" : "이메일 저장됨",
+ "Your full name has been changed." : "전체 이름이 변경되었습니다.",
+ "Unable to change full name" : "전체 이름을 변경할 수 없음",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "신뢰할 수 있는 도메인 목록에 \"{domain}\"을(를) 추가하시겠습니까?",
"Add trusted domain" : "신뢰할 수 있는 도메인 추가",
"Migration in progress. Please wait until the migration is finished" : "이전 작업 중입니다. 작업이 완료될 때까지 기다려 주십시오",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "앱이 활성화되었지만, 앱을 업데이트해야 합니다. 5초 후 앱 업데이트 페이지로 넘어갑니다.",
"App update" : "앱 업데이트",
"No apps found for \"{query}\"" : "\"{query}\"에 해당하는 앱을 찾을 수 없음",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "오류가 발생했습니다. ASCII로 인코딩된 PEM 인증서를 업로드하십시오.",
+ "Valid until {date}" : "{date}까지 유효함",
+ "Delete" : "삭제",
"An error occurred: {message}" : "오류 발생: {message}",
"Select a profile picture" : "프로필 사진 선택",
"Very weak password" : "매우 약한 암호",
@@ -86,9 +89,6 @@
"So-so password" : "그저 그런 암호",
"Good password" : "좋은 암호",
"Strong password" : "강력한 암호",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "오류가 발생했습니다. ASCII로 인코딩된 PEM 인증서를 업로드하십시오.",
- "Valid until {date}" : "{date}까지 유효함",
- "Delete" : "삭제",
"Groups" : "그룹",
"Unable to delete {objName}" : "{objName}을(를) 삭제할 수 없음",
"Error creating group" : "그룹을 생성하는 중 오류가 발생했습니다",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "올바른 암호를 입력해야 함",
"A valid email must be provided" : "올바른 이메일 주소를 입력해야 함",
"__language_name__" : "한국어",
- "Sync clients" : "동기화 클라이언트",
"Personal info" : "개인 정보",
- "SSL root certificates" : "SSL 루트 인증서",
+ "Sync clients" : "동기화 클라이언트",
"Everything (fatal issues, errors, warnings, info, debug)" : "모두 (치명적 문제, 오류, 경고, 정보, 디버그)",
"Info, warnings, errors and fatal issues" : "정보, 경고, 오류, 치명적 문제",
"Warnings, errors and fatal issues" : "경고, 오류, 치명적 문제",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "다음 중 하나 이상의 로캘을 지원하기 위하여 필요한 패키지를 시스템에 설치하는 것을 추천합니다: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "도메인의 루트 디렉터리 아래에 설치되어 있지 않고 시스템 cron을 사용한다면 URL 생성에 문제가 발생할 수도 있습니다. 이 문제를 해결하려면 설치본의 웹 루트 경로에 있는 config.php 파일의 \"overwrite.cli.url\" 옵션을 변경하십시오(제안: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "CLI로 cronjob을 실행할 수 없었습니다. 다음 기술적 오류가 발생했습니다:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "잠금 백엔드로 데이터베이스를 사용하고 있으므로 트랜잭션 기반 파일 잠금을 사용합니다. 더 좋은 성능을 내려면 memcache 기반 잠금 사용을 추천합니다. 더 많은 정보를 보려면 <a target=\"_blank\" href=\"%s\">문서 ↗</a>를 참고하십시오.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "<a target=\"_blank\" href=\"%s\">설치 가이드 ↗</a>를 다시 확인하시고 <a href=\"#log-section\">로그</a>의 오류 및 경고를 확인하십시오.",
"All checks passed." : "모든 검사를 통과했습니다.",
"Open documentation" : "문서 열기",
@@ -186,11 +184,11 @@
"Store credentials" : "인증 정보 저장",
"Test email settings" : "이메일 설정 시험",
"Send email" : "이메일 보내기",
- "Log level" : "로그 단계",
"Download logfile" : "로그 파일 다운로드",
"More" : "더 중요함",
"Less" : "덜 중요함",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "로그 파일이 100MB보다 큽니다. 다운로드하는 데 시간이 걸릴 수 있습니다!",
+ "What to log" : "남길 로그",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "데이터베이스로 SQLite를 사용하고 있습니다. 대규모의 파일을 관리하려고 한다면 다른 데이터베이스 백엔드로 전환할 것을 권장합니다.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "특히 파일 동기화를 위해 데스크톱 클라이언트를 사용할 예정이면, SQLite를 사용하지 않는 것이 좋습니다.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "다른 데이터베이스로 이전하려면 다음 명령을 사용하십시오: 'occ db:convert-type' 다른 명령을 알아보려면 <a target=\"_blank\" href=\"%s\">문서 ↗</a>를 참고하십시오.",
@@ -204,8 +202,6 @@
"Developer documentation" : "개발자 문서",
"Experimental applications ahead" : "실험적인 앱 사용 예정",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "실험적인 앱은 보안 문제 검사를 통과하지 않았으며, 아직 새롭거나, 불안정하거나, 개발 중일 수도 있습니다. 이러한 앱을 설치하면 데이터 손실 및 보안 문제가 발생할 수도 있습니다.",
- "by" : "작성:",
- "licensed" : "라이선스:",
"Documentation:" : "문서:",
"User documentation" : "사용자 문서",
"Admin documentation" : "관리 문서",
@@ -215,6 +211,11 @@
"Enable only for specific groups" : "특정 그룹에만 허용",
"Uninstall App" : "앱 제거",
"Enable experimental apps" : "실험적인 앱 사용",
+ "Common Name" : "공통 이름",
+ "Valid until" : "만료 기간:",
+ "Issued By" : "발급자:",
+ "Valid until %s" : "%s까지 유효함",
+ "Import root certificate" : "루트 인증서 가져오기",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "안녕하세요.<br><br>%s 계정을 사용할 수 있음을 알려 드립니다.<br><br>사용자 이름: %s<br>접근 링크: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "감사합니다!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "안녕하세요.\n\n%s 계정을 사용할 수 있음을 알려 드립니다.\n\n사용자 이름: %s\n접근 링크: %s\n\n",
@@ -223,40 +224,30 @@
"Forum" : "포럼",
"Issue tracker" : "이슈 트래커",
"Commercial support" : "상용 지원",
- "Get the apps to sync your files" : "파일 동기화 앱 가져오기",
- "Desktop client" : "데스크톱 클라이언트",
- "Android app" : "Android 앱",
- "iOS app" : "iOS 앱",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "프로젝트를 지원하려면\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">개발에 참여하거나</a>\n\t\t\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">널리 알려 주십시오</a>!",
- "Show First Run Wizard again" : "첫 실행 마법사 다시 보이기",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "현재 공간 중 <strong>%s</strong>/<strong>%s</strong>을(를) 사용 중입니다",
- "Password" : "암호",
- "Unable to change your password" : "암호를 변경할 수 없음",
- "Current password" : "현재 암호",
- "New password" : "새 암호",
- "Change password" : "암호 변경",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "현재 <strong>%s</strong> / <strong>%s</strong>을(를) 사용중입니다.",
+ "Profile picture" : "프로필 사진",
+ "Upload new" : "새로 업로드",
+ "Remove image" : "그림 삭제",
+ "Cancel" : "취소",
"Full name" : "전체 이름",
"No display name set" : "표시 이름이 설정되지 않음",
"Email" : "이메일",
"Your email address" : "이메일 주소",
- "Fill in an email address to enable password recovery and receive notifications" : "이메일 주소를 입력하면 암호 찾기 및 알림 수신이 가능합니다",
"No email address set" : "이메일 주소가 설정되지 않음",
"You are member of the following groups:" : "다음 그룹의 구성원입니다:",
- "Profile picture" : "프로필 사진",
- "Upload new" : "새로 업로드",
- "Select new from Files" : "파일에서 선택",
- "Remove image" : "그림 삭제",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "PNG나 JPG 파일입니다. 정사각형을 사용하는 것이 가장 좋지만 잘라낼 수 있습니다. 파일 최대 크기는 20MB입니다.",
- "Your avatar is provided by your original account." : "원본 계정의 아바타를 사용합니다.",
- "Cancel" : "취소",
- "Choose as profile image" : "프로필 이미지로 사용",
+ "Password" : "암호",
+ "Unable to change your password" : "암호를 변경할 수 없음",
+ "Current password" : "현재 암호",
+ "New password" : "새 암호",
+ "Change password" : "암호 변경",
"Language" : "언어",
"Help translate" : "번역 돕기",
- "Common Name" : "공통 이름",
- "Valid until" : "만료 기간:",
- "Issued By" : "발급자:",
- "Valid until %s" : "%s까지 유효함",
- "Import root certificate" : "루트 인증서 가져오기",
+ "Get the apps to sync your files" : "파일 동기화 앱 가져오기",
+ "Desktop client" : "데스크톱 클라이언트",
+ "Android app" : "Android 앱",
+ "iOS app" : "iOS 앱",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "프로젝트를 지원하려면\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">개발에 참여하거나</a>\n\t\t\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">널리 알려 주십시오</a>!",
+ "Show First Run Wizard again" : "첫 실행 마법사 다시 보이기",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "{communityopen}ownCloud 커뮤니티{linkclose}에서 개발함. {githubopen}원본 코드{linkclose}는 {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} 라이선스로 배포됩니다.",
"Show storage location" : "저장소 위치 보이기",
"Show last log in" : "마지막 로그인 시간 보이기",
diff --git a/settings/l10n/ku_IQ.js b/settings/l10n/ku_IQ.js
index 1359dc748a3..1bdf686bf4d 100644
--- a/settings/l10n/ku_IQ.js
+++ b/settings/l10n/ku_IQ.js
@@ -8,11 +8,10 @@ OC.L10N.register(
"Login" : "چوونەژوورەوە",
"Encryption" : "نهێنیکردن",
"Server address" : "ناونیشانی ڕاژه",
- "by" : "له‌لایه‌ن",
+ "Cancel" : "لابردن",
+ "Email" : "ئیمه‌یل",
"Password" : "وشەی تێپەربو",
"New password" : "وشەی نهێنی نوێ",
- "Email" : "ئیمه‌یل",
- "Cancel" : "لابردن",
"Username" : "ناوی به‌کارهێنه‌ر"
},
"nplurals=2; plural=(n != 1);");
diff --git a/settings/l10n/ku_IQ.json b/settings/l10n/ku_IQ.json
index f7dfd226aae..cfc9fc59e7c 100644
--- a/settings/l10n/ku_IQ.json
+++ b/settings/l10n/ku_IQ.json
@@ -6,11 +6,10 @@
"Login" : "چوونەژوورەوە",
"Encryption" : "نهێنیکردن",
"Server address" : "ناونیشانی ڕاژه",
- "by" : "له‌لایه‌ن",
+ "Cancel" : "لابردن",
+ "Email" : "ئیمه‌یل",
"Password" : "وشەی تێپەربو",
"New password" : "وشەی نهێنی نوێ",
- "Email" : "ئیمه‌یل",
- "Cancel" : "لابردن",
"Username" : "ناوی به‌کارهێنه‌ر"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/settings/l10n/lb.js b/settings/l10n/lb.js
index 79643dc416a..88117d9b016 100644
--- a/settings/l10n/lb.js
+++ b/settings/l10n/lb.js
@@ -5,9 +5,9 @@ OC.L10N.register(
"Redis" : "Redis",
"Cron" : "Cron",
"Log" : "Log",
- "Authentication error" : "Authentifikatioun's Fehler",
"Language changed" : "Sprooch huet geännert",
"Invalid request" : "Ongülteg Requête",
+ "Authentication error" : "Authentifikatioun's Fehler",
"Admins can't remove themself from the admin group" : "Admins kennen sech selwer net aus enger Admin Group läschen.",
"Unable to add user to group %s" : "Onmeiglech User an Grupp ze sätzen %s",
"Wrong password" : "Falscht Passwuert",
@@ -32,21 +32,20 @@ OC.L10N.register(
"Port" : "Port",
"More" : "Méi",
"Less" : "Manner",
- "by" : "vun",
"Cheers!" : "Prost!",
- "Desktop client" : "Desktop-Programm",
- "Android app" : "Android-App",
- "iOS app" : "iOS-App",
+ "Cancel" : "Ofbriechen",
+ "Email" : "Email",
+ "Your email address" : "Deng Email Adress",
"Password" : "Passwuert",
"Unable to change your password" : "Konnt däin Passwuert net änneren",
"Current password" : "Momentan 't Passwuert",
"New password" : "Neit Passwuert",
"Change password" : "Passwuert änneren",
- "Email" : "Email",
- "Your email address" : "Deng Email Adress",
- "Cancel" : "Ofbriechen",
"Language" : "Sprooch",
"Help translate" : "Hëllef iwwersetzen",
+ "Desktop client" : "Desktop-Programm",
+ "Android app" : "Android-App",
+ "iOS app" : "iOS-App",
"Username" : "Benotzernumm",
"Create" : "Erstellen",
"Group" : "Grupp",
diff --git a/settings/l10n/lb.json b/settings/l10n/lb.json
index 26af461d141..a686607e272 100644
--- a/settings/l10n/lb.json
+++ b/settings/l10n/lb.json
@@ -3,9 +3,9 @@
"Redis" : "Redis",
"Cron" : "Cron",
"Log" : "Log",
- "Authentication error" : "Authentifikatioun's Fehler",
"Language changed" : "Sprooch huet geännert",
"Invalid request" : "Ongülteg Requête",
+ "Authentication error" : "Authentifikatioun's Fehler",
"Admins can't remove themself from the admin group" : "Admins kennen sech selwer net aus enger Admin Group läschen.",
"Unable to add user to group %s" : "Onmeiglech User an Grupp ze sätzen %s",
"Wrong password" : "Falscht Passwuert",
@@ -30,21 +30,20 @@
"Port" : "Port",
"More" : "Méi",
"Less" : "Manner",
- "by" : "vun",
"Cheers!" : "Prost!",
- "Desktop client" : "Desktop-Programm",
- "Android app" : "Android-App",
- "iOS app" : "iOS-App",
+ "Cancel" : "Ofbriechen",
+ "Email" : "Email",
+ "Your email address" : "Deng Email Adress",
"Password" : "Passwuert",
"Unable to change your password" : "Konnt däin Passwuert net änneren",
"Current password" : "Momentan 't Passwuert",
"New password" : "Neit Passwuert",
"Change password" : "Passwuert änneren",
- "Email" : "Email",
- "Your email address" : "Deng Email Adress",
- "Cancel" : "Ofbriechen",
"Language" : "Sprooch",
"Help translate" : "Hëllef iwwersetzen",
+ "Desktop client" : "Desktop-Programm",
+ "Android app" : "Android-App",
+ "iOS app" : "iOS-App",
"Username" : "Benotzernumm",
"Create" : "Erstellen",
"Group" : "Grupp",
diff --git a/settings/l10n/lo.js b/settings/l10n/lo.js
index 862f93e195f..43069818133 100644
--- a/settings/l10n/lo.js
+++ b/settings/l10n/lo.js
@@ -3,7 +3,7 @@ OC.L10N.register(
{
"Sharing" : "ການແບ່ງປັນ",
"Log" : "ບັນທຶກ",
- "Unable to change full name" : "ບໍ່ສາມາດປ່ຽນຊື່ເຕັມໄດ້",
- "Couldn't remove app." : "ບໍ່ສາມາດລຶບແອັບຯອອກໄດ້"
+ "Couldn't remove app." : "ບໍ່ສາມາດລຶບແອັບຯອອກໄດ້",
+ "Unable to change full name" : "ບໍ່ສາມາດປ່ຽນຊື່ເຕັມໄດ້"
},
"nplurals=1; plural=0;");
diff --git a/settings/l10n/lo.json b/settings/l10n/lo.json
index 75515944189..942e427821e 100644
--- a/settings/l10n/lo.json
+++ b/settings/l10n/lo.json
@@ -1,7 +1,7 @@
{ "translations": {
"Sharing" : "ການແບ່ງປັນ",
"Log" : "ບັນທຶກ",
- "Unable to change full name" : "ບໍ່ສາມາດປ່ຽນຊື່ເຕັມໄດ້",
- "Couldn't remove app." : "ບໍ່ສາມາດລຶບແອັບຯອອກໄດ້"
+ "Couldn't remove app." : "ບໍ່ສາມາດລຶບແອັບຯອອກໄດ້",
+ "Unable to change full name" : "ບໍ່ສາມາດປ່ຽນຊື່ເຕັມໄດ້"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/settings/l10n/lt_LT.js b/settings/l10n/lt_LT.js
index 2b739db71c9..7e8e43c75f0 100644
--- a/settings/l10n/lt_LT.js
+++ b/settings/l10n/lt_LT.js
@@ -1,14 +1,21 @@
OC.L10N.register(
"settings",
{
+ "APCu" : "APCu",
+ "Redis" : "Redis",
+ "Security & setup warnings" : "Saugos ir diegimo perspėjimai",
"Sharing" : "Dalijimasis",
+ "Server-side encryption" : "Šifravimas serveryje",
"External Storage" : "Išorinės saugyklos",
"Cron" : "Cron",
+ "Email server" : "Pašto serveris",
"Log" : "Žurnalas",
+ "Tips & tricks" : "Patarimai ir gudrybės",
"Updates" : "Atnaujinimai",
- "Authentication error" : "Autentikacijos klaida",
+ "Couldn't remove app." : "Nepavyko pašalinti programėlės.",
"Language changed" : "Kalba pakeista",
"Invalid request" : "Klaidinga užklausa",
+ "Authentication error" : "Autentikacijos klaida",
"Admins can't remove themself from the admin group" : "Administratoriai negali pašalinti savęs iš administratorių grupės",
"Unable to add user to group %s" : "Nepavyko pridėti vartotojo prie grupės %s",
"Unable to remove user from group %s" : "Nepavyko ištrinti vartotojo iš grupės %s",
@@ -17,12 +24,19 @@ OC.L10N.register(
"No user supplied" : "Nepateiktas naudotojas",
"Please provide an admin recovery password, otherwise all user data will be lost" : "Prašome įvesti administratoriaus atkūrimo slaptažodį, kitaip visi naudotojo suomenys bus prarasti",
"Wrong admin recovery password. Please check the password and try again." : "Netinkamas administratoriau atkūrimo slaptažodis. Prašome pasitikrinti ir bandyti vėl.",
+ "Backend doesn't support password change, but the user's encryption key was successfully updated." : "Vartotojo slaptažodžio pakeitimas negalimas, bet šifravimo raktas atnaujintas sėkmingai.",
"Unable to change password" : "Nepavyksta pakeisti slaptažodžio",
"Enabled" : "Įjungta",
+ "Not enabled" : "Neįjungta",
"Federated Cloud Sharing" : "Viešas dalijimasis padebesiu",
"Saved" : "Išsaugoti",
"Email sent" : "Laiškas išsiųstas",
+ "Invalid mail address" : "Neteisingas pašto adresas",
+ "Your %s account was created" : "Tavo paskyra %s sukurta",
+ "Unable to delete user." : "Nepavyko ištrinti vartotojo.",
"Email saved" : "El. paštas išsaugotas",
+ "Your full name has been changed." : "Pilnas vardas pakeistas.",
+ "Unable to change full name" : "Nepavyko pakeisti pilno vardo",
"All" : "Viskas",
"Please wait...." : "Prašome palaukti...",
"Error while disabling app" : "Klaida išjungiant programą",
@@ -32,13 +46,13 @@ OC.L10N.register(
"Updating...." : "Atnaujinama...",
"Error while updating app" : "Įvyko klaida atnaujinant programą",
"Updated" : "Atnaujinta",
+ "Delete" : "Ištrinti",
"Select a profile picture" : "Pažymėkite profilio paveikslėlį",
"Very weak password" : "Labai silpnas slaptažodis",
"Weak password" : "Silpnas slaptažodis",
"So-so password" : "Neblogas slaptažodis",
"Good password" : "Geras slaptažodis",
"Strong password" : "Stiprus slaptažodis",
- "Delete" : "Ištrinti",
"Groups" : "Grupės",
"undo" : "anuliuoti",
"never" : "niekada",
@@ -47,7 +61,6 @@ OC.L10N.register(
"Error creating user" : "Klaida kuriant vartotoją",
"A valid password must be provided" : "Slaptažodis turi būti tinkamas",
"__language_name__" : "Lietuvių",
- "SSL root certificates" : "SSL sertifikatas",
"Fatal issues only" : "Tik kritinės problemos",
"None" : "Nieko",
"Login" : "Prisijungti",
@@ -63,34 +76,29 @@ OC.L10N.register(
"Authentication required" : "Reikalinga autentikacija",
"Server address" : "Serverio adresas",
"Port" : "Prievadas",
- "Log level" : "Žurnalo išsamumas",
"More" : "Daugiau",
"Less" : "Mažiau",
"Version" : "Versija",
- "by" : " ",
"Cheers!" : "Sveikinimai!",
"Forum" : "Forumas",
- "Get the apps to sync your files" : "Atsisiųskite programėlių, kad sinchronizuotumėte savo failus",
- "Desktop client" : "Darbastalio klientas",
- "Android app" : "Android programa",
- "iOS app" : "iOS programa",
- "Show First Run Wizard again" : "Rodyti pirmo karto vedlį dar kartą",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Jūs naudojate <strong>%s</strong> iš galimų <strong>%s</strong>",
+ "Profile picture" : "Profilio paveikslėlis",
+ "Upload new" : "Įkelti naują",
+ "Remove image" : "Pašalinti paveikslėlį",
+ "Cancel" : "Atšaukti",
+ "Email" : "El. Paštas",
+ "Your email address" : "Jūsų el. pašto adresas",
"Password" : "Slaptažodis",
"Unable to change your password" : "Neįmanoma pakeisti slaptažodžio",
"Current password" : "Dabartinis slaptažodis",
"New password" : "Naujas slaptažodis",
"Change password" : "Pakeisti slaptažodį",
- "Email" : "El. Paštas",
- "Your email address" : "Jūsų el. pašto adresas",
- "Profile picture" : "Profilio paveikslėlis",
- "Upload new" : "Įkelti naują",
- "Select new from Files" : "Pasirinkti naują iš failų",
- "Remove image" : "Pašalinti paveikslėlį",
- "Cancel" : "Atšaukti",
- "Choose as profile image" : "Pasirinkite profilio paveiksliuką",
"Language" : "Kalba",
"Help translate" : "Padėkite išversti",
+ "Get the apps to sync your files" : "Atsisiųskite programėlių, kad sinchronizuotumėte savo failus",
+ "Desktop client" : "Darbastalio klientas",
+ "Android app" : "Android programa",
+ "iOS app" : "iOS programa",
+ "Show First Run Wizard again" : "Rodyti pirmo karto vedlį dar kartą",
"Username" : "Prisijungimo vardas",
"Create" : "Sukurti",
"Admin Recovery Password" : "Administracinis atkūrimo slaptažodis",
diff --git a/settings/l10n/lt_LT.json b/settings/l10n/lt_LT.json
index a8cd70f7dd6..f15481a21e0 100644
--- a/settings/l10n/lt_LT.json
+++ b/settings/l10n/lt_LT.json
@@ -1,12 +1,19 @@
{ "translations": {
+ "APCu" : "APCu",
+ "Redis" : "Redis",
+ "Security & setup warnings" : "Saugos ir diegimo perspėjimai",
"Sharing" : "Dalijimasis",
+ "Server-side encryption" : "Šifravimas serveryje",
"External Storage" : "Išorinės saugyklos",
"Cron" : "Cron",
+ "Email server" : "Pašto serveris",
"Log" : "Žurnalas",
+ "Tips & tricks" : "Patarimai ir gudrybės",
"Updates" : "Atnaujinimai",
- "Authentication error" : "Autentikacijos klaida",
+ "Couldn't remove app." : "Nepavyko pašalinti programėlės.",
"Language changed" : "Kalba pakeista",
"Invalid request" : "Klaidinga užklausa",
+ "Authentication error" : "Autentikacijos klaida",
"Admins can't remove themself from the admin group" : "Administratoriai negali pašalinti savęs iš administratorių grupės",
"Unable to add user to group %s" : "Nepavyko pridėti vartotojo prie grupės %s",
"Unable to remove user from group %s" : "Nepavyko ištrinti vartotojo iš grupės %s",
@@ -15,12 +22,19 @@
"No user supplied" : "Nepateiktas naudotojas",
"Please provide an admin recovery password, otherwise all user data will be lost" : "Prašome įvesti administratoriaus atkūrimo slaptažodį, kitaip visi naudotojo suomenys bus prarasti",
"Wrong admin recovery password. Please check the password and try again." : "Netinkamas administratoriau atkūrimo slaptažodis. Prašome pasitikrinti ir bandyti vėl.",
+ "Backend doesn't support password change, but the user's encryption key was successfully updated." : "Vartotojo slaptažodžio pakeitimas negalimas, bet šifravimo raktas atnaujintas sėkmingai.",
"Unable to change password" : "Nepavyksta pakeisti slaptažodžio",
"Enabled" : "Įjungta",
+ "Not enabled" : "Neįjungta",
"Federated Cloud Sharing" : "Viešas dalijimasis padebesiu",
"Saved" : "Išsaugoti",
"Email sent" : "Laiškas išsiųstas",
+ "Invalid mail address" : "Neteisingas pašto adresas",
+ "Your %s account was created" : "Tavo paskyra %s sukurta",
+ "Unable to delete user." : "Nepavyko ištrinti vartotojo.",
"Email saved" : "El. paštas išsaugotas",
+ "Your full name has been changed." : "Pilnas vardas pakeistas.",
+ "Unable to change full name" : "Nepavyko pakeisti pilno vardo",
"All" : "Viskas",
"Please wait...." : "Prašome palaukti...",
"Error while disabling app" : "Klaida išjungiant programą",
@@ -30,13 +44,13 @@
"Updating...." : "Atnaujinama...",
"Error while updating app" : "Įvyko klaida atnaujinant programą",
"Updated" : "Atnaujinta",
+ "Delete" : "Ištrinti",
"Select a profile picture" : "Pažymėkite profilio paveikslėlį",
"Very weak password" : "Labai silpnas slaptažodis",
"Weak password" : "Silpnas slaptažodis",
"So-so password" : "Neblogas slaptažodis",
"Good password" : "Geras slaptažodis",
"Strong password" : "Stiprus slaptažodis",
- "Delete" : "Ištrinti",
"Groups" : "Grupės",
"undo" : "anuliuoti",
"never" : "niekada",
@@ -45,7 +59,6 @@
"Error creating user" : "Klaida kuriant vartotoją",
"A valid password must be provided" : "Slaptažodis turi būti tinkamas",
"__language_name__" : "Lietuvių",
- "SSL root certificates" : "SSL sertifikatas",
"Fatal issues only" : "Tik kritinės problemos",
"None" : "Nieko",
"Login" : "Prisijungti",
@@ -61,34 +74,29 @@
"Authentication required" : "Reikalinga autentikacija",
"Server address" : "Serverio adresas",
"Port" : "Prievadas",
- "Log level" : "Žurnalo išsamumas",
"More" : "Daugiau",
"Less" : "Mažiau",
"Version" : "Versija",
- "by" : " ",
"Cheers!" : "Sveikinimai!",
"Forum" : "Forumas",
- "Get the apps to sync your files" : "Atsisiųskite programėlių, kad sinchronizuotumėte savo failus",
- "Desktop client" : "Darbastalio klientas",
- "Android app" : "Android programa",
- "iOS app" : "iOS programa",
- "Show First Run Wizard again" : "Rodyti pirmo karto vedlį dar kartą",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Jūs naudojate <strong>%s</strong> iš galimų <strong>%s</strong>",
+ "Profile picture" : "Profilio paveikslėlis",
+ "Upload new" : "Įkelti naują",
+ "Remove image" : "Pašalinti paveikslėlį",
+ "Cancel" : "Atšaukti",
+ "Email" : "El. Paštas",
+ "Your email address" : "Jūsų el. pašto adresas",
"Password" : "Slaptažodis",
"Unable to change your password" : "Neįmanoma pakeisti slaptažodžio",
"Current password" : "Dabartinis slaptažodis",
"New password" : "Naujas slaptažodis",
"Change password" : "Pakeisti slaptažodį",
- "Email" : "El. Paštas",
- "Your email address" : "Jūsų el. pašto adresas",
- "Profile picture" : "Profilio paveikslėlis",
- "Upload new" : "Įkelti naują",
- "Select new from Files" : "Pasirinkti naują iš failų",
- "Remove image" : "Pašalinti paveikslėlį",
- "Cancel" : "Atšaukti",
- "Choose as profile image" : "Pasirinkite profilio paveiksliuką",
"Language" : "Kalba",
"Help translate" : "Padėkite išversti",
+ "Get the apps to sync your files" : "Atsisiųskite programėlių, kad sinchronizuotumėte savo failus",
+ "Desktop client" : "Darbastalio klientas",
+ "Android app" : "Android programa",
+ "iOS app" : "iOS programa",
+ "Show First Run Wizard again" : "Rodyti pirmo karto vedlį dar kartą",
"Username" : "Prisijungimo vardas",
"Create" : "Sukurti",
"Admin Recovery Password" : "Administracinis atkūrimo slaptažodis",
diff --git a/settings/l10n/lv.js b/settings/l10n/lv.js
index b84b57dd315..516ad3205c7 100644
--- a/settings/l10n/lv.js
+++ b/settings/l10n/lv.js
@@ -6,12 +6,10 @@ OC.L10N.register(
"Cron" : "Cron",
"Log" : "Žurnāls",
"Updates" : "Atjauninājumi",
- "Authentication error" : "Autentifikācijas kļūda",
- "Your full name has been changed." : "Jūsu pilnais vārds tika mainīts.",
- "Unable to change full name" : "Nav iespējams nomainīt jūsu pilno vārdu",
"Couldn't remove app." : "Nebija iespējams atslēgt lietoni.",
"Language changed" : "Valoda tika nomainīta",
"Invalid request" : "Nederīgs vaicājums",
+ "Authentication error" : "Autentifikācijas kļūda",
"Admins can't remove themself from the admin group" : "Administratori nevar izņemt paši sevi no administratoru grupas",
"Unable to add user to group %s" : "Nevar pievienot lietotāju grupai %s",
"Unable to remove user from group %s" : "Nevar izņemt lietotāju no grupas %s",
@@ -40,6 +38,8 @@ OC.L10N.register(
"Invalid user" : "Nepareizs lietotājs",
"Unable to change mail address" : "Nevar nomainīt e-pasta adresi",
"Email saved" : "E-pasts tika saglabāts",
+ "Your full name has been changed." : "Jūsu pilnais vārds tika mainīts.",
+ "Unable to change full name" : "Nav iespējams nomainīt jūsu pilno vārdu",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Vai esat pārliecināts, ka vēlaties pievienot \"{domain}\" kā uzticamu domēnu?",
"Add trusted domain" : "Pievienot uzticamu domēnu",
"Sending..." : "Sūta...",
@@ -56,6 +56,8 @@ OC.L10N.register(
"Uninstalling ...." : "Atinstalē ....",
"Error while uninstalling app" : "Kļūda, atinstalējot lietotni",
"Uninstall" : "Atinstalēt",
+ "Valid until {date}" : "Valīds līdz {date}",
+ "Delete" : "Dzēst",
"An error occurred: {message}" : "Notika kļūda: {message}",
"Select a profile picture" : "Izvēlieties profila attēlu",
"Very weak password" : "Ļoti vāja parole",
@@ -63,8 +65,6 @@ OC.L10N.register(
"So-so password" : "Normāla parole",
"Good password" : "Laba parole",
"Strong password" : "Lieliska parole",
- "Valid until {date}" : "Valīds līdz {date}",
- "Delete" : "Dzēst",
"Groups" : "Grupas",
"Unable to delete {objName}" : "Nevar izdzēst {objName}",
"Error creating group" : "Kļūda, veidojot grupu",
@@ -81,7 +81,6 @@ OC.L10N.register(
"A valid email must be provided" : "Jānorāda derīga e-pasta adrese",
"__language_name__" : "__valodas_nosaukums__",
"Sync clients" : "Sinhronizācijas lietotnes",
- "SSL root certificates" : "SSL saknes sertifikāti",
"Everything (fatal issues, errors, warnings, info, debug)" : "Viss (letālas problēmas, kļūdas, brīdinājumi, informatīvas ziņas, atkļūdošanas paziņojumi)",
"Info, warnings, errors and fatal issues" : "Informatīvas ziņas, brīdinājumi, kļūdas un letālas problēmas",
"Warnings, errors and fatal issues" : "Brīdinājumi, kļūdas un letālas problēmas",
@@ -112,11 +111,9 @@ OC.L10N.register(
"SMTP Password" : "SMTP parole",
"Test email settings" : "Izmēģināt e-pasta iestatījumus",
"Send email" : "Sūtīt e-pastu",
- "Log level" : "Žurnāla līmenis",
"More" : "Vairāk",
"Less" : "Mazāk",
"Version" : "Versija",
- "by" : "līdz",
"Documentation:" : "Dokumentācija:",
"User documentation" : "Lietotāja dokumentācija",
"Admin documentation" : "Administratora dokumentācija",
@@ -124,26 +121,24 @@ OC.L10N.register(
"Hide description …" : "Slēpt aprakstu …",
"Online documentation" : "Tiešsaistes dokumentācija",
"Forum" : "Forums",
- "Get the apps to sync your files" : "Saņem lietotnes, lai sinhronizētu savas datnes",
- "Desktop client" : "Darbvirsmas klients",
- "Android app" : "Android lietotne",
- "iOS app" : "iOS lietotne",
- "Show First Run Wizard again" : "Vēlreiz rādīt pirmās palaišanas vedni",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Jūs lietojat <strong>%s</strong> no pieejamajiem <strong>%s</strong>",
+ "Profile picture" : "Profila attēls",
+ "Upload new" : "Ielādēt jaunu",
+ "Remove image" : "Novākt attēlu",
+ "Cancel" : "Atcelt",
+ "Email" : "E-pasts",
+ "Your email address" : "Jūsu e-pasta adrese",
"Password" : "Parole",
"Unable to change your password" : "Nevar nomainīt jūsu paroli",
"Current password" : "Pašreizējā parole",
"New password" : "Jauna parole",
"Change password" : "Mainīt paroli",
- "Email" : "E-pasts",
- "Your email address" : "Jūsu e-pasta adrese",
- "Profile picture" : "Profila attēls",
- "Upload new" : "Ielādēt jaunu",
- "Select new from Files" : "Izvēlēties jaunu no Failiem",
- "Remove image" : "Novākt attēlu",
- "Cancel" : "Atcelt",
"Language" : "Valoda",
"Help translate" : "Palīdzi tulkot",
+ "Get the apps to sync your files" : "Saņem lietotnes, lai sinhronizētu savas datnes",
+ "Desktop client" : "Darbvirsmas klients",
+ "Android app" : "Android lietotne",
+ "iOS app" : "iOS lietotne",
+ "Show First Run Wizard again" : "Vēlreiz rādīt pirmās palaišanas vedni",
"Send email to new user" : "Sūtīt e-pastu jaunajam lietotājam",
"Show email address" : "Rādīt e-pasta adreses",
"Username" : "Lietotājvārds",
diff --git a/settings/l10n/lv.json b/settings/l10n/lv.json
index 23172d90b8e..7eeceea5efa 100644
--- a/settings/l10n/lv.json
+++ b/settings/l10n/lv.json
@@ -4,12 +4,10 @@
"Cron" : "Cron",
"Log" : "Žurnāls",
"Updates" : "Atjauninājumi",
- "Authentication error" : "Autentifikācijas kļūda",
- "Your full name has been changed." : "Jūsu pilnais vārds tika mainīts.",
- "Unable to change full name" : "Nav iespējams nomainīt jūsu pilno vārdu",
"Couldn't remove app." : "Nebija iespējams atslēgt lietoni.",
"Language changed" : "Valoda tika nomainīta",
"Invalid request" : "Nederīgs vaicājums",
+ "Authentication error" : "Autentifikācijas kļūda",
"Admins can't remove themself from the admin group" : "Administratori nevar izņemt paši sevi no administratoru grupas",
"Unable to add user to group %s" : "Nevar pievienot lietotāju grupai %s",
"Unable to remove user from group %s" : "Nevar izņemt lietotāju no grupas %s",
@@ -38,6 +36,8 @@
"Invalid user" : "Nepareizs lietotājs",
"Unable to change mail address" : "Nevar nomainīt e-pasta adresi",
"Email saved" : "E-pasts tika saglabāts",
+ "Your full name has been changed." : "Jūsu pilnais vārds tika mainīts.",
+ "Unable to change full name" : "Nav iespējams nomainīt jūsu pilno vārdu",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Vai esat pārliecināts, ka vēlaties pievienot \"{domain}\" kā uzticamu domēnu?",
"Add trusted domain" : "Pievienot uzticamu domēnu",
"Sending..." : "Sūta...",
@@ -54,6 +54,8 @@
"Uninstalling ...." : "Atinstalē ....",
"Error while uninstalling app" : "Kļūda, atinstalējot lietotni",
"Uninstall" : "Atinstalēt",
+ "Valid until {date}" : "Valīds līdz {date}",
+ "Delete" : "Dzēst",
"An error occurred: {message}" : "Notika kļūda: {message}",
"Select a profile picture" : "Izvēlieties profila attēlu",
"Very weak password" : "Ļoti vāja parole",
@@ -61,8 +63,6 @@
"So-so password" : "Normāla parole",
"Good password" : "Laba parole",
"Strong password" : "Lieliska parole",
- "Valid until {date}" : "Valīds līdz {date}",
- "Delete" : "Dzēst",
"Groups" : "Grupas",
"Unable to delete {objName}" : "Nevar izdzēst {objName}",
"Error creating group" : "Kļūda, veidojot grupu",
@@ -79,7 +79,6 @@
"A valid email must be provided" : "Jānorāda derīga e-pasta adrese",
"__language_name__" : "__valodas_nosaukums__",
"Sync clients" : "Sinhronizācijas lietotnes",
- "SSL root certificates" : "SSL saknes sertifikāti",
"Everything (fatal issues, errors, warnings, info, debug)" : "Viss (letālas problēmas, kļūdas, brīdinājumi, informatīvas ziņas, atkļūdošanas paziņojumi)",
"Info, warnings, errors and fatal issues" : "Informatīvas ziņas, brīdinājumi, kļūdas un letālas problēmas",
"Warnings, errors and fatal issues" : "Brīdinājumi, kļūdas un letālas problēmas",
@@ -110,11 +109,9 @@
"SMTP Password" : "SMTP parole",
"Test email settings" : "Izmēģināt e-pasta iestatījumus",
"Send email" : "Sūtīt e-pastu",
- "Log level" : "Žurnāla līmenis",
"More" : "Vairāk",
"Less" : "Mazāk",
"Version" : "Versija",
- "by" : "līdz",
"Documentation:" : "Dokumentācija:",
"User documentation" : "Lietotāja dokumentācija",
"Admin documentation" : "Administratora dokumentācija",
@@ -122,26 +119,24 @@
"Hide description …" : "Slēpt aprakstu …",
"Online documentation" : "Tiešsaistes dokumentācija",
"Forum" : "Forums",
- "Get the apps to sync your files" : "Saņem lietotnes, lai sinhronizētu savas datnes",
- "Desktop client" : "Darbvirsmas klients",
- "Android app" : "Android lietotne",
- "iOS app" : "iOS lietotne",
- "Show First Run Wizard again" : "Vēlreiz rādīt pirmās palaišanas vedni",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Jūs lietojat <strong>%s</strong> no pieejamajiem <strong>%s</strong>",
+ "Profile picture" : "Profila attēls",
+ "Upload new" : "Ielādēt jaunu",
+ "Remove image" : "Novākt attēlu",
+ "Cancel" : "Atcelt",
+ "Email" : "E-pasts",
+ "Your email address" : "Jūsu e-pasta adrese",
"Password" : "Parole",
"Unable to change your password" : "Nevar nomainīt jūsu paroli",
"Current password" : "Pašreizējā parole",
"New password" : "Jauna parole",
"Change password" : "Mainīt paroli",
- "Email" : "E-pasts",
- "Your email address" : "Jūsu e-pasta adrese",
- "Profile picture" : "Profila attēls",
- "Upload new" : "Ielādēt jaunu",
- "Select new from Files" : "Izvēlēties jaunu no Failiem",
- "Remove image" : "Novākt attēlu",
- "Cancel" : "Atcelt",
"Language" : "Valoda",
"Help translate" : "Palīdzi tulkot",
+ "Get the apps to sync your files" : "Saņem lietotnes, lai sinhronizētu savas datnes",
+ "Desktop client" : "Darbvirsmas klients",
+ "Android app" : "Android lietotne",
+ "iOS app" : "iOS lietotne",
+ "Show First Run Wizard again" : "Vēlreiz rādīt pirmās palaišanas vedni",
"Send email to new user" : "Sūtīt e-pastu jaunajam lietotājam",
"Show email address" : "Rādīt e-pasta adreses",
"Username" : "Lietotājvārds",
diff --git a/settings/l10n/mk.js b/settings/l10n/mk.js
index f4ce5676543..b4d4f81b404 100644
--- a/settings/l10n/mk.js
+++ b/settings/l10n/mk.js
@@ -10,12 +10,10 @@ OC.L10N.register(
"Log" : "Записник",
"Tips & tricks" : "Совети и трикови",
"Updates" : "Ажурирања",
- "Authentication error" : "Грешка во автентикација",
- "Your full name has been changed." : "Вашето целосно име е променето.",
- "Unable to change full name" : "Не можам да го променам целото име",
"Couldn't remove app." : "Не можам да ја отстранам апликацијата.",
"Language changed" : "Јазикот е сменет",
"Invalid request" : "Неправилно барање",
+ "Authentication error" : "Грешка во автентикација",
"Admins can't remove themself from the admin group" : "Администраторите неможе да се избришат себеси од админ групата",
"Unable to add user to group %s" : "Неможе да додадам корисник во група %s",
"Unable to remove user from group %s" : "Неможе да избришам корисник од група %s",
@@ -28,6 +26,7 @@ OC.L10N.register(
"Unable to change password" : "Вашата лозинка неможе да се смени",
"Enabled" : "Овозможен",
"Not enabled" : "Не е овозможено",
+ "Federated Cloud Sharing" : "Федерирано клауд споделување",
"A problem occurred, please check your log files (Error: %s)" : "Се случи грешка, ве молам проверете ги вашите датотеки за логови (Грешка: %s)",
"Migration Completed" : "Миграцијата заврши",
"Group already exists." : "Групата веќе постои.",
@@ -38,9 +37,24 @@ OC.L10N.register(
"test email settings" : "провери ги нагодувањата за електронска пошта",
"A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "Се случи грешка при праќање на порака. Ве молам проверете ги вашите подесувања. (Error: %s)",
"Email sent" : "Е-порака пратена",
+ "Invalid mail address" : "Неправилна електронска адреса/пошта",
+ "A user with that name already exists." : "Корисник со ова име веќе постои.",
+ "Unable to create user." : "Неможе да додадам корисник.",
+ "Your %s account was created" : "Вашата %s сметка е креирана",
+ "Unable to delete user." : "Неможам да избришам корисник",
+ "Forbidden" : "Забрането",
+ "Invalid user" : "Неправилен корисник",
+ "Unable to change mail address" : "Не можам да ја променам електронската адреса/пошта",
"Email saved" : "Електронската пошта е снимена",
+ "Your full name has been changed." : "Вашето целосно име е променето.",
+ "Unable to change full name" : "Не можам да го променам целото име",
+ "Migration started …" : "Миграцијата е започнаа ...",
"Sending..." : "Испраќам...",
+ "Official" : "Официјален",
+ "Approved" : "Одобрен",
+ "Experimental" : "Експериментален",
"All" : "Сите",
+ "No apps found for your version" : "За вашата верзија не се пронајдени апликации",
"Please wait...." : "Ве молам почекајте ...",
"Error while disabling app" : "Грешка при исклучувањето на апликацијата",
"Disable" : "Оневозможи",
@@ -49,24 +63,34 @@ OC.L10N.register(
"Updating...." : "Надградувам ...",
"Error while updating app" : "Грешка додека ја надградувам апликацијата",
"Updated" : "Надграден",
+ "Uninstalling ...." : "Деинсталирам ...",
+ "Error while uninstalling app" : "Грешка при деинсталација на апликацијата",
+ "Uninstall" : "Деинсталирај",
+ "App update" : "Надградба на апликацијата",
+ "Valid until {date}" : "Валидно до {date}",
+ "Delete" : "Избриши",
+ "An error occurred: {message}" : "Се случи грешка: {message}",
"Select a profile picture" : "Одбери фотографија за профилот",
"Very weak password" : "Многу слаба лозинка",
"Weak password" : "Слаба лозинка",
"So-so password" : "Така така лозинка",
"Good password" : "Добра лозинка",
"Strong password" : "Јака лозинка",
- "Delete" : "Избриши",
"Groups" : "Групи",
+ "Unable to delete {objName}" : "Не можам да избришам {objName}",
"Error creating group" : "Грешка при креирање на група",
"A valid group name must be provided" : "Мора да се обезбеди валидно име на група",
"undo" : "врати",
+ "no group" : "нема група",
"never" : "никогаш",
+ "deleted {userName}" : "избришан {userName}",
"add group" : "додади група",
"A valid username must be provided" : "Мора да се обезбеди валидно корисничко име ",
"Error creating user" : "Грешка при креирање на корисникот",
"A valid password must be provided" : "Мора да се обезбеди валидна лозинка",
"__language_name__" : "__language_name__",
- "SSL root certificates" : "SSL root сертификати",
+ "Personal info" : "Лични податоци",
+ "Sync clients" : "Клиенти за синхронизација",
"Info, warnings, errors and fatal issues" : "Информации, предупредувања, грешки и фатални работи",
"Warnings, errors and fatal issues" : "Предупредувања, грешки и фатални работи",
"Errors and fatal issues" : "Грешки и фатални работи",
@@ -77,6 +101,7 @@ OC.L10N.register(
"NT LAN Manager" : "NT LAN Менаџер",
"SSL" : "SSL",
"TLS" : "TLS",
+ "Open documentation" : "Отвори ја документацијата",
"Allow apps to use the Share API" : "Дозволете апликациите да го користат API-то за споделување",
"Allow users to share via link" : "Допушти корисниците да споделуваат со линкови",
"Enforce password protection" : "Наметни заштита на лозинка",
@@ -103,34 +128,28 @@ OC.L10N.register(
"SMTP Password" : "SMTP лозинка",
"Test email settings" : "Провери ги нагодувањаа за електронска пошта",
"Send email" : "Испрати пошта",
- "Log level" : "Ниво на логирање",
"More" : "Повеќе",
"Less" : "Помалку",
"Version" : "Верзија",
- "by" : "од",
"Documentation:" : "Документација:",
"Enable only for specific groups" : "Овозможи само на специфицирани групи",
"Cheers!" : "Поздрав!",
"Forum" : "Форум",
- "Get the apps to sync your files" : "Преземете апликации за синхронизирање на вашите датотеки",
- "Show First Run Wizard again" : "Прикажи го повторно волшебникот при првото стартување",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Имате искористено <strong>%s</strong> од достапните <strong>%s</strong>",
+ "Profile picture" : "Фотографија за профил",
+ "Upload new" : "Префрли нова",
+ "Remove image" : "Отстрани ја фотографијата",
+ "Cancel" : "Откажи",
+ "Email" : "Е-пошта",
+ "Your email address" : "Вашата адреса за е-пошта",
"Password" : "Лозинка",
"Unable to change your password" : "Вашата лозинка неможе да се смени",
"Current password" : "Моментална лозинка",
"New password" : "Нова лозинка",
"Change password" : "Смени лозинка",
- "Email" : "Е-пошта",
- "Your email address" : "Вашата адреса за е-пошта",
- "Profile picture" : "Фотографија за профил",
- "Upload new" : "Префрли нова",
- "Select new from Files" : "Одбери нова од датотеките",
- "Remove image" : "Отстрани ја фотографијата",
- "Your avatar is provided by your original account." : "Вашиот аватар е креиран со вашата оригинална сметка",
- "Cancel" : "Откажи",
- "Choose as profile image" : "Одбери фотографија за профилот",
"Language" : "Јазик",
"Help translate" : "Помогни во преводот",
+ "Get the apps to sync your files" : "Преземете апликации за синхронизирање на вашите датотеки",
+ "Show First Run Wizard again" : "Прикажи го повторно волшебникот при првото стартување",
"Username" : "Корисничко име",
"Create" : "Создај",
"Admin Recovery Password" : "Обновување на Admin лозинката",
diff --git a/settings/l10n/mk.json b/settings/l10n/mk.json
index c93ae59e35c..ae7f4a91aff 100644
--- a/settings/l10n/mk.json
+++ b/settings/l10n/mk.json
@@ -8,12 +8,10 @@
"Log" : "Записник",
"Tips & tricks" : "Совети и трикови",
"Updates" : "Ажурирања",
- "Authentication error" : "Грешка во автентикација",
- "Your full name has been changed." : "Вашето целосно име е променето.",
- "Unable to change full name" : "Не можам да го променам целото име",
"Couldn't remove app." : "Не можам да ја отстранам апликацијата.",
"Language changed" : "Јазикот е сменет",
"Invalid request" : "Неправилно барање",
+ "Authentication error" : "Грешка во автентикација",
"Admins can't remove themself from the admin group" : "Администраторите неможе да се избришат себеси од админ групата",
"Unable to add user to group %s" : "Неможе да додадам корисник во група %s",
"Unable to remove user from group %s" : "Неможе да избришам корисник од група %s",
@@ -26,6 +24,7 @@
"Unable to change password" : "Вашата лозинка неможе да се смени",
"Enabled" : "Овозможен",
"Not enabled" : "Не е овозможено",
+ "Federated Cloud Sharing" : "Федерирано клауд споделување",
"A problem occurred, please check your log files (Error: %s)" : "Се случи грешка, ве молам проверете ги вашите датотеки за логови (Грешка: %s)",
"Migration Completed" : "Миграцијата заврши",
"Group already exists." : "Групата веќе постои.",
@@ -36,9 +35,24 @@
"test email settings" : "провери ги нагодувањата за електронска пошта",
"A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "Се случи грешка при праќање на порака. Ве молам проверете ги вашите подесувања. (Error: %s)",
"Email sent" : "Е-порака пратена",
+ "Invalid mail address" : "Неправилна електронска адреса/пошта",
+ "A user with that name already exists." : "Корисник со ова име веќе постои.",
+ "Unable to create user." : "Неможе да додадам корисник.",
+ "Your %s account was created" : "Вашата %s сметка е креирана",
+ "Unable to delete user." : "Неможам да избришам корисник",
+ "Forbidden" : "Забрането",
+ "Invalid user" : "Неправилен корисник",
+ "Unable to change mail address" : "Не можам да ја променам електронската адреса/пошта",
"Email saved" : "Електронската пошта е снимена",
+ "Your full name has been changed." : "Вашето целосно име е променето.",
+ "Unable to change full name" : "Не можам да го променам целото име",
+ "Migration started …" : "Миграцијата е започнаа ...",
"Sending..." : "Испраќам...",
+ "Official" : "Официјален",
+ "Approved" : "Одобрен",
+ "Experimental" : "Експериментален",
"All" : "Сите",
+ "No apps found for your version" : "За вашата верзија не се пронајдени апликации",
"Please wait...." : "Ве молам почекајте ...",
"Error while disabling app" : "Грешка при исклучувањето на апликацијата",
"Disable" : "Оневозможи",
@@ -47,24 +61,34 @@
"Updating...." : "Надградувам ...",
"Error while updating app" : "Грешка додека ја надградувам апликацијата",
"Updated" : "Надграден",
+ "Uninstalling ...." : "Деинсталирам ...",
+ "Error while uninstalling app" : "Грешка при деинсталација на апликацијата",
+ "Uninstall" : "Деинсталирај",
+ "App update" : "Надградба на апликацијата",
+ "Valid until {date}" : "Валидно до {date}",
+ "Delete" : "Избриши",
+ "An error occurred: {message}" : "Се случи грешка: {message}",
"Select a profile picture" : "Одбери фотографија за профилот",
"Very weak password" : "Многу слаба лозинка",
"Weak password" : "Слаба лозинка",
"So-so password" : "Така така лозинка",
"Good password" : "Добра лозинка",
"Strong password" : "Јака лозинка",
- "Delete" : "Избриши",
"Groups" : "Групи",
+ "Unable to delete {objName}" : "Не можам да избришам {objName}",
"Error creating group" : "Грешка при креирање на група",
"A valid group name must be provided" : "Мора да се обезбеди валидно име на група",
"undo" : "врати",
+ "no group" : "нема група",
"never" : "никогаш",
+ "deleted {userName}" : "избришан {userName}",
"add group" : "додади група",
"A valid username must be provided" : "Мора да се обезбеди валидно корисничко име ",
"Error creating user" : "Грешка при креирање на корисникот",
"A valid password must be provided" : "Мора да се обезбеди валидна лозинка",
"__language_name__" : "__language_name__",
- "SSL root certificates" : "SSL root сертификати",
+ "Personal info" : "Лични податоци",
+ "Sync clients" : "Клиенти за синхронизација",
"Info, warnings, errors and fatal issues" : "Информации, предупредувања, грешки и фатални работи",
"Warnings, errors and fatal issues" : "Предупредувања, грешки и фатални работи",
"Errors and fatal issues" : "Грешки и фатални работи",
@@ -75,6 +99,7 @@
"NT LAN Manager" : "NT LAN Менаџер",
"SSL" : "SSL",
"TLS" : "TLS",
+ "Open documentation" : "Отвори ја документацијата",
"Allow apps to use the Share API" : "Дозволете апликациите да го користат API-то за споделување",
"Allow users to share via link" : "Допушти корисниците да споделуваат со линкови",
"Enforce password protection" : "Наметни заштита на лозинка",
@@ -101,34 +126,28 @@
"SMTP Password" : "SMTP лозинка",
"Test email settings" : "Провери ги нагодувањаа за електронска пошта",
"Send email" : "Испрати пошта",
- "Log level" : "Ниво на логирање",
"More" : "Повеќе",
"Less" : "Помалку",
"Version" : "Верзија",
- "by" : "од",
"Documentation:" : "Документација:",
"Enable only for specific groups" : "Овозможи само на специфицирани групи",
"Cheers!" : "Поздрав!",
"Forum" : "Форум",
- "Get the apps to sync your files" : "Преземете апликации за синхронизирање на вашите датотеки",
- "Show First Run Wizard again" : "Прикажи го повторно волшебникот при првото стартување",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Имате искористено <strong>%s</strong> од достапните <strong>%s</strong>",
+ "Profile picture" : "Фотографија за профил",
+ "Upload new" : "Префрли нова",
+ "Remove image" : "Отстрани ја фотографијата",
+ "Cancel" : "Откажи",
+ "Email" : "Е-пошта",
+ "Your email address" : "Вашата адреса за е-пошта",
"Password" : "Лозинка",
"Unable to change your password" : "Вашата лозинка неможе да се смени",
"Current password" : "Моментална лозинка",
"New password" : "Нова лозинка",
"Change password" : "Смени лозинка",
- "Email" : "Е-пошта",
- "Your email address" : "Вашата адреса за е-пошта",
- "Profile picture" : "Фотографија за профил",
- "Upload new" : "Префрли нова",
- "Select new from Files" : "Одбери нова од датотеките",
- "Remove image" : "Отстрани ја фотографијата",
- "Your avatar is provided by your original account." : "Вашиот аватар е креиран со вашата оригинална сметка",
- "Cancel" : "Откажи",
- "Choose as profile image" : "Одбери фотографија за профилот",
"Language" : "Јазик",
"Help translate" : "Помогни во преводот",
+ "Get the apps to sync your files" : "Преземете апликации за синхронизирање на вашите датотеки",
+ "Show First Run Wizard again" : "Прикажи го повторно волшебникот при првото стартување",
"Username" : "Корисничко име",
"Create" : "Создај",
"Admin Recovery Password" : "Обновување на Admin лозинката",
diff --git a/settings/l10n/mn.js b/settings/l10n/mn.js
index 30c8a71df7a..75ca2475868 100644
--- a/settings/l10n/mn.js
+++ b/settings/l10n/mn.js
@@ -4,17 +4,17 @@ OC.L10N.register(
"Sharing" : "Түгээлт",
"Cron" : "Крон",
"Log" : "Лог бичилт",
- "Authentication error" : "Нотолгооны алдаа",
- "Your full name has been changed." : "Таны бүтэн нэр солигдлоо.",
- "Unable to change full name" : "Бүтэн нэр солих боломжгүй байна",
"Couldn't remove app." : "Апп-ыг устгаж чадсангүй",
"Language changed" : "Хэл солигдлоо",
"Invalid request" : "Буруу хүсэлт",
+ "Authentication error" : "Нотолгооны алдаа",
"Admins can't remove themself from the admin group" : "Админууд өөрсдийгөө Админ бүлгээс хасаж чадахгүй",
"Wrong password" : "Нууц үг буруу",
+ "Your full name has been changed." : "Таны бүтэн нэр солигдлоо.",
+ "Unable to change full name" : "Бүтэн нэр солих боломжгүй байна",
"All" : "Бүгд",
- "Password" : "Нууц үг",
"Email" : "И-мэйл",
+ "Password" : "Нууц үг",
"Username" : "Хэрэглэгчийн нэр"
},
"nplurals=2; plural=(n != 1);");
diff --git a/settings/l10n/mn.json b/settings/l10n/mn.json
index 95400f3893c..a98fbc86a0e 100644
--- a/settings/l10n/mn.json
+++ b/settings/l10n/mn.json
@@ -2,17 +2,17 @@
"Sharing" : "Түгээлт",
"Cron" : "Крон",
"Log" : "Лог бичилт",
- "Authentication error" : "Нотолгооны алдаа",
- "Your full name has been changed." : "Таны бүтэн нэр солигдлоо.",
- "Unable to change full name" : "Бүтэн нэр солих боломжгүй байна",
"Couldn't remove app." : "Апп-ыг устгаж чадсангүй",
"Language changed" : "Хэл солигдлоо",
"Invalid request" : "Буруу хүсэлт",
+ "Authentication error" : "Нотолгооны алдаа",
"Admins can't remove themself from the admin group" : "Админууд өөрсдийгөө Админ бүлгээс хасаж чадахгүй",
"Wrong password" : "Нууц үг буруу",
+ "Your full name has been changed." : "Таны бүтэн нэр солигдлоо.",
+ "Unable to change full name" : "Бүтэн нэр солих боломжгүй байна",
"All" : "Бүгд",
- "Password" : "Нууц үг",
"Email" : "И-мэйл",
+ "Password" : "Нууц үг",
"Username" : "Хэрэглэгчийн нэр"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/settings/l10n/ms_MY.js b/settings/l10n/ms_MY.js
index 8bdb9b3878c..30ff133bd42 100644
--- a/settings/l10n/ms_MY.js
+++ b/settings/l10n/ms_MY.js
@@ -2,9 +2,9 @@ OC.L10N.register(
"settings",
{
"Log" : "Log",
- "Authentication error" : "Ralat pengesahan",
"Language changed" : "Bahasa diubah",
"Invalid request" : "Permintaan tidak sah",
+ "Authentication error" : "Ralat pengesahan",
"Email saved" : "Emel disimpan",
"Disable" : "Nyahaktif",
"Enable" : "Aktif",
@@ -14,18 +14,16 @@ OC.L10N.register(
"__language_name__" : "_nama_bahasa_",
"Login" : "Log masuk",
"Server address" : "Alamat pelayan",
- "Log level" : "Tahap Log",
"More" : "Lanjutan",
- "by" : "oleh",
+ "Profile picture" : "Gambar profil",
+ "Cancel" : "Batal",
+ "Email" : "Email",
+ "Your email address" : "Alamat emel anda",
"Password" : "Kata laluan",
"Unable to change your password" : "Gagal mengubah kata laluan anda ",
"Current password" : "Kata laluan semasa",
"New password" : "Kata laluan baru",
"Change password" : "Ubah kata laluan",
- "Email" : "Email",
- "Your email address" : "Alamat emel anda",
- "Profile picture" : "Gambar profil",
- "Cancel" : "Batal",
"Language" : "Bahasa",
"Help translate" : "Bantu terjemah",
"Username" : "Nama pengguna",
diff --git a/settings/l10n/ms_MY.json b/settings/l10n/ms_MY.json
index 4547f0a32b5..19504cee599 100644
--- a/settings/l10n/ms_MY.json
+++ b/settings/l10n/ms_MY.json
@@ -1,8 +1,8 @@
{ "translations": {
"Log" : "Log",
- "Authentication error" : "Ralat pengesahan",
"Language changed" : "Bahasa diubah",
"Invalid request" : "Permintaan tidak sah",
+ "Authentication error" : "Ralat pengesahan",
"Email saved" : "Emel disimpan",
"Disable" : "Nyahaktif",
"Enable" : "Aktif",
@@ -12,18 +12,16 @@
"__language_name__" : "_nama_bahasa_",
"Login" : "Log masuk",
"Server address" : "Alamat pelayan",
- "Log level" : "Tahap Log",
"More" : "Lanjutan",
- "by" : "oleh",
+ "Profile picture" : "Gambar profil",
+ "Cancel" : "Batal",
+ "Email" : "Email",
+ "Your email address" : "Alamat emel anda",
"Password" : "Kata laluan",
"Unable to change your password" : "Gagal mengubah kata laluan anda ",
"Current password" : "Kata laluan semasa",
"New password" : "Kata laluan baru",
"Change password" : "Ubah kata laluan",
- "Email" : "Email",
- "Your email address" : "Alamat emel anda",
- "Profile picture" : "Gambar profil",
- "Cancel" : "Batal",
"Language" : "Bahasa",
"Help translate" : "Bantu terjemah",
"Username" : "Nama pengguna",
diff --git a/settings/l10n/my_MM.js b/settings/l10n/my_MM.js
index 88ad33d0057..99814ff2418 100644
--- a/settings/l10n/my_MM.js
+++ b/settings/l10n/my_MM.js
@@ -1,11 +1,11 @@
OC.L10N.register(
"settings",
{
- "Authentication error" : "ခွင့်ပြုချက်မအောင်မြင်",
"Invalid request" : "တောင်းဆိုချက်မမှန်ကန်ပါ",
+ "Authentication error" : "ခွင့်ပြုချက်မအောင်မြင်",
+ "Cancel" : "ပယ်ဖျက်မည်",
"Password" : "စကားဝှက်",
"New password" : "စကားဝှက်အသစ်",
- "Cancel" : "ပယ်ဖျက်မည်",
"Username" : "သုံးစွဲသူအမည်"
},
"nplurals=1; plural=0;");
diff --git a/settings/l10n/my_MM.json b/settings/l10n/my_MM.json
index 0ded957958f..08dcf1722c8 100644
--- a/settings/l10n/my_MM.json
+++ b/settings/l10n/my_MM.json
@@ -1,9 +1,9 @@
{ "translations": {
- "Authentication error" : "ခွင့်ပြုချက်မအောင်မြင်",
"Invalid request" : "တောင်းဆိုချက်မမှန်ကန်ပါ",
+ "Authentication error" : "ခွင့်ပြုချက်မအောင်မြင်",
+ "Cancel" : "ပယ်ဖျက်မည်",
"Password" : "စကားဝှက်",
"New password" : "စကားဝှက်အသစ်",
- "Cancel" : "ပယ်ဖျက်မည်",
"Username" : "သုံးစွဲသူအမည်"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/settings/l10n/nb_NO.js b/settings/l10n/nb_NO.js
index 44585ece158..3a09b1fc947 100644
--- a/settings/l10n/nb_NO.js
+++ b/settings/l10n/nb_NO.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Logg",
"Tips & tricks" : "Tips og triks",
"Updates" : "Oppdateringer",
- "Authentication error" : "Autentiseringsfeil",
- "Your full name has been changed." : "Ditt fulle navn er blitt endret.",
- "Unable to change full name" : "Klarte ikke å endre fullt navn",
"Couldn't remove app." : "Klarte ikke å fjerne app.",
"Language changed" : "Språk endret",
"Invalid request" : "Ugyldig forespørsel",
+ "Authentication error" : "Autentiseringsfeil",
"Admins can't remove themself from the admin group" : "Admin kan ikke flytte seg selv fra admingruppen",
"Unable to add user to group %s" : "Kan ikke legge bruker til gruppen %s",
"Unable to remove user from group %s" : "Kan ikke slette bruker fra gruppen %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Ugyldig bruker",
"Unable to change mail address" : "Kan ikke endre epost-adresse",
"Email saved" : "Epost lagret",
+ "Your full name has been changed." : "Ditt fulle navn er blitt endret.",
+ "Unable to change full name" : "Klarte ikke å endre fullt navn",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ønsker du virkelig å legge til \"{domain}\" som tiltrodd domene?",
"Add trusted domain" : "Legg til et tiltrodd domene",
"Migration in progress. Please wait until the migration is finished" : "Migrering utføres. Vent til migreringen er ferdig.",
@@ -80,6 +80,10 @@ OC.L10N.register(
"Uninstall" : "Avinstaller",
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Appen er aktivert men må oppdateres. Du vil bli omdirigert til oppdateringssiden om 5 sekunder.",
"App update" : "Oppdatering av applikasjon",
+ "No apps found for \"{query}\"" : "Ingen apper funnet for \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Det oppstod en feil. Vennligst last opp et ASCII-kodet PEM-sertifikat.",
+ "Valid until {date}" : "Gyldig til {date}",
+ "Delete" : "Slett",
"An error occurred: {message}" : "Det oppstod en feil: {message}",
"Select a profile picture" : "Velg et profilbilde",
"Very weak password" : "Veldig svakt passord",
@@ -87,9 +91,6 @@ OC.L10N.register(
"So-so password" : "So-so-passord",
"Good password" : "Bra passord",
"Strong password" : "Sterkt passord",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Det oppstod en feil. Vennligst last opp et ASCII-kodet PEM-sertifikat.",
- "Valid until {date}" : "Gyldig til {date}",
- "Delete" : "Slett",
"Groups" : "Grupper",
"Unable to delete {objName}" : "Kan ikke slette {objName}",
"Error creating group" : "Feil ved oppretting av gruppe",
@@ -106,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Oppgi et gyldig passord",
"A valid email must be provided" : "En gyldig e-postadresse må oppgis",
"__language_name__" : "__language_name__",
- "Sync clients" : "Synkroniseringsklienter",
"Personal info" : "Personlig informasjon",
- "SSL root certificates" : "SSL rotsertifikater",
+ "Sync clients" : "Synkroniseringsklienter",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alt (fatale problemer, feil, advarsler, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, advarsler, feil og fatale problemer",
"Warnings, errors and fatal issues" : "Advarsler, feil og fatale problemer",
@@ -134,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Vi anbefaler sterkt å installere de påkrevde pakkene på systemet ditt for å støtte en av følgende nasjonale innstillinger: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Hvis installasjonen din ikke er installert i roten av domenet og bruker systemets cron, kan det bli problemer med URL-genereringen. For å unngå disse problemene, sett \"overwrite.cli.url\" i filen config.php til web-roten for installasjonen din (Foreslått: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Det var ikke mulig å kjøre cron-jobben vi CLI. Følgende tekniske feil oppstod:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transaksjonsbasert fil-låsing bruker databasen som låsemekanisme. For best ytelse anbefales det å konfigurerer en memcache for låsing. Se <a target=\"_blank\" href=\"%s\">dokumentasjonen ↗</a> for mer informasjon.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Vennligst dobbeltsjekk <a target=\"_blank\" href=\"%s\">Installasjonsveiledningene ↗</a> og se etter feil og advarsler i <a href=\"#log-section\">loggen</a>.",
"All checks passed." : "Alle sjekker bestått.",
"Open documentation" : "Åpne dokumentasjonen",
@@ -187,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Lagre påloggingsdetaljer",
"Test email settings" : "Test innstillinger for e-post",
"Send email" : "Send e-post",
- "Log level" : "Loggnivå",
"Download logfile" : "Last ned loggfil",
"More" : "Mer",
"Less" : "Mindre",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Loggfilen er over 100 MB, nedlastingen kan ta en stund!",
+ "What to log" : "Hva som skal logges",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite brukes som database. For større installasjoner anbefaler vi å bytte til en annen database-server.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "SQLite er spesielt frarådet om man bruker desktopklienten til filsynkronisering",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "For å migrere til en annen database, bruk kommandolinjeverktøyet: 'occ db:convert-type', eller les i <a target=\"_blank\" href=\"%s\">dokumentasjonen ↗</a>.",
@@ -205,17 +204,23 @@ OC.L10N.register(
"Developer documentation" : "Utviklerdokumentasjon",
"Experimental applications ahead" : "Eksperimentelle applikasjoner forut",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Eksperimentelle apper er ikke sjekket for sikkerhetsproblemer. De er nye eller de anses som ustabile og under stadig utvikling. Å installere slike apper kan forårsake tap av data eller brudd på sikkerheten.",
- "by" : "av",
- "licensed" : "lisensiert",
"Documentation:" : "Dokumentasjon:",
"User documentation" : "Brukerdokumentasjon",
"Admin documentation" : "Admin-dokumentasjon",
"Show description …" : "Vis beskrivelse …",
"Hide description …" : "Skjul beskrivelse …",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Denne appen har ingen minimumsversjon av ownCloud. Dette vil være en feil i ownCloud 11 og senere.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Denne appen har ingen maksimumsversjon av ownCloud. Dette vil være en feil i ownCloud 11 og senere.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Denne appen kan ikke installeres fordi følgende avhengigheter ikke er tilfredsstilt:",
"Enable only for specific groups" : "Aktiver kun for visse grupper",
"Uninstall App" : "Avinstaller app",
"Enable experimental apps" : "Aktiver eksperimentelle apper",
+ "SSL Root Certificates" : "SSL rotsertifikater",
+ "Common Name" : "Vanlig navn",
+ "Valid until" : "Gyldig til",
+ "Issued By" : "Utstedt av",
+ "Valid until %s" : "Gyldig til %s",
+ "Import root certificate" : "Importer rotsertifikat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hei,<br><br>vil bare informere om at du nå har en %s-konto.<br><br>Brukernavnet ditt: %s<br>Gå dit: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Ha det!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hei,\n\nVil bare informere om at du nå har en %s-konto.\n\nBrukernavnet ditt: %s\nGå dit: %s\n\n",
@@ -224,40 +229,35 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Problemsporing",
"Commercial support" : "Forretningsstøtte",
- "Get the apps to sync your files" : "Hent apper som synkroniserer filene dine",
- "Desktop client" : "Skrivebordsklient",
- "Android app" : "Android-app",
- "iOS app" : "iOS-app",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Hvis du vil støtte prosjektet kan du\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">delta i utviklingen</a>\n\t\teller\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spre budskapet</a>!",
- "Show First Run Wizard again" : "Vis \"Førstegangs veiviser\" på nytt",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du har brukt <strong>%s</strong> av de tilgjengelige <strong>%s</strong>",
- "Password" : "Passord",
- "Unable to change your password" : "Kunne ikke endre passordet ditt",
- "Current password" : "Nåværende passord",
- "New password" : "Nytt passord",
- "Change password" : "Endre passord",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Du bruker <strong>%s</strong> av <strong>%s</strong>",
+ "Profile picture" : "Profilbilde",
+ "Upload new" : "Last opp nytt",
+ "Select from Files" : "Velg fra Filer",
+ "Remove image" : "Fjern bilde",
+ "png or jpg, max. 20 MB" : "png eller jpg, maks. 20 MB",
+ "Picture provided by original account" : "Bilde kommer fra opprinnelig konto",
+ "Cancel" : "Avbryt",
+ "Choose as profile picture" : "Velg som profilbilde",
"Full name" : "Fullt navn",
"No display name set" : "Visningsnavn ikke satt",
"Email" : "Epost",
"Your email address" : "Din e-postadresse",
- "Fill in an email address to enable password recovery and receive notifications" : "Legg inn en e-postadresse for å aktivere passordgjenfinning og motta varsler",
+ "For password recovery and notifications" : "For passord-gjenoppretting og varsler",
"No email address set" : "E-postadresse ikke satt",
"You are member of the following groups:" : "Du er medlem av følgende grupper:",
- "Profile picture" : "Profilbilde",
- "Upload new" : "Last opp nytt",
- "Select new from Files" : "Velg nytt fra Filer",
- "Remove image" : "Fjern bilde",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Enten png eller jpg. Helst kvadratisk, men du kan beskjære bildet. Filen kan ikke være større enn 20 MB.",
- "Your avatar is provided by your original account." : "Avataren din kommer fra din opprinnelige konto.",
- "Cancel" : "Avbryt",
- "Choose as profile image" : "Velg som profilbilde",
+ "Password" : "Passord",
+ "Unable to change your password" : "Kunne ikke endre passordet ditt",
+ "Current password" : "Nåværende passord",
+ "New password" : "Nytt passord",
+ "Change password" : "Endre passord",
"Language" : "Språk",
"Help translate" : "Bidra til oversettelsen",
- "Common Name" : "Vanlig navn",
- "Valid until" : "Gyldig til",
- "Issued By" : "Utstedt av",
- "Valid until %s" : "Gyldig til %s",
- "Import root certificate" : "Importer rotsertifikat",
+ "Get the apps to sync your files" : "Hent apper som synkroniserer filene dine",
+ "Desktop client" : "Skrivebordsklient",
+ "Android app" : "Android-app",
+ "iOS app" : "iOS-app",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Hvis du vil støtte prosjektet kan du\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">delta i utviklingen</a>\n\t\teller\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spre budskapet</a>!",
+ "Show First Run Wizard again" : "Vis \"Førstegangs veiviser\" på nytt",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Utviklet av {communityopen}ownCloud-fellesskapet{linkclose}. {githubopen}Kildekoden{linkclose} er lisensiert under {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Vis lagringssted",
"Show last log in" : "Vis site innlogging",
diff --git a/settings/l10n/nb_NO.json b/settings/l10n/nb_NO.json
index 2cd023b3ac8..c2368bb9b78 100644
--- a/settings/l10n/nb_NO.json
+++ b/settings/l10n/nb_NO.json
@@ -10,12 +10,10 @@
"Log" : "Logg",
"Tips & tricks" : "Tips og triks",
"Updates" : "Oppdateringer",
- "Authentication error" : "Autentiseringsfeil",
- "Your full name has been changed." : "Ditt fulle navn er blitt endret.",
- "Unable to change full name" : "Klarte ikke å endre fullt navn",
"Couldn't remove app." : "Klarte ikke å fjerne app.",
"Language changed" : "Språk endret",
"Invalid request" : "Ugyldig forespørsel",
+ "Authentication error" : "Autentiseringsfeil",
"Admins can't remove themself from the admin group" : "Admin kan ikke flytte seg selv fra admingruppen",
"Unable to add user to group %s" : "Kan ikke legge bruker til gruppen %s",
"Unable to remove user from group %s" : "Kan ikke slette bruker fra gruppen %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Ugyldig bruker",
"Unable to change mail address" : "Kan ikke endre epost-adresse",
"Email saved" : "Epost lagret",
+ "Your full name has been changed." : "Ditt fulle navn er blitt endret.",
+ "Unable to change full name" : "Klarte ikke å endre fullt navn",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ønsker du virkelig å legge til \"{domain}\" som tiltrodd domene?",
"Add trusted domain" : "Legg til et tiltrodd domene",
"Migration in progress. Please wait until the migration is finished" : "Migrering utføres. Vent til migreringen er ferdig.",
@@ -78,6 +78,10 @@
"Uninstall" : "Avinstaller",
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Appen er aktivert men må oppdateres. Du vil bli omdirigert til oppdateringssiden om 5 sekunder.",
"App update" : "Oppdatering av applikasjon",
+ "No apps found for \"{query}\"" : "Ingen apper funnet for \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Det oppstod en feil. Vennligst last opp et ASCII-kodet PEM-sertifikat.",
+ "Valid until {date}" : "Gyldig til {date}",
+ "Delete" : "Slett",
"An error occurred: {message}" : "Det oppstod en feil: {message}",
"Select a profile picture" : "Velg et profilbilde",
"Very weak password" : "Veldig svakt passord",
@@ -85,9 +89,6 @@
"So-so password" : "So-so-passord",
"Good password" : "Bra passord",
"Strong password" : "Sterkt passord",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Det oppstod en feil. Vennligst last opp et ASCII-kodet PEM-sertifikat.",
- "Valid until {date}" : "Gyldig til {date}",
- "Delete" : "Slett",
"Groups" : "Grupper",
"Unable to delete {objName}" : "Kan ikke slette {objName}",
"Error creating group" : "Feil ved oppretting av gruppe",
@@ -104,9 +105,8 @@
"A valid password must be provided" : "Oppgi et gyldig passord",
"A valid email must be provided" : "En gyldig e-postadresse må oppgis",
"__language_name__" : "__language_name__",
- "Sync clients" : "Synkroniseringsklienter",
"Personal info" : "Personlig informasjon",
- "SSL root certificates" : "SSL rotsertifikater",
+ "Sync clients" : "Synkroniseringsklienter",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alt (fatale problemer, feil, advarsler, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, advarsler, feil og fatale problemer",
"Warnings, errors and fatal issues" : "Advarsler, feil og fatale problemer",
@@ -132,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Vi anbefaler sterkt å installere de påkrevde pakkene på systemet ditt for å støtte en av følgende nasjonale innstillinger: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Hvis installasjonen din ikke er installert i roten av domenet og bruker systemets cron, kan det bli problemer med URL-genereringen. For å unngå disse problemene, sett \"overwrite.cli.url\" i filen config.php til web-roten for installasjonen din (Foreslått: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Det var ikke mulig å kjøre cron-jobben vi CLI. Følgende tekniske feil oppstod:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transaksjonsbasert fil-låsing bruker databasen som låsemekanisme. For best ytelse anbefales det å konfigurerer en memcache for låsing. Se <a target=\"_blank\" href=\"%s\">dokumentasjonen ↗</a> for mer informasjon.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Vennligst dobbeltsjekk <a target=\"_blank\" href=\"%s\">Installasjonsveiledningene ↗</a> og se etter feil og advarsler i <a href=\"#log-section\">loggen</a>.",
"All checks passed." : "Alle sjekker bestått.",
"Open documentation" : "Åpne dokumentasjonen",
@@ -185,11 +184,11 @@
"Store credentials" : "Lagre påloggingsdetaljer",
"Test email settings" : "Test innstillinger for e-post",
"Send email" : "Send e-post",
- "Log level" : "Loggnivå",
"Download logfile" : "Last ned loggfil",
"More" : "Mer",
"Less" : "Mindre",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Loggfilen er over 100 MB, nedlastingen kan ta en stund!",
+ "What to log" : "Hva som skal logges",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite brukes som database. For større installasjoner anbefaler vi å bytte til en annen database-server.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "SQLite er spesielt frarådet om man bruker desktopklienten til filsynkronisering",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "For å migrere til en annen database, bruk kommandolinjeverktøyet: 'occ db:convert-type', eller les i <a target=\"_blank\" href=\"%s\">dokumentasjonen ↗</a>.",
@@ -203,17 +202,23 @@
"Developer documentation" : "Utviklerdokumentasjon",
"Experimental applications ahead" : "Eksperimentelle applikasjoner forut",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Eksperimentelle apper er ikke sjekket for sikkerhetsproblemer. De er nye eller de anses som ustabile og under stadig utvikling. Å installere slike apper kan forårsake tap av data eller brudd på sikkerheten.",
- "by" : "av",
- "licensed" : "lisensiert",
"Documentation:" : "Dokumentasjon:",
"User documentation" : "Brukerdokumentasjon",
"Admin documentation" : "Admin-dokumentasjon",
"Show description …" : "Vis beskrivelse …",
"Hide description …" : "Skjul beskrivelse …",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Denne appen har ingen minimumsversjon av ownCloud. Dette vil være en feil i ownCloud 11 og senere.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Denne appen har ingen maksimumsversjon av ownCloud. Dette vil være en feil i ownCloud 11 og senere.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Denne appen kan ikke installeres fordi følgende avhengigheter ikke er tilfredsstilt:",
"Enable only for specific groups" : "Aktiver kun for visse grupper",
"Uninstall App" : "Avinstaller app",
"Enable experimental apps" : "Aktiver eksperimentelle apper",
+ "SSL Root Certificates" : "SSL rotsertifikater",
+ "Common Name" : "Vanlig navn",
+ "Valid until" : "Gyldig til",
+ "Issued By" : "Utstedt av",
+ "Valid until %s" : "Gyldig til %s",
+ "Import root certificate" : "Importer rotsertifikat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hei,<br><br>vil bare informere om at du nå har en %s-konto.<br><br>Brukernavnet ditt: %s<br>Gå dit: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Ha det!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hei,\n\nVil bare informere om at du nå har en %s-konto.\n\nBrukernavnet ditt: %s\nGå dit: %s\n\n",
@@ -222,40 +227,35 @@
"Forum" : "Forum",
"Issue tracker" : "Problemsporing",
"Commercial support" : "Forretningsstøtte",
- "Get the apps to sync your files" : "Hent apper som synkroniserer filene dine",
- "Desktop client" : "Skrivebordsklient",
- "Android app" : "Android-app",
- "iOS app" : "iOS-app",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Hvis du vil støtte prosjektet kan du\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">delta i utviklingen</a>\n\t\teller\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spre budskapet</a>!",
- "Show First Run Wizard again" : "Vis \"Førstegangs veiviser\" på nytt",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du har brukt <strong>%s</strong> av de tilgjengelige <strong>%s</strong>",
- "Password" : "Passord",
- "Unable to change your password" : "Kunne ikke endre passordet ditt",
- "Current password" : "Nåværende passord",
- "New password" : "Nytt passord",
- "Change password" : "Endre passord",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Du bruker <strong>%s</strong> av <strong>%s</strong>",
+ "Profile picture" : "Profilbilde",
+ "Upload new" : "Last opp nytt",
+ "Select from Files" : "Velg fra Filer",
+ "Remove image" : "Fjern bilde",
+ "png or jpg, max. 20 MB" : "png eller jpg, maks. 20 MB",
+ "Picture provided by original account" : "Bilde kommer fra opprinnelig konto",
+ "Cancel" : "Avbryt",
+ "Choose as profile picture" : "Velg som profilbilde",
"Full name" : "Fullt navn",
"No display name set" : "Visningsnavn ikke satt",
"Email" : "Epost",
"Your email address" : "Din e-postadresse",
- "Fill in an email address to enable password recovery and receive notifications" : "Legg inn en e-postadresse for å aktivere passordgjenfinning og motta varsler",
+ "For password recovery and notifications" : "For passord-gjenoppretting og varsler",
"No email address set" : "E-postadresse ikke satt",
"You are member of the following groups:" : "Du er medlem av følgende grupper:",
- "Profile picture" : "Profilbilde",
- "Upload new" : "Last opp nytt",
- "Select new from Files" : "Velg nytt fra Filer",
- "Remove image" : "Fjern bilde",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Enten png eller jpg. Helst kvadratisk, men du kan beskjære bildet. Filen kan ikke være større enn 20 MB.",
- "Your avatar is provided by your original account." : "Avataren din kommer fra din opprinnelige konto.",
- "Cancel" : "Avbryt",
- "Choose as profile image" : "Velg som profilbilde",
+ "Password" : "Passord",
+ "Unable to change your password" : "Kunne ikke endre passordet ditt",
+ "Current password" : "Nåværende passord",
+ "New password" : "Nytt passord",
+ "Change password" : "Endre passord",
"Language" : "Språk",
"Help translate" : "Bidra til oversettelsen",
- "Common Name" : "Vanlig navn",
- "Valid until" : "Gyldig til",
- "Issued By" : "Utstedt av",
- "Valid until %s" : "Gyldig til %s",
- "Import root certificate" : "Importer rotsertifikat",
+ "Get the apps to sync your files" : "Hent apper som synkroniserer filene dine",
+ "Desktop client" : "Skrivebordsklient",
+ "Android app" : "Android-app",
+ "iOS app" : "iOS-app",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Hvis du vil støtte prosjektet kan du\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">delta i utviklingen</a>\n\t\teller\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spre budskapet</a>!",
+ "Show First Run Wizard again" : "Vis \"Førstegangs veiviser\" på nytt",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Utviklet av {communityopen}ownCloud-fellesskapet{linkclose}. {githubopen}Kildekoden{linkclose} er lisensiert under {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Vis lagringssted",
"Show last log in" : "Vis site innlogging",
diff --git a/settings/l10n/nds.js b/settings/l10n/nds.js
index e1998c807fd..a8c440f6e0b 100644
--- a/settings/l10n/nds.js
+++ b/settings/l10n/nds.js
@@ -3,17 +3,17 @@ OC.L10N.register(
{
"External Storage" : "Externer Speicher",
"Saved" : "Gespeichert",
+ "Delete" : "Löschen",
"Very weak password" : "Sehr schwaches Passwort",
"Weak password" : "Schwaches Passwort",
"So-so password" : "Mittelstarkes Passwort",
"Good password" : "Gutes Passwort",
"Strong password" : "Starkes Passwort",
- "Delete" : "Löschen",
"None" : "Keine(r)",
"Enable encryption" : "Verschlüsselung aktivieren",
"Port" : "Port",
- "Password" : "Passwort",
"Cancel" : "Abbrechen",
+ "Password" : "Passwort",
"Username" : "Benutzername"
},
"nplurals=2; plural=(n != 1);");
diff --git a/settings/l10n/nds.json b/settings/l10n/nds.json
index 2c56decc573..a8b5ae43a75 100644
--- a/settings/l10n/nds.json
+++ b/settings/l10n/nds.json
@@ -1,17 +1,17 @@
{ "translations": {
"External Storage" : "Externer Speicher",
"Saved" : "Gespeichert",
+ "Delete" : "Löschen",
"Very weak password" : "Sehr schwaches Passwort",
"Weak password" : "Schwaches Passwort",
"So-so password" : "Mittelstarkes Passwort",
"Good password" : "Gutes Passwort",
"Strong password" : "Starkes Passwort",
- "Delete" : "Löschen",
"None" : "Keine(r)",
"Enable encryption" : "Verschlüsselung aktivieren",
"Port" : "Port",
- "Password" : "Passwort",
"Cancel" : "Abbrechen",
+ "Password" : "Passwort",
"Username" : "Benutzername"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/settings/l10n/nl.js b/settings/l10n/nl.js
index 9b4aff943f2..60962c89c61 100644
--- a/settings/l10n/nl.js
+++ b/settings/l10n/nl.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Log",
"Tips & tricks" : "Tips & trucs",
"Updates" : "Updates",
- "Authentication error" : "Authenticatie fout",
- "Your full name has been changed." : "Uw volledige naam is gewijzigd.",
- "Unable to change full name" : "Kan de volledige naam niet wijzigen",
"Couldn't remove app." : "Kon app niet verwijderen.",
"Language changed" : "Taal aangepast",
"Invalid request" : "Ongeldige aanvraag",
+ "Authentication error" : "Authenticatie fout",
"Admins can't remove themself from the admin group" : "Admins kunnen zichzelf niet uit de admin groep verwijderen",
"Unable to add user to group %s" : "Niet in staat om gebruiker toe te voegen aan groep %s",
"Unable to remove user from group %s" : "Niet in staat om gebruiker te verwijderen uit groep %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Ongeldige gebruiker",
"Unable to change mail address" : "Kan e-mailadres niet wijzigen",
"Email saved" : "E-mail bewaard",
+ "Your full name has been changed." : "Uw volledige naam is gewijzigd.",
+ "Unable to change full name" : "Kan de volledige naam niet wijzigen",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Weet u zeker dat u \"{domain}\" als een vertrouwd domein wilt toevoegen?",
"Add trusted domain" : "Vertrouwd domein toevoegen",
"Migration in progress. Please wait until the migration is finished" : "Migratie bezig. Wacht tot het proces klaar is.",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "De app is geactiveerd maar moet worden bijgewerkt. U wordt over 5 seconden doorgeleid naar de bijwerkpagina.",
"App update" : "App update",
"No apps found for \"{query}\"" : "Geen apps gevonden voor \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Er trad een fout op. Upload als een ASCII-gecodeerd PEM certificaat.",
+ "Valid until {date}" : "Geldig tot {date}",
+ "Delete" : "Verwijder",
"An error occurred: {message}" : "Er heeft zich een fout voorgedaan: {message}",
"Select a profile picture" : "Kies een profielafbeelding",
"Very weak password" : "Zeer zwak wachtwoord",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Matig wachtwoord",
"Good password" : "Goed wachtwoord",
"Strong password" : "Sterk wachtwoord",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Er trad een fout op. Upload als een ASCII-gecodeerd PEM certificaat.",
- "Valid until {date}" : "Geldig tot {date}",
- "Delete" : "Verwijder",
"Groups" : "Groepen",
"Unable to delete {objName}" : "Kan {objName} niet verwijderen",
"Error creating group" : "Fout bij aanmaken groep",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Er moet een geldig wachtwoord worden opgegeven",
"A valid email must be provided" : "Er moet een geldig e-mailadres worden opgegeven",
"__language_name__" : "Nederlands",
- "Sync clients" : "Sync clients",
"Personal info" : "Persoonlijke info",
- "SSL root certificates" : "SSL root certificaten",
+ "Sync clients" : "Sync clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alles (fatale problemen, fouten, waarschuwingen, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, waarschuwingen, fouten en fatale problemen",
"Warnings, errors and fatal issues" : "Waarschuwingen, fouten en fatale problemen",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "We adviseren met klem om de noodzakelijke pakketten op uw systeem te installeren om een van de volgende talen te ondersteunen: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Als uw installatie niet in de hoofddirectory van het domein staat, maar wel cron gebruikt, dan kunnen er problemen ontstaan bij het genereren van URL's. Om deze problemen te voorkomen zou u de \"overwrite.cli.url\" optie in config.php moeten instellen op het webroot pad van uw ownCloud (aanbevolen: \"%s\") ",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "het was niet mogelijk om de cronjob via CLI uit te voeren. De volgende technische problemen traden op:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transactionele bestandslocking gebruikt de database als blokkeermechanisme. Voor de beste prestaties wordt geadviseerd om een memcache voor locking te configureren. Zie de <a target=\"_blank\" href=\"%s\">documentatie ↗</a> voor meer informatie.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Lees de <a href='%s'>installatie handleiding</a> goed door en controleer op fouten en waarschuwingen in de <a href=\"#log-section\">logging</a>.",
"All checks passed." : "Alle checks geslaagd",
"Open documentation" : "Open documentatie",
@@ -188,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Opslaan inloggegevens",
"Test email settings" : "Test e-mailinstellingen",
"Send email" : "Versturen e-mail",
- "Log level" : "Log niveau",
"Download logfile" : "Download logbestand",
"More" : "Meer",
"Less" : "Minder",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Het logbestand is groter dan 100MB. Downloaden kost even tijd!",
+ "What to log" : "Wat loggen",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite wordt gebruikt als database. Voor grotere installaties adviseren we om te schakelen naar een andere database engine.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Vooral wanneer de desktop client wordt gebruik voor bestandssynchronisatie wordt gebruik van sqlite afgeraden.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Om te migreren naar een andere database moet u de commandoregel tool gebruiken: 'occ db:convert-type', lees de <a target=\"_blank\" href=\"%s\">documentatie ↗</a>.",
@@ -206,17 +204,25 @@ OC.L10N.register(
"Developer documentation" : "Ontwikkelaarsdocumentatie",
"Experimental applications ahead" : "Experimentele applicaties vooraan",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentele apps zijn niet gecontroleerd op beveiligingsproblemen, zijn nieuw of staan bekend als instabiel en worden volop ontwikkeld. Installatie kan leiden tot gegevensverlies of beveiligingsincidenten.",
- "by" : "door",
- "licensed" : "gelicenseerd",
+ "by %s" : "op %s",
+ "%s-licensed" : "%s-licensed",
"Documentation:" : "Documentatie:",
"User documentation" : "Gebruikersdocumentatie",
"Admin documentation" : "Beheerdocumentatie",
"Show description …" : "Toon beschrijving ...",
"Hide description …" : "Verberg beschrijving ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Deze app heeft geen minimum ownCloud versienummer toegewezen gekregen. Dit wordt een fout in ownCloud 11 en later.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Deze app heeft geen maximum ownCloud versienummer toegewezen gekregen. Dit wordt een fout in ownCloud 11 en later.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Deze app kan niet worden geïnstalleerd omdat de volgende afhankelijkheden niet zijn ingevuld:",
"Enable only for specific groups" : "Alleen voor bepaalde groepen activeren",
"Uninstall App" : "De-installeren app",
"Enable experimental apps" : "Inschakelen experimentele apps",
+ "SSL Root Certificates" : "SSL Root Certificaten",
+ "Common Name" : "Common Name",
+ "Valid until" : "Geldig tot",
+ "Issued By" : "Uitgegeven door",
+ "Valid until %s" : "Geldig tot %s",
+ "Import root certificate" : "Importeren root certificaat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hallo daar,<br><br>we willen u laten weten dat u nu een %s account hebt.<br><br>Uw gebruikersnaam: %s<br>Ga naar: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Proficiat!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hallo,\n\nwe willen u laten weten dat u nu een %s account hebt.\n\nUw gebruikersnaam: %s\nGa naar: %s\n\n",
@@ -225,41 +231,36 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Issue tracker",
"Commercial support" : "Commerciële ondersteuning",
- "Get the apps to sync your files" : "Download de apps om bestanden te synchroniseren",
- "Desktop client" : "Desktop client",
- "Android app" : "Android app",
- "iOS app" : "iOS app",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Als u het project wilt ondersteunen\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ontwikkel mee</a>\n\t\tof\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">verkondig het nieuws</a>!",
- "Show First Run Wizard again" : "Toon de Eerste start Wizard opnieuw",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "U heeft <strong>%s</strong> gebruikt van de beschikbare <strong>%s</strong>",
- "Password" : "Wachtwoord",
- "Unable to change your password" : "Niet in staat om uw wachtwoord te wijzigen",
- "Current password" : "Huidig wachtwoord",
- "New password" : "Nieuw",
- "Change password" : "Wijzig wachtwoord",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "U gebruikt <strong>%s</strong> van <strong>%s</strong>",
+ "Profile picture" : "Profielafbeelding",
+ "Upload new" : "Upload een nieuwe",
+ "Select from Files" : "Kies uit bestanden",
+ "Remove image" : "Afbeelding verwijderen",
+ "png or jpg, max. 20 MB" : "png of jpg, max. 20 MB",
+ "Picture provided by original account" : "Afbeelding is verstrekt door originele account.",
+ "Cancel" : "Annuleer",
+ "Choose as profile picture" : "Kies als profielafbeelding",
"Full name" : "Volledige naam",
"No display name set" : "Nog geen weergavenaam ingesteld",
"Email" : "E-mailadres",
"Your email address" : "Uw e-mailadres",
- "Fill in an email address to enable password recovery and receive notifications" : "Vul een e-mailadres in om wachtwoordherstel mogelijk te maken en meldingen te ontvangen",
+ "For password recovery and notifications" : "Voor wachtwoordherstel en meldingen",
"No email address set" : "Geen e-mailadres opgegeven",
"You are member of the following groups:" : "U bent lid van de volgende groepen:",
- "Profile picture" : "Profielafbeelding",
- "Upload new" : "Upload een nieuwe",
- "Select new from Files" : "Selecteer een nieuwe vanuit bestanden",
- "Remove image" : "Afbeelding verwijderen",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Of png, of jpg. Bij voorkeur vierkant, maar u kunt de afbeelding bijsnijden. Het bestand mag niet groter zijn dan 20 MB.",
- "Your avatar is provided by your original account." : "Uw avatar is verstrekt door uw originele account.",
- "Cancel" : "Annuleer",
- "Choose as profile image" : "Kies als profielafbeelding",
+ "Password" : "Wachtwoord",
+ "Unable to change your password" : "Niet in staat om uw wachtwoord te wijzigen",
+ "Current password" : "Huidig wachtwoord",
+ "New password" : "Nieuw",
+ "Change password" : "Wijzig wachtwoord",
"Language" : "Taal",
"Help translate" : "Help met vertalen",
- "Common Name" : "Common Name",
- "Valid until" : "Geldig tot",
- "Issued By" : "Uitgegeven door",
- "Valid until %s" : "Geldig tot %s",
- "Import root certificate" : "Importeren root certificaat",
- "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Ontwikkeld door de {communityopen}ownCloud gemeenschaplinkclose}, de {githubopen}source code{linkclose} is gelicenseerd onder de {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
+ "Get the apps to sync your files" : "Download de apps om bestanden te synchroniseren",
+ "Desktop client" : "Desktop client",
+ "Android app" : "Android app",
+ "iOS app" : "iOS app",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Als u het project wilt ondersteunen\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ontwikkel mee</a>\n\t\tof\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">verkondig het nieuws</a>!",
+ "Show First Run Wizard again" : "Toon de Eerste start Wizard opnieuw",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Ontwikkeld door de {communityopen}ownCloud gemeenschap{linkclose}, de {githubopen}source code{linkclose} is gelicenseerd onder de {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Toon opslaglocatie",
"Show last log in" : "Toon laatste inlog",
"Show user backend" : "Toon backend gebruiker",
diff --git a/settings/l10n/nl.json b/settings/l10n/nl.json
index 14cea3dcb63..2c201e83e30 100644
--- a/settings/l10n/nl.json
+++ b/settings/l10n/nl.json
@@ -10,12 +10,10 @@
"Log" : "Log",
"Tips & tricks" : "Tips & trucs",
"Updates" : "Updates",
- "Authentication error" : "Authenticatie fout",
- "Your full name has been changed." : "Uw volledige naam is gewijzigd.",
- "Unable to change full name" : "Kan de volledige naam niet wijzigen",
"Couldn't remove app." : "Kon app niet verwijderen.",
"Language changed" : "Taal aangepast",
"Invalid request" : "Ongeldige aanvraag",
+ "Authentication error" : "Authenticatie fout",
"Admins can't remove themself from the admin group" : "Admins kunnen zichzelf niet uit de admin groep verwijderen",
"Unable to add user to group %s" : "Niet in staat om gebruiker toe te voegen aan groep %s",
"Unable to remove user from group %s" : "Niet in staat om gebruiker te verwijderen uit groep %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Ongeldige gebruiker",
"Unable to change mail address" : "Kan e-mailadres niet wijzigen",
"Email saved" : "E-mail bewaard",
+ "Your full name has been changed." : "Uw volledige naam is gewijzigd.",
+ "Unable to change full name" : "Kan de volledige naam niet wijzigen",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Weet u zeker dat u \"{domain}\" als een vertrouwd domein wilt toevoegen?",
"Add trusted domain" : "Vertrouwd domein toevoegen",
"Migration in progress. Please wait until the migration is finished" : "Migratie bezig. Wacht tot het proces klaar is.",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "De app is geactiveerd maar moet worden bijgewerkt. U wordt over 5 seconden doorgeleid naar de bijwerkpagina.",
"App update" : "App update",
"No apps found for \"{query}\"" : "Geen apps gevonden voor \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Er trad een fout op. Upload als een ASCII-gecodeerd PEM certificaat.",
+ "Valid until {date}" : "Geldig tot {date}",
+ "Delete" : "Verwijder",
"An error occurred: {message}" : "Er heeft zich een fout voorgedaan: {message}",
"Select a profile picture" : "Kies een profielafbeelding",
"Very weak password" : "Zeer zwak wachtwoord",
@@ -86,9 +89,6 @@
"So-so password" : "Matig wachtwoord",
"Good password" : "Goed wachtwoord",
"Strong password" : "Sterk wachtwoord",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Er trad een fout op. Upload als een ASCII-gecodeerd PEM certificaat.",
- "Valid until {date}" : "Geldig tot {date}",
- "Delete" : "Verwijder",
"Groups" : "Groepen",
"Unable to delete {objName}" : "Kan {objName} niet verwijderen",
"Error creating group" : "Fout bij aanmaken groep",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Er moet een geldig wachtwoord worden opgegeven",
"A valid email must be provided" : "Er moet een geldig e-mailadres worden opgegeven",
"__language_name__" : "Nederlands",
- "Sync clients" : "Sync clients",
"Personal info" : "Persoonlijke info",
- "SSL root certificates" : "SSL root certificaten",
+ "Sync clients" : "Sync clients",
"Everything (fatal issues, errors, warnings, info, debug)" : "Alles (fatale problemen, fouten, waarschuwingen, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, waarschuwingen, fouten en fatale problemen",
"Warnings, errors and fatal issues" : "Waarschuwingen, fouten en fatale problemen",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "We adviseren met klem om de noodzakelijke pakketten op uw systeem te installeren om een van de volgende talen te ondersteunen: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Als uw installatie niet in de hoofddirectory van het domein staat, maar wel cron gebruikt, dan kunnen er problemen ontstaan bij het genereren van URL's. Om deze problemen te voorkomen zou u de \"overwrite.cli.url\" optie in config.php moeten instellen op het webroot pad van uw ownCloud (aanbevolen: \"%s\") ",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "het was niet mogelijk om de cronjob via CLI uit te voeren. De volgende technische problemen traden op:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transactionele bestandslocking gebruikt de database als blokkeermechanisme. Voor de beste prestaties wordt geadviseerd om een memcache voor locking te configureren. Zie de <a target=\"_blank\" href=\"%s\">documentatie ↗</a> voor meer informatie.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Lees de <a href='%s'>installatie handleiding</a> goed door en controleer op fouten en waarschuwingen in de <a href=\"#log-section\">logging</a>.",
"All checks passed." : "Alle checks geslaagd",
"Open documentation" : "Open documentatie",
@@ -186,11 +184,11 @@
"Store credentials" : "Opslaan inloggegevens",
"Test email settings" : "Test e-mailinstellingen",
"Send email" : "Versturen e-mail",
- "Log level" : "Log niveau",
"Download logfile" : "Download logbestand",
"More" : "Meer",
"Less" : "Minder",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Het logbestand is groter dan 100MB. Downloaden kost even tijd!",
+ "What to log" : "Wat loggen",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite wordt gebruikt als database. Voor grotere installaties adviseren we om te schakelen naar een andere database engine.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Vooral wanneer de desktop client wordt gebruik voor bestandssynchronisatie wordt gebruik van sqlite afgeraden.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Om te migreren naar een andere database moet u de commandoregel tool gebruiken: 'occ db:convert-type', lees de <a target=\"_blank\" href=\"%s\">documentatie ↗</a>.",
@@ -204,17 +202,25 @@
"Developer documentation" : "Ontwikkelaarsdocumentatie",
"Experimental applications ahead" : "Experimentele applicaties vooraan",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentele apps zijn niet gecontroleerd op beveiligingsproblemen, zijn nieuw of staan bekend als instabiel en worden volop ontwikkeld. Installatie kan leiden tot gegevensverlies of beveiligingsincidenten.",
- "by" : "door",
- "licensed" : "gelicenseerd",
+ "by %s" : "op %s",
+ "%s-licensed" : "%s-licensed",
"Documentation:" : "Documentatie:",
"User documentation" : "Gebruikersdocumentatie",
"Admin documentation" : "Beheerdocumentatie",
"Show description …" : "Toon beschrijving ...",
"Hide description …" : "Verberg beschrijving ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Deze app heeft geen minimum ownCloud versienummer toegewezen gekregen. Dit wordt een fout in ownCloud 11 en later.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Deze app heeft geen maximum ownCloud versienummer toegewezen gekregen. Dit wordt een fout in ownCloud 11 en later.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Deze app kan niet worden geïnstalleerd omdat de volgende afhankelijkheden niet zijn ingevuld:",
"Enable only for specific groups" : "Alleen voor bepaalde groepen activeren",
"Uninstall App" : "De-installeren app",
"Enable experimental apps" : "Inschakelen experimentele apps",
+ "SSL Root Certificates" : "SSL Root Certificaten",
+ "Common Name" : "Common Name",
+ "Valid until" : "Geldig tot",
+ "Issued By" : "Uitgegeven door",
+ "Valid until %s" : "Geldig tot %s",
+ "Import root certificate" : "Importeren root certificaat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hallo daar,<br><br>we willen u laten weten dat u nu een %s account hebt.<br><br>Uw gebruikersnaam: %s<br>Ga naar: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Proficiat!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hallo,\n\nwe willen u laten weten dat u nu een %s account hebt.\n\nUw gebruikersnaam: %s\nGa naar: %s\n\n",
@@ -223,41 +229,36 @@
"Forum" : "Forum",
"Issue tracker" : "Issue tracker",
"Commercial support" : "Commerciële ondersteuning",
- "Get the apps to sync your files" : "Download de apps om bestanden te synchroniseren",
- "Desktop client" : "Desktop client",
- "Android app" : "Android app",
- "iOS app" : "iOS app",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Als u het project wilt ondersteunen\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ontwikkel mee</a>\n\t\tof\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">verkondig het nieuws</a>!",
- "Show First Run Wizard again" : "Toon de Eerste start Wizard opnieuw",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "U heeft <strong>%s</strong> gebruikt van de beschikbare <strong>%s</strong>",
- "Password" : "Wachtwoord",
- "Unable to change your password" : "Niet in staat om uw wachtwoord te wijzigen",
- "Current password" : "Huidig wachtwoord",
- "New password" : "Nieuw",
- "Change password" : "Wijzig wachtwoord",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "U gebruikt <strong>%s</strong> van <strong>%s</strong>",
+ "Profile picture" : "Profielafbeelding",
+ "Upload new" : "Upload een nieuwe",
+ "Select from Files" : "Kies uit bestanden",
+ "Remove image" : "Afbeelding verwijderen",
+ "png or jpg, max. 20 MB" : "png of jpg, max. 20 MB",
+ "Picture provided by original account" : "Afbeelding is verstrekt door originele account.",
+ "Cancel" : "Annuleer",
+ "Choose as profile picture" : "Kies als profielafbeelding",
"Full name" : "Volledige naam",
"No display name set" : "Nog geen weergavenaam ingesteld",
"Email" : "E-mailadres",
"Your email address" : "Uw e-mailadres",
- "Fill in an email address to enable password recovery and receive notifications" : "Vul een e-mailadres in om wachtwoordherstel mogelijk te maken en meldingen te ontvangen",
+ "For password recovery and notifications" : "Voor wachtwoordherstel en meldingen",
"No email address set" : "Geen e-mailadres opgegeven",
"You are member of the following groups:" : "U bent lid van de volgende groepen:",
- "Profile picture" : "Profielafbeelding",
- "Upload new" : "Upload een nieuwe",
- "Select new from Files" : "Selecteer een nieuwe vanuit bestanden",
- "Remove image" : "Afbeelding verwijderen",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Of png, of jpg. Bij voorkeur vierkant, maar u kunt de afbeelding bijsnijden. Het bestand mag niet groter zijn dan 20 MB.",
- "Your avatar is provided by your original account." : "Uw avatar is verstrekt door uw originele account.",
- "Cancel" : "Annuleer",
- "Choose as profile image" : "Kies als profielafbeelding",
+ "Password" : "Wachtwoord",
+ "Unable to change your password" : "Niet in staat om uw wachtwoord te wijzigen",
+ "Current password" : "Huidig wachtwoord",
+ "New password" : "Nieuw",
+ "Change password" : "Wijzig wachtwoord",
"Language" : "Taal",
"Help translate" : "Help met vertalen",
- "Common Name" : "Common Name",
- "Valid until" : "Geldig tot",
- "Issued By" : "Uitgegeven door",
- "Valid until %s" : "Geldig tot %s",
- "Import root certificate" : "Importeren root certificaat",
- "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Ontwikkeld door de {communityopen}ownCloud gemeenschaplinkclose}, de {githubopen}source code{linkclose} is gelicenseerd onder de {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
+ "Get the apps to sync your files" : "Download de apps om bestanden te synchroniseren",
+ "Desktop client" : "Desktop client",
+ "Android app" : "Android app",
+ "iOS app" : "iOS app",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Als u het project wilt ondersteunen\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ontwikkel mee</a>\n\t\tof\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">verkondig het nieuws</a>!",
+ "Show First Run Wizard again" : "Toon de Eerste start Wizard opnieuw",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Ontwikkeld door de {communityopen}ownCloud gemeenschap{linkclose}, de {githubopen}source code{linkclose} is gelicenseerd onder de {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Toon opslaglocatie",
"Show last log in" : "Toon laatste inlog",
"Show user backend" : "Toon backend gebruiker",
diff --git a/settings/l10n/nn_NO.js b/settings/l10n/nn_NO.js
index fb3c45debb4..686b9a9ddf2 100644
--- a/settings/l10n/nn_NO.js
+++ b/settings/l10n/nn_NO.js
@@ -4,9 +4,9 @@ OC.L10N.register(
"Sharing" : "Deling",
"Cron" : "Cron",
"Log" : "Logg",
- "Authentication error" : "Autentiseringsfeil",
"Language changed" : "Språk endra",
"Invalid request" : "Ugyldig førespurnad",
+ "Authentication error" : "Autentiseringsfeil",
"Admins can't remove themself from the admin group" : "Administratorar kan ikkje fjerna seg sjølve frå admin-gruppa",
"Unable to add user to group %s" : "Klarte ikkje leggja til brukaren til gruppa %s",
"Unable to remove user from group %s" : "Klarte ikkje fjerna brukaren frå gruppa %s",
@@ -27,10 +27,10 @@ OC.L10N.register(
"Updating...." : "Oppdaterer …",
"Error while updating app" : "Feil ved oppdatering av app",
"Updated" : "Oppdatert",
+ "Delete" : "Slett",
"Select a profile picture" : "Vel eit profilbilete",
"Very weak password" : "Veldig svakt passord",
"Weak password" : "Svakt passord",
- "Delete" : "Slett",
"Groups" : "Grupper",
"undo" : "angra",
"never" : "aldri",
@@ -47,30 +47,25 @@ OC.L10N.register(
"Execute one task with each page loaded" : "Utfør éi oppgåve for kvar sidelasting",
"Encryption" : "Kryptering",
"Server address" : "Tenaradresse",
- "Log level" : "Log nivå",
"More" : "Meir",
"Less" : "Mindre",
"Version" : "Utgåve",
- "by" : "av",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Få app-ar som kan synkronisera filene dine",
- "Show First Run Wizard again" : "Vis Oppstartvegvisaren igjen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du har brukt <strong>%s</strong> av dine tilgjengelege <strong>%s</strong>",
+ "Profile picture" : "Profilbilete",
+ "Upload new" : "Last opp ny",
+ "Remove image" : "Fjern bilete",
+ "Cancel" : "Avbryt",
+ "Email" : "E-post",
+ "Your email address" : "Di epost-adresse",
"Password" : "Passord",
"Unable to change your password" : "Klarte ikkje endra passordet",
"Current password" : "Passord",
"New password" : "Nytt passord",
"Change password" : "Endra passord",
- "Email" : "E-post",
- "Your email address" : "Di epost-adresse",
- "Profile picture" : "Profilbilete",
- "Upload new" : "Last opp ny",
- "Select new from Files" : "Vel ny frå Filer",
- "Remove image" : "Fjern bilete",
- "Cancel" : "Avbryt",
- "Choose as profile image" : "Vel som profilbilete",
"Language" : "Språk",
"Help translate" : "Hjelp oss å omsetja",
+ "Get the apps to sync your files" : "Få app-ar som kan synkronisera filene dine",
+ "Show First Run Wizard again" : "Vis Oppstartvegvisaren igjen",
"Username" : "Brukarnamn",
"Create" : "Lag",
"Admin Recovery Password" : "Gjenopprettingspassord for administrator",
diff --git a/settings/l10n/nn_NO.json b/settings/l10n/nn_NO.json
index b1bcc62ea32..27f3c7e0d42 100644
--- a/settings/l10n/nn_NO.json
+++ b/settings/l10n/nn_NO.json
@@ -2,9 +2,9 @@
"Sharing" : "Deling",
"Cron" : "Cron",
"Log" : "Logg",
- "Authentication error" : "Autentiseringsfeil",
"Language changed" : "Språk endra",
"Invalid request" : "Ugyldig førespurnad",
+ "Authentication error" : "Autentiseringsfeil",
"Admins can't remove themself from the admin group" : "Administratorar kan ikkje fjerna seg sjølve frå admin-gruppa",
"Unable to add user to group %s" : "Klarte ikkje leggja til brukaren til gruppa %s",
"Unable to remove user from group %s" : "Klarte ikkje fjerna brukaren frå gruppa %s",
@@ -25,10 +25,10 @@
"Updating...." : "Oppdaterer …",
"Error while updating app" : "Feil ved oppdatering av app",
"Updated" : "Oppdatert",
+ "Delete" : "Slett",
"Select a profile picture" : "Vel eit profilbilete",
"Very weak password" : "Veldig svakt passord",
"Weak password" : "Svakt passord",
- "Delete" : "Slett",
"Groups" : "Grupper",
"undo" : "angra",
"never" : "aldri",
@@ -45,30 +45,25 @@
"Execute one task with each page loaded" : "Utfør éi oppgåve for kvar sidelasting",
"Encryption" : "Kryptering",
"Server address" : "Tenaradresse",
- "Log level" : "Log nivå",
"More" : "Meir",
"Less" : "Mindre",
"Version" : "Utgåve",
- "by" : "av",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Få app-ar som kan synkronisera filene dine",
- "Show First Run Wizard again" : "Vis Oppstartvegvisaren igjen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du har brukt <strong>%s</strong> av dine tilgjengelege <strong>%s</strong>",
+ "Profile picture" : "Profilbilete",
+ "Upload new" : "Last opp ny",
+ "Remove image" : "Fjern bilete",
+ "Cancel" : "Avbryt",
+ "Email" : "E-post",
+ "Your email address" : "Di epost-adresse",
"Password" : "Passord",
"Unable to change your password" : "Klarte ikkje endra passordet",
"Current password" : "Passord",
"New password" : "Nytt passord",
"Change password" : "Endra passord",
- "Email" : "E-post",
- "Your email address" : "Di epost-adresse",
- "Profile picture" : "Profilbilete",
- "Upload new" : "Last opp ny",
- "Select new from Files" : "Vel ny frå Filer",
- "Remove image" : "Fjern bilete",
- "Cancel" : "Avbryt",
- "Choose as profile image" : "Vel som profilbilete",
"Language" : "Språk",
"Help translate" : "Hjelp oss å omsetja",
+ "Get the apps to sync your files" : "Få app-ar som kan synkronisera filene dine",
+ "Show First Run Wizard again" : "Vis Oppstartvegvisaren igjen",
"Username" : "Brukarnamn",
"Create" : "Lag",
"Admin Recovery Password" : "Gjenopprettingspassord for administrator",
diff --git a/settings/l10n/oc.js b/settings/l10n/oc.js
index 70c66652e42..5d6e199352d 100644
--- a/settings/l10n/oc.js
+++ b/settings/l10n/oc.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Log",
"Tips & tricks" : "Estècs e astúcias",
"Updates" : "Mesas a jorn",
- "Authentication error" : "Error d'autentificacion",
- "Your full name has been changed." : "Vòstre nom complet es estat modificat.",
- "Unable to change full name" : "Impossible de cambiar lo nom complet",
"Couldn't remove app." : "Impossible de suprimir l'aplicacion.",
"Language changed" : "Lenga cambiada",
"Invalid request" : "Requèsta invalida",
+ "Authentication error" : "Error d'autentificacion",
"Admins can't remove themself from the admin group" : "Los administrators se pòdon pas levar eles-meteisses del grop admin",
"Unable to add user to group %s" : "Impossible d'apondre l'utilizaire al grop %s",
"Unable to remove user from group %s" : "Impossible de suprimir l'utilizaire del grop %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Utilizaire invalid",
"Unable to change mail address" : "Impossible de modificar l'adreça de corrièl",
"Email saved" : "Email salvat",
+ "Your full name has been changed." : "Vòstre nom complet es estat modificat.",
+ "Unable to change full name" : "Impossible de cambiar lo nom complet",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Sètz segur que volètz apondre \"{domain}\" coma domeni de fisança ?",
"Add trusted domain" : "Apondre un domeni de fisança",
"Migration in progress. Please wait until the migration is finished" : "Migracion en cors. Esperatz qu'aquela s'acabe",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "L'aplicacion es estada activada mas deu èsser mesa a jorn. Seretz redirigit cap a la pagina de las mesas a jorn dins 5 segondas.",
"App update" : "Mesa a jorn",
"No apps found for \"{query}\"" : "Cap d'aplicacion pas trobada per \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Una error s'es produsida. Provesissètz un certificat PEM encodat al format ASCII.",
+ "Valid until {date}" : "Valid fins al {date}",
+ "Delete" : "Suprimir",
"An error occurred: {message}" : "Una error s'es produsida : {message}",
"Select a profile picture" : "Seleccionar una fòto de perfil ",
"Very weak password" : "Senhal de fòrt febla seguretat",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Senhal de seguretat tot bèl juste acceptable",
"Good password" : "Senhal de seguretat sufisenta",
"Strong password" : "Senhal de fòrta seguretat",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Una error s'es produsida. Provesissètz un certificat PEM encodat al format ASCII.",
- "Valid until {date}" : "Valid fins al {date}",
- "Delete" : "Suprimir",
"Groups" : "Gropes",
"Unable to delete {objName}" : "Impossible de suprimir {objName}",
"Error creating group" : "Error al moment de la creacion del grop",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Un senhal valid deu èsser picat",
"A valid email must be provided" : "Vos cal provesir una adreça de corrièl valida",
"__language_name__" : "Occitan-lengadocian",
- "Sync clients" : "Clients de sincronizacion",
"Personal info" : "Informacions personalas",
- "SSL root certificates" : "Certificats raiç SSL",
+ "Sync clients" : "Clients de sincronizacion",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tot (errors fatalas, errors, avertiments, informacions, desbugatge)",
"Info, warnings, errors and fatal issues" : "Informacions, avertiments, errors e errors fatalas",
"Warnings, errors and fatal issues" : "Avertiments, errors e errors fatalas",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Vos recomandam d'installar sus vòstre sistèma los paquets requesits a la presa en carga d'un dels paramètres regionals seguents : %s",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se vòstra installacion es pas estada efectuada a la raiç del domeni e qu'utiliza lo cron del sistèma, i pòt aver de problèmas amb la generacion d'URL. Per los evitar, configuratz l'opcion \"overwrite.cli.url\" de vòstre fichièr config.php amb lo camin de la raiç de vòstra installacion (suggerit : \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Lo prètzfach cron a pas pogut s'executar via CLI. Aquelas errors tecnicas son aparegudas :",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Lo verrolhatge transaccional de fichièrs utiliza la banca de donadas. Per obténer de performànciasmelhor il est recommandé d'utiliser plutôt memcache. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Consultatz los <a target=\"_blank\" href=\"%s\">guidas d'installacion ↗</a>, e cercatz d'errors o avertiments dins <a href=\"#log-section\">los logs</a>.",
"All checks passed." : "Totes los tèsts an capitat.",
"Open documentation" : "Veire la documentacion",
@@ -188,7 +186,6 @@ OC.L10N.register(
"Store credentials" : "Enregistrar los identificants",
"Test email settings" : "Testar los paramètres e-mail",
"Send email" : "Mandar un mail",
- "Log level" : "Nivèl de log",
"Download logfile" : "Telecargar lo fichièr de jornalizacion",
"More" : "Mai",
"Less" : "Mens",
@@ -206,8 +203,6 @@ OC.L10N.register(
"Developer documentation" : "Documentacion pels desvolopaires",
"Experimental applications ahead" : "Atencion! Aplicacions experimentalas",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Las aplicacions experimentalas son pas estadas testadas pels problèmas de seguretat, son novèlas o conegudasper èsser instablas e son encara en desvolopament. Las installar pòt causar de pèrdas de donadas o de falhas de seguretat. ",
- "by" : "per",
- "licensed" : "Jos licéncia",
"Documentation:" : "Documentacion :",
"User documentation" : "Documentacion utilizaire",
"Admin documentation" : "Documentacion administrator",
@@ -217,6 +212,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Activar unicament per certans gropes",
"Uninstall App" : "Desinstallar l'aplicacion",
"Enable experimental apps" : "Activar las aplicacions experimentalas",
+ "Common Name" : "Nom d'usatge",
+ "Valid until" : "Valid fins a",
+ "Issued By" : "Desliurat per",
+ "Valid until %s" : "Valid fins a %s",
+ "Import root certificate" : "Importar un certificat raiç",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Bonjorn,<br><br>Un compte %s es estat creat per vos.<br><br>Vòstre nom d'utilizaire es : %s<br>Visitatz vòstre compte : <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "A lèu !",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Bonjorn,<br><br>Un compte %s es estat creat per vos.<br><br>Vòstre nom d'utilizaire es : %s<br>Visitatz vòstre compte : %s<br><br>\n",
@@ -225,40 +225,29 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Seguiment de problèmas",
"Commercial support" : "Supòrt comercial",
- "Get the apps to sync your files" : "Obtenètz las aplicacions de sincronizacion de vòstres fichièrs",
- "Desktop client" : "Client de burèu",
- "Android app" : "Aplicacion Android",
- "iOS app" : "Aplicacion iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se volètz aportar vòstre supòrt al projècte\n <a href=\"https://owncloud.org/contribute\"\n target=\"_blank\" rel=\"noreferrer\">rejonhètz lo desvolopament</a>\n o\n <a href=\"https://owncloud.org/promote\"\n target=\"_blank\" rel=\"noreferrer\">fasètz passar l'informacion</a> !",
- "Show First Run Wizard again" : "Reveire la fenèstra d'acuèlh afichada al moment de vòstra primièra connexion",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Utilizatz <strong>%s</strong> dels <strong>%s<strong> disponibles",
- "Password" : "Senhal",
- "Unable to change your password" : "Impossible de cambiar vòstre senhal",
- "Current password" : "Senhal actual",
- "New password" : "Senhal novèl",
- "Change password" : "Cambiar de senhal",
+ "Profile picture" : "Fòto de perfil",
+ "Upload new" : "Novèla dempuèi vòstre ordenador",
+ "Remove image" : "Suprimir l'imatge",
+ "Cancel" : "Anullar",
"Full name" : "Nom complet",
"No display name set" : "Cap de nom d'afichatge pas configurat",
"Email" : "Adreça mail",
"Your email address" : "Vòstra adreça mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Picatz vòstra adreça mail per permetre la reïnicializacion del senhal e la recepcion de las notificacions",
"No email address set" : "Cap d'adreça e-mail pas configurada",
"You are member of the following groups:" : "Sètz membre dels gropes seguents :",
- "Profile picture" : "Fòto de perfil",
- "Upload new" : "Novèla dempuèi vòstre ordenador",
- "Select new from Files" : "Novèla dempuèi los Fichièrs",
- "Remove image" : "Suprimir l'imatge",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Format png o jpg de maximum 20 Mo. Idealament carrada, mas la poiretz requadrar.",
- "Your avatar is provided by your original account." : "Vòstre avatar es provesit per vòstre compte original.",
- "Cancel" : "Anullar",
- "Choose as profile image" : "Causir en tant que fòto de perfil",
+ "Password" : "Senhal",
+ "Unable to change your password" : "Impossible de cambiar vòstre senhal",
+ "Current password" : "Senhal actual",
+ "New password" : "Senhal novèl",
+ "Change password" : "Cambiar de senhal",
"Language" : "Lenga",
"Help translate" : "Ajudatz a tradusir",
- "Common Name" : "Nom d'usatge",
- "Valid until" : "Valid fins a",
- "Issued By" : "Desliurat per",
- "Valid until %s" : "Valid fins a %s",
- "Import root certificate" : "Importar un certificat raiç",
+ "Get the apps to sync your files" : "Obtenètz las aplicacions de sincronizacion de vòstres fichièrs",
+ "Desktop client" : "Client de burèu",
+ "Android app" : "Aplicacion Android",
+ "iOS app" : "Aplicacion iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se volètz aportar vòstre supòrt al projècte\n <a href=\"https://owncloud.org/contribute\"\n target=\"_blank\" rel=\"noreferrer\">rejonhètz lo desvolopament</a>\n o\n <a href=\"https://owncloud.org/promote\"\n target=\"_blank\" rel=\"noreferrer\">fasètz passar l'informacion</a> !",
+ "Show First Run Wizard again" : "Reveire la fenèstra d'acuèlh afichada al moment de vòstra primièra connexion",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desvolopat per la {communityopen}comunautat ownCloud{linkclose}, lo {githubopen}code font{linkclose} es jos licéncia {licenseopen}<abbr lang=\"en\" title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Afichar l'emplaçament de l'emmagazinatge",
"Show last log in" : "Far veire la darrièra connexion",
diff --git a/settings/l10n/oc.json b/settings/l10n/oc.json
index a7e987f9787..e271f050188 100644
--- a/settings/l10n/oc.json
+++ b/settings/l10n/oc.json
@@ -10,12 +10,10 @@
"Log" : "Log",
"Tips & tricks" : "Estècs e astúcias",
"Updates" : "Mesas a jorn",
- "Authentication error" : "Error d'autentificacion",
- "Your full name has been changed." : "Vòstre nom complet es estat modificat.",
- "Unable to change full name" : "Impossible de cambiar lo nom complet",
"Couldn't remove app." : "Impossible de suprimir l'aplicacion.",
"Language changed" : "Lenga cambiada",
"Invalid request" : "Requèsta invalida",
+ "Authentication error" : "Error d'autentificacion",
"Admins can't remove themself from the admin group" : "Los administrators se pòdon pas levar eles-meteisses del grop admin",
"Unable to add user to group %s" : "Impossible d'apondre l'utilizaire al grop %s",
"Unable to remove user from group %s" : "Impossible de suprimir l'utilizaire del grop %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Utilizaire invalid",
"Unable to change mail address" : "Impossible de modificar l'adreça de corrièl",
"Email saved" : "Email salvat",
+ "Your full name has been changed." : "Vòstre nom complet es estat modificat.",
+ "Unable to change full name" : "Impossible de cambiar lo nom complet",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Sètz segur que volètz apondre \"{domain}\" coma domeni de fisança ?",
"Add trusted domain" : "Apondre un domeni de fisança",
"Migration in progress. Please wait until the migration is finished" : "Migracion en cors. Esperatz qu'aquela s'acabe",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "L'aplicacion es estada activada mas deu èsser mesa a jorn. Seretz redirigit cap a la pagina de las mesas a jorn dins 5 segondas.",
"App update" : "Mesa a jorn",
"No apps found for \"{query}\"" : "Cap d'aplicacion pas trobada per \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Una error s'es produsida. Provesissètz un certificat PEM encodat al format ASCII.",
+ "Valid until {date}" : "Valid fins al {date}",
+ "Delete" : "Suprimir",
"An error occurred: {message}" : "Una error s'es produsida : {message}",
"Select a profile picture" : "Seleccionar una fòto de perfil ",
"Very weak password" : "Senhal de fòrt febla seguretat",
@@ -86,9 +89,6 @@
"So-so password" : "Senhal de seguretat tot bèl juste acceptable",
"Good password" : "Senhal de seguretat sufisenta",
"Strong password" : "Senhal de fòrta seguretat",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Una error s'es produsida. Provesissètz un certificat PEM encodat al format ASCII.",
- "Valid until {date}" : "Valid fins al {date}",
- "Delete" : "Suprimir",
"Groups" : "Gropes",
"Unable to delete {objName}" : "Impossible de suprimir {objName}",
"Error creating group" : "Error al moment de la creacion del grop",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Un senhal valid deu èsser picat",
"A valid email must be provided" : "Vos cal provesir una adreça de corrièl valida",
"__language_name__" : "Occitan-lengadocian",
- "Sync clients" : "Clients de sincronizacion",
"Personal info" : "Informacions personalas",
- "SSL root certificates" : "Certificats raiç SSL",
+ "Sync clients" : "Clients de sincronizacion",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tot (errors fatalas, errors, avertiments, informacions, desbugatge)",
"Info, warnings, errors and fatal issues" : "Informacions, avertiments, errors e errors fatalas",
"Warnings, errors and fatal issues" : "Avertiments, errors e errors fatalas",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Vos recomandam d'installar sus vòstre sistèma los paquets requesits a la presa en carga d'un dels paramètres regionals seguents : %s",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se vòstra installacion es pas estada efectuada a la raiç del domeni e qu'utiliza lo cron del sistèma, i pòt aver de problèmas amb la generacion d'URL. Per los evitar, configuratz l'opcion \"overwrite.cli.url\" de vòstre fichièr config.php amb lo camin de la raiç de vòstra installacion (suggerit : \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Lo prètzfach cron a pas pogut s'executar via CLI. Aquelas errors tecnicas son aparegudas :",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Lo verrolhatge transaccional de fichièrs utiliza la banca de donadas. Per obténer de performànciasmelhor il est recommandé d'utiliser plutôt memcache. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Consultatz los <a target=\"_blank\" href=\"%s\">guidas d'installacion ↗</a>, e cercatz d'errors o avertiments dins <a href=\"#log-section\">los logs</a>.",
"All checks passed." : "Totes los tèsts an capitat.",
"Open documentation" : "Veire la documentacion",
@@ -186,7 +184,6 @@
"Store credentials" : "Enregistrar los identificants",
"Test email settings" : "Testar los paramètres e-mail",
"Send email" : "Mandar un mail",
- "Log level" : "Nivèl de log",
"Download logfile" : "Telecargar lo fichièr de jornalizacion",
"More" : "Mai",
"Less" : "Mens",
@@ -204,8 +201,6 @@
"Developer documentation" : "Documentacion pels desvolopaires",
"Experimental applications ahead" : "Atencion! Aplicacions experimentalas",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Las aplicacions experimentalas son pas estadas testadas pels problèmas de seguretat, son novèlas o conegudasper èsser instablas e son encara en desvolopament. Las installar pòt causar de pèrdas de donadas o de falhas de seguretat. ",
- "by" : "per",
- "licensed" : "Jos licéncia",
"Documentation:" : "Documentacion :",
"User documentation" : "Documentacion utilizaire",
"Admin documentation" : "Documentacion administrator",
@@ -215,6 +210,11 @@
"Enable only for specific groups" : "Activar unicament per certans gropes",
"Uninstall App" : "Desinstallar l'aplicacion",
"Enable experimental apps" : "Activar las aplicacions experimentalas",
+ "Common Name" : "Nom d'usatge",
+ "Valid until" : "Valid fins a",
+ "Issued By" : "Desliurat per",
+ "Valid until %s" : "Valid fins a %s",
+ "Import root certificate" : "Importar un certificat raiç",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Bonjorn,<br><br>Un compte %s es estat creat per vos.<br><br>Vòstre nom d'utilizaire es : %s<br>Visitatz vòstre compte : <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "A lèu !",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Bonjorn,<br><br>Un compte %s es estat creat per vos.<br><br>Vòstre nom d'utilizaire es : %s<br>Visitatz vòstre compte : %s<br><br>\n",
@@ -223,40 +223,29 @@
"Forum" : "Forum",
"Issue tracker" : "Seguiment de problèmas",
"Commercial support" : "Supòrt comercial",
- "Get the apps to sync your files" : "Obtenètz las aplicacions de sincronizacion de vòstres fichièrs",
- "Desktop client" : "Client de burèu",
- "Android app" : "Aplicacion Android",
- "iOS app" : "Aplicacion iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se volètz aportar vòstre supòrt al projècte\n <a href=\"https://owncloud.org/contribute\"\n target=\"_blank\" rel=\"noreferrer\">rejonhètz lo desvolopament</a>\n o\n <a href=\"https://owncloud.org/promote\"\n target=\"_blank\" rel=\"noreferrer\">fasètz passar l'informacion</a> !",
- "Show First Run Wizard again" : "Reveire la fenèstra d'acuèlh afichada al moment de vòstra primièra connexion",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Utilizatz <strong>%s</strong> dels <strong>%s<strong> disponibles",
- "Password" : "Senhal",
- "Unable to change your password" : "Impossible de cambiar vòstre senhal",
- "Current password" : "Senhal actual",
- "New password" : "Senhal novèl",
- "Change password" : "Cambiar de senhal",
+ "Profile picture" : "Fòto de perfil",
+ "Upload new" : "Novèla dempuèi vòstre ordenador",
+ "Remove image" : "Suprimir l'imatge",
+ "Cancel" : "Anullar",
"Full name" : "Nom complet",
"No display name set" : "Cap de nom d'afichatge pas configurat",
"Email" : "Adreça mail",
"Your email address" : "Vòstra adreça mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Picatz vòstra adreça mail per permetre la reïnicializacion del senhal e la recepcion de las notificacions",
"No email address set" : "Cap d'adreça e-mail pas configurada",
"You are member of the following groups:" : "Sètz membre dels gropes seguents :",
- "Profile picture" : "Fòto de perfil",
- "Upload new" : "Novèla dempuèi vòstre ordenador",
- "Select new from Files" : "Novèla dempuèi los Fichièrs",
- "Remove image" : "Suprimir l'imatge",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Format png o jpg de maximum 20 Mo. Idealament carrada, mas la poiretz requadrar.",
- "Your avatar is provided by your original account." : "Vòstre avatar es provesit per vòstre compte original.",
- "Cancel" : "Anullar",
- "Choose as profile image" : "Causir en tant que fòto de perfil",
+ "Password" : "Senhal",
+ "Unable to change your password" : "Impossible de cambiar vòstre senhal",
+ "Current password" : "Senhal actual",
+ "New password" : "Senhal novèl",
+ "Change password" : "Cambiar de senhal",
"Language" : "Lenga",
"Help translate" : "Ajudatz a tradusir",
- "Common Name" : "Nom d'usatge",
- "Valid until" : "Valid fins a",
- "Issued By" : "Desliurat per",
- "Valid until %s" : "Valid fins a %s",
- "Import root certificate" : "Importar un certificat raiç",
+ "Get the apps to sync your files" : "Obtenètz las aplicacions de sincronizacion de vòstres fichièrs",
+ "Desktop client" : "Client de burèu",
+ "Android app" : "Aplicacion Android",
+ "iOS app" : "Aplicacion iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se volètz aportar vòstre supòrt al projècte\n <a href=\"https://owncloud.org/contribute\"\n target=\"_blank\" rel=\"noreferrer\">rejonhètz lo desvolopament</a>\n o\n <a href=\"https://owncloud.org/promote\"\n target=\"_blank\" rel=\"noreferrer\">fasètz passar l'informacion</a> !",
+ "Show First Run Wizard again" : "Reveire la fenèstra d'acuèlh afichada al moment de vòstra primièra connexion",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desvolopat per la {communityopen}comunautat ownCloud{linkclose}, lo {githubopen}code font{linkclose} es jos licéncia {licenseopen}<abbr lang=\"en\" title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Afichar l'emplaçament de l'emmagazinatge",
"Show last log in" : "Far veire la darrièra connexion",
diff --git a/settings/l10n/pa.js b/settings/l10n/pa.js
index 8e7335dbf7d..15cdb279dda 100644
--- a/settings/l10n/pa.js
+++ b/settings/l10n/pa.js
@@ -14,9 +14,9 @@ OC.L10N.register(
"__language_name__" : "__ਭਾਸ਼ਾ_ਨਾਂ__",
"Login" : "ਲਾਗਇਨ",
"Server address" : "ਸਰਵਰ ਐਡਰੈਸ",
+ "Cancel" : "ਰੱਦ ਕਰੋ",
"Password" : "ਪਾਸਵਰ",
"Change password" : "ਪਾਸਵਰਡ ਬਦਲੋ",
- "Cancel" : "ਰੱਦ ਕਰੋ",
"Username" : "ਯੂਜ਼ਰ-ਨਾਂ"
},
"nplurals=2; plural=(n != 1);");
diff --git a/settings/l10n/pa.json b/settings/l10n/pa.json
index 3d59dc75ffb..b400a8510de 100644
--- a/settings/l10n/pa.json
+++ b/settings/l10n/pa.json
@@ -12,9 +12,9 @@
"__language_name__" : "__ਭਾਸ਼ਾ_ਨਾਂ__",
"Login" : "ਲਾਗਇਨ",
"Server address" : "ਸਰਵਰ ਐਡਰੈਸ",
+ "Cancel" : "ਰੱਦ ਕਰੋ",
"Password" : "ਪਾਸਵਰ",
"Change password" : "ਪਾਸਵਰਡ ਬਦਲੋ",
- "Cancel" : "ਰੱਦ ਕਰੋ",
"Username" : "ਯੂਜ਼ਰ-ਨਾਂ"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/settings/l10n/pl.js b/settings/l10n/pl.js
index 86108df8f01..31e4c29ce5e 100644
--- a/settings/l10n/pl.js
+++ b/settings/l10n/pl.js
@@ -7,12 +7,10 @@ OC.L10N.register(
"Cron" : "Cron",
"Log" : "Logi",
"Updates" : "Aktualizacje",
- "Authentication error" : "Błąd uwierzytelniania",
- "Your full name has been changed." : "Twoja pełna nazwa została zmieniona.",
- "Unable to change full name" : "Nie można zmienić pełnej nazwy",
"Couldn't remove app." : "Nie można usunąć aplikacji.",
"Language changed" : "Zmieniono język",
"Invalid request" : "Nieprawidłowe żądanie",
+ "Authentication error" : "Błąd uwierzytelniania",
"Admins can't remove themself from the admin group" : "Administratorzy nie mogą usunąć siebie samych z grupy administratorów",
"Unable to add user to group %s" : "Nie można dodać użytkownika do grupy %s",
"Unable to remove user from group %s" : "Nie można usunąć użytkownika z grupy %s",
@@ -40,6 +38,8 @@ OC.L10N.register(
"Invalid user" : "Nieprawidłowy użytkownik",
"Unable to change mail address" : "Nie można zmienić adresu email",
"Email saved" : "E-mail zapisany",
+ "Your full name has been changed." : "Twoja pełna nazwa została zmieniona.",
+ "Unable to change full name" : "Nie można zmienić pełnej nazwy",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Czy jesteś pewien/pewna że chcesz dodać \"{domain}\" jako zaufaną domenę?",
"Add trusted domain" : "Dodaj zaufaną domenę",
"Sending..." : "Wysyłam...",
@@ -57,14 +57,14 @@ OC.L10N.register(
"Uninstalling ...." : "Odinstalowywanie....",
"Error while uninstalling app" : "Błąd przy odinstalowywaniu aplikacji",
"Uninstall" : "Odinstaluj",
+ "Valid until {date}" : "Ważny do {date}",
+ "Delete" : "Usuń",
"Select a profile picture" : "Wybierz zdjęcie profilu",
"Very weak password" : "Bardzo słabe hasło",
"Weak password" : "Słabe hasło",
"So-so password" : "Mało skomplikowane hasło",
"Good password" : "Dobre hasło",
"Strong password" : "Mocne hasło",
- "Valid until {date}" : "Ważny do {date}",
- "Delete" : "Usuń",
"Groups" : "Grupy",
"Unable to delete {objName}" : "Nie można usunąć {objName}",
"Error creating group" : "Błąd podczas tworzenia grupy",
@@ -81,7 +81,6 @@ OC.L10N.register(
"A valid password must be provided" : "Należy podać prawidłowe hasło",
"A valid email must be provided" : "Podaj poprawny adres email",
"__language_name__" : "polski",
- "SSL root certificates" : "Główny certyfikat SSL",
"Everything (fatal issues, errors, warnings, info, debug)" : "Wszystko (Informacje, ostrzeżenia, błędy i poważne problemy, debug)",
"Info, warnings, errors and fatal issues" : "Informacje, ostrzeżenia, błędy i poważne problemy",
"Warnings, errors and fatal issues" : "Ostrzeżenia, błędy i poważne problemy",
@@ -134,15 +133,12 @@ OC.L10N.register(
"Store credentials" : "Zapisz poświadczenia",
"Test email settings" : "Ustawienia testowej wiadomości",
"Send email" : "Wyślij email",
- "Log level" : "Poziom logów",
"Download logfile" : "Pobierz plik log",
"More" : "Więcej",
"Less" : "Mniej",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Plik log jest większy niż 100MB. Ściąganie może trochę potrwać!",
"Version" : "Wersja",
"Developer documentation" : "Dokumentacja dewelopera",
- "by" : "przez",
- "licensed" : "Licencja",
"Documentation:" : "Dokumentacja:",
"User documentation" : "Dokumentacja użytkownika",
"Show description …" : "Pokaż opis ...",
@@ -151,6 +147,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Włącz tylko dla określonych grup",
"Uninstall App" : "Odinstaluj aplikację",
"Enable experimental apps" : "Włącz eksperymentalne aplikacje",
+ "Common Name" : "Nazwa CN",
+ "Valid until" : "Ważny do",
+ "Issued By" : "Wydany przez",
+ "Valid until %s" : "Ważny do %s",
+ "Import root certificate" : "Importuj główny certyfikat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Witaj,<br><br>informujemy, że teraz masz konto na %s .<br><br>Twoja nazwa użytkownika: %s<br>Dostęp pod adresem: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Pozdrawiam!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Witaj,\n\ninformujemy, że teraz masz konto na %s .\n\nTwoja nazwa użytkownika:: %s\nDostęp pod adresem: %s\n\n",
@@ -158,37 +159,27 @@ OC.L10N.register(
"Online documentation" : "Dokumentacja Online",
"Forum" : "Forum",
"Commercial support" : "Wsparcie komercyjne",
- "Get the apps to sync your files" : "Pobierz aplikacje żeby synchronizować swoje pliki",
- "Desktop client" : "Klient na komputer",
- "Android app" : "Aplikacja Android",
- "iOS app" : "Aplikacja iOS",
- "Show First Run Wizard again" : "Uruchom ponownie kreatora pierwszego uruchomienia",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Wykorzystujesz <strong>%s</strong> z dostępnych <strong>%s</strong>",
- "Password" : "Hasło",
- "Unable to change your password" : "Nie można zmienić hasła",
- "Current password" : "Bieżące hasło",
- "New password" : "Nowe hasło",
- "Change password" : "Zmień hasło",
+ "Profile picture" : "Zdjęcie profilu",
+ "Upload new" : "Wczytaj nowe",
+ "Remove image" : "Usuń zdjęcie",
+ "Cancel" : "Anuluj",
"Full name" : "Pełna nazwa",
"No display name set" : "Brak nazwa wyświetlanej",
"Email" : "Email",
"Your email address" : "Twój adres e-mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Wypełnij adres email aby włączyć odzyskiwanie hasła oraz otrzymywać powiadomienia",
"No email address set" : "Brak adresu email",
- "Profile picture" : "Zdjęcie profilu",
- "Upload new" : "Wczytaj nowe",
- "Select new from Files" : "Wybierz nowe z plików",
- "Remove image" : "Usuń zdjęcie",
- "Your avatar is provided by your original account." : "Twój awatar jest ustawiony jako domyślny.",
- "Cancel" : "Anuluj",
- "Choose as profile image" : "Wybierz zdjęcie profilu",
+ "Password" : "Hasło",
+ "Unable to change your password" : "Nie można zmienić hasła",
+ "Current password" : "Bieżące hasło",
+ "New password" : "Nowe hasło",
+ "Change password" : "Zmień hasło",
"Language" : "Język",
"Help translate" : "Pomóż w tłumaczeniu",
- "Common Name" : "Nazwa CN",
- "Valid until" : "Ważny do",
- "Issued By" : "Wydany przez",
- "Valid until %s" : "Ważny do %s",
- "Import root certificate" : "Importuj główny certyfikat",
+ "Get the apps to sync your files" : "Pobierz aplikacje żeby synchronizować swoje pliki",
+ "Desktop client" : "Klient na komputer",
+ "Android app" : "Aplikacja Android",
+ "iOS app" : "Aplikacja iOS",
+ "Show First Run Wizard again" : "Uruchom ponownie kreatora pierwszego uruchomienia",
"Show storage location" : "Pokaż miejsce przechowywania",
"Show last log in" : "Pokaż ostatni login",
"Send email to new user" : "Wyślij email do nowego użytkownika",
diff --git a/settings/l10n/pl.json b/settings/l10n/pl.json
index f84a6214abc..b838a678202 100644
--- a/settings/l10n/pl.json
+++ b/settings/l10n/pl.json
@@ -5,12 +5,10 @@
"Cron" : "Cron",
"Log" : "Logi",
"Updates" : "Aktualizacje",
- "Authentication error" : "Błąd uwierzytelniania",
- "Your full name has been changed." : "Twoja pełna nazwa została zmieniona.",
- "Unable to change full name" : "Nie można zmienić pełnej nazwy",
"Couldn't remove app." : "Nie można usunąć aplikacji.",
"Language changed" : "Zmieniono język",
"Invalid request" : "Nieprawidłowe żądanie",
+ "Authentication error" : "Błąd uwierzytelniania",
"Admins can't remove themself from the admin group" : "Administratorzy nie mogą usunąć siebie samych z grupy administratorów",
"Unable to add user to group %s" : "Nie można dodać użytkownika do grupy %s",
"Unable to remove user from group %s" : "Nie można usunąć użytkownika z grupy %s",
@@ -38,6 +36,8 @@
"Invalid user" : "Nieprawidłowy użytkownik",
"Unable to change mail address" : "Nie można zmienić adresu email",
"Email saved" : "E-mail zapisany",
+ "Your full name has been changed." : "Twoja pełna nazwa została zmieniona.",
+ "Unable to change full name" : "Nie można zmienić pełnej nazwy",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Czy jesteś pewien/pewna że chcesz dodać \"{domain}\" jako zaufaną domenę?",
"Add trusted domain" : "Dodaj zaufaną domenę",
"Sending..." : "Wysyłam...",
@@ -55,14 +55,14 @@
"Uninstalling ...." : "Odinstalowywanie....",
"Error while uninstalling app" : "Błąd przy odinstalowywaniu aplikacji",
"Uninstall" : "Odinstaluj",
+ "Valid until {date}" : "Ważny do {date}",
+ "Delete" : "Usuń",
"Select a profile picture" : "Wybierz zdjęcie profilu",
"Very weak password" : "Bardzo słabe hasło",
"Weak password" : "Słabe hasło",
"So-so password" : "Mało skomplikowane hasło",
"Good password" : "Dobre hasło",
"Strong password" : "Mocne hasło",
- "Valid until {date}" : "Ważny do {date}",
- "Delete" : "Usuń",
"Groups" : "Grupy",
"Unable to delete {objName}" : "Nie można usunąć {objName}",
"Error creating group" : "Błąd podczas tworzenia grupy",
@@ -79,7 +79,6 @@
"A valid password must be provided" : "Należy podać prawidłowe hasło",
"A valid email must be provided" : "Podaj poprawny adres email",
"__language_name__" : "polski",
- "SSL root certificates" : "Główny certyfikat SSL",
"Everything (fatal issues, errors, warnings, info, debug)" : "Wszystko (Informacje, ostrzeżenia, błędy i poważne problemy, debug)",
"Info, warnings, errors and fatal issues" : "Informacje, ostrzeżenia, błędy i poważne problemy",
"Warnings, errors and fatal issues" : "Ostrzeżenia, błędy i poważne problemy",
@@ -132,15 +131,12 @@
"Store credentials" : "Zapisz poświadczenia",
"Test email settings" : "Ustawienia testowej wiadomości",
"Send email" : "Wyślij email",
- "Log level" : "Poziom logów",
"Download logfile" : "Pobierz plik log",
"More" : "Więcej",
"Less" : "Mniej",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Plik log jest większy niż 100MB. Ściąganie może trochę potrwać!",
"Version" : "Wersja",
"Developer documentation" : "Dokumentacja dewelopera",
- "by" : "przez",
- "licensed" : "Licencja",
"Documentation:" : "Dokumentacja:",
"User documentation" : "Dokumentacja użytkownika",
"Show description …" : "Pokaż opis ...",
@@ -149,6 +145,11 @@
"Enable only for specific groups" : "Włącz tylko dla określonych grup",
"Uninstall App" : "Odinstaluj aplikację",
"Enable experimental apps" : "Włącz eksperymentalne aplikacje",
+ "Common Name" : "Nazwa CN",
+ "Valid until" : "Ważny do",
+ "Issued By" : "Wydany przez",
+ "Valid until %s" : "Ważny do %s",
+ "Import root certificate" : "Importuj główny certyfikat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Witaj,<br><br>informujemy, że teraz masz konto na %s .<br><br>Twoja nazwa użytkownika: %s<br>Dostęp pod adresem: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Pozdrawiam!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Witaj,\n\ninformujemy, że teraz masz konto na %s .\n\nTwoja nazwa użytkownika:: %s\nDostęp pod adresem: %s\n\n",
@@ -156,37 +157,27 @@
"Online documentation" : "Dokumentacja Online",
"Forum" : "Forum",
"Commercial support" : "Wsparcie komercyjne",
- "Get the apps to sync your files" : "Pobierz aplikacje żeby synchronizować swoje pliki",
- "Desktop client" : "Klient na komputer",
- "Android app" : "Aplikacja Android",
- "iOS app" : "Aplikacja iOS",
- "Show First Run Wizard again" : "Uruchom ponownie kreatora pierwszego uruchomienia",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Wykorzystujesz <strong>%s</strong> z dostępnych <strong>%s</strong>",
- "Password" : "Hasło",
- "Unable to change your password" : "Nie można zmienić hasła",
- "Current password" : "Bieżące hasło",
- "New password" : "Nowe hasło",
- "Change password" : "Zmień hasło",
+ "Profile picture" : "Zdjęcie profilu",
+ "Upload new" : "Wczytaj nowe",
+ "Remove image" : "Usuń zdjęcie",
+ "Cancel" : "Anuluj",
"Full name" : "Pełna nazwa",
"No display name set" : "Brak nazwa wyświetlanej",
"Email" : "Email",
"Your email address" : "Twój adres e-mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Wypełnij adres email aby włączyć odzyskiwanie hasła oraz otrzymywać powiadomienia",
"No email address set" : "Brak adresu email",
- "Profile picture" : "Zdjęcie profilu",
- "Upload new" : "Wczytaj nowe",
- "Select new from Files" : "Wybierz nowe z plików",
- "Remove image" : "Usuń zdjęcie",
- "Your avatar is provided by your original account." : "Twój awatar jest ustawiony jako domyślny.",
- "Cancel" : "Anuluj",
- "Choose as profile image" : "Wybierz zdjęcie profilu",
+ "Password" : "Hasło",
+ "Unable to change your password" : "Nie można zmienić hasła",
+ "Current password" : "Bieżące hasło",
+ "New password" : "Nowe hasło",
+ "Change password" : "Zmień hasło",
"Language" : "Język",
"Help translate" : "Pomóż w tłumaczeniu",
- "Common Name" : "Nazwa CN",
- "Valid until" : "Ważny do",
- "Issued By" : "Wydany przez",
- "Valid until %s" : "Ważny do %s",
- "Import root certificate" : "Importuj główny certyfikat",
+ "Get the apps to sync your files" : "Pobierz aplikacje żeby synchronizować swoje pliki",
+ "Desktop client" : "Klient na komputer",
+ "Android app" : "Aplikacja Android",
+ "iOS app" : "Aplikacja iOS",
+ "Show First Run Wizard again" : "Uruchom ponownie kreatora pierwszego uruchomienia",
"Show storage location" : "Pokaż miejsce przechowywania",
"Show last log in" : "Pokaż ostatni login",
"Send email to new user" : "Wyślij email do nowego użytkownika",
diff --git a/settings/l10n/pt_BR.js b/settings/l10n/pt_BR.js
index 9caeb6169ad..144c4a812f2 100644
--- a/settings/l10n/pt_BR.js
+++ b/settings/l10n/pt_BR.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Registro",
"Tips & tricks" : "Dicas & Truques",
"Updates" : "Atualizações",
- "Authentication error" : "Erro de autenticação",
- "Your full name has been changed." : "Seu nome completo foi alterado.",
- "Unable to change full name" : "Não é possível alterar o nome completo",
"Couldn't remove app." : "Não foi possível remover aplicativos.",
"Language changed" : "Idioma alterado",
"Invalid request" : "Pedido inválido",
+ "Authentication error" : "Erro de autenticação",
"Admins can't remove themself from the admin group" : "Administradores não pode remover a si mesmos do grupo de administração",
"Unable to add user to group %s" : "Não foi possível adicionar usuário ao grupo %s",
"Unable to remove user from group %s" : "Não foi possível remover usuário do grupo %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Usuário inválido",
"Unable to change mail address" : "Não é possível trocar o endereço de email",
"Email saved" : "E-mail salvo",
+ "Your full name has been changed." : "Seu nome completo foi alterado.",
+ "Unable to change full name" : "Não é possível alterar o nome completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Você tem certeza que você quer adicionar \"{domain}\" como domínio confiável?",
"Add trusted domain" : "Adicionar domínio confiável",
"Migration in progress. Please wait until the migration is finished" : "Migração em progresso. Por favor aguarde até que a migração seja finalizada",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "O aplicativo foi habilitado, mas precisa ser atualizado. Você será redirecionado para a página de atualização em 5 segundos.",
"App update" : "Atualização de aplicativo",
"No apps found for \"{query}\"" : "Nenhum aplicativo encontrado para \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ocorreu um erro. Por favor envie um certificado ASCII-encoded PEM",
+ "Valid until {date}" : "Vádido até {date}",
+ "Delete" : "Excluir",
"An error occurred: {message}" : "Ocorreu um erro: {message}",
"Select a profile picture" : "Selecione uma imagem para o perfil",
"Very weak password" : "Senha muito fraca",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Senha mais ou menos",
"Good password" : "Boa senha",
"Strong password" : "Senha forte",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ocorreu um erro. Por favor envie um certificado ASCII-encoded PEM",
- "Valid until {date}" : "Vádido até {date}",
- "Delete" : "Excluir",
"Groups" : "Grupos",
"Unable to delete {objName}" : "Não é possível excluir {objName}",
"Error creating group" : "Erro ao criar grupo",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Forneça uma senha válida",
"A valid email must be provided" : "Deve ser informado um e-mail válido",
"__language_name__" : "__language_name__",
- "Sync clients" : "Clientes de Sincronização",
"Personal info" : "Informação pessoal",
- "SSL root certificates" : "Certificados SSL raíz",
+ "Sync clients" : "Clientes de Sincronização",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tudo (questões fatais, erros, avisos, informações, depuração)",
"Info, warnings, errors and fatal issues" : "Informações, avisos, erros e problemas fatais",
"Warnings, errors and fatal issues" : "Avisos, erros e problemas fatais",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Nós sugerimos a instalação dos pacotes necessários em seu sistema para suportar um dos seguintes locais: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se a sua instalação não estiver instalada na raiz do domínio e usa cron do sistema, pode haver problemas com a geração de URL. Para evitar esses problemas, por favor, defina a opção \"overwrite.cli.url\" em seu arquivo config.php para o caminho webroot de sua instalação (Sugestão: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Não foi possível executar o cron via CLI. Os seguintes erros técnicos têm aparecido:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Bloqueio de arquivos transacional está usando o banco de dados como bloqueio de back-end, para o melhor o desempenho é aconselhável configurar um cache de memória para bloqueio. Veja a <a target=\"_blank\" href=\"%s\">documentação ↗</a> para mais informação.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Por favor, verifique os <a target=\"_blank\" href=\"%s\">guias de instalação ↗</a>, e verificar se há erros ou avisos no <a href=\"#log-section\">log</a>.",
"All checks passed." : "Todas as verificações passaram.",
"Open documentation" : "Abrir documentação",
@@ -188,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Armazenar credenciais",
"Test email settings" : "Configurações de e-mail de teste",
"Send email" : "Enviar email",
- "Log level" : "Nível de registro",
"Download logfile" : "Baixar o arquivo de log",
"More" : "Mais",
"Less" : "Menos",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "O arquivo de log é maior que 100 MB. Baixar esse arquivo requer algum tempo!",
+ "What to log" : "O que colocar no log",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite é usada como base de dados. Para instalações maiores recomendamos mudar para um backend de banco de dados diferente.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Especialmente quando se utiliza o cliente de desktop para sincronização de arquivos o uso de SQLite é desencorajado.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Para migrar para outro banco de dados usar a ferramenta de linha de comando: 'db occ: converter-type', verifique a <a target=\"_blank\" href=\"%s\">documentação ↗</a>.",
@@ -206,59 +204,62 @@ OC.L10N.register(
"Developer documentation" : "Documentação do desenvolvedor",
"Experimental applications ahead" : "Aplicações experimentais à frente",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Aplicativos experimentais não são marcados por questões de segurança, por serem novos ou conhecidos como instáveis e sob forte desenvolvimento. Instalá-los pode causar perda de dados ou falhas de segurança.",
- "by" : "por",
- "licensed" : "licenciado",
+ "by %s" : "por %s",
+ "%s-licensed" : "%s-licenciado",
"Documentation:" : "Documentação:",
"User documentation" : "Documentação do usuário",
"Admin documentation" : "Documentação para Administração",
"Show description …" : "Mostrar descrição ...",
"Hide description …" : "Esconder descrição ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Este aplicativo não tem atribuída nenhuma versão ownCloud mínima. Isto será um erro no ownCloud 11 e posterior.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Este aplicativo não tem atribuída nenhuma versão ownCloud máxima. Isto será um erro no ownCloud 11 e posterior.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Este aplicativo não pode ser instalado porque as seguintes dependências não forão cumpridas:",
"Enable only for specific groups" : "Ativar apenas para grupos específicos",
"Uninstall App" : "Desinstalar Aplicativo",
"Enable experimental apps" : "Habilitar aplicativos experimentais",
+ "SSL Root Certificates" : "Certificados Raiz SSL",
+ "Common Name" : "Nome",
+ "Valid until" : "Válido até",
+ "Issued By" : "Emitido Por",
+ "Valid until %s" : "Válido até %s",
+ "Import root certificate" : "Importar certificado raiz",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Olá,<br><br>somente para lembrar que agora você tem uma conta %s.<br><br>Seu nome de usuário é: %s<br>Acesse em: <a href=\"%s\">%s</a><br><br>",
- "Cheers!" : "Saúde!",
+ "Cheers!" : "Saudações!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Olá,\n\nsomente para lembrar que agora você tem uma conta %s.\n\nSeu nome de usuário é: %s\nAcesse em: %s\n\n",
"Administrator documentation" : "Documentação do administrador",
"Online documentation" : "Documentação online",
"Forum" : "Fórum",
"Issue tracker" : "Rastreador de tópicos",
"Commercial support" : "Suporte comercial",
- "Get the apps to sync your files" : "Faça com que os apps sincronizem seus arquivos",
- "Desktop client" : "Cliente Desktop",
- "Android app" : "App Android",
- "iOS app" : "App iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se você quiser dar suporte ao projeto\n⇥⇥<a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\">juntese ao desenvolvimento</a>\n⇥⇥ou\n⇥⇥<a href=\"https://owncloud.org/promote\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\">espalhe para o mundo</a>!",
- "Show First Run Wizard again" : "Mostrar Assistente de Primeira Execução novamente",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Você usou <strong>%s</strong> do seu espaço de <strong>%s</strong>",
- "Password" : "Senha",
- "Unable to change your password" : "Não é possivel alterar a sua senha",
- "Current password" : "Senha atual",
- "New password" : "Nova senha",
- "Change password" : "Alterar senha",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Você está usando <strong>%s</strong> de <strong>%s</strong>",
+ "Profile picture" : "Imagem para o perfil",
+ "Upload new" : "Enviar nova foto",
+ "Select from Files" : "Selecionar de Arquivos",
+ "Remove image" : "Remover imagem",
+ "png or jpg, max. 20 MB" : "png ou jpg, max. 20 MB",
+ "Picture provided by original account" : "Imagem fornecida por conta original",
+ "Cancel" : "Cancelar",
+ "Choose as profile picture" : "Escolha como imagem de perfil",
"Full name" : "Nome completo",
"No display name set" : "Nenhuma exibição de nome de configuração",
"Email" : "E-mail",
"Your email address" : "Seu endereço de e-mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Preencha com um e-mail para permitir a recuperação de senha e receber notificações",
+ "For password recovery and notifications" : "Para recuperação de senha e notificações",
"No email address set" : "Nenhum endereço de email foi configurado",
"You are member of the following groups:" : "Você é membro dos seguintes grupos:",
- "Profile picture" : "Imagem para o perfil",
- "Upload new" : "Enviar nova foto",
- "Select new from Files" : "Selecinar uma nova dos Arquivos",
- "Remove image" : "Remover imagem",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Ou png ou jpg. Idealmente quadrada, mas você será capaz de cortá-la. O arquivo não pode exceder o tamanho máximo de 20 MB.",
- "Your avatar is provided by your original account." : "Seu avatar é fornecido por sua conta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Escolha como imagem para o perfil",
+ "Password" : "Senha",
+ "Unable to change your password" : "Não é possivel alterar a sua senha",
+ "Current password" : "Senha atual",
+ "New password" : "Nova senha",
+ "Change password" : "Alterar senha",
"Language" : "Idioma",
"Help translate" : "Ajude a traduzir",
- "Common Name" : "Nome",
- "Valid until" : "Válido até",
- "Issued By" : "Emitido Por",
- "Valid until %s" : "Válido até %s",
- "Import root certificate" : "Importar certificado raiz",
+ "Get the apps to sync your files" : "Obtenha apps para sincronizar seus arquivos",
+ "Desktop client" : "Cliente Desktop",
+ "Android app" : "App Android",
+ "iOS app" : "App iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se você quiser suportar o projeto, \n⇥⇥<a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\">ajude com o desenvolvimento</a>\n⇥⇥ou\n⇥⇥<a href=\"https://owncloud.org/promote\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\">ajude a divulgá-lo</a>!",
+ "Show First Run Wizard again" : "Mostrar Assistente de Primeira Execução novamente",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desenvolvido {communityopen}pela comunidade ownCloud{linkclose}, o {githubopen}código fonte{linkclose} está licenciado sob a {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostrar localização de armazenamento",
"Show last log in" : "Mostrar o último acesso",
diff --git a/settings/l10n/pt_BR.json b/settings/l10n/pt_BR.json
index 52072f8f1fa..fb06b056b44 100644
--- a/settings/l10n/pt_BR.json
+++ b/settings/l10n/pt_BR.json
@@ -10,12 +10,10 @@
"Log" : "Registro",
"Tips & tricks" : "Dicas & Truques",
"Updates" : "Atualizações",
- "Authentication error" : "Erro de autenticação",
- "Your full name has been changed." : "Seu nome completo foi alterado.",
- "Unable to change full name" : "Não é possível alterar o nome completo",
"Couldn't remove app." : "Não foi possível remover aplicativos.",
"Language changed" : "Idioma alterado",
"Invalid request" : "Pedido inválido",
+ "Authentication error" : "Erro de autenticação",
"Admins can't remove themself from the admin group" : "Administradores não pode remover a si mesmos do grupo de administração",
"Unable to add user to group %s" : "Não foi possível adicionar usuário ao grupo %s",
"Unable to remove user from group %s" : "Não foi possível remover usuário do grupo %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Usuário inválido",
"Unable to change mail address" : "Não é possível trocar o endereço de email",
"Email saved" : "E-mail salvo",
+ "Your full name has been changed." : "Seu nome completo foi alterado.",
+ "Unable to change full name" : "Não é possível alterar o nome completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Você tem certeza que você quer adicionar \"{domain}\" como domínio confiável?",
"Add trusted domain" : "Adicionar domínio confiável",
"Migration in progress. Please wait until the migration is finished" : "Migração em progresso. Por favor aguarde até que a migração seja finalizada",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "O aplicativo foi habilitado, mas precisa ser atualizado. Você será redirecionado para a página de atualização em 5 segundos.",
"App update" : "Atualização de aplicativo",
"No apps found for \"{query}\"" : "Nenhum aplicativo encontrado para \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ocorreu um erro. Por favor envie um certificado ASCII-encoded PEM",
+ "Valid until {date}" : "Vádido até {date}",
+ "Delete" : "Excluir",
"An error occurred: {message}" : "Ocorreu um erro: {message}",
"Select a profile picture" : "Selecione uma imagem para o perfil",
"Very weak password" : "Senha muito fraca",
@@ -86,9 +89,6 @@
"So-so password" : "Senha mais ou menos",
"Good password" : "Boa senha",
"Strong password" : "Senha forte",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ocorreu um erro. Por favor envie um certificado ASCII-encoded PEM",
- "Valid until {date}" : "Vádido até {date}",
- "Delete" : "Excluir",
"Groups" : "Grupos",
"Unable to delete {objName}" : "Não é possível excluir {objName}",
"Error creating group" : "Erro ao criar grupo",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Forneça uma senha válida",
"A valid email must be provided" : "Deve ser informado um e-mail válido",
"__language_name__" : "__language_name__",
- "Sync clients" : "Clientes de Sincronização",
"Personal info" : "Informação pessoal",
- "SSL root certificates" : "Certificados SSL raíz",
+ "Sync clients" : "Clientes de Sincronização",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tudo (questões fatais, erros, avisos, informações, depuração)",
"Info, warnings, errors and fatal issues" : "Informações, avisos, erros e problemas fatais",
"Warnings, errors and fatal issues" : "Avisos, erros e problemas fatais",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Nós sugerimos a instalação dos pacotes necessários em seu sistema para suportar um dos seguintes locais: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se a sua instalação não estiver instalada na raiz do domínio e usa cron do sistema, pode haver problemas com a geração de URL. Para evitar esses problemas, por favor, defina a opção \"overwrite.cli.url\" em seu arquivo config.php para o caminho webroot de sua instalação (Sugestão: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Não foi possível executar o cron via CLI. Os seguintes erros técnicos têm aparecido:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Bloqueio de arquivos transacional está usando o banco de dados como bloqueio de back-end, para o melhor o desempenho é aconselhável configurar um cache de memória para bloqueio. Veja a <a target=\"_blank\" href=\"%s\">documentação ↗</a> para mais informação.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Por favor, verifique os <a target=\"_blank\" href=\"%s\">guias de instalação ↗</a>, e verificar se há erros ou avisos no <a href=\"#log-section\">log</a>.",
"All checks passed." : "Todas as verificações passaram.",
"Open documentation" : "Abrir documentação",
@@ -186,11 +184,11 @@
"Store credentials" : "Armazenar credenciais",
"Test email settings" : "Configurações de e-mail de teste",
"Send email" : "Enviar email",
- "Log level" : "Nível de registro",
"Download logfile" : "Baixar o arquivo de log",
"More" : "Mais",
"Less" : "Menos",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "O arquivo de log é maior que 100 MB. Baixar esse arquivo requer algum tempo!",
+ "What to log" : "O que colocar no log",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite é usada como base de dados. Para instalações maiores recomendamos mudar para um backend de banco de dados diferente.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Especialmente quando se utiliza o cliente de desktop para sincronização de arquivos o uso de SQLite é desencorajado.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Para migrar para outro banco de dados usar a ferramenta de linha de comando: 'db occ: converter-type', verifique a <a target=\"_blank\" href=\"%s\">documentação ↗</a>.",
@@ -204,59 +202,62 @@
"Developer documentation" : "Documentação do desenvolvedor",
"Experimental applications ahead" : "Aplicações experimentais à frente",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Aplicativos experimentais não são marcados por questões de segurança, por serem novos ou conhecidos como instáveis e sob forte desenvolvimento. Instalá-los pode causar perda de dados ou falhas de segurança.",
- "by" : "por",
- "licensed" : "licenciado",
+ "by %s" : "por %s",
+ "%s-licensed" : "%s-licenciado",
"Documentation:" : "Documentação:",
"User documentation" : "Documentação do usuário",
"Admin documentation" : "Documentação para Administração",
"Show description …" : "Mostrar descrição ...",
"Hide description …" : "Esconder descrição ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Este aplicativo não tem atribuída nenhuma versão ownCloud mínima. Isto será um erro no ownCloud 11 e posterior.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Este aplicativo não tem atribuída nenhuma versão ownCloud máxima. Isto será um erro no ownCloud 11 e posterior.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Este aplicativo não pode ser instalado porque as seguintes dependências não forão cumpridas:",
"Enable only for specific groups" : "Ativar apenas para grupos específicos",
"Uninstall App" : "Desinstalar Aplicativo",
"Enable experimental apps" : "Habilitar aplicativos experimentais",
+ "SSL Root Certificates" : "Certificados Raiz SSL",
+ "Common Name" : "Nome",
+ "Valid until" : "Válido até",
+ "Issued By" : "Emitido Por",
+ "Valid until %s" : "Válido até %s",
+ "Import root certificate" : "Importar certificado raiz",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Olá,<br><br>somente para lembrar que agora você tem uma conta %s.<br><br>Seu nome de usuário é: %s<br>Acesse em: <a href=\"%s\">%s</a><br><br>",
- "Cheers!" : "Saúde!",
+ "Cheers!" : "Saudações!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Olá,\n\nsomente para lembrar que agora você tem uma conta %s.\n\nSeu nome de usuário é: %s\nAcesse em: %s\n\n",
"Administrator documentation" : "Documentação do administrador",
"Online documentation" : "Documentação online",
"Forum" : "Fórum",
"Issue tracker" : "Rastreador de tópicos",
"Commercial support" : "Suporte comercial",
- "Get the apps to sync your files" : "Faça com que os apps sincronizem seus arquivos",
- "Desktop client" : "Cliente Desktop",
- "Android app" : "App Android",
- "iOS app" : "App iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se você quiser dar suporte ao projeto\n⇥⇥<a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\">juntese ao desenvolvimento</a>\n⇥⇥ou\n⇥⇥<a href=\"https://owncloud.org/promote\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\">espalhe para o mundo</a>!",
- "Show First Run Wizard again" : "Mostrar Assistente de Primeira Execução novamente",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Você usou <strong>%s</strong> do seu espaço de <strong>%s</strong>",
- "Password" : "Senha",
- "Unable to change your password" : "Não é possivel alterar a sua senha",
- "Current password" : "Senha atual",
- "New password" : "Nova senha",
- "Change password" : "Alterar senha",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Você está usando <strong>%s</strong> de <strong>%s</strong>",
+ "Profile picture" : "Imagem para o perfil",
+ "Upload new" : "Enviar nova foto",
+ "Select from Files" : "Selecionar de Arquivos",
+ "Remove image" : "Remover imagem",
+ "png or jpg, max. 20 MB" : "png ou jpg, max. 20 MB",
+ "Picture provided by original account" : "Imagem fornecida por conta original",
+ "Cancel" : "Cancelar",
+ "Choose as profile picture" : "Escolha como imagem de perfil",
"Full name" : "Nome completo",
"No display name set" : "Nenhuma exibição de nome de configuração",
"Email" : "E-mail",
"Your email address" : "Seu endereço de e-mail",
- "Fill in an email address to enable password recovery and receive notifications" : "Preencha com um e-mail para permitir a recuperação de senha e receber notificações",
+ "For password recovery and notifications" : "Para recuperação de senha e notificações",
"No email address set" : "Nenhum endereço de email foi configurado",
"You are member of the following groups:" : "Você é membro dos seguintes grupos:",
- "Profile picture" : "Imagem para o perfil",
- "Upload new" : "Enviar nova foto",
- "Select new from Files" : "Selecinar uma nova dos Arquivos",
- "Remove image" : "Remover imagem",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Ou png ou jpg. Idealmente quadrada, mas você será capaz de cortá-la. O arquivo não pode exceder o tamanho máximo de 20 MB.",
- "Your avatar is provided by your original account." : "Seu avatar é fornecido por sua conta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Escolha como imagem para o perfil",
+ "Password" : "Senha",
+ "Unable to change your password" : "Não é possivel alterar a sua senha",
+ "Current password" : "Senha atual",
+ "New password" : "Nova senha",
+ "Change password" : "Alterar senha",
"Language" : "Idioma",
"Help translate" : "Ajude a traduzir",
- "Common Name" : "Nome",
- "Valid until" : "Válido até",
- "Issued By" : "Emitido Por",
- "Valid until %s" : "Válido até %s",
- "Import root certificate" : "Importar certificado raiz",
+ "Get the apps to sync your files" : "Obtenha apps para sincronizar seus arquivos",
+ "Desktop client" : "Cliente Desktop",
+ "Android app" : "App Android",
+ "iOS app" : "App iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se você quiser suportar o projeto, \n⇥⇥<a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\">ajude com o desenvolvimento</a>\n⇥⇥ou\n⇥⇥<a href=\"https://owncloud.org/promote\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\">ajude a divulgá-lo</a>!",
+ "Show First Run Wizard again" : "Mostrar Assistente de Primeira Execução novamente",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desenvolvido {communityopen}pela comunidade ownCloud{linkclose}, o {githubopen}código fonte{linkclose} está licenciado sob a {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostrar localização de armazenamento",
"Show last log in" : "Mostrar o último acesso",
diff --git a/settings/l10n/pt_PT.js b/settings/l10n/pt_PT.js
index c964856142f..aaa4af517c3 100644
--- a/settings/l10n/pt_PT.js
+++ b/settings/l10n/pt_PT.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Registo",
"Tips & tricks" : "Dicas e truqes",
"Updates" : "Atualizações",
- "Authentication error" : "Erro na autenticação",
- "Your full name has been changed." : "O seu nome completo foi alterado.",
- "Unable to change full name" : "Não foi possível alterar o seu nome completo",
"Couldn't remove app." : "Não foi possível remover a aplicação.",
"Language changed" : "Idioma alterado",
"Invalid request" : "Pedido Inválido",
+ "Authentication error" : "Erro na autenticação",
"Admins can't remove themself from the admin group" : "Os administradores não se podem remover a eles próprios do grupo 'admin'.",
"Unable to add user to group %s" : "Não é possível adicionar o utilizador ao grupo %s",
"Unable to remove user from group %s" : "Não é possível remover o utilizador do grupo %s",
@@ -30,7 +28,9 @@ OC.L10N.register(
"Unable to change password" : "Não foi possível alterar a sua palavra-passe ",
"Enabled" : "Ativada",
"Not enabled" : "Desativada",
+ "installing and updating apps via the app store or Federated Cloud Sharing" : "instalando e atualizando aplicações via loja de aplicações ou Partilha de Nuvem Federada",
"Federated Cloud Sharing" : "Partilha de Cloud Federada",
+ "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL está a usar uma versão %s desatualizada (%s). Por favor, atualize o seu sistema operativo ou algumas funcionalidades como %s não funcionarão corretamente.",
"A problem occurred, please check your log files (Error: %s)" : "Ocorreu um problema, por favor, verifique os ficheiros de registo (Erro: %s)",
"Migration Completed" : "Migração Concluída",
"Group already exists." : "O grupo já existe.",
@@ -51,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Utilizador inválido",
"Unable to change mail address" : "Não foi possível alterar o teu endereço de email",
"Email saved" : "E-mail guardado",
+ "Your full name has been changed." : "O seu nome completo foi alterado.",
+ "Unable to change full name" : "Não foi possível alterar o seu nome completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Você tem certeza que quer adicionar \"{domain}\" como domínio confiável?",
"Add trusted domain" : "Adicionar domínio confiável ",
"Migration in progress. Please wait until the migration is finished" : "Migração em progresso. Por favor, aguarde até que a mesma esteja concluída..",
@@ -62,6 +64,8 @@ OC.L10N.register(
"All" : "Todos",
"No apps found for your version" : "Nenhuma aplicação encontrada para a sua versão",
"Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "As apps oficiais são desenvolvidas por e na comunidade da ownCloud. Elas oferecem funcionalidade central para a ownCloud e está pronta para uma utilização na produção.",
+ "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "As aplicações aprovadas são desenvolvidas por developers de confiança e passaram numa verificação de segurança. São mantidas ativamente num repositório de código aberto e quem as mantém considera-as estáveis para uso casual a normal.",
+ "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "Esta aplicação não foi verificada por problemas de segurança e é nova ou conhecida por ser instável. Instale-a por sua conta e risco.",
"Update to %s" : "Actualizar para %s",
"Please wait...." : "Por favor, aguarde...",
"Error while disabling app" : "Ocorreu um erro enquanto desativava a app",
@@ -74,7 +78,12 @@ OC.L10N.register(
"Uninstalling ...." : "A desinstalar....",
"Error while uninstalling app" : "Ocorreu um erro durante a desinstalação da app",
"Uninstall" : "Desinstalar",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "A aplicação foi ativada, mas precisa de ser atualizada. Você será redirecionado para a página de atualização em 5 segundos.",
"App update" : "Atualizar App",
+ "No apps found for \"{query}\"" : "Não foram encontradas aplicações para \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ocorreu um erro. Por favor, envie um certificado PEM codificado em ASCII.",
+ "Valid until {date}" : "Válida até {date}",
+ "Delete" : "Apagar",
"An error occurred: {message}" : "Ocorreu um erro: {message}",
"Select a profile picture" : "Selecione uma fotografia de perfil",
"Very weak password" : "Palavra-passe muito fraca",
@@ -82,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Palavra-passe aceitável",
"Good password" : "Palavra-passe boa",
"Strong password" : "Palavra-passe forte",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ocorreu um erro. Por favor, envie um certificado PEM codificado em ASCII.",
- "Valid until {date}" : "Válida até {date}",
- "Delete" : "Apagar",
"Groups" : "Grupos",
"Unable to delete {objName}" : "Não é possível apagar {objNome}",
"Error creating group" : "Ocorreu um erro ao criar o grupo",
@@ -101,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Deve ser indicada uma palavra-passe válida",
"A valid email must be provided" : "Deve ser fornecido um email válido",
"__language_name__" : "__language_name__",
- "Sync clients" : "Clientes de sync",
"Personal info" : "Informação pessoal",
- "SSL root certificates" : "Certificados de raiz SSL",
+ "Sync clients" : "Clientes de sync",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tudo (problemas fatais, erros, avisos, informação, depuração)",
"Info, warnings, errors and fatal issues" : "Informação, avisos, erros e problemas fatais",
"Warnings, errors and fatal issues" : "Avisos, erros e problemas fatais",
@@ -115,17 +120,22 @@ OC.L10N.register(
"NT LAN Manager" : "Gestor de REDE NT",
"SSL" : "SSL",
"TLS" : "TLS",
+ "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "php não parece estar bem instalado para consultar variáveis de ambiente do sistema. O teste com getenv(\"PATH\") apenas devolveu uma resposta em branco.",
+ "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "Por favor, verifique a <a target=\"_blank\" href=\"%s\">documentação de instalação ↗</a> para notas de configuração do php e configuração php do seu servidor, especialmente quando utiliza php-fpm.",
"The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "A configuração Só-de-Leitura foi ativada. Isto evita definir algumas configurações através da interface da Web. Além disso, o ficheiro precisa de ser definido gravável manualmente para cada atualização.",
"PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible." : "PHP está aparentemente configurado a remover blocos doc em linha. Isto vai fazer algumas aplicações basicas inacessíveis.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isto é provavelmente causado por uma cache/acelerador como o Zend OPcache or eAcelerador.",
"Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "O seu servidor está a correr Microsoft Windows. Nós recomendamos Linux para uma experiência de utilizador optimizada.",
+ "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "%1$s abaixo da versão %2$s está instalado. Por motivos de estabilidade e desempenho, recomendamos que atualize para a nova versão %1$s.",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "O Módulo PHP 'fileinfo' não se encontra instalado/activado. É fortemente recomendado que active este módulo para obter os melhores resultado com a detecção dos tipos de mime.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Bloqueio de arquivos transacionais está desativado, isto poderá levar a problemas com condições de corrida. Ative 'filelocking.enabled' no config.php para evitar estes problemas. Consulte a <a target=\"_blank\" href=\"%s\">documentação ↗</a> para mais informação.",
"System locale can not be set to a one which supports UTF-8." : "Não é possível definir a internacionalização do sistema para um que suporte o UTF-8.",
"This means that there might be problems with certain characters in file names." : "Isto significa que podem haver problemas com alguns caracteres nos nomes dos ficheiros.",
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Nós recomendamos fortemente que instale no seu sistema os pacotes necessários para suportar uma das seguintes locallidades: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se a sua instalação não está instalada na raiz do domínio e usa o sistema cron, pode haver problemas com a geração de URL. Para evitar esses problemas, por favor, defina a opção \"overwrite.cli.url\" no ficheiro config.php para o caminho webroot da sua instalação (Sugestão: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Não foi possível executar o cronjob via CLI. Os seguintes erros técnicos apareceram:",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Por favor, verifique os <a target=\"_blank\" href=\"%s\">guias de instalação ↗</a>, e verifique se existe algum erro ou aviso no <a href=\"#log-section\">log</a>.",
+ "All checks passed." : "Todas as verificações passaram.",
"Open documentation" : "Abrir documentação",
"Allow apps to use the Share API" : "Permitir que os utilizadores usem a API de partilha",
"Allow users to share via link" : "Permitir que os utilizadores partilhem através do link",
@@ -141,14 +151,25 @@ OC.L10N.register(
"Allow users to send mail notification for shared files to other users" : "Autorizar utilizadores a enviarem notificações de email acerca de ficheiros partilhados a outros utilizadores",
"Exclude groups from sharing" : "Excluir grupos das partilhas",
"These groups will still be able to receive shares, but not to initiate them." : "Estes grupos poderão receber partilhas, mas não poderão iniciá-las.",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Permitir o auto-completar de nome de utilizador no diálogo da partilha. Se isto for desativado, será necessário preencher o nome de utilizador completo.",
"Last cron job execution: %s." : "Última execução de cron job: %s.",
"Last cron job execution: %s. Something seems wrong." : "Última execução de cron job: %s. Algo está errado.",
"Cron was not executed yet!" : "Cron ainda não foi executado!",
"Execute one task with each page loaded" : "Executar uma tarefa com cada página carregada",
"cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php está registado num serviço webcron para chamar a página cron.php por http a cada 15 minutos.",
"Use system's cron service to call the cron.php file every 15 minutes." : "Usar o serviço sistema cron para ligar o ficheiro cron.php a cada 15 minutos.",
+ "Enable server-side encryption" : "Ativar encriptação do lado do servidor",
+ "Please read carefully before activating server-side encryption: " : "Por favor, leia cuidadosamente antes de ativar a encriptação do lado do servidor:",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "Uma vez ativada a encriptação, todos os ficheiros carregados para o servidor a partir deste ponto serão encriptados pelo servidor. Só será possível desativar a encriptação numa data mais tarde se o módulo de encriptação ativo suportar essa função, assim como todas as pré-condições (e.g. definir chave de recuperação) sejam cumpridas.",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "A encriptação por si só não garante a segurança do sistema. Por favor, consulte a documentação ownCloud para mais informação acerca de como funciona a aplicação de encriptação, assim como os casos de uso suportados.",
+ "Be aware that encryption always increases the file size." : "Tenha em conta que a encriptação aumenta sempre o tamanho do ficheiro.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "É sempre bom criar cópias de segurança regulares dos seus dados, em caso de encriptação tenha a certeza de que faz cópia das chaves de encriptação em conjunto com os seus dados.",
+ "This is the final warning: Do you really want to enable encryption?" : "Este é o aviso final: quer mesmo ativar a encriptação?",
"Enable encryption" : "Ative a encriptação",
+ "No encryption module loaded, please enable an encryption module in the app menu." : "Nenhum módulo de encriptação carregador, por favor ative um módulo de encriptação no menu das aplicações.",
"Select default encryption module:" : "Selecionar o módulo de encriptação predefinido:",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run 'occ encryption:migrate'" : "Precisa de migrar as suas chaves de encriptação da encriptação antiga (ownCloud <= 8.0) para a nova. Por favor, ative o \"Módulo de encriptação padrão\" e execute 'occ encryption:migrate'",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : "Precisa de migrar as suas chaves de encriptação da encriptação antiga (ownCloud <= 8.0) para a nova.",
"Start migration" : "Iniciar migração",
"This is used for sending out notifications." : "Isto é utilizado para enviar notificações",
"Send mode" : "Modo de Envio",
@@ -165,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Armazenar credenciais",
"Test email settings" : "Testar definições de e-mail",
"Send email" : "Enviar email",
- "Log level" : "Nível do registo",
"Download logfile" : "Descarregar logfile",
"More" : "Mais",
"Less" : "Menos",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "O logfile é maior que 100MB. O download do mesmo poderá demorar algum tempo!",
+ "What to log" : "Fazer log do quê?",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite é utilizado como uma base de dados. Para instalações maiores nós recomendamos que mude para uma interface de base de dados diferente.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "O uso de SQLite é desencorajado especialmente se estiver a pensar em dar uso ao cliente desktop para sincronizar os seus ficheiros no seu computador.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Para migrar para outro tipo de base de dados, use a ferramenta de comando de linha: 'occ db:convert-type', ou seja a <a target=\"_blank\" href=\"%s\">documentação↗</a>.",
@@ -183,17 +204,25 @@ OC.L10N.register(
"Developer documentation" : "Documentação de Programador",
"Experimental applications ahead" : "Aplicações experimentais de futuro",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "As apps experimentais não estão selecionadas para problemas de segurança, nova ou conhecida como instável e em forte desenvolvimento. Ao instalá-las pode causar a perda de dados ou quebra de segurança.",
- "by" : "por",
- "licensed" : "licenciado",
+ "by %s" : "por %s",
+ "%s-licensed" : "%s-autorizado",
"Documentation:" : "Documentação:",
"User documentation" : "Documentação de Utilizador",
"Admin documentation" : "Documentação do Administrador",
"Show description …" : "Mostrar descrição ...",
"Hide description …" : "Esconder descrição ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Esta aplicação não tem uma versão mínima de ownCloud atribuída. Isto será um erro no ownCloud 11 e seguintes.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Esta aplicação não tem uma versão máxima de ownCloud atribuída. Isto será um erro no ownCloud 11 e seguintes.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Esta aplicação não pode ser instalada porque as seguintes dependências não podem ser realizadas:",
"Enable only for specific groups" : "Activar só para grupos específicos",
"Uninstall App" : "Desinstalar aplicação",
"Enable experimental apps" : "Ativar apps experimentais",
+ "SSL Root Certificates" : "Certificados SSL Root",
+ "Common Name" : "Nome Comum",
+ "Valid until" : "Válido até",
+ "Issued By" : "Emitido Por",
+ "Valid until %s" : "Válido até %s",
+ "Import root certificate" : "Importar certificado root",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Olá,<br><br>apenas para informar que você tem uma conta %s.<br><br>O seu nome de utilizador: %s<br>Acesse à sua conta: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Parabéns!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Olá,\n\napenas para informar que você tem uma conta %s.\n\nO seu nome de utilizador: %s\nAcesse à sua conta: %s\n\n",
@@ -202,39 +231,35 @@ OC.L10N.register(
"Forum" : "Fórum",
"Issue tracker" : "Pesquisador de problemad",
"Commercial support" : "Suporte Comercial",
- "Get the apps to sync your files" : "Obtenha as aplicações para sincronizar os seus ficheiros",
- "Desktop client" : "Cliente Desktop",
- "Android app" : "Aplicação Android",
- "iOS app" : "Aplicação iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se quer apoiar o projecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">junte-se ao desenvolvimento</a>\n\t\tou\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">espalhe a palavra</a>!",
- "Show First Run Wizard again" : "Mostrar novamente Wizard de Arranque Inicial",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Usou <strong>%s</strong> do disponivel <strong>%s</strong>",
- "Password" : "Palavra-passe",
- "Unable to change your password" : "Não foi possível alterar a sua palavra-passe",
- "Current password" : "Palavra-passe atual",
- "New password" : "Nova palavra-passe",
- "Change password" : "Alterar palavra-passe",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Está a usar <strong>%s</strong> de <strong>%s</strong>",
+ "Profile picture" : "Foto do perfil",
+ "Upload new" : "Carregar novo",
+ "Select from Files" : "Seleccione dos Ficheiros",
+ "Remove image" : "Remover imagem",
+ "png or jpg, max. 20 MB" : "png ou jpg, máx. 20 MB",
+ "Picture provided by original account" : "Imagem fornecida pela conta original",
+ "Cancel" : "Cancelar",
+ "Choose as profile picture" : "Escolher como fotografia de perfil",
"Full name" : "Nome completo",
"No display name set" : "Nenhum nome display estabelecido",
"Email" : "Email",
"Your email address" : "O seu endereço de email",
- "Fill in an email address to enable password recovery and receive notifications" : "Preencha com um endereço e-mail para permitir a recuperação da palavra-passe e receber notificações",
+ "For password recovery and notifications" : "Para recuperação da palavra-passe e notificações",
"No email address set" : "Nenhum endereço de email estabelecido",
"You are member of the following groups:" : "Você é membro dos seguintes grupos:",
- "Profile picture" : "Foto do perfil",
- "Upload new" : "Carregar novo",
- "Select new from Files" : "Seleccionar novo a partir dos ficheiros",
- "Remove image" : "Remover imagem",
- "Your avatar is provided by your original account." : "O seu avatar é fornecido pela sua conta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Escolha uma fotografia de perfil",
+ "Password" : "Palavra-passe",
+ "Unable to change your password" : "Não foi possível alterar a sua palavra-passe",
+ "Current password" : "Palavra-passe atual",
+ "New password" : "Nova palavra-passe",
+ "Change password" : "Alterar palavra-passe",
"Language" : "Idioma",
"Help translate" : "Ajude a traduzir",
- "Common Name" : "Nome Comum",
- "Valid until" : "Válido até",
- "Issued By" : "Emitido Por",
- "Valid until %s" : "Válido até %s",
- "Import root certificate" : "Importar certificado root",
+ "Get the apps to sync your files" : "Obtenha as aplicações para sincronizar os seus ficheiros",
+ "Desktop client" : "Cliente Desktop",
+ "Android app" : "Aplicação Android",
+ "iOS app" : "Aplicação iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se quer apoiar o projecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">junte-se ao desenvolvimento</a>\n\t\tou\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">espalhe a palavra</a>!",
+ "Show First Run Wizard again" : "Mostrar novamente Wizard de Arranque Inicial",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desenvolvido pela {communityopen}comunidade ownCloud{linkclose}, o {githubopen}código-fonte{linkclose} está licenciado sob a {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostrar a localização do armazenamento",
"Show last log in" : "Mostrar ultimo acesso de entrada",
diff --git a/settings/l10n/pt_PT.json b/settings/l10n/pt_PT.json
index 53a9da55517..b6d35b4bce1 100644
--- a/settings/l10n/pt_PT.json
+++ b/settings/l10n/pt_PT.json
@@ -10,12 +10,10 @@
"Log" : "Registo",
"Tips & tricks" : "Dicas e truqes",
"Updates" : "Atualizações",
- "Authentication error" : "Erro na autenticação",
- "Your full name has been changed." : "O seu nome completo foi alterado.",
- "Unable to change full name" : "Não foi possível alterar o seu nome completo",
"Couldn't remove app." : "Não foi possível remover a aplicação.",
"Language changed" : "Idioma alterado",
"Invalid request" : "Pedido Inválido",
+ "Authentication error" : "Erro na autenticação",
"Admins can't remove themself from the admin group" : "Os administradores não se podem remover a eles próprios do grupo 'admin'.",
"Unable to add user to group %s" : "Não é possível adicionar o utilizador ao grupo %s",
"Unable to remove user from group %s" : "Não é possível remover o utilizador do grupo %s",
@@ -28,7 +26,9 @@
"Unable to change password" : "Não foi possível alterar a sua palavra-passe ",
"Enabled" : "Ativada",
"Not enabled" : "Desativada",
+ "installing and updating apps via the app store or Federated Cloud Sharing" : "instalando e atualizando aplicações via loja de aplicações ou Partilha de Nuvem Federada",
"Federated Cloud Sharing" : "Partilha de Cloud Federada",
+ "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL está a usar uma versão %s desatualizada (%s). Por favor, atualize o seu sistema operativo ou algumas funcionalidades como %s não funcionarão corretamente.",
"A problem occurred, please check your log files (Error: %s)" : "Ocorreu um problema, por favor, verifique os ficheiros de registo (Erro: %s)",
"Migration Completed" : "Migração Concluída",
"Group already exists." : "O grupo já existe.",
@@ -49,6 +49,8 @@
"Invalid user" : "Utilizador inválido",
"Unable to change mail address" : "Não foi possível alterar o teu endereço de email",
"Email saved" : "E-mail guardado",
+ "Your full name has been changed." : "O seu nome completo foi alterado.",
+ "Unable to change full name" : "Não foi possível alterar o seu nome completo",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Você tem certeza que quer adicionar \"{domain}\" como domínio confiável?",
"Add trusted domain" : "Adicionar domínio confiável ",
"Migration in progress. Please wait until the migration is finished" : "Migração em progresso. Por favor, aguarde até que a mesma esteja concluída..",
@@ -60,6 +62,8 @@
"All" : "Todos",
"No apps found for your version" : "Nenhuma aplicação encontrada para a sua versão",
"Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "As apps oficiais são desenvolvidas por e na comunidade da ownCloud. Elas oferecem funcionalidade central para a ownCloud e está pronta para uma utilização na produção.",
+ "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "As aplicações aprovadas são desenvolvidas por developers de confiança e passaram numa verificação de segurança. São mantidas ativamente num repositório de código aberto e quem as mantém considera-as estáveis para uso casual a normal.",
+ "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "Esta aplicação não foi verificada por problemas de segurança e é nova ou conhecida por ser instável. Instale-a por sua conta e risco.",
"Update to %s" : "Actualizar para %s",
"Please wait...." : "Por favor, aguarde...",
"Error while disabling app" : "Ocorreu um erro enquanto desativava a app",
@@ -72,7 +76,12 @@
"Uninstalling ...." : "A desinstalar....",
"Error while uninstalling app" : "Ocorreu um erro durante a desinstalação da app",
"Uninstall" : "Desinstalar",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "A aplicação foi ativada, mas precisa de ser atualizada. Você será redirecionado para a página de atualização em 5 segundos.",
"App update" : "Atualizar App",
+ "No apps found for \"{query}\"" : "Não foram encontradas aplicações para \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ocorreu um erro. Por favor, envie um certificado PEM codificado em ASCII.",
+ "Valid until {date}" : "Válida até {date}",
+ "Delete" : "Apagar",
"An error occurred: {message}" : "Ocorreu um erro: {message}",
"Select a profile picture" : "Selecione uma fotografia de perfil",
"Very weak password" : "Palavra-passe muito fraca",
@@ -80,9 +89,6 @@
"So-so password" : "Palavra-passe aceitável",
"Good password" : "Palavra-passe boa",
"Strong password" : "Palavra-passe forte",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ocorreu um erro. Por favor, envie um certificado PEM codificado em ASCII.",
- "Valid until {date}" : "Válida até {date}",
- "Delete" : "Apagar",
"Groups" : "Grupos",
"Unable to delete {objName}" : "Não é possível apagar {objNome}",
"Error creating group" : "Ocorreu um erro ao criar o grupo",
@@ -99,9 +105,8 @@
"A valid password must be provided" : "Deve ser indicada uma palavra-passe válida",
"A valid email must be provided" : "Deve ser fornecido um email válido",
"__language_name__" : "__language_name__",
- "Sync clients" : "Clientes de sync",
"Personal info" : "Informação pessoal",
- "SSL root certificates" : "Certificados de raiz SSL",
+ "Sync clients" : "Clientes de sync",
"Everything (fatal issues, errors, warnings, info, debug)" : "Tudo (problemas fatais, erros, avisos, informação, depuração)",
"Info, warnings, errors and fatal issues" : "Informação, avisos, erros e problemas fatais",
"Warnings, errors and fatal issues" : "Avisos, erros e problemas fatais",
@@ -113,17 +118,22 @@
"NT LAN Manager" : "Gestor de REDE NT",
"SSL" : "SSL",
"TLS" : "TLS",
+ "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "php não parece estar bem instalado para consultar variáveis de ambiente do sistema. O teste com getenv(\"PATH\") apenas devolveu uma resposta em branco.",
+ "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "Por favor, verifique a <a target=\"_blank\" href=\"%s\">documentação de instalação ↗</a> para notas de configuração do php e configuração php do seu servidor, especialmente quando utiliza php-fpm.",
"The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "A configuração Só-de-Leitura foi ativada. Isto evita definir algumas configurações através da interface da Web. Além disso, o ficheiro precisa de ser definido gravável manualmente para cada atualização.",
"PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible." : "PHP está aparentemente configurado a remover blocos doc em linha. Isto vai fazer algumas aplicações basicas inacessíveis.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isto é provavelmente causado por uma cache/acelerador como o Zend OPcache or eAcelerador.",
"Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "O seu servidor está a correr Microsoft Windows. Nós recomendamos Linux para uma experiência de utilizador optimizada.",
+ "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "%1$s abaixo da versão %2$s está instalado. Por motivos de estabilidade e desempenho, recomendamos que atualize para a nova versão %1$s.",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "O Módulo PHP 'fileinfo' não se encontra instalado/activado. É fortemente recomendado que active este módulo para obter os melhores resultado com a detecção dos tipos de mime.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Bloqueio de arquivos transacionais está desativado, isto poderá levar a problemas com condições de corrida. Ative 'filelocking.enabled' no config.php para evitar estes problemas. Consulte a <a target=\"_blank\" href=\"%s\">documentação ↗</a> para mais informação.",
"System locale can not be set to a one which supports UTF-8." : "Não é possível definir a internacionalização do sistema para um que suporte o UTF-8.",
"This means that there might be problems with certain characters in file names." : "Isto significa que podem haver problemas com alguns caracteres nos nomes dos ficheiros.",
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Nós recomendamos fortemente que instale no seu sistema os pacotes necessários para suportar uma das seguintes locallidades: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se a sua instalação não está instalada na raiz do domínio e usa o sistema cron, pode haver problemas com a geração de URL. Para evitar esses problemas, por favor, defina a opção \"overwrite.cli.url\" no ficheiro config.php para o caminho webroot da sua instalação (Sugestão: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Não foi possível executar o cronjob via CLI. Os seguintes erros técnicos apareceram:",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Por favor, verifique os <a target=\"_blank\" href=\"%s\">guias de instalação ↗</a>, e verifique se existe algum erro ou aviso no <a href=\"#log-section\">log</a>.",
+ "All checks passed." : "Todas as verificações passaram.",
"Open documentation" : "Abrir documentação",
"Allow apps to use the Share API" : "Permitir que os utilizadores usem a API de partilha",
"Allow users to share via link" : "Permitir que os utilizadores partilhem através do link",
@@ -139,14 +149,25 @@
"Allow users to send mail notification for shared files to other users" : "Autorizar utilizadores a enviarem notificações de email acerca de ficheiros partilhados a outros utilizadores",
"Exclude groups from sharing" : "Excluir grupos das partilhas",
"These groups will still be able to receive shares, but not to initiate them." : "Estes grupos poderão receber partilhas, mas não poderão iniciá-las.",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Permitir o auto-completar de nome de utilizador no diálogo da partilha. Se isto for desativado, será necessário preencher o nome de utilizador completo.",
"Last cron job execution: %s." : "Última execução de cron job: %s.",
"Last cron job execution: %s. Something seems wrong." : "Última execução de cron job: %s. Algo está errado.",
"Cron was not executed yet!" : "Cron ainda não foi executado!",
"Execute one task with each page loaded" : "Executar uma tarefa com cada página carregada",
"cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php está registado num serviço webcron para chamar a página cron.php por http a cada 15 minutos.",
"Use system's cron service to call the cron.php file every 15 minutes." : "Usar o serviço sistema cron para ligar o ficheiro cron.php a cada 15 minutos.",
+ "Enable server-side encryption" : "Ativar encriptação do lado do servidor",
+ "Please read carefully before activating server-side encryption: " : "Por favor, leia cuidadosamente antes de ativar a encriptação do lado do servidor:",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "Uma vez ativada a encriptação, todos os ficheiros carregados para o servidor a partir deste ponto serão encriptados pelo servidor. Só será possível desativar a encriptação numa data mais tarde se o módulo de encriptação ativo suportar essa função, assim como todas as pré-condições (e.g. definir chave de recuperação) sejam cumpridas.",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "A encriptação por si só não garante a segurança do sistema. Por favor, consulte a documentação ownCloud para mais informação acerca de como funciona a aplicação de encriptação, assim como os casos de uso suportados.",
+ "Be aware that encryption always increases the file size." : "Tenha em conta que a encriptação aumenta sempre o tamanho do ficheiro.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "É sempre bom criar cópias de segurança regulares dos seus dados, em caso de encriptação tenha a certeza de que faz cópia das chaves de encriptação em conjunto com os seus dados.",
+ "This is the final warning: Do you really want to enable encryption?" : "Este é o aviso final: quer mesmo ativar a encriptação?",
"Enable encryption" : "Ative a encriptação",
+ "No encryption module loaded, please enable an encryption module in the app menu." : "Nenhum módulo de encriptação carregador, por favor ative um módulo de encriptação no menu das aplicações.",
"Select default encryption module:" : "Selecionar o módulo de encriptação predefinido:",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run 'occ encryption:migrate'" : "Precisa de migrar as suas chaves de encriptação da encriptação antiga (ownCloud <= 8.0) para a nova. Por favor, ative o \"Módulo de encriptação padrão\" e execute 'occ encryption:migrate'",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : "Precisa de migrar as suas chaves de encriptação da encriptação antiga (ownCloud <= 8.0) para a nova.",
"Start migration" : "Iniciar migração",
"This is used for sending out notifications." : "Isto é utilizado para enviar notificações",
"Send mode" : "Modo de Envio",
@@ -163,11 +184,11 @@
"Store credentials" : "Armazenar credenciais",
"Test email settings" : "Testar definições de e-mail",
"Send email" : "Enviar email",
- "Log level" : "Nível do registo",
"Download logfile" : "Descarregar logfile",
"More" : "Mais",
"Less" : "Menos",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "O logfile é maior que 100MB. O download do mesmo poderá demorar algum tempo!",
+ "What to log" : "Fazer log do quê?",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite é utilizado como uma base de dados. Para instalações maiores nós recomendamos que mude para uma interface de base de dados diferente.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "O uso de SQLite é desencorajado especialmente se estiver a pensar em dar uso ao cliente desktop para sincronizar os seus ficheiros no seu computador.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Para migrar para outro tipo de base de dados, use a ferramenta de comando de linha: 'occ db:convert-type', ou seja a <a target=\"_blank\" href=\"%s\">documentação↗</a>.",
@@ -181,17 +202,25 @@
"Developer documentation" : "Documentação de Programador",
"Experimental applications ahead" : "Aplicações experimentais de futuro",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "As apps experimentais não estão selecionadas para problemas de segurança, nova ou conhecida como instável e em forte desenvolvimento. Ao instalá-las pode causar a perda de dados ou quebra de segurança.",
- "by" : "por",
- "licensed" : "licenciado",
+ "by %s" : "por %s",
+ "%s-licensed" : "%s-autorizado",
"Documentation:" : "Documentação:",
"User documentation" : "Documentação de Utilizador",
"Admin documentation" : "Documentação do Administrador",
"Show description …" : "Mostrar descrição ...",
"Hide description …" : "Esconder descrição ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Esta aplicação não tem uma versão mínima de ownCloud atribuída. Isto será um erro no ownCloud 11 e seguintes.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Esta aplicação não tem uma versão máxima de ownCloud atribuída. Isto será um erro no ownCloud 11 e seguintes.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Esta aplicação não pode ser instalada porque as seguintes dependências não podem ser realizadas:",
"Enable only for specific groups" : "Activar só para grupos específicos",
"Uninstall App" : "Desinstalar aplicação",
"Enable experimental apps" : "Ativar apps experimentais",
+ "SSL Root Certificates" : "Certificados SSL Root",
+ "Common Name" : "Nome Comum",
+ "Valid until" : "Válido até",
+ "Issued By" : "Emitido Por",
+ "Valid until %s" : "Válido até %s",
+ "Import root certificate" : "Importar certificado root",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Olá,<br><br>apenas para informar que você tem uma conta %s.<br><br>O seu nome de utilizador: %s<br>Acesse à sua conta: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Parabéns!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Olá,\n\napenas para informar que você tem uma conta %s.\n\nO seu nome de utilizador: %s\nAcesse à sua conta: %s\n\n",
@@ -200,39 +229,35 @@
"Forum" : "Fórum",
"Issue tracker" : "Pesquisador de problemad",
"Commercial support" : "Suporte Comercial",
- "Get the apps to sync your files" : "Obtenha as aplicações para sincronizar os seus ficheiros",
- "Desktop client" : "Cliente Desktop",
- "Android app" : "Aplicação Android",
- "iOS app" : "Aplicação iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se quer apoiar o projecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">junte-se ao desenvolvimento</a>\n\t\tou\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">espalhe a palavra</a>!",
- "Show First Run Wizard again" : "Mostrar novamente Wizard de Arranque Inicial",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Usou <strong>%s</strong> do disponivel <strong>%s</strong>",
- "Password" : "Palavra-passe",
- "Unable to change your password" : "Não foi possível alterar a sua palavra-passe",
- "Current password" : "Palavra-passe atual",
- "New password" : "Nova palavra-passe",
- "Change password" : "Alterar palavra-passe",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Está a usar <strong>%s</strong> de <strong>%s</strong>",
+ "Profile picture" : "Foto do perfil",
+ "Upload new" : "Carregar novo",
+ "Select from Files" : "Seleccione dos Ficheiros",
+ "Remove image" : "Remover imagem",
+ "png or jpg, max. 20 MB" : "png ou jpg, máx. 20 MB",
+ "Picture provided by original account" : "Imagem fornecida pela conta original",
+ "Cancel" : "Cancelar",
+ "Choose as profile picture" : "Escolher como fotografia de perfil",
"Full name" : "Nome completo",
"No display name set" : "Nenhum nome display estabelecido",
"Email" : "Email",
"Your email address" : "O seu endereço de email",
- "Fill in an email address to enable password recovery and receive notifications" : "Preencha com um endereço e-mail para permitir a recuperação da palavra-passe e receber notificações",
+ "For password recovery and notifications" : "Para recuperação da palavra-passe e notificações",
"No email address set" : "Nenhum endereço de email estabelecido",
"You are member of the following groups:" : "Você é membro dos seguintes grupos:",
- "Profile picture" : "Foto do perfil",
- "Upload new" : "Carregar novo",
- "Select new from Files" : "Seleccionar novo a partir dos ficheiros",
- "Remove image" : "Remover imagem",
- "Your avatar is provided by your original account." : "O seu avatar é fornecido pela sua conta original.",
- "Cancel" : "Cancelar",
- "Choose as profile image" : "Escolha uma fotografia de perfil",
+ "Password" : "Palavra-passe",
+ "Unable to change your password" : "Não foi possível alterar a sua palavra-passe",
+ "Current password" : "Palavra-passe atual",
+ "New password" : "Nova palavra-passe",
+ "Change password" : "Alterar palavra-passe",
"Language" : "Idioma",
"Help translate" : "Ajude a traduzir",
- "Common Name" : "Nome Comum",
- "Valid until" : "Válido até",
- "Issued By" : "Emitido Por",
- "Valid until %s" : "Válido até %s",
- "Import root certificate" : "Importar certificado root",
+ "Get the apps to sync your files" : "Obtenha as aplicações para sincronizar os seus ficheiros",
+ "Desktop client" : "Cliente Desktop",
+ "Android app" : "Aplicação Android",
+ "iOS app" : "Aplicação iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Se quer apoiar o projecto\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">junte-se ao desenvolvimento</a>\n\t\tou\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">espalhe a palavra</a>!",
+ "Show First Run Wizard again" : "Mostrar novamente Wizard de Arranque Inicial",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Desenvolvido pela {communityopen}comunidade ownCloud{linkclose}, o {githubopen}código-fonte{linkclose} está licenciado sob a {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Mostrar a localização do armazenamento",
"Show last log in" : "Mostrar ultimo acesso de entrada",
diff --git a/settings/l10n/ro.js b/settings/l10n/ro.js
index b969fae1b60..bcdafb9e79d 100644
--- a/settings/l10n/ro.js
+++ b/settings/l10n/ro.js
@@ -8,11 +8,9 @@ OC.L10N.register(
"Log" : "Jurnal de activitate",
"Tips & tricks" : "Tips & tricks",
"Updates" : "Actualizări",
- "Authentication error" : "Eroare la autentificare",
- "Your full name has been changed." : "Numele tău complet a fost schimbat.",
- "Unable to change full name" : "Nu s-a puput schimba numele complet",
"Language changed" : "Limba a fost schimbată",
"Invalid request" : "Cerere eronată",
+ "Authentication error" : "Eroare la autentificare",
"Admins can't remove themself from the admin group" : "Administratorii nu se pot șterge singuri din grupul admin",
"Unable to add user to group %s" : "Nu s-a putut adăuga utilizatorul la grupul %s",
"Unable to remove user from group %s" : "Nu s-a putut elimina utilizatorul din grupul %s",
@@ -34,6 +32,8 @@ OC.L10N.register(
"Forbidden" : "Interzis",
"Invalid user" : "Utilizator nevalid",
"Email saved" : "E-mail salvat",
+ "Your full name has been changed." : "Numele tău complet a fost schimbat.",
+ "Unable to change full name" : "Nu s-a puput schimba numele complet",
"Sending..." : "Se expediază...",
"All" : "Toate ",
"Please wait...." : "Aşteptaţi vă rog....",
@@ -46,12 +46,12 @@ OC.L10N.register(
"Updated" : "Actualizat",
"Uninstalling ...." : "Dezinstalaza ....",
"Uninstall" : "Dezinstalați",
+ "Delete" : "Șterge",
"Select a profile picture" : "Selectează o imagine de profil",
"Very weak password" : "Parolă foarte slabă",
"Weak password" : "Parolă slabă",
"Good password" : "Parolă bună",
"Strong password" : "Parolă puternică",
- "Delete" : "Șterge",
"Groups" : "Grupuri",
"undo" : "Anulează ultima acțiune",
"never" : "niciodată",
@@ -60,7 +60,6 @@ OC.L10N.register(
"Error creating user" : "Eroare la crearea utilizatorului",
"A valid password must be provided" : "Trebuie să furnizaţi o parolă validă",
"__language_name__" : "_language_name_",
- "SSL root certificates" : "Certificate SSL root",
"None" : "Niciuna",
"Login" : "Autentificare",
"SSL" : "SSL",
@@ -82,32 +81,27 @@ OC.L10N.register(
"SMTP Password" : "Parolă SMTP",
"Test email settings" : "Verifică setările de e-mail",
"Send email" : "Expediază mesajul",
- "Log level" : "Nivel jurnal",
"More" : "Mai mult",
"Less" : "Mai puțin",
"Version" : "Versiunea",
- "by" : "după",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Ia acum aplicatia pentru sincronizarea fisierelor ",
- "Desktop client" : "Client Desktop",
- "Android app" : "Aplicatie Android",
- "iOS app" : "Aplicație iOS",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ați utilizat <strong>%s</strong> din <strong>%s</strong> disponibile",
+ "Profile picture" : "Imagine de profil",
+ "Upload new" : "Încarcă una nouă",
+ "Remove image" : "Înlătură imagine",
+ "Cancel" : "Anulare",
+ "Email" : "Email",
+ "Your email address" : "Adresa ta de email",
"Password" : "Parolă",
"Unable to change your password" : "Imposibil de-ați schimbat parola",
"Current password" : "Parola curentă",
"New password" : "Noua parolă",
"Change password" : "Schimbă parola",
- "Email" : "Email",
- "Your email address" : "Adresa ta de email",
- "Profile picture" : "Imagine de profil",
- "Upload new" : "Încarcă una nouă",
- "Select new from Files" : "Selectează una din Fișiere",
- "Remove image" : "Înlătură imagine",
- "Cancel" : "Anulare",
- "Choose as profile image" : "Alege drept imagine de profil",
"Language" : "Limba",
"Help translate" : "Ajută la traducere",
+ "Get the apps to sync your files" : "Ia acum aplicatia pentru sincronizarea fisierelor ",
+ "Desktop client" : "Client Desktop",
+ "Android app" : "Aplicatie Android",
+ "iOS app" : "Aplicație iOS",
"Username" : "Nume utilizator",
"Create" : "Crează",
"Admin Recovery Password" : "Parolă de recuperare a Administratorului",
diff --git a/settings/l10n/ro.json b/settings/l10n/ro.json
index 83c2572901d..f5247007a32 100644
--- a/settings/l10n/ro.json
+++ b/settings/l10n/ro.json
@@ -6,11 +6,9 @@
"Log" : "Jurnal de activitate",
"Tips & tricks" : "Tips & tricks",
"Updates" : "Actualizări",
- "Authentication error" : "Eroare la autentificare",
- "Your full name has been changed." : "Numele tău complet a fost schimbat.",
- "Unable to change full name" : "Nu s-a puput schimba numele complet",
"Language changed" : "Limba a fost schimbată",
"Invalid request" : "Cerere eronată",
+ "Authentication error" : "Eroare la autentificare",
"Admins can't remove themself from the admin group" : "Administratorii nu se pot șterge singuri din grupul admin",
"Unable to add user to group %s" : "Nu s-a putut adăuga utilizatorul la grupul %s",
"Unable to remove user from group %s" : "Nu s-a putut elimina utilizatorul din grupul %s",
@@ -32,6 +30,8 @@
"Forbidden" : "Interzis",
"Invalid user" : "Utilizator nevalid",
"Email saved" : "E-mail salvat",
+ "Your full name has been changed." : "Numele tău complet a fost schimbat.",
+ "Unable to change full name" : "Nu s-a puput schimba numele complet",
"Sending..." : "Se expediază...",
"All" : "Toate ",
"Please wait...." : "Aşteptaţi vă rog....",
@@ -44,12 +44,12 @@
"Updated" : "Actualizat",
"Uninstalling ...." : "Dezinstalaza ....",
"Uninstall" : "Dezinstalați",
+ "Delete" : "Șterge",
"Select a profile picture" : "Selectează o imagine de profil",
"Very weak password" : "Parolă foarte slabă",
"Weak password" : "Parolă slabă",
"Good password" : "Parolă bună",
"Strong password" : "Parolă puternică",
- "Delete" : "Șterge",
"Groups" : "Grupuri",
"undo" : "Anulează ultima acțiune",
"never" : "niciodată",
@@ -58,7 +58,6 @@
"Error creating user" : "Eroare la crearea utilizatorului",
"A valid password must be provided" : "Trebuie să furnizaţi o parolă validă",
"__language_name__" : "_language_name_",
- "SSL root certificates" : "Certificate SSL root",
"None" : "Niciuna",
"Login" : "Autentificare",
"SSL" : "SSL",
@@ -80,32 +79,27 @@
"SMTP Password" : "Parolă SMTP",
"Test email settings" : "Verifică setările de e-mail",
"Send email" : "Expediază mesajul",
- "Log level" : "Nivel jurnal",
"More" : "Mai mult",
"Less" : "Mai puțin",
"Version" : "Versiunea",
- "by" : "după",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Ia acum aplicatia pentru sincronizarea fisierelor ",
- "Desktop client" : "Client Desktop",
- "Android app" : "Aplicatie Android",
- "iOS app" : "Aplicație iOS",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ați utilizat <strong>%s</strong> din <strong>%s</strong> disponibile",
+ "Profile picture" : "Imagine de profil",
+ "Upload new" : "Încarcă una nouă",
+ "Remove image" : "Înlătură imagine",
+ "Cancel" : "Anulare",
+ "Email" : "Email",
+ "Your email address" : "Adresa ta de email",
"Password" : "Parolă",
"Unable to change your password" : "Imposibil de-ați schimbat parola",
"Current password" : "Parola curentă",
"New password" : "Noua parolă",
"Change password" : "Schimbă parola",
- "Email" : "Email",
- "Your email address" : "Adresa ta de email",
- "Profile picture" : "Imagine de profil",
- "Upload new" : "Încarcă una nouă",
- "Select new from Files" : "Selectează una din Fișiere",
- "Remove image" : "Înlătură imagine",
- "Cancel" : "Anulare",
- "Choose as profile image" : "Alege drept imagine de profil",
"Language" : "Limba",
"Help translate" : "Ajută la traducere",
+ "Get the apps to sync your files" : "Ia acum aplicatia pentru sincronizarea fisierelor ",
+ "Desktop client" : "Client Desktop",
+ "Android app" : "Aplicatie Android",
+ "iOS app" : "Aplicație iOS",
"Username" : "Nume utilizator",
"Create" : "Crează",
"Admin Recovery Password" : "Parolă de recuperare a Administratorului",
diff --git a/settings/l10n/ru.js b/settings/l10n/ru.js
index ab6621483a5..33697368a27 100644
--- a/settings/l10n/ru.js
+++ b/settings/l10n/ru.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Журнал",
"Tips & tricks" : "Советы и трюки",
"Updates" : "Обновления",
- "Authentication error" : "Ошибка аутентификации",
- "Your full name has been changed." : "Ваше полное имя было изменено.",
- "Unable to change full name" : "Невозможно изменить полное имя",
"Couldn't remove app." : "Невозможно удалить приложение.",
"Language changed" : "Язык изменён",
"Invalid request" : "Неправильный запрос",
+ "Authentication error" : "Ошибка аутентификации",
"Admins can't remove themself from the admin group" : "Администратор не может удалить сам себя из группы администраторов",
"Unable to add user to group %s" : "Невозможно добавить пользователя в группу %s",
"Unable to remove user from group %s" : "Невозможно удалить пользователя из группы %s",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Неверный пользователь",
"Unable to change mail address" : "Невозможно изменить адрес электронной почты",
"Email saved" : "Email сохранен",
+ "Your full name has been changed." : "Ваше полное имя было изменено.",
+ "Unable to change full name" : "Невозможно изменить полное имя",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Вы действительно хотите добавить домен \"{domain}\" как доверенный?",
"Add trusted domain" : "Добавить доверенный домен",
"Migration in progress. Please wait until the migration is finished" : "Миграция в процессе. Пожалуйста, подождите завершения миграции",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Приложение было включено и нуждается в обновлении. Вас перенаправит на страницу обновления через 5 секунд.",
"App update" : "Обновить приложения",
"No apps found for \"{query}\"" : "Не найдено приложений по вашему \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Произошла ошибка. Пожалуйста загрузите сертификат PEM в ASCII кодировке.",
+ "Valid until {date}" : "Действительно до {дата}",
+ "Delete" : "Удалить",
"An error occurred: {message}" : "Произошла ошибка: {message}",
"Select a profile picture" : "Выберите аватар",
"Very weak password" : "Очень слабый пароль",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Так себе пароль",
"Good password" : "Хороший пароль",
"Strong password" : "Стойкий пароль",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Произошла ошибка. Пожалуйста загрузите сертификат PEM в ASCII кодировке.",
- "Valid until {date}" : "Действительно до {дата}",
- "Delete" : "Удалить",
"Groups" : "Группы",
"Unable to delete {objName}" : "Невозможно удалить {objName}",
"Error creating group" : "Ошибка создания группы",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Должен быть указан правильный пароль",
"A valid email must be provided" : "Должен быть указан корректный адрес email",
"__language_name__" : "Русский",
- "Sync clients" : "Синхронизация клиентов",
"Personal info" : "Личная информация",
- "SSL root certificates" : "Корневые сертификаты SSL",
+ "Sync clients" : "Синхронизация клиентов",
"Everything (fatal issues, errors, warnings, info, debug)" : "Все (критические проблемы, ошибки, предупреждения, информационные, отладочные)",
"Info, warnings, errors and fatal issues" : "Информационные, предупреждения, ошибки и критические проблемы",
"Warnings, errors and fatal issues" : "Предупреждения, ошибки и критические проблемы",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Мы рекомендуем установить требуемые пакеты для вашей системы для поддержки одного из следующих языков: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Если ваша копия ownCloud установлена не в корне домена и использует системный планировщик cron, возможны проблемы с правильной генерацией URL. Чтобы избежать этого, установите опцию \"overwrite.cli.url\" в файле config.php равной пути папки установки. (Предположительно: \"%s\".)",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Не удается запустить задачу планировщика через CLI. Произошли следующие технические ошибки:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Механизм блокировки файлов во время передачи основан на базе данных, для лучшей производительности рекомендуется использование memcache. За подробной информацией обратитесь к <a target=\"_blank\" href=\"%s\">документации</a>.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Пожалуйста, перепроверьте <a href=\"%s\">инструкцию по установке</a> и проверьте ошибки или предупреждения в <a href=\"#log-section\">журнале</a>",
"All checks passed." : "Все проверки пройдены.",
"Open documentation" : "Открыть документацию",
@@ -188,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Сохранить учётные данные",
"Test email settings" : "Проверить настройки почты",
"Send email" : "Отправить email",
- "Log level" : "Уровень детализации журнала",
"Download logfile" : "Скачать журнал",
"More" : "Больше",
"Less" : "Меньше",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Лог-файл - больше 100 мб. Его скачивание может занять некоторое время!",
+ "What to log" : "Что записывать в журнал",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "В качестве базы данных используется SQLite. Для больших установок мы рекомендуем переключиться на другую серверную базу данных.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Особенно вызывает сомнение использование SQLite при синхронизации файлов с использование клиента для ПК.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Для перехода на другую базу данных используйте команду: 'occ db:convert-type' или ознакомьтесь с <a target=\"_blank\" href=\"%s\">документацией ↗</a>.",
@@ -206,17 +204,25 @@ OC.L10N.register(
"Developer documentation" : "Документация для разработчиков",
"Experimental applications ahead" : "Экспериментальные приложения",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Экспериментальные приложения не проверялись на наличие уязвимостей безопасности, они также могут быть нестабильны, т.к. находятся в активной разработке. Их установка может повлечь потерю информации или нарушение безопасности.",
- "by" : "автор",
- "licensed" : "Лицензировано",
+ "by %s" : "от %s",
+ "%s-licensed" : "Лицензия %s",
"Documentation:" : "Документация:",
"User documentation" : "Пользовательская документация",
"Admin documentation" : "Документация для администратора",
"Show description …" : "Показать описание ...",
"Hide description …" : "Скрыть описание ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Для этого приложения не указана минимальная версия ownClowd. Будет считаться ошибкой начиная с версии ownClowd 11.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Для этого приложения не указана максимальная версия ownClowd. Будет считаться ошибкой начиная с версии ownClowd 11.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Приложение не может быть установлено, следующие зависимости не удовлетворены:",
"Enable only for specific groups" : "Включить только для этих групп",
"Uninstall App" : "Удалить приложение",
"Enable experimental apps" : "Включить экспериментальные приложения",
+ "SSL Root Certificates" : "Корневые сертификаты SSL",
+ "Common Name" : "Общее Имя",
+ "Valid until" : "Действительно до",
+ "Issued By" : "Выдан",
+ "Valid until %s" : "Действительно до %s",
+ "Import root certificate" : "Импорт корневого сертификата",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Здравствуйте,<br><br>просто хотим сообщить, что теперь у вас есть учетная запись на %s.<br><br>Ваше имя пользователя: %s<br>Зайти: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Удачи!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Здравствуйте,\n\nПросто хотим сообщить, что теперь у вас есть учетная запись на %s.\n\nИмя пользователя: %s\nЗайти: %s\n",
@@ -225,40 +231,35 @@ OC.L10N.register(
"Forum" : "Форум",
"Issue tracker" : "трекер проблем",
"Commercial support" : "Коммерческая поддержка",
- "Get the apps to sync your files" : "Получить приложения для синхронизации ваших файлов",
- "Desktop client" : "Клиент для ПК",
- "Android app" : "Android приложение",
- "iOS app" : "iOS приложение",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Если Вы хотите поддержать проект\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">совместная разработка</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">сообщить</a>!",
- "Show First Run Wizard again" : "Показать помощник настройки снова",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Вы использовали <strong>%s</strong> из доступных <strong>%s</strong>",
- "Password" : "Пароль",
- "Unable to change your password" : "Невозможно сменить пароль",
- "Current password" : "Текущий пароль",
- "New password" : "Новый пароль",
- "Change password" : "Сменить пароль",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Вы используете <strong>%s</strong> из <strong>%s</strong>",
+ "Profile picture" : "Аватар",
+ "Upload new" : "Загрузить новый",
+ "Select from Files" : "Выбрать из Файлов",
+ "Remove image" : "Удалить аватар",
+ "png or jpg, max. 20 MB" : "png или jpg, макс. 20 МБ",
+ "Picture provided by original account" : "Картинка из исходной учетной записи",
+ "Cancel" : "Отмена",
+ "Choose as profile picture" : "Выбрать в качестве картинки профиля",
"Full name" : "Полное имя",
"No display name set" : "Отображаемое имя не указано",
"Email" : "E-mail",
"Your email address" : "Ваш адрес электронной почты",
- "Fill in an email address to enable password recovery and receive notifications" : "Введите свой email-адрес для того, чтобы включить возможность восстановления пароля и получения уведомлений",
+ "For password recovery and notifications" : "Для восстановления пароля и уведомлений",
"No email address set" : "E-mail не указан",
"You are member of the following groups:" : "Вы являетесь членом следующих групп:",
- "Profile picture" : "Аватар",
- "Upload new" : "Загрузить новый",
- "Select new from Files" : "Выберите новый из файлов",
- "Remove image" : "Удалить аватар",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Допустимые форматы: png и jpg. В идеале квадратное, но Вы сможете обрезать его. Файл не должен превышать максимальный размер в 20 МБ.",
- "Your avatar is provided by your original account." : "Будет использован аватар вашей оригинальной учетной записи.",
- "Cancel" : "Отмена",
- "Choose as profile image" : "Установить как аватар",
+ "Password" : "Пароль",
+ "Unable to change your password" : "Невозможно сменить пароль",
+ "Current password" : "Текущий пароль",
+ "New password" : "Новый пароль",
+ "Change password" : "Сменить пароль",
"Language" : "Язык",
"Help translate" : "Помочь с переводом",
- "Common Name" : "Общее Имя",
- "Valid until" : "Действительно до",
- "Issued By" : "Выдан",
- "Valid until %s" : "Действительно до %s",
- "Import root certificate" : "Импорт корневого сертификата",
+ "Get the apps to sync your files" : "Получить приложения для синхронизации ваших файлов",
+ "Desktop client" : "Клиент для ПК",
+ "Android app" : "Android приложение",
+ "iOS app" : "iOS приложение",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Если Вы хотите поддержать проект\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">совместная разработка</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">сообщить</a>!",
+ "Show First Run Wizard again" : "Показать помощник настройки снова",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Разработано {communityopen}сообществом ownCloud{linkclose}, {githubopen}исходный код{linkclose} лицензируется в соответствии с{licenseopen}<abbr title=\"Публичной лицензией Affero General\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Показать местонахождение хранилища",
"Show last log in" : "Показать последний вход в систему",
diff --git a/settings/l10n/ru.json b/settings/l10n/ru.json
index 21bb4044ba2..959588abf57 100644
--- a/settings/l10n/ru.json
+++ b/settings/l10n/ru.json
@@ -10,12 +10,10 @@
"Log" : "Журнал",
"Tips & tricks" : "Советы и трюки",
"Updates" : "Обновления",
- "Authentication error" : "Ошибка аутентификации",
- "Your full name has been changed." : "Ваше полное имя было изменено.",
- "Unable to change full name" : "Невозможно изменить полное имя",
"Couldn't remove app." : "Невозможно удалить приложение.",
"Language changed" : "Язык изменён",
"Invalid request" : "Неправильный запрос",
+ "Authentication error" : "Ошибка аутентификации",
"Admins can't remove themself from the admin group" : "Администратор не может удалить сам себя из группы администраторов",
"Unable to add user to group %s" : "Невозможно добавить пользователя в группу %s",
"Unable to remove user from group %s" : "Невозможно удалить пользователя из группы %s",
@@ -51,6 +49,8 @@
"Invalid user" : "Неверный пользователь",
"Unable to change mail address" : "Невозможно изменить адрес электронной почты",
"Email saved" : "Email сохранен",
+ "Your full name has been changed." : "Ваше полное имя было изменено.",
+ "Unable to change full name" : "Невозможно изменить полное имя",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Вы действительно хотите добавить домен \"{domain}\" как доверенный?",
"Add trusted domain" : "Добавить доверенный домен",
"Migration in progress. Please wait until the migration is finished" : "Миграция в процессе. Пожалуйста, подождите завершения миграции",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Приложение было включено и нуждается в обновлении. Вас перенаправит на страницу обновления через 5 секунд.",
"App update" : "Обновить приложения",
"No apps found for \"{query}\"" : "Не найдено приложений по вашему \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Произошла ошибка. Пожалуйста загрузите сертификат PEM в ASCII кодировке.",
+ "Valid until {date}" : "Действительно до {дата}",
+ "Delete" : "Удалить",
"An error occurred: {message}" : "Произошла ошибка: {message}",
"Select a profile picture" : "Выберите аватар",
"Very weak password" : "Очень слабый пароль",
@@ -86,9 +89,6 @@
"So-so password" : "Так себе пароль",
"Good password" : "Хороший пароль",
"Strong password" : "Стойкий пароль",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Произошла ошибка. Пожалуйста загрузите сертификат PEM в ASCII кодировке.",
- "Valid until {date}" : "Действительно до {дата}",
- "Delete" : "Удалить",
"Groups" : "Группы",
"Unable to delete {objName}" : "Невозможно удалить {objName}",
"Error creating group" : "Ошибка создания группы",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "Должен быть указан правильный пароль",
"A valid email must be provided" : "Должен быть указан корректный адрес email",
"__language_name__" : "Русский",
- "Sync clients" : "Синхронизация клиентов",
"Personal info" : "Личная информация",
- "SSL root certificates" : "Корневые сертификаты SSL",
+ "Sync clients" : "Синхронизация клиентов",
"Everything (fatal issues, errors, warnings, info, debug)" : "Все (критические проблемы, ошибки, предупреждения, информационные, отладочные)",
"Info, warnings, errors and fatal issues" : "Информационные, предупреждения, ошибки и критические проблемы",
"Warnings, errors and fatal issues" : "Предупреждения, ошибки и критические проблемы",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Мы рекомендуем установить требуемые пакеты для вашей системы для поддержки одного из следующих языков: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Если ваша копия ownCloud установлена не в корне домена и использует системный планировщик cron, возможны проблемы с правильной генерацией URL. Чтобы избежать этого, установите опцию \"overwrite.cli.url\" в файле config.php равной пути папки установки. (Предположительно: \"%s\".)",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Не удается запустить задачу планировщика через CLI. Произошли следующие технические ошибки:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Механизм блокировки файлов во время передачи основан на базе данных, для лучшей производительности рекомендуется использование memcache. За подробной информацией обратитесь к <a target=\"_blank\" href=\"%s\">документации</a>.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Пожалуйста, перепроверьте <a href=\"%s\">инструкцию по установке</a> и проверьте ошибки или предупреждения в <a href=\"#log-section\">журнале</a>",
"All checks passed." : "Все проверки пройдены.",
"Open documentation" : "Открыть документацию",
@@ -186,11 +184,11 @@
"Store credentials" : "Сохранить учётные данные",
"Test email settings" : "Проверить настройки почты",
"Send email" : "Отправить email",
- "Log level" : "Уровень детализации журнала",
"Download logfile" : "Скачать журнал",
"More" : "Больше",
"Less" : "Меньше",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Лог-файл - больше 100 мб. Его скачивание может занять некоторое время!",
+ "What to log" : "Что записывать в журнал",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "В качестве базы данных используется SQLite. Для больших установок мы рекомендуем переключиться на другую серверную базу данных.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Особенно вызывает сомнение использование SQLite при синхронизации файлов с использование клиента для ПК.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Для перехода на другую базу данных используйте команду: 'occ db:convert-type' или ознакомьтесь с <a target=\"_blank\" href=\"%s\">документацией ↗</a>.",
@@ -204,17 +202,25 @@
"Developer documentation" : "Документация для разработчиков",
"Experimental applications ahead" : "Экспериментальные приложения",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Экспериментальные приложения не проверялись на наличие уязвимостей безопасности, они также могут быть нестабильны, т.к. находятся в активной разработке. Их установка может повлечь потерю информации или нарушение безопасности.",
- "by" : "автор",
- "licensed" : "Лицензировано",
+ "by %s" : "от %s",
+ "%s-licensed" : "Лицензия %s",
"Documentation:" : "Документация:",
"User documentation" : "Пользовательская документация",
"Admin documentation" : "Документация для администратора",
"Show description …" : "Показать описание ...",
"Hide description …" : "Скрыть описание ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Для этого приложения не указана минимальная версия ownClowd. Будет считаться ошибкой начиная с версии ownClowd 11.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Для этого приложения не указана максимальная версия ownClowd. Будет считаться ошибкой начиная с версии ownClowd 11.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Приложение не может быть установлено, следующие зависимости не удовлетворены:",
"Enable only for specific groups" : "Включить только для этих групп",
"Uninstall App" : "Удалить приложение",
"Enable experimental apps" : "Включить экспериментальные приложения",
+ "SSL Root Certificates" : "Корневые сертификаты SSL",
+ "Common Name" : "Общее Имя",
+ "Valid until" : "Действительно до",
+ "Issued By" : "Выдан",
+ "Valid until %s" : "Действительно до %s",
+ "Import root certificate" : "Импорт корневого сертификата",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Здравствуйте,<br><br>просто хотим сообщить, что теперь у вас есть учетная запись на %s.<br><br>Ваше имя пользователя: %s<br>Зайти: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Удачи!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Здравствуйте,\n\nПросто хотим сообщить, что теперь у вас есть учетная запись на %s.\n\nИмя пользователя: %s\nЗайти: %s\n",
@@ -223,40 +229,35 @@
"Forum" : "Форум",
"Issue tracker" : "трекер проблем",
"Commercial support" : "Коммерческая поддержка",
- "Get the apps to sync your files" : "Получить приложения для синхронизации ваших файлов",
- "Desktop client" : "Клиент для ПК",
- "Android app" : "Android приложение",
- "iOS app" : "iOS приложение",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Если Вы хотите поддержать проект\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">совместная разработка</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">сообщить</a>!",
- "Show First Run Wizard again" : "Показать помощник настройки снова",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Вы использовали <strong>%s</strong> из доступных <strong>%s</strong>",
- "Password" : "Пароль",
- "Unable to change your password" : "Невозможно сменить пароль",
- "Current password" : "Текущий пароль",
- "New password" : "Новый пароль",
- "Change password" : "Сменить пароль",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Вы используете <strong>%s</strong> из <strong>%s</strong>",
+ "Profile picture" : "Аватар",
+ "Upload new" : "Загрузить новый",
+ "Select from Files" : "Выбрать из Файлов",
+ "Remove image" : "Удалить аватар",
+ "png or jpg, max. 20 MB" : "png или jpg, макс. 20 МБ",
+ "Picture provided by original account" : "Картинка из исходной учетной записи",
+ "Cancel" : "Отмена",
+ "Choose as profile picture" : "Выбрать в качестве картинки профиля",
"Full name" : "Полное имя",
"No display name set" : "Отображаемое имя не указано",
"Email" : "E-mail",
"Your email address" : "Ваш адрес электронной почты",
- "Fill in an email address to enable password recovery and receive notifications" : "Введите свой email-адрес для того, чтобы включить возможность восстановления пароля и получения уведомлений",
+ "For password recovery and notifications" : "Для восстановления пароля и уведомлений",
"No email address set" : "E-mail не указан",
"You are member of the following groups:" : "Вы являетесь членом следующих групп:",
- "Profile picture" : "Аватар",
- "Upload new" : "Загрузить новый",
- "Select new from Files" : "Выберите новый из файлов",
- "Remove image" : "Удалить аватар",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Допустимые форматы: png и jpg. В идеале квадратное, но Вы сможете обрезать его. Файл не должен превышать максимальный размер в 20 МБ.",
- "Your avatar is provided by your original account." : "Будет использован аватар вашей оригинальной учетной записи.",
- "Cancel" : "Отмена",
- "Choose as profile image" : "Установить как аватар",
+ "Password" : "Пароль",
+ "Unable to change your password" : "Невозможно сменить пароль",
+ "Current password" : "Текущий пароль",
+ "New password" : "Новый пароль",
+ "Change password" : "Сменить пароль",
"Language" : "Язык",
"Help translate" : "Помочь с переводом",
- "Common Name" : "Общее Имя",
- "Valid until" : "Действительно до",
- "Issued By" : "Выдан",
- "Valid until %s" : "Действительно до %s",
- "Import root certificate" : "Импорт корневого сертификата",
+ "Get the apps to sync your files" : "Получить приложения для синхронизации ваших файлов",
+ "Desktop client" : "Клиент для ПК",
+ "Android app" : "Android приложение",
+ "iOS app" : "iOS приложение",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Если Вы хотите поддержать проект\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">совместная разработка</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">сообщить</a>!",
+ "Show First Run Wizard again" : "Показать помощник настройки снова",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Разработано {communityopen}сообществом ownCloud{linkclose}, {githubopen}исходный код{linkclose} лицензируется в соответствии с{licenseopen}<abbr title=\"Публичной лицензией Affero General\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Показать местонахождение хранилища",
"Show last log in" : "Показать последний вход в систему",
diff --git a/settings/l10n/si_LK.js b/settings/l10n/si_LK.js
index 8dc28f5ab1f..4ae34d559f5 100644
--- a/settings/l10n/si_LK.js
+++ b/settings/l10n/si_LK.js
@@ -4,9 +4,9 @@ OC.L10N.register(
"Sharing" : "හුවමාරු කිරීම",
"External Storage" : "භාහිර ගබඩාව",
"Log" : "ලඝුව",
- "Authentication error" : "සත්‍යාපන දෝෂයක්",
"Language changed" : "භාෂාව ාවනස් කිරීම",
"Invalid request" : "අවලංගු අයැදුමක්",
+ "Authentication error" : "සත්‍යාපන දෝෂයක්",
"Unable to add user to group %s" : "පරිශීලකයා %s කණ්ඩායමට එකතු කළ නොහැක",
"Unable to remove user from group %s" : "පරිශීලකයා %s කණ්ඩායමින් ඉවත් කළ නොහැක",
"Email saved" : "වි-තැපෑල සුරකින ලදී",
@@ -17,7 +17,6 @@ OC.L10N.register(
"Groups" : "කණ්ඩායම්",
"undo" : "නිෂ්ප්‍රභ කරන්න",
"never" : "කවදාවත්",
- "SSL root certificates" : "SSL මූල සහතිකයන්",
"None" : "කිසිවක් නැත",
"Login" : "ප්‍රවිශ්ටය",
"Allow resharing" : "යළි යළිත් හුවමාරුවට අවසර දෙමි",
@@ -26,15 +25,14 @@ OC.L10N.register(
"Port" : "තොට",
"More" : "වැඩි",
"Less" : "අඩු",
- "by" : "විසින්",
+ "Cancel" : "එපා",
+ "Email" : "විද්‍යුත් තැපෑල",
+ "Your email address" : "ඔබගේ විද්‍යුත් තැපෑල",
"Password" : "මුර පදය",
"Unable to change your password" : "මුර පදය වෙනස් කළ නොහැකි විය",
"Current password" : "වත්මන් මුරපදය",
"New password" : "නව මුරපදය",
"Change password" : "මුරපදය වෙනස් කිරීම",
- "Email" : "විද්‍යුත් තැපෑල",
- "Your email address" : "ඔබගේ විද්‍යුත් තැපෑල",
- "Cancel" : "එපා",
"Language" : "භාෂාව",
"Help translate" : "පරිවර්ථන සහය",
"Username" : "පරිශීලක නම",
diff --git a/settings/l10n/si_LK.json b/settings/l10n/si_LK.json
index afded14ebf1..06647a07688 100644
--- a/settings/l10n/si_LK.json
+++ b/settings/l10n/si_LK.json
@@ -2,9 +2,9 @@
"Sharing" : "හුවමාරු කිරීම",
"External Storage" : "භාහිර ගබඩාව",
"Log" : "ලඝුව",
- "Authentication error" : "සත්‍යාපන දෝෂයක්",
"Language changed" : "භාෂාව ාවනස් කිරීම",
"Invalid request" : "අවලංගු අයැදුමක්",
+ "Authentication error" : "සත්‍යාපන දෝෂයක්",
"Unable to add user to group %s" : "පරිශීලකයා %s කණ්ඩායමට එකතු කළ නොහැක",
"Unable to remove user from group %s" : "පරිශීලකයා %s කණ්ඩායමින් ඉවත් කළ නොහැක",
"Email saved" : "වි-තැපෑල සුරකින ලදී",
@@ -15,7 +15,6 @@
"Groups" : "කණ්ඩායම්",
"undo" : "නිෂ්ප්‍රභ කරන්න",
"never" : "කවදාවත්",
- "SSL root certificates" : "SSL මූල සහතිකයන්",
"None" : "කිසිවක් නැත",
"Login" : "ප්‍රවිශ්ටය",
"Allow resharing" : "යළි යළිත් හුවමාරුවට අවසර දෙමි",
@@ -24,15 +23,14 @@
"Port" : "තොට",
"More" : "වැඩි",
"Less" : "අඩු",
- "by" : "විසින්",
+ "Cancel" : "එපා",
+ "Email" : "විද්‍යුත් තැපෑල",
+ "Your email address" : "ඔබගේ විද්‍යුත් තැපෑල",
"Password" : "මුර පදය",
"Unable to change your password" : "මුර පදය වෙනස් කළ නොහැකි විය",
"Current password" : "වත්මන් මුරපදය",
"New password" : "නව මුරපදය",
"Change password" : "මුරපදය වෙනස් කිරීම",
- "Email" : "විද්‍යුත් තැපෑල",
- "Your email address" : "ඔබගේ විද්‍යුත් තැපෑල",
- "Cancel" : "එපා",
"Language" : "භාෂාව",
"Help translate" : "පරිවර්ථන සහය",
"Username" : "පරිශීලක නම",
diff --git a/settings/l10n/sk_SK.js b/settings/l10n/sk_SK.js
index 66332871bb0..06f8fd6bc37 100644
--- a/settings/l10n/sk_SK.js
+++ b/settings/l10n/sk_SK.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Záznam",
"Tips & tricks" : "Tipy a triky",
"Updates" : "Aktualizácie",
- "Authentication error" : "Chyba autentifikácie",
- "Your full name has been changed." : "Vaše meno a priezvisko bolo zmenené.",
- "Unable to change full name" : "Nemožno zmeniť meno a priezvisko",
"Couldn't remove app." : "Nemožno odstrániť aplikáciu.",
"Language changed" : "Jazyk zmenený",
"Invalid request" : "Neplatná požiadavka",
+ "Authentication error" : "Chyba autentifikácie",
"Admins can't remove themself from the admin group" : "Administrátori nesmú odstrániť sami seba zo skupiny admin",
"Unable to add user to group %s" : "Nie je možné pridať používateľa do skupiny %s",
"Unable to remove user from group %s" : "Nie je možné odstrániť používateľa zo skupiny %s",
@@ -51,6 +49,8 @@ OC.L10N.register(
"Invalid user" : "Neplatný používateľ",
"Unable to change mail address" : "Nemožno zmeniť emailovú adresu",
"Email saved" : "Email uložený",
+ "Your full name has been changed." : "Vaše meno a priezvisko bolo zmenené.",
+ "Unable to change full name" : "Nemožno zmeniť meno a priezvisko",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ste si istí, že chcete pridať \"{domain}\" medzi dôveryhodné domény?",
"Add trusted domain" : "Pridať dôveryhodnú doménu",
"Migration in progress. Please wait until the migration is finished" : "Prebieha migrácia. Počkajte prosím, kým sa skončí",
@@ -73,14 +73,14 @@ OC.L10N.register(
"Uninstalling ...." : "Prebieha odinštalovanie...",
"Error while uninstalling app" : "Chyba pri odinštalovaní aplikácie",
"Uninstall" : "Odinštalácia",
+ "Valid until {date}" : "Platný do {date}",
+ "Delete" : "Zmazať",
"Select a profile picture" : "Vybrať avatara",
"Very weak password" : "Veľmi slabé heslo",
"Weak password" : "Slabé heslo",
"So-so password" : "Priemerné heslo",
"Good password" : "Dobré heslo",
"Strong password" : "Silné heslo",
- "Valid until {date}" : "Platný do {date}",
- "Delete" : "Zmazať",
"Groups" : "Skupiny",
"Unable to delete {objName}" : "Nemožno vymazať {objName}",
"Error creating group" : "Chyba pri vytváraní skupiny",
@@ -97,9 +97,8 @@ OC.L10N.register(
"A valid password must be provided" : "Musíte zadať platné heslo",
"A valid email must be provided" : "Musíte zadať platnú emailovú adresu",
"__language_name__" : "Slovensky",
- "Sync clients" : "Klienti synchronizácie",
"Personal info" : "Osobné informácie",
- "SSL root certificates" : "Koreňové SSL certifikáty",
+ "Sync clients" : "Klienti synchronizácie",
"Everything (fatal issues, errors, warnings, info, debug)" : "Všetko (fatálne problémy, chyby, upozornenia, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, upozornenia, chyby a fatálne problémy",
"Warnings, errors and fatal issues" : "Upozornenia, chyby a fatálne problémy",
@@ -160,7 +159,6 @@ OC.L10N.register(
"Store credentials" : "Ukladať prihlasovacie údaje",
"Test email settings" : "Nastavenia testovacieho emailu",
"Send email" : "Odoslať email",
- "Log level" : "Úroveň záznamu",
"Download logfile" : "Stiahnuť súbor logu",
"More" : "Viac",
"Less" : "Menej",
@@ -177,8 +175,6 @@ OC.L10N.register(
"Developer documentation" : "Dokumentácia vývojára",
"Experimental applications ahead" : "Experimentálna aplikácia v poradí",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentálne aplikácie nie sú preverované na bezpečnostné chyby, môžu byť nestabilné a veľmi sa meniť. Ich inštaláciou môžete spôsobiť stratu dát alebo bezpečnostné problémy.",
- "by" : "od",
- "licensed" : "licencované",
"Documentation:" : "Dokumentácia:",
"User documentation" : "Príručka používateľa",
"Admin documentation" : "Príručka administrátora",
@@ -188,6 +184,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Povoliť len pre vybrané skupiny",
"Uninstall App" : "Odinštalovanie aplikácie",
"Enable experimental apps" : "Povoliť experimentálne aplikácie",
+ "Common Name" : "Bežný názov",
+ "Valid until" : "Platný do",
+ "Issued By" : "Vydal",
+ "Valid until %s" : "Platný do %s",
+ "Import root certificate" : "Importovať koreňový certifikát",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Dobrý deň,<br><br>toto je oznámenie o novo vytvorenom účte %s.<br><br>Vaše používateľské meno: %s<br>Prihlásiť sa môžete tu: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Pekný deň!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ahoj,\n\ntoto je oznámenie o novo vytvorenom účte %s.\n\nVaše používateľské meno: %s\nPrihlásiť sa môžete tu: %s\n\n",
@@ -196,39 +197,29 @@ OC.L10N.register(
"Forum" : "Fórum",
"Issue tracker" : "Zoznam chýb",
"Commercial support" : "Komerčná podpora",
- "Get the apps to sync your files" : "Získať aplikácie na synchronizáciu vašich súborov",
- "Desktop client" : "Desktopový klient",
- "Android app" : "Android aplikácia",
- "iOS app" : "iOS aplikácia",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ak chcete projekt podporiť,\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">zapojte sa do vývoja</a>\n\t\talebo\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ho propagujte</a>!",
- "Show First Run Wizard again" : "Znovu zobraziť sprievodcu prvým spustením",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Použili ste <strong>%s</strong> z <strong>%s</strong> dostupných ",
- "Password" : "Heslo",
- "Unable to change your password" : "Nie je možné zmeniť vaše heslo",
- "Current password" : "Aktuálne heslo",
- "New password" : "Nové heslo",
- "Change password" : "Zmeniť heslo",
+ "Profile picture" : "Avatar",
+ "Upload new" : "Nahrať nový",
+ "Remove image" : "Zmazať obrázok",
+ "Cancel" : "Zrušiť",
"Full name" : "Meno a priezvisko",
"No display name set" : "Zobrazované meno nie je nastavené",
"Email" : "Email",
"Your email address" : "Vaša emailová adresa",
- "Fill in an email address to enable password recovery and receive notifications" : "Zadajte emailovú adresu pre umožnenie obnovy zabudnutého hesla a pre prijímanie upozornení a oznámení",
"No email address set" : "Emailová adresa nie je nastavená",
"You are member of the following groups:" : "Ste členom nasledovných skupín:",
- "Profile picture" : "Avatar",
- "Upload new" : "Nahrať nový",
- "Select new from Files" : "Vyberte nový zo súborov",
- "Remove image" : "Zmazať obrázok",
- "Your avatar is provided by your original account." : "Váš avatar je použitý z pôvodného účtu.",
- "Cancel" : "Zrušiť",
- "Choose as profile image" : "Vybrať ako avatara",
+ "Password" : "Heslo",
+ "Unable to change your password" : "Nie je možné zmeniť vaše heslo",
+ "Current password" : "Aktuálne heslo",
+ "New password" : "Nové heslo",
+ "Change password" : "Zmeniť heslo",
"Language" : "Jazyk",
"Help translate" : "Pomôcť s prekladom",
- "Common Name" : "Bežný názov",
- "Valid until" : "Platný do",
- "Issued By" : "Vydal",
- "Valid until %s" : "Platný do %s",
- "Import root certificate" : "Importovať koreňový certifikát",
+ "Get the apps to sync your files" : "Získať aplikácie na synchronizáciu vašich súborov",
+ "Desktop client" : "Desktopový klient",
+ "Android app" : "Android aplikácia",
+ "iOS app" : "iOS aplikácia",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ak chcete projekt podporiť,\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">zapojte sa do vývoja</a>\n\t\talebo\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ho propagujte</a>!",
+ "Show First Run Wizard again" : "Znovu zobraziť sprievodcu prvým spustením",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Vyvinula {communityopen}komunita ownCloud{linkclose}. {githubopen}Zdrojový kód{linkclose} je dostupný za podmienok licencie {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Zobraziť umiestnenie úložiska",
"Show last log in" : "Zobraziť posledné prihlásenie",
diff --git a/settings/l10n/sk_SK.json b/settings/l10n/sk_SK.json
index 6cfe691ee75..f346de65508 100644
--- a/settings/l10n/sk_SK.json
+++ b/settings/l10n/sk_SK.json
@@ -10,12 +10,10 @@
"Log" : "Záznam",
"Tips & tricks" : "Tipy a triky",
"Updates" : "Aktualizácie",
- "Authentication error" : "Chyba autentifikácie",
- "Your full name has been changed." : "Vaše meno a priezvisko bolo zmenené.",
- "Unable to change full name" : "Nemožno zmeniť meno a priezvisko",
"Couldn't remove app." : "Nemožno odstrániť aplikáciu.",
"Language changed" : "Jazyk zmenený",
"Invalid request" : "Neplatná požiadavka",
+ "Authentication error" : "Chyba autentifikácie",
"Admins can't remove themself from the admin group" : "Administrátori nesmú odstrániť sami seba zo skupiny admin",
"Unable to add user to group %s" : "Nie je možné pridať používateľa do skupiny %s",
"Unable to remove user from group %s" : "Nie je možné odstrániť používateľa zo skupiny %s",
@@ -49,6 +47,8 @@
"Invalid user" : "Neplatný používateľ",
"Unable to change mail address" : "Nemožno zmeniť emailovú adresu",
"Email saved" : "Email uložený",
+ "Your full name has been changed." : "Vaše meno a priezvisko bolo zmenené.",
+ "Unable to change full name" : "Nemožno zmeniť meno a priezvisko",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ste si istí, že chcete pridať \"{domain}\" medzi dôveryhodné domény?",
"Add trusted domain" : "Pridať dôveryhodnú doménu",
"Migration in progress. Please wait until the migration is finished" : "Prebieha migrácia. Počkajte prosím, kým sa skončí",
@@ -71,14 +71,14 @@
"Uninstalling ...." : "Prebieha odinštalovanie...",
"Error while uninstalling app" : "Chyba pri odinštalovaní aplikácie",
"Uninstall" : "Odinštalácia",
+ "Valid until {date}" : "Platný do {date}",
+ "Delete" : "Zmazať",
"Select a profile picture" : "Vybrať avatara",
"Very weak password" : "Veľmi slabé heslo",
"Weak password" : "Slabé heslo",
"So-so password" : "Priemerné heslo",
"Good password" : "Dobré heslo",
"Strong password" : "Silné heslo",
- "Valid until {date}" : "Platný do {date}",
- "Delete" : "Zmazať",
"Groups" : "Skupiny",
"Unable to delete {objName}" : "Nemožno vymazať {objName}",
"Error creating group" : "Chyba pri vytváraní skupiny",
@@ -95,9 +95,8 @@
"A valid password must be provided" : "Musíte zadať platné heslo",
"A valid email must be provided" : "Musíte zadať platnú emailovú adresu",
"__language_name__" : "Slovensky",
- "Sync clients" : "Klienti synchronizácie",
"Personal info" : "Osobné informácie",
- "SSL root certificates" : "Koreňové SSL certifikáty",
+ "Sync clients" : "Klienti synchronizácie",
"Everything (fatal issues, errors, warnings, info, debug)" : "Všetko (fatálne problémy, chyby, upozornenia, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, upozornenia, chyby a fatálne problémy",
"Warnings, errors and fatal issues" : "Upozornenia, chyby a fatálne problémy",
@@ -158,7 +157,6 @@
"Store credentials" : "Ukladať prihlasovacie údaje",
"Test email settings" : "Nastavenia testovacieho emailu",
"Send email" : "Odoslať email",
- "Log level" : "Úroveň záznamu",
"Download logfile" : "Stiahnuť súbor logu",
"More" : "Viac",
"Less" : "Menej",
@@ -175,8 +173,6 @@
"Developer documentation" : "Dokumentácia vývojára",
"Experimental applications ahead" : "Experimentálna aplikácia v poradí",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentálne aplikácie nie sú preverované na bezpečnostné chyby, môžu byť nestabilné a veľmi sa meniť. Ich inštaláciou môžete spôsobiť stratu dát alebo bezpečnostné problémy.",
- "by" : "od",
- "licensed" : "licencované",
"Documentation:" : "Dokumentácia:",
"User documentation" : "Príručka používateľa",
"Admin documentation" : "Príručka administrátora",
@@ -186,6 +182,11 @@
"Enable only for specific groups" : "Povoliť len pre vybrané skupiny",
"Uninstall App" : "Odinštalovanie aplikácie",
"Enable experimental apps" : "Povoliť experimentálne aplikácie",
+ "Common Name" : "Bežný názov",
+ "Valid until" : "Platný do",
+ "Issued By" : "Vydal",
+ "Valid until %s" : "Platný do %s",
+ "Import root certificate" : "Importovať koreňový certifikát",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Dobrý deň,<br><br>toto je oznámenie o novo vytvorenom účte %s.<br><br>Vaše používateľské meno: %s<br>Prihlásiť sa môžete tu: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Pekný deň!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Ahoj,\n\ntoto je oznámenie o novo vytvorenom účte %s.\n\nVaše používateľské meno: %s\nPrihlásiť sa môžete tu: %s\n\n",
@@ -194,39 +195,29 @@
"Forum" : "Fórum",
"Issue tracker" : "Zoznam chýb",
"Commercial support" : "Komerčná podpora",
- "Get the apps to sync your files" : "Získať aplikácie na synchronizáciu vašich súborov",
- "Desktop client" : "Desktopový klient",
- "Android app" : "Android aplikácia",
- "iOS app" : "iOS aplikácia",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ak chcete projekt podporiť,\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">zapojte sa do vývoja</a>\n\t\talebo\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ho propagujte</a>!",
- "Show First Run Wizard again" : "Znovu zobraziť sprievodcu prvým spustením",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Použili ste <strong>%s</strong> z <strong>%s</strong> dostupných ",
- "Password" : "Heslo",
- "Unable to change your password" : "Nie je možné zmeniť vaše heslo",
- "Current password" : "Aktuálne heslo",
- "New password" : "Nové heslo",
- "Change password" : "Zmeniť heslo",
+ "Profile picture" : "Avatar",
+ "Upload new" : "Nahrať nový",
+ "Remove image" : "Zmazať obrázok",
+ "Cancel" : "Zrušiť",
"Full name" : "Meno a priezvisko",
"No display name set" : "Zobrazované meno nie je nastavené",
"Email" : "Email",
"Your email address" : "Vaša emailová adresa",
- "Fill in an email address to enable password recovery and receive notifications" : "Zadajte emailovú adresu pre umožnenie obnovy zabudnutého hesla a pre prijímanie upozornení a oznámení",
"No email address set" : "Emailová adresa nie je nastavená",
"You are member of the following groups:" : "Ste členom nasledovných skupín:",
- "Profile picture" : "Avatar",
- "Upload new" : "Nahrať nový",
- "Select new from Files" : "Vyberte nový zo súborov",
- "Remove image" : "Zmazať obrázok",
- "Your avatar is provided by your original account." : "Váš avatar je použitý z pôvodného účtu.",
- "Cancel" : "Zrušiť",
- "Choose as profile image" : "Vybrať ako avatara",
+ "Password" : "Heslo",
+ "Unable to change your password" : "Nie je možné zmeniť vaše heslo",
+ "Current password" : "Aktuálne heslo",
+ "New password" : "Nové heslo",
+ "Change password" : "Zmeniť heslo",
"Language" : "Jazyk",
"Help translate" : "Pomôcť s prekladom",
- "Common Name" : "Bežný názov",
- "Valid until" : "Platný do",
- "Issued By" : "Vydal",
- "Valid until %s" : "Platný do %s",
- "Import root certificate" : "Importovať koreňový certifikát",
+ "Get the apps to sync your files" : "Získať aplikácie na synchronizáciu vašich súborov",
+ "Desktop client" : "Desktopový klient",
+ "Android app" : "Android aplikácia",
+ "iOS app" : "iOS aplikácia",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ak chcete projekt podporiť,\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">zapojte sa do vývoja</a>\n\t\talebo\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">ho propagujte</a>!",
+ "Show First Run Wizard again" : "Znovu zobraziť sprievodcu prvým spustením",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Vyvinula {communityopen}komunita ownCloud{linkclose}. {githubopen}Zdrojový kód{linkclose} je dostupný za podmienok licencie {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Zobraziť umiestnenie úložiska",
"Show last log in" : "Zobraziť posledné prihlásenie",
diff --git a/settings/l10n/sl.js b/settings/l10n/sl.js
index 1e436f7b81a..74d7ca28133 100644
--- a/settings/l10n/sl.js
+++ b/settings/l10n/sl.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Dnevnik",
"Tips & tricks" : "Nasveti in triki",
"Updates" : "Posodobitve",
- "Authentication error" : "Napaka med overjanjem",
- "Your full name has been changed." : "Vaše polno ime je spremenjeno.",
- "Unable to change full name" : "Ni mogoče spremeniti polnega imena",
"Couldn't remove app." : "Ni mogoče odstraniti programa.",
"Language changed" : "Jezik je spremenjen",
"Invalid request" : "Neveljavna zahteva",
+ "Authentication error" : "Napaka med overjanjem",
"Admins can't remove themself from the admin group" : "Skrbnikov ni mogoče odstraniti iz skupine skrbnikov (admin)",
"Unable to add user to group %s" : "Uporabnika ni mogoče dodati k skupini %s",
"Unable to remove user from group %s" : "Uporabnika ni mogoče odstraniti iz skupine %s",
@@ -50,6 +48,8 @@ OC.L10N.register(
"Invalid user" : "Neveljavni podatki uporabnika",
"Unable to change mail address" : "Ni mogoče spremeniti naslova elektronske pošte.",
"Email saved" : "Elektronski naslov je shranjen",
+ "Your full name has been changed." : "Vaše polno ime je spremenjeno.",
+ "Unable to change full name" : "Ni mogoče spremeniti polnega imena",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ali ste prepričani, da želite dodati \"{domain}\" kot varno domeno?",
"Add trusted domain" : "Dodaj varno domeno",
"Migration in progress. Please wait until the migration is finished" : "Selitev v teku. Prosimo, počakajte, da se selitev zaključi.",
@@ -72,14 +72,18 @@ OC.L10N.register(
"Uninstalling ...." : "Odstranjevanje namestitve ...",
"Error while uninstalling app" : "Prišlo je do napake med odstranjevanjem programa.",
"Uninstall" : "Odstrani namestitev",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Aplikacija je bila vključena in zahteva še posodobitev. Preusmerjeni boste na stran za posodobitev v 5 sekundah.",
+ "App update" : "Posodabljanje aplikacije",
+ "No apps found for \"{query}\"" : "Ne najdem aplikacije za \"{query}\"",
+ "Valid until {date}" : "Veljavno do {date}",
+ "Delete" : "Izbriši",
+ "An error occurred: {message}" : "Prišlo je do napake: {message}",
"Select a profile picture" : "Izbor slike profila",
"Very weak password" : "Zelo šibko geslo",
"Weak password" : "Šibko geslo",
"So-so password" : "Slabo geslo",
"Good password" : "Dobro geslo",
"Strong password" : "Odlično geslo",
- "Valid until {date}" : "Veljavno do {date}",
- "Delete" : "Izbriši",
"Groups" : "Skupine",
"Unable to delete {objName}" : "Ni mogoče izbrisati {objName}",
"Error creating group" : "Napaka ustvarjanja skupine",
@@ -96,9 +100,8 @@ OC.L10N.register(
"A valid password must be provided" : "Navedeno mora biti veljavno geslo",
"A valid email must be provided" : "Naveden mora biti veljaven naslov elektronske pošte.",
"__language_name__" : "Slovenščina",
- "Sync clients" : "Uskladi odjemalce",
"Personal info" : "Osebni podatki",
- "SSL root certificates" : "Korenska potrdila SSL",
+ "Sync clients" : "Uskladi odjemalce",
"Everything (fatal issues, errors, warnings, info, debug)" : "Vse (podrobnosti, opozorila, hrošče, napake in usodne dogodke)",
"Info, warnings, errors and fatal issues" : "Podrobnosti, opozorila, napake in usodne dogodke",
"Warnings, errors and fatal issues" : "Opozorila, napake in usodne dogodke",
@@ -114,6 +117,7 @@ OC.L10N.register(
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Manjka modul PHP 'fileinfo'. Priporočljivo je omogočiti ta modul za popolno zaznavanje vrst MIME.",
"System locale can not be set to a one which supports UTF-8." : "Sistemskih jezikovnih nastavitev ni mogoče nastaviti na možnost, ki podpira nabor UTF-8.",
"This means that there might be problems with certain characters in file names." : "To pomeni, da se lahko pojavijo napake pri nekaterih znakih v imenih datotek.",
+ "All checks passed." : "Vsa prejerjanja so pozitivna.",
"Open documentation" : "Odprta dokumentacija",
"Allow apps to use the Share API" : "Dovoli programom uporabo vmesnika API souporabe",
"Allow users to share via link" : "Uporabnikom dovoli omogočanje souporabe s povezavami",
@@ -151,13 +155,12 @@ OC.L10N.register(
"Store credentials" : "Shrani poverila",
"Test email settings" : "Preizkus nastavitev elektronske pošte",
"Send email" : "Pošlji elektronsko sporočilo",
- "Log level" : "Raven beleženja",
"Download logfile" : "Prejmi dnevniško datoteko",
"More" : "Več",
"Less" : "Manj",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Datoteeka dnevniškega zapisa je večja od 100MB. Prenos lahko traja dlje!",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Uporabljena baza je SQLite. Za večje namestitve priporočamo prehod na drugačno bazo.",
- "How to do backups" : "Kako napraviti varnostne kopije",
+ "How to do backups" : "Kako ustvariti varnostne kopije",
"Advanced monitoring" : "Napredno sledenje",
"Performance tuning" : "Optimizacija izvajanja",
"Improving the config.php" : "Izboljšanje config.php",
@@ -166,57 +169,56 @@ OC.L10N.register(
"Version" : "Različica",
"Developer documentation" : "Razvojniška dokumentacija",
"Experimental applications ahead" : "Testne aplikacija",
- "by" : "od",
- "licensed" : "licencirano",
"Documentation:" : "Dokumentacija:",
- "User documentation" : "Uporabniška navodila",
- "Show description …" : "Prikaži opis...",
- "Hide description …" : "Skrij opis...",
+ "User documentation" : "Uporabniška dokumentacija",
+ "Admin documentation" : "Skrbniška dokumentacija",
+ "Show description …" : "Pokaži opis ...",
+ "Hide description …" : "Skrij opis ...",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Programa ni mogoče namestiti zaradi nerešenih odvisnosti:",
"Enable only for specific groups" : "Omogoči le za posamezne skupine",
"Uninstall App" : "Odstrani program",
"Enable experimental apps" : "Omogoči testne aplikacije",
+ "SSL Root Certificates" : "Korenska potrdila SSL",
+ "Common Name" : "Splošno ime",
+ "Valid until" : "Veljavno do",
+ "Issued By" : "Izdajatelj",
+ "Valid until %s" : "Veljavno do %s",
+ "Import root certificate" : "Uvozite korenski certifikat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Pozdravljeni,<br><br>samo sporočamo, da imate %s račun.<br><br>Vaše uporabniško ime: %s<br>Dostop: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Na zdravje!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Pozdravljeni,\n\nsamo sporočamo, da imate %s račun.\n\nVaše uporabniško ime: %s\nDostop: %s\n",
- "Administrator documentation" : "Skrbniška navodila",
- "Online documentation" : "Dokumentacija na spletu",
+ "Administrator documentation" : "Skrbniška dokumentacija",
+ "Online documentation" : "Spletna dokumentacija",
"Forum" : "Forum",
"Issue tracker" : "Spremljanje težav",
"Commercial support" : "Komercialna podpora",
- "Get the apps to sync your files" : "Pridobi programe za usklajevanje datotek",
- "Desktop client" : "Namizni odjemalec",
- "Android app" : "Program za Android",
- "iOS app" : "Program za iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Če bi radi podprli projekt\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">pristopite razvoju</a>\n\t\tali\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">razširite glas</a>!",
- "Show First Run Wizard again" : "Zaženi čarovnika prvega zagona",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Uporabljenega je <strong>%s</strong> od razpoložljivih <strong>%s</strong> prostora.",
- "Password" : "Geslo",
- "Unable to change your password" : "Gesla ni mogoče spremeniti.",
- "Current password" : "Trenutno geslo",
- "New password" : "Novo geslo",
- "Change password" : "Spremeni geslo",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Uporabljate <strong>%s</strong> od <strong>%s</strong>",
+ "Profile picture" : "Slika profila",
+ "Upload new" : "Pošlji novo",
+ "Select from Files" : "Izbor iz datotek",
+ "Remove image" : "Odstrani sliko",
+ "png or jpg, max. 20 MB" : "png ali jpg, največ. 20 MB",
+ "Cancel" : "Prekliči",
"Full name" : "Polno ime",
"No display name set" : "Ime za prikaz ni bilo nastavljeno",
"Email" : "Elektronski naslov",
"Your email address" : "Osebni elektronski naslov",
- "Fill in an email address to enable password recovery and receive notifications" : "Podajte elektronski naslov, da vam omogočimo reševanje izgubljenega gesla in sprejem obvestil",
"No email address set" : "Poštni naslov ni bil vpisan",
"You are member of the following groups:" : "Vi ste član sledečih skupin:",
- "Profile picture" : "Slika profila",
- "Upload new" : "Pošlji novo",
- "Select new from Files" : "Izberi novo iz menija datotek",
- "Remove image" : "Odstrani sliko",
- "Your avatar is provided by your original account." : "Podoba je podana v izvornem računu.",
- "Cancel" : "Prekliči",
- "Choose as profile image" : "Izberi kot sliko profila",
+ "Password" : "Geslo",
+ "Unable to change your password" : "Gesla ni mogoče spremeniti.",
+ "Current password" : "Trenutno geslo",
+ "New password" : "Novo geslo",
+ "Change password" : "Spremeni geslo",
"Language" : "Jezik",
"Help translate" : "Sodelujte pri prevajanju",
- "Common Name" : "Splošno ime",
- "Valid until" : "Veljavno do",
- "Issued By" : "Izdajatelj",
- "Valid until %s" : "Veljavno do %s",
- "Import root certificate" : "Uvozite korenski certifikat",
+ "Get the apps to sync your files" : "Pridobi programe za usklajevanje datotek",
+ "Desktop client" : "Namizni odjemalec",
+ "Android app" : "Program za Android",
+ "iOS app" : "Program za iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Če bi radi podprli projekt\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">pristopite razvoju</a>\n\t\tali\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">razširite glas</a>!",
+ "Show First Run Wizard again" : "Zaženi čarovnika prvega zagona",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Produkt razvija {communityopen}ownCloud skupnost{linkclose}, {githubopen}izvorna koda{linkclose} je licencirana pod {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Pokaži mesto shrambe",
"Show last log in" : "Pokaži podatke zadnje prijave",
"Show user backend" : "Pokaži ozadnji program",
diff --git a/settings/l10n/sl.json b/settings/l10n/sl.json
index 6af0302af6a..622484f676f 100644
--- a/settings/l10n/sl.json
+++ b/settings/l10n/sl.json
@@ -10,12 +10,10 @@
"Log" : "Dnevnik",
"Tips & tricks" : "Nasveti in triki",
"Updates" : "Posodobitve",
- "Authentication error" : "Napaka med overjanjem",
- "Your full name has been changed." : "Vaše polno ime je spremenjeno.",
- "Unable to change full name" : "Ni mogoče spremeniti polnega imena",
"Couldn't remove app." : "Ni mogoče odstraniti programa.",
"Language changed" : "Jezik je spremenjen",
"Invalid request" : "Neveljavna zahteva",
+ "Authentication error" : "Napaka med overjanjem",
"Admins can't remove themself from the admin group" : "Skrbnikov ni mogoče odstraniti iz skupine skrbnikov (admin)",
"Unable to add user to group %s" : "Uporabnika ni mogoče dodati k skupini %s",
"Unable to remove user from group %s" : "Uporabnika ni mogoče odstraniti iz skupine %s",
@@ -48,6 +46,8 @@
"Invalid user" : "Neveljavni podatki uporabnika",
"Unable to change mail address" : "Ni mogoče spremeniti naslova elektronske pošte.",
"Email saved" : "Elektronski naslov je shranjen",
+ "Your full name has been changed." : "Vaše polno ime je spremenjeno.",
+ "Unable to change full name" : "Ni mogoče spremeniti polnega imena",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ali ste prepričani, da želite dodati \"{domain}\" kot varno domeno?",
"Add trusted domain" : "Dodaj varno domeno",
"Migration in progress. Please wait until the migration is finished" : "Selitev v teku. Prosimo, počakajte, da se selitev zaključi.",
@@ -70,14 +70,18 @@
"Uninstalling ...." : "Odstranjevanje namestitve ...",
"Error while uninstalling app" : "Prišlo je do napake med odstranjevanjem programa.",
"Uninstall" : "Odstrani namestitev",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Aplikacija je bila vključena in zahteva še posodobitev. Preusmerjeni boste na stran za posodobitev v 5 sekundah.",
+ "App update" : "Posodabljanje aplikacije",
+ "No apps found for \"{query}\"" : "Ne najdem aplikacije za \"{query}\"",
+ "Valid until {date}" : "Veljavno do {date}",
+ "Delete" : "Izbriši",
+ "An error occurred: {message}" : "Prišlo je do napake: {message}",
"Select a profile picture" : "Izbor slike profila",
"Very weak password" : "Zelo šibko geslo",
"Weak password" : "Šibko geslo",
"So-so password" : "Slabo geslo",
"Good password" : "Dobro geslo",
"Strong password" : "Odlično geslo",
- "Valid until {date}" : "Veljavno do {date}",
- "Delete" : "Izbriši",
"Groups" : "Skupine",
"Unable to delete {objName}" : "Ni mogoče izbrisati {objName}",
"Error creating group" : "Napaka ustvarjanja skupine",
@@ -94,9 +98,8 @@
"A valid password must be provided" : "Navedeno mora biti veljavno geslo",
"A valid email must be provided" : "Naveden mora biti veljaven naslov elektronske pošte.",
"__language_name__" : "Slovenščina",
- "Sync clients" : "Uskladi odjemalce",
"Personal info" : "Osebni podatki",
- "SSL root certificates" : "Korenska potrdila SSL",
+ "Sync clients" : "Uskladi odjemalce",
"Everything (fatal issues, errors, warnings, info, debug)" : "Vse (podrobnosti, opozorila, hrošče, napake in usodne dogodke)",
"Info, warnings, errors and fatal issues" : "Podrobnosti, opozorila, napake in usodne dogodke",
"Warnings, errors and fatal issues" : "Opozorila, napake in usodne dogodke",
@@ -112,6 +115,7 @@
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Manjka modul PHP 'fileinfo'. Priporočljivo je omogočiti ta modul za popolno zaznavanje vrst MIME.",
"System locale can not be set to a one which supports UTF-8." : "Sistemskih jezikovnih nastavitev ni mogoče nastaviti na možnost, ki podpira nabor UTF-8.",
"This means that there might be problems with certain characters in file names." : "To pomeni, da se lahko pojavijo napake pri nekaterih znakih v imenih datotek.",
+ "All checks passed." : "Vsa prejerjanja so pozitivna.",
"Open documentation" : "Odprta dokumentacija",
"Allow apps to use the Share API" : "Dovoli programom uporabo vmesnika API souporabe",
"Allow users to share via link" : "Uporabnikom dovoli omogočanje souporabe s povezavami",
@@ -149,13 +153,12 @@
"Store credentials" : "Shrani poverila",
"Test email settings" : "Preizkus nastavitev elektronske pošte",
"Send email" : "Pošlji elektronsko sporočilo",
- "Log level" : "Raven beleženja",
"Download logfile" : "Prejmi dnevniško datoteko",
"More" : "Več",
"Less" : "Manj",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Datoteeka dnevniškega zapisa je večja od 100MB. Prenos lahko traja dlje!",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Uporabljena baza je SQLite. Za večje namestitve priporočamo prehod na drugačno bazo.",
- "How to do backups" : "Kako napraviti varnostne kopije",
+ "How to do backups" : "Kako ustvariti varnostne kopije",
"Advanced monitoring" : "Napredno sledenje",
"Performance tuning" : "Optimizacija izvajanja",
"Improving the config.php" : "Izboljšanje config.php",
@@ -164,57 +167,56 @@
"Version" : "Različica",
"Developer documentation" : "Razvojniška dokumentacija",
"Experimental applications ahead" : "Testne aplikacija",
- "by" : "od",
- "licensed" : "licencirano",
"Documentation:" : "Dokumentacija:",
- "User documentation" : "Uporabniška navodila",
- "Show description …" : "Prikaži opis...",
- "Hide description …" : "Skrij opis...",
+ "User documentation" : "Uporabniška dokumentacija",
+ "Admin documentation" : "Skrbniška dokumentacija",
+ "Show description …" : "Pokaži opis ...",
+ "Hide description …" : "Skrij opis ...",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Programa ni mogoče namestiti zaradi nerešenih odvisnosti:",
"Enable only for specific groups" : "Omogoči le za posamezne skupine",
"Uninstall App" : "Odstrani program",
"Enable experimental apps" : "Omogoči testne aplikacije",
+ "SSL Root Certificates" : "Korenska potrdila SSL",
+ "Common Name" : "Splošno ime",
+ "Valid until" : "Veljavno do",
+ "Issued By" : "Izdajatelj",
+ "Valid until %s" : "Veljavno do %s",
+ "Import root certificate" : "Uvozite korenski certifikat",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Pozdravljeni,<br><br>samo sporočamo, da imate %s račun.<br><br>Vaše uporabniško ime: %s<br>Dostop: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Na zdravje!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Pozdravljeni,\n\nsamo sporočamo, da imate %s račun.\n\nVaše uporabniško ime: %s\nDostop: %s\n",
- "Administrator documentation" : "Skrbniška navodila",
- "Online documentation" : "Dokumentacija na spletu",
+ "Administrator documentation" : "Skrbniška dokumentacija",
+ "Online documentation" : "Spletna dokumentacija",
"Forum" : "Forum",
"Issue tracker" : "Spremljanje težav",
"Commercial support" : "Komercialna podpora",
- "Get the apps to sync your files" : "Pridobi programe za usklajevanje datotek",
- "Desktop client" : "Namizni odjemalec",
- "Android app" : "Program za Android",
- "iOS app" : "Program za iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Če bi radi podprli projekt\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">pristopite razvoju</a>\n\t\tali\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">razširite glas</a>!",
- "Show First Run Wizard again" : "Zaženi čarovnika prvega zagona",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Uporabljenega je <strong>%s</strong> od razpoložljivih <strong>%s</strong> prostora.",
- "Password" : "Geslo",
- "Unable to change your password" : "Gesla ni mogoče spremeniti.",
- "Current password" : "Trenutno geslo",
- "New password" : "Novo geslo",
- "Change password" : "Spremeni geslo",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Uporabljate <strong>%s</strong> od <strong>%s</strong>",
+ "Profile picture" : "Slika profila",
+ "Upload new" : "Pošlji novo",
+ "Select from Files" : "Izbor iz datotek",
+ "Remove image" : "Odstrani sliko",
+ "png or jpg, max. 20 MB" : "png ali jpg, največ. 20 MB",
+ "Cancel" : "Prekliči",
"Full name" : "Polno ime",
"No display name set" : "Ime za prikaz ni bilo nastavljeno",
"Email" : "Elektronski naslov",
"Your email address" : "Osebni elektronski naslov",
- "Fill in an email address to enable password recovery and receive notifications" : "Podajte elektronski naslov, da vam omogočimo reševanje izgubljenega gesla in sprejem obvestil",
"No email address set" : "Poštni naslov ni bil vpisan",
"You are member of the following groups:" : "Vi ste član sledečih skupin:",
- "Profile picture" : "Slika profila",
- "Upload new" : "Pošlji novo",
- "Select new from Files" : "Izberi novo iz menija datotek",
- "Remove image" : "Odstrani sliko",
- "Your avatar is provided by your original account." : "Podoba je podana v izvornem računu.",
- "Cancel" : "Prekliči",
- "Choose as profile image" : "Izberi kot sliko profila",
+ "Password" : "Geslo",
+ "Unable to change your password" : "Gesla ni mogoče spremeniti.",
+ "Current password" : "Trenutno geslo",
+ "New password" : "Novo geslo",
+ "Change password" : "Spremeni geslo",
"Language" : "Jezik",
"Help translate" : "Sodelujte pri prevajanju",
- "Common Name" : "Splošno ime",
- "Valid until" : "Veljavno do",
- "Issued By" : "Izdajatelj",
- "Valid until %s" : "Veljavno do %s",
- "Import root certificate" : "Uvozite korenski certifikat",
+ "Get the apps to sync your files" : "Pridobi programe za usklajevanje datotek",
+ "Desktop client" : "Namizni odjemalec",
+ "Android app" : "Program za Android",
+ "iOS app" : "Program za iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Če bi radi podprli projekt\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">pristopite razvoju</a>\n\t\tali\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">razširite glas</a>!",
+ "Show First Run Wizard again" : "Zaženi čarovnika prvega zagona",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Produkt razvija {communityopen}ownCloud skupnost{linkclose}, {githubopen}izvorna koda{linkclose} je licencirana pod {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Pokaži mesto shrambe",
"Show last log in" : "Pokaži podatke zadnje prijave",
"Show user backend" : "Pokaži ozadnji program",
diff --git a/settings/l10n/sq.js b/settings/l10n/sq.js
index 56a0a142f07..0f7115b8edd 100644
--- a/settings/l10n/sq.js
+++ b/settings/l10n/sq.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Regjistër",
"Tips & tricks" : "Ndihmëza & rrengje",
"Updates" : "Përditësime",
- "Authentication error" : "Gabim mirëfilltësimi",
- "Your full name has been changed." : "Emri juaj i plotë u ndryshua.",
- "Unable to change full name" : "S’arrin të ndryshojë emrin e plotë",
"Couldn't remove app." : "S’hoqi dot aplikacionin.",
"Language changed" : "Gjuha u ndryshua",
"Invalid request" : "Kërkesë e pavlefshme",
+ "Authentication error" : "Gabim mirëfilltësimi",
"Admins can't remove themself from the admin group" : "Administratorët s’mund të heqin veten prej grupit admin",
"Unable to add user to group %s" : "S’arrin të shtojë përdorues te grupi %s",
"Unable to remove user from group %s" : "S’arrin të heqë përdorues nga grupi %s",
@@ -31,6 +29,7 @@ OC.L10N.register(
"Enabled" : "E aktivizuar",
"Not enabled" : "E paaktivizuar",
"installing and updating apps via the app store or Federated Cloud Sharing" : "instalim dhe përditësim aplikacionesh përmes shitores së aplikacioneve ose Federated Cloud Sharing",
+ "Federated Cloud Sharing" : "Ndarje Në Re të Federuar ",
"cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL-ja po përdor një version %s të vjetruar (%s). Ju lutemi, përditësoni sistemin tuaj operativ ose përndryshe veçori të tilla si %s nuk do të punojnë në mënyrë të qëndrueshme.",
"A problem occurred, please check your log files (Error: %s)" : "Ndodhi një gabim, ju lutemi, kontrolloni kartelat tuaja regjistër (Error: %s)",
"Migration Completed" : "Migrimi u Plotësua",
@@ -52,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Përdorues i pavlefshëm",
"Unable to change mail address" : "S’arrin të ndryshojë adresë email",
"Email saved" : "Email-i u ruajt",
+ "Your full name has been changed." : "Emri juaj i plotë u ndryshua.",
+ "Unable to change full name" : "S’arrin të ndryshojë emrin e plotë",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Jeni vërtet i sigurt se doni të shtoni \"{domain}\" si përkatësi të besuar?",
"Add trusted domain" : "Shtoni përkatësi të besuar",
"Migration in progress. Please wait until the migration is finished" : "Migrimi në rrugë e sipër. Ju lutemi, pritni, teksa migrimi përfundon",
@@ -80,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Aplikacioni është aktivizuar, por lyp të përditësohet. Do të ridrejtoheni te faqja e përditësimeve brenda 5 sekondash.",
"App update" : "Përditësim aplikacioni",
"No apps found for \"{query}\"" : "S’u gjetën aplikacione për \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ndodhi një gabim. Ju lutemi, ngarkoni një dëshmi PEM të koduar me ASCII.",
+ "Valid until {date}" : "E vlefshme deri më {date}",
+ "Delete" : "Fshije",
"An error occurred: {message}" : "Ndodhi një gabim: {message}",
"Select a profile picture" : "Përzgjidhni një foto profili",
"Very weak password" : "Fjalëkalim shumë i dobët",
@@ -87,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Fjalëkalim çka",
"Good password" : "Fjalëkalim i mirë",
"Strong password" : "Fjalëkalim i fortë",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ndodhi një gabim. Ju lutemi, ngarkoni një dëshmi PEM të koduar me ASCII.",
- "Valid until {date}" : "E vlefshme deri më {date}",
- "Delete" : "Fshije",
"Groups" : "Grupe",
"Unable to delete {objName}" : "S’arrin të fshijë {objName}",
"Error creating group" : "Gabim gjatë krijimit të grupit",
@@ -106,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Duhet dhënë një fjalëkalim i vlefshëm",
"A valid email must be provided" : "Duhet dhënë një email i vlefshëm",
"__language_name__" : "Shqip",
- "Sync clients" : "Klientë njëkohësimi",
"Personal info" : "Të dhëna personale",
- "SSL root certificates" : "Dëshmi SSL rrënjë",
+ "Sync clients" : "Klientë njëkohësimi",
"Everything (fatal issues, errors, warnings, info, debug)" : "Gjithçka (probleme fatale, gabime, sinjalizime, të dhëna, diagnostikim)",
"Info, warnings, errors and fatal issues" : "Të dhëna, sinjalizime, gabime dhe probleme fatale",
"Warnings, errors and fatal issues" : "Sinjalizime, gabime dhe probleme fatale",
@@ -117,6 +117,7 @@ OC.L10N.register(
"None" : "Asnjë",
"Login" : "Hyrje",
"Plain" : "E thjeshtë",
+ "NT LAN Manager" : "Përgjegjës Rrjeti NT",
"SSL" : "SSL",
"TLS" : "TLS",
"php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "PHP-ja nuk duket të jetë rregulluar si duhet për të kërkuar ndryshore mjedisi sistemi. Testi me getenv(\"PATH\") kthen vetëm një përgjigje të zbrazët.",
@@ -127,6 +128,7 @@ OC.L10N.register(
"Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "Shërbyesi juaj xhiron nën Microsoft Windows. Këshillojmë fort Linux-in për punim optimal nga ana e përdoruesit.",
"%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "Ka të instaluar %1$s nën versionin %2$s, për arsye qëndrueshmërie dhe performance këshillojmë të përditësohet me një version %1$s më të ri.",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Moduli PHP 'fileinfo' mungon. Ju këshillojmë me forcë ta aktivizoni këtë modul, për të patur përfundimet më të mira në zbulim llojesh MIME.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Kyçja e kartelave gjatë transaksioneve është e çaktivizuar, kjo mund të sjellë probleme me gjendje <em>race conditions</em>. Që të shmangni këto probleme, aktivizoni 'filelocking.enabled' te config.php. Për më tepër të dhëna, shihni <a target=\"_blank\" href=\"%s\">dokumentimin ↗</a>.",
"System locale can not be set to a one which supports UTF-8." : "Si vendore sistemi nuk mund të caktohet një që mbulon UTF-8.",
"This means that there might be problems with certain characters in file names." : "Kjo do të thotë që mund të ketë probleme me disa shenja në emra kartelash.",
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Këshillojmë me forcë instalimin në sistemin tuaj të paketave të domosdoshme për mbulim të një prej vendoreve vijuese: %s.",
@@ -145,7 +147,7 @@ OC.L10N.register(
"days" : "ditësh",
"Enforce expiration date" : "Detyro datë skadimi",
"Allow resharing" : "Lejo rindarje",
- "Restrict users to only share with users in their groups" : "Përdoruesit kufizoji të ndajnë gjëra vetëm me përdorues në grupin e tyre",
+ "Restrict users to only share with users in their groups" : "Përdoruesve kufizoju të ndajnë gjëra vetëm me përdorues në grupin e tyre",
"Allow users to send mail notification for shared files to other users" : "Lejoju përdoruesve t’u dërgojnë përdoruesve të tjerë njoftime me email për kartela të ndara me të tjerët",
"Exclude groups from sharing" : "Përjashtoni grupe nga ndarjet",
"These groups will still be able to receive shares, but not to initiate them." : "Këto grupe prapë do të jenë në gjendje të marrin ndarje nga të tjerët, por jo të fillojnë të tilla.",
@@ -184,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Depozitoji kredencialet",
"Test email settings" : "Testoni rregullimet e email-it",
"Send email" : "Dërgo email",
- "Log level" : "Shkallë regjistrimi",
"Download logfile" : "Shkarkoni kartelën regjistër",
"More" : "Më tepër",
"Less" : "Më pak",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Kartela regjistër është më e madhe se 100 MB. Shkarkimi i saj mund të hajë ca kohë!",
+ "What to log" : "Ç’të regjistrohet",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Si bazë të dhënash përdoret SQLite. Për instalime më të ngarkuara, këshillojmë të kalohet në një program tjetër baze të dhënash.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Përdorimi i SQLite-it nuk këshillohet veçanërisht kur përdoret klienti desktop për njëkohësim kartelash.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Për të kaluar te një tjetër bazë të dhënash përdorni mjetin rresht urdhrash: 'occ db:convert-type', ose shihni <a target=\"_blank\" href=\"%s\">dokumentimin ↗</a>.",
@@ -202,17 +204,25 @@ OC.L10N.register(
"Developer documentation" : "Dokumentim për zhvillues",
"Experimental applications ahead" : "Keni përpara aplikacione eksperimentale",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Aplikacionet eksperimentale nuk kontrollohen për probleme sigurie, mund të jenë të rinj ose të njohur si të paqëndrueshëm, dhe nën zhvillim intensiv. Instalimi i tyre mund të shkaktojë humbje të dhënash ose cenim të sigurisë.",
- "by" : "nga",
- "licensed" : "licencuar sipas",
+ "by %s" : "nga %s",
+ "%s-licensed" : "licencuar prej %s",
"Documentation:" : "Dokumentim:",
"User documentation" : "Dokumentim për përdoruesit",
"Admin documentation" : "Dokumentim për përgjegjësit",
"Show description …" : "Shfaq përshkrim …",
"Hide description …" : "Fshihe përshkrimin …",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Ky aplikacion nuk ka të përcaktuar version minimum për ownCloud-in. Kjo do të përbëjë një gabim për ownCloud 11 dhe të mëvonshëm.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Ky aplikacion nuk ka të përcaktuar version maksimum për ownCloud-in. Kjo do të përbëjë një gabim për ownCloud 11 dhe të mëvonshëm.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Ky aplikacion s’mund të instalohet, ngaqë për të nuk plotësohen varësitë vijuese:",
"Enable only for specific groups" : "Aktivizoje vetëm për grupe të veçantë",
"Uninstall App" : "Çinstaloje Aplikacionin",
"Enable experimental apps" : "Aktivizo aplikacione eksperimentale",
+ "SSL Root Certificates" : "Dëshmi SSL Rrënjë",
+ "Common Name" : "Emër i Rëndomtë",
+ "Valid until" : "E vlefshme deri më",
+ "Issued By" : "Lëshuar Nga",
+ "Valid until %s" : "E vlefshme deri më %s",
+ "Import root certificate" : "Importoni dëshmi rrënjë",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Njatjeta,<br><br>thjesht po ju bëjmë të ditur që tani keni një llogar %s.<br><br>Emri juaj i përdoruesit: %s<br>Hyni në të te: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Gëzuar!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Njatjeta,\n\nthjesht po ju bëjmë të ditur që tani keni një llogari %s.\n\nEmri juaj i përdoruesit: %s\nHyni në të te: %s\n\n",
@@ -221,40 +231,35 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Gjurmues të metash",
"Commercial support" : "Asistencë komerciale",
- "Get the apps to sync your files" : "Merrni aplikacionet për njëkohësim të kartelave tuaja",
- "Desktop client" : "Klient desktopi",
- "Android app" : "Aplikacion për Android",
- "iOS app" : "Aplikacion për iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Nëse doni ta përkrahni projektin\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">merrni pjesë te zhvillimi i tij</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">përhapni fjalën për të</a>!",
- "Show First Run Wizard again" : "Shfaqe sërish Ndihmësin e Herës së Parë",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Keni përdorur <strong>%s</strong> nga <strong>%s</strong> tuajat",
- "Password" : "Fjalëkalim",
- "Unable to change your password" : "S’arrin të ndryshojë fjalëkalimin tuaj",
- "Current password" : "Fjalëkalimi i tanishëm",
- "New password" : "Fjalëkalimi i ri",
- "Change password" : "Ndrysho fjalëkalimin",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Po përdorni <strong>%s</strong> nga <strong>%s</strong>",
+ "Profile picture" : "Foto profili",
+ "Upload new" : "Ngarko të re",
+ "Select from Files" : "Përzgjidhni prej Kartelash",
+ "Remove image" : "Hiqe figurën",
+ "png or jpg, max. 20 MB" : "png ose jpg, maks. 20 MB",
+ "Picture provided by original account" : "Foto e prurë nga llogaria origjinale",
+ "Cancel" : "Anuloje",
+ "Choose as profile picture" : "Zgjidhni një foto profili",
"Full name" : "Emër i plotë",
"No display name set" : "S’është caktuar emër për në ekran",
"Email" : "Email",
"Your email address" : "Adresa juaj email",
- "Fill in an email address to enable password recovery and receive notifications" : "Futni një adresë email që të aktivizoni rimarrje fjalëkalimi dhe për të marrë njoftime",
+ "For password recovery and notifications" : "Për rimarrje fjalëkalimesh dhe njoftime ",
"No email address set" : "S’është caktuar adresë email",
"You are member of the following groups:" : "Jeni anëtar i grupeve vijuese:",
- "Profile picture" : "Foto profili",
- "Upload new" : "Ngarko të re",
- "Select new from Files" : "Përzgjidhni të re prej Kartelash",
- "Remove image" : "Hiqe figurën",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Ose png, ose jpg. E mira do të ishte katrore, por do të jeni në gjendje ta qethni. Nuk lejohet që kartela të tejkalojë madhësinë maksimum prej 20 MB.",
- "Your avatar is provided by your original account." : "Avatari juaj jepet nga llogaria juaj origjinale.",
- "Cancel" : "Anuloje",
- "Choose as profile image" : "Zgjidhni një figurë profili",
+ "Password" : "Fjalëkalim",
+ "Unable to change your password" : "S’arrin të ndryshojë fjalëkalimin tuaj",
+ "Current password" : "Fjalëkalimi i tanishëm",
+ "New password" : "Fjalëkalimi i ri",
+ "Change password" : "Ndrysho fjalëkalimin",
"Language" : "Gjuhë",
"Help translate" : "Ndihmoni në përkthim",
- "Common Name" : "Emër i Rëndomtë",
- "Valid until" : "E vlefshme deri më",
- "Issued By" : "Lëshuar Nga",
- "Valid until %s" : "E vlefshme deri më %s",
- "Import root certificate" : "Importoni dëshmi rrënjë",
+ "Get the apps to sync your files" : "Merrni aplikacionet për njëkohësim të kartelave tuaja",
+ "Desktop client" : "Klient desktopi",
+ "Android app" : "Aplikacion për Android",
+ "iOS app" : "Aplikacion për iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Nëse doni ta përkrahni projektin\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">merrni pjesë te zhvillimi i tij</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">përhapni fjalën për të</a>!",
+ "Show First Run Wizard again" : "Shfaqe sërish Ndihmësin e Herës së Parë",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Krijuar nga {communityopen}bashkësia ownCloud{linkclose}, {githubopen}kodi burim{linkclose} mund të përdoret sipas licencës {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Shfaq vendndodhje depozite",
"Show last log in" : "Shfaq hyrjen e fundit",
@@ -264,7 +269,7 @@ OC.L10N.register(
"Username" : "Emër përdoruesi",
"E-Mail" : "Email",
"Create" : "Krijoje",
- "Admin Recovery Password" : "Rigjetja e fjalëkalimit të Admin",
+ "Admin Recovery Password" : "Fjalëkalim Rikthimesh Nga Përgjegjësi",
"Enter the recovery password in order to recover the users files during password change" : "Jepni fjalëkalim rimarrje që të mund të rimerrni kartela përdoruesi gjatë ndryshimit të fjalëkalimit",
"Add Group" : "Shtoni Grup",
"Group" : "Grup",
diff --git a/settings/l10n/sq.json b/settings/l10n/sq.json
index eb5f05106a4..26adb15ed38 100644
--- a/settings/l10n/sq.json
+++ b/settings/l10n/sq.json
@@ -10,12 +10,10 @@
"Log" : "Regjistër",
"Tips & tricks" : "Ndihmëza & rrengje",
"Updates" : "Përditësime",
- "Authentication error" : "Gabim mirëfilltësimi",
- "Your full name has been changed." : "Emri juaj i plotë u ndryshua.",
- "Unable to change full name" : "S’arrin të ndryshojë emrin e plotë",
"Couldn't remove app." : "S’hoqi dot aplikacionin.",
"Language changed" : "Gjuha u ndryshua",
"Invalid request" : "Kërkesë e pavlefshme",
+ "Authentication error" : "Gabim mirëfilltësimi",
"Admins can't remove themself from the admin group" : "Administratorët s’mund të heqin veten prej grupit admin",
"Unable to add user to group %s" : "S’arrin të shtojë përdorues te grupi %s",
"Unable to remove user from group %s" : "S’arrin të heqë përdorues nga grupi %s",
@@ -29,6 +27,7 @@
"Enabled" : "E aktivizuar",
"Not enabled" : "E paaktivizuar",
"installing and updating apps via the app store or Federated Cloud Sharing" : "instalim dhe përditësim aplikacionesh përmes shitores së aplikacioneve ose Federated Cloud Sharing",
+ "Federated Cloud Sharing" : "Ndarje Në Re të Federuar ",
"cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL-ja po përdor një version %s të vjetruar (%s). Ju lutemi, përditësoni sistemin tuaj operativ ose përndryshe veçori të tilla si %s nuk do të punojnë në mënyrë të qëndrueshme.",
"A problem occurred, please check your log files (Error: %s)" : "Ndodhi një gabim, ju lutemi, kontrolloni kartelat tuaja regjistër (Error: %s)",
"Migration Completed" : "Migrimi u Plotësua",
@@ -50,6 +49,8 @@
"Invalid user" : "Përdorues i pavlefshëm",
"Unable to change mail address" : "S’arrin të ndryshojë adresë email",
"Email saved" : "Email-i u ruajt",
+ "Your full name has been changed." : "Emri juaj i plotë u ndryshua.",
+ "Unable to change full name" : "S’arrin të ndryshojë emrin e plotë",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Jeni vërtet i sigurt se doni të shtoni \"{domain}\" si përkatësi të besuar?",
"Add trusted domain" : "Shtoni përkatësi të besuar",
"Migration in progress. Please wait until the migration is finished" : "Migrimi në rrugë e sipër. Ju lutemi, pritni, teksa migrimi përfundon",
@@ -78,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Aplikacioni është aktivizuar, por lyp të përditësohet. Do të ridrejtoheni te faqja e përditësimeve brenda 5 sekondash.",
"App update" : "Përditësim aplikacioni",
"No apps found for \"{query}\"" : "S’u gjetën aplikacione për \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ndodhi një gabim. Ju lutemi, ngarkoni një dëshmi PEM të koduar me ASCII.",
+ "Valid until {date}" : "E vlefshme deri më {date}",
+ "Delete" : "Fshije",
"An error occurred: {message}" : "Ndodhi një gabim: {message}",
"Select a profile picture" : "Përzgjidhni një foto profili",
"Very weak password" : "Fjalëkalim shumë i dobët",
@@ -85,9 +89,6 @@
"So-so password" : "Fjalëkalim çka",
"Good password" : "Fjalëkalim i mirë",
"Strong password" : "Fjalëkalim i fortë",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Ndodhi një gabim. Ju lutemi, ngarkoni një dëshmi PEM të koduar me ASCII.",
- "Valid until {date}" : "E vlefshme deri më {date}",
- "Delete" : "Fshije",
"Groups" : "Grupe",
"Unable to delete {objName}" : "S’arrin të fshijë {objName}",
"Error creating group" : "Gabim gjatë krijimit të grupit",
@@ -104,9 +105,8 @@
"A valid password must be provided" : "Duhet dhënë një fjalëkalim i vlefshëm",
"A valid email must be provided" : "Duhet dhënë një email i vlefshëm",
"__language_name__" : "Shqip",
- "Sync clients" : "Klientë njëkohësimi",
"Personal info" : "Të dhëna personale",
- "SSL root certificates" : "Dëshmi SSL rrënjë",
+ "Sync clients" : "Klientë njëkohësimi",
"Everything (fatal issues, errors, warnings, info, debug)" : "Gjithçka (probleme fatale, gabime, sinjalizime, të dhëna, diagnostikim)",
"Info, warnings, errors and fatal issues" : "Të dhëna, sinjalizime, gabime dhe probleme fatale",
"Warnings, errors and fatal issues" : "Sinjalizime, gabime dhe probleme fatale",
@@ -115,6 +115,7 @@
"None" : "Asnjë",
"Login" : "Hyrje",
"Plain" : "E thjeshtë",
+ "NT LAN Manager" : "Përgjegjës Rrjeti NT",
"SSL" : "SSL",
"TLS" : "TLS",
"php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "PHP-ja nuk duket të jetë rregulluar si duhet për të kërkuar ndryshore mjedisi sistemi. Testi me getenv(\"PATH\") kthen vetëm një përgjigje të zbrazët.",
@@ -125,6 +126,7 @@
"Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "Shërbyesi juaj xhiron nën Microsoft Windows. Këshillojmë fort Linux-in për punim optimal nga ana e përdoruesit.",
"%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "Ka të instaluar %1$s nën versionin %2$s, për arsye qëndrueshmërie dhe performance këshillojmë të përditësohet me një version %1$s më të ri.",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Moduli PHP 'fileinfo' mungon. Ju këshillojmë me forcë ta aktivizoni këtë modul, për të patur përfundimet më të mira në zbulim llojesh MIME.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Kyçja e kartelave gjatë transaksioneve është e çaktivizuar, kjo mund të sjellë probleme me gjendje <em>race conditions</em>. Që të shmangni këto probleme, aktivizoni 'filelocking.enabled' te config.php. Për më tepër të dhëna, shihni <a target=\"_blank\" href=\"%s\">dokumentimin ↗</a>.",
"System locale can not be set to a one which supports UTF-8." : "Si vendore sistemi nuk mund të caktohet një që mbulon UTF-8.",
"This means that there might be problems with certain characters in file names." : "Kjo do të thotë që mund të ketë probleme me disa shenja në emra kartelash.",
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Këshillojmë me forcë instalimin në sistemin tuaj të paketave të domosdoshme për mbulim të një prej vendoreve vijuese: %s.",
@@ -143,7 +145,7 @@
"days" : "ditësh",
"Enforce expiration date" : "Detyro datë skadimi",
"Allow resharing" : "Lejo rindarje",
- "Restrict users to only share with users in their groups" : "Përdoruesit kufizoji të ndajnë gjëra vetëm me përdorues në grupin e tyre",
+ "Restrict users to only share with users in their groups" : "Përdoruesve kufizoju të ndajnë gjëra vetëm me përdorues në grupin e tyre",
"Allow users to send mail notification for shared files to other users" : "Lejoju përdoruesve t’u dërgojnë përdoruesve të tjerë njoftime me email për kartela të ndara me të tjerët",
"Exclude groups from sharing" : "Përjashtoni grupe nga ndarjet",
"These groups will still be able to receive shares, but not to initiate them." : "Këto grupe prapë do të jenë në gjendje të marrin ndarje nga të tjerët, por jo të fillojnë të tilla.",
@@ -182,11 +184,11 @@
"Store credentials" : "Depozitoji kredencialet",
"Test email settings" : "Testoni rregullimet e email-it",
"Send email" : "Dërgo email",
- "Log level" : "Shkallë regjistrimi",
"Download logfile" : "Shkarkoni kartelën regjistër",
"More" : "Më tepër",
"Less" : "Më pak",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Kartela regjistër është më e madhe se 100 MB. Shkarkimi i saj mund të hajë ca kohë!",
+ "What to log" : "Ç’të regjistrohet",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Si bazë të dhënash përdoret SQLite. Për instalime më të ngarkuara, këshillojmë të kalohet në një program tjetër baze të dhënash.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Përdorimi i SQLite-it nuk këshillohet veçanërisht kur përdoret klienti desktop për njëkohësim kartelash.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Për të kaluar te një tjetër bazë të dhënash përdorni mjetin rresht urdhrash: 'occ db:convert-type', ose shihni <a target=\"_blank\" href=\"%s\">dokumentimin ↗</a>.",
@@ -200,17 +202,25 @@
"Developer documentation" : "Dokumentim për zhvillues",
"Experimental applications ahead" : "Keni përpara aplikacione eksperimentale",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Aplikacionet eksperimentale nuk kontrollohen për probleme sigurie, mund të jenë të rinj ose të njohur si të paqëndrueshëm, dhe nën zhvillim intensiv. Instalimi i tyre mund të shkaktojë humbje të dhënash ose cenim të sigurisë.",
- "by" : "nga",
- "licensed" : "licencuar sipas",
+ "by %s" : "nga %s",
+ "%s-licensed" : "licencuar prej %s",
"Documentation:" : "Dokumentim:",
"User documentation" : "Dokumentim për përdoruesit",
"Admin documentation" : "Dokumentim për përgjegjësit",
"Show description …" : "Shfaq përshkrim …",
"Hide description …" : "Fshihe përshkrimin …",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Ky aplikacion nuk ka të përcaktuar version minimum për ownCloud-in. Kjo do të përbëjë një gabim për ownCloud 11 dhe të mëvonshëm.",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "Ky aplikacion nuk ka të përcaktuar version maksimum për ownCloud-in. Kjo do të përbëjë një gabim për ownCloud 11 dhe të mëvonshëm.",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Ky aplikacion s’mund të instalohet, ngaqë për të nuk plotësohen varësitë vijuese:",
"Enable only for specific groups" : "Aktivizoje vetëm për grupe të veçantë",
"Uninstall App" : "Çinstaloje Aplikacionin",
"Enable experimental apps" : "Aktivizo aplikacione eksperimentale",
+ "SSL Root Certificates" : "Dëshmi SSL Rrënjë",
+ "Common Name" : "Emër i Rëndomtë",
+ "Valid until" : "E vlefshme deri më",
+ "Issued By" : "Lëshuar Nga",
+ "Valid until %s" : "E vlefshme deri më %s",
+ "Import root certificate" : "Importoni dëshmi rrënjë",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Njatjeta,<br><br>thjesht po ju bëjmë të ditur që tani keni një llogar %s.<br><br>Emri juaj i përdoruesit: %s<br>Hyni në të te: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Gëzuar!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Njatjeta,\n\nthjesht po ju bëjmë të ditur që tani keni një llogari %s.\n\nEmri juaj i përdoruesit: %s\nHyni në të te: %s\n\n",
@@ -219,40 +229,35 @@
"Forum" : "Forum",
"Issue tracker" : "Gjurmues të metash",
"Commercial support" : "Asistencë komerciale",
- "Get the apps to sync your files" : "Merrni aplikacionet për njëkohësim të kartelave tuaja",
- "Desktop client" : "Klient desktopi",
- "Android app" : "Aplikacion për Android",
- "iOS app" : "Aplikacion për iOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Nëse doni ta përkrahni projektin\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">merrni pjesë te zhvillimi i tij</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">përhapni fjalën për të</a>!",
- "Show First Run Wizard again" : "Shfaqe sërish Ndihmësin e Herës së Parë",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Keni përdorur <strong>%s</strong> nga <strong>%s</strong> tuajat",
- "Password" : "Fjalëkalim",
- "Unable to change your password" : "S’arrin të ndryshojë fjalëkalimin tuaj",
- "Current password" : "Fjalëkalimi i tanishëm",
- "New password" : "Fjalëkalimi i ri",
- "Change password" : "Ndrysho fjalëkalimin",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "Po përdorni <strong>%s</strong> nga <strong>%s</strong>",
+ "Profile picture" : "Foto profili",
+ "Upload new" : "Ngarko të re",
+ "Select from Files" : "Përzgjidhni prej Kartelash",
+ "Remove image" : "Hiqe figurën",
+ "png or jpg, max. 20 MB" : "png ose jpg, maks. 20 MB",
+ "Picture provided by original account" : "Foto e prurë nga llogaria origjinale",
+ "Cancel" : "Anuloje",
+ "Choose as profile picture" : "Zgjidhni një foto profili",
"Full name" : "Emër i plotë",
"No display name set" : "S’është caktuar emër për në ekran",
"Email" : "Email",
"Your email address" : "Adresa juaj email",
- "Fill in an email address to enable password recovery and receive notifications" : "Futni një adresë email që të aktivizoni rimarrje fjalëkalimi dhe për të marrë njoftime",
+ "For password recovery and notifications" : "Për rimarrje fjalëkalimesh dhe njoftime ",
"No email address set" : "S’është caktuar adresë email",
"You are member of the following groups:" : "Jeni anëtar i grupeve vijuese:",
- "Profile picture" : "Foto profili",
- "Upload new" : "Ngarko të re",
- "Select new from Files" : "Përzgjidhni të re prej Kartelash",
- "Remove image" : "Hiqe figurën",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Ose png, ose jpg. E mira do të ishte katrore, por do të jeni në gjendje ta qethni. Nuk lejohet që kartela të tejkalojë madhësinë maksimum prej 20 MB.",
- "Your avatar is provided by your original account." : "Avatari juaj jepet nga llogaria juaj origjinale.",
- "Cancel" : "Anuloje",
- "Choose as profile image" : "Zgjidhni një figurë profili",
+ "Password" : "Fjalëkalim",
+ "Unable to change your password" : "S’arrin të ndryshojë fjalëkalimin tuaj",
+ "Current password" : "Fjalëkalimi i tanishëm",
+ "New password" : "Fjalëkalimi i ri",
+ "Change password" : "Ndrysho fjalëkalimin",
"Language" : "Gjuhë",
"Help translate" : "Ndihmoni në përkthim",
- "Common Name" : "Emër i Rëndomtë",
- "Valid until" : "E vlefshme deri më",
- "Issued By" : "Lëshuar Nga",
- "Valid until %s" : "E vlefshme deri më %s",
- "Import root certificate" : "Importoni dëshmi rrënjë",
+ "Get the apps to sync your files" : "Merrni aplikacionet për njëkohësim të kartelave tuaja",
+ "Desktop client" : "Klient desktopi",
+ "Android app" : "Aplikacion për Android",
+ "iOS app" : "Aplikacion për iOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Nëse doni ta përkrahni projektin\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">merrni pjesë te zhvillimi i tij</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">përhapni fjalën për të</a>!",
+ "Show First Run Wizard again" : "Shfaqe sërish Ndihmësin e Herës së Parë",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Krijuar nga {communityopen}bashkësia ownCloud{linkclose}, {githubopen}kodi burim{linkclose} mund të përdoret sipas licencës {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}.",
"Show storage location" : "Shfaq vendndodhje depozite",
"Show last log in" : "Shfaq hyrjen e fundit",
@@ -262,7 +267,7 @@
"Username" : "Emër përdoruesi",
"E-Mail" : "Email",
"Create" : "Krijoje",
- "Admin Recovery Password" : "Rigjetja e fjalëkalimit të Admin",
+ "Admin Recovery Password" : "Fjalëkalim Rikthimesh Nga Përgjegjësi",
"Enter the recovery password in order to recover the users files during password change" : "Jepni fjalëkalim rimarrje që të mund të rimerrni kartela përdoruesi gjatë ndryshimit të fjalëkalimit",
"Add Group" : "Shtoni Grup",
"Group" : "Grup",
diff --git a/settings/l10n/sr.js b/settings/l10n/sr.js
index 28c61337eb8..a7c3b299b85 100644
--- a/settings/l10n/sr.js
+++ b/settings/l10n/sr.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Бележење",
"Tips & tricks" : "Савети и трикови",
"Updates" : "Ажурирања",
- "Authentication error" : "Грешка при провери идентитета",
- "Your full name has been changed." : "Ваше пуно име је промењено.",
- "Unable to change full name" : "Не могу да променим пуно име",
"Couldn't remove app." : "Не могу да уклоним апликацију.",
"Language changed" : "Језик је промењен",
"Invalid request" : "Неисправан захтев",
+ "Authentication error" : "Грешка при провери идентитета",
"Admins can't remove themself from the admin group" : "Администратор не може себе да уклони из admin групе",
"Unable to add user to group %s" : "Не могу да додам корисника у групу %s",
"Unable to remove user from group %s" : "Не могу да уклоним корисника из групе %s",
@@ -51,6 +49,8 @@ OC.L10N.register(
"Invalid user" : "Неисправан корисник",
"Unable to change mail address" : "Не могу да изменим е-адресу",
"Email saved" : "Е-порука сачувана",
+ "Your full name has been changed." : "Ваше пуно име је промењено.",
+ "Unable to change full name" : "Не могу да променим пуно име",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Да ли заиста желите да додате „{domain}“ као поуздан домен?",
"Add trusted domain" : "Додај поуздан домен",
"Migration in progress. Please wait until the migration is finished" : "Пресељење је у току. Сачекајте док се не заврши",
@@ -76,15 +76,15 @@ OC.L10N.register(
"Uninstalling ...." : "Деинсталирам ...",
"Error while uninstalling app" : "Грешка при деинсталацији апликације",
"Uninstall" : "Деинсталирај",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Дошло је до грешке. Отпремите АСКИ кодирани ПЕМ сертификат.",
+ "Valid until {date}" : "Важи до {date}",
+ "Delete" : "Обриши",
"Select a profile picture" : "Изаберите слику профила",
"Very weak password" : "Веома слаба лозинка",
"Weak password" : "Слаба лозинка",
"So-so password" : "Осредња лозинка",
"Good password" : "Добра лозинка",
"Strong password" : "Јака лозинка",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Дошло је до грешке. Отпремите АСКИ кодирани ПЕМ сертификат.",
- "Valid until {date}" : "Важи до {date}",
- "Delete" : "Обриши",
"Groups" : "Групе",
"Unable to delete {objName}" : "Не могу да обришем {objName}",
"Error creating group" : "Грешка при прављењу групе",
@@ -101,9 +101,8 @@ OC.L10N.register(
"A valid password must be provided" : "Морате унети исправну лозинку",
"A valid email must be provided" : "Мора бити наведена исправна е-адреса",
"__language_name__" : "Српски",
- "Sync clients" : "Синхронизовање клијената",
"Personal info" : "Лични подаци",
- "SSL root certificates" : "ССЛ корени сертификати",
+ "Sync clients" : "Синхронизовање клијената",
"Everything (fatal issues, errors, warnings, info, debug)" : "Све (фаталне проблеме, грешке, упозорења, информације, отклањање грешака)",
"Info, warnings, errors and fatal issues" : "Информације, упозорења, грешке и фатални проблеми",
"Warnings, errors and fatal issues" : "Упозорења, грешке и фатални проблеми",
@@ -171,7 +170,6 @@ OC.L10N.register(
"Store credentials" : "Сачувај акредитиве",
"Test email settings" : "Тестирај поставке е-поште",
"Send email" : "Пошаљи е-пошту",
- "Log level" : "Ниво бележења",
"Download logfile" : "Преузми записник",
"More" : "Више",
"Less" : "Мање",
@@ -189,8 +187,6 @@ OC.L10N.register(
"Developer documentation" : "Програмерска документација",
"Experimental applications ahead" : "Експериментална апликација",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Експерименталне апликације се непроверене што се тиче безбедности и могу бити нестабилне и недовршене. Инсталирање може довести до губитка података или нарушавања безбедности.",
- "by" : "од",
- "licensed" : "лиценцирано",
"Documentation:" : "Документација:",
"User documentation" : "Корисничка документација",
"Admin documentation" : "Администраторска документација",
@@ -200,6 +196,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Укључи само за одређене групе",
"Uninstall App" : "Деинсталирај апликацију",
"Enable experimental apps" : "Укључи експерименталне апликације",
+ "Common Name" : "Уобичајено име",
+ "Valid until" : "Важи до",
+ "Issued By" : "Издавач",
+ "Valid until %s" : "Важи до %s",
+ "Import root certificate" : "Увоз кореног сертификата",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Поздрав,<br><br>само вас обавештавам да сад имате %s налог.<br><br>Ваше корисничко име: %s<br>Приступите му на: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Здраво!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Поздрав.\n\nСамо да знате да сада имате %s налог.\n\nВаше корисничко име: %s\nПриступите му на: %s\n",
@@ -208,39 +209,29 @@ OC.L10N.register(
"Forum" : "Форум",
"Issue tracker" : "Пратилац проблема",
"Commercial support" : "Комерцијална подршка",
- "Get the apps to sync your files" : "Преузмите апликације ради синхронизовања ваших фајлова",
- "Desktop client" : "Клијент за рачунар",
- "Android app" : "Андроид апликација",
- "iOS app" : "иОС апликација",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ако желите да подржите пројект\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">придружите се развоју</a>\n\t\tили\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">разгласите свима</a>!",
- "Show First Run Wizard again" : "Поново прикажи чаробњака за прво покретање",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Искористили сте <strong>%s</strong> од дозвољених <strong>%s</strong>",
- "Password" : "Лозинка",
- "Unable to change your password" : "Не могу да изменим вашу лозинку",
- "Current password" : "Тренутна лозинка",
- "New password" : "Нова лозинка",
- "Change password" : "Измени лозинку",
+ "Profile picture" : "Слика профила",
+ "Upload new" : "Отпреми нову",
+ "Remove image" : "Уклони слику",
+ "Cancel" : "Одустани",
"Full name" : "Пуно име",
"No display name set" : "Није постављено име за приказ",
"Email" : "Е-пошта",
"Your email address" : "Ваша адреса е-поште",
- "Fill in an email address to enable password recovery and receive notifications" : "Попуните е-адресу да омогућите обнављање лозинке и добијате обавештења",
"No email address set" : "Није постављена е-адреса",
"You are member of the following groups:" : "Имате чланство у следећим групама:",
- "Profile picture" : "Слика профила",
- "Upload new" : "Отпреми нову",
- "Select new from Files" : "Изабери нову из фајлова",
- "Remove image" : "Уклони слику",
- "Your avatar is provided by your original account." : "Ваш аватар је добијен са оригиналног налога.",
- "Cancel" : "Одустани",
- "Choose as profile image" : "Изаберите слику профила",
+ "Password" : "Лозинка",
+ "Unable to change your password" : "Не могу да изменим вашу лозинку",
+ "Current password" : "Тренутна лозинка",
+ "New password" : "Нова лозинка",
+ "Change password" : "Измени лозинку",
"Language" : "Језик",
"Help translate" : " Помозите у превођењу",
- "Common Name" : "Уобичајено име",
- "Valid until" : "Важи до",
- "Issued By" : "Издавач",
- "Valid until %s" : "Важи до %s",
- "Import root certificate" : "Увоз кореног сертификата",
+ "Get the apps to sync your files" : "Преузмите апликације ради синхронизовања ваших фајлова",
+ "Desktop client" : "Клијент за рачунар",
+ "Android app" : "Андроид апликација",
+ "iOS app" : "иОС апликација",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ако желите да подржите пројект\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">придружите се развоју</a>\n\t\tили\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">разгласите свима</a>!",
+ "Show First Run Wizard again" : "Поново прикажи чаробњака за прво покретање",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Развијено од стране {communityopen}оунКлауд заједнице{linkclose}, {githubopen}изворни код{linkclose} је лиценциран под {licenseopen}<abbr title=\"Аферо општа јавна лиценца\">АОЈЛ (AGPL)</abbr>{linkclose}.",
"Show storage location" : "Прикажи локацију складишта",
"Show last log in" : "Прикажи последњу пријаву",
diff --git a/settings/l10n/sr.json b/settings/l10n/sr.json
index 2aff5a9d2b2..235977f5d79 100644
--- a/settings/l10n/sr.json
+++ b/settings/l10n/sr.json
@@ -10,12 +10,10 @@
"Log" : "Бележење",
"Tips & tricks" : "Савети и трикови",
"Updates" : "Ажурирања",
- "Authentication error" : "Грешка при провери идентитета",
- "Your full name has been changed." : "Ваше пуно име је промењено.",
- "Unable to change full name" : "Не могу да променим пуно име",
"Couldn't remove app." : "Не могу да уклоним апликацију.",
"Language changed" : "Језик је промењен",
"Invalid request" : "Неисправан захтев",
+ "Authentication error" : "Грешка при провери идентитета",
"Admins can't remove themself from the admin group" : "Администратор не може себе да уклони из admin групе",
"Unable to add user to group %s" : "Не могу да додам корисника у групу %s",
"Unable to remove user from group %s" : "Не могу да уклоним корисника из групе %s",
@@ -49,6 +47,8 @@
"Invalid user" : "Неисправан корисник",
"Unable to change mail address" : "Не могу да изменим е-адресу",
"Email saved" : "Е-порука сачувана",
+ "Your full name has been changed." : "Ваше пуно име је промењено.",
+ "Unable to change full name" : "Не могу да променим пуно име",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Да ли заиста желите да додате „{domain}“ као поуздан домен?",
"Add trusted domain" : "Додај поуздан домен",
"Migration in progress. Please wait until the migration is finished" : "Пресељење је у току. Сачекајте док се не заврши",
@@ -74,15 +74,15 @@
"Uninstalling ...." : "Деинсталирам ...",
"Error while uninstalling app" : "Грешка при деинсталацији апликације",
"Uninstall" : "Деинсталирај",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Дошло је до грешке. Отпремите АСКИ кодирани ПЕМ сертификат.",
+ "Valid until {date}" : "Важи до {date}",
+ "Delete" : "Обриши",
"Select a profile picture" : "Изаберите слику профила",
"Very weak password" : "Веома слаба лозинка",
"Weak password" : "Слаба лозинка",
"So-so password" : "Осредња лозинка",
"Good password" : "Добра лозинка",
"Strong password" : "Јака лозинка",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Дошло је до грешке. Отпремите АСКИ кодирани ПЕМ сертификат.",
- "Valid until {date}" : "Важи до {date}",
- "Delete" : "Обриши",
"Groups" : "Групе",
"Unable to delete {objName}" : "Не могу да обришем {objName}",
"Error creating group" : "Грешка при прављењу групе",
@@ -99,9 +99,8 @@
"A valid password must be provided" : "Морате унети исправну лозинку",
"A valid email must be provided" : "Мора бити наведена исправна е-адреса",
"__language_name__" : "Српски",
- "Sync clients" : "Синхронизовање клијената",
"Personal info" : "Лични подаци",
- "SSL root certificates" : "ССЛ корени сертификати",
+ "Sync clients" : "Синхронизовање клијената",
"Everything (fatal issues, errors, warnings, info, debug)" : "Све (фаталне проблеме, грешке, упозорења, информације, отклањање грешака)",
"Info, warnings, errors and fatal issues" : "Информације, упозорења, грешке и фатални проблеми",
"Warnings, errors and fatal issues" : "Упозорења, грешке и фатални проблеми",
@@ -169,7 +168,6 @@
"Store credentials" : "Сачувај акредитиве",
"Test email settings" : "Тестирај поставке е-поште",
"Send email" : "Пошаљи е-пошту",
- "Log level" : "Ниво бележења",
"Download logfile" : "Преузми записник",
"More" : "Више",
"Less" : "Мање",
@@ -187,8 +185,6 @@
"Developer documentation" : "Програмерска документација",
"Experimental applications ahead" : "Експериментална апликација",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Експерименталне апликације се непроверене што се тиче безбедности и могу бити нестабилне и недовршене. Инсталирање може довести до губитка података или нарушавања безбедности.",
- "by" : "од",
- "licensed" : "лиценцирано",
"Documentation:" : "Документација:",
"User documentation" : "Корисничка документација",
"Admin documentation" : "Администраторска документација",
@@ -198,6 +194,11 @@
"Enable only for specific groups" : "Укључи само за одређене групе",
"Uninstall App" : "Деинсталирај апликацију",
"Enable experimental apps" : "Укључи експерименталне апликације",
+ "Common Name" : "Уобичајено име",
+ "Valid until" : "Важи до",
+ "Issued By" : "Издавач",
+ "Valid until %s" : "Важи до %s",
+ "Import root certificate" : "Увоз кореног сертификата",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Поздрав,<br><br>само вас обавештавам да сад имате %s налог.<br><br>Ваше корисничко име: %s<br>Приступите му на: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Здраво!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Поздрав.\n\nСамо да знате да сада имате %s налог.\n\nВаше корисничко име: %s\nПриступите му на: %s\n",
@@ -206,39 +207,29 @@
"Forum" : "Форум",
"Issue tracker" : "Пратилац проблема",
"Commercial support" : "Комерцијална подршка",
- "Get the apps to sync your files" : "Преузмите апликације ради синхронизовања ваших фајлова",
- "Desktop client" : "Клијент за рачунар",
- "Android app" : "Андроид апликација",
- "iOS app" : "иОС апликација",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ако желите да подржите пројект\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">придружите се развоју</a>\n\t\tили\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">разгласите свима</a>!",
- "Show First Run Wizard again" : "Поново прикажи чаробњака за прво покретање",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Искористили сте <strong>%s</strong> од дозвољених <strong>%s</strong>",
- "Password" : "Лозинка",
- "Unable to change your password" : "Не могу да изменим вашу лозинку",
- "Current password" : "Тренутна лозинка",
- "New password" : "Нова лозинка",
- "Change password" : "Измени лозинку",
+ "Profile picture" : "Слика профила",
+ "Upload new" : "Отпреми нову",
+ "Remove image" : "Уклони слику",
+ "Cancel" : "Одустани",
"Full name" : "Пуно име",
"No display name set" : "Није постављено име за приказ",
"Email" : "Е-пошта",
"Your email address" : "Ваша адреса е-поште",
- "Fill in an email address to enable password recovery and receive notifications" : "Попуните е-адресу да омогућите обнављање лозинке и добијате обавештења",
"No email address set" : "Није постављена е-адреса",
"You are member of the following groups:" : "Имате чланство у следећим групама:",
- "Profile picture" : "Слика профила",
- "Upload new" : "Отпреми нову",
- "Select new from Files" : "Изабери нову из фајлова",
- "Remove image" : "Уклони слику",
- "Your avatar is provided by your original account." : "Ваш аватар је добијен са оригиналног налога.",
- "Cancel" : "Одустани",
- "Choose as profile image" : "Изаберите слику профила",
+ "Password" : "Лозинка",
+ "Unable to change your password" : "Не могу да изменим вашу лозинку",
+ "Current password" : "Тренутна лозинка",
+ "New password" : "Нова лозинка",
+ "Change password" : "Измени лозинку",
"Language" : "Језик",
"Help translate" : " Помозите у превођењу",
- "Common Name" : "Уобичајено име",
- "Valid until" : "Важи до",
- "Issued By" : "Издавач",
- "Valid until %s" : "Важи до %s",
- "Import root certificate" : "Увоз кореног сертификата",
+ "Get the apps to sync your files" : "Преузмите апликације ради синхронизовања ваших фајлова",
+ "Desktop client" : "Клијент за рачунар",
+ "Android app" : "Андроид апликација",
+ "iOS app" : "иОС апликација",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Ако желите да подржите пројект\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">придружите се развоју</a>\n\t\tили\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">разгласите свима</a>!",
+ "Show First Run Wizard again" : "Поново прикажи чаробњака за прво покретање",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Развијено од стране {communityopen}оунКлауд заједнице{linkclose}, {githubopen}изворни код{linkclose} је лиценциран под {licenseopen}<abbr title=\"Аферо општа јавна лиценца\">АОЈЛ (AGPL)</abbr>{linkclose}.",
"Show storage location" : "Прикажи локацију складишта",
"Show last log in" : "Прикажи последњу пријаву",
diff --git a/settings/l10n/sr@latin.js b/settings/l10n/sr@latin.js
index baacd0efddb..74140b16670 100644
--- a/settings/l10n/sr@latin.js
+++ b/settings/l10n/sr@latin.js
@@ -3,34 +3,33 @@ OC.L10N.register(
{
"External Storage" : "Spoljašnje skladište",
"Updates" : "Ažuriranja",
- "Authentication error" : "Greška pri autentifikaciji",
"Language changed" : "Jezik je izmenjen",
"Invalid request" : "Neispravan zahtev",
+ "Authentication error" : "Greška pri autentifikaciji",
"Saved" : "Sačuvano",
"Email sent" : "Email poslat",
+ "Delete" : "Obriši",
"Very weak password" : "Veoma slaba lozinka",
"Weak password" : "Slaba lozinka",
"So-so password" : "Osrednja lozinka",
"Good password" : "Dobra lozinka",
"Strong password" : "Jaka lozinka",
- "Delete" : "Obriši",
"Groups" : "Grupe",
"never" : "nikad",
"Port" : "Port",
- "by" : "od",
"Cheers!" : "U zdravlje!",
- "Get the apps to sync your files" : "Preuzmite aplikacije za sinhronizaciju Vaših fajlova",
- "Desktop client" : "Desktop klijent",
- "Android app" : "Android aplikacija",
- "iOS app" : "iOS aplikacija",
+ "Cancel" : "Otkaži",
+ "Email" : "E-mail",
"Password" : "Lozinka",
"Unable to change your password" : "Ne mogu da izmenim vašu lozinku",
"Current password" : "Trenutna lozinka",
"New password" : "Nova lozinka",
"Change password" : "Izmeni lozinku",
- "Email" : "E-mail",
- "Cancel" : "Otkaži",
"Language" : "Jezik",
+ "Get the apps to sync your files" : "Preuzmite aplikacije za sinhronizaciju Vaših fajlova",
+ "Desktop client" : "Desktop klijent",
+ "Android app" : "Android aplikacija",
+ "iOS app" : "iOS aplikacija",
"Username" : "Korisničko ime",
"Create" : "Napravi",
"Group" : "Grupa",
diff --git a/settings/l10n/sr@latin.json b/settings/l10n/sr@latin.json
index 70392768da4..e2265e5ff1a 100644
--- a/settings/l10n/sr@latin.json
+++ b/settings/l10n/sr@latin.json
@@ -1,34 +1,33 @@
{ "translations": {
"External Storage" : "Spoljašnje skladište",
"Updates" : "Ažuriranja",
- "Authentication error" : "Greška pri autentifikaciji",
"Language changed" : "Jezik je izmenjen",
"Invalid request" : "Neispravan zahtev",
+ "Authentication error" : "Greška pri autentifikaciji",
"Saved" : "Sačuvano",
"Email sent" : "Email poslat",
+ "Delete" : "Obriši",
"Very weak password" : "Veoma slaba lozinka",
"Weak password" : "Slaba lozinka",
"So-so password" : "Osrednja lozinka",
"Good password" : "Dobra lozinka",
"Strong password" : "Jaka lozinka",
- "Delete" : "Obriši",
"Groups" : "Grupe",
"never" : "nikad",
"Port" : "Port",
- "by" : "od",
"Cheers!" : "U zdravlje!",
- "Get the apps to sync your files" : "Preuzmite aplikacije za sinhronizaciju Vaših fajlova",
- "Desktop client" : "Desktop klijent",
- "Android app" : "Android aplikacija",
- "iOS app" : "iOS aplikacija",
+ "Cancel" : "Otkaži",
+ "Email" : "E-mail",
"Password" : "Lozinka",
"Unable to change your password" : "Ne mogu da izmenim vašu lozinku",
"Current password" : "Trenutna lozinka",
"New password" : "Nova lozinka",
"Change password" : "Izmeni lozinku",
- "Email" : "E-mail",
- "Cancel" : "Otkaži",
"Language" : "Jezik",
+ "Get the apps to sync your files" : "Preuzmite aplikacije za sinhronizaciju Vaših fajlova",
+ "Desktop client" : "Desktop klijent",
+ "Android app" : "Android aplikacija",
+ "iOS app" : "iOS aplikacija",
"Username" : "Korisničko ime",
"Create" : "Napravi",
"Group" : "Grupa",
diff --git a/settings/l10n/sv.js b/settings/l10n/sv.js
index 43c6bf06218..4c0014f8aab 100644
--- a/settings/l10n/sv.js
+++ b/settings/l10n/sv.js
@@ -6,12 +6,10 @@ OC.L10N.register(
"Cron" : "Cron",
"Log" : "Logg",
"Updates" : "Uppdateringar",
- "Authentication error" : "Fel vid autentisering",
- "Your full name has been changed." : "Hela ditt namn har ändrats",
- "Unable to change full name" : "Kunde inte ändra hela namnet",
"Couldn't remove app." : "Kunde inte ta bort applikationen.",
"Language changed" : "Språk ändrades",
"Invalid request" : "Ogiltig begäran",
+ "Authentication error" : "Fel vid autentisering",
"Admins can't remove themself from the admin group" : "Administratörer kan inte ta bort sig själva från admingruppen",
"Unable to add user to group %s" : "Kan inte lägga till användare i gruppen %s",
"Unable to remove user from group %s" : "Kan inte radera användare från gruppen %s",
@@ -39,6 +37,8 @@ OC.L10N.register(
"Invalid user" : "Ogiltig användare",
"Unable to change mail address" : "Kan inte ändra e-postadress",
"Email saved" : "E-post sparad",
+ "Your full name has been changed." : "Hela ditt namn har ändrats",
+ "Unable to change full name" : "Kunde inte ändra hela namnet",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Är du verkligen säker på att du vill lägga till \"{domain}\" som en trusted domian?",
"Add trusted domain" : "Lägg till betrodd domän",
"Sending..." : "Skickar ...",
@@ -55,14 +55,14 @@ OC.L10N.register(
"Uninstalling ...." : "Avinstallerar ...",
"Error while uninstalling app" : "Ett fel inträffade när applikatonen avinstallerades",
"Uninstall" : "Avinstallera",
+ "Valid until {date}" : "Giltig t.o.m. {date}",
+ "Delete" : "Radera",
"Select a profile picture" : "Välj en profilbild",
"Very weak password" : "Väldigt svagt lösenord",
"Weak password" : "Svagt lösenord",
"So-so password" : "Okej lösenord",
"Good password" : "Bra lösenord",
"Strong password" : "Starkt lösenord",
- "Valid until {date}" : "Giltig t.o.m. {date}",
- "Delete" : "Radera",
"Groups" : "Grupper",
"Unable to delete {objName}" : "Kunde inte radera {objName}",
"Error creating group" : "Fel vid skapande av grupp",
@@ -78,7 +78,6 @@ OC.L10N.register(
"A valid password must be provided" : "Ett giltigt lösenord måste anges",
"A valid email must be provided" : "En giltig e-postadress måste anges",
"__language_name__" : "__language_name__",
- "SSL root certificates" : "SSL rotcertifikat",
"Everything (fatal issues, errors, warnings, info, debug)" : "Allting (allvarliga fel, fel, varningar, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, varningar och allvarliga fel",
"Warnings, errors and fatal issues" : "Varningar, fel och allvarliga fel",
@@ -132,50 +131,42 @@ OC.L10N.register(
"Store credentials" : "Lagra inloggningsuppgifter",
"Test email settings" : "Testa e-postinställningar",
"Send email" : "Skicka e-post",
- "Log level" : "Nivå på loggning",
"Download logfile" : "Ladda ner loggfil",
"More" : "Mer",
"Less" : "Mindre",
"Version" : "Version",
- "by" : "av",
- "licensed" : "licensierad",
"Documentation:" : "Dokumentation:",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Denna applikation kan inte installeras då följande beroenden inte är uppfyllda: %s",
"Enable only for specific groups" : "Aktivera endast för specifika grupper",
"Uninstall App" : "Avinstallera applikation",
+ "Common Name" : "Vanligt namn",
+ "Valid until" : "Giltigt till",
+ "Issued By" : "Utfärdat av",
+ "Valid until %s" : "Giltigt till %s",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hej där,<br><br>vill bara informera dig om att du nu har ett %s konto.<br><br>Ditt användarnamn: %s<br>Accessa det genom: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Ha de fint!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hej där,\n\nvill bara informera dig om att du nu har ett %s konto.\n\nDitt användarnamn: %s\nAccessa det genom: %s\n",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Skaffa apparna för att synkronisera dina filer",
- "Desktop client" : "Skrivbordsklient",
- "Android app" : "Android-app",
- "iOS app" : "iOS-app",
- "Show First Run Wizard again" : "Visa Första uppstarts-guiden igen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du har använt <strong>%s</strong> av tillgängliga <strong>%s</strong>",
+ "Profile picture" : "Profilbild",
+ "Upload new" : "Ladda upp ny",
+ "Remove image" : "Radera bild",
+ "Cancel" : "Avbryt",
+ "No display name set" : "Inget visningsnamn angivet",
+ "Email" : "E-post",
+ "Your email address" : "Din e-postadress",
+ "No email address set" : "Ingen e-postadress angiven",
"Password" : "Lösenord",
"Unable to change your password" : "Kunde inte ändra ditt lösenord",
"Current password" : "Nuvarande lösenord",
"New password" : "Nytt lösenord",
"Change password" : "Ändra lösenord",
- "No display name set" : "Inget visningsnamn angivet",
- "Email" : "E-post",
- "Your email address" : "Din e-postadress",
- "Fill in an email address to enable password recovery and receive notifications" : "Fyll i en e-postadress för att aktivera återställning av lösenord och mottagande av notifieringar",
- "No email address set" : "Ingen e-postadress angiven",
- "Profile picture" : "Profilbild",
- "Upload new" : "Ladda upp ny",
- "Select new from Files" : "Välj ny från filer",
- "Remove image" : "Radera bild",
- "Your avatar is provided by your original account." : "Din avatar tillhandahålls av ditt ursprungliga konto.",
- "Cancel" : "Avbryt",
- "Choose as profile image" : "Välj som profilbild",
"Language" : "Språk",
"Help translate" : "Hjälp att översätta",
- "Common Name" : "Vanligt namn",
- "Valid until" : "Giltigt till",
- "Issued By" : "Utfärdat av",
- "Valid until %s" : "Giltigt till %s",
+ "Get the apps to sync your files" : "Skaffa apparna för att synkronisera dina filer",
+ "Desktop client" : "Skrivbordsklient",
+ "Android app" : "Android-app",
+ "iOS app" : "iOS-app",
+ "Show First Run Wizard again" : "Visa Första uppstarts-guiden igen",
"Show storage location" : "Visa lagringsplats",
"Show last log in" : "Visa senaste inloggning",
"Show user backend" : "Visa användar-back-end",
diff --git a/settings/l10n/sv.json b/settings/l10n/sv.json
index 3e61a6e9650..727efde7524 100644
--- a/settings/l10n/sv.json
+++ b/settings/l10n/sv.json
@@ -4,12 +4,10 @@
"Cron" : "Cron",
"Log" : "Logg",
"Updates" : "Uppdateringar",
- "Authentication error" : "Fel vid autentisering",
- "Your full name has been changed." : "Hela ditt namn har ändrats",
- "Unable to change full name" : "Kunde inte ändra hela namnet",
"Couldn't remove app." : "Kunde inte ta bort applikationen.",
"Language changed" : "Språk ändrades",
"Invalid request" : "Ogiltig begäran",
+ "Authentication error" : "Fel vid autentisering",
"Admins can't remove themself from the admin group" : "Administratörer kan inte ta bort sig själva från admingruppen",
"Unable to add user to group %s" : "Kan inte lägga till användare i gruppen %s",
"Unable to remove user from group %s" : "Kan inte radera användare från gruppen %s",
@@ -37,6 +35,8 @@
"Invalid user" : "Ogiltig användare",
"Unable to change mail address" : "Kan inte ändra e-postadress",
"Email saved" : "E-post sparad",
+ "Your full name has been changed." : "Hela ditt namn har ändrats",
+ "Unable to change full name" : "Kunde inte ändra hela namnet",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Är du verkligen säker på att du vill lägga till \"{domain}\" som en trusted domian?",
"Add trusted domain" : "Lägg till betrodd domän",
"Sending..." : "Skickar ...",
@@ -53,14 +53,14 @@
"Uninstalling ...." : "Avinstallerar ...",
"Error while uninstalling app" : "Ett fel inträffade när applikatonen avinstallerades",
"Uninstall" : "Avinstallera",
+ "Valid until {date}" : "Giltig t.o.m. {date}",
+ "Delete" : "Radera",
"Select a profile picture" : "Välj en profilbild",
"Very weak password" : "Väldigt svagt lösenord",
"Weak password" : "Svagt lösenord",
"So-so password" : "Okej lösenord",
"Good password" : "Bra lösenord",
"Strong password" : "Starkt lösenord",
- "Valid until {date}" : "Giltig t.o.m. {date}",
- "Delete" : "Radera",
"Groups" : "Grupper",
"Unable to delete {objName}" : "Kunde inte radera {objName}",
"Error creating group" : "Fel vid skapande av grupp",
@@ -76,7 +76,6 @@
"A valid password must be provided" : "Ett giltigt lösenord måste anges",
"A valid email must be provided" : "En giltig e-postadress måste anges",
"__language_name__" : "__language_name__",
- "SSL root certificates" : "SSL rotcertifikat",
"Everything (fatal issues, errors, warnings, info, debug)" : "Allting (allvarliga fel, fel, varningar, info, debug)",
"Info, warnings, errors and fatal issues" : "Info, varningar och allvarliga fel",
"Warnings, errors and fatal issues" : "Varningar, fel och allvarliga fel",
@@ -130,50 +129,42 @@
"Store credentials" : "Lagra inloggningsuppgifter",
"Test email settings" : "Testa e-postinställningar",
"Send email" : "Skicka e-post",
- "Log level" : "Nivå på loggning",
"Download logfile" : "Ladda ner loggfil",
"More" : "Mer",
"Less" : "Mindre",
"Version" : "Version",
- "by" : "av",
- "licensed" : "licensierad",
"Documentation:" : "Dokumentation:",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Denna applikation kan inte installeras då följande beroenden inte är uppfyllda: %s",
"Enable only for specific groups" : "Aktivera endast för specifika grupper",
"Uninstall App" : "Avinstallera applikation",
+ "Common Name" : "Vanligt namn",
+ "Valid until" : "Giltigt till",
+ "Issued By" : "Utfärdat av",
+ "Valid until %s" : "Giltigt till %s",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Hej där,<br><br>vill bara informera dig om att du nu har ett %s konto.<br><br>Ditt användarnamn: %s<br>Accessa det genom: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Ha de fint!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Hej där,\n\nvill bara informera dig om att du nu har ett %s konto.\n\nDitt användarnamn: %s\nAccessa det genom: %s\n",
"Forum" : "Forum",
- "Get the apps to sync your files" : "Skaffa apparna för att synkronisera dina filer",
- "Desktop client" : "Skrivbordsklient",
- "Android app" : "Android-app",
- "iOS app" : "iOS-app",
- "Show First Run Wizard again" : "Visa Första uppstarts-guiden igen",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Du har använt <strong>%s</strong> av tillgängliga <strong>%s</strong>",
+ "Profile picture" : "Profilbild",
+ "Upload new" : "Ladda upp ny",
+ "Remove image" : "Radera bild",
+ "Cancel" : "Avbryt",
+ "No display name set" : "Inget visningsnamn angivet",
+ "Email" : "E-post",
+ "Your email address" : "Din e-postadress",
+ "No email address set" : "Ingen e-postadress angiven",
"Password" : "Lösenord",
"Unable to change your password" : "Kunde inte ändra ditt lösenord",
"Current password" : "Nuvarande lösenord",
"New password" : "Nytt lösenord",
"Change password" : "Ändra lösenord",
- "No display name set" : "Inget visningsnamn angivet",
- "Email" : "E-post",
- "Your email address" : "Din e-postadress",
- "Fill in an email address to enable password recovery and receive notifications" : "Fyll i en e-postadress för att aktivera återställning av lösenord och mottagande av notifieringar",
- "No email address set" : "Ingen e-postadress angiven",
- "Profile picture" : "Profilbild",
- "Upload new" : "Ladda upp ny",
- "Select new from Files" : "Välj ny från filer",
- "Remove image" : "Radera bild",
- "Your avatar is provided by your original account." : "Din avatar tillhandahålls av ditt ursprungliga konto.",
- "Cancel" : "Avbryt",
- "Choose as profile image" : "Välj som profilbild",
"Language" : "Språk",
"Help translate" : "Hjälp att översätta",
- "Common Name" : "Vanligt namn",
- "Valid until" : "Giltigt till",
- "Issued By" : "Utfärdat av",
- "Valid until %s" : "Giltigt till %s",
+ "Get the apps to sync your files" : "Skaffa apparna för att synkronisera dina filer",
+ "Desktop client" : "Skrivbordsklient",
+ "Android app" : "Android-app",
+ "iOS app" : "iOS-app",
+ "Show First Run Wizard again" : "Visa Första uppstarts-guiden igen",
"Show storage location" : "Visa lagringsplats",
"Show last log in" : "Visa senaste inloggning",
"Show user backend" : "Visa användar-back-end",
diff --git a/settings/l10n/ta_LK.js b/settings/l10n/ta_LK.js
index f611af9eb14..b38eaf0eaaa 100644
--- a/settings/l10n/ta_LK.js
+++ b/settings/l10n/ta_LK.js
@@ -2,9 +2,9 @@ OC.L10N.register(
"settings",
{
"External Storage" : "வெளி சேமிப்பு",
- "Authentication error" : "அத்தாட்சிப்படுத்தலில் வழு",
"Language changed" : "மொழி மாற்றப்பட்டது",
"Invalid request" : "செல்லுபடியற்ற வேண்டுகோள்",
+ "Authentication error" : "அத்தாட்சிப்படுத்தலில் வழு",
"Unable to add user to group %s" : "குழு %s இல் பயனாளரை சேர்க்க முடியாது",
"Unable to remove user from group %s" : "குழு %s இலிருந்து பயனாளரை நீக்கமுடியாது",
"Email saved" : "மின்னஞ்சல் சேமிக்கப்பட்டது",
@@ -16,7 +16,6 @@ OC.L10N.register(
"undo" : "முன் செயல் நீக்கம் ",
"never" : "ஒருபோதும்",
"__language_name__" : "_மொழி_பெயர்_",
- "SSL root certificates" : "SSL வேர் சான்றிதழ்கள்",
"None" : "ஒன்றுமில்லை",
"Login" : "புகுபதிகை",
"Encryption" : "மறைக்குறியீடு",
@@ -25,16 +24,14 @@ OC.L10N.register(
"Credentials" : "சான்று ஆவணங்கள்",
"More" : "மேலதிக",
"Less" : "குறைவான",
- "by" : "மூலம்",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "நீங்கள் <strong>%s</strong> இலுள்ள <strong>%s</strong>பயன்படுத்தியுள்ளீர்கள்",
+ "Cancel" : "இரத்து செய்க",
+ "Email" : "மின்னஞ்சல்",
+ "Your email address" : "உங்களுடைய மின்னஞ்சல் முகவரி",
"Password" : "கடவுச்சொல்",
"Unable to change your password" : "உங்களுடைய கடவுச்சொல்லை மாற்றமுடியாது",
"Current password" : "தற்போதைய கடவுச்சொல்",
"New password" : "புதிய கடவுச்சொல்",
"Change password" : "கடவுச்சொல்லை மாற்றுக",
- "Email" : "மின்னஞ்சல்",
- "Your email address" : "உங்களுடைய மின்னஞ்சல் முகவரி",
- "Cancel" : "இரத்து செய்க",
"Language" : "மொழி",
"Help translate" : "மொழிபெயர்க்க உதவி",
"Username" : "பயனாளர் பெயர்",
diff --git a/settings/l10n/ta_LK.json b/settings/l10n/ta_LK.json
index 1a16f5f7b3e..2d5b11732d8 100644
--- a/settings/l10n/ta_LK.json
+++ b/settings/l10n/ta_LK.json
@@ -1,8 +1,8 @@
{ "translations": {
"External Storage" : "வெளி சேமிப்பு",
- "Authentication error" : "அத்தாட்சிப்படுத்தலில் வழு",
"Language changed" : "மொழி மாற்றப்பட்டது",
"Invalid request" : "செல்லுபடியற்ற வேண்டுகோள்",
+ "Authentication error" : "அத்தாட்சிப்படுத்தலில் வழு",
"Unable to add user to group %s" : "குழு %s இல் பயனாளரை சேர்க்க முடியாது",
"Unable to remove user from group %s" : "குழு %s இலிருந்து பயனாளரை நீக்கமுடியாது",
"Email saved" : "மின்னஞ்சல் சேமிக்கப்பட்டது",
@@ -14,7 +14,6 @@
"undo" : "முன் செயல் நீக்கம் ",
"never" : "ஒருபோதும்",
"__language_name__" : "_மொழி_பெயர்_",
- "SSL root certificates" : "SSL வேர் சான்றிதழ்கள்",
"None" : "ஒன்றுமில்லை",
"Login" : "புகுபதிகை",
"Encryption" : "மறைக்குறியீடு",
@@ -23,16 +22,14 @@
"Credentials" : "சான்று ஆவணங்கள்",
"More" : "மேலதிக",
"Less" : "குறைவான",
- "by" : "மூலம்",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "நீங்கள் <strong>%s</strong> இலுள்ள <strong>%s</strong>பயன்படுத்தியுள்ளீர்கள்",
+ "Cancel" : "இரத்து செய்க",
+ "Email" : "மின்னஞ்சல்",
+ "Your email address" : "உங்களுடைய மின்னஞ்சல் முகவரி",
"Password" : "கடவுச்சொல்",
"Unable to change your password" : "உங்களுடைய கடவுச்சொல்லை மாற்றமுடியாது",
"Current password" : "தற்போதைய கடவுச்சொல்",
"New password" : "புதிய கடவுச்சொல்",
"Change password" : "கடவுச்சொல்லை மாற்றுக",
- "Email" : "மின்னஞ்சல்",
- "Your email address" : "உங்களுடைய மின்னஞ்சல் முகவரி",
- "Cancel" : "இரத்து செய்க",
"Language" : "மொழி",
"Help translate" : "மொழிபெயர்க்க உதவி",
"Username" : "பயனாளர் பெயர்",
diff --git a/settings/l10n/te.js b/settings/l10n/te.js
index f09acb41060..6db1a682c12 100644
--- a/settings/l10n/te.js
+++ b/settings/l10n/te.js
@@ -4,11 +4,11 @@ OC.L10N.register(
"Delete" : "తొలగించు",
"Server address" : "సేవకి చిరునామా",
"More" : "మరిన్ని",
- "Password" : "సంకేతపదం",
- "New password" : "కొత్త సంకేతపదం",
+ "Cancel" : "రద్దుచేయి",
"Email" : "ఈమెయిలు",
"Your email address" : "మీ ఈమెయిలు చిరునామా",
- "Cancel" : "రద్దుచేయి",
+ "Password" : "సంకేతపదం",
+ "New password" : "కొత్త సంకేతపదం",
"Language" : "భాష",
"Username" : "వాడుకరి పేరు"
},
diff --git a/settings/l10n/te.json b/settings/l10n/te.json
index 031f99d1498..5b4d5344fa3 100644
--- a/settings/l10n/te.json
+++ b/settings/l10n/te.json
@@ -2,11 +2,11 @@
"Delete" : "తొలగించు",
"Server address" : "సేవకి చిరునామా",
"More" : "మరిన్ని",
- "Password" : "సంకేతపదం",
- "New password" : "కొత్త సంకేతపదం",
+ "Cancel" : "రద్దుచేయి",
"Email" : "ఈమెయిలు",
"Your email address" : "మీ ఈమెయిలు చిరునామా",
- "Cancel" : "రద్దుచేయి",
+ "Password" : "సంకేతపదం",
+ "New password" : "కొత్త సంకేతపదం",
"Language" : "భాష",
"Username" : "వాడుకరి పేరు"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/settings/l10n/th_TH.js b/settings/l10n/th_TH.js
index d4de49436b0..0eeb7d30057 100644
--- a/settings/l10n/th_TH.js
+++ b/settings/l10n/th_TH.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "บันทึกการเปลี่ยนแปลง",
"Tips & tricks" : "เคล็ดลับและเทคนิค",
"Updates" : "อัพเดท",
- "Authentication error" : "เกิดข้อผิดพลาดในสิทธิ์การเข้าใช้งาน",
- "Your full name has been changed." : "ชื่อเต็มของคุณถูกเปลี่ยนแปลง",
- "Unable to change full name" : "ไม่สามารถเปลี่ยนชื่อเต็ม",
"Couldn't remove app." : "ไม่สามารถลบแอพฯ",
"Language changed" : "เปลี่ยนภาษาเรียบร้อยแล้ว",
"Invalid request" : "คำร้องขอไม่ถูกต้อง",
+ "Authentication error" : "เกิดข้อผิดพลาดในสิทธิ์การเข้าใช้งาน",
"Admins can't remove themself from the admin group" : "ผู้ดูแลระบบไม่สามารถลบตัวเองออกจากกลุ่มผู้ดูแลได้",
"Unable to add user to group %s" : "ไม่สามารถเพิ่มผู้ใช้งานเข้าไปที่กลุ่ม %s ได้",
"Unable to remove user from group %s" : "ไม่สามารถลบผู้ใช้งานออกจากกลุ่ม %s ได้",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "ผู้ใช้ไม่ถูกต้อง",
"Unable to change mail address" : "ไม่สามารถที่จะเปลี่ยนที่อยู่อีเมล",
"Email saved" : "อีเมลถูกบันทึกแล้ว",
+ "Your full name has been changed." : "ชื่อเต็มของคุณถูกเปลี่ยนแปลง",
+ "Unable to change full name" : "ไม่สามารถเปลี่ยนชื่อเต็ม",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "คุณแน่ใจจริงๆ ว่าคุณต้องการเพิ่ม \"{domain}\" เป็นโดเมนที่เชื่อถือได้?",
"Add trusted domain" : "เพิ่มโดเมนที่เชื่อถือได้",
"Migration in progress. Please wait until the migration is finished" : "ในระหว่างดำเนินการโยกย้าย กรุณารอสักครู่จนกว่าการโยกย้ายจะเสร็จสิ้น",
@@ -81,6 +81,9 @@ OC.L10N.register(
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "แอพฯจะต้องเปิดใช้งานก่อนทำการอัพเดท คุณจะถูกนำไปยังหน้าอัพเดทใน 5 วินาที",
"App update" : "อัพเดทแอพฯ",
"No apps found for \"{query}\"" : "ไม่พบแอพฯสำหรับ \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "เกิดข้อผิดพลาด กรุณาอัพโหลดใบรับรองเข้ารหัส ASCII PEM",
+ "Valid until {date}" : "ใช้ได้จนถึงวันที่ {date}",
+ "Delete" : "ลบ",
"An error occurred: {message}" : "เกิดข้อผิดพลาด: {message}",
"Select a profile picture" : "เลือกรูปภาพโปรไฟล์",
"Very weak password" : "รหัสผ่านระดับต่ำมาก",
@@ -88,9 +91,6 @@ OC.L10N.register(
"So-so password" : "รหัสผ่านระดับปกติ",
"Good password" : "รหัสผ่านระดับดี",
"Strong password" : "รหัสผ่านระดับดีมาก",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "เกิดข้อผิดพลาด กรุณาอัพโหลดใบรับรองเข้ารหัส ASCII PEM",
- "Valid until {date}" : "ใช้ได้จนถึงวันที่ {date}",
- "Delete" : "ลบ",
"Groups" : "กลุ่ม",
"Unable to delete {objName}" : "ไม่สามารถลบ {objName}",
"Error creating group" : "ข้อผิดพลาดขณะกำลังสร้างกลุ่ม",
@@ -107,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "จะต้องระบุรหัสผ่านที่ถูกต้อง",
"A valid email must be provided" : "จะต้องระบุอีเมลที่ถูกต้อง",
"__language_name__" : "ภาษาไทย - Thai languages",
- "Sync clients" : "ประสานข้อมูลไคลเอนต์",
"Personal info" : "ข้อมูลส่วนบุคคล",
- "SSL root certificates" : "ใบรับรองความปลอดภัยด้วยระบบ SSL จาก Root",
+ "Sync clients" : "ประสานข้อมูลไคลเอนต์",
"Everything (fatal issues, errors, warnings, info, debug)" : "ทุกอย่าง (ปัญหาร้ายแรง ข้อผิดพลาด คำเตือน ข้อมูล การแก้ปัญหา)",
"Info, warnings, errors and fatal issues" : "ข้อมูล คำเตือน ข้อผิดพลาดและปัญหาร้ายแรง",
"Warnings, errors and fatal issues" : "คำเตือนข้อผิดพลาดและปัญหาที่ร้ายแรง",
@@ -135,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "เราขอแนะนำให้ติดตั้งแพคเกจที่จำเป็นต้องใช้ในระบบของคุณ ให้การสนับสนุนตำแหน่งที่ตั้งดังต่อไปนี้: %s",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "หากการติดตั้งของคุณไม่ได้ติดตั้งในรากของโดเมนและใช้ระบบ cron อาจมีปัญหาเกี่ยวกับการสร้าง URL เพื่อหลีกเลี่ยงปัญหาเหล่านี้โปรดไปตั้งค่า \"overwrite.cli.url\" ในไฟล์ config.php ของคุณไปยังเส้นทาง webroot ของการติดตั้งของคุณ (แนะนำ: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "มันเป็นไปไม่ได้ที่จะดำเนินการ cronjob ผ่านทาง CLI ข้อผิดพลาดทางเทคนิคต่อไปนี้จะปรากฏ:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "การทำธุรกรรมล็อคไฟล์จะใช้ฐานข้อมูลเป็นล็อคแบ็กเอนด์ สำหรับประสิทธิภาพที่ดีที่สุดก็ควรที่จะกำหนดค่า memcache สำหรับล็อค ดูเพิ่มเติมได้จาก <a target=\"_blank\" href=\"%s\">เอกสาร</a>",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "กรุณาตรวจสอบ <a target=\"_blank\" href=\"%s\">คู่มือการติดตั้ง</a> และตรวจสอบข้อผิดพลาดหรือคำเตือนใน <a href=\"#log-section\">บันทึก</a>",
"All checks passed." : "ผ่านการตรวจสอบทั้งหมด",
"Open documentation" : "เปิดเอกสาร",
@@ -188,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "ข้อมูลประจำตัวของร้านค้า",
"Test email settings" : "การตั้งค่าอีเมลทดสอบ",
"Send email" : "ส่งอีเมล",
- "Log level" : "ระดับการเก็บบันทึก log",
"Download logfile" : "ดาวน์โหลดไฟล์บันทึก",
"More" : "มาก",
"Less" : "น้อย",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "ไฟล์บันทึกมีขนาดใหญ่กว่า 100 เมกะไบต์ มันอาจจะใช้เวลาดาวน์โหลดนาน!",
+ "What to log" : "อะไรที่จะบันทึก",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "จะใช้ SQLite เป็นฐานข้อมูล สำหรับการติดตั้งขนาดใหญ่เราขอแนะนำเพื่อสลับไปยังฐานข้อมูลแบ็กเอนด์ที่แตกต่างกัน",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "โดยเฉพาะอย่างยิ่งเมื่อใช้ไคลเอนต์เดสก์ทอปสำหรับการประสานข้อมูลโดย SQLite",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "การโยกย้ายไปยังฐานข้อมูลอื่นใช้เครื่องมือบรรทัดคำสั่ง: 'occ db:convert-type' หรือดูที่ <a target=\"_blank\" href=\"%s\">เอกสาร</a>",
@@ -206,17 +204,25 @@ OC.L10N.register(
"Developer documentation" : "เอกสารสำหรับนักพัฒนา",
"Experimental applications ahead" : "การใช้งานก่อนการทดลอง",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "การทดลองแอพพลิเคชันไม่ได้ถูกตรวจสอบปัญหาด้านความปลอดภัย การติดตั้งพวกเขาสามารถก่อให้เกิดการสูญเสียข้อมูลหรือการละเมิดความปลอดภัย",
- "by" : "โดย",
- "licensed" : "ได้รับใบอนุญาต",
+ "by %s" : "โดย %s",
+ "%s-licensed" : "%s ได้รับใบอนุญาต",
"Documentation:" : "เอกสาร:",
"User documentation" : "เอกสารสำหรับผู้ใช้",
"Admin documentation" : "เอกสารผู้ดูแลระบบ",
"Show description …" : "แสดงรายละเอียด ...",
"Hide description …" : "ซ่อนรายละเอียด ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "แอพฯนี้ได้ไม่บ่งบอกรุ่นต่ำสุดของ ownCloud นี้จะเป็นข้อผิดพลาดใน ownCloud ที่ 11 และรุ่นต่อมา",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "แอพฯนี้ได้ไม่บ่งบอกรุ่นสูงสุดของ ownCloud นี้จะเป็นข้อผิดพลาดใน ownCloud ที่ 11 และรุ่นต่อมา",
"This app cannot be installed because the following dependencies are not fulfilled:" : "ไม่สามารถติดตั้งแอพฯนี้เพราะไม่มีตัวอ้างอิงต่อไปนี้:",
"Enable only for specific groups" : "เปิดใช้งานเพียงเฉพาะกลุ่ม",
"Uninstall App" : "ถอนการติดตั้งแอพฯ",
"Enable experimental apps" : "เปิดใช้งานแอพพลิเคชั่นทดลอง",
+ "SSL Root Certificates" : "ใบรับรอง SSL",
+ "Common Name" : "ชื่อทั่วไป",
+ "Valid until" : "ใช้ได้จนถึง",
+ "Issued By" : "ปัญหาโดย",
+ "Valid until %s" : "ใช้ได้จนถึง %s",
+ "Import root certificate" : "นำเข้าใบรับรองหลัก",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "นี่คุณ<br><br>อยากจะแจ้งให้คุณทราบว่าขณะนี้คุณมีบัญชี %s<br><br>ชื่อผู้ใช้ของคุณคือ: %s<br>เข้าไปงานได้ที่: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "ไชโย!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "นี่คุณ\n\nอยากให้คุณทราบว่าขณะนี้คุณมี %s บัญชี\n\nชื่อผู้ใช้ของคุณ: %s\nดูได้ที่: %s\n",
@@ -225,40 +231,35 @@ OC.L10N.register(
"Forum" : "ฟอรั่ม",
"Issue tracker" : "ติดตามปัญหา",
"Commercial support" : "สนับสนุนเชิงพาณิชย์",
- "Get the apps to sync your files" : "ใช้แอพพลิเคชันในการประสานไฟล์ของคุณ",
- "Desktop client" : "เดสก์ทอปผู้ใช้",
- "Android app" : "แอพฯ แอนดรอยด์",
- "iOS app" : "แอพฯ IOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "หากคุณต้องการที่จะสนับสนุนโครงการ <a href=\"https://owncloud.org/contribute\" target=\"_blank\" rel=\"noreferrer\">เข้าร่วมการพัฒนา</a> หรือ <a href=\"https://owncloud.org/promote\" target=\"_blank\" rel=\"noreferrer\">กระจายข่าวสาร</a>!\n\t\t",
- "Show First Run Wizard again" : "แสดงหน้าจอวิซาร์ดนำทางครั้งแรกอีกครั้ง",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "คุณได้ใช้งานไปแล้ว <strong>%s</strong> จากจำนวนที่สามารถใช้ได้ <strong>%s</strong>",
- "Password" : "รหัสผ่าน",
- "Unable to change your password" : "ไม่สามารถเปลี่ยนรหัสผ่านของคุณได้",
- "Current password" : "รหัสผ่านปัจจุบัน",
- "New password" : "รหัสผ่านใหม่",
- "Change password" : "เปลี่ยนรหัสผ่าน",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "คุณกำลังใช้ <strong>%s</strong> ของ <strong>%s</strong>",
+ "Profile picture" : "รูปภาพโปรไฟล์",
+ "Upload new" : "อัพโหลดใหม่",
+ "Select from Files" : "เลือกจากไฟล์",
+ "Remove image" : "ลบรูปภาพ",
+ "png or jpg, max. 20 MB" : "png หรือ jpg, สูงสุด 20 เมกะไบต์",
+ "Picture provided by original account" : "ใช้รูปภาพจากบัญชีเดิม",
+ "Cancel" : "ยกเลิก",
+ "Choose as profile picture" : "เลือกรูปภาพโปรไฟล์",
"Full name" : "ชื่อเต็ม",
"No display name set" : "ไม่มีชื่อที่แสดง",
"Email" : "อีเมล",
"Your email address" : "ที่อยู่อีเมล์ของคุณ",
- "Fill in an email address to enable password recovery and receive notifications" : "กรอกที่อยู่อีเมลเพื่อเปิดใช้งานการกู้คืนรหัสผ่านและการได้รับการแจ้งเตือน",
+ "For password recovery and notifications" : "สำหรับการกู้คืนรหัสผ่านและการแจ้งเตือน",
"No email address set" : "ไม่ได้ตั้งค่าที่อยู่อีเมล",
"You are member of the following groups:" : "คุณเป็นสมาชิกของกลุ่มต่อไปนี้:",
- "Profile picture" : "รูปภาพโปรไฟล์",
- "Upload new" : "อัพโหลดใหม่",
- "Select new from Files" : "เลือกใหม่จากไฟล์",
- "Remove image" : "ลบรูปภาพ",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "การครอบตัดรูปภาพ .PNG หรือ .JPG ให้รูปเป็นสี่เหลี่ยม ไฟล์ต้องมีขนาดไม่เกิน 20 เมกะไบต์",
- "Your avatar is provided by your original account." : "อวตาลของคุณถูกระบุโดยบัญชีเดิมของคุณ",
- "Cancel" : "ยกเลิก",
- "Choose as profile image" : "เลือกรูปภาพโปรไฟล์",
+ "Password" : "รหัสผ่าน",
+ "Unable to change your password" : "ไม่สามารถเปลี่ยนรหัสผ่านของคุณได้",
+ "Current password" : "รหัสผ่านปัจจุบัน",
+ "New password" : "รหัสผ่านใหม่",
+ "Change password" : "เปลี่ยนรหัสผ่าน",
"Language" : "ภาษา",
"Help translate" : "มาช่วยกันแปลสิ!",
- "Common Name" : "ชื่อทั่วไป",
- "Valid until" : "ใช้ได้จนถึง",
- "Issued By" : "ปัญหาโดย",
- "Valid until %s" : "ใช้ได้จนถึง %s",
- "Import root certificate" : "นำเข้าใบรับรองหลัก",
+ "Get the apps to sync your files" : "ใช้แอพพลิเคชันในการประสานไฟล์ของคุณ",
+ "Desktop client" : "เดสก์ทอปผู้ใช้",
+ "Android app" : "แอพฯ แอนดรอยด์",
+ "iOS app" : "แอพฯ IOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "หากคุณต้องการที่จะสนับสนุนโครงการ <a href=\"https://owncloud.org/contribute\" target=\"_blank\" rel=\"noreferrer\">เข้าร่วมการพัฒนา</a> หรือ <a href=\"https://owncloud.org/promote\" target=\"_blank\" rel=\"noreferrer\">กระจายข่าวสาร</a>!\n\t\t",
+ "Show First Run Wizard again" : "แสดงหน้าจอวิซาร์ดนำทางครั้งแรกอีกครั้ง",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "ที่พัฒนาโดย {communityopen} ชุมชน ownCloud {linkclose} {githubopen}รหัสต้นฉบับ{linkclose} อยู่ภายใต้สัญญา {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}",
"Show storage location" : "แสดงสถานที่จัดเก็บข้อมูล",
"Show last log in" : "แสดงการเข้าสู่ระบบล่าสุด",
diff --git a/settings/l10n/th_TH.json b/settings/l10n/th_TH.json
index f365ca49746..be5c8488f36 100644
--- a/settings/l10n/th_TH.json
+++ b/settings/l10n/th_TH.json
@@ -10,12 +10,10 @@
"Log" : "บันทึกการเปลี่ยนแปลง",
"Tips & tricks" : "เคล็ดลับและเทคนิค",
"Updates" : "อัพเดท",
- "Authentication error" : "เกิดข้อผิดพลาดในสิทธิ์การเข้าใช้งาน",
- "Your full name has been changed." : "ชื่อเต็มของคุณถูกเปลี่ยนแปลง",
- "Unable to change full name" : "ไม่สามารถเปลี่ยนชื่อเต็ม",
"Couldn't remove app." : "ไม่สามารถลบแอพฯ",
"Language changed" : "เปลี่ยนภาษาเรียบร้อยแล้ว",
"Invalid request" : "คำร้องขอไม่ถูกต้อง",
+ "Authentication error" : "เกิดข้อผิดพลาดในสิทธิ์การเข้าใช้งาน",
"Admins can't remove themself from the admin group" : "ผู้ดูแลระบบไม่สามารถลบตัวเองออกจากกลุ่มผู้ดูแลได้",
"Unable to add user to group %s" : "ไม่สามารถเพิ่มผู้ใช้งานเข้าไปที่กลุ่ม %s ได้",
"Unable to remove user from group %s" : "ไม่สามารถลบผู้ใช้งานออกจากกลุ่ม %s ได้",
@@ -51,6 +49,8 @@
"Invalid user" : "ผู้ใช้ไม่ถูกต้อง",
"Unable to change mail address" : "ไม่สามารถที่จะเปลี่ยนที่อยู่อีเมล",
"Email saved" : "อีเมลถูกบันทึกแล้ว",
+ "Your full name has been changed." : "ชื่อเต็มของคุณถูกเปลี่ยนแปลง",
+ "Unable to change full name" : "ไม่สามารถเปลี่ยนชื่อเต็ม",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "คุณแน่ใจจริงๆ ว่าคุณต้องการเพิ่ม \"{domain}\" เป็นโดเมนที่เชื่อถือได้?",
"Add trusted domain" : "เพิ่มโดเมนที่เชื่อถือได้",
"Migration in progress. Please wait until the migration is finished" : "ในระหว่างดำเนินการโยกย้าย กรุณารอสักครู่จนกว่าการโยกย้ายจะเสร็จสิ้น",
@@ -79,6 +79,9 @@
"The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "แอพฯจะต้องเปิดใช้งานก่อนทำการอัพเดท คุณจะถูกนำไปยังหน้าอัพเดทใน 5 วินาที",
"App update" : "อัพเดทแอพฯ",
"No apps found for \"{query}\"" : "ไม่พบแอพฯสำหรับ \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "เกิดข้อผิดพลาด กรุณาอัพโหลดใบรับรองเข้ารหัส ASCII PEM",
+ "Valid until {date}" : "ใช้ได้จนถึงวันที่ {date}",
+ "Delete" : "ลบ",
"An error occurred: {message}" : "เกิดข้อผิดพลาด: {message}",
"Select a profile picture" : "เลือกรูปภาพโปรไฟล์",
"Very weak password" : "รหัสผ่านระดับต่ำมาก",
@@ -86,9 +89,6 @@
"So-so password" : "รหัสผ่านระดับปกติ",
"Good password" : "รหัสผ่านระดับดี",
"Strong password" : "รหัสผ่านระดับดีมาก",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "เกิดข้อผิดพลาด กรุณาอัพโหลดใบรับรองเข้ารหัส ASCII PEM",
- "Valid until {date}" : "ใช้ได้จนถึงวันที่ {date}",
- "Delete" : "ลบ",
"Groups" : "กลุ่ม",
"Unable to delete {objName}" : "ไม่สามารถลบ {objName}",
"Error creating group" : "ข้อผิดพลาดขณะกำลังสร้างกลุ่ม",
@@ -105,9 +105,8 @@
"A valid password must be provided" : "จะต้องระบุรหัสผ่านที่ถูกต้อง",
"A valid email must be provided" : "จะต้องระบุอีเมลที่ถูกต้อง",
"__language_name__" : "ภาษาไทย - Thai languages",
- "Sync clients" : "ประสานข้อมูลไคลเอนต์",
"Personal info" : "ข้อมูลส่วนบุคคล",
- "SSL root certificates" : "ใบรับรองความปลอดภัยด้วยระบบ SSL จาก Root",
+ "Sync clients" : "ประสานข้อมูลไคลเอนต์",
"Everything (fatal issues, errors, warnings, info, debug)" : "ทุกอย่าง (ปัญหาร้ายแรง ข้อผิดพลาด คำเตือน ข้อมูล การแก้ปัญหา)",
"Info, warnings, errors and fatal issues" : "ข้อมูล คำเตือน ข้อผิดพลาดและปัญหาร้ายแรง",
"Warnings, errors and fatal issues" : "คำเตือนข้อผิดพลาดและปัญหาที่ร้ายแรง",
@@ -133,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "เราขอแนะนำให้ติดตั้งแพคเกจที่จำเป็นต้องใช้ในระบบของคุณ ให้การสนับสนุนตำแหน่งที่ตั้งดังต่อไปนี้: %s",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "หากการติดตั้งของคุณไม่ได้ติดตั้งในรากของโดเมนและใช้ระบบ cron อาจมีปัญหาเกี่ยวกับการสร้าง URL เพื่อหลีกเลี่ยงปัญหาเหล่านี้โปรดไปตั้งค่า \"overwrite.cli.url\" ในไฟล์ config.php ของคุณไปยังเส้นทาง webroot ของการติดตั้งของคุณ (แนะนำ: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "มันเป็นไปไม่ได้ที่จะดำเนินการ cronjob ผ่านทาง CLI ข้อผิดพลาดทางเทคนิคต่อไปนี้จะปรากฏ:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "การทำธุรกรรมล็อคไฟล์จะใช้ฐานข้อมูลเป็นล็อคแบ็กเอนด์ สำหรับประสิทธิภาพที่ดีที่สุดก็ควรที่จะกำหนดค่า memcache สำหรับล็อค ดูเพิ่มเติมได้จาก <a target=\"_blank\" href=\"%s\">เอกสาร</a>",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "กรุณาตรวจสอบ <a target=\"_blank\" href=\"%s\">คู่มือการติดตั้ง</a> และตรวจสอบข้อผิดพลาดหรือคำเตือนใน <a href=\"#log-section\">บันทึก</a>",
"All checks passed." : "ผ่านการตรวจสอบทั้งหมด",
"Open documentation" : "เปิดเอกสาร",
@@ -186,11 +184,11 @@
"Store credentials" : "ข้อมูลประจำตัวของร้านค้า",
"Test email settings" : "การตั้งค่าอีเมลทดสอบ",
"Send email" : "ส่งอีเมล",
- "Log level" : "ระดับการเก็บบันทึก log",
"Download logfile" : "ดาวน์โหลดไฟล์บันทึก",
"More" : "มาก",
"Less" : "น้อย",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "ไฟล์บันทึกมีขนาดใหญ่กว่า 100 เมกะไบต์ มันอาจจะใช้เวลาดาวน์โหลดนาน!",
+ "What to log" : "อะไรที่จะบันทึก",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "จะใช้ SQLite เป็นฐานข้อมูล สำหรับการติดตั้งขนาดใหญ่เราขอแนะนำเพื่อสลับไปยังฐานข้อมูลแบ็กเอนด์ที่แตกต่างกัน",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "โดยเฉพาะอย่างยิ่งเมื่อใช้ไคลเอนต์เดสก์ทอปสำหรับการประสานข้อมูลโดย SQLite",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "การโยกย้ายไปยังฐานข้อมูลอื่นใช้เครื่องมือบรรทัดคำสั่ง: 'occ db:convert-type' หรือดูที่ <a target=\"_blank\" href=\"%s\">เอกสาร</a>",
@@ -204,17 +202,25 @@
"Developer documentation" : "เอกสารสำหรับนักพัฒนา",
"Experimental applications ahead" : "การใช้งานก่อนการทดลอง",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "การทดลองแอพพลิเคชันไม่ได้ถูกตรวจสอบปัญหาด้านความปลอดภัย การติดตั้งพวกเขาสามารถก่อให้เกิดการสูญเสียข้อมูลหรือการละเมิดความปลอดภัย",
- "by" : "โดย",
- "licensed" : "ได้รับใบอนุญาต",
+ "by %s" : "โดย %s",
+ "%s-licensed" : "%s ได้รับใบอนุญาต",
"Documentation:" : "เอกสาร:",
"User documentation" : "เอกสารสำหรับผู้ใช้",
"Admin documentation" : "เอกสารผู้ดูแลระบบ",
"Show description …" : "แสดงรายละเอียด ...",
"Hide description …" : "ซ่อนรายละเอียด ...",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "แอพฯนี้ได้ไม่บ่งบอกรุ่นต่ำสุดของ ownCloud นี้จะเป็นข้อผิดพลาดใน ownCloud ที่ 11 และรุ่นต่อมา",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "แอพฯนี้ได้ไม่บ่งบอกรุ่นสูงสุดของ ownCloud นี้จะเป็นข้อผิดพลาดใน ownCloud ที่ 11 และรุ่นต่อมา",
"This app cannot be installed because the following dependencies are not fulfilled:" : "ไม่สามารถติดตั้งแอพฯนี้เพราะไม่มีตัวอ้างอิงต่อไปนี้:",
"Enable only for specific groups" : "เปิดใช้งานเพียงเฉพาะกลุ่ม",
"Uninstall App" : "ถอนการติดตั้งแอพฯ",
"Enable experimental apps" : "เปิดใช้งานแอพพลิเคชั่นทดลอง",
+ "SSL Root Certificates" : "ใบรับรอง SSL",
+ "Common Name" : "ชื่อทั่วไป",
+ "Valid until" : "ใช้ได้จนถึง",
+ "Issued By" : "ปัญหาโดย",
+ "Valid until %s" : "ใช้ได้จนถึง %s",
+ "Import root certificate" : "นำเข้าใบรับรองหลัก",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "นี่คุณ<br><br>อยากจะแจ้งให้คุณทราบว่าขณะนี้คุณมีบัญชี %s<br><br>ชื่อผู้ใช้ของคุณคือ: %s<br>เข้าไปงานได้ที่: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "ไชโย!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "นี่คุณ\n\nอยากให้คุณทราบว่าขณะนี้คุณมี %s บัญชี\n\nชื่อผู้ใช้ของคุณ: %s\nดูได้ที่: %s\n",
@@ -223,40 +229,35 @@
"Forum" : "ฟอรั่ม",
"Issue tracker" : "ติดตามปัญหา",
"Commercial support" : "สนับสนุนเชิงพาณิชย์",
- "Get the apps to sync your files" : "ใช้แอพพลิเคชันในการประสานไฟล์ของคุณ",
- "Desktop client" : "เดสก์ทอปผู้ใช้",
- "Android app" : "แอพฯ แอนดรอยด์",
- "iOS app" : "แอพฯ IOS",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "หากคุณต้องการที่จะสนับสนุนโครงการ <a href=\"https://owncloud.org/contribute\" target=\"_blank\" rel=\"noreferrer\">เข้าร่วมการพัฒนา</a> หรือ <a href=\"https://owncloud.org/promote\" target=\"_blank\" rel=\"noreferrer\">กระจายข่าวสาร</a>!\n\t\t",
- "Show First Run Wizard again" : "แสดงหน้าจอวิซาร์ดนำทางครั้งแรกอีกครั้ง",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "คุณได้ใช้งานไปแล้ว <strong>%s</strong> จากจำนวนที่สามารถใช้ได้ <strong>%s</strong>",
- "Password" : "รหัสผ่าน",
- "Unable to change your password" : "ไม่สามารถเปลี่ยนรหัสผ่านของคุณได้",
- "Current password" : "รหัสผ่านปัจจุบัน",
- "New password" : "รหัสผ่านใหม่",
- "Change password" : "เปลี่ยนรหัสผ่าน",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "คุณกำลังใช้ <strong>%s</strong> ของ <strong>%s</strong>",
+ "Profile picture" : "รูปภาพโปรไฟล์",
+ "Upload new" : "อัพโหลดใหม่",
+ "Select from Files" : "เลือกจากไฟล์",
+ "Remove image" : "ลบรูปภาพ",
+ "png or jpg, max. 20 MB" : "png หรือ jpg, สูงสุด 20 เมกะไบต์",
+ "Picture provided by original account" : "ใช้รูปภาพจากบัญชีเดิม",
+ "Cancel" : "ยกเลิก",
+ "Choose as profile picture" : "เลือกรูปภาพโปรไฟล์",
"Full name" : "ชื่อเต็ม",
"No display name set" : "ไม่มีชื่อที่แสดง",
"Email" : "อีเมล",
"Your email address" : "ที่อยู่อีเมล์ของคุณ",
- "Fill in an email address to enable password recovery and receive notifications" : "กรอกที่อยู่อีเมลเพื่อเปิดใช้งานการกู้คืนรหัสผ่านและการได้รับการแจ้งเตือน",
+ "For password recovery and notifications" : "สำหรับการกู้คืนรหัสผ่านและการแจ้งเตือน",
"No email address set" : "ไม่ได้ตั้งค่าที่อยู่อีเมล",
"You are member of the following groups:" : "คุณเป็นสมาชิกของกลุ่มต่อไปนี้:",
- "Profile picture" : "รูปภาพโปรไฟล์",
- "Upload new" : "อัพโหลดใหม่",
- "Select new from Files" : "เลือกใหม่จากไฟล์",
- "Remove image" : "ลบรูปภาพ",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "การครอบตัดรูปภาพ .PNG หรือ .JPG ให้รูปเป็นสี่เหลี่ยม ไฟล์ต้องมีขนาดไม่เกิน 20 เมกะไบต์",
- "Your avatar is provided by your original account." : "อวตาลของคุณถูกระบุโดยบัญชีเดิมของคุณ",
- "Cancel" : "ยกเลิก",
- "Choose as profile image" : "เลือกรูปภาพโปรไฟล์",
+ "Password" : "รหัสผ่าน",
+ "Unable to change your password" : "ไม่สามารถเปลี่ยนรหัสผ่านของคุณได้",
+ "Current password" : "รหัสผ่านปัจจุบัน",
+ "New password" : "รหัสผ่านใหม่",
+ "Change password" : "เปลี่ยนรหัสผ่าน",
"Language" : "ภาษา",
"Help translate" : "มาช่วยกันแปลสิ!",
- "Common Name" : "ชื่อทั่วไป",
- "Valid until" : "ใช้ได้จนถึง",
- "Issued By" : "ปัญหาโดย",
- "Valid until %s" : "ใช้ได้จนถึง %s",
- "Import root certificate" : "นำเข้าใบรับรองหลัก",
+ "Get the apps to sync your files" : "ใช้แอพพลิเคชันในการประสานไฟล์ของคุณ",
+ "Desktop client" : "เดสก์ทอปผู้ใช้",
+ "Android app" : "แอพฯ แอนดรอยด์",
+ "iOS app" : "แอพฯ IOS",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "หากคุณต้องการที่จะสนับสนุนโครงการ <a href=\"https://owncloud.org/contribute\" target=\"_blank\" rel=\"noreferrer\">เข้าร่วมการพัฒนา</a> หรือ <a href=\"https://owncloud.org/promote\" target=\"_blank\" rel=\"noreferrer\">กระจายข่าวสาร</a>!\n\t\t",
+ "Show First Run Wizard again" : "แสดงหน้าจอวิซาร์ดนำทางครั้งแรกอีกครั้ง",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "ที่พัฒนาโดย {communityopen} ชุมชน ownCloud {linkclose} {githubopen}รหัสต้นฉบับ{linkclose} อยู่ภายใต้สัญญา {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}",
"Show storage location" : "แสดงสถานที่จัดเก็บข้อมูล",
"Show last log in" : "แสดงการเข้าสู่ระบบล่าสุด",
diff --git a/settings/l10n/tr.js b/settings/l10n/tr.js
index a3cec1f93fd..393a12a30a2 100644
--- a/settings/l10n/tr.js
+++ b/settings/l10n/tr.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "Günlük",
"Tips & tricks" : "İpuçları ve hileler",
"Updates" : "Güncellemeler",
- "Authentication error" : "Kimlik doğrulama hatası",
- "Your full name has been changed." : "Tam adınız değiştirildi.",
- "Unable to change full name" : "Tam adınız değiştirilirken hata",
"Couldn't remove app." : "Uygulama kaldırılamadı.",
"Language changed" : "Dil değiştirildi",
"Invalid request" : "Geçersiz istek",
+ "Authentication error" : "Kimlik doğrulama hatası",
"Admins can't remove themself from the admin group" : "Yöneticiler kendilerini admin grubundan kaldıramaz",
"Unable to add user to group %s" : "Kullanıcı %s grubuna eklenemiyor",
"Unable to remove user from group %s" : "%s grubundan kullanıcı kaldırılamıyor",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "Geçersiz kullanıcı",
"Unable to change mail address" : "Posta adresini değiştirme başarısız",
"Email saved" : "E-posta kaydedildi",
+ "Your full name has been changed." : "Tam adınız değiştirildi.",
+ "Unable to change full name" : "Tam adınız değiştirilirken hata",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "\"{domain}\" alan adını güvenilir alan adı olarak eklemek istediğinizden emin misiniz?",
"Add trusted domain" : "Güvenilir alan adı ekle",
"Migration in progress. Please wait until the migration is finished" : "Taşınma sürüyor. Lütfen taşınma tamamlanana kadar bekleyin",
@@ -78,6 +78,12 @@ OC.L10N.register(
"Uninstalling ...." : "Kaldırılıyor ....",
"Error while uninstalling app" : "Uygulama kaldırılırken hata",
"Uninstall" : "Kaldır",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Uygulama etkinleştirildi fakat güncellenmesi gerekiyor. 5 saniye içinde güncelleme sayfasına yönlendirileceksiniz.",
+ "App update" : "Uygulama güncellemesi",
+ "No apps found for \"{query}\"" : "\"{query}\" için uygulama bulunamadı",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Bir hata oluştu. Lütfen ASCII-kodlanmış PEM sertifikasını yükleyin.",
+ "Valid until {date}" : "{date} tarihine kadar geçerli",
+ "Delete" : "Sil",
"An error occurred: {message}" : "Bir hata oluştu: {message}",
"Select a profile picture" : "Bir profil fotoğrafı seçin",
"Very weak password" : "Çok güçsüz parola",
@@ -85,9 +91,6 @@ OC.L10N.register(
"So-so password" : "Normal parola",
"Good password" : "İyi parola",
"Strong password" : "Güçlü parola",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Bir hata oluştu. Lütfen ASCII-kodlanmış PEM sertifikasını yükleyin.",
- "Valid until {date}" : "{date} tarihine kadar geçerli",
- "Delete" : "Sil",
"Groups" : "Gruplar",
"Unable to delete {objName}" : "{objName} silinemiyor",
"Error creating group" : "Grup oluşturulurken hata",
@@ -104,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "Geçerli bir parola mutlaka sağlanmalı",
"A valid email must be provided" : "Geçerli bir e-posta belirtilmeli",
"__language_name__" : "Türkçe",
- "Sync clients" : "Eşitleme istemcileri",
"Personal info" : "Kişisel bilgi",
- "SSL root certificates" : "SSL kök sertifikaları",
+ "Sync clients" : "Eşitleme istemcileri",
"Everything (fatal issues, errors, warnings, info, debug)" : "Her şey (Ciddi sorunlar, hatalar, uyarılar, bilgi, hata ayıklama)",
"Info, warnings, errors and fatal issues" : "Bilgi, uyarılar, hatalar ve ciddi sorunlar",
"Warnings, errors and fatal issues" : "Uyarılar, hatalar ve ciddi sorunlar",
@@ -132,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Şu dillerden birini desteklemesi için sisteminize gerekli paketleri kurmanızı şiddetle tavsiye ederiz: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Eğer kurulumunuz alan adının köküne yapılmamışsa ve sistem cron'u kullanıyorsa, URL oluşturma ile ilgili sorunlar oluşabilir. Bu sorunların önüne geçmek için, kurulumunuzun web kök yolundaki config.php dosyasında \"overwrite.cli.url\" seçeneğini ayarlayın (Önerilen: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Bu CLI ile cronjobı çalıştırmak mümkün değildi. Aşağıdaki teknik hatalar ortaya çıkmıştır:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "İşlemsel dosya kilidi, kilitleme arkaucu olarak veritabanını kullanıyor. En iyi performans için kilitleme adına memcache yapılandırılması önerilir. Daha fazla bilgi için <a target=\"_blank\" href=\"%s\">belgelendirmeye ↗</a> bakın.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Lütfen <a target=\"_blank\" href=\"%s\">kurulum rehberlerini ↗</a> iki kez denetleyip <a href=\"#log-section\">günlük</a> içerisindeki hata ve uyarılara bakın.",
"All checks passed." : "Tüm kontroller geçildi.",
"Open documentation" : "Belgelendirmeyi aç",
@@ -159,6 +160,10 @@ OC.L10N.register(
"Use system's cron service to call the cron.php file every 15 minutes." : "Cron.php dosyasını her 15 dakikada bir çağırmak için sistem cron hizmetini kullan.",
"Enable server-side encryption" : "Sunucu taraflı şifrelemeyi aç",
"Please read carefully before activating server-side encryption: " : "Lütfen sunucu tarafında şifrelemeyi etkinleştirmeden önce dikkatlice okuyun: ",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "Şifreleme etkinleştirildiğinde, sunucuya yüklenen tüm dosyalar şifrelenmiş olarak kalacaktır. Şifrelemeyi devre dışı bırakmak sadece ileriki zamanlarda aktif şifreleme modülü desteklediğinde ve ön koşullar (örn: düzenleme anahtarı oluşturulması) yerine getirildiğinde yapılabilir.",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "Şifreleme tek başına sistem güvenliğini garanti etmez. Lütfen şifreleme uygulamasının çalışma bilgisi ve desteklenen kullanım durumları için ownCloud belgelerine bakın.",
+ "Be aware that encryption always increases the file size." : "Şifrelemenin dosya boyutunu büyüteceğini unutmayın.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "Verilerinizi düzenli yedekleyin ve şifreleme anahtarlarınızın verilerinizle birlikte yedeklendiğinden emin olun. ",
"This is the final warning: Do you really want to enable encryption?" : "Bu son uyarıdır: Şifrelemeyi etkinleştirmek istiyor musunuz?",
"Enable encryption" : "Şifrelemeyi aç",
"No encryption module loaded, please enable an encryption module in the app menu." : "Hiç şifrelenme modülü yüklenmemiş, lütfen uygulama menüsünden bir şifreleme modülü etkinleştirin.",
@@ -181,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "Kimlik bilgilerini depola",
"Test email settings" : "E-posta ayarlarını sına",
"Send email" : "E-posta gönder",
- "Log level" : "Günlük seviyesi",
"Download logfile" : "Günlük dosyasını indir",
"More" : "Daha fazla",
"Less" : "Daha az",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Günlük dosyası 100 MB'dan daha büyük. İndirmek zaman alabilir!",
+ "What to log" : "Neler günlüklenmeli",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Veritabanı olarak SQLite kullanılıyor. Daha büyük kurulumlar için farklı bir veritabanı arka ucuna geçmenizi öneriyoruz.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Özellikle dosya eşitleme için masaüstü istemcisi kullanılırken SQLite kullanımı önerilmez.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Başka bir veritabanına geçmek için komut satırı aracını kullanın: 'occ db:convert-type' veya <a target=\"_blank\" href=\"%s\">belgelendirmeye ↗</a> bakın.",
@@ -199,8 +204,6 @@ OC.L10N.register(
"Developer documentation" : "Geliştirici belgelendirmesi",
"Experimental applications ahead" : "İlerideki deneysel uygulamalar",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Deneysel uygulamalar güvenlik açısından denetlenmemiş, yeni veya kararsız olmaya açık ya da geliştirilme aşamasında olan uygulamalardır. Yüklemek veri kaybı veya güvenlik açıklarına sebep olabilir.",
- "by" : "Yazan:",
- "licensed" : "lisanslı",
"Documentation:" : "Belgelendirme:",
"User documentation" : "Kullanıcı belgelendirmesi",
"Admin documentation" : "Yönetici belgelendirmesi",
@@ -210,6 +213,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Sadece belirli gruplar için etkinleştir",
"Uninstall App" : "Uygulamayı Kaldır",
"Enable experimental apps" : "Deneysel uygulamaları etkinleştir",
+ "Common Name" : "Ortak Ad",
+ "Valid until" : "Geçerlilik",
+ "Issued By" : "Veren",
+ "Valid until %s" : "%s tarihine kadar geçerli",
+ "Import root certificate" : "Kök sertifikalarını içe aktar",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Merhaba,<br><br>Sadece artık bir %s hesabınızın olduğunu söylemek istedim.<br><br>Kullanıcı adınız: %s<br>Şuradan erişin: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Hoşçakalın!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Merhaba,\n\nSadece, artık bir %s hesabınızın olduğunu söylemek istedim.\n\nKullanıcı adınız: %s\nErişim: %s\n\n",
@@ -218,40 +226,29 @@ OC.L10N.register(
"Forum" : "Forum",
"Issue tracker" : "Sorun izleyici",
"Commercial support" : "Ticari destek",
- "Get the apps to sync your files" : "Dosyalarınızı eşitlemek için uygulamaları indirin",
- "Desktop client" : "Masaüstü istemcisi",
- "Android app" : "Android uygulaması",
- "iOS app" : "iOS uygulaması",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Projeyi desteklemek istiyorsanız\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">geliştirilmesine katılın</a>\n\t\tveya\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">duyurun</a>!",
- "Show First Run Wizard again" : "İlk Çalıştırma Sihirbazı'nı yeniden göster",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Kullandığınız: <strong>%s</strong>. Kullanılabilir alan: <strong>%s</strong>",
- "Password" : "Parola",
- "Unable to change your password" : "Parolanız değiştirilemiyor",
- "Current password" : "Mevcut parola",
- "New password" : "Yeni parola",
- "Change password" : "Parola değiştir",
+ "Profile picture" : "Profil resmi",
+ "Upload new" : "Yeni yükle",
+ "Remove image" : "Resmi kaldır",
+ "Cancel" : "İptal",
"Full name" : "Ad soyad",
"No display name set" : "Ekran adı ayarlanmamış",
"Email" : "E-posta",
"Your email address" : "E-posta adresiniz",
- "Fill in an email address to enable password recovery and receive notifications" : "Parola kurtarmayı ve bildirim almayı açmak için bir e-posta adresi girin",
"No email address set" : "E-posta adresi ayarlanmamış",
"You are member of the following groups:" : "Şu grupların üyesisiniz:",
- "Profile picture" : "Profil resmi",
- "Upload new" : "Yeni yükle",
- "Select new from Files" : "Dosyalardan seç",
- "Remove image" : "Resmi kaldır",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Png veya jpg'den biri olmalıdır. İdeal olanı karedir ama kırpmanıza izin verilecektir. Dosya boyutu 20MB'ı geçemez.",
- "Your avatar is provided by your original account." : "Görüntü resminiz, özgün hesabınız tarafından sağlanıyor.",
- "Cancel" : "İptal",
- "Choose as profile image" : "Profil resmi olarak seç",
+ "Password" : "Parola",
+ "Unable to change your password" : "Parolanız değiştirilemiyor",
+ "Current password" : "Mevcut parola",
+ "New password" : "Yeni parola",
+ "Change password" : "Parola değiştir",
"Language" : "Dil",
"Help translate" : "Çevirilere yardım edin",
- "Common Name" : "Ortak Ad",
- "Valid until" : "Geçerlilik",
- "Issued By" : "Veren",
- "Valid until %s" : "%s tarihine kadar geçerli",
- "Import root certificate" : "Kök sertifikalarını içe aktar",
+ "Get the apps to sync your files" : "Dosyalarınızı eşitlemek için uygulamaları indirin",
+ "Desktop client" : "Masaüstü istemcisi",
+ "Android app" : "Android uygulaması",
+ "iOS app" : "iOS uygulaması",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Projeyi desteklemek istiyorsanız\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">geliştirilmesine katılın</a>\n\t\tveya\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">duyurun</a>!",
+ "Show First Run Wizard again" : "İlk Çalıştırma Sihirbazı'nı yeniden göster",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "{communityopen}ownCloud topluluğu tarafından{linkclose} geliştirildi. {githubopen}Kaynak kodu{linkclose}, {licenseopen}<abbr title=\"Affero Genel Kamu Lisansı\">AGPL</abbr>{linkclose} ile lisanslanmıştır.",
"Show storage location" : "Depolama konumunu göster",
"Show last log in" : "Son oturum açılma zamanını göster",
diff --git a/settings/l10n/tr.json b/settings/l10n/tr.json
index 6a0e6f7bff4..7a6a135be19 100644
--- a/settings/l10n/tr.json
+++ b/settings/l10n/tr.json
@@ -10,12 +10,10 @@
"Log" : "Günlük",
"Tips & tricks" : "İpuçları ve hileler",
"Updates" : "Güncellemeler",
- "Authentication error" : "Kimlik doğrulama hatası",
- "Your full name has been changed." : "Tam adınız değiştirildi.",
- "Unable to change full name" : "Tam adınız değiştirilirken hata",
"Couldn't remove app." : "Uygulama kaldırılamadı.",
"Language changed" : "Dil değiştirildi",
"Invalid request" : "Geçersiz istek",
+ "Authentication error" : "Kimlik doğrulama hatası",
"Admins can't remove themself from the admin group" : "Yöneticiler kendilerini admin grubundan kaldıramaz",
"Unable to add user to group %s" : "Kullanıcı %s grubuna eklenemiyor",
"Unable to remove user from group %s" : "%s grubundan kullanıcı kaldırılamıyor",
@@ -51,6 +49,8 @@
"Invalid user" : "Geçersiz kullanıcı",
"Unable to change mail address" : "Posta adresini değiştirme başarısız",
"Email saved" : "E-posta kaydedildi",
+ "Your full name has been changed." : "Tam adınız değiştirildi.",
+ "Unable to change full name" : "Tam adınız değiştirilirken hata",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "\"{domain}\" alan adını güvenilir alan adı olarak eklemek istediğinizden emin misiniz?",
"Add trusted domain" : "Güvenilir alan adı ekle",
"Migration in progress. Please wait until the migration is finished" : "Taşınma sürüyor. Lütfen taşınma tamamlanana kadar bekleyin",
@@ -76,6 +76,12 @@
"Uninstalling ...." : "Kaldırılıyor ....",
"Error while uninstalling app" : "Uygulama kaldırılırken hata",
"Uninstall" : "Kaldır",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "Uygulama etkinleştirildi fakat güncellenmesi gerekiyor. 5 saniye içinde güncelleme sayfasına yönlendirileceksiniz.",
+ "App update" : "Uygulama güncellemesi",
+ "No apps found for \"{query}\"" : "\"{query}\" için uygulama bulunamadı",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Bir hata oluştu. Lütfen ASCII-kodlanmış PEM sertifikasını yükleyin.",
+ "Valid until {date}" : "{date} tarihine kadar geçerli",
+ "Delete" : "Sil",
"An error occurred: {message}" : "Bir hata oluştu: {message}",
"Select a profile picture" : "Bir profil fotoğrafı seçin",
"Very weak password" : "Çok güçsüz parola",
@@ -83,9 +89,6 @@
"So-so password" : "Normal parola",
"Good password" : "İyi parola",
"Strong password" : "Güçlü parola",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Bir hata oluştu. Lütfen ASCII-kodlanmış PEM sertifikasını yükleyin.",
- "Valid until {date}" : "{date} tarihine kadar geçerli",
- "Delete" : "Sil",
"Groups" : "Gruplar",
"Unable to delete {objName}" : "{objName} silinemiyor",
"Error creating group" : "Grup oluşturulurken hata",
@@ -102,9 +105,8 @@
"A valid password must be provided" : "Geçerli bir parola mutlaka sağlanmalı",
"A valid email must be provided" : "Geçerli bir e-posta belirtilmeli",
"__language_name__" : "Türkçe",
- "Sync clients" : "Eşitleme istemcileri",
"Personal info" : "Kişisel bilgi",
- "SSL root certificates" : "SSL kök sertifikaları",
+ "Sync clients" : "Eşitleme istemcileri",
"Everything (fatal issues, errors, warnings, info, debug)" : "Her şey (Ciddi sorunlar, hatalar, uyarılar, bilgi, hata ayıklama)",
"Info, warnings, errors and fatal issues" : "Bilgi, uyarılar, hatalar ve ciddi sorunlar",
"Warnings, errors and fatal issues" : "Uyarılar, hatalar ve ciddi sorunlar",
@@ -130,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Şu dillerden birini desteklemesi için sisteminize gerekli paketleri kurmanızı şiddetle tavsiye ederiz: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Eğer kurulumunuz alan adının köküne yapılmamışsa ve sistem cron'u kullanıyorsa, URL oluşturma ile ilgili sorunlar oluşabilir. Bu sorunların önüne geçmek için, kurulumunuzun web kök yolundaki config.php dosyasında \"overwrite.cli.url\" seçeneğini ayarlayın (Önerilen: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Bu CLI ile cronjobı çalıştırmak mümkün değildi. Aşağıdaki teknik hatalar ortaya çıkmıştır:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "İşlemsel dosya kilidi, kilitleme arkaucu olarak veritabanını kullanıyor. En iyi performans için kilitleme adına memcache yapılandırılması önerilir. Daha fazla bilgi için <a target=\"_blank\" href=\"%s\">belgelendirmeye ↗</a> bakın.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Lütfen <a target=\"_blank\" href=\"%s\">kurulum rehberlerini ↗</a> iki kez denetleyip <a href=\"#log-section\">günlük</a> içerisindeki hata ve uyarılara bakın.",
"All checks passed." : "Tüm kontroller geçildi.",
"Open documentation" : "Belgelendirmeyi aç",
@@ -157,6 +158,10 @@
"Use system's cron service to call the cron.php file every 15 minutes." : "Cron.php dosyasını her 15 dakikada bir çağırmak için sistem cron hizmetini kullan.",
"Enable server-side encryption" : "Sunucu taraflı şifrelemeyi aç",
"Please read carefully before activating server-side encryption: " : "Lütfen sunucu tarafında şifrelemeyi etkinleştirmeden önce dikkatlice okuyun: ",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "Şifreleme etkinleştirildiğinde, sunucuya yüklenen tüm dosyalar şifrelenmiş olarak kalacaktır. Şifrelemeyi devre dışı bırakmak sadece ileriki zamanlarda aktif şifreleme modülü desteklediğinde ve ön koşullar (örn: düzenleme anahtarı oluşturulması) yerine getirildiğinde yapılabilir.",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "Şifreleme tek başına sistem güvenliğini garanti etmez. Lütfen şifreleme uygulamasının çalışma bilgisi ve desteklenen kullanım durumları için ownCloud belgelerine bakın.",
+ "Be aware that encryption always increases the file size." : "Şifrelemenin dosya boyutunu büyüteceğini unutmayın.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "Verilerinizi düzenli yedekleyin ve şifreleme anahtarlarınızın verilerinizle birlikte yedeklendiğinden emin olun. ",
"This is the final warning: Do you really want to enable encryption?" : "Bu son uyarıdır: Şifrelemeyi etkinleştirmek istiyor musunuz?",
"Enable encryption" : "Şifrelemeyi aç",
"No encryption module loaded, please enable an encryption module in the app menu." : "Hiç şifrelenme modülü yüklenmemiş, lütfen uygulama menüsünden bir şifreleme modülü etkinleştirin.",
@@ -179,11 +184,11 @@
"Store credentials" : "Kimlik bilgilerini depola",
"Test email settings" : "E-posta ayarlarını sına",
"Send email" : "E-posta gönder",
- "Log level" : "Günlük seviyesi",
"Download logfile" : "Günlük dosyasını indir",
"More" : "Daha fazla",
"Less" : "Daha az",
"The logfile is bigger than 100 MB. Downloading it may take some time!" : "Günlük dosyası 100 MB'dan daha büyük. İndirmek zaman alabilir!",
+ "What to log" : "Neler günlüklenmeli",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "Veritabanı olarak SQLite kullanılıyor. Daha büyük kurulumlar için farklı bir veritabanı arka ucuna geçmenizi öneriyoruz.",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Özellikle dosya eşitleme için masaüstü istemcisi kullanılırken SQLite kullanımı önerilmez.",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Başka bir veritabanına geçmek için komut satırı aracını kullanın: 'occ db:convert-type' veya <a target=\"_blank\" href=\"%s\">belgelendirmeye ↗</a> bakın.",
@@ -197,8 +202,6 @@
"Developer documentation" : "Geliştirici belgelendirmesi",
"Experimental applications ahead" : "İlerideki deneysel uygulamalar",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Deneysel uygulamalar güvenlik açısından denetlenmemiş, yeni veya kararsız olmaya açık ya da geliştirilme aşamasında olan uygulamalardır. Yüklemek veri kaybı veya güvenlik açıklarına sebep olabilir.",
- "by" : "Yazan:",
- "licensed" : "lisanslı",
"Documentation:" : "Belgelendirme:",
"User documentation" : "Kullanıcı belgelendirmesi",
"Admin documentation" : "Yönetici belgelendirmesi",
@@ -208,6 +211,11 @@
"Enable only for specific groups" : "Sadece belirli gruplar için etkinleştir",
"Uninstall App" : "Uygulamayı Kaldır",
"Enable experimental apps" : "Deneysel uygulamaları etkinleştir",
+ "Common Name" : "Ortak Ad",
+ "Valid until" : "Geçerlilik",
+ "Issued By" : "Veren",
+ "Valid until %s" : "%s tarihine kadar geçerli",
+ "Import root certificate" : "Kök sertifikalarını içe aktar",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Merhaba,<br><br>Sadece artık bir %s hesabınızın olduğunu söylemek istedim.<br><br>Kullanıcı adınız: %s<br>Şuradan erişin: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Hoşçakalın!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Merhaba,\n\nSadece, artık bir %s hesabınızın olduğunu söylemek istedim.\n\nKullanıcı adınız: %s\nErişim: %s\n\n",
@@ -216,40 +224,29 @@
"Forum" : "Forum",
"Issue tracker" : "Sorun izleyici",
"Commercial support" : "Ticari destek",
- "Get the apps to sync your files" : "Dosyalarınızı eşitlemek için uygulamaları indirin",
- "Desktop client" : "Masaüstü istemcisi",
- "Android app" : "Android uygulaması",
- "iOS app" : "iOS uygulaması",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Projeyi desteklemek istiyorsanız\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">geliştirilmesine katılın</a>\n\t\tveya\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">duyurun</a>!",
- "Show First Run Wizard again" : "İlk Çalıştırma Sihirbazı'nı yeniden göster",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Kullandığınız: <strong>%s</strong>. Kullanılabilir alan: <strong>%s</strong>",
- "Password" : "Parola",
- "Unable to change your password" : "Parolanız değiştirilemiyor",
- "Current password" : "Mevcut parola",
- "New password" : "Yeni parola",
- "Change password" : "Parola değiştir",
+ "Profile picture" : "Profil resmi",
+ "Upload new" : "Yeni yükle",
+ "Remove image" : "Resmi kaldır",
+ "Cancel" : "İptal",
"Full name" : "Ad soyad",
"No display name set" : "Ekran adı ayarlanmamış",
"Email" : "E-posta",
"Your email address" : "E-posta adresiniz",
- "Fill in an email address to enable password recovery and receive notifications" : "Parola kurtarmayı ve bildirim almayı açmak için bir e-posta adresi girin",
"No email address set" : "E-posta adresi ayarlanmamış",
"You are member of the following groups:" : "Şu grupların üyesisiniz:",
- "Profile picture" : "Profil resmi",
- "Upload new" : "Yeni yükle",
- "Select new from Files" : "Dosyalardan seç",
- "Remove image" : "Resmi kaldır",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Png veya jpg'den biri olmalıdır. İdeal olanı karedir ama kırpmanıza izin verilecektir. Dosya boyutu 20MB'ı geçemez.",
- "Your avatar is provided by your original account." : "Görüntü resminiz, özgün hesabınız tarafından sağlanıyor.",
- "Cancel" : "İptal",
- "Choose as profile image" : "Profil resmi olarak seç",
+ "Password" : "Parola",
+ "Unable to change your password" : "Parolanız değiştirilemiyor",
+ "Current password" : "Mevcut parola",
+ "New password" : "Yeni parola",
+ "Change password" : "Parola değiştir",
"Language" : "Dil",
"Help translate" : "Çevirilere yardım edin",
- "Common Name" : "Ortak Ad",
- "Valid until" : "Geçerlilik",
- "Issued By" : "Veren",
- "Valid until %s" : "%s tarihine kadar geçerli",
- "Import root certificate" : "Kök sertifikalarını içe aktar",
+ "Get the apps to sync your files" : "Dosyalarınızı eşitlemek için uygulamaları indirin",
+ "Desktop client" : "Masaüstü istemcisi",
+ "Android app" : "Android uygulaması",
+ "iOS app" : "iOS uygulaması",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Projeyi desteklemek istiyorsanız\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">geliştirilmesine katılın</a>\n\t\tveya\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">duyurun</a>!",
+ "Show First Run Wizard again" : "İlk Çalıştırma Sihirbazı'nı yeniden göster",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "{communityopen}ownCloud topluluğu tarafından{linkclose} geliştirildi. {githubopen}Kaynak kodu{linkclose}, {licenseopen}<abbr title=\"Affero Genel Kamu Lisansı\">AGPL</abbr>{linkclose} ile lisanslanmıştır.",
"Show storage location" : "Depolama konumunu göster",
"Show last log in" : "Son oturum açılma zamanını göster",
diff --git a/settings/l10n/ug.js b/settings/l10n/ug.js
index 56fc4fb1a89..eb867cece50 100644
--- a/settings/l10n/ug.js
+++ b/settings/l10n/ug.js
@@ -3,9 +3,9 @@ OC.L10N.register(
{
"Sharing" : "ھەمبەھىر",
"Log" : "خاتىرە",
- "Authentication error" : "سالاھىيەت دەلىللەش خاتالىقى",
"Language changed" : "تىل ئۆزگەردى",
"Invalid request" : "ئىناۋەتسىز ئىلتىماس",
+ "Authentication error" : "سالاھىيەت دەلىللەش خاتالىقى",
"Admins can't remove themself from the admin group" : "باشقۇرغۇچى ئۆزىنى باشقۇرۇش گۇرۇپپىسىدىن چىقىرىۋېتەلمەيدۇ",
"Unable to add user to group %s" : "ئىشلەتكۈچىنى %s گۇرۇپپىغا قوشالمايدۇ",
"Unable to remove user from group %s" : "ئىشلەتكۈچىنى %s گۇرۇپپىدىن چىقىرىۋېتەلمەيدۇ",
@@ -32,20 +32,18 @@ OC.L10N.register(
"Encryption" : "شىفىرلاش",
"Server address" : "مۇلازىمېتىر ئادرىسى",
"Port" : "ئېغىز",
- "Log level" : "خاتىرە دەرىجىسى",
"More" : "تېخىمۇ كۆپ",
"Less" : "ئاز",
"Version" : "نەشرى",
- "by" : "سەنئەتكار",
"Forum" : "مۇنبەر",
+ "Cancel" : "ۋاز كەچ",
+ "Email" : "تورخەت",
+ "Your email address" : "تورخەت ئادرېسىڭىز",
"Password" : "ئىم",
"Unable to change your password" : "ئىمنى ئۆزگەرتكىلى بولمايدۇ.",
"Current password" : "نۆۋەتتىكى ئىم",
"New password" : "يېڭى ئىم",
"Change password" : "ئىم ئۆزگەرت",
- "Email" : "تورخەت",
- "Your email address" : "تورخەت ئادرېسىڭىز",
- "Cancel" : "ۋاز كەچ",
"Language" : "تىل",
"Help translate" : "تەرجىمىگە ياردەم",
"Username" : "ئىشلەتكۈچى ئاتى",
diff --git a/settings/l10n/ug.json b/settings/l10n/ug.json
index 149ae1c08c1..046a7517910 100644
--- a/settings/l10n/ug.json
+++ b/settings/l10n/ug.json
@@ -1,9 +1,9 @@
{ "translations": {
"Sharing" : "ھەمبەھىر",
"Log" : "خاتىرە",
- "Authentication error" : "سالاھىيەت دەلىللەش خاتالىقى",
"Language changed" : "تىل ئۆزگەردى",
"Invalid request" : "ئىناۋەتسىز ئىلتىماس",
+ "Authentication error" : "سالاھىيەت دەلىللەش خاتالىقى",
"Admins can't remove themself from the admin group" : "باشقۇرغۇچى ئۆزىنى باشقۇرۇش گۇرۇپپىسىدىن چىقىرىۋېتەلمەيدۇ",
"Unable to add user to group %s" : "ئىشلەتكۈچىنى %s گۇرۇپپىغا قوشالمايدۇ",
"Unable to remove user from group %s" : "ئىشلەتكۈچىنى %s گۇرۇپپىدىن چىقىرىۋېتەلمەيدۇ",
@@ -30,20 +30,18 @@
"Encryption" : "شىفىرلاش",
"Server address" : "مۇلازىمېتىر ئادرىسى",
"Port" : "ئېغىز",
- "Log level" : "خاتىرە دەرىجىسى",
"More" : "تېخىمۇ كۆپ",
"Less" : "ئاز",
"Version" : "نەشرى",
- "by" : "سەنئەتكار",
"Forum" : "مۇنبەر",
+ "Cancel" : "ۋاز كەچ",
+ "Email" : "تورخەت",
+ "Your email address" : "تورخەت ئادرېسىڭىز",
"Password" : "ئىم",
"Unable to change your password" : "ئىمنى ئۆزگەرتكىلى بولمايدۇ.",
"Current password" : "نۆۋەتتىكى ئىم",
"New password" : "يېڭى ئىم",
"Change password" : "ئىم ئۆزگەرت",
- "Email" : "تورخەت",
- "Your email address" : "تورخەت ئادرېسىڭىز",
- "Cancel" : "ۋاز كەچ",
"Language" : "تىل",
"Help translate" : "تەرجىمىگە ياردەم",
"Username" : "ئىشلەتكۈچى ئاتى",
diff --git a/settings/l10n/uk.js b/settings/l10n/uk.js
index 0c98817594c..97b8f50c050 100644
--- a/settings/l10n/uk.js
+++ b/settings/l10n/uk.js
@@ -11,12 +11,10 @@ OC.L10N.register(
"Log" : "Журнал",
"Tips & tricks" : "Поради і трюки",
"Updates" : "Оновлення",
- "Authentication error" : "Помилка автентифікації",
- "Your full name has been changed." : "Ваше повне ім'я було змінено",
- "Unable to change full name" : "Неможливо змінити повне ім'я",
"Couldn't remove app." : "Неможливо видалити додаток.",
"Language changed" : "Мову змінено",
"Invalid request" : "Некоректний запит",
+ "Authentication error" : "Помилка автентифікації",
"Admins can't remove themself from the admin group" : "Адміністратор не може видалити себе з групи адміністраторів",
"Unable to add user to group %s" : "Не вдалося додати користувача у групу %s",
"Unable to remove user from group %s" : "Не вдалося видалити користувача із групи %s",
@@ -52,6 +50,8 @@ OC.L10N.register(
"Invalid user" : "Неправильний користувач",
"Unable to change mail address" : "Неможливо поміняти email адресу",
"Email saved" : "Адресу збережено",
+ "Your full name has been changed." : "Ваше повне ім'я було змінено",
+ "Unable to change full name" : "Неможливо змінити повне ім'я",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ви дійсно бажаєте додати \"{domain}\" як довірений домен?",
"Add trusted domain" : "Додати довірений домен",
"Migration in progress. Please wait until the migration is finished" : "Міграція триває. Будь ласка, зачекайте доки процес міграції завершиться",
@@ -77,6 +77,9 @@ OC.L10N.register(
"Uninstalling ...." : "Видалення...",
"Error while uninstalling app" : "Помилка видалення додатка",
"Uninstall" : "Видалити",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Виникла помилка. Будь ласка вивантажте PEM сертифікат в ASCII-кодуванні.",
+ "Valid until {date}" : "Дійсно до {date}",
+ "Delete" : "Видалити",
"An error occurred: {message}" : "Сталася помилка: {message}",
"Select a profile picture" : "Обрати зображення облікового запису",
"Very weak password" : "Дуже слабкий пароль",
@@ -84,9 +87,6 @@ OC.L10N.register(
"So-so password" : "Такий собі пароль",
"Good password" : "Добрий пароль",
"Strong password" : "Надійний пароль",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Виникла помилка. Будь ласка вивантажте PEM сертифікат в ASCII-кодуванні.",
- "Valid until {date}" : "Дійсно до {date}",
- "Delete" : "Видалити",
"Groups" : "Групи",
"Unable to delete {objName}" : "Не вдалося видалити {objName}",
"Error creating group" : "Помилка створення групи",
@@ -103,9 +103,8 @@ OC.L10N.register(
"A valid password must be provided" : "Потрібно задати вірний пароль",
"A valid email must be provided" : "Вкажіть дійсний email",
"__language_name__" : "__language_name__",
- "Sync clients" : "Клієнти синхронізації",
"Personal info" : "Особиста інформація",
- "SSL root certificates" : "Кореневі SSL сертифікати",
+ "Sync clients" : "Клієнти синхронізації",
"Everything (fatal issues, errors, warnings, info, debug)" : "Усі (критичні проблеми, помилки, попередження, інформаційні, налагодження)",
"Info, warnings, errors and fatal issues" : "Інформаційні, попередження, помилки та критичні проблеми",
"Warnings, errors and fatal issues" : "Попередження, помилки та критичні проблеми",
@@ -169,7 +168,6 @@ OC.L10N.register(
"Store credentials" : "Зберігати облікові дані",
"Test email settings" : "Тестувати налаштування електронної пошти",
"Send email" : "Надіслати листа",
- "Log level" : "Рівень протоколювання",
"Download logfile" : "Завантажити файл журналу",
"More" : "Більше",
"Less" : "Менше",
@@ -186,8 +184,6 @@ OC.L10N.register(
"Developer documentation" : "Документація для розробників",
"Experimental applications ahead" : "Спершу експериментальні додатки",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Експериментальні додатки не перевірені на наявність проблем безпеки, нові або нестабільні і в процесі активної розробки. Встановлення їх може спричинити втрату даних або дірки в безпеці.",
- "by" : "по",
- "licensed" : "Ліцензовано",
"Documentation:" : "Документація:",
"User documentation" : "Користувацька документація",
"Admin documentation" : "Документація адміністратора",
@@ -197,6 +193,11 @@ OC.L10N.register(
"Enable only for specific groups" : "Включити тільки для конкретних груп",
"Uninstall App" : "Видалити додаток",
"Enable experimental apps" : "Увімкнути експериментальні застосунки",
+ "Common Name" : "Ім'я:",
+ "Valid until" : "Дійсно до",
+ "Issued By" : "Виданий",
+ "Valid until %s" : "Дійсно до %s",
+ "Import root certificate" : "Імпортувати кореневий сертифікат",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Агов,<br><br>просто щоб ви знали, у вас є аккаунт %s.<br><br>Ваше ім'я користувача: %s<br>Перейдіть сюди: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Будьмо!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Агов,\n\nпросто щоб ви знали, у вас є аккаунт %s.\n\nВаше ім'я користувача: %s\nПерейдіть сюди: %s\n\n",
@@ -205,39 +206,29 @@ OC.L10N.register(
"Forum" : "Форум",
"Issue tracker" : "Вирішення проблем",
"Commercial support" : "Комерційна підтримка",
- "Get the apps to sync your files" : "Отримати додатки для синхронізації ваших файлів",
- "Desktop client" : "Клієнт для ПК",
- "Android app" : "Android-додаток",
- "iOS app" : "iOS додаток",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Якщо Ви хочете підтримати проект\n⇥⇥ <a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> спільна розробка </a> \n⇥⇥або\n⇥ ⇥ <a href=\"https://owncloud.org/promote\"\n ⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> повідомити у світі </a> !",
- "Show First Run Wizard again" : "Показувати Майстер Налаштувань знову",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ви використали <strong>%s</strong> із доступних <strong>%s</strong>",
- "Password" : "Пароль",
- "Unable to change your password" : "Не вдалося змінити Ваш пароль",
- "Current password" : "Поточний пароль",
- "New password" : "Новий пароль",
- "Change password" : "Змінити пароль",
+ "Profile picture" : "Зображення облікового запису",
+ "Upload new" : "Завантажити нове",
+ "Remove image" : "Видалити зображення",
+ "Cancel" : "Відмінити",
"Full name" : "Повне ім'я",
"No display name set" : "Коротке ім'я не вказано",
"Email" : "E-mail",
"Your email address" : "Ваша адреса електронної пошти",
- "Fill in an email address to enable password recovery and receive notifications" : "Введіть адресу електронної пошти, щоб ввімкнути відновлення паролю та отримання повідомлень",
"No email address set" : "E-mail не вказано",
"You are member of the following groups:" : "Ви є членом наступних груп:",
- "Profile picture" : "Зображення облікового запису",
- "Upload new" : "Завантажити нове",
- "Select new from Files" : "Обрати із завантажених файлів",
- "Remove image" : "Видалити зображення",
- "Your avatar is provided by your original account." : "Буде використано аватар вашого оригінального облікового запису.",
- "Cancel" : "Відмінити",
- "Choose as profile image" : "Обрати зображенням облікового запису",
+ "Password" : "Пароль",
+ "Unable to change your password" : "Не вдалося змінити Ваш пароль",
+ "Current password" : "Поточний пароль",
+ "New password" : "Новий пароль",
+ "Change password" : "Змінити пароль",
"Language" : "Мова",
"Help translate" : "Допомогти з перекладом",
- "Common Name" : "Ім'я:",
- "Valid until" : "Дійсно до",
- "Issued By" : "Виданий",
- "Valid until %s" : "Дійсно до %s",
- "Import root certificate" : "Імпортувати кореневий сертифікат",
+ "Get the apps to sync your files" : "Отримати додатки для синхронізації ваших файлів",
+ "Desktop client" : "Клієнт для ПК",
+ "Android app" : "Android-додаток",
+ "iOS app" : "iOS додаток",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Якщо Ви хочете підтримати проект\n⇥⇥ <a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> спільна розробка </a> \n⇥⇥або\n⇥ ⇥ <a href=\"https://owncloud.org/promote\"\n ⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> повідомити у світі </a> !",
+ "Show First Run Wizard again" : "Показувати Майстер Налаштувань знову",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Розроблено {communityopen} спільнотою ownCloud {linkclose}, {githubopen} вихідний код {linkclose} ліцензується відповідно до {licenseopen} <abbr title = \"Публічної ліцензії Affero General\"> AGPL </ abbr> {linkclose}.",
"Show storage location" : "Показати місцезнаходження сховища",
"Show last log in" : "Показати останній вхід в систему",
diff --git a/settings/l10n/uk.json b/settings/l10n/uk.json
index c9378c70b16..b6f75842e19 100644
--- a/settings/l10n/uk.json
+++ b/settings/l10n/uk.json
@@ -9,12 +9,10 @@
"Log" : "Журнал",
"Tips & tricks" : "Поради і трюки",
"Updates" : "Оновлення",
- "Authentication error" : "Помилка автентифікації",
- "Your full name has been changed." : "Ваше повне ім'я було змінено",
- "Unable to change full name" : "Неможливо змінити повне ім'я",
"Couldn't remove app." : "Неможливо видалити додаток.",
"Language changed" : "Мову змінено",
"Invalid request" : "Некоректний запит",
+ "Authentication error" : "Помилка автентифікації",
"Admins can't remove themself from the admin group" : "Адміністратор не може видалити себе з групи адміністраторів",
"Unable to add user to group %s" : "Не вдалося додати користувача у групу %s",
"Unable to remove user from group %s" : "Не вдалося видалити користувача із групи %s",
@@ -50,6 +48,8 @@
"Invalid user" : "Неправильний користувач",
"Unable to change mail address" : "Неможливо поміняти email адресу",
"Email saved" : "Адресу збережено",
+ "Your full name has been changed." : "Ваше повне ім'я було змінено",
+ "Unable to change full name" : "Неможливо змінити повне ім'я",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "Ви дійсно бажаєте додати \"{domain}\" як довірений домен?",
"Add trusted domain" : "Додати довірений домен",
"Migration in progress. Please wait until the migration is finished" : "Міграція триває. Будь ласка, зачекайте доки процес міграції завершиться",
@@ -75,6 +75,9 @@
"Uninstalling ...." : "Видалення...",
"Error while uninstalling app" : "Помилка видалення додатка",
"Uninstall" : "Видалити",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Виникла помилка. Будь ласка вивантажте PEM сертифікат в ASCII-кодуванні.",
+ "Valid until {date}" : "Дійсно до {date}",
+ "Delete" : "Видалити",
"An error occurred: {message}" : "Сталася помилка: {message}",
"Select a profile picture" : "Обрати зображення облікового запису",
"Very weak password" : "Дуже слабкий пароль",
@@ -82,9 +85,6 @@
"So-so password" : "Такий собі пароль",
"Good password" : "Добрий пароль",
"Strong password" : "Надійний пароль",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "Виникла помилка. Будь ласка вивантажте PEM сертифікат в ASCII-кодуванні.",
- "Valid until {date}" : "Дійсно до {date}",
- "Delete" : "Видалити",
"Groups" : "Групи",
"Unable to delete {objName}" : "Не вдалося видалити {objName}",
"Error creating group" : "Помилка створення групи",
@@ -101,9 +101,8 @@
"A valid password must be provided" : "Потрібно задати вірний пароль",
"A valid email must be provided" : "Вкажіть дійсний email",
"__language_name__" : "__language_name__",
- "Sync clients" : "Клієнти синхронізації",
"Personal info" : "Особиста інформація",
- "SSL root certificates" : "Кореневі SSL сертифікати",
+ "Sync clients" : "Клієнти синхронізації",
"Everything (fatal issues, errors, warnings, info, debug)" : "Усі (критичні проблеми, помилки, попередження, інформаційні, налагодження)",
"Info, warnings, errors and fatal issues" : "Інформаційні, попередження, помилки та критичні проблеми",
"Warnings, errors and fatal issues" : "Попередження, помилки та критичні проблеми",
@@ -167,7 +166,6 @@
"Store credentials" : "Зберігати облікові дані",
"Test email settings" : "Тестувати налаштування електронної пошти",
"Send email" : "Надіслати листа",
- "Log level" : "Рівень протоколювання",
"Download logfile" : "Завантажити файл журналу",
"More" : "Більше",
"Less" : "Менше",
@@ -184,8 +182,6 @@
"Developer documentation" : "Документація для розробників",
"Experimental applications ahead" : "Спершу експериментальні додатки",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Експериментальні додатки не перевірені на наявність проблем безпеки, нові або нестабільні і в процесі активної розробки. Встановлення їх може спричинити втрату даних або дірки в безпеці.",
- "by" : "по",
- "licensed" : "Ліцензовано",
"Documentation:" : "Документація:",
"User documentation" : "Користувацька документація",
"Admin documentation" : "Документація адміністратора",
@@ -195,6 +191,11 @@
"Enable only for specific groups" : "Включити тільки для конкретних груп",
"Uninstall App" : "Видалити додаток",
"Enable experimental apps" : "Увімкнути експериментальні застосунки",
+ "Common Name" : "Ім'я:",
+ "Valid until" : "Дійсно до",
+ "Issued By" : "Виданий",
+ "Valid until %s" : "Дійсно до %s",
+ "Import root certificate" : "Імпортувати кореневий сертифікат",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "Агов,<br><br>просто щоб ви знали, у вас є аккаунт %s.<br><br>Ваше ім'я користувача: %s<br>Перейдіть сюди: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "Будьмо!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "Агов,\n\nпросто щоб ви знали, у вас є аккаунт %s.\n\nВаше ім'я користувача: %s\nПерейдіть сюди: %s\n\n",
@@ -203,39 +204,29 @@
"Forum" : "Форум",
"Issue tracker" : "Вирішення проблем",
"Commercial support" : "Комерційна підтримка",
- "Get the apps to sync your files" : "Отримати додатки для синхронізації ваших файлів",
- "Desktop client" : "Клієнт для ПК",
- "Android app" : "Android-додаток",
- "iOS app" : "iOS додаток",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Якщо Ви хочете підтримати проект\n⇥⇥ <a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> спільна розробка </a> \n⇥⇥або\n⇥ ⇥ <a href=\"https://owncloud.org/promote\"\n ⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> повідомити у світі </a> !",
- "Show First Run Wizard again" : "Показувати Майстер Налаштувань знову",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Ви використали <strong>%s</strong> із доступних <strong>%s</strong>",
- "Password" : "Пароль",
- "Unable to change your password" : "Не вдалося змінити Ваш пароль",
- "Current password" : "Поточний пароль",
- "New password" : "Новий пароль",
- "Change password" : "Змінити пароль",
+ "Profile picture" : "Зображення облікового запису",
+ "Upload new" : "Завантажити нове",
+ "Remove image" : "Видалити зображення",
+ "Cancel" : "Відмінити",
"Full name" : "Повне ім'я",
"No display name set" : "Коротке ім'я не вказано",
"Email" : "E-mail",
"Your email address" : "Ваша адреса електронної пошти",
- "Fill in an email address to enable password recovery and receive notifications" : "Введіть адресу електронної пошти, щоб ввімкнути відновлення паролю та отримання повідомлень",
"No email address set" : "E-mail не вказано",
"You are member of the following groups:" : "Ви є членом наступних груп:",
- "Profile picture" : "Зображення облікового запису",
- "Upload new" : "Завантажити нове",
- "Select new from Files" : "Обрати із завантажених файлів",
- "Remove image" : "Видалити зображення",
- "Your avatar is provided by your original account." : "Буде використано аватар вашого оригінального облікового запису.",
- "Cancel" : "Відмінити",
- "Choose as profile image" : "Обрати зображенням облікового запису",
+ "Password" : "Пароль",
+ "Unable to change your password" : "Не вдалося змінити Ваш пароль",
+ "Current password" : "Поточний пароль",
+ "New password" : "Новий пароль",
+ "Change password" : "Змінити пароль",
"Language" : "Мова",
"Help translate" : "Допомогти з перекладом",
- "Common Name" : "Ім'я:",
- "Valid until" : "Дійсно до",
- "Issued By" : "Виданий",
- "Valid until %s" : "Дійсно до %s",
- "Import root certificate" : "Імпортувати кореневий сертифікат",
+ "Get the apps to sync your files" : "Отримати додатки для синхронізації ваших файлів",
+ "Desktop client" : "Клієнт для ПК",
+ "Android app" : "Android-додаток",
+ "iOS app" : "iOS додаток",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "Якщо Ви хочете підтримати проект\n⇥⇥ <a href=\"https://owncloud.org/contribute\"\n⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> спільна розробка </a> \n⇥⇥або\n⇥ ⇥ <a href=\"https://owncloud.org/promote\"\n ⇥⇥⇥target=\"_blank\" rel=\"noreferrer\"> повідомити у світі </a> !",
+ "Show First Run Wizard again" : "Показувати Майстер Налаштувань знову",
"Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "Розроблено {communityopen} спільнотою ownCloud {linkclose}, {githubopen} вихідний код {linkclose} ліцензується відповідно до {licenseopen} <abbr title = \"Публічної ліцензії Affero General\"> AGPL </ abbr> {linkclose}.",
"Show storage location" : "Показати місцезнаходження сховища",
"Show last log in" : "Показати останній вхід в систему",
diff --git a/settings/l10n/ur_PK.js b/settings/l10n/ur_PK.js
index d59ea076104..a7d7b31f6ab 100644
--- a/settings/l10n/ur_PK.js
+++ b/settings/l10n/ur_PK.js
@@ -3,18 +3,18 @@ OC.L10N.register(
{
"Invalid request" : "غلط درخواست",
"Email sent" : "ارسال شدہ ای میل ",
+ "Delete" : "حذف کریں",
"Very weak password" : "بہت کمزور پاسورڈ",
"Weak password" : "کمزور پاسورڈ",
"So-so password" : "نص نص پاسورڈ",
"Good password" : "اچھا پاسورڈ",
"Strong password" : "مضبوط پاسورڈ",
- "Delete" : "حذف کریں",
"More" : "مزید",
"Less" : "کم",
"Cheers!" : "واہ!",
+ "Cancel" : "منسوخ کریں",
"Password" : "پاسورڈ",
"New password" : "نیا پاسورڈ",
- "Cancel" : "منسوخ کریں",
"Username" : "یوزر نیم",
"Other" : "دیگر"
},
diff --git a/settings/l10n/ur_PK.json b/settings/l10n/ur_PK.json
index 842c262782b..63c0fe8e803 100644
--- a/settings/l10n/ur_PK.json
+++ b/settings/l10n/ur_PK.json
@@ -1,18 +1,18 @@
{ "translations": {
"Invalid request" : "غلط درخواست",
"Email sent" : "ارسال شدہ ای میل ",
+ "Delete" : "حذف کریں",
"Very weak password" : "بہت کمزور پاسورڈ",
"Weak password" : "کمزور پاسورڈ",
"So-so password" : "نص نص پاسورڈ",
"Good password" : "اچھا پاسورڈ",
"Strong password" : "مضبوط پاسورڈ",
- "Delete" : "حذف کریں",
"More" : "مزید",
"Less" : "کم",
"Cheers!" : "واہ!",
+ "Cancel" : "منسوخ کریں",
"Password" : "پاسورڈ",
"New password" : "نیا پاسورڈ",
- "Cancel" : "منسوخ کریں",
"Username" : "یوزر نیم",
"Other" : "دیگر"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/settings/l10n/vi.js b/settings/l10n/vi.js
index c451a11e489..57fd6b8acae 100644
--- a/settings/l10n/vi.js
+++ b/settings/l10n/vi.js
@@ -6,11 +6,9 @@ OC.L10N.register(
"External Storage" : "Lưu trữ ngoài",
"Cron" : "Cron",
"Log" : "Log",
- "Authentication error" : "Lỗi xác thực",
- "Your full name has been changed." : "Họ và tên đã được thay đổi.",
- "Unable to change full name" : "Họ và tên không thể đổi ",
"Language changed" : "Ngôn ngữ đã được thay đổi",
"Invalid request" : "Yêu cầu không hợp lệ",
+ "Authentication error" : "Lỗi xác thực",
"Admins can't remove themself from the admin group" : "Quản trị viên không thể loại bỏ chính họ khỏi nhóm quản lý",
"Unable to add user to group %s" : "Không thể thêm người dùng vào nhóm %s",
"Unable to remove user from group %s" : "Không thể xóa người dùng từ nhóm %s",
@@ -19,6 +17,8 @@ OC.L10N.register(
"Saved" : "Đã lưu",
"Email sent" : "Email đã được gửi",
"Email saved" : "Lưu email",
+ "Your full name has been changed." : "Họ và tên đã được thay đổi.",
+ "Unable to change full name" : "Họ và tên không thể đổi ",
"All" : "Tất cả",
"Please wait...." : "Xin hãy đợi...",
"Disable" : "Tắt",
@@ -31,7 +31,6 @@ OC.L10N.register(
"undo" : "lùi lại",
"never" : "không thay đổi",
"__language_name__" : "__Ngôn ngữ___",
- "SSL root certificates" : "Chứng chỉ SSL root",
"None" : "Không gì cả",
"Login" : "Đăng nhập",
"Allow apps to use the Share API" : "Cho phép các ứng dụng sử dụng chia sẻ API",
@@ -44,25 +43,22 @@ OC.L10N.register(
"More" : "hơn",
"Less" : "ít",
"Version" : "Phiên bản",
- "by" : "bởi",
"Cheers!" : "Chúc mừng!",
"Forum" : "Diễn đàn",
- "Get the apps to sync your files" : "Nhận ứng dụng để đồng bộ file của bạn",
- "Show First Run Wizard again" : "Hiện lại việc chạy đồ thuật khởi đầu",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Bạn đã sử dụng <strong>%s </ strong> có sẵn <strong> %s </ strong>",
+ "Upload new" : "Tải lên",
+ "Remove image" : "Xóa ",
+ "Cancel" : "Hủy",
+ "Email" : "Email",
+ "Your email address" : "Email của bạn",
"Password" : "Mật khẩu",
"Unable to change your password" : "Không thể đổi mật khẩu",
"Current password" : "Mật khẩu cũ",
"New password" : "Mật khẩu mới",
"Change password" : "Đổi mật khẩu",
- "Email" : "Email",
- "Your email address" : "Email của bạn",
- "Upload new" : "Tải lên",
- "Remove image" : "Xóa ",
- "Cancel" : "Hủy",
- "Choose as profile image" : "Chọn hình ảnh như hồ sơ cá nhân",
"Language" : "Ngôn ngữ",
"Help translate" : "Hỗ trợ dịch thuật",
+ "Get the apps to sync your files" : "Nhận ứng dụng để đồng bộ file của bạn",
+ "Show First Run Wizard again" : "Hiện lại việc chạy đồ thuật khởi đầu",
"Username" : "Tên đăng nhập",
"Create" : "Tạo",
"Group" : "N",
diff --git a/settings/l10n/vi.json b/settings/l10n/vi.json
index a86e778713b..c4517eaf5db 100644
--- a/settings/l10n/vi.json
+++ b/settings/l10n/vi.json
@@ -4,11 +4,9 @@
"External Storage" : "Lưu trữ ngoài",
"Cron" : "Cron",
"Log" : "Log",
- "Authentication error" : "Lỗi xác thực",
- "Your full name has been changed." : "Họ và tên đã được thay đổi.",
- "Unable to change full name" : "Họ và tên không thể đổi ",
"Language changed" : "Ngôn ngữ đã được thay đổi",
"Invalid request" : "Yêu cầu không hợp lệ",
+ "Authentication error" : "Lỗi xác thực",
"Admins can't remove themself from the admin group" : "Quản trị viên không thể loại bỏ chính họ khỏi nhóm quản lý",
"Unable to add user to group %s" : "Không thể thêm người dùng vào nhóm %s",
"Unable to remove user from group %s" : "Không thể xóa người dùng từ nhóm %s",
@@ -17,6 +15,8 @@
"Saved" : "Đã lưu",
"Email sent" : "Email đã được gửi",
"Email saved" : "Lưu email",
+ "Your full name has been changed." : "Họ và tên đã được thay đổi.",
+ "Unable to change full name" : "Họ và tên không thể đổi ",
"All" : "Tất cả",
"Please wait...." : "Xin hãy đợi...",
"Disable" : "Tắt",
@@ -29,7 +29,6 @@
"undo" : "lùi lại",
"never" : "không thay đổi",
"__language_name__" : "__Ngôn ngữ___",
- "SSL root certificates" : "Chứng chỉ SSL root",
"None" : "Không gì cả",
"Login" : "Đăng nhập",
"Allow apps to use the Share API" : "Cho phép các ứng dụng sử dụng chia sẻ API",
@@ -42,25 +41,22 @@
"More" : "hơn",
"Less" : "ít",
"Version" : "Phiên bản",
- "by" : "bởi",
"Cheers!" : "Chúc mừng!",
"Forum" : "Diễn đàn",
- "Get the apps to sync your files" : "Nhận ứng dụng để đồng bộ file của bạn",
- "Show First Run Wizard again" : "Hiện lại việc chạy đồ thuật khởi đầu",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "Bạn đã sử dụng <strong>%s </ strong> có sẵn <strong> %s </ strong>",
+ "Upload new" : "Tải lên",
+ "Remove image" : "Xóa ",
+ "Cancel" : "Hủy",
+ "Email" : "Email",
+ "Your email address" : "Email của bạn",
"Password" : "Mật khẩu",
"Unable to change your password" : "Không thể đổi mật khẩu",
"Current password" : "Mật khẩu cũ",
"New password" : "Mật khẩu mới",
"Change password" : "Đổi mật khẩu",
- "Email" : "Email",
- "Your email address" : "Email của bạn",
- "Upload new" : "Tải lên",
- "Remove image" : "Xóa ",
- "Cancel" : "Hủy",
- "Choose as profile image" : "Chọn hình ảnh như hồ sơ cá nhân",
"Language" : "Ngôn ngữ",
"Help translate" : "Hỗ trợ dịch thuật",
+ "Get the apps to sync your files" : "Nhận ứng dụng để đồng bộ file của bạn",
+ "Show First Run Wizard again" : "Hiện lại việc chạy đồ thuật khởi đầu",
"Username" : "Tên đăng nhập",
"Create" : "Tạo",
"Group" : "N",
diff --git a/settings/l10n/zh_CN.js b/settings/l10n/zh_CN.js
index a1f828172d4..e9b4d71321b 100644
--- a/settings/l10n/zh_CN.js
+++ b/settings/l10n/zh_CN.js
@@ -12,12 +12,10 @@ OC.L10N.register(
"Log" : "日志",
"Tips & tricks" : "技巧提示",
"Updates" : "更新",
- "Authentication error" : "认证错误",
- "Your full name has been changed." : "您的全名已修改。",
- "Unable to change full name" : "无法修改全名",
"Couldn't remove app." : "无法删除应用。",
"Language changed" : "语言已修改",
"Invalid request" : "无效请求",
+ "Authentication error" : "认证错误",
"Admins can't remove themself from the admin group" : "管理员不能将自己移出管理组。",
"Unable to add user to group %s" : "无法把用户增加到组 %s",
"Unable to remove user from group %s" : "无法从组%s中移除用户",
@@ -53,6 +51,8 @@ OC.L10N.register(
"Invalid user" : "用户无效",
"Unable to change mail address" : "无法更改邮箱地址",
"Email saved" : "电子邮件已保存",
+ "Your full name has been changed." : "您的全名已修改。",
+ "Unable to change full name" : "无法修改全名",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "你真的希望添加 \"{domain}\" 为信任域?",
"Add trusted domain" : "添加信任域",
"Migration in progress. Please wait until the migration is finished" : "迁移正在进行中。请等待,直到完成迁移",
@@ -78,6 +78,12 @@ OC.L10N.register(
"Uninstalling ...." : "卸载中....",
"Error while uninstalling app" : "卸载应用时发生了一个错误",
"Uninstall" : "卸载",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "该应用已启用,但是需要更新。5秒后将跳转到更新页面。",
+ "App update" : "应用更新",
+ "No apps found for \"{query}\"" : "未找到应用适合 \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "出现了一个错误。请上传 ASCII 编码的 PEM 证书。",
+ "Valid until {date}" : "有效期至 {date}",
+ "Delete" : "删除",
"An error occurred: {message}" : "发生错误: {message}",
"Select a profile picture" : "选择头像",
"Very weak password" : "非常弱的密码",
@@ -85,9 +91,6 @@ OC.L10N.register(
"So-so password" : "一般强度的密码",
"Good password" : "较强的密码",
"Strong password" : "强密码",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "出现了一个错误。请上传 ASCII 编码的 PEM 证书。",
- "Valid until {date}" : "有效期至 {date}",
- "Delete" : "删除",
"Groups" : "组",
"Unable to delete {objName}" : "无法删除 {objName}",
"Error creating group" : "创建组时出错",
@@ -104,9 +107,8 @@ OC.L10N.register(
"A valid password must be provided" : "必须提供合法的密码",
"A valid email must be provided" : "必须提供合法的用户名",
"__language_name__" : "简体中文",
- "Sync clients" : "客户端",
"Personal info" : "个人信息",
- "SSL root certificates" : "SSL 根证书",
+ "Sync clients" : "客户端",
"Everything (fatal issues, errors, warnings, info, debug)" : "所有(灾难性问题,错误,警告,信息,调试)",
"Info, warnings, errors and fatal issues" : "信息,警告,错误和灾难性问题",
"Warnings, errors and fatal issues" : "警告,错误和灾难性问题",
@@ -132,7 +134,6 @@ OC.L10N.register(
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "我们强烈建议安装在系统上所需的软件包支持以下区域设置之一: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "如果你不是安装在网域根目录而且又使用系统定时计划任务,那么可以导致 URL 链接生成问题。为了避免这些问题,请在你的 Config.php 文件中设置 \\\"overwrite.cli.url\\\" 选项为 webroot 安装根目录 (建议: \\\"%s\\\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "由于下面的错误,无法通过 CLI 执行定时计划任务:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "事务文件锁定正在使用的数据库作为锁定后端,为获得最佳的性能建议配置的 memcache 用来锁定。请参阅<a target=\"_blank\" href=\"%s\">文档↗</a>了解详情。",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "请点击检查 <a target=\\\"_blank\\\" href=\\\"%s\\\"> 安装向导 ↗</a>, 点击 <a href=\\\"#log-section\\\"> 日志 </a>查看详细错误和警告。",
"All checks passed." : "所有检查已通过。",
"Open documentation" : "打开文档",
@@ -150,6 +151,7 @@ OC.L10N.register(
"Allow users to send mail notification for shared files to other users" : "允许用户发送共享文件的邮件通知给其他用户",
"Exclude groups from sharing" : "在分享中排除组",
"These groups will still be able to receive shares, but not to initiate them." : "这些组将仍可以获取分享,但无法向他人分享。",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "允许在共享对话框中的自动补全用户名。如果被禁用,需要输入用户全名。",
"Last cron job execution: %s." : "上次定时任务执行于: %s.",
"Last cron job execution: %s. Something seems wrong." : "上次定时任务执行于: %s. 似乎有些问题。",
"Cron was not executed yet!" : "定时任务还未被执行!",
@@ -180,7 +182,6 @@ OC.L10N.register(
"Store credentials" : "存储凭据",
"Test email settings" : "测试电子邮件设置",
"Send email" : "发送邮件",
- "Log level" : "日志级别",
"Download logfile" : "下载日志文件",
"More" : "更多",
"Less" : "更少",
@@ -198,8 +199,6 @@ OC.L10N.register(
"Developer documentation" : "开发者文档",
"Experimental applications ahead" : "未来的实验应用",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "实验应用程序没有在安全性的问题上作过多检查,新的或已知的不稳定 BUG 都在开发中。安装它们可能会导致数据丢失或安全漏洞。",
- "by" : "被",
- "licensed" : "许可",
"Documentation:" : "文档:",
"User documentation" : "用户文档",
"Admin documentation" : "管理员文档",
@@ -209,6 +208,11 @@ OC.L10N.register(
"Enable only for specific groups" : "仅对特定的组开放",
"Uninstall App" : "卸载应用",
"Enable experimental apps" : "启用实验性应用程序",
+ "Common Name" : "通用名称",
+ "Valid until" : "有效期至",
+ "Issued By" : "授权由",
+ "Valid until %s" : "有效期至 %s",
+ "Import root certificate" : "导入根证书",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "亲,<br><br>现在我们为你开通了 %s 私有云帐户。<br><br>你的用户名: %s<br>访问网址: <a href=\\\"%s\\\">%s</a><br><br>",
"Cheers!" : "干杯!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "亲,\\n\\n 现在我们为你开通了 %s 私有去帐户。\\n\\n 你的用户名: %s\\n 访问网址: %s\\n 你的初始密码需要咨询系统管理员。或者你也可以在登录页面输入任意密码登录,\\n登录窗口将出现忘记密码链接,点击通过注册邮箱重设初始密码。\\n\\n",
@@ -217,41 +221,30 @@ OC.L10N.register(
"Forum" : "论坛",
"Issue tracker" : "问题跟踪",
"Commercial support" : "商业支持",
- "Get the apps to sync your files" : "安装应用进行文件同步",
- "Desktop client" : "桌面客户端",
- "Android app" : "Android 应用",
- "iOS app" : "iOS 应用",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "想支持ownCloud项目?请\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">参加开发</a>\n\t\t或者\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">帮助推广</a>吧!",
- "Show First Run Wizard again" : "再次显示首次运行向导",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "你已使用 <strong>%s</strong>,有效空间 <strong>%s</strong>",
- "Password" : "密码",
- "Unable to change your password" : "无法修改密码",
- "Current password" : "当前密码",
- "New password" : "新密码",
- "Change password" : "修改密码",
+ "Profile picture" : "联系人图片",
+ "Upload new" : "上传新的",
+ "Remove image" : "移除图片",
+ "Cancel" : "取消",
"Full name" : "全名",
"No display name set" : "不显示名称设置",
"Email" : "电子邮件",
"Your email address" : "您的电子邮件",
- "Fill in an email address to enable password recovery and receive notifications" : "填入电子邮件地址从而启用密码恢复和接收通知",
"No email address set" : "尚未设置 Email 地址",
"You are member of the following groups:" : "您是以下组的成员:",
- "Profile picture" : "联系人图片",
- "Upload new" : "上传新的",
- "Select new from Files" : "从文件中选择一个新的",
- "Remove image" : "移除图片",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "png 或 jpg。正方形比较理想但你也可以之后对其进行裁剪。文件大小最大不允许超过 20MB。",
- "Your avatar is provided by your original account." : "您的头像由您的原始账户所提供。",
- "Cancel" : "取消",
- "Choose as profile image" : "用作头像",
+ "Password" : "密码",
+ "Unable to change your password" : "无法修改密码",
+ "Current password" : "当前密码",
+ "New password" : "新密码",
+ "Change password" : "修改密码",
"Language" : "语言",
"Help translate" : "帮助翻译",
- "Common Name" : "通用名称",
- "Valid until" : "有效期至",
- "Issued By" : "授权由",
- "Valid until %s" : "有效期至 %s",
- "Import root certificate" : "导入根证书",
- "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "由 {communityopen}ownCloud 社区{linkclose}开发,{githubopen}源代码{linkclose}在 {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr> 许可证{linkclose}下发布。",
+ "Get the apps to sync your files" : "安装应用进行文件同步",
+ "Desktop client" : "桌面客户端",
+ "Android app" : "Android 应用",
+ "iOS app" : "iOS 应用",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "想支持ownCloud项目?请\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">参加开发</a>\n\t\t或者\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">帮助推广</a>吧!",
+ "Show First Run Wizard again" : "再次显示首次运行向导",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "由 {communityopen}ownCloud 社区{linkclose}开发,{githubopen}源代码{linkclose}的发布需遵守 {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr> 许可协议{linkclose}。",
"Show storage location" : "显示存储位置",
"Show last log in" : "显示最后登录",
"Show user backend" : "显示用户后端",
diff --git a/settings/l10n/zh_CN.json b/settings/l10n/zh_CN.json
index 9cb1c97b9d6..7e15e5c0db7 100644
--- a/settings/l10n/zh_CN.json
+++ b/settings/l10n/zh_CN.json
@@ -10,12 +10,10 @@
"Log" : "日志",
"Tips & tricks" : "技巧提示",
"Updates" : "更新",
- "Authentication error" : "认证错误",
- "Your full name has been changed." : "您的全名已修改。",
- "Unable to change full name" : "无法修改全名",
"Couldn't remove app." : "无法删除应用。",
"Language changed" : "语言已修改",
"Invalid request" : "无效请求",
+ "Authentication error" : "认证错误",
"Admins can't remove themself from the admin group" : "管理员不能将自己移出管理组。",
"Unable to add user to group %s" : "无法把用户增加到组 %s",
"Unable to remove user from group %s" : "无法从组%s中移除用户",
@@ -51,6 +49,8 @@
"Invalid user" : "用户无效",
"Unable to change mail address" : "无法更改邮箱地址",
"Email saved" : "电子邮件已保存",
+ "Your full name has been changed." : "您的全名已修改。",
+ "Unable to change full name" : "无法修改全名",
"Are you really sure you want add \"{domain}\" as trusted domain?" : "你真的希望添加 \"{domain}\" 为信任域?",
"Add trusted domain" : "添加信任域",
"Migration in progress. Please wait until the migration is finished" : "迁移正在进行中。请等待,直到完成迁移",
@@ -76,6 +76,12 @@
"Uninstalling ...." : "卸载中....",
"Error while uninstalling app" : "卸载应用时发生了一个错误",
"Uninstall" : "卸载",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "该应用已启用,但是需要更新。5秒后将跳转到更新页面。",
+ "App update" : "应用更新",
+ "No apps found for \"{query}\"" : "未找到应用适合 \"{query}\"",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "出现了一个错误。请上传 ASCII 编码的 PEM 证书。",
+ "Valid until {date}" : "有效期至 {date}",
+ "Delete" : "删除",
"An error occurred: {message}" : "发生错误: {message}",
"Select a profile picture" : "选择头像",
"Very weak password" : "非常弱的密码",
@@ -83,9 +89,6 @@
"So-so password" : "一般强度的密码",
"Good password" : "较强的密码",
"Strong password" : "强密码",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "出现了一个错误。请上传 ASCII 编码的 PEM 证书。",
- "Valid until {date}" : "有效期至 {date}",
- "Delete" : "删除",
"Groups" : "组",
"Unable to delete {objName}" : "无法删除 {objName}",
"Error creating group" : "创建组时出错",
@@ -102,9 +105,8 @@
"A valid password must be provided" : "必须提供合法的密码",
"A valid email must be provided" : "必须提供合法的用户名",
"__language_name__" : "简体中文",
- "Sync clients" : "客户端",
"Personal info" : "个人信息",
- "SSL root certificates" : "SSL 根证书",
+ "Sync clients" : "客户端",
"Everything (fatal issues, errors, warnings, info, debug)" : "所有(灾难性问题,错误,警告,信息,调试)",
"Info, warnings, errors and fatal issues" : "信息,警告,错误和灾难性问题",
"Warnings, errors and fatal issues" : "警告,错误和灾难性问题",
@@ -130,7 +132,6 @@
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "我们强烈建议安装在系统上所需的软件包支持以下区域设置之一: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "如果你不是安装在网域根目录而且又使用系统定时计划任务,那么可以导致 URL 链接生成问题。为了避免这些问题,请在你的 Config.php 文件中设置 \\\"overwrite.cli.url\\\" 选项为 webroot 安装根目录 (建议: \\\"%s\\\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "由于下面的错误,无法通过 CLI 执行定时计划任务:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "事务文件锁定正在使用的数据库作为锁定后端,为获得最佳的性能建议配置的 memcache 用来锁定。请参阅<a target=\"_blank\" href=\"%s\">文档↗</a>了解详情。",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "请点击检查 <a target=\\\"_blank\\\" href=\\\"%s\\\"> 安装向导 ↗</a>, 点击 <a href=\\\"#log-section\\\"> 日志 </a>查看详细错误和警告。",
"All checks passed." : "所有检查已通过。",
"Open documentation" : "打开文档",
@@ -148,6 +149,7 @@
"Allow users to send mail notification for shared files to other users" : "允许用户发送共享文件的邮件通知给其他用户",
"Exclude groups from sharing" : "在分享中排除组",
"These groups will still be able to receive shares, but not to initiate them." : "这些组将仍可以获取分享,但无法向他人分享。",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "允许在共享对话框中的自动补全用户名。如果被禁用,需要输入用户全名。",
"Last cron job execution: %s." : "上次定时任务执行于: %s.",
"Last cron job execution: %s. Something seems wrong." : "上次定时任务执行于: %s. 似乎有些问题。",
"Cron was not executed yet!" : "定时任务还未被执行!",
@@ -178,7 +180,6 @@
"Store credentials" : "存储凭据",
"Test email settings" : "测试电子邮件设置",
"Send email" : "发送邮件",
- "Log level" : "日志级别",
"Download logfile" : "下载日志文件",
"More" : "更多",
"Less" : "更少",
@@ -196,8 +197,6 @@
"Developer documentation" : "开发者文档",
"Experimental applications ahead" : "未来的实验应用",
"Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "实验应用程序没有在安全性的问题上作过多检查,新的或已知的不稳定 BUG 都在开发中。安装它们可能会导致数据丢失或安全漏洞。",
- "by" : "被",
- "licensed" : "许可",
"Documentation:" : "文档:",
"User documentation" : "用户文档",
"Admin documentation" : "管理员文档",
@@ -207,6 +206,11 @@
"Enable only for specific groups" : "仅对特定的组开放",
"Uninstall App" : "卸载应用",
"Enable experimental apps" : "启用实验性应用程序",
+ "Common Name" : "通用名称",
+ "Valid until" : "有效期至",
+ "Issued By" : "授权由",
+ "Valid until %s" : "有效期至 %s",
+ "Import root certificate" : "导入根证书",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "亲,<br><br>现在我们为你开通了 %s 私有云帐户。<br><br>你的用户名: %s<br>访问网址: <a href=\\\"%s\\\">%s</a><br><br>",
"Cheers!" : "干杯!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "亲,\\n\\n 现在我们为你开通了 %s 私有去帐户。\\n\\n 你的用户名: %s\\n 访问网址: %s\\n 你的初始密码需要咨询系统管理员。或者你也可以在登录页面输入任意密码登录,\\n登录窗口将出现忘记密码链接,点击通过注册邮箱重设初始密码。\\n\\n",
@@ -215,41 +219,30 @@
"Forum" : "论坛",
"Issue tracker" : "问题跟踪",
"Commercial support" : "商业支持",
- "Get the apps to sync your files" : "安装应用进行文件同步",
- "Desktop client" : "桌面客户端",
- "Android app" : "Android 应用",
- "iOS app" : "iOS 应用",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "想支持ownCloud项目?请\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">参加开发</a>\n\t\t或者\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">帮助推广</a>吧!",
- "Show First Run Wizard again" : "再次显示首次运行向导",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "你已使用 <strong>%s</strong>,有效空间 <strong>%s</strong>",
- "Password" : "密码",
- "Unable to change your password" : "无法修改密码",
- "Current password" : "当前密码",
- "New password" : "新密码",
- "Change password" : "修改密码",
+ "Profile picture" : "联系人图片",
+ "Upload new" : "上传新的",
+ "Remove image" : "移除图片",
+ "Cancel" : "取消",
"Full name" : "全名",
"No display name set" : "不显示名称设置",
"Email" : "电子邮件",
"Your email address" : "您的电子邮件",
- "Fill in an email address to enable password recovery and receive notifications" : "填入电子邮件地址从而启用密码恢复和接收通知",
"No email address set" : "尚未设置 Email 地址",
"You are member of the following groups:" : "您是以下组的成员:",
- "Profile picture" : "联系人图片",
- "Upload new" : "上传新的",
- "Select new from Files" : "从文件中选择一个新的",
- "Remove image" : "移除图片",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "png 或 jpg。正方形比较理想但你也可以之后对其进行裁剪。文件大小最大不允许超过 20MB。",
- "Your avatar is provided by your original account." : "您的头像由您的原始账户所提供。",
- "Cancel" : "取消",
- "Choose as profile image" : "用作头像",
+ "Password" : "密码",
+ "Unable to change your password" : "无法修改密码",
+ "Current password" : "当前密码",
+ "New password" : "新密码",
+ "Change password" : "修改密码",
"Language" : "语言",
"Help translate" : "帮助翻译",
- "Common Name" : "通用名称",
- "Valid until" : "有效期至",
- "Issued By" : "授权由",
- "Valid until %s" : "有效期至 %s",
- "Import root certificate" : "导入根证书",
- "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "由 {communityopen}ownCloud 社区{linkclose}开发,{githubopen}源代码{linkclose}在 {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr> 许可证{linkclose}下发布。",
+ "Get the apps to sync your files" : "安装应用进行文件同步",
+ "Desktop client" : "桌面客户端",
+ "Android app" : "Android 应用",
+ "iOS app" : "iOS 应用",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "想支持ownCloud项目?请\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">参加开发</a>\n\t\t或者\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">帮助推广</a>吧!",
+ "Show First Run Wizard again" : "再次显示首次运行向导",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "由 {communityopen}ownCloud 社区{linkclose}开发,{githubopen}源代码{linkclose}的发布需遵守 {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr> 许可协议{linkclose}。",
"Show storage location" : "显示存储位置",
"Show last log in" : "显示最后登录",
"Show user backend" : "显示用户后端",
diff --git a/settings/l10n/zh_HK.js b/settings/l10n/zh_HK.js
index c2d56692bcf..7fff6540b53 100644
--- a/settings/l10n/zh_HK.js
+++ b/settings/l10n/zh_HK.js
@@ -32,21 +32,20 @@ OC.L10N.register(
"Port" : "連接埠",
"SMTP Username" : "SMTP 使用者名稱",
"SMTP Password" : "SMTP 密碼",
- "Log level" : "日誌等級",
"More" : "更多",
"Version" : "版本",
"Forum" : "討論區",
- "Android app" : "Android 應用程式",
- "iOS app" : "iOS 應用程式",
+ "Remove image" : "刪除圖片",
+ "Cancel" : "取消",
+ "Email" : "電郵",
+ "Your email address" : "你的電郵地址",
"Password" : "密碼",
"New password" : "新密碼",
"Change password" : "更改密碼",
- "Email" : "電郵",
- "Your email address" : "你的電郵地址",
- "Remove image" : "刪除圖片",
- "Cancel" : "取消",
"Language" : "語言",
"Help translate" : "幫忙翻譯",
+ "Android app" : "Android 應用程式",
+ "iOS app" : "iOS 應用程式",
"Username" : "用戶名稱",
"Create" : "新增",
"Group" : "群組",
diff --git a/settings/l10n/zh_HK.json b/settings/l10n/zh_HK.json
index 4a5e3ed713a..27421c62505 100644
--- a/settings/l10n/zh_HK.json
+++ b/settings/l10n/zh_HK.json
@@ -30,21 +30,20 @@
"Port" : "連接埠",
"SMTP Username" : "SMTP 使用者名稱",
"SMTP Password" : "SMTP 密碼",
- "Log level" : "日誌等級",
"More" : "更多",
"Version" : "版本",
"Forum" : "討論區",
- "Android app" : "Android 應用程式",
- "iOS app" : "iOS 應用程式",
+ "Remove image" : "刪除圖片",
+ "Cancel" : "取消",
+ "Email" : "電郵",
+ "Your email address" : "你的電郵地址",
"Password" : "密碼",
"New password" : "新密碼",
"Change password" : "更改密碼",
- "Email" : "電郵",
- "Your email address" : "你的電郵地址",
- "Remove image" : "刪除圖片",
- "Cancel" : "取消",
"Language" : "語言",
"Help translate" : "幫忙翻譯",
+ "Android app" : "Android 應用程式",
+ "iOS app" : "iOS 應用程式",
"Username" : "用戶名稱",
"Create" : "新增",
"Group" : "群組",
diff --git a/settings/l10n/zh_TW.js b/settings/l10n/zh_TW.js
index caa85e2b443..14e94ae0f30 100644
--- a/settings/l10n/zh_TW.js
+++ b/settings/l10n/zh_TW.js
@@ -10,17 +10,15 @@ OC.L10N.register(
"Cron" : "工作排程",
"Email server" : "郵件伺服器",
"Log" : "紀錄檔",
- "Tips & tricks" : "技巧 & 提示",
+ "Tips & tricks" : "技巧和提示",
"Updates" : "更新",
- "Authentication error" : "認證錯誤",
- "Your full name has been changed." : "您的全名已變更。",
- "Unable to change full name" : "無法變更全名",
"Couldn't remove app." : "無法移除應用程式",
"Language changed" : "語言已變更",
"Invalid request" : "無效請求",
+ "Authentication error" : "認證錯誤",
"Admins can't remove themself from the admin group" : "管理者帳號無法從管理者群組中移除",
- "Unable to add user to group %s" : "使用者加入群組 %s 錯誤",
- "Unable to remove user from group %s" : "使用者移出群組 %s 錯誤",
+ "Unable to add user to group %s" : "無法將使用者加入群組 %s",
+ "Unable to remove user from group %s" : "無法將使用者移出群組 %s",
"Couldn't update app." : "無法更新應用程式",
"Wrong password" : "密碼錯誤",
"No user supplied" : "未提供使用者",
@@ -29,11 +27,11 @@ OC.L10N.register(
"Backend doesn't support password change, but the user's encryption key was successfully updated." : "後端不支援變更密碼,但成功更新使用者的加密金鑰",
"Unable to change password" : "無法修改密碼",
"Enabled" : "已啓用",
- "Not enabled" : "無啟動",
+ "Not enabled" : "未啟用",
"installing and updating apps via the app store or Federated Cloud Sharing" : "透過應用程式中心或是聯盟式雲端分享來安裝、更新應用程式",
"Federated Cloud Sharing" : "聯盟式雲端分享",
- "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL 使用的版本 %s (%s)已經過期,請您更新您的作業系統,否則功能如 %s 可能無法正常運作。",
- "A problem occurred, please check your log files (Error: %s)" : "出現了一個問題,請您檢查您的記錄檔 (錯誤: %s)",
+ "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL 使用的 %s 版本已經過期 (%s),請您更新您的作業系統,否則功能如 %s 可能無法正常運作",
+ "A problem occurred, please check your log files (Error: %s)" : "出現問題,請您檢查您的記錄檔(錯誤:%s)",
"Migration Completed" : "遷移已完成",
"Group already exists." : "群組已存在",
"Unable to add group." : "無法新增群組",
@@ -41,9 +39,9 @@ OC.L10N.register(
"log-level out of allowed range" : "log-level 超過允許範圍",
"Saved" : "已儲存",
"test email settings" : "測試郵件設定",
- "A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "寄出郵件時發生問題,請檢查您的設定。(錯誤訊息:%s)",
+ "A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "寄出郵件時發生問題,請檢查您的設定(錯誤訊息:%s)",
"Email sent" : "Email 已寄出",
- "You need to set your user email before being able to send test emails." : "在準備要寄出測試郵件時您需要設定您的使用者郵件。",
+ "You need to set your user email before being able to send test emails." : "在寄出測試郵件前您需要設定信箱位址",
"Invalid mail address" : "無效的 email 地址",
"A user with that name already exists." : "同名的使用者已經存在",
"Unable to create user." : "無法建立使用者",
@@ -53,47 +51,49 @@ OC.L10N.register(
"Invalid user" : "無效的使用者",
"Unable to change mail address" : "無法更改 email 地址",
"Email saved" : "Email 已儲存",
- "Are you really sure you want add \"{domain}\" as trusted domain?" : "您確定要新增 \"{domain}' 為信任的網域?",
+ "Your full name has been changed." : "您的全名已變更",
+ "Unable to change full name" : "無法變更全名",
+ "Are you really sure you want add \"{domain}\" as trusted domain?" : "您確定要新增 \"{domain}' 為信任的網域?",
"Add trusted domain" : "新增信任的網域",
"Migration in progress. Please wait until the migration is finished" : "資料搬移中,請耐心等候直到資料搬移結束",
- "Migration started …" : "遷移開始中 ...",
- "Sending..." : "寄送中...",
+ "Migration started …" : "開始遷移…",
+ "Sending..." : "傳送中…",
"Official" : "官方",
- "Approved" : "已批准",
+ "Approved" : "審查通過",
"Experimental" : "實驗性質",
"All" : "所有",
- "No apps found for your version" : "在您的版本中未找到任何應用程式",
- "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "官方應用程式是由ownCloud社群開發,他們提供ownCloud的主要功能並確定功能已經準備好可以被使用。",
- "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "認可的應用程式經由可信任的開發人員所設計,並且經過一連串的安全測試,他們在開放的程式庫中維護這些應用程式,而且確保這些應用程式能穩定的正常使用。",
- "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "這個應用程式並沒有經過安全檢測,可能會是不穩定的,如果您要安裝的話,風險自行負責。",
+ "No apps found for your version" : "沒有找到適合您的版本的應用程式",
+ "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "官方應用程式由 ownCloud 社群開發,他們提供 ownCloud 的主要功能,並確保穩定性足供正式使用",
+ "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "審查通過的應用程式經由可信任的開發人員所設計,並且經過一連串的安全測試,他們在開放的程式庫中維護這些應用程式,而且確保這些應用程式能穩定運作",
+ "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "這個新應用程式並沒有經過安全檢測,可能會是不穩定的,如果您要安裝的話,風險自行負責。",
"Update to %s" : "更新到 %s",
- "Please wait...." : "請稍候...",
+ "Please wait...." : "請稍候…",
"Error while disabling app" : "停用應用程式錯誤",
"Disable" : "停用",
"Enable" : "啟用",
- "Error while enabling app" : "啓用應用程式錯誤",
- "Updating...." : "更新中...",
+ "Error while enabling app" : "啟用應用程式錯誤",
+ "Updating...." : "更新中…",
"Error while updating app" : "更新應用程式錯誤",
"Updated" : "已更新",
"Uninstalling ...." : "正在解除安裝…",
"Error while uninstalling app" : "移除應用程式錯誤",
"Uninstall" : "解除安裝",
- "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "這個應用程式已經可以使用,但是需要更新,您將會在5秒後被引導至更新頁面。",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "這個應用程式已啟用但是需要更新,您將會在 5 秒後被引導至更新頁面",
"App update" : "應用程式更新",
- "No apps found for \"{query}\"" : "此\"{query}\"未找到任何應用程式",
- "An error occurred: {message}" : "發生錯誤:{message}",
- "Select a profile picture" : "選擇大頭貼",
- "Very weak password" : "非常弱的密碼",
- "Weak password" : "弱的密碼",
- "So-so password" : "普通的密碼",
- "Good password" : "好的密碼",
- "Strong password" : "很強的密碼",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "錯誤發生,請您上傳ASCII編碼的PEM憑證。",
+ "No apps found for \"{query}\"" : "\"{query}\" 並未找到任何應用程式",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "發生錯誤,請您上傳 ASCII 編碼的 PEM 憑證",
"Valid until {date}" : "{date} 前有效",
"Delete" : "刪除",
+ "An error occurred: {message}" : "發生錯誤:{message}",
+ "Select a profile picture" : "選擇大頭貼",
+ "Very weak password" : "密碼強度非常弱",
+ "Weak password" : "密碼強度弱",
+ "So-so password" : "密碼強度普通",
+ "Good password" : "密碼強度佳",
+ "Strong password" : "密碼強度極佳",
"Groups" : "群組",
"Unable to delete {objName}" : "無法刪除 {objName}",
- "Error creating group" : "創建群組時發生錯誤",
+ "Error creating group" : "建立群組時發生錯誤",
"A valid group name must be provided" : "必須提供一個有效的群組名稱",
"deleted {groupName}" : "刪除 {groupName}",
"undo" : "復原",
@@ -103,81 +103,81 @@ OC.L10N.register(
"add group" : "新增群組",
"Changing the password will result in data loss, because data recovery is not available for this user" : "更改密碼會造成資料遺失,因為資料復原的功能無法在這個使用者使用",
"A valid username must be provided" : "必須提供一個有效的用戶名",
- "Error creating user" : "建立用戶時出現錯誤",
+ "Error creating user" : "建立使用者時出現錯誤",
"A valid password must be provided" : "一定要提供一個有效的密碼",
- "A valid email must be provided" : "必須提供一個有效的電子郵件",
+ "A valid email must be provided" : "必須提供一個有效的電子郵件地址",
"__language_name__" : "__language_name__",
- "Sync clients" : "同步客戶端",
"Personal info" : "個人資訊",
- "SSL root certificates" : "SSL 根憑證",
- "Everything (fatal issues, errors, warnings, info, debug)" : "全部(嚴重問題,錯誤,警告,資訊,除錯)",
- "Info, warnings, errors and fatal issues" : "資訊,警告,錯誤和嚴重問題",
- "Warnings, errors and fatal issues" : "警告,錯誤和嚴重問題",
+ "Sync clients" : "同步客戶端",
+ "Everything (fatal issues, errors, warnings, info, debug)" : "全部(嚴重問題、錯誤、警告、資訊、除錯訊息)",
+ "Info, warnings, errors and fatal issues" : "嚴重問題、錯誤、警告、資訊",
+ "Warnings, errors and fatal issues" : "嚴重問題、錯誤、警告",
"Errors and fatal issues" : "錯誤和嚴重問題",
"Fatal issues only" : "只有嚴重問題",
"None" : "無",
"Login" : "登入",
- "Plain" : "文字",
+ "Plain" : "Plain",
"NT LAN Manager" : "NT LAN Manager",
"SSL" : "SSL",
"TLS" : "TLS",
- "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "php看起來沒有設定完成,無法正確取得系統環境變數,getenv(\"PATH\")回傳資料為空值。",
- "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "請您參考 <a target=\"_blank\" href=\"%s\">安裝文件手冊 ↗</a> 來確認php的設定值以及伺服器端的php設定,特別是當您使用php-fpm。",
- "The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "僅供讀取功能已經啟用,這樣可以預防來至網頁端的設定操作,當檔案需要更改時,每次都需要手動更新為可寫入的模式。",
- "Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "您使用的伺服器是微軟的Windows,我們強烈建議您改用Linux以求最好的使用者體驗。",
- "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "%1$s 已經安裝以下版本 %2$s,為求穩定及效能表現,我們建議您將版本更新至新版的 %1$s。",
+ "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "PHP 看起來沒有設定完成,無法正確取得系統環境變數,getenv(\"PATH\") 回傳資料為空值",
+ "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "請至 <a target=\"_blank\" href=\"%s\">安裝手冊 ↗</a> 檢視 PHP 的設定說明以及伺服器端的 PHP 設定,特別是當您使用 php-fpm。",
+ "The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "「唯讀設定檔」已經啟用,這樣可以防止來自網頁端的設定操作,每次需要更改設定時,都需要手動將設定檔暫時改為可讀寫。",
+ "PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible." : "PHP 已經設定成「剪除 inline doc block」模式,這將會使幾個核心應用程式無法使用",
+ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "這大概是由快取或是加速器像是 Zend OPcache, eAccelerator 造成的",
+ "Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "您使用的伺服器是微軟的 Windows,我們強烈建議您改用 Linux 以求最好的使用者體驗",
+ "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "%1$s 的版本低於 %2$s,為求穩定及效能表現,我們建議更新至 %1$s。",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "未偵測到 PHP 模組 'fileinfo'。我們強烈建議啟用這個模組以取得最好的 mime-type 支援。",
- "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "事務型文件鎖定的功能已經取消,這可能會造成競態條件,請在config.php中啟用 'filelocking.enabled' 以避免出現這樣的問題,請參考<a target=\"_blank\" href=\"%s\">文件手冊 ↗</a> 來了解更多的資訊。",
- "System locale can not be set to a one which supports UTF-8." : "系統語系無法設定只支援 UTF-8",
- "This means that there might be problems with certain characters in file names." : "這個意思是指在檔名中使用一些字元可能會有問題",
- "We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "我們強烈建議在您的系統上安裝必要的套件來支援以下的語系: %s",
- "If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "如果您不是使用root來安裝,而是透過系統自定義的排程的話,URL的生成可能會有問題,為了避免這樣的狀況,請您在config.php檔案裡設置 \"overwrite.cli.url\",設定您安裝的webroot的路徑 (建議值: \"%s\")",
- "It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : " 不可能透過CLI來執行cronjob,發生以下技術性錯誤:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "事務型文件鎖定目前是使用後端資料庫的鎖定功能,為了達到最好的效能,建議鎖定功能使用記憶體快取,請看<a target=\"_blank\" href=\"%s\">文件手冊 ↗</a> 來獲得更多的資訊。",
- "Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "請再次檢查 <a target=\"_blank\" href=\"%s\">安裝導引手冊 ↗</a>,並且確定沒有任何的錯誤或是警告訊息在 <a href=\"#log-section\">記錄檔</a>。",
- "All checks passed." : "通過所有的檢查。",
- "Open documentation" : "開啟文件",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transactional file locking 已經停用,這可能會造成 race condition,請在 config.php 中設定 'filelocking.enabled' 以避免出現這樣的問題,請參考<a target=\"_blank\" href=\"%s\">說明文件 ↗</a> 來了解更多",
+ "System locale can not be set to a one which supports UTF-8." : "無法設定為一個支援 UTF-8 的系統語系",
+ "This means that there might be problems with certain characters in file names." : "這表示檔名中使用一些特殊字元可能會造成問題",
+ "We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "我們強烈建議在您的系統上安裝必要的套件來支援以下的語系:%s",
+ "If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "如果您的安裝不在網域的最上層,並且使用 cron 作為排程器,URL 的生成可能會有問題,為了避免這樣的狀況,請您在 config.php 檔案裡設定 overwrite.cli.url 為您安裝的 webroot 路徑(建議值:\"%s\")",
+ "It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : " 無法透過 CLI 來執行排程工作,發生以下技術性錯誤:",
+ "Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "請再次檢查 <a target=\"_blank\" href=\"%s\">安裝手冊 ↗</a>,並且確定沒有任何的錯誤或是警告訊息在 <a href=\"#log-section\">記錄檔</a>",
+ "All checks passed." : "所有檢查正常",
+ "Open documentation" : "開啟說明文件",
"Allow apps to use the Share API" : "允許 apps 使用分享 API",
- "Allow users to share via link" : "允使用者透過連結分享",
+ "Allow users to share via link" : "允許使用者透過連結分享",
"Enforce password protection" : "強制分享連結使用密碼保護",
- "Allow public uploads" : "允許任何人上傳",
+ "Allow public uploads" : "允許公開上傳",
"Allow users to send mail notification for shared files" : "允許使用者寄送有關分享檔案的郵件通知",
- "Set default expiration date" : "設定預設到期日期",
+ "Set default expiration date" : "設定預設到期日",
"Expire after " : "在什麼時候過期",
"days" : "天",
- "Enforce expiration date" : "強制分享連結設置分享期限",
+ "Enforce expiration date" : "強制分享連結設定到期日",
"Allow resharing" : "允許轉貼分享",
- "Restrict users to only share with users in their groups" : "限制使用者只能分享給群組裡的其他使用者。",
+ "Restrict users to only share with users in their groups" : "限制使用者只能分享給群組裡的其他使用者",
"Allow users to send mail notification for shared files to other users" : "允許使用者寄送檔案分享通知給其他使用者",
- "Exclude groups from sharing" : "禁止群組分享檔案",
- "These groups will still be able to receive shares, but not to initiate them." : "這個群組依然能夠收到其他分享,但是沒有辦法啟用。",
- "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "允許使用者名稱自動補齊在分享對話框,如果取消這個功能,必須完整輸入使用者名稱。",
- "Last cron job execution: %s." : "最後的排程已執行: %s。",
- "Last cron job execution: %s. Something seems wrong." : "最後的排程已執行: %s。看起來發生了一些錯誤。",
- "Cron was not executed yet!" : "排程沒有執行!",
- "Execute one task with each page loaded" : "當頁面載入時,執行",
- "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "已經與 webcron 服務註冊好,將會每15分鐘呼叫 cron.php",
- "Use system's cron service to call the cron.php file every 15 minutes." : "使用系統的 cron 服務每15分鐘呼叫 cron.php 一次",
- "Enable server-side encryption" : "啓用伺服器端加密",
- "Please read carefully before activating server-side encryption: " : "在您啟動伺服器端的加密之前,請詳細閱讀:",
- "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "一旦加密模式啟動,從各地上傳到伺服器端的所有檔案都會被加密,日後要取消這個功能的唯一可能是加密模組有支援,而且所有的設定(例如: 還原鑰匙)都符合。",
- "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "無法在此保證系統單獨加密的安全性,請您參考ownCloud的文件手冊中,加密應用程式的工作方式、支援和使用者案例,來獲得更多資訊。",
- "Be aware that encryption always increases the file size." : "請您要知道一件事,加密一定會增加檔案的大小。",
- "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "定時備份您的資料沒有壞處,萬一您有加密的話,請確保您也有讓您的資料和加密鑰匙一起備份。",
- "This is the final warning: Do you really want to enable encryption?" : "這是最後的警告:請問您真的要開啟加密模式?",
+ "Exclude groups from sharing" : "禁止特定群組分享檔案",
+ "These groups will still be able to receive shares, but not to initiate them." : "這些群組仍然能接受其他人的分享,但是沒有辦法發起分享",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "允許使用者名稱自動補齊在分享對話框,如果取消這個功能,必須完整輸入使用者名稱",
+ "Last cron job execution: %s." : "最近一次執行的排程工作:%s",
+ "Last cron job execution: %s. Something seems wrong." : "最近一次執行的排程工作:%s ,看起來發生了一些錯誤",
+ "Cron was not executed yet!" : "Cron 沒有執行!",
+ "Execute one task with each page loaded" : "每個頁面載入時執行",
+ "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "已經與 webcron 服務註冊好,將會每 15 分鐘透過 HTTP 呼叫 cron.php",
+ "Use system's cron service to call the cron.php file every 15 minutes." : "使用系統的 cron 服務每 15 分鐘呼叫 cron.php 一次",
+ "Enable server-side encryption" : "啟用伺服器端加密",
+ "Please read carefully before activating server-side encryption: " : "在您啟動伺服器端加密之前,請仔細閱讀:",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "一旦加密模式啟動,從各地上傳到伺服器端的檔案都會被加密,若日後要停用加密,需要加密模組的支援,而且所有的設定(例如: 還原金鑰)都正確",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "單純的加密不能保障系統的安全,請參閱 ownCloud 說明文件以瞭解加密程式的運作,還有它支援的使用情境",
+ "Be aware that encryption always increases the file size." : "請注意,加密一定會增加檔案的大小",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "定時備份您的資料沒有壞處,若您有啟用加密,請確保您也有備份加密金鑰",
+ "This is the final warning: Do you really want to enable encryption?" : "這是最後的警告:請問您真的要開啟加密模式?",
"Enable encryption" : "啟用加密",
- "No encryption module loaded, please enable an encryption module in the app menu." : "沒有載入加密模組,請您在應用程式清單中開啟加密模組。",
- "Select default encryption module:" : "選擇預設的加密模組:",
- "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run 'occ encryption:migrate'" : " 您需要搬移您的加密鑰匙從舊版的加密 (ownCloud <= 8.0) 到新版,請開啟 \"預設加密模組\" 並執行 'occ encryption:migrate'",
- "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : " 您需要搬移您的加密鑰匙從舊版的加密 (ownCloud <= 8.0) 到新版。",
- "Start migration" : "開始搬移",
- "This is used for sending out notifications." : "寄送通知用",
+ "No encryption module loaded, please enable an encryption module in the app menu." : "沒有載入加密模組,請您在應用程式清單中啟用加密模組",
+ "Select default encryption module:" : "選擇預設的加密模組:",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run 'occ encryption:migrate'" : " 您需要遷移您的加密金鑰從舊版的加密 (ownCloud <= 8.0) 到新版,請啟用「預設加密模組」並執行 'occ encryption:migrate'",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : " 您需要遷移您的加密金鑰從舊版的加密 (ownCloud <= 8.0) 到新版",
+ "Start migration" : "開始遷移",
+ "This is used for sending out notifications." : "用於寄送通知",
"Send mode" : "寄送模式",
"Encryption" : "加密",
"From address" : "寄件地址",
"mail" : "電子郵件",
- "Authentication method" : "驗證方式",
- "Authentication required" : "必須驗證",
+ "Authentication method" : "認證方式",
+ "Authentication required" : "需要認證",
"Server address" : "伺服器位址",
"Port" : "連接埠",
"Credentials" : "帳密",
@@ -186,11 +186,11 @@ OC.L10N.register(
"Store credentials" : "儲存帳密",
"Test email settings" : "測試郵件設定",
"Send email" : "寄送郵件",
- "Log level" : "紀錄層級",
"Download logfile" : "下載記錄檔",
"More" : "更多",
"Less" : "更少",
- "The logfile is bigger than 100 MB. Downloading it may take some time!" : "記錄檔的大小大於100MB,下載可能需要一些時間!",
+ "The logfile is bigger than 100 MB. Downloading it may take some time!" : "記錄檔大於 100MB,下載可能需要一些時間!",
+ "What to log" : "記錄哪些訊息",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "將會使用 SQLite 作為資料庫,在大型安裝中建議使用其他種資料庫",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "若使用桌面版程式同步檔案,不建議使用 SQLite",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "如果要搬移到其他資料庫,請使用命令提示字元工具: 'occ db:convert-type', 或者是參考 <a target=\"_blank\" href=\"%s\">documentation ↗</a>",
@@ -203,18 +203,23 @@ OC.L10N.register(
"Version" : "版本",
"Developer documentation" : "開發者說明文件",
"Experimental applications ahead" : "以下是實驗性質的應用程式",
- "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "實驗性質的應用程式並沒有經過安全檢測,可能會是不穩定而且開發困難,安裝他們可能會造成資料遺失或是安全問題。",
- "by" : "由",
- "licensed" : "許可證",
- "Documentation:" : "文件:",
+ "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "實驗性質的應用程式並沒有經過安全檢測,可能會不穩定而且正在開發中,安裝他們可能會造成資料遺失或是安全問題",
+ "Documentation:" : "說明文件:",
"User documentation" : "用戶說明文件",
"Admin documentation" : "管理者文件",
"Show description …" : "顯示描述",
"Hide description …" : "隱藏描述",
- "This app cannot be installed because the following dependencies are not fulfilled:" : "這個應用程式無法備被安裝,下列的相依性並不是完整的:",
- "Enable only for specific groups" : "僅對特定的群組開啟",
- "Uninstall App" : "刪除 App",
- "Enable experimental apps" : "啟用測試中的應用程式",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "此應用程式沒有指定支援的最小 ownCloud 版本,從 ownCloud 11 之後這會是個錯誤",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "此應用程式沒有指定支援的最大 ownCloud 版本,從 ownCloud 11 之後這會是個錯誤",
+ "This app cannot be installed because the following dependencies are not fulfilled:" : "這個應用程式無法被安裝,因為欠缺下列相依套件:",
+ "Enable only for specific groups" : "僅對特定的群組啟用",
+ "Uninstall App" : "解除安裝 App",
+ "Enable experimental apps" : "啟用實驗性質的應用程式",
+ "Common Name" : "Common Name",
+ "Valid until" : "到期日",
+ "Issued By" : "發行者:",
+ "Valid until %s" : "有效至 %s",
+ "Import root certificate" : "匯入根憑證",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "嗨,<br><br>通知您一聲,您現在有了 %s 的帳號。<br><br>您的帳號: %s<br>開通帳號: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "太棒了!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "嗨,\n\n通知您一聲,您現在有了 %s 的帳號。\n\n您的帳號:%s\n開通帳號:%s\n\n",
@@ -223,40 +228,36 @@ OC.L10N.register(
"Forum" : "論壇",
"Issue tracker" : "問題追蹤",
"Commercial support" : "商用支援",
- "Get the apps to sync your files" : "下載應用程式來同步您的檔案",
- "Desktop client" : "桌面客戶端",
- "Android app" : "Android 應用程式",
- "iOS app" : "iOS 應用程式",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "若您想支援這個計畫\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">加入開發者</a>\n\t\t或\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">替我們宣傳</a>!",
- "Show First Run Wizard again" : "再次顯示首次使用精靈",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "您已經使用了 <strong>%s</strong> ,目前可用空間為 <strong>%s</strong>",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "您正在使用 <strong>%s</strong> 的 <strong>%s</strong>",
+ "Profile picture" : "大頭照",
+ "Upload new" : "上傳新的",
+ "Select from Files" : "從檔案應用程式選擇",
+ "Remove image" : "移除圖片",
+ "png or jpg, max. 20 MB" : "png 或 jpg ,最大 20 MB",
+ "Picture provided by original account" : "原本的帳戶提供的圖片",
+ "Cancel" : "取消",
+ "Choose as profile picture" : "選為大頭照",
+ "Full name" : "全名",
+ "No display name set" : "未設定顯示名稱",
+ "Email" : "信箱",
+ "Your email address" : "您的電子郵件信箱",
+ "For password recovery and notifications" : "用於密碼重設和通知",
+ "No email address set" : "未設定電子郵件信箱",
+ "You are member of the following groups:" : "您的帳號屬於這些群組:",
"Password" : "密碼",
"Unable to change your password" : "無法變更您的密碼",
"Current password" : "目前密碼",
"New password" : "新密碼",
"Change password" : "變更密碼",
- "Full name" : "全名",
- "No display name set" : "未設置顯示名稱",
- "Email" : "信箱",
- "Your email address" : "您的電子郵件信箱",
- "Fill in an email address to enable password recovery and receive notifications" : "填入電子郵件地址來啟用忘記密碼和接收通知的功能",
- "No email address set" : "未設置電子郵件信箱",
- "You are member of the following groups:" : "您的會員帳號歸類在以下群組:",
- "Profile picture" : "個人資料照片",
- "Upload new" : "上傳新的",
- "Select new from Files" : "從已上傳的檔案中選一個",
- "Remove image" : "移除圖片",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "可以使用 png 或 jpg 格式,最好是方形的,但是您之後也可以裁剪它。圖片容量最大請勿超過 20 MB。",
- "Your avatar is provided by your original account." : "您的圖像是由您原來的帳號所提供的。",
- "Cancel" : "取消",
- "Choose as profile image" : "設定為大頭貼",
"Language" : "語言",
"Help translate" : "幫助翻譯",
- "Common Name" : "Common Name",
- "Valid until" : "前有效",
- "Issued By" : "發行者:",
- "Valid until %s" : "有效至 %s",
- "Import root certificate" : "匯入root憑證",
+ "Get the apps to sync your files" : "下載應用程式來同步您的檔案",
+ "Desktop client" : "桌面客戶端",
+ "Android app" : "Android 應用程式",
+ "iOS app" : "iOS 應用程式",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "若您想支援這個計畫\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">加入開發者</a>\n\t\t或\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">替我們宣傳</a>!",
+ "Show First Run Wizard again" : "再次顯示首次使用精靈",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "由 {communityopen}ownCloud 社群{linkclose} 開發,{githubopen}原始碼{linkclose}使用 {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} 授權釋出",
"Show storage location" : "顯示儲存位置",
"Show last log in" : "顯示最近登入",
"Show user backend" : "顯示用戶後台",
@@ -272,13 +273,14 @@ OC.L10N.register(
"Everyone" : "所有人",
"Admins" : "管理者",
"Default Quota" : "預設容量限制",
- "Please enter storage quota (ex: \"512 MB\" or \"12 GB\")" : "請輸入空間配額(例如: \"512 MB\"或是 \"12 GB\")",
+ "Please enter storage quota (ex: \"512 MB\" or \"12 GB\")" : "請輸入空間配額(例如 \"512 MB\" 或是 \"12 GB\")",
"Unlimited" : "無限制",
"Other" : "其他",
"Full Name" : "全名",
+ "Group Admin for" : "指定群組管理者",
"Quota" : "容量限制",
"Storage Location" : "儲存位置",
- "User Backend" : "用戶後台",
+ "User Backend" : "用戶後端",
"Last Login" : "上次登入",
"change full name" : "變更全名",
"set new password" : "設定新密碼",
diff --git a/settings/l10n/zh_TW.json b/settings/l10n/zh_TW.json
index 2d7951b8930..0fc46a9ee8f 100644
--- a/settings/l10n/zh_TW.json
+++ b/settings/l10n/zh_TW.json
@@ -8,17 +8,15 @@
"Cron" : "工作排程",
"Email server" : "郵件伺服器",
"Log" : "紀錄檔",
- "Tips & tricks" : "技巧 & 提示",
+ "Tips & tricks" : "技巧和提示",
"Updates" : "更新",
- "Authentication error" : "認證錯誤",
- "Your full name has been changed." : "您的全名已變更。",
- "Unable to change full name" : "無法變更全名",
"Couldn't remove app." : "無法移除應用程式",
"Language changed" : "語言已變更",
"Invalid request" : "無效請求",
+ "Authentication error" : "認證錯誤",
"Admins can't remove themself from the admin group" : "管理者帳號無法從管理者群組中移除",
- "Unable to add user to group %s" : "使用者加入群組 %s 錯誤",
- "Unable to remove user from group %s" : "使用者移出群組 %s 錯誤",
+ "Unable to add user to group %s" : "無法將使用者加入群組 %s",
+ "Unable to remove user from group %s" : "無法將使用者移出群組 %s",
"Couldn't update app." : "無法更新應用程式",
"Wrong password" : "密碼錯誤",
"No user supplied" : "未提供使用者",
@@ -27,11 +25,11 @@
"Backend doesn't support password change, but the user's encryption key was successfully updated." : "後端不支援變更密碼,但成功更新使用者的加密金鑰",
"Unable to change password" : "無法修改密碼",
"Enabled" : "已啓用",
- "Not enabled" : "無啟動",
+ "Not enabled" : "未啟用",
"installing and updating apps via the app store or Federated Cloud Sharing" : "透過應用程式中心或是聯盟式雲端分享來安裝、更新應用程式",
"Federated Cloud Sharing" : "聯盟式雲端分享",
- "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL 使用的版本 %s (%s)已經過期,請您更新您的作業系統,否則功能如 %s 可能無法正常運作。",
- "A problem occurred, please check your log files (Error: %s)" : "出現了一個問題,請您檢查您的記錄檔 (錯誤: %s)",
+ "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL 使用的 %s 版本已經過期 (%s),請您更新您的作業系統,否則功能如 %s 可能無法正常運作",
+ "A problem occurred, please check your log files (Error: %s)" : "出現問題,請您檢查您的記錄檔(錯誤:%s)",
"Migration Completed" : "遷移已完成",
"Group already exists." : "群組已存在",
"Unable to add group." : "無法新增群組",
@@ -39,9 +37,9 @@
"log-level out of allowed range" : "log-level 超過允許範圍",
"Saved" : "已儲存",
"test email settings" : "測試郵件設定",
- "A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "寄出郵件時發生問題,請檢查您的設定。(錯誤訊息:%s)",
+ "A problem occurred while sending the email. Please revise your settings. (Error: %s)" : "寄出郵件時發生問題,請檢查您的設定(錯誤訊息:%s)",
"Email sent" : "Email 已寄出",
- "You need to set your user email before being able to send test emails." : "在準備要寄出測試郵件時您需要設定您的使用者郵件。",
+ "You need to set your user email before being able to send test emails." : "在寄出測試郵件前您需要設定信箱位址",
"Invalid mail address" : "無效的 email 地址",
"A user with that name already exists." : "同名的使用者已經存在",
"Unable to create user." : "無法建立使用者",
@@ -51,47 +49,49 @@
"Invalid user" : "無效的使用者",
"Unable to change mail address" : "無法更改 email 地址",
"Email saved" : "Email 已儲存",
- "Are you really sure you want add \"{domain}\" as trusted domain?" : "您確定要新增 \"{domain}' 為信任的網域?",
+ "Your full name has been changed." : "您的全名已變更",
+ "Unable to change full name" : "無法變更全名",
+ "Are you really sure you want add \"{domain}\" as trusted domain?" : "您確定要新增 \"{domain}' 為信任的網域?",
"Add trusted domain" : "新增信任的網域",
"Migration in progress. Please wait until the migration is finished" : "資料搬移中,請耐心等候直到資料搬移結束",
- "Migration started …" : "遷移開始中 ...",
- "Sending..." : "寄送中...",
+ "Migration started …" : "開始遷移…",
+ "Sending..." : "傳送中…",
"Official" : "官方",
- "Approved" : "已批准",
+ "Approved" : "審查通過",
"Experimental" : "實驗性質",
"All" : "所有",
- "No apps found for your version" : "在您的版本中未找到任何應用程式",
- "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "官方應用程式是由ownCloud社群開發,他們提供ownCloud的主要功能並確定功能已經準備好可以被使用。",
- "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "認可的應用程式經由可信任的開發人員所設計,並且經過一連串的安全測試,他們在開放的程式庫中維護這些應用程式,而且確保這些應用程式能穩定的正常使用。",
- "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "這個應用程式並沒有經過安全檢測,可能會是不穩定的,如果您要安裝的話,風險自行負責。",
+ "No apps found for your version" : "沒有找到適合您的版本的應用程式",
+ "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "官方應用程式由 ownCloud 社群開發,他們提供 ownCloud 的主要功能,並確保穩定性足供正式使用",
+ "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "審查通過的應用程式經由可信任的開發人員所設計,並且經過一連串的安全測試,他們在開放的程式庫中維護這些應用程式,而且確保這些應用程式能穩定運作",
+ "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "這個新應用程式並沒有經過安全檢測,可能會是不穩定的,如果您要安裝的話,風險自行負責。",
"Update to %s" : "更新到 %s",
- "Please wait...." : "請稍候...",
+ "Please wait...." : "請稍候…",
"Error while disabling app" : "停用應用程式錯誤",
"Disable" : "停用",
"Enable" : "啟用",
- "Error while enabling app" : "啓用應用程式錯誤",
- "Updating...." : "更新中...",
+ "Error while enabling app" : "啟用應用程式錯誤",
+ "Updating...." : "更新中…",
"Error while updating app" : "更新應用程式錯誤",
"Updated" : "已更新",
"Uninstalling ...." : "正在解除安裝…",
"Error while uninstalling app" : "移除應用程式錯誤",
"Uninstall" : "解除安裝",
- "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "這個應用程式已經可以使用,但是需要更新,您將會在5秒後被引導至更新頁面。",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "這個應用程式已啟用但是需要更新,您將會在 5 秒後被引導至更新頁面",
"App update" : "應用程式更新",
- "No apps found for \"{query}\"" : "此\"{query}\"未找到任何應用程式",
- "An error occurred: {message}" : "發生錯誤:{message}",
- "Select a profile picture" : "選擇大頭貼",
- "Very weak password" : "非常弱的密碼",
- "Weak password" : "弱的密碼",
- "So-so password" : "普通的密碼",
- "Good password" : "好的密碼",
- "Strong password" : "很強的密碼",
- "An error occurred. Please upload an ASCII-encoded PEM certificate." : "錯誤發生,請您上傳ASCII編碼的PEM憑證。",
+ "No apps found for \"{query}\"" : "\"{query}\" 並未找到任何應用程式",
+ "An error occurred. Please upload an ASCII-encoded PEM certificate." : "發生錯誤,請您上傳 ASCII 編碼的 PEM 憑證",
"Valid until {date}" : "{date} 前有效",
"Delete" : "刪除",
+ "An error occurred: {message}" : "發生錯誤:{message}",
+ "Select a profile picture" : "選擇大頭貼",
+ "Very weak password" : "密碼強度非常弱",
+ "Weak password" : "密碼強度弱",
+ "So-so password" : "密碼強度普通",
+ "Good password" : "密碼強度佳",
+ "Strong password" : "密碼強度極佳",
"Groups" : "群組",
"Unable to delete {objName}" : "無法刪除 {objName}",
- "Error creating group" : "創建群組時發生錯誤",
+ "Error creating group" : "建立群組時發生錯誤",
"A valid group name must be provided" : "必須提供一個有效的群組名稱",
"deleted {groupName}" : "刪除 {groupName}",
"undo" : "復原",
@@ -101,81 +101,81 @@
"add group" : "新增群組",
"Changing the password will result in data loss, because data recovery is not available for this user" : "更改密碼會造成資料遺失,因為資料復原的功能無法在這個使用者使用",
"A valid username must be provided" : "必須提供一個有效的用戶名",
- "Error creating user" : "建立用戶時出現錯誤",
+ "Error creating user" : "建立使用者時出現錯誤",
"A valid password must be provided" : "一定要提供一個有效的密碼",
- "A valid email must be provided" : "必須提供一個有效的電子郵件",
+ "A valid email must be provided" : "必須提供一個有效的電子郵件地址",
"__language_name__" : "__language_name__",
- "Sync clients" : "同步客戶端",
"Personal info" : "個人資訊",
- "SSL root certificates" : "SSL 根憑證",
- "Everything (fatal issues, errors, warnings, info, debug)" : "全部(嚴重問題,錯誤,警告,資訊,除錯)",
- "Info, warnings, errors and fatal issues" : "資訊,警告,錯誤和嚴重問題",
- "Warnings, errors and fatal issues" : "警告,錯誤和嚴重問題",
+ "Sync clients" : "同步客戶端",
+ "Everything (fatal issues, errors, warnings, info, debug)" : "全部(嚴重問題、錯誤、警告、資訊、除錯訊息)",
+ "Info, warnings, errors and fatal issues" : "嚴重問題、錯誤、警告、資訊",
+ "Warnings, errors and fatal issues" : "嚴重問題、錯誤、警告",
"Errors and fatal issues" : "錯誤和嚴重問題",
"Fatal issues only" : "只有嚴重問題",
"None" : "無",
"Login" : "登入",
- "Plain" : "文字",
+ "Plain" : "Plain",
"NT LAN Manager" : "NT LAN Manager",
"SSL" : "SSL",
"TLS" : "TLS",
- "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "php看起來沒有設定完成,無法正確取得系統環境變數,getenv(\"PATH\")回傳資料為空值。",
- "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "請您參考 <a target=\"_blank\" href=\"%s\">安裝文件手冊 ↗</a> 來確認php的設定值以及伺服器端的php設定,特別是當您使用php-fpm。",
- "The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "僅供讀取功能已經啟用,這樣可以預防來至網頁端的設定操作,當檔案需要更改時,每次都需要手動更新為可寫入的模式。",
- "Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "您使用的伺服器是微軟的Windows,我們強烈建議您改用Linux以求最好的使用者體驗。",
- "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "%1$s 已經安裝以下版本 %2$s,為求穩定及效能表現,我們建議您將版本更新至新版的 %1$s。",
+ "php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "PHP 看起來沒有設定完成,無法正確取得系統環境變數,getenv(\"PATH\") 回傳資料為空值",
+ "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "請至 <a target=\"_blank\" href=\"%s\">安裝手冊 ↗</a> 檢視 PHP 的設定說明以及伺服器端的 PHP 設定,特別是當您使用 php-fpm。",
+ "The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "「唯讀設定檔」已經啟用,這樣可以防止來自網頁端的設定操作,每次需要更改設定時,都需要手動將設定檔暫時改為可讀寫。",
+ "PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible." : "PHP 已經設定成「剪除 inline doc block」模式,這將會使幾個核心應用程式無法使用",
+ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "這大概是由快取或是加速器像是 Zend OPcache, eAccelerator 造成的",
+ "Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "您使用的伺服器是微軟的 Windows,我們強烈建議您改用 Linux 以求最好的使用者體驗",
+ "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "%1$s 的版本低於 %2$s,為求穩定及效能表現,我們建議更新至 %1$s。",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "未偵測到 PHP 模組 'fileinfo'。我們強烈建議啟用這個模組以取得最好的 mime-type 支援。",
- "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "事務型文件鎖定的功能已經取消,這可能會造成競態條件,請在config.php中啟用 'filelocking.enabled' 以避免出現這樣的問題,請參考<a target=\"_blank\" href=\"%s\">文件手冊 ↗</a> 來了解更多的資訊。",
- "System locale can not be set to a one which supports UTF-8." : "系統語系無法設定只支援 UTF-8",
- "This means that there might be problems with certain characters in file names." : "這個意思是指在檔名中使用一些字元可能會有問題",
- "We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "我們強烈建議在您的系統上安裝必要的套件來支援以下的語系: %s",
- "If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "如果您不是使用root來安裝,而是透過系統自定義的排程的話,URL的生成可能會有問題,為了避免這樣的狀況,請您在config.php檔案裡設置 \"overwrite.cli.url\",設定您安裝的webroot的路徑 (建議值: \"%s\")",
- "It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : " 不可能透過CLI來執行cronjob,發生以下技術性錯誤:",
- "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "事務型文件鎖定目前是使用後端資料庫的鎖定功能,為了達到最好的效能,建議鎖定功能使用記憶體快取,請看<a target=\"_blank\" href=\"%s\">文件手冊 ↗</a> 來獲得更多的資訊。",
- "Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "請再次檢查 <a target=\"_blank\" href=\"%s\">安裝導引手冊 ↗</a>,並且確定沒有任何的錯誤或是警告訊息在 <a href=\"#log-section\">記錄檔</a>。",
- "All checks passed." : "通過所有的檢查。",
- "Open documentation" : "開啟文件",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transactional file locking 已經停用,這可能會造成 race condition,請在 config.php 中設定 'filelocking.enabled' 以避免出現這樣的問題,請參考<a target=\"_blank\" href=\"%s\">說明文件 ↗</a> 來了解更多",
+ "System locale can not be set to a one which supports UTF-8." : "無法設定為一個支援 UTF-8 的系統語系",
+ "This means that there might be problems with certain characters in file names." : "這表示檔名中使用一些特殊字元可能會造成問題",
+ "We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "我們強烈建議在您的系統上安裝必要的套件來支援以下的語系:%s",
+ "If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "如果您的安裝不在網域的最上層,並且使用 cron 作為排程器,URL 的生成可能會有問題,為了避免這樣的狀況,請您在 config.php 檔案裡設定 overwrite.cli.url 為您安裝的 webroot 路徑(建議值:\"%s\")",
+ "It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : " 無法透過 CLI 來執行排程工作,發生以下技術性錯誤:",
+ "Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "請再次檢查 <a target=\"_blank\" href=\"%s\">安裝手冊 ↗</a>,並且確定沒有任何的錯誤或是警告訊息在 <a href=\"#log-section\">記錄檔</a>",
+ "All checks passed." : "所有檢查正常",
+ "Open documentation" : "開啟說明文件",
"Allow apps to use the Share API" : "允許 apps 使用分享 API",
- "Allow users to share via link" : "允使用者透過連結分享",
+ "Allow users to share via link" : "允許使用者透過連結分享",
"Enforce password protection" : "強制分享連結使用密碼保護",
- "Allow public uploads" : "允許任何人上傳",
+ "Allow public uploads" : "允許公開上傳",
"Allow users to send mail notification for shared files" : "允許使用者寄送有關分享檔案的郵件通知",
- "Set default expiration date" : "設定預設到期日期",
+ "Set default expiration date" : "設定預設到期日",
"Expire after " : "在什麼時候過期",
"days" : "天",
- "Enforce expiration date" : "強制分享連結設置分享期限",
+ "Enforce expiration date" : "強制分享連結設定到期日",
"Allow resharing" : "允許轉貼分享",
- "Restrict users to only share with users in their groups" : "限制使用者只能分享給群組裡的其他使用者。",
+ "Restrict users to only share with users in their groups" : "限制使用者只能分享給群組裡的其他使用者",
"Allow users to send mail notification for shared files to other users" : "允許使用者寄送檔案分享通知給其他使用者",
- "Exclude groups from sharing" : "禁止群組分享檔案",
- "These groups will still be able to receive shares, but not to initiate them." : "這個群組依然能夠收到其他分享,但是沒有辦法啟用。",
- "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "允許使用者名稱自動補齊在分享對話框,如果取消這個功能,必須完整輸入使用者名稱。",
- "Last cron job execution: %s." : "最後的排程已執行: %s。",
- "Last cron job execution: %s. Something seems wrong." : "最後的排程已執行: %s。看起來發生了一些錯誤。",
- "Cron was not executed yet!" : "排程沒有執行!",
- "Execute one task with each page loaded" : "當頁面載入時,執行",
- "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "已經與 webcron 服務註冊好,將會每15分鐘呼叫 cron.php",
- "Use system's cron service to call the cron.php file every 15 minutes." : "使用系統的 cron 服務每15分鐘呼叫 cron.php 一次",
- "Enable server-side encryption" : "啓用伺服器端加密",
- "Please read carefully before activating server-side encryption: " : "在您啟動伺服器端的加密之前,請詳細閱讀:",
- "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "一旦加密模式啟動,從各地上傳到伺服器端的所有檔案都會被加密,日後要取消這個功能的唯一可能是加密模組有支援,而且所有的設定(例如: 還原鑰匙)都符合。",
- "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "無法在此保證系統單獨加密的安全性,請您參考ownCloud的文件手冊中,加密應用程式的工作方式、支援和使用者案例,來獲得更多資訊。",
- "Be aware that encryption always increases the file size." : "請您要知道一件事,加密一定會增加檔案的大小。",
- "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "定時備份您的資料沒有壞處,萬一您有加密的話,請確保您也有讓您的資料和加密鑰匙一起備份。",
- "This is the final warning: Do you really want to enable encryption?" : "這是最後的警告:請問您真的要開啟加密模式?",
+ "Exclude groups from sharing" : "禁止特定群組分享檔案",
+ "These groups will still be able to receive shares, but not to initiate them." : "這些群組仍然能接受其他人的分享,但是沒有辦法發起分享",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "允許使用者名稱自動補齊在分享對話框,如果取消這個功能,必須完整輸入使用者名稱",
+ "Last cron job execution: %s." : "最近一次執行的排程工作:%s",
+ "Last cron job execution: %s. Something seems wrong." : "最近一次執行的排程工作:%s ,看起來發生了一些錯誤",
+ "Cron was not executed yet!" : "Cron 沒有執行!",
+ "Execute one task with each page loaded" : "每個頁面載入時執行",
+ "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "已經與 webcron 服務註冊好,將會每 15 分鐘透過 HTTP 呼叫 cron.php",
+ "Use system's cron service to call the cron.php file every 15 minutes." : "使用系統的 cron 服務每 15 分鐘呼叫 cron.php 一次",
+ "Enable server-side encryption" : "啟用伺服器端加密",
+ "Please read carefully before activating server-side encryption: " : "在您啟動伺服器端加密之前,請仔細閱讀:",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "一旦加密模式啟動,從各地上傳到伺服器端的檔案都會被加密,若日後要停用加密,需要加密模組的支援,而且所有的設定(例如: 還原金鑰)都正確",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "單純的加密不能保障系統的安全,請參閱 ownCloud 說明文件以瞭解加密程式的運作,還有它支援的使用情境",
+ "Be aware that encryption always increases the file size." : "請注意,加密一定會增加檔案的大小",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "定時備份您的資料沒有壞處,若您有啟用加密,請確保您也有備份加密金鑰",
+ "This is the final warning: Do you really want to enable encryption?" : "這是最後的警告:請問您真的要開啟加密模式?",
"Enable encryption" : "啟用加密",
- "No encryption module loaded, please enable an encryption module in the app menu." : "沒有載入加密模組,請您在應用程式清單中開啟加密模組。",
- "Select default encryption module:" : "選擇預設的加密模組:",
- "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run 'occ encryption:migrate'" : " 您需要搬移您的加密鑰匙從舊版的加密 (ownCloud <= 8.0) 到新版,請開啟 \"預設加密模組\" 並執行 'occ encryption:migrate'",
- "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : " 您需要搬移您的加密鑰匙從舊版的加密 (ownCloud <= 8.0) 到新版。",
- "Start migration" : "開始搬移",
- "This is used for sending out notifications." : "寄送通知用",
+ "No encryption module loaded, please enable an encryption module in the app menu." : "沒有載入加密模組,請您在應用程式清單中啟用加密模組",
+ "Select default encryption module:" : "選擇預設的加密模組:",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run 'occ encryption:migrate'" : " 您需要遷移您的加密金鑰從舊版的加密 (ownCloud <= 8.0) 到新版,請啟用「預設加密模組」並執行 'occ encryption:migrate'",
+ "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : " 您需要遷移您的加密金鑰從舊版的加密 (ownCloud <= 8.0) 到新版",
+ "Start migration" : "開始遷移",
+ "This is used for sending out notifications." : "用於寄送通知",
"Send mode" : "寄送模式",
"Encryption" : "加密",
"From address" : "寄件地址",
"mail" : "電子郵件",
- "Authentication method" : "驗證方式",
- "Authentication required" : "必須驗證",
+ "Authentication method" : "認證方式",
+ "Authentication required" : "需要認證",
"Server address" : "伺服器位址",
"Port" : "連接埠",
"Credentials" : "帳密",
@@ -184,11 +184,11 @@
"Store credentials" : "儲存帳密",
"Test email settings" : "測試郵件設定",
"Send email" : "寄送郵件",
- "Log level" : "紀錄層級",
"Download logfile" : "下載記錄檔",
"More" : "更多",
"Less" : "更少",
- "The logfile is bigger than 100 MB. Downloading it may take some time!" : "記錄檔的大小大於100MB,下載可能需要一些時間!",
+ "The logfile is bigger than 100 MB. Downloading it may take some time!" : "記錄檔大於 100MB,下載可能需要一些時間!",
+ "What to log" : "記錄哪些訊息",
"SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "將會使用 SQLite 作為資料庫,在大型安裝中建議使用其他種資料庫",
"Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "若使用桌面版程式同步檔案,不建議使用 SQLite",
"To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "如果要搬移到其他資料庫,請使用命令提示字元工具: 'occ db:convert-type', 或者是參考 <a target=\"_blank\" href=\"%s\">documentation ↗</a>",
@@ -201,18 +201,23 @@
"Version" : "版本",
"Developer documentation" : "開發者說明文件",
"Experimental applications ahead" : "以下是實驗性質的應用程式",
- "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "實驗性質的應用程式並沒有經過安全檢測,可能會是不穩定而且開發困難,安裝他們可能會造成資料遺失或是安全問題。",
- "by" : "由",
- "licensed" : "許可證",
- "Documentation:" : "文件:",
+ "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "實驗性質的應用程式並沒有經過安全檢測,可能會不穩定而且正在開發中,安裝他們可能會造成資料遺失或是安全問題",
+ "Documentation:" : "說明文件:",
"User documentation" : "用戶說明文件",
"Admin documentation" : "管理者文件",
"Show description …" : "顯示描述",
"Hide description …" : "隱藏描述",
- "This app cannot be installed because the following dependencies are not fulfilled:" : "這個應用程式無法備被安裝,下列的相依性並不是完整的:",
- "Enable only for specific groups" : "僅對特定的群組開啟",
- "Uninstall App" : "刪除 App",
- "Enable experimental apps" : "啟用測試中的應用程式",
+ "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "此應用程式沒有指定支援的最小 ownCloud 版本,從 ownCloud 11 之後這會是個錯誤",
+ "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "此應用程式沒有指定支援的最大 ownCloud 版本,從 ownCloud 11 之後這會是個錯誤",
+ "This app cannot be installed because the following dependencies are not fulfilled:" : "這個應用程式無法被安裝,因為欠缺下列相依套件:",
+ "Enable only for specific groups" : "僅對特定的群組啟用",
+ "Uninstall App" : "解除安裝 App",
+ "Enable experimental apps" : "啟用實驗性質的應用程式",
+ "Common Name" : "Common Name",
+ "Valid until" : "到期日",
+ "Issued By" : "發行者:",
+ "Valid until %s" : "有效至 %s",
+ "Import root certificate" : "匯入根憑證",
"Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href=\"%s\">%s</a><br><br>" : "嗨,<br><br>通知您一聲,您現在有了 %s 的帳號。<br><br>您的帳號: %s<br>開通帳號: <a href=\"%s\">%s</a><br><br>",
"Cheers!" : "太棒了!",
"Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n" : "嗨,\n\n通知您一聲,您現在有了 %s 的帳號。\n\n您的帳號:%s\n開通帳號:%s\n\n",
@@ -221,40 +226,36 @@
"Forum" : "論壇",
"Issue tracker" : "問題追蹤",
"Commercial support" : "商用支援",
- "Get the apps to sync your files" : "下載應用程式來同步您的檔案",
- "Desktop client" : "桌面客戶端",
- "Android app" : "Android 應用程式",
- "iOS app" : "iOS 應用程式",
- "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "若您想支援這個計畫\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">加入開發者</a>\n\t\t或\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">替我們宣傳</a>!",
- "Show First Run Wizard again" : "再次顯示首次使用精靈",
- "You have used <strong>%s</strong> of the available <strong>%s</strong>" : "您已經使用了 <strong>%s</strong> ,目前可用空間為 <strong>%s</strong>",
+ "You are using <strong>%s</strong> of <strong>%s</strong>" : "您正在使用 <strong>%s</strong> 的 <strong>%s</strong>",
+ "Profile picture" : "大頭照",
+ "Upload new" : "上傳新的",
+ "Select from Files" : "從檔案應用程式選擇",
+ "Remove image" : "移除圖片",
+ "png or jpg, max. 20 MB" : "png 或 jpg ,最大 20 MB",
+ "Picture provided by original account" : "原本的帳戶提供的圖片",
+ "Cancel" : "取消",
+ "Choose as profile picture" : "選為大頭照",
+ "Full name" : "全名",
+ "No display name set" : "未設定顯示名稱",
+ "Email" : "信箱",
+ "Your email address" : "您的電子郵件信箱",
+ "For password recovery and notifications" : "用於密碼重設和通知",
+ "No email address set" : "未設定電子郵件信箱",
+ "You are member of the following groups:" : "您的帳號屬於這些群組:",
"Password" : "密碼",
"Unable to change your password" : "無法變更您的密碼",
"Current password" : "目前密碼",
"New password" : "新密碼",
"Change password" : "變更密碼",
- "Full name" : "全名",
- "No display name set" : "未設置顯示名稱",
- "Email" : "信箱",
- "Your email address" : "您的電子郵件信箱",
- "Fill in an email address to enable password recovery and receive notifications" : "填入電子郵件地址來啟用忘記密碼和接收通知的功能",
- "No email address set" : "未設置電子郵件信箱",
- "You are member of the following groups:" : "您的會員帳號歸類在以下群組:",
- "Profile picture" : "個人資料照片",
- "Upload new" : "上傳新的",
- "Select new from Files" : "從已上傳的檔案中選一個",
- "Remove image" : "移除圖片",
- "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "可以使用 png 或 jpg 格式,最好是方形的,但是您之後也可以裁剪它。圖片容量最大請勿超過 20 MB。",
- "Your avatar is provided by your original account." : "您的圖像是由您原來的帳號所提供的。",
- "Cancel" : "取消",
- "Choose as profile image" : "設定為大頭貼",
"Language" : "語言",
"Help translate" : "幫助翻譯",
- "Common Name" : "Common Name",
- "Valid until" : "前有效",
- "Issued By" : "發行者:",
- "Valid until %s" : "有效至 %s",
- "Import root certificate" : "匯入root憑證",
+ "Get the apps to sync your files" : "下載應用程式來同步您的檔案",
+ "Desktop client" : "桌面客戶端",
+ "Android app" : "Android 應用程式",
+ "iOS app" : "iOS 應用程式",
+ "If you want to support the project\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">join development</a>\n\t\tor\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">spread the word</a>!" : "若您想支援這個計畫\n\t\t<a href=\"https://owncloud.org/contribute\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">加入開發者</a>\n\t\t或\n\t\t<a href=\"https://owncloud.org/promote\"\n\t\t\ttarget=\"_blank\" rel=\"noreferrer\">替我們宣傳</a>!",
+ "Show First Run Wizard again" : "再次顯示首次使用精靈",
+ "Developed by the {communityopen}ownCloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose}." : "由 {communityopen}ownCloud 社群{linkclose} 開發,{githubopen}原始碼{linkclose}使用 {licenseopen}<abbr title=\"Affero General Public License\">AGPL</abbr>{linkclose} 授權釋出",
"Show storage location" : "顯示儲存位置",
"Show last log in" : "顯示最近登入",
"Show user backend" : "顯示用戶後台",
@@ -270,13 +271,14 @@
"Everyone" : "所有人",
"Admins" : "管理者",
"Default Quota" : "預設容量限制",
- "Please enter storage quota (ex: \"512 MB\" or \"12 GB\")" : "請輸入空間配額(例如: \"512 MB\"或是 \"12 GB\")",
+ "Please enter storage quota (ex: \"512 MB\" or \"12 GB\")" : "請輸入空間配額(例如 \"512 MB\" 或是 \"12 GB\")",
"Unlimited" : "無限制",
"Other" : "其他",
"Full Name" : "全名",
+ "Group Admin for" : "指定群組管理者",
"Quota" : "容量限制",
"Storage Location" : "儲存位置",
- "User Backend" : "用戶後台",
+ "User Backend" : "用戶後端",
"Last Login" : "上次登入",
"change full name" : "變更全名",
"set new password" : "設定新密碼",
diff --git a/settings/languageCodes.php b/settings/languageCodes.php
index 8c58079c2cb..f83123df672 100644
--- a/settings/languageCodes.php
+++ b/settings/languageCodes.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/middleware/subadminmiddleware.php b/settings/middleware/subadminmiddleware.php
index 78dabada3e2..00f221721a6 100644
--- a/settings/middleware/subadminmiddleware.php
+++ b/settings/middleware/subadminmiddleware.php
@@ -3,7 +3,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
diff --git a/settings/personal.php b/settings/personal.php
index bf1e1ad8793..d2d4fc90f5e 100644
--- a/settings/personal.php
+++ b/settings/personal.php
@@ -17,7 +17,7 @@
* @author Vincent Petry <pvince81@owncloud.com>
* @author Volkan Gezer <volkangezer@gmail.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -43,6 +43,7 @@ $urlGenerator = \OC::$server->getURLGenerator();
// Highlight navigation entry
OC_Util::addScript( 'settings', 'personal' );
+OC_Util::addScript('settings', 'certificates');
OC_Util::addStyle( 'settings', 'settings' );
\OC_Util::addVendorScript('strengthify/jquery.strengthify');
\OC_Util::addVendorStyle('strengthify/strengthify');
@@ -54,23 +55,24 @@ if ($config->getSystemValue('enable_avatars', true) === true) {
}
// Highlight navigation entry
-OC_App::setActiveNavigationEntry( 'personal' );
+OC::$server->getNavigationManager()->setActiveEntry('personal');
$storageInfo=OC_Helper::getStorageInfo('/');
-$email=$config->getUserValue(OC_User::getUser(), 'settings', 'email', '');
+$user = OC::$server->getUserManager()->get(OC_User::getUser());
+$email = $user->getEMailAddress();
$userLang=$config->getUserValue( OC_User::getUser(), 'core', 'lang', OC_L10N::findLanguage() );
-$languageCodes=OC_L10N::findAvailableLanguages();
+$languageCodes = \OC::$server->getL10NFactory()->findAvailableLanguages();
// array of common languages
-$commonlangcodes = array(
+$commonLangCodes = array(
'en', 'es', 'fr', 'de', 'de_DE', 'ja', 'ar', 'ru', 'nl', 'it', 'pt_BR', 'pt_PT', 'da', 'fi_FI', 'nb_NO', 'sv', 'tr', 'zh_CN', 'ko'
);
$languageNames=include 'languageCodes.php';
$languages=array();
-$commonlanguages = array();
+$commonLanguages = array();
foreach($languageCodes as $lang) {
$l = \OC::$server->getL10N('settings', $lang);
// TRANSLATORS this is the language name for the language switcher in the personal settings and should be the localized version
@@ -82,12 +84,12 @@ foreach($languageCodes as $lang) {
$ln=array('code'=>$lang, 'name'=>$lang);
}
- // put apropriate languages into apropriate arrays, to print them sorted
+ // put appropriate languages into appropriate arrays, to print them sorted
// used language -> common languages -> divider -> other languages
if ($lang === $userLang) {
$userLang = $ln;
- } elseif (in_array($lang, $commonlangcodes)) {
- $commonlanguages[array_search($lang, $commonlangcodes)]=$ln;
+ } elseif (in_array($lang, $commonLangCodes)) {
+ $commonLanguages[array_search($lang, $commonLangCodes)]=$ln;
} else {
$languages[]=$ln;
}
@@ -101,7 +103,7 @@ if (!is_array($userLang)) {
];
}
-ksort($commonlanguages);
+ksort($commonLanguages);
// sort now by displayed language not the iso-code
usort( $languages, function ($a, $b) {
@@ -142,12 +144,12 @@ $tmpl->assign('usage_relative', $storageInfo['relative']);
$tmpl->assign('clients', $clients);
$tmpl->assign('email', $email);
$tmpl->assign('languages', $languages);
-$tmpl->assign('commonlanguages', $commonlanguages);
+$tmpl->assign('commonlanguages', $commonLanguages);
$tmpl->assign('activelanguage', $userLang);
$tmpl->assign('passwordChangeSupported', OC_User::canUserChangePassword(OC_User::getUser()));
$tmpl->assign('displayNameChangeSupported', OC_User::canUserChangeDisplayName(OC_User::getUser()));
$tmpl->assign('displayName', OC_User::getDisplayName());
-$tmpl->assign('enableAvatars', $config->getSystemValue('enable_avatars', true));
+$tmpl->assign('enableAvatars', $config->getSystemValue('enable_avatars', true) === true);
$tmpl->assign('avatarChangeSupported', OC_User::canUserChangeAvatar(OC_User::getUser()));
$tmpl->assign('certs', $certificateManager->listCertificates());
$tmpl->assign('showCertificates', $enableCertImport);
@@ -162,11 +164,22 @@ $tmpl->assign('groups', $groups2);
// add hardcoded forms from the template
$l = \OC::$server->getL10N('settings');
$formsAndMore = [];
+$formsAndMore[]= ['anchor' => 'avatar', 'section-name' => $l->t('Personal info')];
$formsAndMore[]= ['anchor' => 'clientsbox', 'section-name' => $l->t('Sync clients')];
-$formsAndMore[]= ['anchor' => 'passwordform', 'section-name' => $l->t('Personal info')];
$forms=OC_App::getForms('personal');
+
+// add bottom hardcoded forms from the template
+if ($enableCertImport) {
+ $certificatesTemplate = new OC_Template('settings', 'certificates');
+ $certificatesTemplate->assign('type', 'personal');
+ $certificatesTemplate->assign('uploadRoute', 'settings.Certificate.addPersonalRootCertificate');
+ $certificatesTemplate->assign('certs', $certificateManager->listCertificates());
+ $certificatesTemplate->assign('urlGenerator', $urlGenerator);
+ $forms[] = $certificatesTemplate->fetchPage();
+}
+
$formsMap = array_map(function($form){
if (preg_match('%(<h2(?P<class>[^>]*)>.*?</h2>)%i', $form, $regs)) {
$sectionName = str_replace('<h2'.$regs['class'].'>', '', $regs[0]);
@@ -175,7 +188,7 @@ $formsMap = array_map(function($form){
$anchor = str_replace(' ', '-', $anchor);
return array(
- 'anchor' => 'goto-' . $anchor,
+ 'anchor' => $anchor,
'section-name' => $sectionName,
'form' => $form
);
@@ -187,12 +200,5 @@ $formsMap = array_map(function($form){
$formsAndMore = array_merge($formsAndMore, $formsMap);
-// add bottom hardcoded forms from the template
-if($enableCertImport) {
- $formsAndMore[]= array( 'anchor' => 'ssl-root-certificates', 'section-name' => $l->t('SSL root certificates') );
-}
-
-
-
$tmpl->assign('forms', $formsAndMore);
$tmpl->printPage();
diff --git a/settings/routes.php b/settings/routes.php
index 6ba38388d3a..8828e621145 100644
--- a/settings/routes.php
+++ b/settings/routes.php
@@ -3,15 +3,16 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <schiessle@owncloud.com>
* @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Clark Tomlinson <fallen013@gmail.com>
* @author Frank Karlitschek <frank@owncloud.org>
* @author Georg Ehrke <georg@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Raghu Nayyar <me@iraghu.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -46,14 +47,19 @@ $application->registerRoutes($this, [
['name' => 'AppSettings#listApps', 'url' => '/settings/apps/list', 'verb' => 'GET'],
['name' => 'AppSettings#changeExperimentalConfigState', 'url' => '/settings/apps/experimental', 'verb' => 'POST'],
['name' => 'SecuritySettings#trustedDomains', 'url' => '/settings/admin/security/trustedDomains', 'verb' => 'POST'],
+ ['name' => 'Users#setDisplayName', 'url' => '/settings/users/{username}/displayName', 'verb' => 'POST'],
['name' => 'Users#setMailAddress', 'url' => '/settings/users/{id}/mailAddress', 'verb' => 'PUT'],
['name' => 'Users#stats', 'url' => '/settings/users/stats', 'verb' => 'GET'],
['name' => 'LogSettings#setLogLevel', 'url' => '/settings/admin/log/level', 'verb' => 'POST'],
['name' => 'LogSettings#getEntries', 'url' => '/settings/admin/log/entries', 'verb' => 'GET'],
['name' => 'LogSettings#download', 'url' => '/settings/admin/log/download', 'verb' => 'GET'],
['name' => 'CheckSetup#check', 'url' => '/settings/ajax/checksetup', 'verb' => 'GET'],
+ ['name' => 'CheckSetup#getFailedIntegrityCheckFiles', 'url' => '/settings/integrity/failed', 'verb' => 'GET'],
+ ['name' => 'CheckSetup#rescanFailedIntegrityCheck', 'url' => '/settings/integrity/rescan', 'verb' => 'GET'],
['name' => 'Certificate#addPersonalRootCertificate', 'url' => '/settings/personal/certificate', 'verb' => 'POST'],
['name' => 'Certificate#removePersonalRootCertificate', 'url' => '/settings/personal/certificate/{certificateIdentifier}', 'verb' => 'DELETE'],
+ ['name' => 'Certificate#addSystemRootCertificate', 'url' => '/settings/admin/certificate', 'verb' => 'POST'],
+ ['name' => 'Certificate#removeSystemRootCertificate', 'url' => '/settings/admin/certificate/{certificateIdentifier}', 'verb' => 'DELETE'],
]
]);
@@ -79,8 +85,6 @@ $this->create('settings_ajax_togglesubadmins', '/settings/ajax/togglesubadmins.p
$this->create('settings_users_changepassword', '/settings/users/changepassword')
->post()
->action('OC\Settings\ChangePassword\Controller', 'changeUserPassword');
-$this->create('settings_ajax_changedisplayname', '/settings/ajax/changedisplayname.php')
- ->actionInclude('settings/ajax/changedisplayname.php');
$this->create('settings_ajax_changegorupname', '/settings/ajax/changegroupname.php')
->actionInclude('settings/ajax/changegroupname.php');
// personal
diff --git a/settings/templates/admin.php b/settings/templates/admin.php
index 27785c26dfe..539e4b94b8b 100644
--- a/settings/templates/admin.php
+++ b/settings/templates/admin.php
@@ -56,7 +56,7 @@ if ($_['mail_smtpmode'] == 'qmail') {
if (isset($form['anchor'])) {
$anchor = '#' . $form['anchor'];
$sectionName = $form['section-name'];
- print_unescaped(sprintf("<li><a href='%s'>%s</a></li>", OC_Util::sanitizeHTML($anchor), OC_Util::sanitizeHTML($sectionName)));
+ print_unescaped(sprintf("<li><a href='%s'>%s</a></li>", \OCP\Util::sanitizeHTML($anchor), \OCP\Util::sanitizeHTML($sectionName)));
}
}?>
</ul>
@@ -177,17 +177,11 @@ if ($_['cronErrors']) {
?>
</ul>
-<div id="postsetupchecks">
+<div id="postsetupchecks" data-check-wellknown="<?php if($_['checkForWorkingWellKnownSetup']) { p('true'); } else { p('false'); } ?>">
<div class="loading"></div>
<ul class="errors hidden"></ul>
<ul class="warnings hidden"></ul>
- <ul class="info hidden">
- <?php if ($_['fileLockingType'] === 'db'):?>
- <li>
- <?php print_unescaped($l->t('Transactional file locking is using the database as locking backend, for best performance it\'s advised to configure a memcache for locking. See the <a target="_blank" href="%s">documentation ↗</a> for more information.', link_to_docs('admin-transactional-locking'))); ?>
- </li>
- <?php endif; ?>
- </ul>
+ <ul class="info hidden"></ul>
<p class="hint hidden">
<?php print_unescaped($l->t('Please double check the <a target="_blank" href="%s">installation guides ↗</a>, and check for any errors or warnings in the <a href="#log-section">log</a>.', link_to_docs('admin-install'))); ?>
</p>
@@ -290,18 +284,18 @@ if ($_['cronErrors']) {
$relative_time = relative_modified_date($_['lastcron']);
$absolute_time = OC_Util::formatDate($_['lastcron']);
if (time() - $_['lastcron'] <= 3600): ?>
- <span class="cronstatus success"></span>
+ <span class="status success"></span>
<span class="crondate" original-title="<?php p($absolute_time);?>">
<?php p($l->t("Last cron job execution: %s.", [$relative_time]));?>
</span>
<?php else: ?>
- <span class="cronstatus error"></span>
+ <span class="status error"></span>
<span class="crondate" original-title="<?php p($absolute_time);?>">
<?php p($l->t("Last cron job execution: %s. Something seems wrong.", [$relative_time]));?>
</span>
<?php endif;
else: ?>
- <span class="cronstatus error"></span>
+ <span class="status error"></span>
<?php p($l->t("Cron was not executed yet!"));
endif; ?>
</p>
@@ -491,15 +485,6 @@ if ($_['cronErrors']) {
<div class="section" id="log-section">
<h2><?php p($l->t('Log'));?></h2>
- <?php p($l->t('Log level'));?> <select name='loglevel' id='loglevel'>
-<?php for ($i = 0; $i < 5; $i++):
- $selected = '';
- if ($i == $_['loglevel']):
- $selected = 'selected="selected"';
- endif; ?>
- <option value='<?php p($i)?>' <?php p($selected) ?>><?php p($levelLabels[$i])?></option>
-<?php endfor;?>
-</select>
<?php if ($_['showLog'] && $_['doesLogFileExist']): ?>
<table id="log" class="grid">
<?php foreach ($_['entries'] as $entry): ?>
@@ -537,6 +522,16 @@ if ($_['cronErrors']) {
</em>
<?php endif; ?>
<?php endif; ?>
+
+ <p><?php p($l->t('What to log'));?> <select name='loglevel' id='loglevel'>
+ <?php for ($i = 0; $i < 5; $i++):
+ $selected = '';
+ if ($i == $_['loglevel']):
+ $selected = 'selected="selected"';
+ endif; ?>
+ <option value='<?php p($i)?>' <?php p($selected) ?>><?php p($levelLabels[$i])?></option>
+ <?php endfor;?>
+ </select></p>
</div>
<div class="section" id="admin-tips">
@@ -567,11 +562,11 @@ if ($_['cronErrors']) {
<div class="section">
<h2><?php p($l->t('Version'));?></h2>
- <strong><?php p($theme->getTitle()); ?></strong> <?php p(OC_Util::getHumanVersion()) ?>
- <?php include('settings.development.notice.php'); ?>
+ <p><a href="<?php print_unescaped($theme->getBaseUrl()); ?>" target="_blank"><?php p($theme->getTitle()); ?></a> <?php p(OC_Util::getHumanVersion()) ?></p>
+ <p><?php include('settings.development.notice.php'); ?></p>
</div>
-<div class="section credits-footer">
- <p><?php print_unescaped($theme->getShortFooter()); ?></p>
-</div>
+
+
+
</div>
diff --git a/settings/templates/apps.php b/settings/templates/apps.php
index 3168fd8beeb..489062d5191 100644
--- a/settings/templates/apps.php
+++ b/settings/templates/apps.php
@@ -29,7 +29,7 @@ script(
</li>
{{/each}}
-<?php if(OC_Config::getValue('appstoreenabled', true) === true): ?>
+<?php if($_['appstoreEnabled']): ?>
<li>
<a class="app-external" target="_blank" href="https://owncloud.org/dev"><?php p($l->t('Developer documentation'));?> ↗</a>
</li>
@@ -60,9 +60,9 @@ script(
</h2>
<div class="app-version"> {{version}}</div>
{{#if profilepage}}<a href="{{profilepage}}" target="_blank" rel="noreferrer">{{/if}}
- <div class="app-author"><?php p($l->t('by')); ?> {{author}}
+ <div class="app-author"><?php p($l->t('by %s', ['{{author}}']));?>
{{#if licence}}
- ({{licence}}-<?php p($l->t('licensed')); ?>)
+ (<?php p($l->t('%s-licensed', ['{{licence}}'])); ?>)
{{/if}}
</div>
{{#if profilepage}}</a>{{/if}}
@@ -97,6 +97,18 @@ script(
<div class="app-description-toggle-show"><?php p($l->t("Show description …"));?></div>
<div class="app-description-toggle-hide hidden"><?php p($l->t("Hide description …"));?></div>
+ {{#if missingMinOwnCloudVersion}}
+ <div class="app-dependencies">
+ <p><?php p($l->t('This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later.')); ?></p>
+ </div>
+ {{else}}
+ {{#if missingMaxOwnCloudVersion}}
+ <div class="app-dependencies">
+ <p><?php p($l->t('This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later.')); ?></p>
+ </div>
+ {{/if}}
+ {{/if}}
+
{{#unless canInstall}}
<div class="app-dependencies">
<p><?php p($l->t('This app cannot be installed because the following dependencies are not fulfilled:')); ?></p>
diff --git a/settings/templates/certificates.php b/settings/templates/certificates.php
new file mode 100644
index 00000000000..c1ccdcaef95
--- /dev/null
+++ b/settings/templates/certificates.php
@@ -0,0 +1,44 @@
+<div class="section">
+ <h2><?php p($l->t('SSL Root Certificates')); ?></h2>
+ <table id="sslCertificate" class="grid" data-type="<?php p($_['type']); ?>">
+ <thead>
+ <tr>
+ <th><?php p($l->t('Common Name')); ?></th>
+ <th><?php p($l->t('Valid until')); ?></th>
+ <th><?php p($l->t('Issued By')); ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($_['certs'] as $rootCert): /**@var \OCP\ICertificate $rootCert */ ?>
+ <tr class="<?php echo ($rootCert->isExpired()) ? 'expired' : 'valid' ?>"
+ data-name="<?php p($rootCert->getName()) ?>">
+ <td class="rootCert"
+ title="<?php p($rootCert->getOrganization()) ?>">
+ <?php p($rootCert->getCommonName()) ?>
+ </td>
+ <td title="<?php p($l->t('Valid until %s', $l->l('date', $rootCert->getExpireDate()))) ?>">
+ <?php echo $l->l('date', $rootCert->getExpireDate()) ?>
+ </td>
+ <td title="<?php p($rootCert->getIssuerOrganization()) ?>">
+ <?php p($rootCert->getIssuerName()) ?>
+ </td>
+ <td <?php if ($rootCert != ''): ?>class="remove"
+ <?php else: ?>style="visibility:hidden;"
+ <?php endif; ?>><img alt="<?php p($l->t('Delete')); ?>"
+ title="<?php p($l->t('Delete')); ?>"
+ class="svg action"
+ src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"/>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+ <form class="uploadButton" method="post"
+ action="<?php p($_['urlGenerator']->linkToRoute($_['uploadRoute'])); ?>"
+ target="certUploadFrame">
+ <label for="rootcert_import" class="inlineblock button"
+ id="rootcert_import_button"><?php p($l->t('Import root certificate')); ?></label>
+ <input type="file" id="rootcert_import" name="rootcert_import"
+ class="hiddenuploadfield">
+ </form>
+</div>
diff --git a/settings/templates/email.new_user.php b/settings/templates/email.new_user.php
index 74149632cb8..8b13ac753eb 100644
--- a/settings/templates/email.new_user.php
+++ b/settings/templates/email.new_user.php
@@ -4,7 +4,7 @@
<tr>
<td bgcolor="<?php p($theme->getMailHeaderColor());?>" width="20px">&nbsp;</td>
<td bgcolor="<?php p($theme->getMailHeaderColor());?>">
- <img src="<?php p(OC_Helper::makeURLAbsolute(image_path('', 'logo-mail.gif'))); ?>" alt="<?php p($theme->getName()); ?>"/>
+ <img src="<?php p(\OC::$server->getURLGenerator()->getAbsoluteURL(image_path('', 'logo-mail.gif'))); ?>" alt="<?php p($theme->getName()); ?>"/>
</td>
</tr>
<tr><td colspan="2">&nbsp;</td></tr>
diff --git a/settings/templates/personal.php b/settings/templates/personal.php
index 0eba71d77d1..b00a5c5dd8a 100644
--- a/settings/templates/personal.php
+++ b/settings/templates/personal.php
@@ -4,8 +4,8 @@
* See the COPYING-README file.
*/
-/** @var $_ array */
-/** @var $_['urlGenerator'] */
+/** @var $_ mixed[]|\OCP\IURLGenerator[] */
+/** @var \OC_Defaults $theme */
?>
<div id="app-navigation">
@@ -14,7 +14,7 @@
if (isset($form['anchor'])) {
$anchor = '#' . $form['anchor'];
$sectionName = $form['section-name'];
- print_unescaped(sprintf("<li><a href='%s'>%s</a></li>", OC_Util::sanitizeHTML($anchor), OC_Util::sanitizeHTML($sectionName)));
+ print_unescaped(sprintf("<li><a href='%s'>%s</a></li>", \OCP\Util::sanitizeHTML($anchor), \OCP\Util::sanitizeHTML($sectionName)));
}
}?>
</ul>
@@ -22,75 +22,39 @@
<div id="app-content">
-<div id="clientsbox" class="clientsbox center">
- <h2><?php p($l->t('Get the apps to sync your files'));?></h2>
- <a href="<?php p($_['clients']['desktop']); ?>" target="_blank">
- <img src="<?php print_unescaped(OCP\Util::imagePath('core', 'desktopapp.png')); ?>"
- alt="<?php p($l->t('Desktop client'));?>" />
- </a>
- <a href="<?php p($_['clients']['android']); ?>" target="_blank">
- <img src="<?php print_unescaped(OCP\Util::imagePath('core', 'googleplay.png')); ?>"
- alt="<?php p($l->t('Android app'));?>" />
- </a>
- <a href="<?php p($_['clients']['ios']); ?>" target="_blank">
- <img src="<?php print_unescaped(OCP\Util::imagePath('core', 'appstore.png')); ?>"
- alt="<?php p($l->t('iOS app'));?>" />
- </a>
-
- <?php if (OC_Util::getEditionString() === ''): ?>
- <p class="center">
- <?php print_unescaped($l->t('If you want to support the project
- <a href="https://owncloud.org/contribute"
- target="_blank" rel="noreferrer">join development</a>
- or
- <a href="https://owncloud.org/promote"
- target="_blank" rel="noreferrer">spread the word</a>!'));?>
- </p>
- <?php endif; ?>
-
- <?php if(OC_APP::isEnabled('firstrunwizard')) {?>
- <p class="center"><a class="button" href="#" id="showWizard"><?php p($l->t('Show First Run Wizard again'));?></a></p>
- <?php }?>
-</div>
-
-
<div id="quota" class="section">
<div style="width:<?php p($_['usage_relative']);?>%"
<?php if($_['usage_relative'] > 80): ?> class="quota-warning" <?php endif; ?>>
<p id="quotatext">
- <?php print_unescaped($l->t('You have used <strong>%s</strong> of the available <strong>%s</strong>',
+ <?php print_unescaped($l->t('You are using <strong>%s</strong> of <strong>%s</strong>',
array($_['usage'], $_['total_space'])));?>
</p>
</div>
</div>
+<?php if ($_['enableAvatars']): ?>
+<form id="avatar" class="section" method="post" action="<?php p(\OC::$server->getURLGenerator()->linkToRoute('core.avatar.postAvatar')); ?>">
+ <h2><?php p($l->t('Profile picture')); ?></h2>
+ <div id="displayavatar">
+ <div class="avatardiv"></div>
+ <div class="warning hidden"></div>
+ <?php if ($_['avatarChangeSupported']): ?>
+ <label for="uploadavatar" class="inlineblock button icon-upload svg" id="uploadavatarbutton" title="<?php p($l->t('Upload new')); ?>"></label>
+ <div class="inlineblock button icon-folder svg" id="selectavatar" title="<?php p($l->t('Select from Files')); ?>"></div>
+ <div class="hidden button icon-delete svg" id="removeavatar" title="<?php p($l->t('Remove image')); ?>"></div>
+ <input type="file" name="files[]" id="uploadavatar" class="hiddenuploadfield">
+ <p><em><?php p($l->t('png or jpg, max. 20 MB')); ?></em></p>
+ <?php else: ?>
+ <?php p($l->t('Picture provided by original account')); ?>
+ <?php endif; ?>
+ </div>
-<?php
-if($_['passwordChangeSupported']) {
- script('jquery-showpassword');
-?>
-<form id="passwordform" class="section">
- <h2 class="inlineblock"><?php p($l->t('Password'));?></h2>
- <div class="hidden icon-checkmark" id="password-changed"></div>
- <div class="hidden" id="password-error"><?php p($l->t('Unable to change your password'));?></div>
- <br>
- <label for="pass1" class="onlyInIE8"><?php echo $l->t('Current password');?>: </label>
- <input type="password" id="pass1" name="oldpassword"
- placeholder="<?php echo $l->t('Current password');?>"
- autocomplete="off" autocapitalize="off" autocorrect="off" />
- <label for="pass2" class="onlyInIE8"><?php echo $l->t('New password');?>: </label>
- <input type="password" id="pass2" name="personal-password"
- placeholder="<?php echo $l->t('New password');?>"
- data-typetoggle="#personal-show"
- autocomplete="off" autocapitalize="off" autocorrect="off" />
- <input type="checkbox" id="personal-show" name="show" /><label for="personal-show" class="svg"></label>
- <input id="passwordbutton" type="submit" value="<?php echo $l->t('Change password');?>" />
- <br/>
- <div class="strengthify-wrapper"></div>
+ <div id="cropper" class="hidden">
+ <div class="inlineblock button" id="abortcropperbutton"><?php p($l->t('Cancel')); ?></div>
+ <div class="inlineblock button primary" id="sendcropperbutton"><?php p($l->t('Choose as profile picture')); ?></div>
+ </div>
</form>
-<?php
-}
-?>
+<?php endif; ?>
<?php
if($_['displayNameChangeSupported']) {
@@ -127,7 +91,7 @@ if($_['passwordChangeSupported']) {
placeholder="<?php p($l->t('Your email address'));?>"
autocomplete="on" autocapitalize="off" autocorrect="off" />
<span class="msg"></span><br />
- <em><?php p($l->t('Fill in an email address to enable password recovery and receive notifications'));?></em>
+ <em><?php p($l->t('For password recovery and notifications'));?></em>
</form>
<?php
} else {
@@ -148,29 +112,32 @@ if($_['passwordChangeSupported']) {
</p>
</div>
-<?php if ($_['enableAvatars']): ?>
-<form id="avatar" class="section" method="post" action="<?php p(\OC_Helper::linkToRoute('core.avatar.postAvatar')); ?>">
- <h2><?php p($l->t('Profile picture')); ?></h2>
- <div id="displayavatar">
- <div class="avatardiv"></div><br>
- <div class="warning hidden"></div>
- <?php if ($_['avatarChangeSupported']): ?>
- <label for="uploadavatar" class="inlineblock button" id="uploadavatarbutton"><?php p($l->t('Upload new')); ?></label>
- <div class="inlineblock button" id="selectavatar"><?php p($l->t('Select new from Files')); ?></div>
- <div class="inlineblock button" id="removeavatar"><?php p($l->t('Remove image')); ?></div>
- <input type="file" name="files[]" id="uploadavatar" class="hiddenuploadfield">
- <br>
- <?php p($l->t('Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB.')); ?>
- <?php else: ?>
- <?php p($l->t('Your avatar is provided by your original account.')); ?>
- <?php endif; ?>
- </div>
- <div id="cropper" class="hidden">
- <div class="inlineblock button" id="abortcropperbutton"><?php p($l->t('Cancel')); ?></div>
- <div class="inlineblock button primary" id="sendcropperbutton"><?php p($l->t('Choose as profile image')); ?></div>
- </div>
+<?php
+if($_['passwordChangeSupported']) {
+ script('jquery-showpassword');
+?>
+<form id="passwordform" class="section">
+ <h2 class="inlineblock"><?php p($l->t('Password'));?></h2>
+ <div class="hidden icon-checkmark" id="password-changed"></div>
+ <div class="hidden" id="password-error"><?php p($l->t('Unable to change your password'));?></div>
+ <br>
+ <label for="pass1" class="onlyInIE8"><?php echo $l->t('Current password');?>: </label>
+ <input type="password" id="pass1" name="oldpassword"
+ placeholder="<?php echo $l->t('Current password');?>"
+ autocomplete="off" autocapitalize="off" autocorrect="off" />
+ <label for="pass2" class="onlyInIE8"><?php echo $l->t('New password');?>: </label>
+ <input type="password" id="pass2" name="personal-password"
+ placeholder="<?php echo $l->t('New password');?>"
+ data-typetoggle="#personal-show"
+ autocomplete="off" autocapitalize="off" autocorrect="off" />
+ <input type="checkbox" id="personal-show" name="show" /><label for="personal-show" class="svg"></label>
+ <input id="passwordbutton" type="submit" value="<?php echo $l->t('Change password');?>" />
+ <br/>
+ <div class="strengthify-wrapper"></div>
</form>
-<?php endif; ?>
+<?php
+}
+?>
<form class="section">
<h2>
@@ -200,62 +167,47 @@ if($_['passwordChangeSupported']) {
<?php endif; ?>
</form>
+<div id="clientsbox" class="section clientsbox">
+ <h2><?php p($l->t('Get the apps to sync your files'));?></h2>
+ <a href="<?php p($_['clients']['desktop']); ?>" target="_blank">
+ <img src="<?php print_unescaped(OCP\Util::imagePath('core', 'desktopapp.png')); ?>"
+ alt="<?php p($l->t('Desktop client'));?>" />
+ </a>
+ <a href="<?php p($_['clients']['android']); ?>" target="_blank">
+ <img src="<?php print_unescaped(OCP\Util::imagePath('core', 'googleplay.png')); ?>"
+ alt="<?php p($l->t('Android app'));?>" />
+ </a>
+ <a href="<?php p($_['clients']['ios']); ?>" target="_blank">
+ <img src="<?php print_unescaped(OCP\Util::imagePath('core', 'appstore.png')); ?>"
+ alt="<?php p($l->t('iOS app'));?>" />
+ </a>
+
+ <?php if (OC_Util::getEditionString() === ''): ?>
+ <p>
+ <?php print_unescaped($l->t('If you want to support the project
+ <a href="https://owncloud.org/contribute"
+ target="_blank" rel="noreferrer">join development</a>
+ or
+ <a href="https://owncloud.org/promote"
+ target="_blank" rel="noreferrer">spread the word</a>!'));?>
+ </p>
+ <?php endif; ?>
+
+ <?php if(OC_APP::isEnabled('firstrunwizard')) {?>
+ <p><a class="button" href="#" id="showWizard"><?php p($l->t('Show First Run Wizard again'));?></a></p>
+ <?php }?>
+</div>
+
<?php foreach($_['forms'] as $form) {
if (isset($form['form'])) {?>
<div id="<?php isset($form['anchor']) ? p($form['anchor']) : p('');?>"><?php print_unescaped($form['form']);?></div>
<?php }
};?>
-<?php if($_['showCertificates']) : ?>
-<div id="ssl-root-certificates" class="section">
- <h2><?php p($l->t('SSL root certificates')); ?></h2>
- <table id="sslCertificate" class="grid">
- <thead>
- <th><?php p($l->t('Common Name')); ?></th>
- <th><?php p($l->t('Valid until')); ?></th>
- <th><?php p($l->t('Issued By')); ?></th>
- <th/>
- </thead>
- <tbody>
- <?php foreach ($_['certs'] as $rootCert): /**@var \OCP\ICertificate $rootCert*/ ?>
- <tr class="<?php echo ($rootCert->isExpired()) ? 'expired' : 'valid' ?>" data-name="<?php p($rootCert->getName()) ?>">
- <td class="rootCert" title="<?php p($rootCert->getOrganization())?>">
- <?php p($rootCert->getCommonName()) ?>
- </td>
- <td title="<?php p($l->t('Valid until %s', $l->l('date', $rootCert->getExpireDate()))) ?>">
- <?php echo $l->l('date', $rootCert->getExpireDate()) ?>
- </td>
- <td title="<?php p($rootCert->getIssuerOrganization()) ?>">
- <?php p($rootCert->getIssuerName()) ?>
- </td>
- <td <?php if ($rootCert != ''): ?>class="remove"
- <?php else: ?>style="visibility:hidden;"
- <?php endif; ?>><img alt="<?php p($l->t('Delete')); ?>"
- title="<?php p($l->t('Delete')); ?>"
- class="svg action"
- src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"/>
- </td>
- </tr>
- <?php endforeach; ?>
- </tbody>
- </table>
- <form class="uploadButton" method="post" action="<?php p($_['urlGenerator']->linkToRoute('settings.Certificate.addPersonalRootCertificate')); ?>" target="certUploadFrame">
- <label for="rootcert_import" class="inlineblock button" id="rootcert_import_button"><?php p($l->t('Import root certificate')); ?></label>
- <input type="file" id="rootcert_import" name="rootcert_import" class="hiddenuploadfield">
- </form>
-</div>
-<?php endif; ?>
-
<div class="section">
<h2><?php p($l->t('Version'));?></h2>
- <strong><?php p($theme->getTitle()); ?></strong> <?php p(OC_Util::getHumanVersion()) ?><br />
- <?php include('settings.development.notice.php'); ?>
+ <p><a href="<?php print_unescaped($theme->getBaseUrl()); ?>" target="_blank"><?php p($theme->getTitle()); ?></a> <?php p(OC_Util::getHumanVersion()) ?></p>
+ <p><?php include('settings.development.notice.php'); ?></p>
</div>
-<div class="section credits-footer">
- <p><?php print_unescaped($theme->getShortFooter()); ?></p>
-</div>
-
-
-
</div>
diff --git a/settings/users.php b/settings/users.php
index 2795032a161..0dff85c1ade 100644
--- a/settings/users.php
+++ b/settings/users.php
@@ -11,12 +11,12 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Stephan Peijnik <speijnik@anexia-it.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -35,9 +35,9 @@
OC_Util::checkSubAdminUser();
-OC_App::setActiveNavigationEntry( 'core_users' );
+\OC::$server->getNavigationManager()->setActiveEntry('core_users');
-$userManager = \OC_User::getManager();
+$userManager = \OC::$server->getUserManager();
$groupManager = \OC_Group::getManager();
// Set the sort option: SORT_USERCOUNT or SORT_GROUPNAME
@@ -103,6 +103,8 @@ $defaultQuota=$config->getAppValue('files', 'default_quota', 'none');
$defaultQuotaIsUserDefined=array_search($defaultQuota, $quotaPreset)===false
&& array_search($defaultQuota, array('none', 'default'))===false;
+\OC::$server->getEventDispatcher()->dispatch('OC\Settings\Users::loadAdditionalScripts');
+
$tmpl = new OC_Template("settings", "users/main", "user");
$tmpl->assign('groups', $groups);
$tmpl->assign('sortGroups', $sortGroupsBy);
@@ -114,7 +116,7 @@ $tmpl->assign('quota_preset', $quotaPreset);
$tmpl->assign('default_quota', $defaultQuota);
$tmpl->assign('defaultQuotaIsUserDefined', $defaultQuotaIsUserDefined);
$tmpl->assign('recoveryAdminEnabled', $recoveryAdminEnabled);
-$tmpl->assign('enableAvatars', \OC::$server->getConfig()->getSystemValue('enable_avatars', true));
+$tmpl->assign('enableAvatars', \OC::$server->getConfig()->getSystemValue('enable_avatars', true) === true);
$tmpl->assign('show_storage_location', $config->getAppValue('core', 'umgmt_show_storage_location', 'false'));
$tmpl->assign('show_last_login', $config->getAppValue('core', 'umgmt_show_last_login', 'false'));
diff --git a/status.php b/status.php
index f59dc16b6a2..86f1f68dde1 100644
--- a/status.php
+++ b/status.php
@@ -8,7 +8,7 @@
* @author Masaki Kawabata Neto <masaki.kawabata@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -36,7 +36,7 @@ try {
$values=array(
'installed'=>$installed,
'maintenance' => $maintenance,
- 'version'=>implode('.', OC_Util::getVersion()),
+ 'version'=>implode('.', \OCP\Util::getVersion()),
'versionstring'=>OC_Util::getVersionString(),
'edition'=>OC_Util::getEditionString());
if (OC::$CLI) {
diff --git a/tests/core/command/config/system/deleteconfigtest.php b/tests/core/command/config/system/deleteconfigtest.php
index aa1f93274c7..11bfb6ae7ad 100644
--- a/tests/core/command/config/system/deleteconfigtest.php
+++ b/tests/core/command/config/system/deleteconfigtest.php
@@ -50,32 +50,31 @@ class DeleteConfigTest extends TestCase {
$this->command = new DeleteConfig($systemConfig);
}
-
public function deleteData() {
return [
[
- 'name',
+ 'name1',
true,
true,
0,
'info',
],
[
- 'name',
+ 'name2',
true,
false,
0,
'info',
],
[
- 'name',
+ 'name3',
false,
false,
0,
'info',
],
[
- 'name',
+ 'name4',
false,
true,
1,
@@ -105,7 +104,7 @@ class DeleteConfigTest extends TestCase {
$this->consoleInput->expects($this->once())
->method('getArgument')
->with('name')
- ->willReturn($configName);
+ ->willReturn([$configName]);
$this->consoleInput->expects($this->any())
->method('hasParameterOption')
->with('--error-if-not-exists')
@@ -117,4 +116,103 @@ class DeleteConfigTest extends TestCase {
$this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]));
}
+
+ public function deleteArrayData() {
+ return [
+ [
+ ['name', 'sub'],
+ true,
+ false,
+ true,
+ true,
+ 0,
+ 'info',
+ ],
+ [
+ ['name', 'sub', '2sub'],
+ true,
+ false,
+ ['sub' => ['2sub' => 1], 'sub2' => false],
+ ['sub' => [], 'sub2' => false],
+ 0,
+ 'info',
+ ],
+ [
+ ['name', 'sub3'],
+ true,
+ false,
+ ['sub' => ['2sub' => 1], 'sub2' => false],
+ ['sub' => ['2sub' => 1], 'sub2' => false],
+ 0,
+ 'info',
+ ],
+ [
+ ['name', 'sub'],
+ false,
+ true,
+ true,
+ true,
+ 1,
+ 'error',
+ ],
+ [
+ ['name', 'sub'],
+ true,
+ true,
+ true,
+ true,
+ 1,
+ 'error',
+ ],
+ [
+ ['name', 'sub3'],
+ true,
+ true,
+ ['sub' => ['2sub' => 1], 'sub2' => false],
+ ['sub' => ['2sub' => 1], 'sub2' => false],
+ 1,
+ 'error',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider deleteArrayData
+ *
+ * @param string[] $configNames
+ * @param bool $configKeyExists
+ * @param bool $checkIfKeyExists
+ * @param mixed $configValue
+ * @param mixed $updateValue
+ * @param int $expectedReturn
+ * @param string $expectedMessage
+ */
+ public function testArrayDelete(array $configNames, $configKeyExists, $checkIfKeyExists, $configValue, $updateValue, $expectedReturn, $expectedMessage) {
+ $this->systemConfig->expects(($checkIfKeyExists) ? $this->once() : $this->never())
+ ->method('getKeys')
+ ->willReturn($configKeyExists ? [$configNames[0]] : []);
+
+ $this->systemConfig->expects(($configKeyExists) ? $this->once() : $this->never())
+ ->method('getValue')
+ ->willReturn($configValue);
+
+ $this->systemConfig->expects(($expectedReturn === 0) ? $this->once() : $this->never())
+ ->method('setValue')
+ ->with($configNames[0], $updateValue);
+
+ $this->consoleInput->expects($this->once())
+ ->method('getArgument')
+ ->with('name')
+ ->willReturn($configNames);
+ $this->consoleInput->expects($this->any())
+ ->method('hasParameterOption')
+ ->with('--error-if-not-exists')
+ ->willReturn($checkIfKeyExists);
+
+ $this->consoleOutput->expects($this->any())
+ ->method('writeln')
+ ->with($this->stringContains($expectedMessage));
+
+ $this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]));
+ }
}
diff --git a/tests/core/command/config/system/getconfigtest.php b/tests/core/command/config/system/getconfigtest.php
index 54dcdd434ab..ebbea634cde 100644
--- a/tests/core/command/config/system/getconfigtest.php
+++ b/tests/core/command/config/system/getconfigtest.php
@@ -90,13 +90,19 @@ class GetConfigTest extends TestCase {
['name', ['a' => 1, 'b' => 2], true, null, false, 'json', 0, json_encode(['a' => 1, 'b' => 2])],
['name', ['a' => 1, 'b' => 2], true, null, false, 'plain', 0, "a: 1\nb: 2"],
+ // Nested depth
+ [['name', 'a'], ['a' => 1, 'b' => 2], true, null, false, 'json', 0, json_encode(1)],
+ [['name', 'a'], ['a' => 1, 'b' => 2], true, null, false, 'plain', 0, '1'],
+ [['name', 'c'], ['a' => 1, 'b' => 2], true, true, true, 'json', 0, json_encode(true)],
+ [['name', 'c'], ['a' => 1, 'b' => 2], true, true, false, 'json', 1, null],
+
];
}
/**
* @dataProvider getData
*
- * @param string $configName
+ * @param string[] $configNames
* @param mixed $value
* @param bool $configExists
* @param mixed $defaultValue
@@ -105,7 +111,13 @@ class GetConfigTest extends TestCase {
* @param int $expectedReturn
* @param string $expectedMessage
*/
- public function testGet($configName, $value, $configExists, $defaultValue, $hasDefault, $outputFormat, $expectedReturn, $expectedMessage) {
+ public function testGet($configNames, $value, $configExists, $defaultValue, $hasDefault, $outputFormat, $expectedReturn, $expectedMessage) {
+ if (is_array($configNames)) {
+ $configName = $configNames[0];
+ } else {
+ $configName = $configNames;
+ $configNames = [$configName];
+ }
$this->systemConfig->expects($this->atLeastOnce())
->method('getKeys')
->willReturn($configExists ? [$configName] : []);
@@ -122,7 +134,7 @@ class GetConfigTest extends TestCase {
$this->consoleInput->expects($this->once())
->method('getArgument')
->with('name')
- ->willReturn($configName);
+ ->willReturn($configNames);
$this->consoleInput->expects($this->any())
->method('getOption')
->willReturnMap([
diff --git a/tests/core/command/config/system/setconfigtest.php b/tests/core/command/config/system/setconfigtest.php
index bbabee9b18f..c0b664d7522 100644
--- a/tests/core/command/config/system/setconfigtest.php
+++ b/tests/core/command/config/system/setconfigtest.php
@@ -53,63 +53,123 @@ class SetConfigTest extends TestCase {
public function setData() {
return [
- [
- 'name',
- 'newvalue',
- true,
- true,
- true,
- 'info',
- ],
- [
- 'name',
- 'newvalue',
- false,
- true,
- false,
- 'comment',
- ],
+ [['name'], 'newvalue', null, 'newvalue'],
+ [['a', 'b', 'c'], 'foobar', null, ['b' => ['c' => 'foobar']]],
+ [['a', 'b', 'c'], 'foobar', ['b' => ['d' => 'barfoo']], ['b' => ['d' => 'barfoo', 'c' => 'foobar']]],
];
}
/**
* @dataProvider setData
*
- * @param string $configName
- * @param mixed $newValue
- * @param bool $configExists
- * @param bool $updateOnly
- * @param bool $updated
- * @param string $expectedMessage
+ * @param array $configNames
+ * @param string $newValue
+ * @param mixed $existingData
+ * @param mixed $expectedValue
*/
- public function testSet($configName, $newValue, $configExists, $updateOnly, $updated, $expectedMessage) {
+ public function testSet($configNames, $newValue, $existingData, $expectedValue) {
$this->systemConfig->expects($this->once())
- ->method('getKeys')
- ->willReturn($configExists ? [$configName] : []);
+ ->method('setValue')
+ ->with($configNames[0], $expectedValue);
+ $this->systemConfig->method('getValue')
+ ->with($configNames[0])
+ ->willReturn($existingData);
- if ($updated) {
- $this->systemConfig->expects($this->once())
- ->method('setValue')
- ->with($configName, $newValue);
- }
+ $this->consoleInput->expects($this->once())
+ ->method('getArgument')
+ ->with('name')
+ ->willReturn($configNames);
+ $this->consoleInput->method('getOption')
+ ->will($this->returnValueMap([
+ ['value', $newValue],
+ ['type', 'string'],
+ ]));
+
+ $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
+ }
+
+ public function setUpdateOnlyProvider() {
+ return [
+ [['name'], null],
+ [['a', 'b', 'c'], null],
+ [['a', 'b', 'c'], ['b' => 'foobar']],
+ [['a', 'b', 'c'], ['b' => ['d' => 'foobar']]],
+ ];
+ }
+
+ /**
+ * @dataProvider setUpdateOnlyProvider
+ * @expectedException \UnexpectedValueException
+ */
+ public function testSetUpdateOnly($configNames, $existingData) {
+ $this->systemConfig->expects($this->never())
+ ->method('setValue');
+ $this->systemConfig->method('getValue')
+ ->with($configNames[0])
+ ->willReturn($existingData);
+ $this->systemConfig->method('getKeys')
+ ->willReturn($existingData ? $configNames[0] : []);
$this->consoleInput->expects($this->once())
->method('getArgument')
->with('name')
- ->willReturn($configName);
- $this->consoleInput->expects($this->any())
- ->method('getOption')
- ->with('value')
- ->willReturn($newValue);
- $this->consoleInput->expects($this->any())
- ->method('hasParameterOption')
- ->with('--update-only')
- ->willReturn($updateOnly);
-
- $this->consoleOutput->expects($this->any())
- ->method('writeln')
- ->with($this->stringContains($expectedMessage));
+ ->willReturn($configNames);
+ $this->consoleInput->method('getOption')
+ ->will($this->returnValueMap([
+ ['value', 'foobar'],
+ ['type', 'string'],
+ ['update-only', true],
+ ]));
$this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
}
+
+ public function castValueProvider() {
+ return [
+ [null, 'string', ['value' => '', 'readable-value' => 'empty string']],
+
+ ['abc', 'string', ['value' => 'abc', 'readable-value' => 'string abc']],
+
+ ['123', 'integer', ['value' => 123, 'readable-value' => 'integer 123']],
+ ['456', 'int', ['value' => 456, 'readable-value' => 'integer 456']],
+
+ ['2.25', 'double', ['value' => 2.25, 'readable-value' => 'double 2.25']],
+ ['0.5', 'float', ['value' => 0.5, 'readable-value' => 'double 0.5']],
+
+ ['', 'null', ['value' => null, 'readable-value' => 'null']],
+
+ ['true', 'boolean', ['value' => true, 'readable-value' => 'boolean true']],
+ ['false', 'bool', ['value' => false, 'readable-value' => 'boolean false']],
+ ];
+ }
+
+ /**
+ * @dataProvider castValueProvider
+ */
+ public function testCastValue($value, $type, $expectedValue) {
+ $this->assertSame($expectedValue,
+ $this->invokePrivate($this->command, 'castValue', [$value, $type])
+ );
+ }
+
+ public function castValueInvalidProvider() {
+ return [
+ ['123', 'foobar'],
+
+ [null, 'integer'],
+ ['abc', 'integer'],
+ ['76ggg', 'double'],
+ ['true', 'float'],
+ ['foobar', 'boolean'],
+ ];
+ }
+
+ /**
+ * @dataProvider castValueInvalidProvider
+ * @expectedException \InvalidArgumentException
+ */
+ public function testCastValueInvalid($value, $type) {
+ $this->invokePrivate($this->command, 'castValue', [$value, $type]);
+ }
+
}
diff --git a/tests/core/avatar/avatarcontrollertest.php b/tests/core/controller/avatarcontrollertest.php
index 948a432d2ed..8e5e58904a7 100644
--- a/tests/core/avatar/avatarcontrollertest.php
+++ b/tests/core/controller/avatarcontrollertest.php
@@ -18,19 +18,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-namespace OC\Core\Avatar;
+namespace OC\Core\Controller;
use OC;
use OC\Core\Application;
use OCP\AppFramework\IAppContainer;
-use OC\Files\Filesystem;
use OCP\AppFramework\Http;
-use OCP\Image;
use OCP\Files\Folder;
use OCP\Files\File;
+use OCP\Files\NotFoundException;
use OCP\IUser;
use OCP\IAvatar;
-
+use Punic\Exception;
use Test\Traits\UserTrait;
/**
@@ -44,7 +43,9 @@ function is_uploaded_file($filename) {
/**
* Class AvatarControllerTest
*
- * @package OC\Core\Avatar
+ * @group DB
+ *
+ * @package OC\Core\Controller
*/
class AvatarControllerTest extends \Test\TestCase {
use UserTrait;
@@ -57,6 +58,8 @@ class AvatarControllerTest extends \Test\TestCase {
private $avatarMock;
/** @var IUser */
private $userMock;
+ /** @var File */
+ private $avatarFile;
protected function setUp() {
parent::setUp();
@@ -89,6 +92,10 @@ class AvatarControllerTest extends \Test\TestCase {
->willReturnMap([['userId', $this->userMock]]);
$this->container['UserSession']->method('getUser')->willReturn($this->userMock);
+ $this->avatarFile = $this->getMock('OCP\Files\File');
+ $this->avatarFile->method('getContnet')->willReturn('image data');
+ $this->avatarFile->method('getMimeType')->willReturn('image type');
+ $this->avatarFile->method('getEtag')->willReturn('my etag');
}
public function tearDown() {
@@ -101,6 +108,7 @@ class AvatarControllerTest extends \Test\TestCase {
*/
public function testGetAvatarNoAvatar() {
$this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock);
+ $this->avatarMock->method('getFile')->will($this->throwException(new NotFoundException()));
$response = $this->avatarController->getAvatar('userId', 32);
//Comment out until JS is fixed
@@ -113,12 +121,8 @@ class AvatarControllerTest extends \Test\TestCase {
* Fetch the user's avatar
*/
public function testGetAvatar() {
- $image = $this->getMock('OCP\IImage');
- $image->method('data')->willReturn('image data');
- $image->method('mimeType')->willReturn('image type');
-
- $this->avatarMock->method('get')->willReturn($image);
- $this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock);
+ $this->avatarMock->method('getFile')->willReturn($this->avatarFile);
+ $this->container['AvatarManager']->method('getAvatar')->with('userId')->willReturn($this->avatarMock);
$response = $this->avatarController->getAvatar('userId', 32);
@@ -126,17 +130,19 @@ class AvatarControllerTest extends \Test\TestCase {
$this->assertArrayHasKey('Content-Type', $response->getHeaders());
$this->assertEquals('image type', $response->getHeaders()['Content-Type']);
- $this->assertEquals(crc32('image data'), $response->getEtag());
+ $this->assertEquals('my etag', $response->getEtag());
}
/**
* Fetch the avatar of a non-existing user
*/
public function testGetAvatarNoUser() {
- $this->avatarMock->method('get')->willReturn(null);
- $this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock);
+ $this->container['AvatarManager']
+ ->method('getAvatar')
+ ->with('userDoesNotExist')
+ ->will($this->throwException(new \Exception('user does not exist')));
- $response = $this->avatarController->getAvatar('userDoesnotexist', 32);
+ $response = $this->avatarController->getAvatar('userDoesNotExist', 32);
//Comment out until JS is fixed
//$this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus());
@@ -149,8 +155,9 @@ class AvatarControllerTest extends \Test\TestCase {
*/
public function testGetAvatarSize() {
$this->avatarMock->expects($this->once())
- ->method('get')
- ->with($this->equalTo(32));
+ ->method('getFile')
+ ->with($this->equalTo(32))
+ ->willReturn($this->avatarFile);
$this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock);
@@ -162,8 +169,9 @@ class AvatarControllerTest extends \Test\TestCase {
*/
public function testGetAvatarSizeMin() {
$this->avatarMock->expects($this->once())
- ->method('get')
- ->with($this->equalTo(64));
+ ->method('getFile')
+ ->with($this->equalTo(64))
+ ->willReturn($this->avatarFile);
$this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock);
@@ -175,8 +183,9 @@ class AvatarControllerTest extends \Test\TestCase {
*/
public function testGetAvatarSizeMax() {
$this->avatarMock->expects($this->once())
- ->method('get')
- ->with($this->equalTo(2048));
+ ->method('getFile')
+ ->with($this->equalTo(2048))
+ ->willReturn($this->avatarFile);
$this->container['AvatarManager']->method('getAvatar')->willReturn($this->avatarMock);
@@ -315,6 +324,23 @@ class AvatarControllerTest extends \Test\TestCase {
}
/**
+ * Test posting avatar from existing folder
+ */
+ public function testPostAvatarFromNoFile() {
+ $file = $this->getMock('OCP\Files\Node');
+ $this->container['UserFolder']
+ ->method('get')
+ ->with('folder')
+ ->willReturn($file);
+
+ //Create request return
+ $response = $this->avatarController->postAvatar('folder');
+
+ //On correct upload always respond with the notsquare message
+ $this->assertEquals(['data' => ['message' => 'Please select a file.']], $response->getData());
+ }
+
+ /**
* Test what happens if the upload of the avatar fails
*/
public function testPostAvatarException() {
diff --git a/tests/core/lostpassword/controller/lostcontrollertest.php b/tests/core/controller/lostcontrollertest.php
index 0f8cb4fc5c8..44bc539247f 100644
--- a/tests/core/lostpassword/controller/lostcontrollertest.php
+++ b/tests/core/controller/lostcontrollertest.php
@@ -19,66 +19,113 @@
*
*/
-namespace OC\Core\LostPassword\Controller;
-use OC\Core\Application;
+namespace OC\Core\Controller;
+
use OCP\AppFramework\Http\TemplateResponse;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\IConfig;
+use OCP\IL10N;
+use OCP\IRequest;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\Mail\IMailer;
+use OCP\Security\ISecureRandom;
+use PHPUnit_Framework_MockObject_MockObject;
/**
* Class LostControllerTest
*
- * @package OC\Core\LostPassword\Controller
+ * @package OC\Core\Controller
*/
class LostControllerTest extends \PHPUnit_Framework_TestCase {
- private $container;
/** @var LostController */
private $lostController;
+ /** @var IUser */
+ private $existingUser;
+ /** @var IURLGenerator | PHPUnit_Framework_MockObject_MockObject */
+ private $urlGenerator;
+ /** @var IL10N */
+ private $l10n;
+ /** @var IUserManager | PHPUnit_Framework_MockObject_MockObject */
+ private $userManager;
+ /** @var \OC_Defaults */
+ private $defaults;
+ /** @var IConfig | PHPUnit_Framework_MockObject_MockObject */
+ private $config;
+ /** @var IMailer | PHPUnit_Framework_MockObject_MockObject */
+ private $mailer;
+ /** @var ISecureRandom | PHPUnit_Framework_MockObject_MockObject */
+ private $secureRandom;
+ /** @var ITimeFactory | PHPUnit_Framework_MockObject_MockObject */
+ private $timeFactory;
+ /** @var IRequest */
+ private $request;
protected function setUp() {
- $app = new Application();
- $this->container = $app->getContainer();
- $this->container['AppName'] = 'core';
- $this->container['Config'] = $this->getMockBuilder('\OCP\IConfig')
+
+ $this->existingUser = $this->getMockBuilder('OCP\IUser')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->existingUser
+ ->expects($this->any())
+ ->method('getEMailAddress')
+ ->willReturn('test@example.com');
+
+ $this->config = $this->getMockBuilder('\OCP\IConfig')
->disableOriginalConstructor()->getMock();
- $this->container['L10N'] = $this->getMockBuilder('\OCP\IL10N')
+ $this->l10n = $this->getMockBuilder('\OCP\IL10N')
->disableOriginalConstructor()->getMock();
- $this->container['L10N']
+ $this->l10n
->expects($this->any())
->method('t')
->will($this->returnCallback(function($text, $parameters = array()) {
return vsprintf($text, $parameters);
}));
- $this->container['Defaults'] = $this->getMockBuilder('\OC_Defaults')
+ $this->defaults = $this->getMockBuilder('\OC_Defaults')
->disableOriginalConstructor()->getMock();
- $this->container['UserManager'] = $this->getMockBuilder('\OCP\IUserManager')
+ $this->userManager = $this->getMockBuilder('\OCP\IUserManager')
->disableOriginalConstructor()->getMock();
- $this->container['Config'] = $this->getMockBuilder('\OCP\IConfig')
+ $this->urlGenerator = $this->getMockBuilder('\OCP\IURLGenerator')
->disableOriginalConstructor()->getMock();
- $this->container['URLGenerator'] = $this->getMockBuilder('\OCP\IURLGenerator')
+ $this->mailer = $this->getMockBuilder('\OCP\Mail\IMailer')
->disableOriginalConstructor()->getMock();
- $this->container['Mailer'] = $this->getMockBuilder('\OCP\Mail\IMailer')
+ $this->secureRandom = $this->getMockBuilder('\OCP\Security\ISecureRandom')
->disableOriginalConstructor()->getMock();
- $this->container['SecureRandom'] = $this->getMockBuilder('\OCP\Security\ISecureRandom')
+ $this->timeFactory = $this->getMockBuilder('\OCP\AppFramework\Utility\ITimeFactory')
->disableOriginalConstructor()->getMock();
- $this->container['TimeFactory'] = $this->getMockBuilder('\OCP\AppFramework\Utility\ITimeFactory')
+ $this->request = $this->getMockBuilder('OCP\IRequest')
->disableOriginalConstructor()->getMock();
- $this->container['IsEncryptionEnabled'] = true;
- $this->lostController = $this->container['LostController'];
+ $this->lostController = new LostController(
+ 'Core',
+ $this->request,
+ $this->urlGenerator,
+ $this->userManager,
+ $this->defaults,
+ $this->l10n,
+ $this->config,
+ $this->secureRandom,
+ 'lostpassword-noreply@localhost',
+ true,
+ $this->mailer,
+ $this->timeFactory
+ );
}
public function testResetFormUnsuccessful() {
$userId = 'admin';
$token = 'MySecretToken';
- $this->container['URLGenerator']
+ $this->urlGenerator
->expects($this->once())
->method('linkToRouteAbsolute')
->with('core.lost.setPassword', array('userId' => 'admin', 'token' => 'MySecretToken'))
->will($this->returnValue('https://ownCloud.com/index.php/lostpassword/'));
$response = $this->lostController->resetform($token, $userId);
- $expectedResponse = new TemplateResponse('core/lostpassword',
- 'resetpassword',
+ $expectedResponse = new TemplateResponse('core',
+ 'lostpassword/resetpassword',
array(
'link' => 'https://ownCloud.com/index.php/lostpassword/',
),
@@ -89,7 +136,7 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
public function testEmailUnsucessful() {
$existingUser = 'ExistingUser';
$nonExistingUser = 'NonExistingUser';
- $this->container['UserManager']
+ $this->userManager
->expects($this->any())
->method('userExists')
->will($this->returnValueMap(array(
@@ -106,7 +153,7 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
$this->assertSame($expectedResponse, $response);
// With no mail address
- $this->container['Config']
+ $this->config
->expects($this->any())
->method('getUserValue')
->with($existingUser, 'settings', 'email')
@@ -120,35 +167,30 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
}
public function testEmailSuccessful() {
- $randomToken = $this->container['SecureRandom'];
- $this->container['SecureRandom']
+ $this->secureRandom
->expects($this->once())
->method('generate')
->with('21')
->will($this->returnValue('ThisIsMaybeANotSoSecretToken!'));
- $this->container['UserManager']
- ->expects($this->once())
- ->method('userExists')
- ->with('ExistingUser')
- ->will($this->returnValue(true));
- $this->container['TimeFactory']
+ $this->userManager
+ ->expects($this->once())
+ ->method('userExists')
+ ->with('ExistingUser')
+ ->will($this->returnValue(true));
+ $this->userManager
+ ->expects($this->any())
+ ->method('get')
+ ->with('ExistingUser')
+ ->willReturn($this->existingUser);
+ $this->timeFactory
->expects($this->once())
->method('getTime')
->will($this->returnValue(12348));
- $this->container['Config']
- ->expects($this->once())
- ->method('getUserValue')
- ->with('ExistingUser', 'settings', 'email')
- ->will($this->returnValue('test@example.com'));
- $this->container['SecureRandom']
- ->expects($this->once())
- ->method('getMediumStrengthGenerator')
- ->will($this->returnValue($randomToken));
- $this->container['Config']
+ $this->config
->expects($this->once())
->method('setUserValue')
->with('ExistingUser', 'owncloud', 'lostpassword', '12348:ThisIsMaybeANotSoSecretToken!');
- $this->container['URLGenerator']
+ $this->urlGenerator
->expects($this->once())
->method('linkToRouteAbsolute')
->with('core.lost.resetform', array('userId' => 'ExistingUser', 'token' => 'ThisIsMaybeANotSoSecretToken!'))
@@ -171,11 +213,11 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
->expects($this->at(3))
->method('setFrom')
->with(['lostpassword-noreply@localhost' => null]);
- $this->container['Mailer']
+ $this->mailer
->expects($this->at(0))
->method('createMessage')
->will($this->returnValue($message));
- $this->container['Mailer']
+ $this->mailer
->expects($this->at(1))
->method('send')
->with($message);
@@ -186,35 +228,30 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
}
public function testEmailCantSendException() {
- $randomToken = $this->container['SecureRandom'];
- $this->container['SecureRandom']
+ $this->secureRandom
->expects($this->once())
->method('generate')
->with('21')
->will($this->returnValue('ThisIsMaybeANotSoSecretToken!'));
- $this->container['UserManager']
+ $this->userManager
->expects($this->once())
->method('userExists')
->with('ExistingUser')
->will($this->returnValue(true));
- $this->container['Config']
- ->expects($this->once())
- ->method('getUserValue')
- ->with('ExistingUser', 'settings', 'email')
- ->will($this->returnValue('test@example.com'));
- $this->container['SecureRandom']
- ->expects($this->once())
- ->method('getMediumStrengthGenerator')
- ->will($this->returnValue($randomToken));
- $this->container['Config']
+ $this->userManager
+ ->expects($this->any())
+ ->method('get')
+ ->with('ExistingUser')
+ ->willReturn($this->existingUser);
+ $this->config
->expects($this->once())
->method('setUserValue')
->with('ExistingUser', 'owncloud', 'lostpassword', '12348:ThisIsMaybeANotSoSecretToken!');
- $this->container['TimeFactory']
+ $this->timeFactory
->expects($this->once())
->method('getTime')
->will($this->returnValue(12348));
- $this->container['URLGenerator']
+ $this->urlGenerator
->expects($this->once())
->method('linkToRouteAbsolute')
->with('core.lost.resetform', array('userId' => 'ExistingUser', 'token' => 'ThisIsMaybeANotSoSecretToken!'))
@@ -237,11 +274,11 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
->expects($this->at(3))
->method('setFrom')
->with(['lostpassword-noreply@localhost' => null]);
- $this->container['Mailer']
+ $this->mailer
->expects($this->at(0))
->method('createMessage')
->will($this->returnValue($message));
- $this->container['Mailer']
+ $this->mailer
->expects($this->at(1))
->method('send')
->with($message)
@@ -253,7 +290,7 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
}
public function testSetPasswordUnsuccessful() {
- $this->container['Config']
+ $this->config
->expects($this->once())
->method('getUserValue')
->with('InvalidTokenUser', 'owncloud', 'lostpassword', null)
@@ -275,7 +312,7 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
}
public function testSetPasswordSuccessful() {
- $this->container['Config']
+ $this->config
->expects($this->once())
->method('getUserValue')
->with('ValidTokenUser', 'owncloud', 'lostpassword', null)
@@ -290,16 +327,16 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
->method('setPassword')
->with('NewPassword')
->will($this->returnValue(true));
- $this->container['UserManager']
+ $this->userManager
->expects($this->once())
->method('get')
->with('ValidTokenUser')
->will($this->returnValue($user));
- $this->container['Config']
+ $this->config
->expects($this->once())
->method('deleteUserValue')
->with('ValidTokenUser', 'owncloud', 'lostpassword');
- $this->container['TimeFactory']
+ $this->timeFactory
->expects($this->once())
->method('getTime')
->will($this->returnValue(12348));
@@ -310,19 +347,19 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
}
public function testSetPasswordExpiredToken() {
- $this->container['Config']
+ $this->config
->expects($this->once())
->method('getUserValue')
->with('ValidTokenUser', 'owncloud', 'lostpassword', null)
->will($this->returnValue('12345:TheOnlyAndOnlyOneTokenToResetThePassword'));
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()->getMock();
- $this->container['UserManager']
+ $this->userManager
->expects($this->once())
->method('get')
->with('ValidTokenUser')
->will($this->returnValue($user));
- $this->container['TimeFactory']
+ $this->timeFactory
->expects($this->once())
->method('getTime')
->will($this->returnValue(55546));
@@ -336,14 +373,14 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
}
public function testSetPasswordInvalidDataInDb() {
- $this->container['Config']
+ $this->config
->expects($this->once())
->method('getUserValue')
->with('ValidTokenUser', 'owncloud', 'lostpassword', null)
->will($this->returnValue('TheOnlyAndOnlyOneTokenToResetThePassword'));
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()->getMock();
- $this->container['UserManager']
+ $this->userManager
->expects($this->once())
->method('get')
->with('ValidTokenUser')
@@ -358,7 +395,7 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
}
public function testSetPasswordExpiredTokenDueToLogin() {
- $this->container['Config']
+ $this->config
->expects($this->once())
->method('getUserValue')
->with('ValidTokenUser', 'owncloud', 'lostpassword', null)
@@ -369,12 +406,12 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
->expects($this->once())
->method('getLastLogin')
->will($this->returnValue(12346));
- $this->container['UserManager']
+ $this->userManager
->expects($this->once())
->method('get')
->with('ValidTokenUser')
->will($this->returnValue($user));
- $this->container['TimeFactory']
+ $this->timeFactory
->expects($this->once())
->method('getTime')
->will($this->returnValue(12345));
@@ -388,7 +425,7 @@ class LostControllerTest extends \PHPUnit_Framework_TestCase {
}
public function testIsSetPasswordWithoutTokenFailing() {
- $this->container['Config']
+ $this->config
->expects($this->once())
->method('getUserValue')
->with('ValidTokenUser', 'owncloud', 'lostpassword', null)
diff --git a/tests/data/integritycheck/SomeApp.crt b/tests/data/integritycheck/SomeApp.crt
new file mode 100644
index 00000000000..a9bd4cd8a7c
--- /dev/null
+++ b/tests/data/integritycheck/SomeApp.crt
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf/qTQvoyKAwDQYJKoZIhvcNAQEF
+BQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw
+MzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk
+F8cAobMMi50qHCv9IrOn/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl/j
++ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+
+A+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M
+w0xDv30D5UkE/2N7Pa/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4
+GB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6
+dol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj
+t5O7Zn2wA7I4ddDS/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC
+cxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT/x/mqN3PfRmlnFBNACUw9bpZ
+SOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz
+tFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4
+6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf
+FWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS
+HVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70/4imPoKxbAVCpd/cveVcFyDC19j1yB
+Bapwu87oh+muoeaZxOlqQI4UxjBlR/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v
+0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3
+pPhEpo1dRpiXaF7WGIV1X6DI/ipWvfrF7CEy6I/kP1InY/vMDjQjeDnJ/VrXIWXO
+yZvHXVaN/m+1RlETsH7YO/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF
+49/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7
+7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW
+UO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS/P4RB1NkHA9+NTvmBpTonS
+SFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP/Y7xwxLv7
+4B+pXTAcRK0zECDEaX3npS8xWzrB
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/data/integritycheck/SomeApp.key b/tests/data/integritycheck/SomeApp.key
new file mode 100644
index 00000000000..ce59eb1b86f
--- /dev/null
+++ b/tests/data/integritycheck/SomeApp.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEAryrTHrZqAZJEGp5axp4TAV96kyQXxwChswyLnSocK/0is6f9
+kf2XnbEGtsiQStWZGOaXLR3gmEPxiaGJ2yH040piX+P6KyGxkMzx4012ncTD58Rh
+W9jVbuZHWpTbg1aPRvNWwKUjuG89Ui7DsCN8EOrULn4D5lItJdi84rZwRaN3FB+4
+1nARlKOYDrcNSWUEiubfkhpO9+7KFToFb3IdnGZvz4zDTEO/fQPlSQT/Y3s9r8dA
+kvEJH7fMqJtEredTJEMtJfEyRT0+cU1o81fn1U+DKPgYHUIVJOiV0lU8XinOHunf
+q4ZdlXGzybcsUPg6XyaGLuOTENmOoU3jqDNHSvbc/Lp2iX299rAYihTCn0u8vRLs
+y91FjShrMtfAKUs/g5DXvOlIwCIKPt+A1PrrUlqY8aO3k7tmfbADsjh10NL8cNNY
+K73xnBz18cimwk+AJn1rCirGLgyd/s+T2DmedeGzMYJzHEgBJAoz4aF3OhHEqSdr
+HZHNQLALNw9G0KPwBBP/H+ao3c99GaWcUE0AJTD1ullI6g2rakIX2KB+0NalIhdD
+fylWkotajCOODcNVGZUoGCK8edSdUvLNgFqEc+PS9rO0W1QVFqpcOe37irJQbKtP
+mHmmNlpNwchxIHg+JqtjB1W+CyWDCdDM5RwYDNFYEPjqNXZus/m8VjeDqI8CAwEA
+AQKCAgAGEpX/GpPSOh/iTFsZR6GhCo5VS4sHex4f9u9gI3WWkNADKm+//+qhrOFu
+tMVL0tvb4SKcjcyber+E5fTBhAvZVVrTuDOUCzb8rh40oxrZnVitUEGPzZSYo6MV
+oNN7WiTdcNIxG4iBfFnD35spIBHNBFcWxYedFHw8M6dYtLpvr5sRN4hQ5tG1NXaw
+C+iKAtaFejuF9SOHtN+MnNZTZsFgCq0VpOugWTjqPJhWT7YK3NrmnSG/9ls6nkSa
+E8ftv3dCapHGHvZ/MABaLTTWOtXurzL82Jz9Zq0U+ns3L31IRmq+55y5dY8I/0gc
+Vh1TMUfUxKEiPwF6NBCdxvV9f0mZYQPEeHATnkew/SW35EDPgPSS/H3jJLORhAUJ
+7ZzDkvwdfWjnHxyzJtbHHZ8r3gqwq0rqfyd4Rz04TusUukfikdy5ooL1dMLiy3od
+V40zQxVpI44zrrLBjaJ+OItdD5NFRu82K0OF653a/1fP7x4fw3j/ATVQhW8g0EE3
+oEEdGaciqXDWNxlSwiZUmteq3chN+JRXrBWlOodV5LyJwiy5/5NMV91a5AP0wOsT
+BXzhkjnLsGJMSQuzDs1CFUVjqs1PudhyW+pgoy8HaTSfamKiAHbJlBSuSX0acR7S
+iwiGhzkChWtUv1vMVM56z19g/umwmZujwhr2jkN1Y0zZH//xAQKCAQEA3GV74emO
+IMjsb8VbJyCHycYEfcu7fZ90mLrK7yyjNxobROniqjWYT92fjse1qrTv54luxFN7
+EUF5ec9QRYo1mnyltjqTCx3jfqMlCr94LaIEdMQJ/f3vW6pEj7xY4RSY9hZX8v1Z
+mrhKcFkqGSFdWLliVD471Mxi2/7T8mKjmVhKy3P+Cm1aHardGqvT/mUTOB0sO0OT
+CJSRUWh2Tx2d3B1M6nDXZL8TTVdndEKUycj204Pf6fm6bMJcVuro/kPcwByhG+Ar
+dAKN4HdEa+XmrfqDKzl9yhLUpwXa7rI8g5if/oVj2kF/hny4mboL4U4rC+YWQZ1f
+TBklcYPCx2NgqwKCAQEAy3bioCaqa+iAsSWLjRp1Dh+93vI7WXvuPdLkAQ/Iz6yQ
+sCqjQj/4jIxm7qmhbh8X3B8VkaX2jnuaR9nUuZyjIvHg1WMCMeMYWiok5GCppkyH
+yLoEIT1mTyTe3Wjk37Zi+1UQRHPS/8noVtVj0ng95SChnmguDF3otvl4lLH+wgCz
+z1xMO9VyLTEGU3jbPgXqNeGKdqk/kEsU4C+NuwPiRMAuDuKR+s5ldB293GBPnFKu
+OqgzVoJJChLAPUvzSE+hJmWin2hoCZMktLUdSCng9rm9AhXWYpLwUrANZuvI8RfO
+9wX1NR17U+QbX2PvDlEl6B9Yt3G4R9qNxUPLrjP/rQKCAQEAyDO3kMOjw8xAWleg
+Ma6vKm6h7dN/gOGz/HjRlumpaYhhdPwwVgVRUlszcXOgZmzt8Bk7cUOT61zah/f2
+JvUhNDA+J4aVw+dmm8Z/A4BiHrGp8peRrBNbtpy4owiog+099Wzef2/8UTtPAzc7
+spBIRyw/Ud8mYms28jhNN0S677TwXFgFUFt9HK31IyEq9U/DYZm+cCc2DPlH9/c4
+YS26FBTZpazTPEUFt5/J7iX9Gj9fV0vXvqaG3fy//IRvGWlzwV9ASh4b2snnLxuo
+H4s7PJbvR/h1d3YbjY0YDvQBXFjsHTv2NHCC8xugZKRH3mYvXCOp2/ikdG/zP2Y9
+LPns+QKCAQB1M2Mx63PpusE+yajMO/xHiYM+xHvpfNjsZemOrv/2mKmzwKvQQrcy
+hsHYIoBpxaFh28n53wbaZlqlntXJoW/bdkcTw/eEsxLZBUPBBelTcOwadQRh/VNM
+ralvErgcIZx8uDApripRy4V5V2wr1bWZoaVXcR1tZD7j/2o1BR8Bs5PgE4OaR8aA
+P6gsNwbbgF68cNHorm9997HrvZi/rGoPPkCJtHtwZKnOLD+sjRHuszXHdhI0d9II
+6mowJOrbsXrbelolxud+9HKFYXqfkfgTR0SXyep3V7r1dpIRwio6roM6igUIdpYO
+6evWk+MldRsHzd61tNz5DuzxP685Bpz1AoIBAGnP0wLx3B9ri2Q5g3ENPdZhAop+
+/CMZUWR297yc0gSIoCnTBtNG3y735P887zOQlIZaFnnMzPP85mPMMMUT5Os5kFrE
+MzHaNkgpbxD2xcAB3sA1Hk/yn/c/nuTTZpTTYGv0OVE+/rQ4l2al1ngWTTz8/Bf1
+m3IDKluBTNkoD8DnS9+9CT3YWpnEr3sw8Vqzuat5hSgneJP1dtv2dCDXQ4MOUZbL
+riXuafvnlbC6tfmOGdeZ90rdTQWRIckP8zDZI0kZ1XADEwD1iTnWgfI1hoKI4MN8
+3h4JbmLC0nvaRDivwOuy2BDhpYW6wRtphSYvfshlmAptt306Na35FUvLL80=
+-----END RSA PRIVATE KEY----- \ No newline at end of file
diff --git a/tests/data/integritycheck/app/AnotherFile.txt b/tests/data/integritycheck/app/AnotherFile.txt
new file mode 100644
index 00000000000..cf85999ddfc
--- /dev/null
+++ b/tests/data/integritycheck/app/AnotherFile.txt
@@ -0,0 +1 @@
+Another file with some Content.
diff --git a/tests/data/integritycheck/app/subfolder/file.txt b/tests/data/integritycheck/app/subfolder/file.txt
new file mode 100644
index 00000000000..69cd4e0afaf
--- /dev/null
+++ b/tests/data/integritycheck/app/subfolder/file.txt
@@ -0,0 +1 @@
+A file with some content.
diff --git a/tests/data/integritycheck/appWithInvalidData/AnotherFile.txt b/tests/data/integritycheck/appWithInvalidData/AnotherFile.txt
new file mode 100644
index 00000000000..c73a4892418
--- /dev/null
+++ b/tests/data/integritycheck/appWithInvalidData/AnotherFile.txt
@@ -0,0 +1 @@
+TAMPERED FILE. \ No newline at end of file
diff --git a/tests/data/integritycheck/appWithInvalidData/UnecessaryFile b/tests/data/integritycheck/appWithInvalidData/UnecessaryFile
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/tests/data/integritycheck/appWithInvalidData/UnecessaryFile
diff --git a/tests/data/integritycheck/core.crt b/tests/data/integritycheck/core.crt
new file mode 100644
index 00000000000..475a59bddce
--- /dev/null
+++ b/tests/data/integritycheck/core.crt
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIEvjCCAqagAwIBAgIUc/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF
+BQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw
+MzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s
+iOf4RwPXR6SE9bWZEm/b72SfWk//J6AbrD8WiOzBuT/ODy6k5T1arEdHO+Pux0W1
+MxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr/xolP3oD+eLbShPcblhdS
+VtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0
+klnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5/2riAzIssMFSCarWCx0AKYb54+d
+xLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77
+H87KFhYW8tKFFvF1V3AHl/sFQ9tDHaxM9Y0pZ2jPp/ccdiqnmdkBxBDqsiRvHvVB
+Cn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO/wAtd2vUW8UFiq
+s2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ/zrM0
+i8nfCFwTxWRxp3H9KoECzO/zS5R5KIS7s3/wq/w9T2Ie4rcecgXwDizwnn0C/aKc
+bDIjujpL1s9HO05pcD/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ
+Q238lC+A/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2
+AvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji
+oNCXUbExC/0iCPUqdHZIVb+Lc/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd
+9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb
+H+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th/55
+cf3Fovj6JJgbb9XFxrdnsOsDOu/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX
+uVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO//+TJtXRbyNgsf
+oMRZGi8DLGU2SGEAHcRH/QZHq/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1
+0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI/XUxEWOa2F
+K2EqhErgMK/N07U1JJJay5tYZRtvkGq46oP/5kQG8hYST0MDK6VihJoPpvCmAm4E
+pEYKQ96x6A4EH9Y9mZlYozH/eqmxPbTK8n89/p7Ydun4rI+B2iiLnY8REWWy6+UQ
+V204fGUkJqW5CrKy3P3XvY9X
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/data/integritycheck/core.key b/tests/data/integritycheck/core.key
new file mode 100644
index 00000000000..4a588d47356
--- /dev/null
+++ b/tests/data/integritycheck/core.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAtvoSAemQCpls7m9E7xdKHsbtcZYfDmyI5/hHA9dHpIT1tZkS
+b9vvZJ9aT/8noBusPxaI7MG5P84PLqTlPVqsR0c74+7HRbUzFgkkjiQfvgoqAykL
+RIHRG37xasypXWveGEnjp1/pev/GiU/egP54ttKE9xuWF1JW2RkSSh6/xKHovbAM
+J4cPI/HO+PXDZ1N0ZU70rO2fTEiXJ8QFqSq8Fa1zHKLcufSSWfGUzHe08NQTiSq+
+mJr2o2IHUA3Y9X3d42vn/auIDMiywwVIJqtYLHQAphvnj53EulxgXKo8nTJ0EKQX
+vwMPjlEJl63o81iR3OBuqVRYQYaiaS4OglsGDjDODM7QPvsfzsoWFhby0oUW8XVX
+cAeX+wVD20MdrEz1jSlnaM+n9xx2KqeZ2QHEEOqyJG8e9UEKfqqlvi9YYULu8c4F
+9iymYQvXMuUpdm/d7MxkRnDs71m9Q/dU7/AC13a9RbxQWKqza/VCc0s3qM2HnWht
+zCasG9aEnL29Ah20iNBsPGpZMeHXNRKvD3CuWSUIFn/OszSLyd8IXBPFZHGncf0q
+gQLM7/NLlHkohLuzf/Cr/D1PYh7itx5yBfAOLPCefQL9opxsMiO6OkvWz0c7Tmlw
+P9XfApw9nWLPKYGSYzIhsvnaJFU3kVNUd5l1c+kW6r4JNAlDbfyUL4D8o5UCAwEA
+AQKCAgBOkCKpNYqGMogF/DqB2eMWQd1zdryQ6eMCjqSXLpjxN7F0LmwvISSxdIZH
+cMunwBn94IQb+7W5gpUcNurCpCryU9CQNlbTRFDR9kz+xt3mL+EICFhxKrgI8UFg
+1M0ncogir58Sn2jVSfsJvARSKHDWNp+mpe6UxuLJRi2HK5q1J7uRroQZeLD0gv+V
+/5fNxpRkZzlBAqnyC/zyswSnNNUbDaUuN3NEWJF6EvMLs546BST6MSMyzN53GkD/
+i2KLTWa3Hf62+S5qJsYyXBM1nz41n/0jVTngfSIZzk4Fm4Z5DE+vUXVsqzjDp2HS
+AXbS/UVrq+V3yOI4CEG1nXPXXpPDS/werQcSvANGHd/LLiQ3qfcs1S/SBihDjSFQ
+CBgH3y06qDdnKxdPjpRYZpOBnkdQLHF4OwlhPXBd083Ep7jiF1WIgzwBP9o9wEWi
+dVT0Vr5vsB61MQ+4p26Us1yWm51g6AxpTu5y2RPmbuDh1IvNbheeITQMSmbtGf1R
+JZ4yqrnYpd3akja9hwko1xoWuHT15rr2pTs8g/PtHH7sNkZdThMtJscEt4YIIxoN
+CQ+VM4lGYogtySbYEiUkRNF3t06AsPhBehcH7oldUqb6UKKoi6NCZOiC5RsdpOY3
+JJX2nkCMk52264sI+kWl6kEVBpMzeLW+BM0Xi1AQRyHPIY+VZQKCAQEA4sjNh35x
+ezjiOWsq84UOUHdvei9HAm+MQMM2pEgdHWjjawhoH122gi2G/tpgNGONl/XNmZkk
+ni00jFtNRA9xDF6mv1CynxiWhKGLdEH3MELQqGyeNOE9GBQVMo2W2J2mvOj+GzC+
+cRrEBjR1MDGx+XLO8FbYyKiwVg8/OIT9hIYSlBIsu0bPwYb6X3KlfZfmdh/MZvCs
+HDthzRYnJlkVerB/2ZnfTVYflQh7XoKFipVXFMs+oG0mKCUT4HpqXWTek1Jqt8bQ
+og9235C0jEcFWjSHtp2Jhena8yMD4YKQGI7tFVFm9UkHkKPcdfIW+hoVC4vLI0fs
+LMwhzOvFof4pawKCAQEAzoyGHKUA2KG8JVV49C5LKLmJv0nBj7aT5EXcg1J9OZn7
+zP/o/BHJQpeLNI2UD5c0Ron33iRLVqNvU4sTdo597Qoc2jWsZWRmdTz2Q4VvnxHu
+VBvao0vUG4xqIbMtv4VRkuNg9EmlF4luT5+x30E6DWDMK0RhSmM9yWG7My6JG2IN
+LZ457tWvk7F1HTKNt3uFJTAOx0VqjJsbaw7Gsq7hTmObTUa+q8Ss0oK+iRkP5Obv
+9F9zUWv2UjKs/G4JYADfFhS1Ovha8pu5p+NszlGBGvG99EErRpiUPcxCTjSiUvDl
+ALn3YTDc9oSC+6b/sI7/4uQVSri5ybXLGzbtMWKm/wKCAQEAvO12M6uF1Ja1+Ams
+lYTCQQzO5OZf7MqK+CTo74FYJ/kKhE9TltXWRqqw7L12Kg7Jlc/jgVNQaynTvh4N
+x2Zp0llD5tvOgrXUJxgBek++Iwl2lOkv/3OpFtccNao5AaqMjpI3puU7sjQPG/A1
+tHmh/+LCPPzMypWlmXxIOcio/u9GqO5fL4E1cM8G4985uOCD0OJ6wUM8zqQ1vMn4
+wXyzZSuGxvvmSKI320teo4Ruxd3V1u/e830arZT98yNoWve+aNLfLszFYE0rxeHi
+V36PGe/rI5ooSFRi3+zKveKsMplXL0xKTouRbtDjx6pvs9losN6701+GhGdmvTWp
+xmNbkwKCAQEAmY94FcvG+UglbUxChKf2UOzAMGtRcNs40Lnv2+J0H2MQBbUtLlq6
+2rt4TzYDIiQ0RU1F7u3k5SDVH7OCYN5HWPfvw3usFCW01uzf2gtWlVjra7TZtBYo
+N+MI9M0V8hHYN/C8oGIwT3Npg+EiiO0hj9ircm+ANaHayeHTH5Y1cRpQ2d2NDLfp
+tVB11aNEIWm/74nvMs+1C5w1oj52E1pZP8JmL+ms0F+EbW2u4pazbmcTdweP4LT3
+iN0MJxBX//wl33C93H3QgBauzNcUib+m0LVxmCrrVa0SaW92zFXtaOSYHRYliSie
+3thd2WKrLkTikXkpK0hzODfkLPOFHPZPWQKCAQAG0Yz7eQblxIHII60ReeYIovum
+Gmn+ot0jeuPg5gYpopQygL87ygc00ER+SHgZLBjIx3uCYDbC6Q4SzEPLa/aUS3/e
+94vYBVoWYvTYUazuwgJBA1Xm7BnlqG7cQziJOQxBIJBXaX96xUptcmlKrIIYD9Jz
+qeUbbbqN4bBYjXJdNdMqU1f6t2IK7hcjFXJMpS2wJdv1AlYCUWDquQ0BUePCJAPf
+N0rKm12ffhi564NqN/6PtT7iEkSPKT2CEyqrvXwx0Lajz0ZokFzRm2iYUTxik2fI
+Lcq5zXyM4gs1hDnrasn1g0JyfeUgnPNNuWeFG0cMb8o7FeYQImhqheIgMJLP
+-----END RSA PRIVATE KEY----- \ No newline at end of file
diff --git a/tests/data/integritycheck/htaccessUnmodified/.htaccess b/tests/data/integritycheck/htaccessUnmodified/.htaccess
new file mode 100644
index 00000000000..9bcb05db96c
--- /dev/null
+++ b/tests/data/integritycheck/htaccessUnmodified/.htaccess
@@ -0,0 +1 @@
+# Start of valid file \ No newline at end of file
diff --git a/tests/data/integritycheck/htaccessUnmodified/subfolder/.htaccess b/tests/data/integritycheck/htaccessUnmodified/subfolder/.htaccess
new file mode 100644
index 00000000000..33d4437c928
--- /dev/null
+++ b/tests/data/integritycheck/htaccessUnmodified/subfolder/.htaccess
@@ -0,0 +1,4 @@
+# Start of valid file
+#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####
+
+# Content that should change the hash in the root folder \ No newline at end of file
diff --git a/tests/data/integritycheck/htaccessWithInvalidModifiedContent/.htaccess b/tests/data/integritycheck/htaccessWithInvalidModifiedContent/.htaccess
new file mode 100644
index 00000000000..d3c2f69f120
--- /dev/null
+++ b/tests/data/integritycheck/htaccessWithInvalidModifiedContent/.htaccess
@@ -0,0 +1,5 @@
+# Start of valid file
+#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####
+# Content that should not modify the hash
+#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####
+# but it does because it is twice \ No newline at end of file
diff --git a/tests/data/integritycheck/htaccessWithValidModifiedContent/.htaccess b/tests/data/integritycheck/htaccessWithValidModifiedContent/.htaccess
new file mode 100644
index 00000000000..33d4437c928
--- /dev/null
+++ b/tests/data/integritycheck/htaccessWithValidModifiedContent/.htaccess
@@ -0,0 +1,4 @@
+# Start of valid file
+#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####
+
+# Content that should change the hash in the root folder \ No newline at end of file
diff --git a/tests/data/integritycheck/htaccessWithValidModifiedContent/subfolder/.htaccess b/tests/data/integritycheck/htaccessWithValidModifiedContent/subfolder/.htaccess
new file mode 100644
index 00000000000..33d4437c928
--- /dev/null
+++ b/tests/data/integritycheck/htaccessWithValidModifiedContent/subfolder/.htaccess
@@ -0,0 +1,4 @@
+# Start of valid file
+#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####
+
+# Content that should change the hash in the root folder \ No newline at end of file
diff --git a/tests/data/integritycheck/root.crt b/tests/data/integritycheck/root.crt
new file mode 100644
index 00000000000..539bd9a199f
--- /dev/null
+++ b/tests/data/integritycheck/root.crt
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIE1DCCArygAwIBAgIUFgEnT7tUWNgEKfbMiRTOm3Z8figwDQYJKoZIhvcNAQEF
+BQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMCAXDTE1MTEw
+MzIxMDMzMloYDzk5OTkxMjMxMjM1OTU5WjAjMSEwHwYDVQQKDBhvd25DbG91ZCBD
+b2RlIFNpZ25pbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCt
+rYEwiwpuhzRNx1L2SntkL/zalA7OkwEcsBn4Ysw47nEdvp648AVohT7d+U7+DWix
+O06xvlAJUhqYTXX7EG9n+mBnG+TIMq2zlei0Jj3uq1pEZE9elfGZael2uc8gRXMZ
+YFmSlTvzexqvfK4B3DwoZaMaWJecEO9iyuUyzHMBpE8bHtGDOUGy/oTO9WASbtl9
+Rfk38VLLV6csCPwKjii6Q3YZ+AYU0YqLg22BwZlqlTexUjWAmVIqaoxmSEuKa41X
+nuAIHfP65oiob86s4IvJXVr3r7NjdF2IJ/ZrwmjGKaWgSZKcoZBPLArZJeJiIQ4Y
+KzLZATwba5dWswV0mbDj8eP2BG+02NVKxylOBbeoBESnahZeZ5nJ5XKZr+ErJAUW
+b417fEnYaQNBlNnijjkqXaDipmTktUfnv4lm30sUAgho6I3Ga7gQrFPzKg9V4j2S
++LOTc1HmJOnR6Kfttx+yAHYLKtvV5yIMMpz+rZ2X5g/N2GdgleZj5VU9nmKzTPeG
+x6V+dBaIkqNe8/AXaVnxt9KSb03Q/+CFjKTNDtEN5fNJuXS0+h+oop6nhpktM2i7
+gCpxeLNEaQaeoxR5093VN00oOJOYBvQoVGEDftEwdG6dWbTZsIykBF7aK+p8DMy9
+tCdc2GnGMEuFlUNA9ucv2Rv7IcuPdspnK31CZoMNKwIDAQABMA0GCSqGSIb3DQEB
+BQUAA4ICAQBROWec0HOsnLPN40gkBQ62mNBUJgcAr5K2eMIEMSRFRD2ldEVOvmCO
+u1Q62umy9tiSRiFQTcG1J9k0zlOjy/hfpBl2G1Zce0OoEeuNkH7c0W/idHSloWRZ
+YlK3tVJD6DzY6s9VbO6e/ncecNsXkirkWp/cvMYquH2d4OmSl0/hW0VMdxOCLxkA
+xbW+3Dh05u7tgKVRD67/GRvLtg+xHaOJqiOh3MpMaHy+6xT5Fd5K2QC0pcGtZuqF
+EnnfdeUI/Dy76yQE8pBfjaUFf3TS1n1E6kun1Nkf0X4pvwi8W1goLsPu5sWDNNga
+1RGYj0o5OdIo27qebfmu76WX0fNNd47VabtzNV+W7Msj0yeZg+hxAtAvs0ZEyJh+
+4biWsv+ALSlqz4sSdoOVGUEBdnkUrWN19lou62ix9vTmuCrVEA3TuZA3PR0+hqqQ
+/A/DcmWwxWYKyaBgxwHc/nGo1qWrDh22P5Rp7++Zw3kOCY6QmeJkAiHFs6Crw4ub
+HKVMw3fV5H9oiUFjadPZoCU51uXKX4YRqKxWJ5djlp4r1GCEQHyxngTsmH3komnw
+kh4LsEQRqdhuT0A4sZN7CenMJfQiFqupL7RVSycJFQpgzwVFmOzjCVT4PT/W5ARv
+9YtqEkvyoRTwErwuN/FIVvhWnIP/C69Z1/T/nXyj86P2G7PMgnchIQ==
+-----END CERTIFICATE-----
diff --git a/tests/data/integritycheck/root.key b/tests/data/integritycheck/root.key
new file mode 100644
index 00000000000..557b0a26e3a
--- /dev/null
+++ b/tests/data/integritycheck/root.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEAra2BMIsKboc0TcdS9kp7ZC/82pQOzpMBHLAZ+GLMOO5xHb6e
+uPAFaIU+3flO/g1osTtOsb5QCVIamE11+xBvZ/pgZxvkyDKts5XotCY97qtaRGRP
+XpXxmWnpdrnPIEVzGWBZkpU783sar3yuAdw8KGWjGliXnBDvYsrlMsxzAaRPGx7R
+gzlBsv6EzvVgEm7ZfUX5N/FSy1enLAj8Co4oukN2GfgGFNGKi4NtgcGZapU3sVI1
+gJlSKmqMZkhLimuNV57gCB3z+uaIqG/OrOCLyV1a96+zY3RdiCf2a8JoximloEmS
+nKGQTywK2SXiYiEOGCsy2QE8G2uXVrMFdJmw4/Hj9gRvtNjVSscpTgW3qAREp2oW
+XmeZyeVyma/hKyQFFm+Ne3xJ2GkDQZTZ4o45Kl2g4qZk5LVH57+JZt9LFAIIaOiN
+xmu4EKxT8yoPVeI9kvizk3NR5iTp0ein7bcfsgB2Cyrb1eciDDKc/q2dl+YPzdhn
+YJXmY+VVPZ5is0z3hselfnQWiJKjXvPwF2lZ8bfSkm9N0P/ghYykzQ7RDeXzSbl0
+tPofqKKep4aZLTNou4AqcXizRGkGnqMUedPd1TdNKDiTmAb0KFRhA37RMHRunVm0
+2bCMpARe2ivqfAzMvbQnXNhpxjBLhZVDQPbnL9kb+yHLj3bKZyt9QmaDDSsCAwEA
+AQKCAgEAnR6/JkRTPqTQW6D8W9YMBRoovTF+p8F0GxjxlbUDnmmQKeGeRB7YNbN9
+qWD25n0I/nVx/vj1/UiqyKgjGOvIbZ+kAQPKGJdIb5Qp/nguRTH9qqu45g/ujuSz
+EfaM/Fv4AbgZsLOTlfUDskiwPvyX68/vG1GUbtsfRhfZ+/fb/1s/OYDK99Ufq6f4
+TCbOMD7aQSvBh6upRE5a7Up/gakUDVYkjN/F2KWsmgRfWCjl+vddd+ywfFO4cqkL
+tSioNmSQbPlNIeq/I3fVn9PufJVzwMrVFgh82HeYein1E43ALa3VqcmFem/rVsS4
+V7SfNjlDP/gsuwcT8paGRigUwmScEkyXYJ7oSNEN8Xe4kWWakfwGpa1HmaYPdHx+
+O+G8coHp2kcc/tUZma+Ffo3tNRMfGcpowG+PetbCh4uSNPo5U5U5W53+vxgyZHFi
+lY7gc5HVi5JBSxmWwTa3RDcz1dByWS83NdObrxAntp3W9g8tVj2N9gfUnJS+wp3d
+m8HvO3bzIUuhQcWAtcnXqRAGsl+uc/xgdF2membV/yOHdn2Z1zXKEnjC1T6cEV06
+qocwgp0/EAMhzL4FP8xA9MvztZR7bJOyUihTIadG7Zb18XBea7yA73KvfYGrzjsg
+lmqV4CbGuo0If8SJD03xXthMqi5cBXu4V13sYAbNO8pPDjhfPIkCggEBAOUjScLN
+RoaoOBO3JUWoYauZrf9sa72/zzTOg+c8unQquExMjnsyEVJPD4+TpKGN5/sewwb5
+zksI5c1njOrdFdSKoKlgB/6owv2v70Uqe+HeVA+m5Qy6JSgMAAXZgJ5PtaCCu+Xq
+MOqTd/xInfP1oCecJF9UvqeQJBJN16fMXBib9J5+sLCRJnFNywfmlfAiIOa4MIoY
+Tz7LW+r4Zot0x2o6KcCT8AB3LJIz2seHmTf9Jjk17kw7pFJWtZf6eA1lgDlzadKJ
+iHgrdSbchDZv410B0df/ZV+gZ7PMgK/cbo3H3JOXPV1dxmTONTIIvxYj1LmOdMP4
+p5oeM367LUWQN20CggEBAMIJykbsm7IVthkMeCm/VhG/wd44iB0g5+us8q8pUO1+
+KfTzytHPjMack5a/XaEApRRiJpCAJNcBpUNbJqaOZQ1QqnX6ozlSR2aUi27noVz6
+/heG+3qZElejYfLMpJAF1crjdFJIqKucizc+E6AZ+nOixpJcDABYWby9QQw4O1Pr
+Ii3E7xyFvqizYzE7P/HG6P0gMxta9aKHKGhGHX51Uc+BUfF0T0ymXVvWLlfMg+HI
+SBPqMphW+YR0xwK21A2LvqYBM2MyaThY2wyVSZs9akjiAukRwX8l7lA5A/try0Q0
+1POyN6oo1H7iSHuraqXfDjcSpK5M/QOpXMuoPyTI//cCggEBAKCn00mwH6i+PUMl
+gA6M9p4YTDTwUcJiv+cofLcejyRv53QnoSajfh2VrTVfsWhMVMBvWxKDB674eBdC
+aT0q8elpoSfgWvqkXML+HecC2IUPGyU2QRZhVTf04fc3/sQA4zm9L/0N7GosJ05N
+o+Gu8DGVerMUefCGUaQ7y96snE3s2uBdt4i03J1Ii/foJmyNoT/jGLVaQgWnE7V1
+oIBayo6iZS/PCdFpvWhszxJi8nydE7W9KG1uy9GnVf9O7+mEpxig4StqnrKS1br/
+lfuNC37kjbrCKNOZZdxcoEWtah4iaXdZ7P6Ph1CafBWuqDvft4C6bwgQSYL3ded/
+WUiSyykCggEAePeThF3TvtUsPjd43kXriYsreLdzm/08uL+MWEkAq96gl5Y5Fk43
+LEbG+A77dvko8Skzc5h/3w6mkfRMhz90njVw37ZOddjmrHvk5VJAVfAf4lkDhG3T
+cpFn6e9MlIEexKrChN3JUZt5awonQAOSEO8krm/2B20NHM47tDuGOQ34s+H3U6fJ
+sfCL4VBX0Ao6jDu7wM0XH6j1NvSnRIQtaZjslgP1wApjX3KKV7Anc+XhkZDK1BA8
+5CfNPdLvJja9t04+VBREZp12ikSzq7VBAojsWZL5N6RVCuxQoDiWc0IglIDBlTJ5
+L1Uw7PBzv07s1MappgRXJCY8tLaCDxPEBwKCAQEA1Rxj0YpQ1D+8oFQ3ck0b4ODy
+DCSCNe6Xw+Wzv5BqGVsQCmW14uVBT+S/qij5dTrGIPXudLSHtdjs9tmoDqnkxY/o
+Nj5rx6J2brnNLTD7yo/j74kgaRwSuHafpGX1C0zge0rgIgVu8DhWHan7F/38K0cO
+T1jYJbYcTAvEcO1XXXItnaHR1ETY4p0G5FvUTLWaNQnQTU3r5ZaCkjXN9UBA2k6U
+6j6A9/JXIlNPFNoB103iAD5jvHa96AlivHSyp4UTlsiwAxec316CY2zdWrVWQCF4
+J8DspH3ygeLtvKOveEYsiaiNuJLKREC2GIRUm6O4C/RdP0s0QAODpk+yGCfukg==
+-----END RSA PRIVATE KEY-----
diff --git a/tests/enable_all.php b/tests/enable_all.php
index 464155b1f39..6f2d1fa8717 100644
--- a/tests/enable_all.php
+++ b/tests/enable_all.php
@@ -22,4 +22,4 @@ enableApp('encryption');
enableApp('user_ldap');
enableApp('files_versions');
enableApp('provisioning_api');
-
+enableApp('federation');
diff --git a/tests/karma.config.js b/tests/karma.config.js
index 64a94ef230b..2b569fb7584 100644
--- a/tests/karma.config.js
+++ b/tests/karma.config.js
@@ -67,7 +67,8 @@ module.exports = function(config) {
// up with the global namespace/classes/state
'apps/files_external/js/app.js',
'apps/files_external/js/mountsfilelist.js',
- 'apps/files_external/js/settings.js'
+ 'apps/files_external/js/settings.js',
+ 'apps/files_external/js/statusmanager.js'
],
testFiles: ['apps/files_external/tests/js/*.js']
},
@@ -82,6 +83,29 @@ module.exports = function(config) {
testFiles: ['apps/files_versions/tests/js/**/*.js']
},
{
+ name: 'comments',
+ srcFiles: [
+ // need to enforce loading order...
+ 'apps/comments/js/app.js',
+ 'apps/comments/js/commentmodel.js',
+ 'apps/comments/js/commentcollection.js',
+ 'apps/comments/js/commentsummarymodel.js',
+ 'apps/comments/js/commentstabview.js',
+ 'apps/comments/js/filesplugin.js'
+ ],
+ testFiles: ['apps/comments/tests/js/**/*.js']
+ },
+ {
+ name: 'systemtags',
+ srcFiles: [
+ // need to enforce loading order...
+ 'apps/systemtags/js/app.js',
+ 'apps/systemtags/js/systemtagsinfoview.js',
+ 'apps/systemtags/js/filesplugin.js'
+ ],
+ testFiles: ['apps/systemtags/tests/js/**/*.js']
+ },
+ {
name: 'settings',
srcFiles: [
'settings/js/apps.js',
@@ -164,15 +188,15 @@ module.exports = function(config) {
// need to test the core app as well ?
if (testCore) {
// core tests
- files.push(corePath + 'tests/specs/*.js');
+ files.push(corePath + 'tests/specs/**/*.js');
}
function addApp(app) {
// if only a string was specified, expand to structure
if (typeof(app) === 'string') {
app = {
- srcFiles: 'apps/' + app + '/js/*.js',
- testFiles: 'apps/' + app + '/tests/js/*.js'
+ srcFiles: 'apps/' + app + '/js/**/*.js',
+ testFiles: 'apps/' + app + '/tests/js/**/*.js'
};
}
diff --git a/tests/lib/allconfig.php b/tests/lib/allconfig.php
index 7f8ad5ec221..869bf9b8d66 100644
--- a/tests/lib/allconfig.php
+++ b/tests/lib/allconfig.php
@@ -8,6 +8,13 @@
namespace Test;
+/**
+ * Class TestAllConfig
+ *
+ * @group DB
+ *
+ * @package Test
+ */
class TestAllConfig extends \Test\TestCase {
/** @var \OCP\IDBConnection */
@@ -21,7 +28,9 @@ class TestAllConfig extends \Test\TestCase {
$connection = $this->connection;
}
if($systemConfig === null) {
- $systemConfig = $this->getMock('\OC\SystemConfig');
+ $systemConfig = $this->getMockBuilder('\OC\SystemConfig')
+ ->disableOriginalConstructor()
+ ->getMock();
}
return new \OC\AllConfig($systemConfig, $connection);
}
@@ -81,14 +90,7 @@ class TestAllConfig extends \Test\TestCase {
}
public function testSetUserValueWithPreCondition() {
- // mock the check for the database to run the correct SQL statements for each database type
- $systemConfig = $this->getMock('\OC\SystemConfig');
- $systemConfig->expects($this->once())
- ->method('getValue')
- ->with($this->equalTo('dbtype'),
- $this->equalTo('sqlite'))
- ->will($this->returnValue(\OC::$server->getConfig()->getSystemValue('dbtype', 'sqlite')));
- $config = $this->getConfig($systemConfig);
+ $config = $this->getConfig();
$selectAllSQL = 'SELECT `userid`, `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?';
@@ -125,14 +127,7 @@ class TestAllConfig extends \Test\TestCase {
* @expectedException \OCP\PreConditionNotMetException
*/
public function testSetUserValueWithPreConditionFailure() {
- // mock the check for the database to run the correct SQL statements for each database type
- $systemConfig = $this->getMock('\OC\SystemConfig');
- $systemConfig->expects($this->once())
- ->method('getValue')
- ->with($this->equalTo('dbtype'),
- $this->equalTo('sqlite'))
- ->will($this->returnValue(\OC::$server->getConfig()->getSystemValue('dbtype', 'sqlite')));
- $config = $this->getConfig($systemConfig);
+ $config = $this->getConfig();
$selectAllSQL = 'SELECT `userid`, `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?';
@@ -387,7 +382,9 @@ class TestAllConfig extends \Test\TestCase {
public function testGetUsersForUserValue() {
// mock the check for the database to run the correct SQL statements for each database type
- $systemConfig = $this->getMock('\OC\SystemConfig');
+ $systemConfig = $this->getMockBuilder('\OC\SystemConfig')
+ ->disableOriginalConstructor()
+ ->getMock();
$systemConfig->expects($this->once())
->method('getValue')
->with($this->equalTo('dbtype'),
diff --git a/tests/lib/app.php b/tests/lib/app.php
index 485091cee4c..389c9e5d2cf 100644
--- a/tests/lib/app.php
+++ b/tests/lib/app.php
@@ -1,5 +1,4 @@
<?php
-
/**
* Copyright (c) 2012 Bernhard Posselt <dev@bernhard-posselt.com>
* Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com>
@@ -7,6 +6,12 @@
* later.
* See the COPYING-README file.
*/
+
+/**
+ * Class Test_App
+ *
+ * @group DB
+ */
class Test_App extends \Test\TestCase {
const TEST_USER1 = 'user1';
@@ -306,6 +311,7 @@ class Test_App extends \Test\TestCase {
'app3',
'appforgroup1',
'appforgroup12',
+ 'dav',
),
false
),
@@ -318,6 +324,7 @@ class Test_App extends \Test\TestCase {
'app3',
'appforgroup12',
'appforgroup2',
+ 'dav',
),
false
),
@@ -331,6 +338,7 @@ class Test_App extends \Test\TestCase {
'appforgroup1',
'appforgroup12',
'appforgroup2',
+ 'dav',
),
false
),
@@ -344,6 +352,7 @@ class Test_App extends \Test\TestCase {
'appforgroup1',
'appforgroup12',
'appforgroup2',
+ 'dav',
),
false,
),
@@ -357,6 +366,7 @@ class Test_App extends \Test\TestCase {
'appforgroup1',
'appforgroup12',
'appforgroup2',
+ 'dav',
),
true,
),
@@ -434,11 +444,11 @@ class Test_App extends \Test\TestCase {
);
$apps = \OC_App::getEnabledApps(true);
- $this->assertEquals(array('files', 'app3'), $apps);
+ $this->assertEquals(array('files', 'app3', 'dav'), $apps);
// mock should not be called again here
$apps = \OC_App::getEnabledApps(false);
- $this->assertEquals(array('files', 'app3'), $apps);
+ $this->assertEquals(array('files', 'app3', 'dav'), $apps);
$this->restoreAppConfig();
\OC_User::setUserId(null);
@@ -451,7 +461,7 @@ class Test_App extends \Test\TestCase {
$appConfig = $this->getMock(
'\OC\AppConfig',
array('getValues'),
- array(\OC_DB::getConnection()),
+ array(\OC::$server->getDatabaseConnection()),
'',
false
);
@@ -478,8 +488,8 @@ class Test_App extends \Test\TestCase {
* Restore the original app config service.
*/
private function restoreAppConfig() {
- \OC::$server->registerService('AppConfig', function ($c) {
- return new \OC\AppConfig(\OC_DB::getConnection());
+ \OC::$server->registerService('AppConfig', function (\OC\Server $c) {
+ return new \OC\AppConfig($c->getDatabaseConnection());
});
\OC::$server->registerService('AppManager', function (\OC\Server $c) {
return new \OC\App\AppManager($c->getUserSession(), $c->getAppConfig(), $c->getGroupManager(), $c->getMemCacheFactory());
diff --git a/tests/lib/app/dependencyanalyzer.php b/tests/lib/app/dependencyanalyzer.php
index 58f1c0a7a99..fecba518856 100644
--- a/tests/lib/app/dependencyanalyzer.php
+++ b/tests/lib/app/dependencyanalyzer.php
@@ -12,8 +12,9 @@ namespace Test\App;
use OC;
use OC\App\Platform;
use OCP\IL10N;
+use Test\TestCase;
-class DependencyAnalyzer extends \PHPUnit_Framework_TestCase {
+class DependencyAnalyzer extends TestCase {
/** @var Platform */
private $platformMock;
diff --git a/tests/lib/app/infoparser.php b/tests/lib/app/infoparser.php
index fb4ffe8af94..1e5257abec3 100644
--- a/tests/lib/app/infoparser.php
+++ b/tests/lib/app/infoparser.php
@@ -10,8 +10,9 @@
namespace Test\App;
use OC;
+use Test\TestCase;
-class InfoParser extends \PHPUnit_Framework_TestCase {
+class InfoParser extends TestCase {
/**
* @var \OC\App\InfoParser
diff --git a/tests/lib/app/manager.php b/tests/lib/app/manager.php
index 7333d7601b1..f82f1049ce3 100644
--- a/tests/lib/app/manager.php
+++ b/tests/lib/app/manager.php
@@ -11,8 +11,15 @@ namespace Test\App;
use OC\Group\Group;
use OC\User\User;
+use Test\TestCase;
-class Manager extends \PHPUnit_Framework_TestCase {
+/**
+ * Class Manager
+ *
+ * @package Test\App
+ * @group DB
+ */
+class Manager extends TestCase {
/**
* @return \OCP\IAppConfig | \PHPUnit_Framework_MockObject_MockObject
*/
@@ -115,6 +122,93 @@ class Manager extends \PHPUnit_Framework_TestCase {
$this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
}
+ public function dataEnableAppForGroupsAllowedTypes() {
+ return [
+ [[]],
+ [[
+ 'types' => [],
+ ]],
+ [[
+ 'types' => ['nickvergessen'],
+ ]],
+ ];
+ }
+
+ /**
+ * @dataProvider dataEnableAppForGroupsAllowedTypes
+ *
+ * @param array $appInfo
+ */
+ public function testEnableAppForGroupsAllowedTypes(array $appInfo) {
+ $groups = array(
+ new Group('group1', array(), null),
+ new Group('group2', array(), null)
+ );
+ $this->expectClearCache();
+
+ /** @var \OC\App\AppManager|\PHPUnit_Framework_MockObject_MockObject $manager */
+ $manager = $this->getMockBuilder('OC\App\AppManager')
+ ->setConstructorArgs([
+ $this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory
+ ])
+ ->setMethods([
+ 'getAppInfo'
+ ])
+ ->getMock();
+
+ $manager->expects($this->once())
+ ->method('getAppInfo')
+ ->with('test')
+ ->willReturn($appInfo);
+
+ $manager->enableAppForGroups('test', $groups);
+ $this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
+ }
+
+ public function dataEnableAppForGroupsForbiddenTypes() {
+ return [
+ ['filesystem'],
+ ['prelogin'],
+ ['authentication'],
+ ['logging'],
+ ['prevent_group_restriction'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataEnableAppForGroupsForbiddenTypes
+ *
+ * @param string $type
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage test can't be enabled for groups.
+ */
+ public function testEnableAppForGroupsForbiddenTypes($type) {
+ $groups = array(
+ new Group('group1', array(), null),
+ new Group('group2', array(), null)
+ );
+
+ /** @var \OC\App\AppManager|\PHPUnit_Framework_MockObject_MockObject $manager */
+ $manager = $this->getMockBuilder('OC\App\AppManager')
+ ->setConstructorArgs([
+ $this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory
+ ])
+ ->setMethods([
+ 'getAppInfo'
+ ])
+ ->getMock();
+
+ $manager->expects($this->once())
+ ->method('getAppInfo')
+ ->with('test')
+ ->willReturn([
+ 'types' => [$type],
+ ]);
+
+ $manager->enableAppForGroups('test', $groups);
+ }
+
public function testIsInstalledEnabled() {
$this->appConfig->setValue('test', 'enabled', 'yes');
$this->assertTrue($this->manager->isInstalled('test'));
@@ -188,7 +282,7 @@ class Manager extends \PHPUnit_Framework_TestCase {
$this->appConfig->setValue('test1', 'enabled', 'yes');
$this->appConfig->setValue('test2', 'enabled', 'no');
$this->appConfig->setValue('test3', 'enabled', '["foo"]');
- $this->assertEquals(['test1', 'test3'], $this->manager->getInstalledApps());
+ $this->assertEquals(['dav', 'files', 'test1', 'test3'], $this->manager->getInstalledApps());
}
public function testGetAppsForUser() {
@@ -202,7 +296,7 @@ class Manager extends \PHPUnit_Framework_TestCase {
$this->appConfig->setValue('test2', 'enabled', 'no');
$this->appConfig->setValue('test3', 'enabled', '["foo"]');
$this->appConfig->setValue('test4', 'enabled', '["asd"]');
- $this->assertEquals(['test1', 'test3'], $this->manager->getEnabledAppsForUser($user));
+ $this->assertEquals(['dav', 'files', 'test1', 'test3'], $this->manager->getEnabledAppsForUser($user));
}
public function testGetAppsNeedingUpgrade() {
@@ -212,6 +306,8 @@ class Manager extends \PHPUnit_Framework_TestCase {
->getMock();
$appInfos = [
+ 'dav' => ['id' => 'dav'],
+ 'files' => ['id' => 'files'],
'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '9.0.0'],
'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
@@ -250,6 +346,8 @@ class Manager extends \PHPUnit_Framework_TestCase {
->getMock();
$appInfos = [
+ 'dav' => ['id' => 'dav'],
+ 'files' => ['id' => 'files'],
'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '8.0.0'],
'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
diff --git a/tests/lib/appconfig.php b/tests/lib/appconfig.php
index 98420abe7bc..64f0f80e045 100644
--- a/tests/lib/appconfig.php
+++ b/tests/lib/appconfig.php
@@ -11,6 +11,13 @@ namespace Test\Lib;
use Test\TestCase;
+/**
+ * Class AppConfig
+ *
+ * @group DB
+ *
+ * @package Test\Lib
+ */
class AppConfig extends TestCase {
/** @var \OCP\IAppConfig */
protected $appConfig;
diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php
index 05190ca09b5..3d41d6590aa 100644
--- a/tests/lib/appframework/AppTest.php
+++ b/tests/lib/appframework/AppTest.php
@@ -79,9 +79,9 @@ class AppTest extends \Test\TestCase {
$this->container['OCP\\AppFramework\\Http\\IOutput'] = $this->io;
$this->container['urlParams'] = array();
- $this->appPath = __DIR__ . '/../../../apps/namespacetestapp/appinfo';
- $infoXmlPath = $this->appPath . '/info.xml';
- mkdir($this->appPath, 0777, true);
+ $this->appPath = __DIR__ . '/../../../apps/namespacetestapp';
+ $infoXmlPath = $this->appPath . '/appinfo/info.xml';
+ mkdir($this->appPath . '/appinfo', 0777, true);
$xml = '<?xml version="1.0" encoding="UTF-8"?>' .
'<info>' .
@@ -128,6 +128,7 @@ class AppTest extends \Test\TestCase {
protected function tearDown() {
rrmdir($this->appPath);
+ parent::tearDown();
}
diff --git a/tests/lib/appframework/dependencyinjection/DIContainerTest.php b/tests/lib/appframework/dependencyinjection/DIContainerTest.php
index 0cbdddbb205..fc15b5a44ee 100644
--- a/tests/lib/appframework/dependencyinjection/DIContainerTest.php
+++ b/tests/lib/appframework/dependencyinjection/DIContainerTest.php
@@ -36,7 +36,9 @@ class DIContainerTest extends \Test\TestCase {
protected function setUp(){
parent::setUp();
- $this->container = new DIContainer('name');
+ $this->container = $this->getMock('OC\AppFramework\DependencyInjection\DIContainer',
+ ['isAdminUser'], ['name']
+ );
$this->api = $this->getMock('OC\AppFramework\Core\API', array(), array('hi'));
}
diff --git a/tests/lib/appframework/http/ContentSecurityPolicyTest.php b/tests/lib/appframework/http/ContentSecurityPolicyTest.php
index 6d9c6d7b8d9..adf03185e9f 100644
--- a/tests/lib/appframework/http/ContentSecurityPolicyTest.php
+++ b/tests/lib/appframework/http/ContentSecurityPolicyTest.php
@@ -426,21 +426,4 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
-
- public function testConfigureStacked() {
- $expectedPolicy = "default-src 'none';script-src 'self' script.owncloud.org;style-src 'self' style.owncloud.org;img-src 'self' data: blob: img.owncloud.org;font-src 'self' font.owncloud.org;connect-src 'self' connect.owncloud.org;media-src 'self' media.owncloud.org;object-src objects.owncloud.org;frame-src frame.owncloud.org;child-src child.owncloud.org";
-
- $this->contentSecurityPolicy->allowInlineStyle(false)
- ->allowEvalScript(false)
- ->addAllowedScriptDomain('script.owncloud.org')
- ->addAllowedStyleDomain('style.owncloud.org')
- ->addAllowedFontDomain('font.owncloud.org')
- ->addAllowedImageDomain('img.owncloud.org')
- ->addAllowedConnectDomain('connect.owncloud.org')
- ->addAllowedMediaDomain('media.owncloud.org')
- ->addAllowedObjectDomain('objects.owncloud.org')
- ->addAllowedChildSrcDomain('child.owncloud.org')
- ->addAllowedFrameDomain('frame.owncloud.org');
- $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
- }
}
diff --git a/tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php b/tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php
new file mode 100644
index 00000000000..0d0f92de819
--- /dev/null
+++ b/tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php
@@ -0,0 +1,430 @@
+<?php
+/**
+ * Copyright (c) 2015 Lukas Reschke lukas@owncloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+
+namespace OC\AppFramework\Http;
+
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
+
+/**
+ * Class ContentSecurityPolicyTest
+ *
+ * @package OC\AppFramework\Http
+ */
+class EmptyContentSecurityPolicyTest extends \Test\TestCase {
+
+ /** @var EmptyContentSecurityPolicy */
+ private $contentSecurityPolicy;
+
+ public function setUp() {
+ parent::setUp();
+ $this->contentSecurityPolicy = new EmptyContentSecurityPolicy();
+ }
+
+ public function testGetPolicyDefault() {
+ $defaultPolicy = "default-src 'none'";
+ $this->assertSame($defaultPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptDomainValid() {
+ $expectedPolicy = "default-src 'none';script-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';script-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowScriptDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowScriptDomainMultiple() {
+ $expectedPolicy = "default-src 'none';script-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowScriptDomainMultipleStacked() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org')->disallowScriptDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptAllowInline() {
+ $expectedPolicy = "default-src 'none';script-src 'unsafe-inline'";
+
+ $this->contentSecurityPolicy->allowInlineScript(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptAllowInlineWithDomain() {
+ $expectedPolicy = "default-src 'none';script-src www.owncloud.com 'unsafe-inline'";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->allowInlineScript(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptAllowInlineAndEval() {
+ $expectedPolicy = "default-src 'none';script-src 'unsafe-inline' 'unsafe-eval'";
+
+ $this->contentSecurityPolicy->allowInlineScript(true);
+ $this->contentSecurityPolicy->allowEvalScript(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleDomainValid() {
+ $expectedPolicy = "default-src 'none';style-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';style-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowStyleDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowStyleDomainMultiple() {
+ $expectedPolicy = "default-src 'none';style-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowStyleDomainMultipleStacked() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org')->disallowStyleDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleAllowInline() {
+ $expectedPolicy = "default-src 'none';style-src 'unsafe-inline'";
+
+ $this->contentSecurityPolicy->allowInlineStyle(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleAllowInlineWithDomain() {
+ $expectedPolicy = "default-src 'none';style-src www.owncloud.com 'unsafe-inline'";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->allowInlineStyle(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleDisallowInline() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->allowInlineStyle(false);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyImageDomainValid() {
+ $expectedPolicy = "default-src 'none';img-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyImageDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';img-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowImageDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowImageDomainMultiple() {
+ $expectedPolicy = "default-src 'none';img-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowImageDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org')->disallowImageDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyFontDomainValid() {
+ $expectedPolicy = "default-src 'none';font-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyFontDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';font-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFontDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFontDomainMultiple() {
+ $expectedPolicy = "default-src 'none';font-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFontDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org')->disallowFontDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyConnectDomainValid() {
+ $expectedPolicy = "default-src 'none';connect-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyConnectDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';connect-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowConnectDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowConnectDomainMultiple() {
+ $expectedPolicy = "default-src 'none';connect-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowConnectDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org')->disallowConnectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyMediaDomainValid() {
+ $expectedPolicy = "default-src 'none';media-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyMediaDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';media-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowMediaDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowMediaDomainMultiple() {
+ $expectedPolicy = "default-src 'none';media-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowMediaDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org')->disallowMediaDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyObjectDomainValid() {
+ $expectedPolicy = "default-src 'none';object-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyObjectDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';object-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowObjectDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowObjectDomainMultiple() {
+ $expectedPolicy = "default-src 'none';object-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowObjectDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org')->disallowObjectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetAllowedFrameDomain() {
+ $expectedPolicy = "default-src 'none';frame-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyFrameDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';frame-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFrameDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFrameDomainMultiple() {
+ $expectedPolicy = "default-src 'none';frame-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFrameDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org')->disallowFrameDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetAllowedChildSrcDomain() {
+ $expectedPolicy = "default-src 'none';child-src child.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyChildSrcValidMultiple() {
+ $expectedPolicy = "default-src 'none';child-src child.owncloud.com child.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowChildSrcDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowChildSrcDomainMultiple() {
+ $expectedPolicy = "default-src 'none';child-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowChildSrcDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+}
diff --git a/tests/lib/appframework/http/RequestTest.php b/tests/lib/appframework/http/RequestTest.php
index f628a30f1da..3f1d09c2a93 100644
--- a/tests/lib/appframework/http/RequestTest.php
+++ b/tests/lib/appframework/http/RequestTest.php
@@ -10,7 +10,8 @@
namespace OC\AppFramework\Http;
-use OC\Security\Crypto;
+use OC\Security\CSRF\CsrfToken;
+use OC\Security\CSRF\CsrfTokenManager;
use OCP\Security\ISecureRandom;
use OCP\IConfig;
@@ -26,6 +27,8 @@ class RequestTest extends \Test\TestCase {
protected $secureRandom;
/** @var IConfig */
protected $config;
+ /** @var CsrfTokenManager */
+ protected $csrfTokenManager;
protected function setUp() {
parent::setUp();
@@ -38,6 +41,8 @@ class RequestTest extends \Test\TestCase {
$this->secureRandom = $this->getMockBuilder('\OCP\Security\ISecureRandom')->getMock();
$this->config = $this->getMockBuilder('\OCP\IConfig')->getMock();
+ $this->csrfTokenManager = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenManager')
+ ->disableOriginalConstructor()->getMock();
}
protected function tearDown() {
@@ -55,6 +60,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -87,6 +93,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -109,6 +116,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -128,6 +136,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -147,6 +156,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -163,6 +173,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -184,6 +195,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -207,6 +219,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -228,6 +241,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -252,6 +266,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -272,6 +287,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -296,6 +312,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -325,6 +342,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -346,6 +364,7 @@ class RequestTest extends \Test\TestCase {
$vars,
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -353,22 +372,16 @@ class RequestTest extends \Test\TestCase {
}
public function testGetIdWithoutModUnique() {
- $lowRandomSource = $this->getMockBuilder('\OCP\Security\ISecureRandom')
- ->disableOriginalConstructor()->getMock();
- $lowRandomSource->expects($this->once())
+ $this->secureRandom->expects($this->once())
->method('generate')
->with('20')
->will($this->returnValue('GeneratedByOwnCloudItself'));
- $this->secureRandom
- ->expects($this->once())
- ->method('getLowStrengthGenerator')
- ->will($this->returnValue($lowRandomSource));
-
$request = new Request(
[],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -380,6 +393,7 @@ class RequestTest extends \Test\TestCase {
[],
\OC::$server->getSecureRandom(),
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
$firstId = $request->getId();
@@ -404,6 +418,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -432,6 +447,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -460,6 +476,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -492,6 +509,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -542,6 +560,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -569,6 +588,7 @@ class RequestTest extends \Test\TestCase {
[],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -590,6 +610,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
$requestHttp = new Request(
@@ -600,6 +621,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -623,6 +645,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
$this->assertSame('https', $request->getServerProtocol());
@@ -643,6 +666,28 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
+ $this->stream
+ );
+ $this->assertSame('http', $request->getServerProtocol());
+ }
+
+ public function testGetServerProtocolWithHttpsServerValueEmpty() {
+ $this->config
+ ->expects($this->once())
+ ->method('getSystemValue')
+ ->with('overwriteprotocol')
+ ->will($this->returnValue(''));
+
+ $request = new Request(
+ [
+ 'server' => [
+ 'HTTPS' => ''
+ ],
+ ],
+ $this->secureRandom,
+ $this->config,
+ $this->csrfTokenManager,
$this->stream
);
$this->assertSame('http', $request->getServerProtocol());
@@ -659,6 +704,7 @@ class RequestTest extends \Test\TestCase {
[],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
$this->assertSame('http', $request->getServerProtocol());
@@ -679,6 +725,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -693,20 +740,39 @@ class RequestTest extends \Test\TestCase {
*/
public function testUserAgent($testAgent, $userAgent, $matches) {
$request = new Request(
- [
- 'server' => [
- 'HTTP_USER_AGENT' => $testAgent,
- ]
- ],
- $this->secureRandom,
- $this->config,
- $this->stream
+ [
+ 'server' => [
+ 'HTTP_USER_AGENT' => $testAgent,
+ ]
+ ],
+ $this->secureRandom,
+ $this->config,
+ $this->csrfTokenManager,
+ $this->stream
);
$this->assertSame($matches, $request->isUserAgent($userAgent));
}
/**
+ * @dataProvider userAgentProvider
+ * @param string $testAgent
+ * @param array $userAgent
+ * @param bool $matches
+ */
+ public function testUndefinedUserAgent($testAgent, $userAgent, $matches) {
+ $request = new Request(
+ [],
+ $this->secureRandom,
+ $this->config,
+ $this->csrfTokenManager,
+ $this->stream
+ );
+
+ $this->assertFalse($request->isUserAgent($userAgent));
+ }
+
+ /**
* @return array
*/
function userAgentProvider() {
@@ -788,6 +854,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -804,6 +871,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -821,6 +889,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -838,6 +907,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -865,6 +935,7 @@ class RequestTest extends \Test\TestCase {
[],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -886,6 +957,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -912,6 +984,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -938,6 +1011,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -954,6 +1028,7 @@ class RequestTest extends \Test\TestCase {
[],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -981,6 +1056,7 @@ class RequestTest extends \Test\TestCase {
[],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -996,6 +1072,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -1016,6 +1093,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -1036,6 +1114,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -1058,6 +1137,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -1080,6 +1160,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -1102,6 +1183,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -1124,6 +1206,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -1178,6 +1261,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
);
@@ -1217,6 +1301,7 @@ class RequestTest extends \Test\TestCase {
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
])
->getMock();
@@ -1237,13 +1322,19 @@ class RequestTest extends \Test\TestCase {
'get' => [
'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
],
- 'requesttoken' => 'MyStoredRequestToken',
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
])
->getMock();
+ $token = new CsrfToken('AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds');
+ $this->csrfTokenManager
+ ->expects($this->once())
+ ->method('isTokenValid')
+ ->with($token)
+ ->willReturn(true);
$this->assertTrue($request->passesCSRFCheck());
}
@@ -1257,13 +1348,19 @@ class RequestTest extends \Test\TestCase {
'post' => [
'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
],
- 'requesttoken' => 'MyStoredRequestToken',
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
])
->getMock();
+ $token = new CsrfToken('AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds');
+ $this->csrfTokenManager
+ ->expects($this->once())
+ ->method('isTokenValid')
+ ->with($token)
+ ->willReturn(true);
$this->assertTrue($request->passesCSRFCheck());
}
@@ -1277,13 +1374,19 @@ class RequestTest extends \Test\TestCase {
'server' => [
'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
],
- 'requesttoken' => 'MyStoredRequestToken',
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
])
->getMock();
+ $token = new CsrfToken('AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds');
+ $this->csrfTokenManager
+ ->expects($this->once())
+ ->method('isTokenValid')
+ ->with($token)
+ ->willReturn(true);
$this->assertTrue($request->passesCSRFCheck());
}
@@ -1313,14 +1416,21 @@ class RequestTest extends \Test\TestCase {
'server' => [
'HTTP_REQUESTTOKEN' => $invalidToken,
],
- 'requesttoken' => 'MyStoredRequestToken',
],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
])
->getMock();
+ $token = new CsrfToken($invalidToken);
+ $this->csrfTokenManager
+ ->expects($this->any())
+ ->method('isTokenValid')
+ ->with($token)
+ ->willReturn(false);
+
$this->assertFalse($request->passesCSRFCheck());
}
@@ -1332,6 +1442,7 @@ class RequestTest extends \Test\TestCase {
[],
$this->secureRandom,
$this->config,
+ $this->csrfTokenManager,
$this->stream
])
->getMock();
diff --git a/tests/lib/appframework/middleware/security/CORSMiddlewareTest.php b/tests/lib/appframework/middleware/security/CORSMiddlewareTest.php
index ca526fb859c..cf5f97a046f 100644
--- a/tests/lib/appframework/middleware/security/CORSMiddlewareTest.php
+++ b/tests/lib/appframework/middleware/security/CORSMiddlewareTest.php
@@ -14,7 +14,7 @@ namespace OC\AppFramework\Middleware\Security;
use OC\AppFramework\Http\Request;
use OC\AppFramework\Utility\ControllerMethodReflector;
-
+use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
@@ -91,7 +91,7 @@ class CORSMiddlewareTest extends \Test\TestCase {
/**
* @CORS
- * @expectedException \OC\AppFramework\Middleware\Security\SecurityException
+ * @expectedException \OC\AppFramework\Middleware\Security\Exceptions\SecurityException
*/
public function testCorsIgnoredIfWithCredentialsHeaderPresent() {
$request = new Request(
@@ -160,7 +160,7 @@ class CORSMiddlewareTest extends \Test\TestCase {
/**
* @CORS
- * @expectedException \OC\AppFramework\Middleware\Security\SecurityException
+ * @expectedException \OC\AppFramework\Middleware\Security\Exceptions\SecurityException
*/
public function testCORSShouldNotAllowCookieAuth() {
$request = new Request(
diff --git a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php
index 347a0423ea6..9e71a3d0961 100644
--- a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php
+++ b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php
@@ -1,34 +1,41 @@
<?php
-
/**
- * ownCloud - App Framework
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
*
- * @author Bernhard Posselt
- * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
*
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
*
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
+
namespace OC\AppFramework\Middleware\Security;
use OC\AppFramework\Http;
use OC\AppFramework\Http\Request;
+use OC\Appframework\Middleware\Security\Exceptions\AppNotEnabledException;
+use OC\Appframework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException;
+use OC\Appframework\Middleware\Security\Exceptions\NotAdminException;
+use OC\Appframework\Middleware\Security\Exceptions\NotLoggedInException;
+use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\Security\CSP\ContentSecurityPolicy;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Http\TemplateResponse;
class SecurityMiddlewareTest extends \Test\TestCase {
@@ -42,6 +49,7 @@ class SecurityMiddlewareTest extends \Test\TestCase {
private $logger;
private $navigationManager;
private $urlGenerator;
+ private $contentSecurityPolicyManager;
protected function setUp() {
parent::setUp();
@@ -66,13 +74,21 @@ class SecurityMiddlewareTest extends \Test\TestCase {
'OCP\IRequest')
->disableOriginalConstructor()
->getMock();
+ $this->contentSecurityPolicyManager = $this->getMockBuilder(
+ 'OC\Security\CSP\ContentSecurityPolicyManager')
+ ->disableOriginalConstructor()
+ ->getMock();
$this->middleware = $this->getMiddleware(true, true);
$this->secException = new SecurityException('hey', false);
$this->secAjaxException = new SecurityException('hey', true);
}
-
- private function getMiddleware($isLoggedIn, $isAdminUser){
+ /**
+ * @param bool $isLoggedIn
+ * @param bool $isAdminUser
+ * @return SecurityMiddleware
+ */
+ private function getMiddleware($isLoggedIn, $isAdminUser) {
return new SecurityMiddleware(
$this->request,
$this->reader,
@@ -81,7 +97,8 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->logger,
'files',
$isLoggedIn,
- $isAdminUser
+ $isAdminUser,
+ $this->contentSecurityPolicyManager
);
}
@@ -219,8 +236,8 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$sec = $this->getMiddleware($isLoggedIn, $isAdminUser);
- if($shouldFail){
- $this->setExpectedException('\OC\AppFramework\Middleware\Security\SecurityException');
+ if($shouldFail) {
+ $this->setExpectedException('\OC\AppFramework\Middleware\Security\Exceptions\SecurityException');
} else {
$this->assertTrue(true);
}
@@ -232,7 +249,7 @@ class SecurityMiddlewareTest extends \Test\TestCase {
/**
* @PublicPage
- * @expectedException \OC\AppFramework\Middleware\Security\SecurityException
+ * @expectedException \OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException
*/
public function testCsrfCheck(){
$this->request->expects($this->once())
@@ -311,25 +328,85 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->middleware->afterException($this->controller, 'test', $ex);
}
-
- public function testAfterExceptionReturnsRedirect(){
+ public function testAfterExceptionReturnsRedirectForNotLoggedInUser() {
$this->request = new Request(
- [
- 'server' =>
[
- 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
- 'REQUEST_URI' => 'owncloud/index.php/apps/specialapp'
- ]
+ 'server' =>
+ [
+ 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+ 'REQUEST_URI' => 'owncloud/index.php/apps/specialapp'
+ ]
+ ],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->middleware = $this->getMiddleware(false, false);
+ $this->urlGenerator
+ ->expects($this->once())
+ ->method('getAbsoluteURL')
+ ->with('index.php')
+ ->will($this->returnValue('http://localhost/index.php'));
+ $this->logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('Current user is not logged in');
+ $response = $this->middleware->afterException(
+ $this->controller,
+ 'test',
+ new NotLoggedInException()
+ );
+
+ $expected = new RedirectResponse('http://localhost/index.php?redirect_url=owncloud%2Findex.php%2Fapps%2Fspecialapp');
+ $this->assertEquals($expected , $response);
+ }
+
+ /**
+ * @return array
+ */
+ public function exceptionProvider() {
+ return [
+ [
+ new AppNotEnabledException(),
+ ],
+ [
+ new CrossSiteRequestForgeryException(),
+ ],
+ [
+ new NotAdminException(),
],
- $this->getMock('\OCP\Security\ISecureRandom'),
- $this->getMock('\OCP\IConfig')
+ ];
+ }
+
+ /**
+ * @dataProvider exceptionProvider
+ * @param SecurityException $exception
+ */
+ public function testAfterExceptionReturnsTemplateResponse(SecurityException $exception) {
+ $this->request = new Request(
+ [
+ 'server' =>
+ [
+ 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+ 'REQUEST_URI' => 'owncloud/index.php/apps/specialapp'
+ ]
+ ],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->middleware = $this->getMiddleware(false, false);
+ $this->logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with($exception->getMessage());
+ $response = $this->middleware->afterException(
+ $this->controller,
+ 'test',
+ $exception
);
- $this->middleware = $this->getMiddleware(true, true);
- $response = $this->middleware->afterException($this->controller, 'test',
- $this->secException);
- $this->assertTrue($response instanceof RedirectResponse);
- $this->assertEquals('?redirect_url=owncloud%2Findex.php%2Fapps%2Fspecialapp', $response->getRedirectURL());
+ $expected = new TemplateResponse('core', '403', ['file' => $exception->getMessage()], 'guest');
+ $expected->setStatus($exception->getCode());
+ $this->assertEquals($expected , $response);
}
@@ -340,5 +417,31 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->assertTrue($response instanceof JSONResponse);
}
-
+ public function testAfterController() {
+ $response = $this->getMockBuilder('\OCP\AppFramework\Http\Response')->disableOriginalConstructor()->getMock();
+ $defaultPolicy = new ContentSecurityPolicy();
+ $defaultPolicy->addAllowedImageDomain('defaultpolicy');
+ $currentPolicy = new ContentSecurityPolicy();
+ $currentPolicy->addAllowedConnectDomain('currentPolicy');
+ $mergedPolicy = new ContentSecurityPolicy();
+ $mergedPolicy->addAllowedMediaDomain('mergedPolicy');
+ $response
+ ->expects($this->exactly(2))
+ ->method('getContentSecurityPolicy')
+ ->willReturn($currentPolicy);
+ $this->contentSecurityPolicyManager
+ ->expects($this->once())
+ ->method('getDefaultPolicy')
+ ->willReturn($defaultPolicy);
+ $this->contentSecurityPolicyManager
+ ->expects($this->once())
+ ->method('mergePolicies')
+ ->with($defaultPolicy, $currentPolicy)
+ ->willReturn($mergedPolicy);
+ $response->expects($this->once())
+ ->method('setContentSecurityPolicy')
+ ->with($mergedPolicy);
+
+ $this->middleware->afterController($this->controller, 'test', $response);
+ }
}
diff --git a/tests/lib/appframework/routing/RoutingTest.php b/tests/lib/appframework/routing/RoutingTest.php
index 51c191fdfb7..b063ef32835 100644
--- a/tests/lib/appframework/routing/RoutingTest.php
+++ b/tests/lib/appframework/routing/RoutingTest.php
@@ -74,7 +74,7 @@ class RoutingTest extends \Test\TestCase
));
// router mock
- $router = $this->getMock("\OC\Route\Router", array('create'));
+ $router = $this->getMock("\OC\Route\Router", array('create'), [\OC::$server->getLogger()]);
// load route configuration
$container = new DIContainer('app1');
@@ -124,7 +124,7 @@ class RoutingTest extends \Test\TestCase
$route = $this->mockRoute($container, $verb, $controllerName, $actionName, $requirements, $defaults);
// router mock
- $router = $this->getMock("\OC\Route\Router", array('create'));
+ $router = $this->getMock("\OC\Route\Router", array('create'), [\OC::$server->getLogger()]);
// we expect create to be called once:
$router
@@ -148,7 +148,7 @@ class RoutingTest extends \Test\TestCase
private function assertResource($yaml, $resourceName, $url, $controllerName, $paramName)
{
// router mock
- $router = $this->getMock("\OC\Route\Router", array('create'));
+ $router = $this->getMock("\OC\Route\Router", array('create'), [\OC::$server->getLogger()]);
// route mocks
$container = new DIContainer('app1');
diff --git a/tests/lib/appframework/utility/ControllerMethodReflectorTest.php b/tests/lib/appframework/utility/ControllerMethodReflectorTest.php
index a584b5481ba..c643c362a9c 100644
--- a/tests/lib/appframework/utility/ControllerMethodReflectorTest.php
+++ b/tests/lib/appframework/utility/ControllerMethodReflectorTest.php
@@ -104,6 +104,29 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
$this->assertEquals('int', $reader->getType('test'));
}
+ /**
+ * @Annotation
+ * @param int $a
+ * @param int $b
+ */
+ public function arguments3($a, float $b, int $c, $d){}
+
+ /**
+ * @requires PHP 7
+ */
+ public function testReadTypeIntAnnotationsScalarTypes(){
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ '\OC\AppFramework\Utility\ControllerMethodReflectorTest',
+ 'arguments3'
+ );
+
+ $this->assertEquals('int', $reader->getType('a'));
+ $this->assertEquals('float', $reader->getType('b'));
+ $this->assertEquals('int', $reader->getType('c'));
+ $this->assertNull($reader->getType('d'));
+ }
+
/**
* @Annotation
diff --git a/tests/lib/autoloader.php b/tests/lib/autoloader.php
index 9fb717c4f63..6443d87a2e5 100644
--- a/tests/lib/autoloader.php
+++ b/tests/lib/autoloader.php
@@ -90,7 +90,7 @@ class AutoLoader extends TestCase {
public function testLoadCoreNamespaceRepair() {
$this->assertEquals([
- \OC::$SERVERROOT . '/lib/repair/foo/bar.php',
+ \OC::$SERVERROOT . '/lib/private/repair/foo/bar.php',
], $this->loader->findClass('OC\Repair\Foo\Bar'));
}
}
diff --git a/tests/lib/avatar.php b/tests/lib/avatar.php
deleted file mode 100644
index badee9f34d1..00000000000
--- a/tests/lib/avatar.php
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-
-/**
- * Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-use OC\Avatar;
-
-class Test_Avatar extends \Test\TestCase {
- private static $trashBinStatus;
-
- /** @var @var string */
- private $user;
-
- protected function setUp() {
- parent::setUp();
-
- $this->user = $this->getUniqueID();
- $storage = new \OC\Files\Storage\Temporary(array());
- \OC\Files\Filesystem::mount($storage, array(), '/' . $this->user . '/');
- }
-
- public static function setUpBeforeClass() {
- self::$trashBinStatus = \OC_App::isEnabled('files_trashbin');
- \OC_App::disable('files_trashbin');
- }
-
- public static function tearDownAfterClass() {
- if (self::$trashBinStatus) {
- \OC_App::enable('files_trashbin');
- }
- }
-
- /**
- * @return array
- */
- public function traversalProvider() {
- return [
- ['Pot\..\entiallyDangerousUsername'],
- ['Pot/..\entiallyDangerousUsername'],
- ['PotentiallyDangerousUsername/..'],
- ['PotentiallyDangerousUsername\../'],
- ['/../PotentiallyDangerousUsername'],
- ];
- }
-
- /**
- * @dataProvider traversalProvider
- * @expectedException \Exception
- * @expectedExceptionMessage Username may not contain slashes
- * @param string $dangerousUsername
- */
- public function testAvatarTraversal($dangerousUsername) {
- new Avatar($dangerousUsername);
- }
-
- public function testAvatar() {
-
- $avatar = new Avatar($this->user);
-
- $this->assertEquals(false, $avatar->get());
-
- $expected = new OC_Image(\OC::$SERVERROOT . '/tests/data/testavatar.png');
- $expected->resize(64);
- $avatar->set($expected->data());
- $this->assertEquals($expected->data(), $avatar->get()->data());
-
- $avatar->remove();
- $this->assertEquals(false, $avatar->get());
- }
-
- public function testAvatarApi() {
- $avatarManager = \OC::$server->getAvatarManager();
- $avatar = $avatarManager->getAvatar($this->user);
-
- $this->assertEquals(false, $avatar->get());
-
- $expected = new OC_Image(\OC::$SERVERROOT . '/tests/data/testavatar.png');
- $expected->resize(64);
- $avatar->set($expected->data());
- $this->assertEquals($expected->data(), $avatar->get()->data());
-
- $avatar->remove();
- $this->assertEquals(false, $avatar->get());
- }
-}
diff --git a/tests/lib/avatarmanagertest.php b/tests/lib/avatarmanagertest.php
new file mode 100644
index 00000000000..cb9068c46a6
--- /dev/null
+++ b/tests/lib/avatarmanagertest.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+use OC\AvatarManager;
+use OCP\Files\IRootFolder;
+use OCP\IUserManager;
+
+class AvatarManagerTest extends \Test\TestCase {
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ /** @var AvatarManager */
+ private $avatarManager;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->rootFolder = $this->getMock('\OCP\Files\IRootFolder');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+ $l = $this->getMock('\OCP\IL10N');
+ $l->method('t')->will($this->returnArgument(0));
+ $this->avatarManager = new \OC\AvatarManager(
+ $this->userManager,
+ $this->rootFolder,
+ $l);;
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage user does not exist
+ */
+ public function testGetAvatarInvalidUser() {
+ $this->avatarManager->getAvatar('invalidUser');
+ }
+
+ public function testGetAvatarValidUser() {
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('validUser')
+ ->willReturn(true);
+
+ $folder = $this->getMock('\OCP\Files\Folder');
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('validUser')
+ ->willReturn($folder);
+
+ $folder->expects($this->once())
+ ->method('getParent')
+ ->will($this->returnSelf());
+
+ $this->avatarManager->getAvatar('validUser');
+
+ }
+
+}
diff --git a/tests/lib/avatartest.php b/tests/lib/avatartest.php
new file mode 100644
index 00000000000..e7d78311085
--- /dev/null
+++ b/tests/lib/avatartest.php
@@ -0,0 +1,172 @@
+<?php
+
+/**
+ * Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+use OCP\Files\Folder;
+
+class AvatarTest extends \Test\TestCase {
+ /** @var Folder | PHPUnit_Framework_MockObject_MockObject */
+ private $folder;
+
+ /** @var \OC\Avatar */
+ private $avatar;
+
+ /** @var \OC\User\User | PHPUnit_Framework_MockObject_MockObject $user */
+ private $user;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->folder = $this->getMock('\OCP\Files\Folder');
+ /** @var \OCP\IL10N | PHPUnit_Framework_MockObject_MockObject $l */
+ $l = $this->getMock('\OCP\IL10N');
+ $l->method('t')->will($this->returnArgument(0));
+ $this->user = $this->getMockBuilder('\OC\User\User')->disableOriginalConstructor()->getMock();
+ $this->avatar = new \OC\Avatar($this->folder, $l, $this->user);
+ }
+
+ public function testGetNoAvatar() {
+ $this->assertEquals(false, $this->avatar->get());
+ }
+
+ public function testGetAvatarSizeMatch() {
+ $this->folder->method('nodeExists')
+ ->will($this->returnValueMap([
+ ['avatar.jpg', true],
+ ['avatar.128.jpg', true],
+ ]));
+
+ $expected = new OC_Image(\OC::$SERVERROOT . '/tests/data/testavatar.png');
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getContent')->willReturn($expected->data());
+ $this->folder->method('get')->with('avatar.128.jpg')->willReturn($file);
+
+ $this->assertEquals($expected->data(), $this->avatar->get(128)->data());
+ }
+
+ public function testGetAvatarSizeMinusOne() {
+ $this->folder->method('nodeExists')
+ ->will($this->returnValueMap([
+ ['avatar.jpg', true],
+ ]));
+
+ $expected = new OC_Image(\OC::$SERVERROOT . '/tests/data/testavatar.png');
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getContent')->willReturn($expected->data());
+ $this->folder->method('get')->with('avatar.jpg')->willReturn($file);
+
+ $this->assertEquals($expected->data(), $this->avatar->get(-1)->data());
+ }
+
+ public function testGetAvatarNoSizeMatch() {
+ $this->folder->method('nodeExists')
+ ->will($this->returnValueMap([
+ ['avatar.png', true],
+ ['avatar.32.png', false],
+ ]));
+
+ $expected = new OC_Image(\OC::$SERVERROOT . '/tests/data/testavatar.png');
+ $expected2 = new OC_Image(\OC::$SERVERROOT . '/tests/data/testavatar.png');
+ $expected2->resize(32);
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getContent')->willReturn($expected->data());
+
+ $this->folder->method('get')
+ ->will($this->returnCallback(
+ function($path) use ($file) {
+ if ($path === 'avatar.png') {
+ return $file;
+ } else {
+ throw new \OCP\Files\NotFoundException;
+ }
+ }
+ ));
+
+ $newFile = $this->getMock('\OCP\Files\File');
+ $newFile->expects($this->once())
+ ->method('putContent')
+ ->with($expected2->data());
+ $newFile->expects($this->once())
+ ->method('getContent')
+ ->willReturn($expected2->data());
+ $this->folder->expects($this->once())
+ ->method('newFile')
+ ->with('avatar.32.png')
+ ->willReturn($newFile);
+
+ $this->assertEquals($expected2->data(), $this->avatar->get(32)->data());
+ }
+
+ public function testExistsNo() {
+ $this->assertFalse($this->avatar->exists());
+ }
+
+ public function testExiststJPG() {
+ $this->folder->method('nodeExists')
+ ->will($this->returnValueMap([
+ ['avatar.jpg', true],
+ ['avatar.png', false],
+ ]));
+ $this->assertTrue($this->avatar->exists());
+ }
+
+ public function testExistsPNG() {
+ $this->folder->method('nodeExists')
+ ->will($this->returnValueMap([
+ ['avatar.jpg', false],
+ ['avatar.png', true],
+ ]));
+ $this->assertTrue($this->avatar->exists());
+ }
+
+ public function testSetAvatar() {
+ $avatarFileJPG = $this->getMock('\OCP\Files\File');
+ $avatarFileJPG->method('getName')
+ ->willReturn('avatar.jpg');
+ $avatarFileJPG->expects($this->once())->method('delete');
+
+ $avatarFilePNG = $this->getMock('\OCP\Files\File');
+ $avatarFilePNG->method('getName')
+ ->willReturn('avatar.png');
+ $avatarFilePNG->expects($this->once())->method('delete');
+
+ $resizedAvatarFile = $this->getMock('\OCP\Files\File');
+ $resizedAvatarFile->method('getName')
+ ->willReturn('avatar.32.jpg');
+ $resizedAvatarFile->expects($this->once())->method('delete');
+
+ $nonAvatarFile = $this->getMock('\OCP\Files\File');
+ $nonAvatarFile->method('getName')
+ ->willReturn('avatarX');
+ $nonAvatarFile->expects($this->never())->method('delete');
+
+ $this->folder->method('search')
+ ->with('avatar')
+ ->willReturn([$avatarFileJPG, $avatarFilePNG, $resizedAvatarFile, $nonAvatarFile]);
+
+ $newFile = $this->getMock('\OCP\Files\File');
+ $this->folder->expects($this->once())
+ ->method('newFile')
+ ->with('avatar.png')
+ ->willReturn($newFile);
+
+ $image = new OC_Image(\OC::$SERVERROOT . '/tests/data/testavatar.png');
+ $newFile->expects($this->once())
+ ->method('putContent')
+ ->with($image->data());
+
+ // One on remove and once on setting the new avatar
+ $this->user->expects($this->exactly(2))->method('triggerChange');
+
+ $this->avatar->set($image->data());
+ }
+
+}
diff --git a/tests/lib/backgroundjob/job.php b/tests/lib/backgroundjob/job.php
index fec9b0a792d..12413e2c52a 100644
--- a/tests/lib/backgroundjob/job.php
+++ b/tests/lib/backgroundjob/job.php
@@ -18,15 +18,23 @@ class Job extends \Test\TestCase {
public function testRemoveAfterException() {
$jobList = new DummyJobList();
- $job = new TestJob($this, function () {
- throw new \Exception();
+ $e = new \Exception();
+ $job = new TestJob($this, function () use ($e) {
+ throw $e;
});
$jobList->add($job);
+ $logger = $this->getMockBuilder('OCP\ILogger')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $logger->expects($this->once())
+ ->method('logException')
+ ->with($e);
+
$this->assertCount(1, $jobList->getAll());
- $job->execute($jobList);
+ $job->execute($jobList, $logger);
$this->assertTrue($this->run);
- $this->assertCount(0, $jobList->getAll());
+ $this->assertCount(1, $jobList->getAll());
}
public function markRun() {
diff --git a/tests/lib/backgroundjob/joblist.php b/tests/lib/backgroundjob/joblist.php
index d5136676a47..c0796d8253a 100644
--- a/tests/lib/backgroundjob/joblist.php
+++ b/tests/lib/backgroundjob/joblist.php
@@ -8,23 +8,38 @@
namespace Test\BackgroundJob;
-class JobList extends \Test\TestCase {
- /**
- * @var \OC\BackgroundJob\JobList
- */
+use OCP\BackgroundJob\IJob;
+use Test\TestCase;
+
+/**
+ * Class JobList
+ *
+ * @group DB
+ * @package Test\BackgroundJob
+ */
+class JobList extends TestCase {
+ /** @var \OC\BackgroundJob\JobList */
protected $instance;
- /**
- * @var \OCP\IConfig | \PHPUnit_Framework_MockObject_MockObject $config
- */
+ /** @var \OCP\IConfig|\PHPUnit_Framework_MockObject_MockObject */
protected $config;
protected function setUp() {
parent::setUp();
- $conn = \OC::$server->getDatabaseConnection();
+ $connection = \OC::$server->getDatabaseConnection();
$this->config = $this->getMock('\OCP\IConfig');
- $this->instance = new \OC\BackgroundJob\JobList($conn, $this->config);
+ $this->instance = new \OC\BackgroundJob\JobList($connection, $this->config);
+ }
+
+ protected function getAllSorted() {
+ $jobs = $this->instance->getAll();
+
+ usort($jobs, function (IJob $job1, IJob $job2) {
+ return $job1->getId() - $job2->getId();
+ });
+
+ return $jobs;
}
public function argumentProvider() {
@@ -45,11 +60,11 @@ class JobList extends \Test\TestCase {
* @param $argument
*/
public function testAddRemove($argument) {
- $existingJobs = $this->instance->getAll();
+ $existingJobs = $this->getAllSorted();
$job = new TestJob();
$this->instance->add($job, $argument);
- $jobs = $this->instance->getAll();
+ $jobs = $this->getAllSorted();
$this->assertCount(count($existingJobs) + 1, $jobs);
$addedJob = $jobs[count($jobs) - 1];
@@ -58,7 +73,7 @@ class JobList extends \Test\TestCase {
$this->instance->remove($job, $argument);
- $jobs = $this->instance->getAll();
+ $jobs = $this->getAllSorted();
$this->assertEquals($existingJobs, $jobs);
}
@@ -67,19 +82,19 @@ class JobList extends \Test\TestCase {
* @param $argument
*/
public function testRemoveDifferentArgument($argument) {
- $existingJobs = $this->instance->getAll();
+ $existingJobs = $this->getAllSorted();
$job = new TestJob();
$this->instance->add($job, $argument);
- $jobs = $this->instance->getAll();
+ $jobs = $this->getAllSorted();
$this->instance->remove($job, 10);
- $jobs2 = $this->instance->getAll();
+ $jobs2 = $this->getAllSorted();
$this->assertEquals($jobs, $jobs2);
$this->instance->remove($job, $argument);
- $jobs = $this->instance->getAll();
+ $jobs = $this->getAllSorted();
$this->assertEquals($existingJobs, $jobs);
}
@@ -126,7 +141,7 @@ class JobList extends \Test\TestCase {
$this->instance->add($job, 1);
$this->instance->add($job, 2);
- $jobs = $this->instance->getAll();
+ $jobs = $this->getAllSorted();
$savedJob1 = $jobs[count($jobs) - 2];
$savedJob2 = $jobs[count($jobs) - 1];
@@ -149,7 +164,7 @@ class JobList extends \Test\TestCase {
$this->instance->add($job, 1);
$this->instance->add($job, 2);
- $jobs = $this->instance->getAll();
+ $jobs = $this->getAllSorted();
$savedJob2 = $jobs[count($jobs) - 1];
@@ -174,7 +189,7 @@ class JobList extends \Test\TestCase {
$job = new TestJob();
$this->instance->add($job, $argument);
- $jobs = $this->instance->getAll();
+ $jobs = $this->getAllSorted();
$addedJob = $jobs[count($jobs) - 1];
@@ -187,7 +202,7 @@ class JobList extends \Test\TestCase {
$job = new TestJob();
$this->instance->add($job);
- $jobs = $this->instance->getAll();
+ $jobs = $this->getAllSorted();
$addedJob = $jobs[count($jobs) - 1];
@@ -209,7 +224,7 @@ class JobList extends \Test\TestCase {
$this->instance->add('\OC\Non\Existing\Class');
$this->instance->add($job, 2);
- $jobs = $this->instance->getAll();
+ $jobs = $this->getAllSorted();
$savedJob1 = $jobs[count($jobs) - 2];
$savedJob2 = $jobs[count($jobs) - 1];
diff --git a/tests/lib/cache.php b/tests/lib/cache.php
index 894d8c57662..feddcac4693 100644
--- a/tests/lib/cache.php
+++ b/tests/lib/cache.php
@@ -8,7 +8,7 @@
abstract class Test_Cache extends \Test\TestCase {
/**
- * @var \OC\Cache cache;
+ * @var \OCP\ICache cache;
*/
protected $instance;
diff --git a/tests/lib/cache/cappedmemorycache.php b/tests/lib/cache/cappedmemorycache.php
new file mode 100644
index 00000000000..a8fb273b80a
--- /dev/null
+++ b/tests/lib/cache/cappedmemorycache.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Robin Appelman
+ * @copyright 2016 Robin Appelman icewind@owncloud.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test\Cache;
+
+/**
+ * Class FileCache
+ *
+ * @group DB
+ *
+ * @package Test\Cache
+ */
+class CappedMemoryCache extends \Test_Cache {
+ public function setUp() {
+ parent::setUp();
+ $this->instance = new \OC\Cache\CappedMemoryCache();
+ }
+
+ public function testSetOverCap() {
+ $instance = new \OC\Cache\CappedMemoryCache(3);
+
+ $instance->set('1', 'a');
+ $instance->set('2', 'b');
+ $instance->set('3', 'c');
+ $instance->set('4', 'd');
+ $instance->set('5', 'e');
+
+ $this->assertFalse($instance->hasKey('1'));
+ $this->assertFalse($instance->hasKey('2'));
+ $this->assertTrue($instance->hasKey('3'));
+ $this->assertTrue($instance->hasKey('4'));
+ $this->assertTrue($instance->hasKey('5'));
+ }
+
+ function testClear() {
+ $value = 'ipsum lorum';
+ $this->instance->set('1_value1', $value);
+ $this->instance->set('1_value2', $value);
+ $this->instance->set('2_value1', $value);
+ $this->instance->set('3_value1', $value);
+
+ $this->assertTrue($this->instance->clear());
+ $this->assertFalse($this->instance->hasKey('1_value1'));
+ $this->assertFalse($this->instance->hasKey('1_value2'));
+ $this->assertFalse($this->instance->hasKey('2_value1'));
+ $this->assertFalse($this->instance->hasKey('3_value1'));
+ }
+
+ function testIndirectSet() {
+ $this->instance->set('array', []);
+
+ $this->instance['array'][] = 'foo';
+
+ $this->assertEquals(['foo'], $this->instance->get('array'));
+
+ $this->instance['array']['bar'] = 'qwerty';
+
+ $this->assertEquals(['foo', 'bar' => 'qwerty'], $this->instance->get('array'));
+ }
+}
diff --git a/tests/lib/cache/file.php b/tests/lib/cache/file.php
index b5f186c5416..92b784bf8ea 100644
--- a/tests/lib/cache/file.php
+++ b/tests/lib/cache/file.php
@@ -22,6 +22,13 @@
namespace Test\Cache;
+/**
+ * Class FileCache
+ *
+ * @group DB
+ *
+ * @package Test\Cache
+ */
class FileCache extends \Test_Cache {
/**
* @var string
@@ -56,14 +63,15 @@ class FileCache extends \Test_Cache {
$storage = new \OC\Files\Storage\Temporary(array());
\OC\Files\Filesystem::mount($storage,array(),'/');
$datadir = str_replace('local::', '', $storage->getId());
- $this->datadir = \OC_Config::getValue('cachedirectory', \OC::$SERVERROOT.'/data/cache');
- \OC_Config::setValue('cachedirectory', $datadir);
+ $config = \OC::$server->getConfig();
+ $this->datadir = $config->getSystemValue('cachedirectory', \OC::$SERVERROOT.'/data/cache');
+ $config->setSystemValue('cachedirectory', $datadir);
\OC_User::clearBackends();
\OC_User::useBackend(new \Test\Util\User\Dummy());
//login
- \OC_User::createUser('test', 'test');
+ \OC::$server->getUserManager()->createUser('test', 'test');
$this->user = \OC_User::getUser();
\OC_User::setUserId('test');
@@ -79,10 +87,12 @@ class FileCache extends \Test_Cache {
}
protected function tearDown() {
- $this->instance->remove('hack', 'hack');
+ if ($this->instance) {
+ $this->instance->remove('hack', 'hack');
+ }
\OC_User::setUserId($this->user);
- \OC_Config::setValue('cachedirectory', $this->datadir);
+ \OC::$server->getConfig()->setSystemValue('cachedirectory', $this->datadir);
// Restore the original mount point
\OC\Files\Filesystem::clearMounts();
diff --git a/tests/lib/command/integrity/SignAppTest.php b/tests/lib/command/integrity/SignAppTest.php
new file mode 100644
index 00000000000..44a644c45df
--- /dev/null
+++ b/tests/lib/command/integrity/SignAppTest.php
@@ -0,0 +1,253 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace Test\Command\Integrity;
+
+use OC\Core\Command\Integrity\SignApp;
+use OC\IntegrityCheck\Checker;
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
+use OCP\IURLGenerator;
+use Test\TestCase;
+
+class SignAppTest extends TestCase {
+ /** @var Checker */
+ private $checker;
+ /** @var SignApp */
+ private $signApp;
+ /** @var FileAccessHelper */
+ private $fileAccessHelper;
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ public function setUp() {
+ parent::setUp();
+ $this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker')
+ ->disableOriginalConstructor()->getMock();
+ $this->fileAccessHelper = $this->getMockBuilder('\OC\IntegrityCheck\Helpers\FileAccessHelper')
+ ->disableOriginalConstructor()->getMock();
+ $this->urlGenerator = $this->getMockBuilder('\OCP\IURLGenerator')
+ ->disableOriginalConstructor()->getMock();
+ $this->signApp = new SignApp(
+ $this->checker,
+ $this->fileAccessHelper,
+ $this->urlGenerator
+ );
+ }
+
+ public function testExecuteWithMissingPath() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('path')
+ ->will($this->returnValue(null));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue('PrivateKey'));
+ $inputInterface
+ ->expects($this->at(2))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue('Certificate'));
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('This command requires the --path, --privateKey and --certificate.');
+
+ $this->invokePrivate($this->signApp, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ public function testExecuteWithMissingPrivateKey() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('path')
+ ->will($this->returnValue('AppId'));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue(null));
+ $inputInterface
+ ->expects($this->at(2))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue('Certificate'));
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('This command requires the --path, --privateKey and --certificate.');
+
+ $this->invokePrivate($this->signApp, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ public function testExecuteWithMissingCertificate() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('path')
+ ->will($this->returnValue('AppId'));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue('privateKey'));
+ $inputInterface
+ ->expects($this->at(2))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue(null));
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('This command requires the --path, --privateKey and --certificate.');
+
+ $this->invokePrivate($this->signApp, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ public function testExecuteWithNotExistingPrivateKey() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('path')
+ ->will($this->returnValue('AppId'));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue('privateKey'));
+ $inputInterface
+ ->expects($this->at(2))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue('certificate'));
+
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with('privateKey')
+ ->will($this->returnValue(false));
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('Private key "privateKey" does not exists.');
+
+ $this->invokePrivate($this->signApp, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ public function testExecuteWithNotExistingCertificate() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('path')
+ ->will($this->returnValue('AppId'));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue('privateKey'));
+ $inputInterface
+ ->expects($this->at(2))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue('certificate'));
+
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with('privateKey')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/core.key'));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with('certificate')
+ ->will($this->returnValue(false));
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('Certificate "certificate" does not exists.');
+
+ $this->invokePrivate($this->signApp, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ public function testExecute() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('path')
+ ->will($this->returnValue('AppId'));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue('privateKey'));
+ $inputInterface
+ ->expects($this->at(2))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue('certificate'));
+
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with('privateKey')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/core.key'));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with('certificate')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/core.crt'));
+
+ $this->checker
+ ->expects($this->once())
+ ->method('writeAppSignature');
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('Successfully signed "AppId"');
+
+ $this->invokePrivate($this->signApp, 'execute', [$inputInterface, $outputInterface]);
+ }
+}
diff --git a/tests/lib/command/integrity/SignCoreTest.php b/tests/lib/command/integrity/SignCoreTest.php
new file mode 100644
index 00000000000..ff1f6b23a95
--- /dev/null
+++ b/tests/lib/command/integrity/SignCoreTest.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace Test\Command\Integrity;
+
+use OC\Core\Command\Integrity\SignCore;
+use OC\IntegrityCheck\Checker;
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
+use Test\TestCase;
+
+class SignCoreTest extends TestCase {
+ /** @var Checker */
+ private $checker;
+ /** @var SignCore */
+ private $signCore;
+ /** @var FileAccessHelper */
+ private $fileAccessHelper;
+
+ public function setUp() {
+ parent::setUp();
+ $this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker')
+ ->disableOriginalConstructor()->getMock();
+ $this->fileAccessHelper = $this->getMockBuilder('\OC\IntegrityCheck\Helpers\FileAccessHelper')
+ ->disableOriginalConstructor()->getMock();
+ $this->signCore = new SignCore(
+ $this->checker,
+ $this->fileAccessHelper
+ );
+ }
+
+ public function testExecuteWithMissingPrivateKey() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue(null));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue('Certificate'));
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('--privateKey, --certificate and --path are required.');
+
+ $this->invokePrivate($this->signCore, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ public function testExecuteWithMissingCertificate() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue('privateKey'));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue(null));
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('--privateKey, --certificate and --path are required.');
+
+ $this->invokePrivate($this->signCore, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ public function testExecuteWithNotExistingPrivateKey() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue('privateKey'));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue('certificate'));
+ $inputInterface
+ ->expects($this->at(2))
+ ->method('getOption')
+ ->with('path')
+ ->will($this->returnValue('certificate'));
+
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with('privateKey')
+ ->will($this->returnValue(false));
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('Private key "privateKey" does not exists.');
+
+ $this->invokePrivate($this->signCore, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ public function testExecuteWithNotExistingCertificate() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue('privateKey'));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue('certificate'));
+ $inputInterface
+ ->expects($this->at(2))
+ ->method('getOption')
+ ->with('path')
+ ->will($this->returnValue('certificate'));
+
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with('privateKey')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/core.key'));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with('certificate')
+ ->will($this->returnValue(false));
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('Certificate "certificate" does not exists.');
+
+ $this->invokePrivate($this->signCore, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ public function testExecute() {
+ $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface');
+ $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface');
+
+ $inputInterface
+ ->expects($this->at(0))
+ ->method('getOption')
+ ->with('privateKey')
+ ->will($this->returnValue('privateKey'));
+ $inputInterface
+ ->expects($this->at(1))
+ ->method('getOption')
+ ->with('certificate')
+ ->will($this->returnValue('certificate'));
+ $inputInterface
+ ->expects($this->at(2))
+ ->method('getOption')
+ ->with('path')
+ ->will($this->returnValue('certificate'));
+
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with('privateKey')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/core.key'));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with('certificate')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/core.crt'));
+
+ $this->checker
+ ->expects($this->once())
+ ->method('writeCoreSignature');
+
+ $outputInterface
+ ->expects($this->at(0))
+ ->method('writeln')
+ ->with('Successfully signed "core"');
+
+ $this->invokePrivate($this->signCore, 'execute', [$inputInterface, $outputInterface]);
+ }
+}
diff --git a/tests/lib/comments/comment.php b/tests/lib/comments/comment.php
new file mode 100644
index 00000000000..e6f9c941c96
--- /dev/null
+++ b/tests/lib/comments/comment.php
@@ -0,0 +1,112 @@
+<?php
+
+namespace Test\Comments;
+
+use Test\TestCase;
+
+class Test_Comments_Comment extends TestCase
+{
+
+ public function testSettersValidInput() {
+ $comment = new \OC\Comments\Comment();
+
+ $id = 'comment23';
+ $parentId = 'comment11.5';
+ $childrenCount = 6;
+ $message = 'I like to comment comment';
+ $verb = 'comment';
+ $actor = ['type' => 'users', 'id' => 'alice'];
+ $creationDT = new \DateTime();
+ $latestChildDT = new \DateTime('yesterday');
+ $object = ['type' => 'files', 'id' => 'file64'];
+
+ $comment
+ ->setId($id)
+ ->setParentId($parentId)
+ ->setChildrenCount($childrenCount)
+ ->setMessage($message)
+ ->setVerb($verb)
+ ->setActor($actor['type'], $actor['id'])
+ ->setCreationDateTime($creationDT)
+ ->setLatestChildDateTime($latestChildDT)
+ ->setObject($object['type'], $object['id']);
+
+ $this->assertSame($id, $comment->getId());
+ $this->assertSame($parentId, $comment->getParentId());
+ $this->assertSame($childrenCount, $comment->getChildrenCount());
+ $this->assertSame($message, $comment->getMessage());
+ $this->assertSame($verb, $comment->getVerb());
+ $this->assertSame($actor['type'], $comment->getActorType());
+ $this->assertSame($actor['id'], $comment->getActorId());
+ $this->assertSame($creationDT, $comment->getCreationDateTime());
+ $this->assertSame($latestChildDT, $comment->getLatestChildDateTime());
+ $this->assertSame($object['type'], $comment->getObjectType());
+ $this->assertSame($object['id'], $comment->getObjectId());
+ }
+
+ /**
+ * @expectedException \OCP\Comments\IllegalIDChangeException
+ */
+ public function testSetIdIllegalInput() {
+ $comment = new \OC\Comments\Comment();
+
+ $comment->setId('c23');
+ $comment->setId('c17');
+ }
+
+ public function testResetId() {
+ $comment = new \OC\Comments\Comment();
+ $comment->setId('c23');
+ $comment->setId('');
+
+ $this->assertSame('', $comment->getId());
+ }
+
+ public function simpleSetterProvider() {
+ return [
+ ['Id', true],
+ ['ParentId', true],
+ ['Message', true],
+ ['Verb', true],
+ ['Verb', ''],
+ ['ChildrenCount', true],
+ ];
+ }
+
+ /**
+ * @dataProvider simpleSetterProvider
+ * @expectedException \InvalidArgumentException
+ */
+ public function testSimpleSetterInvalidInput($field, $input) {
+ $comment = new \OC\Comments\Comment();
+ $setter = 'set' . $field;
+
+ $comment->$setter($input);
+ }
+
+ public function roleSetterProvider() {
+ return [
+ ['Actor', true, true],
+ ['Actor', 'users', true],
+ ['Actor', true, 'alice'],
+ ['Actor', ' ', ' '],
+ ['Object', true, true],
+ ['Object', 'files', true],
+ ['Object', true, 'file64'],
+ ['Object', ' ', ' '],
+ ];
+ }
+
+ /**
+ * @dataProvider roleSetterProvider
+ * @expectedException \InvalidArgumentException
+ */
+ public function testSetRoleInvalidInput($role, $type, $id){
+ $comment = new \OC\Comments\Comment();
+ $setter = 'set' . $role;
+ $comment->$setter($type, $id);
+ }
+
+
+
+}
diff --git a/tests/lib/comments/fakefactory.php b/tests/lib/comments/fakefactory.php
new file mode 100644
index 00000000000..ff8dfd3a259
--- /dev/null
+++ b/tests/lib/comments/fakefactory.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Test\Comments;
+
+use OCP\IServerContainer;
+
+/**
+ * Class FakeFactory
+ */
+class FakeFactory implements \OCP\Comments\ICommentsManagerFactory {
+
+ public function __construct(IServerContainer $serverContainer) {
+ }
+
+ public function getManager() {
+ return new FakeManager();
+ }
+}
diff --git a/tests/lib/comments/fakemanager.php b/tests/lib/comments/fakemanager.php
new file mode 100644
index 00000000000..7186529e718
--- /dev/null
+++ b/tests/lib/comments/fakemanager.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Test\Comments;
+
+/**
+ * Class FakeManager
+ */
+class FakeManager implements \OCP\Comments\ICommentsManager {
+
+ public function get($id) {}
+
+ public function getTree($id, $limit = 0, $offset = 0) {}
+
+ public function getForObject(
+ $objectType,
+ $objectId,
+ $limit = 0,
+ $offset = 0,
+ \DateTime $notOlderThan = null
+ ) {}
+
+ public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null) {}
+
+ public function create($actorType, $actorId, $objectType, $objectId) {}
+
+ public function delete($id) {}
+
+ public function save(\OCP\Comments\IComment $comment) {}
+
+ public function deleteReferencesOfActor($actorType, $actorId) {}
+
+ public function deleteCommentsAtObject($objectType, $objectId) {}
+
+ public function setReadMark($objectType, $objectId, \DateTime $dateTime, \OCP\IUser $user) {}
+
+ public function getReadMark($objectType, $objectId, \OCP\IUser $user) {}
+
+ public function deleteReadMarksFromUser(\OCP\IUser $user) {}
+
+ public function deleteReadMarksOnObject($objectType, $objectId) {}
+}
diff --git a/tests/lib/comments/manager.php b/tests/lib/comments/manager.php
new file mode 100644
index 00000000000..c55f4728883
--- /dev/null
+++ b/tests/lib/comments/manager.php
@@ -0,0 +1,633 @@
+<?php
+
+namespace Test\Comments;
+
+use OCP\Comments\ICommentsManager;
+use Test\TestCase;
+
+/**
+ * Class Test_Comments_Manager
+ *
+ * @group DB
+ */
+class Test_Comments_Manager extends TestCase
+{
+
+ public function setUp() {
+ parent::setUp();
+
+ $sql = \OC::$server->getDatabaseConnection()->getDatabasePlatform()->getTruncateTableSQL('`*PREFIX*comments`');
+ \OC::$server->getDatabaseConnection()->prepare($sql)->execute();
+ }
+
+ protected function addDatabaseEntry($parentId, $topmostParentId, $creationDT = null, $latestChildDT = null) {
+ if(is_null($creationDT)) {
+ $creationDT = new \DateTime();
+ }
+ if(is_null($latestChildDT)) {
+ $latestChildDT = new \DateTime('yesterday');
+ }
+
+ $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ $qb
+ ->insert('comments')
+ ->values([
+ 'parent_id' => $qb->createNamedParameter($parentId),
+ 'topmost_parent_id' => $qb->createNamedParameter($topmostParentId),
+ 'children_count' => $qb->createNamedParameter(2),
+ 'actor_type' => $qb->createNamedParameter('users'),
+ 'actor_id' => $qb->createNamedParameter('alice'),
+ 'message' => $qb->createNamedParameter('nice one'),
+ 'verb' => $qb->createNamedParameter('comment'),
+ 'creation_timestamp' => $qb->createNamedParameter($creationDT, 'datetime'),
+ 'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, 'datetime'),
+ 'object_type' => $qb->createNamedParameter('files'),
+ 'object_id' => $qb->createNamedParameter('file64'),
+ ])
+ ->execute();
+
+ return $qb->getLastInsertId();
+ }
+
+ protected function getManager() {
+ $factory = new \OC\Comments\ManagerFactory(\OC::$server);
+ return $factory->getManager();
+ }
+
+ /**
+ * @expectedException \OCP\Comments\NotFoundException
+ */
+ public function testGetCommentNotFound() {
+ $manager = $this->getManager();
+ $manager->get('22');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testGetCommentNotFoundInvalidInput() {
+ $manager = $this->getManager();
+ $manager->get('unexisting22');
+ }
+
+ public function testGetComment() {
+ $manager = $this->getManager();
+
+ $creationDT = new \DateTime();
+ $latestChildDT = new \DateTime('yesterday');
+
+ $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ $qb
+ ->insert('comments')
+ ->values([
+ 'parent_id' => $qb->createNamedParameter('2'),
+ 'topmost_parent_id' => $qb->createNamedParameter('1'),
+ 'children_count' => $qb->createNamedParameter(2),
+ 'actor_type' => $qb->createNamedParameter('users'),
+ 'actor_id' => $qb->createNamedParameter('alice'),
+ 'message' => $qb->createNamedParameter('nice one'),
+ 'verb' => $qb->createNamedParameter('comment'),
+ 'creation_timestamp' => $qb->createNamedParameter($creationDT, 'datetime'),
+ 'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, 'datetime'),
+ 'object_type' => $qb->createNamedParameter('files'),
+ 'object_id' => $qb->createNamedParameter('file64'),
+ ])
+ ->execute();
+
+ $id = strval($qb->getLastInsertId());
+
+ $comment = $manager->get($id);
+ $this->assertTrue($comment instanceof \OCP\Comments\IComment);
+ $this->assertSame($comment->getId(), $id);
+ $this->assertSame($comment->getParentId(), '2');
+ $this->assertSame($comment->getTopmostParentId(), '1');
+ $this->assertSame($comment->getChildrenCount(), 2);
+ $this->assertSame($comment->getActorType(), 'users');
+ $this->assertSame($comment->getActorId(), 'alice');
+ $this->assertSame($comment->getMessage(), 'nice one');
+ $this->assertSame($comment->getVerb(), 'comment');
+ $this->assertSame($comment->getObjectType(), 'files');
+ $this->assertSame($comment->getObjectId(), 'file64');
+ $this->assertEquals($comment->getCreationDateTime(), $creationDT);
+ $this->assertEquals($comment->getLatestChildDateTime(), $latestChildDT);
+ }
+
+ /**
+ * @expectedException \OCP\Comments\NotFoundException
+ */
+ public function testGetTreeNotFound() {
+ $manager = $this->getManager();
+ $manager->getTree('22');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testGetTreeNotFoundInvalidIpnut() {
+ $manager = $this->getManager();
+ $manager->getTree('unexisting22');
+ }
+
+ public function testGetTree() {
+ $headId = $this->addDatabaseEntry(0, 0);
+
+ $this->addDatabaseEntry($headId, $headId, new \DateTime('-3 hours'));
+ $this->addDatabaseEntry($headId, $headId, new \DateTime('-2 hours'));
+ $id = $this->addDatabaseEntry($headId, $headId, new \DateTime('-1 hour'));
+
+ $manager = $this->getManager();
+ $tree = $manager->getTree($headId);
+
+ // Verifying the root comment
+ $this->assertTrue(isset($tree['comment']));
+ $this->assertTrue($tree['comment'] instanceof \OCP\Comments\IComment);
+ $this->assertSame($tree['comment']->getId(), strval($headId));
+ $this->assertTrue(isset($tree['replies']));
+ $this->assertSame(count($tree['replies']), 3);
+
+ // one level deep
+ foreach($tree['replies'] as $reply) {
+ $this->assertTrue($reply['comment'] instanceof \OCP\Comments\IComment);
+ $this->assertSame($reply['comment']->getId(), strval($id));
+ $this->assertSame(count($reply['replies']), 0);
+ $id--;
+ }
+ }
+
+ public function testGetTreeNoReplies() {
+ $id = $this->addDatabaseEntry(0, 0);
+
+ $manager = $this->getManager();
+ $tree = $manager->getTree($id);
+
+ // Verifying the root comment
+ $this->assertTrue(isset($tree['comment']));
+ $this->assertTrue($tree['comment'] instanceof \OCP\Comments\IComment);
+ $this->assertSame($tree['comment']->getId(), strval($id));
+ $this->assertTrue(isset($tree['replies']));
+ $this->assertSame(count($tree['replies']), 0);
+
+ // one level deep
+ foreach($tree['replies'] as $reply) {
+ throw new \Exception('This ain`t happen');
+ }
+ }
+
+ public function testGetTreeWithLimitAndOffset() {
+ $headId = $this->addDatabaseEntry(0, 0);
+
+ $this->addDatabaseEntry($headId, $headId, new \DateTime('-3 hours'));
+ $this->addDatabaseEntry($headId, $headId, new \DateTime('-2 hours'));
+ $this->addDatabaseEntry($headId, $headId, new \DateTime('-1 hour'));
+ $idToVerify = $this->addDatabaseEntry($headId, $headId, new \DateTime());
+
+ $manager = $this->getManager();
+
+ for ($offset = 0; $offset < 3; $offset += 2) {
+ $tree = $manager->getTree(strval($headId), 2, $offset);
+
+ // Verifying the root comment
+ $this->assertTrue(isset($tree['comment']));
+ $this->assertTrue($tree['comment'] instanceof \OCP\Comments\IComment);
+ $this->assertSame($tree['comment']->getId(), strval($headId));
+ $this->assertTrue(isset($tree['replies']));
+ $this->assertSame(count($tree['replies']), 2);
+
+ // one level deep
+ foreach ($tree['replies'] as $reply) {
+ $this->assertTrue($reply['comment'] instanceof \OCP\Comments\IComment);
+ $this->assertSame($reply['comment']->getId(), strval($idToVerify));
+ $this->assertSame(count($reply['replies']), 0);
+ $idToVerify--;
+ }
+ }
+ }
+
+ public function testGetForObject() {
+ $this->addDatabaseEntry(0, 0);
+
+ $manager = $this->getManager();
+ $comments = $manager->getForObject('files', 'file64');
+
+ $this->assertTrue(is_array($comments));
+ $this->assertSame(count($comments), 1);
+ $this->assertTrue($comments[0] instanceof \OCP\Comments\IComment);
+ $this->assertSame($comments[0]->getMessage(), 'nice one');
+ }
+
+ public function testGetForObjectWithLimitAndOffset() {
+ $this->addDatabaseEntry(0, 0, new \DateTime('-6 hours'));
+ $this->addDatabaseEntry(0, 0, new \DateTime('-5 hours'));
+ $this->addDatabaseEntry(1, 1, new \DateTime('-4 hours'));
+ $this->addDatabaseEntry(0, 0, new \DateTime('-3 hours'));
+ $this->addDatabaseEntry(2, 2, new \DateTime('-2 hours'));
+ $this->addDatabaseEntry(2, 2, new \DateTime('-1 hours'));
+ $idToVerify = $this->addDatabaseEntry(3, 1, new \DateTime());
+
+ $manager = $this->getManager();
+ $offset = 0;
+ do {
+ $comments = $manager->getForObject('files', 'file64', 3, $offset);
+
+ $this->assertTrue(is_array($comments));
+ foreach($comments as $comment) {
+ $this->assertTrue($comment instanceof \OCP\Comments\IComment);
+ $this->assertSame($comment->getMessage(), 'nice one');
+ $this->assertSame($comment->getId(), strval($idToVerify));
+ $idToVerify--;
+ }
+ $offset += 3;
+ } while(count($comments) > 0);
+ }
+
+ public function testGetForObjectWithDateTimeConstraint() {
+ $this->addDatabaseEntry(0, 0, new \DateTime('-6 hours'));
+ $this->addDatabaseEntry(0, 0, new \DateTime('-5 hours'));
+ $id1 = $this->addDatabaseEntry(0, 0, new \DateTime('-3 hours'));
+ $id2 = $this->addDatabaseEntry(2, 2, new \DateTime('-2 hours'));
+
+ $manager = $this->getManager();
+ $comments = $manager->getForObject('files', 'file64', 0, 0, new \DateTime('-4 hours'));
+
+ $this->assertSame(count($comments), 2);
+ $this->assertSame($comments[0]->getId(), strval($id2));
+ $this->assertSame($comments[1]->getId(), strval($id1));
+ }
+
+ public function testGetForObjectWithLimitAndOffsetAndDateTimeConstraint() {
+ $this->addDatabaseEntry(0, 0, new \DateTime('-7 hours'));
+ $this->addDatabaseEntry(0, 0, new \DateTime('-6 hours'));
+ $this->addDatabaseEntry(1, 1, new \DateTime('-5 hours'));
+ $this->addDatabaseEntry(0, 0, new \DateTime('-3 hours'));
+ $this->addDatabaseEntry(2, 2, new \DateTime('-2 hours'));
+ $this->addDatabaseEntry(2, 2, new \DateTime('-1 hours'));
+ $idToVerify = $this->addDatabaseEntry(3, 1, new \DateTime());
+
+ $manager = $this->getManager();
+ $offset = 0;
+ do {
+ $comments = $manager->getForObject('files', 'file64', 3, $offset, new \DateTime('-4 hours'));
+
+ $this->assertTrue(is_array($comments));
+ foreach($comments as $comment) {
+ $this->assertTrue($comment instanceof \OCP\Comments\IComment);
+ $this->assertSame($comment->getMessage(), 'nice one');
+ $this->assertSame($comment->getId(), strval($idToVerify));
+ $this->assertTrue(intval($comment->getId()) >= 4);
+ $idToVerify--;
+ }
+ $offset += 3;
+ } while(count($comments) > 0);
+ }
+
+ public function testGetNumberOfCommentsForObject() {
+ for($i = 1; $i < 5; $i++) {
+ $this->addDatabaseEntry(0, 0);
+ }
+
+ $manager = $this->getManager();
+
+ $amount = $manager->getNumberOfCommentsForObject('untype', '00');
+ $this->assertSame($amount, 0);
+
+ $amount = $manager->getNumberOfCommentsForObject('files', 'file64');
+ $this->assertSame($amount, 4);
+ }
+
+ public function invalidCreateArgsProvider() {
+ return [
+ ['', 'aId-1', 'oType-1', 'oId-1'],
+ ['aType-1', '', 'oType-1', 'oId-1'],
+ ['aType-1', 'aId-1', '', 'oId-1'],
+ ['aType-1', 'aId-1', 'oType-1', ''],
+ [1, 'aId-1', 'oType-1', 'oId-1'],
+ ['aType-1', 1, 'oType-1', 'oId-1'],
+ ['aType-1', 'aId-1', 1, 'oId-1'],
+ ['aType-1', 'aId-1', 'oType-1', 1],
+ ];
+ }
+
+ /**
+ * @dataProvider invalidCreateArgsProvider
+ * @expectedException \InvalidArgumentException
+ */
+ public function testCreateCommentInvalidArguments($aType, $aId, $oType, $oId) {
+ $manager = $this->getManager();
+ $manager->create($aType, $aId, $oType, $oId);
+ }
+
+ public function testCreateComment() {
+ $actorType = 'bot';
+ $actorId = 'bob';
+ $objectType = 'weather';
+ $objectId = 'bielefeld';
+
+ $comment = $this->getManager()->create($actorType, $actorId, $objectType, $objectId);
+ $this->assertTrue($comment instanceof \OCP\Comments\IComment);
+ $this->assertSame($comment->getActorType(), $actorType);
+ $this->assertSame($comment->getActorId(), $actorId);
+ $this->assertSame($comment->getObjectType(), $objectType);
+ $this->assertSame($comment->getObjectId(), $objectId);
+ }
+
+ /**
+ * @expectedException \OCP\Comments\NotFoundException
+ */
+ public function testDelete() {
+ $manager = $this->getManager();
+
+ $done = $manager->delete('404');
+ $this->assertFalse($done);
+
+ $done = $manager->delete('%');
+ $this->assertFalse($done);
+
+ $done = $manager->delete('');
+ $this->assertFalse($done);
+
+ $id = strval($this->addDatabaseEntry(0, 0));
+ $comment = $manager->get($id);
+ $this->assertTrue($comment instanceof \OCP\Comments\IComment);
+ $done = $manager->delete($id);
+ $this->assertTrue($done);
+ $manager->get($id);
+ }
+
+ public function testSaveNew() {
+ $manager = $this->getManager();
+ $comment = new \OC\Comments\Comment();
+ $comment
+ ->setActor('users', 'alice')
+ ->setObject('files', 'file64')
+ ->setMessage('very beautiful, I am impressed!')
+ ->setVerb('comment');
+
+ $saveSuccessful = $manager->save($comment);
+ $this->assertTrue($saveSuccessful);
+ $this->assertTrue($comment->getId() !== '');
+ $this->assertTrue($comment->getId() !== '0');
+ $this->assertTrue(!is_null($comment->getCreationDateTime()));
+
+ $loadedComment = $manager->get($comment->getId());
+ $this->assertSame($comment->getMessage(), $loadedComment->getMessage());
+ $this->assertEquals($comment->getCreationDateTime(), $loadedComment->getCreationDateTime());
+ }
+
+ public function testSaveUpdate() {
+ $manager = $this->getManager();
+ $comment = new \OC\Comments\Comment();
+ $comment
+ ->setActor('users', 'alice')
+ ->setObject('files', 'file64')
+ ->setMessage('very beautiful, I am impressed!')
+ ->setVerb('comment');
+
+ $manager->save($comment);
+
+ $comment->setMessage('very beautiful, I am really so much impressed!');
+ $manager->save($comment);
+
+ $loadedComment = $manager->get($comment->getId());
+ $this->assertSame($comment->getMessage(), $loadedComment->getMessage());
+ }
+
+ /**
+ * @expectedException \OCP\Comments\NotFoundException
+ */
+ public function testSaveUpdateException() {
+ $manager = $this->getManager();
+ $comment = new \OC\Comments\Comment();
+ $comment
+ ->setActor('users', 'alice')
+ ->setObject('files', 'file64')
+ ->setMessage('very beautiful, I am impressed!')
+ ->setVerb('comment');
+
+ $manager->save($comment);
+
+ $manager->delete($comment->getId());
+ $comment->setMessage('very beautiful, I am really so much impressed!');
+ $manager->save($comment);
+ }
+
+ /**
+ * @expectedException \UnexpectedValueException
+ */
+ public function testSaveIncomplete() {
+ $manager = $this->getManager();
+ $comment = new \OC\Comments\Comment();
+ $comment->setMessage('from no one to nothing');
+ $manager->save($comment);
+ }
+
+ public function testSaveAsChild() {
+ $id = $this->addDatabaseEntry(0, 0);
+
+ $manager = $this->getManager();
+
+ for($i = 0; $i < 3; $i++) {
+ $comment = new \OC\Comments\Comment();
+ $comment
+ ->setActor('users', 'alice')
+ ->setObject('files', 'file64')
+ ->setParentId(strval($id))
+ ->setMessage('full ack')
+ ->setVerb('comment')
+ // setting the creation time avoids using sleep() while making sure to test with different timestamps
+ ->setCreationDateTime(new \DateTime('+' . $i . ' minutes'));
+
+ $manager->save($comment);
+
+ $this->assertSame($comment->getTopmostParentId(), strval($id));
+ $parentComment = $manager->get(strval($id));
+ $this->assertSame($parentComment->getChildrenCount(), $i + 1);
+ $this->assertEquals($parentComment->getLatestChildDateTime(), $comment->getCreationDateTime());
+ }
+ }
+
+ public function invalidActorArgsProvider() {
+ return
+ [
+ ['', ''],
+ [1, 'alice'],
+ ['users', 1],
+ ];
+ }
+
+ /**
+ * @dataProvider invalidActorArgsProvider
+ * @expectedException \InvalidArgumentException
+ */
+ public function testDeleteReferencesOfActorInvalidInput($type, $id) {
+ $manager = $this->getManager();
+ $manager->deleteReferencesOfActor($type, $id);
+ }
+
+ public function testDeleteReferencesOfActor() {
+ $ids = [];
+ $ids[] = $this->addDatabaseEntry(0, 0);
+ $ids[] = $this->addDatabaseEntry(0, 0);
+ $ids[] = $this->addDatabaseEntry(0, 0);
+
+ $manager = $this->getManager();
+
+ // just to make sure they are really set, with correct actor data
+ $comment = $manager->get(strval($ids[1]));
+ $this->assertSame($comment->getActorType(), 'users');
+ $this->assertSame($comment->getActorId(), 'alice');
+
+ $wasSuccessful = $manager->deleteReferencesOfActor('users', 'alice');
+ $this->assertTrue($wasSuccessful);
+
+ foreach($ids as $id) {
+ $comment = $manager->get(strval($id));
+ $this->assertSame($comment->getActorType(), ICommentsManager::DELETED_USER);
+ $this->assertSame($comment->getActorId(), ICommentsManager::DELETED_USER);
+ }
+
+ // actor info is gone from DB, but when database interaction is alright,
+ // we still expect to get true back
+ $wasSuccessful = $manager->deleteReferencesOfActor('users', 'alice');
+ $this->assertTrue($wasSuccessful);
+ }
+
+ public function testDeleteReferencesOfActorWithUserManagement() {
+ $user = \OC::$server->getUserManager()->createUser('xenia', '123456');
+ $this->assertTrue($user instanceof \OCP\IUser);
+
+ $manager = \OC::$server->getCommentsManager();
+ $comment = $manager->create('users', $user->getUID(), 'files', 'file64');
+ $comment
+ ->setMessage('Most important comment I ever left on the Internet.')
+ ->setVerb('comment');
+ $status = $manager->save($comment);
+ $this->assertTrue($status);
+
+ $commentID = $comment->getId();
+ $user->delete();
+
+ $comment = $manager->get($commentID);
+ $this->assertSame($comment->getActorType(), \OCP\Comments\ICommentsManager::DELETED_USER);
+ $this->assertSame($comment->getActorId(), \OCP\Comments\ICommentsManager::DELETED_USER);
+ }
+
+ public function invalidObjectArgsProvider() {
+ return
+ [
+ ['', ''],
+ [1, 'file64'],
+ ['files', 1],
+ ];
+ }
+
+ /**
+ * @dataProvider invalidObjectArgsProvider
+ * @expectedException \InvalidArgumentException
+ */
+ public function testDeleteCommentsAtObjectInvalidInput($type, $id) {
+ $manager = $this->getManager();
+ $manager->deleteCommentsAtObject($type, $id);
+ }
+
+ public function testDeleteCommentsAtObject() {
+ $ids = [];
+ $ids[] = $this->addDatabaseEntry(0, 0);
+ $ids[] = $this->addDatabaseEntry(0, 0);
+ $ids[] = $this->addDatabaseEntry(0, 0);
+
+ $manager = $this->getManager();
+
+ // just to make sure they are really set, with correct actor data
+ $comment = $manager->get(strval($ids[1]));
+ $this->assertSame($comment->getObjectType(), 'files');
+ $this->assertSame($comment->getObjectId(), 'file64');
+
+ $wasSuccessful = $manager->deleteCommentsAtObject('files', 'file64');
+ $this->assertTrue($wasSuccessful);
+
+ $verified = 0;
+ foreach($ids as $id) {
+ try {
+ $manager->get(strval($id));
+ } catch (\OCP\Comments\NotFoundException $e) {
+ $verified++;
+ }
+ }
+ $this->assertSame($verified, 3);
+
+ // actor info is gone from DB, but when database interaction is alright,
+ // we still expect to get true back
+ $wasSuccessful = $manager->deleteCommentsAtObject('files', 'file64');
+ $this->assertTrue($wasSuccessful);
+ }
+
+ public function testSetMarkRead() {
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $dateTimeSet = new \DateTime();
+
+ $manager = $this->getManager();
+ $manager->setReadMark('robot', '36', $dateTimeSet, $user);
+
+ $dateTimeGet = $manager->getReadMark('robot', '36', $user);
+
+ $this->assertEquals($dateTimeGet, $dateTimeSet);
+ }
+
+ public function testSetMarkReadUpdate() {
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $dateTimeSet = new \DateTime('yesterday');
+
+ $manager = $this->getManager();
+ $manager->setReadMark('robot', '36', $dateTimeSet, $user);
+
+ $dateTimeSet = new \DateTime('today');
+ $manager->setReadMark('robot', '36', $dateTimeSet, $user);
+
+ $dateTimeGet = $manager->getReadMark('robot', '36', $user);
+
+ $this->assertEquals($dateTimeGet, $dateTimeSet);
+ }
+
+ public function testReadMarkDeleteUser() {
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $dateTimeSet = new \DateTime();
+
+ $manager = $this->getManager();
+ $manager->setReadMark('robot', '36', $dateTimeSet, $user);
+
+ $manager->deleteReadMarksFromUser($user);
+ $dateTimeGet = $manager->getReadMark('robot', '36', $user);
+
+ $this->assertNull($dateTimeGet);
+ }
+
+ public function testReadMarkDeleteObject() {
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('alice'));
+
+ $dateTimeSet = new \DateTime();
+
+ $manager = $this->getManager();
+ $manager->setReadMark('robot', '36', $dateTimeSet, $user);
+
+ $manager->deleteReadMarksOnObject('robot', '36');
+ $dateTimeGet = $manager->getReadMark('robot', '36', $user);
+
+ $this->assertNull($dateTimeGet);
+ }
+
+}
diff --git a/tests/lib/configtests.php b/tests/lib/configtests.php
index 0269ae542f4..c0251e693c6 100644
--- a/tests/lib/configtests.php
+++ b/tests/lib/configtests.php
@@ -23,7 +23,7 @@ class ConfigTests extends TestCase {
protected function setUp() {
parent::setUp();
- $this->randomTmpDir = \OC_Helper::tmpFolder();
+ $this->randomTmpDir = \OC::$server->getTempManager()->getTemporaryFolder();
$this->configFile = $this->randomTmpDir.'testconfig.php';
file_put_contents($this->configFile, self::TESTCONTENT);
$this->config = new \OC\Config($this->randomTmpDir, 'testconfig.php');
diff --git a/tests/lib/contacts/localadressbook.php b/tests/lib/contacts/localadressbook.php
deleted file mode 100644
index a34d45bf3d0..00000000000
--- a/tests/lib/contacts/localadressbook.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-use OC\Contacts\LocalAddressBook;
-
-/**
- * ownCloud
- *
- * @author Thomas Müller
- * @copyright 2014 Thomas Müller thomas.mueller@tmit.eu
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class Test_LocalAddressBook extends \Test\TestCase
-{
-
- public function testSearchFN() {
- $stub = $this->getMockForAbstractClass('\OCP\IUserManager', array('searchDisplayName'));
-
- $stub->expects($this->any())->method('searchDisplayName')->will($this->returnValue(array(
- new SimpleUserForTesting('tom', 'Thomas'),
- new SimpleUserForTesting('tomtom', 'Thomas T.'),
- )));
-
- $localAddressBook = new LocalAddressBook($stub);
-
- $result = $localAddressBook->search('tom', array('FN'), array());
- $this->assertEquals(2, count($result));
- }
-
- public function testSearchId() {
- $stub = $this->getMockForAbstractClass('\OCP\IUserManager', array('searchDisplayName'));
-
- $stub->expects($this->any())->method('search')->will($this->returnValue(array(
- new SimpleUserForTesting('tom', 'Thomas'),
- new SimpleUserForTesting('tomtom', 'Thomas T.'),
- )));
-
- $localAddressBook = new LocalAddressBook($stub);
-
- $result = $localAddressBook->search('tom', array('id'), array());
- $this->assertEquals(2, count($result));
- }
-}
-
-
-class SimpleUserForTesting implements \OCP\IUser {
-
- public function __construct($uid, $displayName) {
-
- $this->uid = $uid;
- $this->displayName = $displayName;
- }
-
- public function getUID() {
- return $this->uid;
- }
-
- public function getDisplayName() {
- return $this->displayName;
- }
-
- public function setDisplayName($displayName) {
- }
-
- public function getLastLogin() {
- }
-
- public function updateLastLoginTimestamp() {
- }
-
- public function delete() {
- }
-
- public function setPassword($password, $recoveryPassword = null) {
- }
-
- public function getHome() {
- }
-
- public function getBackendClassName() {
- }
-
- public function canChangeAvatar() {
- }
-
- public function canChangePassword() {
- }
-
- public function canChangeDisplayName() {
- }
-
- public function isEnabled() {
- }
-
- public function setEnabled($enabled) {
- }
-}
diff --git a/tests/lib/db.php b/tests/lib/db.php
index 5c25bfb9a5c..88c9ee75b3b 100644
--- a/tests/lib/db.php
+++ b/tests/lib/db.php
@@ -6,6 +6,11 @@
* See the COPYING-README file.
*/
+/**
+ * Class Test_DB
+ *
+ * @group DB
+ */
class Test_DB extends \Test\TestCase {
protected $backupGlobals = FALSE;
@@ -106,11 +111,11 @@ class Test_DB extends \Test\TestCase {
public function testLastInsertId() {
$query = OC_DB::prepare('INSERT INTO `*PREFIX*'.$this->table2.'` (`fullname`,`uri`) VALUES (?,?)');
$result1 = OC_DB::executeAudited($query, array('insertid 1','uri_1'));
- $id1 = OC_DB::insertid('*PREFIX*'.$this->table2);
+ $id1 = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*'.$this->table2);
// we don't know the id we should expect, so insert another row
$result2 = OC_DB::executeAudited($query, array('insertid 2','uri_2'));
- $id2 = OC_DB::insertid('*PREFIX*'.$this->table2);
+ $id2 = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*'.$this->table2);
// now we can check if the two ids are in correct order
$this->assertGreaterThan($id1, $id2);
}
diff --git a/tests/lib/db/connection.php b/tests/lib/db/connection.php
index 720b448d0fb..dd9b31f3ed7 100644
--- a/tests/lib/db/connection.php
+++ b/tests/lib/db/connection.php
@@ -12,28 +12,32 @@ namespace Test\DB;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use OC\DB\MDB2SchemaManager;
+/**
+ * Class Connection
+ *
+ * @group DB
+ *
+ * @package Test\DB
+ */
class Connection extends \Test\TestCase {
/**
* @var \OCP\IDBConnection
*/
private $connection;
- public static function setUpBeforeClass()
- {
+ public static function setUpBeforeClass() {
self::dropTestTable();
parent::setUpBeforeClass();
}
- public static function tearDownAfterClass()
- {
+ public static function tearDownAfterClass() {
self::dropTestTable();
parent::tearDownAfterClass();
}
- protected static function dropTestTable()
- {
+ protected static function dropTestTable() {
if (\OC::$server->getConfig()->getSystemValue('dbtype', 'sqlite') !== 'oci') {
- \OC_DB::dropTable('table');
+ \OC::$server->getDatabaseConnection()->dropTable('table');
}
}
@@ -85,4 +89,93 @@ class Connection extends \Test\TestCase {
$this->connection->dropTable('table');
$this->assertTableNotExist('table');
}
+
+ private function getTextValueByIntergerField($integerField) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->select('textfield')
+ ->from('table')
+ ->where($builder->expr()->eq('integerfield', $builder->createNamedParameter($integerField, \PDO::PARAM_INT)));
+
+ $result = $query->execute();
+ return $result->fetchColumn();
+ }
+
+ public function testSetValues() {
+ $this->makeTestTable();
+ $this->connection->setValues('table', [
+ 'integerfield' => 1
+ ], [
+ 'textfield' => 'foo',
+ 'clobfield' => 'not_null'
+ ]);
+
+ $this->assertEquals('foo', $this->getTextValueByIntergerField(1));
+
+ $this->connection->dropTable('table');
+ }
+
+ public function testSetValuesOverWrite() {
+ $this->makeTestTable();
+ $this->connection->setValues('table', [
+ 'integerfield' => 1
+ ], [
+ 'textfield' => 'foo',
+ 'clobfield' => 'not_null'
+ ]);
+
+ $this->connection->setValues('table', [
+ 'integerfield' => 1
+ ], [
+ 'textfield' => 'bar'
+ ]);
+
+ $this->assertEquals('bar', $this->getTextValueByIntergerField(1));
+
+ $this->connection->dropTable('table');
+ }
+
+ public function testSetValuesOverWritePrecondition() {
+ $this->makeTestTable();
+ $this->connection->setValues('table', [
+ 'integerfield' => 1
+ ], [
+ 'textfield' => 'foo',
+ 'booleanfield' => true,
+ 'clobfield' => 'not_null'
+ ]);
+
+ $this->connection->setValues('table', [
+ 'integerfield' => 1
+ ], [
+ 'textfield' => 'bar'
+ ], [
+ 'booleanfield' => true
+ ]);
+
+ $this->assertEquals('bar', $this->getTextValueByIntergerField(1));
+
+ $this->connection->dropTable('table');
+ }
+
+ /**
+ * @expectedException \OCP\PreConditionNotMetException
+ */
+ public function testSetValuesOverWritePreconditionFailed() {
+ $this->makeTestTable();
+ $this->connection->setValues('table', [
+ 'integerfield' => 1
+ ], [
+ 'textfield' => 'foo',
+ 'booleanfield' => true,
+ 'clobfield' => 'not_null'
+ ]);
+
+ $this->connection->setValues('table', [
+ 'integerfield' => 1
+ ], [
+ 'textfield' => 'bar'
+ ], [
+ 'booleanfield' => false
+ ]);
+ }
}
diff --git a/tests/lib/db/mdb2schemamanager.php b/tests/lib/db/mdb2schemamanager.php
index 8ce6febf3ac..fd412bdec2d 100644
--- a/tests/lib/db/mdb2schemamanager.php
+++ b/tests/lib/db/mdb2schemamanager.php
@@ -11,13 +11,20 @@ namespace Test\DB;
use Doctrine\DBAL\Platforms\OraclePlatform;
+/**
+ * Class MDB2SchemaManager
+ *
+ * @group DB
+ *
+ * @package Test\DB
+ */
class MDB2SchemaManager extends \Test\TestCase {
protected function tearDown() {
// do not drop the table for Oracle as it will create a bogus transaction
// that will break the following test suites requiring transactions
if (\OC::$server->getConfig()->getSystemValue('dbtype', 'sqlite') !== 'oci') {
- \OC_DB::dropTable('table');
+ \OC::$server->getDatabaseConnection()->dropTable('table');
}
parent::tearDown();
@@ -25,7 +32,7 @@ class MDB2SchemaManager extends \Test\TestCase {
public function testAutoIncrement() {
- $connection = \OC_DB::getConnection();
+ $connection = \OC::$server->getDatabaseConnection();
if ($connection->getDatabasePlatform() instanceof OraclePlatform) {
$this->markTestSkipped('Adding auto increment columns in Oracle is not supported.');
}
diff --git a/tests/lib/db/migrator.php b/tests/lib/db/migrator.php
index 4d558909743..84a98c1e338 100644
--- a/tests/lib/db/migrator.php
+++ b/tests/lib/db/migrator.php
@@ -15,6 +15,13 @@ use \Doctrine\DBAL\Schema\Schema;
use \Doctrine\DBAL\Schema\SchemaConfig;
use OCP\IConfig;
+/**
+ * Class Migrator
+ *
+ * @group DB
+ *
+ * @package Test\DB
+ */
class Migrator extends \Test\TestCase {
/**
* @var \Doctrine\DBAL\Connection $connection
@@ -38,7 +45,7 @@ class Migrator extends \Test\TestCase {
parent::setUp();
$this->config = \OC::$server->getConfig();
- $this->connection = \OC_DB::getConnection();
+ $this->connection = \OC::$server->getDatabaseConnection();
if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
$this->markTestSkipped('DB migration tests are not supported on OCI');
}
diff --git a/tests/lib/db/mysqlmigration.php b/tests/lib/db/mysqlmigration.php
index 6c283e6c59c..51e8801dc3b 100644
--- a/tests/lib/db/mysqlmigration.php
+++ b/tests/lib/db/mysqlmigration.php
@@ -6,6 +6,11 @@
* See the COPYING-README file.
*/
+/**
+ * Class TestMySqlMigration
+ *
+ * @group DB
+ */
class TestMySqlMigration extends \Test\TestCase {
/** @var \Doctrine\DBAL\Connection */
@@ -17,7 +22,7 @@ class TestMySqlMigration extends \Test\TestCase {
protected function setUp() {
parent::setUp();
- $this->connection = \OC_DB::getConnection();
+ $this->connection = \OC::$server->getDatabaseConnection();
if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MySqlPlatform) {
$this->markTestSkipped("Test only relevant on MySql");
}
diff --git a/tests/lib/db/querybuilder/expressionbuildertest.php b/tests/lib/db/querybuilder/expressionbuildertest.php
index f041df01019..8310c4adf68 100644
--- a/tests/lib/db/querybuilder/expressionbuildertest.php
+++ b/tests/lib/db/querybuilder/expressionbuildertest.php
@@ -23,22 +23,34 @@ namespace Test\DB\QueryBuilder;
use Doctrine\DBAL\Query\Expression\ExpressionBuilder as DoctrineExpressionBuilder;
use OC\DB\QueryBuilder\ExpressionBuilder;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use Test\TestCase;
-class ExpressionBuilderTest extends \Test\TestCase {
+/**
+ * Class ExpressionBuilderTest
+ *
+ * @group DB
+ *
+ * @package Test\DB\QueryBuilder
+ */
+class ExpressionBuilderTest extends TestCase {
/** @var ExpressionBuilder */
protected $expressionBuilder;
/** @var DoctrineExpressionBuilder */
protected $doctrineExpressionBuilder;
+ /** @var \Doctrine\DBAL\Connection|\OCP\IDBConnection */
+ protected $connection;
+
protected function setUp() {
parent::setUp();
- $connection = \OC::$server->getDatabaseConnection();
+ $this->connection = \OC::$server->getDatabaseConnection();
- $this->expressionBuilder = new ExpressionBuilder($connection);
+ $this->expressionBuilder = new ExpressionBuilder($this->connection);
- $this->doctrineExpressionBuilder = new DoctrineExpressionBuilder($connection);
+ $this->doctrineExpressionBuilder = new DoctrineExpressionBuilder($this->connection);
}
public function dataComparison() {
@@ -335,4 +347,81 @@ class ExpressionBuilderTest extends \Test\TestCase {
$actual->__toString()
);
}
+
+ public function dataClobComparisons() {
+ return [
+ ['eq', '5', IQueryBuilder::PARAM_STR, false, 3],
+ ['eq', '5', IQueryBuilder::PARAM_STR, true, 1],
+ ['neq', '5', IQueryBuilder::PARAM_STR, false, 6],
+ ['neq', '5', IQueryBuilder::PARAM_STR, true, 4],
+ ['lt', '5', IQueryBuilder::PARAM_STR, false, 3],
+ ['lt', '5', IQueryBuilder::PARAM_STR, true, 1],
+ ['lte', '5', IQueryBuilder::PARAM_STR, false, 6],
+ ['lte', '5', IQueryBuilder::PARAM_STR, true, 4],
+ ['gt', '5', IQueryBuilder::PARAM_STR, false, 3],
+ ['gt', '5', IQueryBuilder::PARAM_STR, true, 1],
+ ['gte', '5', IQueryBuilder::PARAM_STR, false, 6],
+ ['gte', '5', IQueryBuilder::PARAM_STR, true, 4],
+ ['like', '%5%', IQueryBuilder::PARAM_STR, false, 3],
+ ['like', '%5%', IQueryBuilder::PARAM_STR, true, 1],
+ ['notLike', '%5%', IQueryBuilder::PARAM_STR, false, 6],
+ ['notLike', '%5%', IQueryBuilder::PARAM_STR, true, 4],
+ ['in', ['5'], IQueryBuilder::PARAM_STR_ARRAY, false, 3],
+ ['in', ['5'], IQueryBuilder::PARAM_STR_ARRAY, true, 1],
+ ['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, false, 6],
+ ['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, true, 4],
+ ];
+ }
+
+ /**
+ * @dataProvider dataClobComparisons
+ * @param string $function
+ * @param mixed $value
+ * @param mixed $type
+ * @param bool $compareKeyToValue
+ * @param int $expected
+ */
+ public function testClobComparisons($function, $value, $type, $compareKeyToValue, $expected) {
+ $appId = $this->getUniqueID('testing');
+ $this->createConfig($appId, 1, 4);
+ $this->createConfig($appId, 2, 5);
+ $this->createConfig($appId, 3, 6);
+ $this->createConfig($appId, 4, 4);
+ $this->createConfig($appId, 5, 5);
+ $this->createConfig($appId, 6, 6);
+ $this->createConfig($appId, 7, 4);
+ $this->createConfig($appId, 8, 5);
+ $this->createConfig($appId, 9, 6);
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select($query->createFunction('COUNT(*) AS `count`'))
+ ->from('appconfig')
+ ->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
+ ->andWhere(call_user_func([$query->expr(), $function], 'configvalue', $query->createNamedParameter($value, $type), IQueryBuilder::PARAM_STR));
+
+ if ($compareKeyToValue) {
+ $query->andWhere(call_user_func([$query->expr(), $function], 'configkey', 'configvalue', IQueryBuilder::PARAM_STR));
+ }
+
+ $result = $query->execute();
+
+ $this->assertEquals(['count' => $expected], $result->fetch());
+ $result->closeCursor();
+
+ $query = $this->connection->getQueryBuilder();
+ $query->delete('appconfig')
+ ->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
+ ->execute();
+ }
+
+ protected function createConfig($appId, $key, $value) {
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('appconfig')
+ ->values([
+ 'appid' => $query->createNamedParameter($appId),
+ 'configkey' => $query->createNamedParameter((string) $key),
+ 'configvalue' => $query->createNamedParameter((string) $value),
+ ])
+ ->execute();
+ }
}
diff --git a/tests/lib/db/querybuilder/querybuildertest.php b/tests/lib/db/querybuilder/querybuildertest.php
index 75e62ba944e..de8f84ac345 100644
--- a/tests/lib/db/querybuilder/querybuildertest.php
+++ b/tests/lib/db/querybuilder/querybuildertest.php
@@ -27,6 +27,13 @@ use OC\DB\QueryBuilder\Parameter;
use OC\DB\QueryBuilder\QueryBuilder;
use OCP\IDBConnection;
+/**
+ * Class QueryBuilderTest
+ *
+ * @group DB
+ *
+ * @package Test\DB\QueryBuilder
+ */
class QueryBuilderTest extends \Test\TestCase {
/** @var QueryBuilder */
protected $queryBuilder;
@@ -41,12 +48,12 @@ class QueryBuilderTest extends \Test\TestCase {
$this->queryBuilder = new QueryBuilder($this->connection);
}
- protected function createTestingRows() {
+ protected function createTestingRows($appId = 'testFirstResult') {
$qB = $this->connection->getQueryBuilder();
for ($i = 1; $i < 10; $i++) {
$qB->insert('*PREFIX*appconfig')
->values([
- 'appid' => $qB->expr()->literal('testFirstResult'),
+ 'appid' => $qB->expr()->literal($appId),
'configkey' => $qB->expr()->literal('testing' . $i),
'configvalue' => $qB->expr()->literal(100 - $i),
])
@@ -73,11 +80,11 @@ class QueryBuilderTest extends \Test\TestCase {
return $rows;
}
- protected function deleteTestingRows() {
+ protected function deleteTestingRows($appId = 'testFirstResult') {
$qB = $this->connection->getQueryBuilder();
$qB->delete('*PREFIX*appconfig')
- ->where($qB->expr()->eq('appid', $qB->expr()->literal('testFirstResult')))
+ ->where($qB->expr()->eq('appid', $qB->expr()->literal($appId)))
->execute();
}
@@ -159,24 +166,25 @@ class QueryBuilderTest extends \Test\TestCase {
}
public function dataSelect() {
+ $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection());
return [
// select('column1')
- [['column1'], ['`column1`'], '`column1`'],
+ [['configvalue'], ['configvalue' => '99']],
// select('column1', 'column2')
- [['column1', 'column2'], ['`column1`', '`column2`'], '`column1`, `column2`'],
+ [['configvalue', 'configkey'], ['configvalue' => '99', 'configkey' => 'testing1']],
// select(['column1', 'column2'])
- [[['column1', 'column2']], ['`column1`', '`column2`'], '`column1`, `column2`'],
+ [[['configvalue', 'configkey']], ['configvalue' => '99', 'configkey' => 'testing1']],
// select(new Literal('column1'))
- [[new Literal('column1')], ['column1'], 'column1'],
+ [[$queryBuilder->expr()->literal('column1')], [], 'column1'],
// select('column1', 'column2')
- [[new Literal('column1'), 'column2'], ['column1', '`column2`'], 'column1, `column2`'],
+ [[$queryBuilder->expr()->literal('column1'), 'configkey'], ['configkey' => 'testing1'], 'column1'],
// select(['column1', 'column2'])
- [[[new Literal('column1'), 'column2']], ['column1', '`column2`'], 'column1, `column2`'],
+ [[[$queryBuilder->expr()->literal('column1'), 'configkey']], ['configkey' => 'testing1'], 'column1'],
];
}
@@ -184,45 +192,134 @@ class QueryBuilderTest extends \Test\TestCase {
* @dataProvider dataSelect
*
* @param array $selectArguments
- * @param array $expectedQueryPart
- * @param string $expectedSelect
+ * @param array $expected
+ * @param string $expectedLiteral
*/
- public function testSelect($selectArguments, $expectedQueryPart, $expectedSelect) {
+ public function testSelect($selectArguments, $expected, $expectedLiteral = '') {
+ $this->deleteTestingRows();
+ $this->createTestingRows();
+
call_user_func_array(
[$this->queryBuilder, 'select'],
$selectArguments
);
- $this->assertSame(
- $expectedQueryPart,
- $this->queryBuilder->getQueryPart('select')
+ $this->queryBuilder->from('*PREFIX*appconfig')
+ ->where($this->queryBuilder->expr()->eq(
+ 'appid',
+ $this->queryBuilder->expr()->literal('testFirstResult')
+ ))
+ ->orderBy('configkey', 'ASC')
+ ->setMaxResults(1);
+
+ $query = $this->queryBuilder->execute();
+ $row = $query->fetch();
+ $query->closeCursor();
+
+ foreach ($expected as $key => $value) {
+ $this->assertArrayHasKey($key, $row);
+ $this->assertEquals($value, $row[$key]);
+ unset($row[$key]);
+ }
+
+ if ($expectedLiteral) {
+ $this->assertEquals([$expectedLiteral], array_values($row));
+ } else {
+ $this->assertEmpty($row);
+ }
+
+ $this->deleteTestingRows();
+ }
+
+ public function dataSelectAlias() {
+ $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection());
+ return [
+ ['configvalue', 'cv', ['cv' => '99']],
+ [$queryBuilder->expr()->literal('column1'), 'thing', ['thing' => 'column1']],
+ ];
+ }
+
+ /**
+ * @dataProvider dataSelectAlias
+ *
+ * @param mixed $select
+ * @param array $alias
+ * @param array $expected
+ */
+ public function testSelectAlias($select, $alias, $expected) {
+ $this->deleteTestingRows();
+ $this->createTestingRows();
+
+ $this->queryBuilder->selectAlias($select, $alias);
+
+ $this->queryBuilder->from('*PREFIX*appconfig')
+ ->where($this->queryBuilder->expr()->eq(
+ 'appid',
+ $this->queryBuilder->expr()->literal('testFirstResult')
+ ))
+ ->orderBy('configkey', 'ASC')
+ ->setMaxResults(1);
+
+ $query = $this->queryBuilder->execute();
+ $row = $query->fetch();
+ $query->closeCursor();
+
+ $this->assertEquals(
+ $expected,
+ $row
);
- $this->assertSame(
- 'SELECT ' . $expectedSelect . ' FROM ',
- $this->queryBuilder->getSQL()
+ $this->deleteTestingRows();
+ }
+
+ public function testSelectDistinct() {
+ $this->deleteTestingRows('testFirstResult1');
+ $this->deleteTestingRows('testFirstResult2');
+ $this->createTestingRows('testFirstResult1');
+ $this->createTestingRows('testFirstResult2');
+
+ $this->queryBuilder->selectDistinct('appid');
+
+ $this->queryBuilder->from('*PREFIX*appconfig')
+ ->where($this->queryBuilder->expr()->in(
+ 'appid',
+ [$this->queryBuilder->expr()->literal('testFirstResult1'), $this->queryBuilder->expr()->literal('testFirstResult2')]
+ ))
+ ->orderBy('appid', 'DESC');
+
+ $query = $this->queryBuilder->execute();
+ $rows = $query->fetchAll();
+ $query->closeCursor();
+
+ $this->assertEquals(
+ [['appid' => 'testFirstResult2'], ['appid' => 'testFirstResult1']],
+ $rows
);
+
+ $this->deleteTestingRows('testFirstResult1');
+ $this->deleteTestingRows('testFirstResult2');
}
public function dataAddSelect() {
+ $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection());
return [
// addSelect('column1')
- [['column1'], ['`column`', '`column1`'], '`column`, `column1`'],
+ [['configvalue'], ['appid' => 'testFirstResult', 'configvalue' => '99']],
// addSelect('column1', 'column2')
- [['column1', 'column2'], ['`column`', '`column1`', '`column2`'], '`column`, `column1`, `column2`'],
+ [['configvalue', 'configkey'], ['appid' => 'testFirstResult', 'configvalue' => '99', 'configkey' => 'testing1']],
// addSelect(['column1', 'column2'])
- [[['column1', 'column2']], ['`column`', '`column1`', '`column2`'], '`column`, `column1`, `column2`'],
+ [[['configvalue', 'configkey']], ['appid' => 'testFirstResult', 'configvalue' => '99', 'configkey' => 'testing1']],
// select(new Literal('column1'))
- [[new Literal('column1')], ['`column`', 'column1'], '`column`, column1'],
+ [[$queryBuilder->expr()->literal('column1')], ['appid' => 'testFirstResult'], 'column1'],
// select('column1', 'column2')
- [[new Literal('column1'), 'column2'], ['`column`', 'column1', '`column2`'], '`column`, column1, `column2`'],
+ [[$queryBuilder->expr()->literal('column1'), 'configkey'], ['appid' => 'testFirstResult', 'configkey' => 'testing1'], 'column1'],
// select(['column1', 'column2'])
- [[[new Literal('column1'), 'column2']], ['`column`', 'column1', '`column2`'], '`column`, column1, `column2`'],
+ [[[$queryBuilder->expr()->literal('column1'), 'configkey']], ['appid' => 'testFirstResult', 'configkey' => 'testing1'], 'column1'],
];
}
@@ -230,25 +327,45 @@ class QueryBuilderTest extends \Test\TestCase {
* @dataProvider dataAddSelect
*
* @param array $selectArguments
- * @param array $expectedQueryPart
- * @param string $expectedSelect
+ * @param array $expected
+ * @param string $expectedLiteral
*/
- public function testAddSelect($selectArguments, $expectedQueryPart, $expectedSelect) {
- $this->queryBuilder->select('column');
+ public function testAddSelect($selectArguments, $expected, $expectedLiteral = '') {
+ $this->deleteTestingRows();
+ $this->createTestingRows();
+
+ $this->queryBuilder->select('appid');
+
call_user_func_array(
[$this->queryBuilder, 'addSelect'],
$selectArguments
);
- $this->assertSame(
- $expectedQueryPart,
- $this->queryBuilder->getQueryPart('select')
- );
+ $this->queryBuilder->from('*PREFIX*appconfig')
+ ->where($this->queryBuilder->expr()->eq(
+ 'appid',
+ $this->queryBuilder->expr()->literal('testFirstResult')
+ ))
+ ->orderBy('configkey', 'ASC')
+ ->setMaxResults(1);
- $this->assertSame(
- 'SELECT ' . $expectedSelect . ' FROM ',
- $this->queryBuilder->getSQL()
- );
+ $query = $this->queryBuilder->execute();
+ $row = $query->fetch();
+ $query->closeCursor();
+
+ foreach ($expected as $key => $value) {
+ $this->assertArrayHasKey($key, $row);
+ $this->assertEquals($value, $row[$key]);
+ unset($row[$key]);
+ }
+
+ if ($expectedLiteral) {
+ $this->assertEquals([$expectedLiteral], array_values($row));
+ } else {
+ $this->assertEmpty($row);
+ }
+
+ $this->deleteTestingRows();
}
public function dataDelete() {
@@ -997,6 +1114,43 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
+ public function testGetLastInsertId() {
+ $qB = $this->connection->getQueryBuilder();
+
+ try {
+ $qB->getLastInsertId();
+ $this->fail('getLastInsertId() should throw an exception, when being called before insert()');
+ } catch (\BadMethodCallException $e) {
+ $this->assertTrue(true);
+ }
+
+ $qB->insert('properties')
+ ->values([
+ 'userid' => $qB->expr()->literal('testFirstResult'),
+ 'propertypath' => $qB->expr()->literal('testing'),
+ 'propertyname' => $qB->expr()->literal('testing'),
+ 'propertyvalue' => $qB->expr()->literal('testing'),
+ ])
+ ->execute();
+
+ $actual = $qB->getLastInsertId();
+
+ $this->assertNotNull($actual);
+ $this->assertInternalType('int', $actual);
+ $this->assertEquals($this->connection->lastInsertId('*PREFIX*properties'), $actual);
+
+ $qB->delete('properties')
+ ->where($qB->expr()->eq('userid', $qB->expr()->literal('testFirstResult')))
+ ->execute();
+
+ try {
+ $qB->getLastInsertId();
+ $this->fail('getLastInsertId() should throw an exception, when being called after delete()');
+ } catch (\BadMethodCallException $e) {
+ $this->assertTrue(true);
+ }
+ }
+
public function dataGetTableName() {
return [
['*PREFIX*table', null, '`*PREFIX*table`'],
@@ -1023,7 +1177,27 @@ class QueryBuilderTest extends \Test\TestCase {
$this->assertSame(
$expected,
- $this->invokePrivate($this->queryBuilder, 'getTableName', [$tableName])
+ $this->queryBuilder->getTableName($tableName)
+ );
+ }
+
+ public function dataGetColumnName() {
+ return [
+ ['column', '', '`column`'],
+ ['column', 'a', 'a.`column`'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataGetColumnName
+ * @param string $column
+ * @param string $prefix
+ * @param string $expected
+ */
+ public function testGetColumnName($column, $prefix, $expected) {
+ $this->assertSame(
+ $expected,
+ $this->queryBuilder->getColumnName($column, $prefix)
);
}
}
diff --git a/tests/lib/db/sqlitemigration.php b/tests/lib/db/sqlitemigration.php
index 9206381ff71..f23f4d4ee86 100644
--- a/tests/lib/db/sqlitemigration.php
+++ b/tests/lib/db/sqlitemigration.php
@@ -6,6 +6,11 @@
* See the COPYING-README file.
*/
+/**
+ * Class TestSqliteMigration
+ *
+ * @group DB
+ */
class TestSqliteMigration extends \Test\TestCase {
/** @var \Doctrine\DBAL\Connection */
@@ -17,7 +22,7 @@ class TestSqliteMigration extends \Test\TestCase {
protected function setUp() {
parent::setUp();
- $this->connection = \OC_DB::getConnection();
+ $this->connection = \OC::$server->getDatabaseConnection();
if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) {
$this->markTestSkipped("Test only relevant on Sqlite");
}
diff --git a/tests/lib/dbschema.php b/tests/lib/dbschema.php
index 97307664b6a..11eacbf397f 100644
--- a/tests/lib/dbschema.php
+++ b/tests/lib/dbschema.php
@@ -9,6 +9,11 @@
use OCP\Security\ISecureRandom;
+/**
+ * Class Test_DBSchema
+ *
+ * @group DB
+ */
class Test_DBSchema extends \Test\TestCase {
protected $schema_file = 'static://test_db_scheme';
protected $schema_file2 = 'static://test_db_scheme2';
@@ -21,7 +26,7 @@ class Test_DBSchema extends \Test\TestCase {
$dbfile = OC::$SERVERROOT.'/tests/data/db_structure.xml';
$dbfile2 = OC::$SERVERROOT.'/tests/data/db_structure2.xml';
- $r = '_' . \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->
+ $r = '_' . \OC::$server->getSecureRandom()->
generate(4, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS) . '_';
$content = file_get_contents( $dbfile );
$content = str_replace( '*dbprefix*', '*dbprefix*'.$r, $content );
@@ -46,7 +51,7 @@ class Test_DBSchema extends \Test\TestCase {
* @medium
*/
public function testSchema() {
- $platform = \OC_DB::getConnection()->getDatabasePlatform();
+ $platform = \OC::$server->getDatabaseConnection()->getDatabasePlatform();
$this->doTestSchemaCreating();
$this->doTestSchemaChanging();
$this->doTestSchemaDumping();
@@ -89,7 +94,7 @@ class Test_DBSchema extends \Test\TestCase {
* @param string $table
*/
public function assertTableNotExist($table) {
- $platform = \OC_DB::getConnection()->getDatabasePlatform();
+ $platform = \OC::$server->getDatabaseConnection()->getDatabasePlatform();
if ($platform instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) {
// sqlite removes the tables after closing the DB
$this->assertTrue(true);
diff --git a/tests/lib/encryption/decryptalltest.php b/tests/lib/encryption/decryptalltest.php
index ce5bcf1e5ae..85fbe3e0ed9 100644
--- a/tests/lib/encryption/decryptalltest.php
+++ b/tests/lib/encryption/decryptalltest.php
@@ -30,6 +30,13 @@ use OC\Files\View;
use OCP\IUserManager;
use Test\TestCase;
+/**
+ * Class DecryptAllTest
+ *
+ * @group DB
+ *
+ * @package Test\Encryption
+ */
class DecryptAllTest extends TestCase {
/** @var \PHPUnit_Framework_MockObject_MockObject | IUserManager */
diff --git a/tests/lib/files/cache/cache.php b/tests/lib/files/cache/cache.php
index c5395a97fd4..54aa7ad789a 100644
--- a/tests/lib/files/cache/cache.php
+++ b/tests/lib/files/cache/cache.php
@@ -16,6 +16,13 @@ class LongId extends \OC\Files\Storage\Temporary {
}
}
+/**
+ * Class Cache
+ *
+ * @group DB
+ *
+ * @package Test\Files\Cache
+ */
class Cache extends \Test\TestCase {
/**
* @var \OC\Files\Storage\Temporary $storage ;
@@ -310,7 +317,7 @@ class Cache extends \Test\TestCase {
function testSearchByTag() {
$userId = $this->getUniqueId('user');
- \OC_User::createUser($userId, $userId);
+ \OC::$server->getUserManager()->createUser($userId, $userId);
$this->loginAsUser($userId);
$user = new \OC\User\User($userId, null);
@@ -366,7 +373,8 @@ class Cache extends \Test\TestCase {
$tagManager->delete('tag2');
$this->logout();
- \OC_User::deleteUser($userId);
+ $user = \OC::$server->getUserManager()->get($userId);
+ if ($user !== null) { $user->delete(); }
}
function testMove() {
@@ -548,7 +556,7 @@ class Cache extends \Test\TestCase {
$this->assertEquals($folderWith00F6, $unNormalizedFolderName['name']);
// put normalized folder
- $this->assertTrue(is_array($this->cache->get('folder/' . $folderWith00F6)));
+ $this->assertInstanceOf('\OCP\Files\Cache\ICacheEntry', $this->cache->get('folder/' . $folderWith00F6));
$this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith00F6, $data));
// at this point we should have only one folder named "Schön"
@@ -633,8 +641,8 @@ class Cache extends \Test\TestCase {
$this->cache->put($name, $folderData);
$this->cache->put('other', $folderData);
$childs = ['asd', 'bar', 'foo', 'sub/folder'];
- $this->cache->put($name . '/sub/folder', $folderData);
- $this->cache->put('other/sub/folder', $folderData);
+ $this->cache->put($name . '/sub', $folderData);
+ $this->cache->put('other/sub', $folderData);
foreach ($childs as $child) {
$this->cache->put($name . '/' . $child, $data);
$this->cache->put('other/' . $child, $data);
diff --git a/tests/lib/files/cache/changepropagator.php b/tests/lib/files/cache/changepropagator.php
deleted file mode 100644
index 1b56da5e97c..00000000000
--- a/tests/lib/files/cache/changepropagator.php
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-/**
- * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-namespace Test\Files\Cache;
-
-use OC\Files\Filesystem;
-use OC\Files\Storage\Temporary;
-use OC\Files\View;
-
-class ChangePropagator extends \Test\TestCase {
- /**
- * @var \OC\Files\Cache\ChangePropagator
- */
- private $propagator;
-
- /**
- * @var \OC\Files\View
- */
- private $view;
-
- /**
- * @var \OC\Files\Storage\Storage
- */
- private $storage;
-
- protected function setUp() {
- parent::setUp();
-
- $this->storage = new Temporary(array());
- $root = $this->getUniqueID('/');
- Filesystem::mount($this->storage, array(), $root);
- $this->view = new View($root);
- $this->propagator = new \OC\Files\Cache\ChangePropagator($this->view);
- }
-
- public function testGetParentsSingle() {
- $this->propagator->addChange('/foo/bar/asd');
- $this->assertEquals(array('/', '/foo', '/foo/bar'), $this->propagator->getAllParents());
- }
-
- public function testGetParentsMultiple() {
- $this->propagator->addChange('/foo/bar/asd');
- $this->propagator->addChange('/foo/qwerty');
- $this->propagator->addChange('/foo/asd/bar');
- $this->assertEquals(array('/', '/foo', '/foo/bar', '/foo/asd'), $this->propagator->getAllParents());
- }
-
- public function testSinglePropagate() {
- $this->view->mkdir('/foo');
- $this->view->mkdir('/foo/bar');
- $this->view->file_put_contents('/foo/bar/sad.txt', 'qwerty');
-
- $oldInfo1 = $this->view->getFileInfo('/');
- $oldInfo2 = $this->view->getFileInfo('/foo');
- $oldInfo3 = $this->view->getFileInfo('/foo/bar');
-
- $time = time() + 50;
-
- $this->propagator->addChange('/foo/bar/sad.txt');
- $this->propagator->propagateChanges($time);
-
- $newInfo1 = $this->view->getFileInfo('/');
- $newInfo2 = $this->view->getFileInfo('/foo');
- $newInfo3 = $this->view->getFileInfo('/foo/bar');
-
- $this->assertEquals($newInfo1->getMTime(), $time);
- $this->assertEquals($newInfo2->getMTime(), $time);
- $this->assertEquals($newInfo3->getMTime(), $time);
-
- $this->assertNotSame($oldInfo1->getEtag(), $newInfo1->getEtag());
- $this->assertNotSame($oldInfo2->getEtag(), $newInfo2->getEtag());
- $this->assertNotSame($oldInfo3->getEtag(), $newInfo3->getEtag());
- }
-
- public function testDontLowerMtime() {
- $time = time();
- $this->view->mkdir('/foo');
- $this->view->mkdir('/foo/bar');
-
- $cache = $this->storage->getCache();
- $cache->put('', ['mtime' => $time - 50]);
- $cache->put('foo', ['mtime' => $time - 150]);
- $cache->put('foo/bar', ['mtime' => $time - 250]);
-
- $this->propagator->addChange('/foo/bar/foo');
- $this->propagator->propagateChanges($time - 100);
-
- $this->assertEquals(50, $time - $cache->get('')['mtime']);
- $this->assertEquals(100, $time - $cache->get('foo')['mtime']);
- $this->assertEquals(100, $time - $cache->get('foo/bar')['mtime']);
- }
-}
diff --git a/tests/lib/files/cache/homecache.php b/tests/lib/files/cache/homecache.php
index 7ebb053bcfa..e133d0afc55 100644
--- a/tests/lib/files/cache/homecache.php
+++ b/tests/lib/files/cache/homecache.php
@@ -43,6 +43,13 @@ class DummyUser extends \OC\User\User {
}
}
+/**
+ * Class HomeCache
+ *
+ * @group DB
+ *
+ * @package Test\Files\Cache
+ */
class HomeCache extends \Test\TestCase {
/**
* @var \OC\Files\Storage\Home $storage
@@ -62,7 +69,7 @@ class HomeCache extends \Test\TestCase {
protected function setUp() {
parent::setUp();
- $this->user = new DummyUser('foo', \OC_Helper::tmpFolder());
+ $this->user = new DummyUser('foo', \OC::$server->getTempManager()->getTemporaryFolder());
$this->storage = new \OC\Files\Storage\Home(array('user' => $this->user));
$this->cache = $this->storage->getCache();
}
diff --git a/tests/lib/files/cache/movefromcachetraittest.php b/tests/lib/files/cache/movefromcachetraittest.php
new file mode 100644
index 00000000000..614c259d996
--- /dev/null
+++ b/tests/lib/files/cache/movefromcachetraittest.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Copyright (c) 2016 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Cache;
+
+use OC\Files\Cache\MoveFromCacheTrait;
+
+class FallBackCrossCacheMoveCache extends \OC\Files\Cache\Cache {
+ use MoveFromCacheTrait;
+}
+
+/**
+ * Class Cache
+ *
+ * @group DB
+ */
+class MoveFromCacheTraitTest extends Cache {
+ protected function setUp() {
+ parent::setUp();
+
+ $this->storage = new \OC\Files\Storage\Temporary(array());
+ $this->storage2 = new \OC\Files\Storage\Temporary(array());
+ $this->cache = new FallBackCrossCacheMoveCache($this->storage);
+ $this->cache2 = new FallBackCrossCacheMoveCache($this->storage2);
+ }
+}
diff --git a/tests/lib/files/cache/scanner.php b/tests/lib/files/cache/scanner.php
index 871b12bac3a..b1eb3f589e8 100644
--- a/tests/lib/files/cache/scanner.php
+++ b/tests/lib/files/cache/scanner.php
@@ -7,7 +7,15 @@
*/
namespace Test\Files\Cache;
+use OC\Files\Cache\CacheEntry;
+/**
+ * Class Scanner
+ *
+ * @group DB
+ *
+ * @package Test\Files\Cache
+ */
class Scanner extends \Test\TestCase {
/**
* @var \OC\Files\Storage\Storage $storage
@@ -219,6 +227,7 @@ class Scanner extends \Test\TestCase {
// manipulate etag to simulate an empty etag
$this->scanner->scan('', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG);
+ /** @var CacheEntry $data0 */
$data0 = $this->cache->get('folder/bar.txt');
$this->assertInternalType('string', $data0['etag']);
$data1 = $this->cache->get('folder');
@@ -226,7 +235,7 @@ class Scanner extends \Test\TestCase {
$data2 = $this->cache->get('');
$this->assertInternalType('string', $data2['etag']);
$data0['etag'] = '';
- $this->cache->put('folder/bar.txt', $data0);
+ $this->cache->put('folder/bar.txt', $data0->getData());
// rescan
$this->scanner->scan('folder/bar.txt', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG);
diff --git a/tests/lib/files/cache/updater.php b/tests/lib/files/cache/updater.php
index b7e76aeace4..cdffac464dc 100644
--- a/tests/lib/files/cache/updater.php
+++ b/tests/lib/files/cache/updater.php
@@ -12,6 +12,13 @@ use OC\Files\Filesystem;
use OC\Files\Storage\Temporary;
use OC\Files\View;
+/**
+ * Class Updater
+ *
+ * @group DB
+ *
+ * @package Test\Files\Cache
+ */
class Updater extends \Test\TestCase {
/**
* @var \OC\Files\Storage\Storage
@@ -39,9 +46,7 @@ class Updater extends \Test\TestCase {
$this->loginAsUser();
$this->storage = new Temporary(array());
- Filesystem::mount($this->storage, array(), '/');
- $this->view = new View('');
- $this->updater = new \OC\Files\Cache\Updater($this->view);
+ $this->updater = $this->storage->getUpdater();
$this->cache = $this->storage->getCache();
}
@@ -56,7 +61,7 @@ class Updater extends \Test\TestCase {
$this->storage->file_put_contents('foo.txt', 'bar');
$this->assertFalse($this->cache->inCache('foo.txt'));
- $this->updater->update('/foo.txt');
+ $this->updater->update('foo.txt');
$this->assertTrue($this->cache->inCache('foo.txt'));
$cached = $this->cache->get('foo.txt');
@@ -65,7 +70,9 @@ class Updater extends \Test\TestCase {
}
public function testUpdatedFile() {
- $this->view->file_put_contents('/foo.txt', 'bar');
+ $this->storage->file_put_contents('foo.txt', 'bar');
+ $this->updater->update('foo.txt');
+
$cached = $this->cache->get('foo.txt');
$this->assertEquals(3, $cached['size']);
$this->assertEquals('text/plain', $cached['mimetype']);
@@ -131,7 +138,7 @@ class Updater extends \Test\TestCase {
$this->assertTrue($this->cache->inCache('foo.txt'));
$this->assertFalse($this->cache->inCache('bar.txt'));
- $this->updater->rename('foo.txt', 'bar.txt');
+ $this->updater->renameFromStorage($this->storage, 'foo.txt', 'bar.txt');
$this->assertFalse($this->cache->inCache('foo.txt'));
$this->assertTrue($this->cache->inCache('bar.txt'));
@@ -149,7 +156,7 @@ class Updater extends \Test\TestCase {
$cached = $this->cache->get('bar.txt');
- $this->updater->rename('foo.txt', 'bar.txt');
+ $this->updater->renameFromStorage($this->storage, 'foo.txt', 'bar.txt');
$this->assertFalse($this->cache->inCache('foo.txt'));
$this->assertTrue($this->cache->inCache('bar.txt'));
@@ -186,7 +193,7 @@ class Updater extends \Test\TestCase {
// some storages (like Dropbox) change storage mtime on rename
$this->storage->touch('sub2/bar.txt', $testmtime);
- $this->updater->rename('sub/foo.txt', 'sub2/bar.txt');
+ $this->updater->renameFromStorage($this->storage, 'sub/foo.txt', 'sub2/bar.txt');
$cachedTargetParent = $this->cache->get('sub2');
$cachedTarget = $this->cache->get('sub2/bar.txt');
@@ -212,26 +219,6 @@ class Updater extends \Test\TestCase {
$this->assertFalse($this->cache->inCache('foo.txt'));
}
- public function testMoveDisabled() {
- $this->storage->file_put_contents('foo.txt', 'qwerty');
- $this->updater->update('foo.txt');
-
- $this->assertTrue($this->cache->inCache('foo.txt'));
- $this->assertFalse($this->cache->inCache('bar.txt'));
- $cached = $this->cache->get('foo.txt');
-
- $this->storage->rename('foo.txt', 'bar.txt');
-
- $this->assertTrue($this->cache->inCache('foo.txt'));
- $this->assertFalse($this->cache->inCache('bar.txt'));
-
- $this->updater->disable();
- $this->updater->rename('foo.txt', 'bar.txt');
-
- $this->assertTrue($this->cache->inCache('foo.txt'));
- $this->assertFalse($this->cache->inCache('bar.txt'));
- }
-
public function testMoveCrossStorage() {
$storage2 = new Temporary(array());
$cache2 = $storage2->getCache();
@@ -251,7 +238,7 @@ class Updater extends \Test\TestCase {
$this->assertTrue($this->cache->inCache('foo.txt'));
$this->assertFalse($cache2->inCache('bar.txt'));
- $this->updater->rename('foo.txt', 'bar/bar.txt');
+ $storage2->getUpdater()->renameFromStorage($this->storage, 'foo.txt', 'bar.txt');
$this->assertFalse($this->cache->inCache('foo.txt'));
$this->assertTrue($cache2->inCache('bar.txt'));
@@ -288,7 +275,8 @@ class Updater extends \Test\TestCase {
$cached[] = $this->cache->get('foo/bar/bar.txt');
// add extension to trigger the possible mimetype change
- $this->view->rename('/foo', '/bar/foo.b');
+ $storage2->moveFromStorage($this->storage, 'foo', 'foo.b');
+ $storage2->getUpdater()->renameFromStorage($this->storage, 'foo', 'foo.b');
$this->assertFalse($this->cache->inCache('foo'));
$this->assertFalse($this->cache->inCache('foo/foo.txt'));
diff --git a/tests/lib/files/cache/updaterlegacy.php b/tests/lib/files/cache/updaterlegacy.php
index f4d52e9a390..09688afd465 100644
--- a/tests/lib/files/cache/updaterlegacy.php
+++ b/tests/lib/files/cache/updaterlegacy.php
@@ -10,7 +10,15 @@ namespace Test\Files\Cache;
use \OC\Files\Filesystem as Filesystem;
use OC\Files\Storage\Temporary;
+use OC\Files\View;
+/**
+ * Class UpdaterLegacy
+ *
+ * @group DB
+ *
+ * @package Test\Files\Cache
+ */
class UpdaterLegacy extends \Test\TestCase {
/**
* @var \OC\Files\Storage\Storage $storage
@@ -49,7 +57,7 @@ class UpdaterLegacy extends \Test\TestCase {
self::$user = $this->getUniqueID();
}
- \OC_User::createUser(self::$user, 'password');
+ \OC::$server->getUserManager()->createUser(self::$user, 'password');
$this->loginAsUser(self::$user);
Filesystem::init(self::$user, '/' . self::$user . '/files');
@@ -64,7 +72,10 @@ class UpdaterLegacy extends \Test\TestCase {
if ($this->cache) {
$this->cache->clear();
}
- $result = \OC_User::deleteUser(self::$user);
+
+ $result = false;
+ $user = \OC::$server->getUserManager()->get(self::$user);
+ if ($user !== null) { $result = $user->delete(); }
$this->assertTrue($result);
$this->logout();
@@ -111,7 +122,8 @@ class UpdaterLegacy extends \Test\TestCase {
$storage2->getScanner()->scan(''); //initialize etags
$cache2 = $storage2->getCache();
Filesystem::mount($storage2, array(), '/' . self::$user . '/files/folder/substorage');
- $folderCachedData = $this->cache->get('folder');
+ $view = new View('/' . self::$user . '/files');
+ $folderCachedData = $view->getFileInfo('folder');
$substorageCachedData = $cache2->get('');
Filesystem::file_put_contents('folder/substorage/foo.txt', 'asd');
$this->assertTrue($cache2->inCache('foo.txt'));
@@ -124,7 +136,7 @@ class UpdaterLegacy extends \Test\TestCase {
$this->assertInternalType('string', $cachedData['etag']);
$this->assertNotSame($substorageCachedData['etag'], $cachedData['etag']);
- $cachedData = $this->cache->get('folder');
+ $cachedData = $view->getFileInfo('folder');
$this->assertInternalType('string', $folderCachedData['etag']);
$this->assertInternalType('string', $cachedData['etag']);
$this->assertNotSame($folderCachedData['etag'], $cachedData['etag']);
@@ -168,8 +180,9 @@ class UpdaterLegacy extends \Test\TestCase {
$cache2 = $storage2->getCache();
Filesystem::mount($storage2, array(), '/' . self::$user . '/files/folder/substorage');
Filesystem::file_put_contents('folder/substorage/foo.txt', 'asd');
+ $view = new View('/' . self::$user . '/files');
$this->assertTrue($cache2->inCache('foo.txt'));
- $folderCachedData = $this->cache->get('folder');
+ $folderCachedData = $view->getFileInfo('folder');
$substorageCachedData = $cache2->get('');
Filesystem::unlink('folder/substorage/foo.txt');
$this->assertFalse($cache2->inCache('foo.txt'));
@@ -180,7 +193,7 @@ class UpdaterLegacy extends \Test\TestCase {
$this->assertNotSame($substorageCachedData['etag'], $cachedData['etag']);
$this->assertGreaterThanOrEqual($substorageCachedData['mtime'], $cachedData['mtime']);
- $cachedData = $this->cache->get('folder');
+ $cachedData = $view->getFileInfo('folder');
$this->assertInternalType('string', $folderCachedData['etag']);
$this->assertInternalType('string', $cachedData['etag']);
$this->assertNotSame($folderCachedData['etag'], $cachedData['etag']);
@@ -222,8 +235,9 @@ class UpdaterLegacy extends \Test\TestCase {
$cache2 = $storage2->getCache();
Filesystem::mount($storage2, array(), '/' . self::$user . '/files/folder/substorage');
Filesystem::file_put_contents('folder/substorage/foo.txt', 'asd');
+ $view = new View('/' . self::$user . '/files');
$this->assertTrue($cache2->inCache('foo.txt'));
- $folderCachedData = $this->cache->get('folder');
+ $folderCachedData = $view->getFileInfo('folder');
$substorageCachedData = $cache2->get('');
$fooCachedData = $cache2->get('foo.txt');
Filesystem::rename('folder/substorage/foo.txt', 'folder/substorage/bar.txt');
@@ -240,7 +254,7 @@ class UpdaterLegacy extends \Test\TestCase {
// rename can cause mtime change - invalid assert
// $this->assertEquals($mtime, $cachedData['mtime']);
- $cachedData = $this->cache->get('folder');
+ $cachedData = $view->getFileInfo('folder');
$this->assertInternalType('string', $folderCachedData['etag']);
$this->assertInternalType('string', $cachedData['etag']);
$this->assertNotSame($folderCachedData['etag'], $cachedData['etag']);
@@ -287,35 +301,4 @@ class UpdaterLegacy extends \Test\TestCase {
$this->assertEquals($time, $cachedData['mtime']);
}
- public function testTouchWithMountPoints() {
- $storage2 = new \OC\Files\Storage\Temporary(array());
- $cache2 = $storage2->getCache();
- Filesystem::mount($storage2, array(), '/' . self::$user . '/files/folder/substorage');
- Filesystem::file_put_contents('folder/substorage/foo.txt', 'asd');
- $this->assertTrue($cache2->inCache('foo.txt'));
- $folderCachedData = $this->cache->get('folder');
- $substorageCachedData = $cache2->get('');
- $fooCachedData = $cache2->get('foo.txt');
- $cachedData = $cache2->get('foo.txt');
- $time = 1371006070;
- $this->cache->put('folder', ['mtime' => $time - 100]);
- Filesystem::touch('folder/substorage/foo.txt', $time);
- $cachedData = $cache2->get('foo.txt');
- $this->assertInternalType('string', $fooCachedData['etag']);
- $this->assertInternalType('string', $cachedData['etag']);
- $this->assertNotSame($fooCachedData['etag'], $cachedData['etag']);
- $this->assertEquals($time, $cachedData['mtime']);
-
- $cachedData = $cache2->get('');
- $this->assertInternalType('string', $substorageCachedData['etag']);
- $this->assertInternalType('string', $cachedData['etag']);
- $this->assertNotSame($substorageCachedData['etag'], $cachedData['etag']);
-
- $cachedData = $this->cache->get('folder');
- $this->assertInternalType('string', $folderCachedData['etag']);
- $this->assertInternalType('string', $cachedData['etag']);
- $this->assertNotSame($folderCachedData['etag'], $cachedData['etag']);
- $this->assertEquals($time, $cachedData['mtime']);
- }
-
}
diff --git a/tests/lib/files/cache/watcher.php b/tests/lib/files/cache/watcher.php
index acc03cc4c77..cb90e92b477 100644
--- a/tests/lib/files/cache/watcher.php
+++ b/tests/lib/files/cache/watcher.php
@@ -8,6 +8,13 @@
namespace Test\Files\Cache;
+/**
+ * Class Watcher
+ *
+ * @group DB
+ *
+ * @package Test\Files\Cache
+ */
class Watcher extends \Test\TestCase {
/**
diff --git a/tests/lib/files/cache/wrapper/cachejail.php b/tests/lib/files/cache/wrapper/cachejail.php
index 13f3dc8858e..9ddf3e9c61c 100644
--- a/tests/lib/files/cache/wrapper/cachejail.php
+++ b/tests/lib/files/cache/wrapper/cachejail.php
@@ -10,6 +10,13 @@ namespace Test\Files\Cache\Wrapper;
use Test\Files\Cache\Cache;
+/**
+ * Class CacheJail
+ *
+ * @group DB
+ *
+ * @package Test\Files\Cache\Wrapper
+ */
class CacheJail extends Cache {
/**
* @var \OC\Files\Cache\Cache $sourceCache
diff --git a/tests/lib/files/cache/wrapper/cachepermissionsmask.php b/tests/lib/files/cache/wrapper/cachepermissionsmask.php
index 72fd22741d3..a4cc7edba37 100644
--- a/tests/lib/files/cache/wrapper/cachepermissionsmask.php
+++ b/tests/lib/files/cache/wrapper/cachepermissionsmask.php
@@ -11,6 +11,13 @@ namespace Test\Files\Cache\Wrapper;
use OCP\Constants;
use Test\Files\Cache\Cache;
+/**
+ * Class CachePermissionsMask
+ *
+ * @group DB
+ *
+ * @package Test\Files\Cache\Wrapper
+ */
class CachePermissionsMask extends Cache {
/**
* @var \OC\Files\Cache\Cache $sourceCache
diff --git a/tests/lib/files/config/usermountcache.php b/tests/lib/files/config/usermountcache.php
new file mode 100644
index 00000000000..070c2f6176d
--- /dev/null
+++ b/tests/lib/files/config/usermountcache.php
@@ -0,0 +1,375 @@
+<?php
+/**
+ * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Config;
+
+use OC\DB\QueryBuilder\Literal;
+use OC\Files\Mount\MountPoint;
+use OC\Log;
+use OC\User\Manager;
+use OCP\Files\Config\ICachedMountInfo;
+use OCP\IDBConnection;
+use OCP\IUserManager;
+use Test\TestCase;
+use Test\Util\User\Dummy;
+
+/**
+ * @group DB
+ */
+class UserMountCache extends TestCase {
+ /**
+ * @var IDBConnection
+ */
+ private $connection;
+
+ /**
+ * @var IUserManager
+ */
+ private $userManager;
+
+ /**
+ * @var \OC\Files\Config\UserMountCache
+ */
+ private $cache;
+
+ private $fileIds = [];
+
+ public function setUp() {
+ $this->fileIds = [];
+ $this->connection = \OC::$server->getDatabaseConnection();
+ $this->userManager = new Manager(null);
+ $userBackend = new Dummy();
+ $userBackend->createUser('u1', '');
+ $userBackend->createUser('u2', '');
+ $this->userManager->registerBackend($userBackend);
+ $this->cache = new \OC\Files\Config\UserMountCache($this->connection, $this->userManager, $this->getMock('\OC\Log'));
+ }
+
+ public function tearDown() {
+ $builder = $this->connection->getQueryBuilder();
+
+ $builder->delete('mounts')->execute();
+
+ $builder = $this->connection->getQueryBuilder();
+
+ foreach ($this->fileIds as $fileId) {
+ $builder->delete('filecache')
+ ->where($builder->expr()->eq('fileid', new Literal($fileId)))
+ ->execute();
+ }
+ }
+
+ private function getStorage($storageId, $rootId) {
+ $storageCache = $this->getMockBuilder('\OC\Files\Cache\Storage')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $storageCache->expects($this->any())
+ ->method('getNumericId')
+ ->will($this->returnValue($storageId));
+
+ $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $cache->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue($rootId));
+
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Storage')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $storage->expects($this->any())
+ ->method('getStorageCache')
+ ->will($this->returnValue($storageCache));
+ $storage->expects($this->any())
+ ->method('getCache')
+ ->will($this->returnValue($cache));
+
+ return $storage;
+ }
+
+ private function clearCache() {
+ $this->invokePrivate($this->cache, 'mountsForUsers', [[]]);
+ }
+
+ public function testNewMounts() {
+ $user = $this->userManager->get('u1');
+
+ $storage = $this->getStorage(10, 20);
+ $mount = new MountPoint($storage, '/asd/');
+
+ $this->cache->registerMounts($user, [$mount]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForUser($user);
+
+ $this->assertCount(1, $cachedMounts);
+ $cachedMount = $cachedMounts[0];
+ $this->assertEquals('/asd/', $cachedMount->getMountPoint());
+ $this->assertEquals($user, $cachedMount->getUser());
+ $this->assertEquals($storage->getCache()->getId(''), $cachedMount->getRootId());
+ $this->assertEquals($storage->getStorageCache()->getNumericId(), $cachedMount->getStorageId());
+ }
+
+ public function testSameMounts() {
+ $user = $this->userManager->get('u1');
+
+ $storage = $this->getStorage(10, 20);
+ $mount = new MountPoint($storage, '/asd/');
+
+ $this->cache->registerMounts($user, [$mount]);
+
+ $this->clearCache();
+
+ $this->cache->registerMounts($user, [$mount]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForUser($user);
+
+ $this->assertCount(1, $cachedMounts);
+ $cachedMount = $cachedMounts[0];
+ $this->assertEquals('/asd/', $cachedMount->getMountPoint());
+ $this->assertEquals($user, $cachedMount->getUser());
+ $this->assertEquals($storage->getCache()->getId(''), $cachedMount->getRootId());
+ $this->assertEquals($storage->getStorageCache()->getNumericId(), $cachedMount->getStorageId());
+ }
+
+ public function testRemoveMounts() {
+ $user = $this->userManager->get('u1');
+
+ $storage = $this->getStorage(10, 20);
+ $mount = new MountPoint($storage, '/asd/');
+
+ $this->cache->registerMounts($user, [$mount]);
+
+ $this->clearCache();
+
+ $this->cache->registerMounts($user, []);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForUser($user);
+
+ $this->assertCount(0, $cachedMounts);
+ }
+
+ public function testChangeMounts() {
+ $user = $this->userManager->get('u1');
+
+ $storage = $this->getStorage(10, 20);
+ $mount = new MountPoint($storage, '/foo/');
+
+ $this->cache->registerMounts($user, [$mount]);
+
+ $this->clearCache();
+
+ $this->cache->registerMounts($user, [$mount]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForUser($user);
+
+ $this->assertCount(1, $cachedMounts);
+ $cachedMount = $cachedMounts[0];
+ $this->assertEquals('/foo/', $cachedMount->getMountPoint());
+ }
+
+ public function testGetMountsForUser() {
+ $user1 = $this->userManager->get('u1');
+ $user2 = $this->userManager->get('u2');
+
+ $mount1 = new MountPoint($this->getStorage(1, 2), '/foo/');
+ $mount2 = new MountPoint($this->getStorage(3, 4), '/bar/');
+
+ $this->cache->registerMounts($user1, [$mount1, $mount2]);
+ $this->cache->registerMounts($user2, [$mount2]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForUser($user1);
+
+ $this->assertCount(2, $cachedMounts);
+ $this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
+ $this->assertEquals($user1, $cachedMounts[0]->getUser());
+ $this->assertEquals(2, $cachedMounts[0]->getRootId());
+ $this->assertEquals(1, $cachedMounts[0]->getStorageId());
+
+ $this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
+ $this->assertEquals($user1, $cachedMounts[1]->getUser());
+ $this->assertEquals(4, $cachedMounts[1]->getRootId());
+ $this->assertEquals(3, $cachedMounts[1]->getStorageId());
+ }
+
+ public function testGetMountsByStorageId() {
+ $user1 = $this->userManager->get('u1');
+ $user2 = $this->userManager->get('u2');
+
+ $mount1 = new MountPoint($this->getStorage(1, 2), '/foo/');
+ $mount2 = new MountPoint($this->getStorage(3, 4), '/bar/');
+
+ $this->cache->registerMounts($user1, [$mount1, $mount2]);
+ $this->cache->registerMounts($user2, [$mount2]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForStorageId(3);
+ $this->sortMounts($cachedMounts);
+
+ $this->assertCount(2, $cachedMounts);
+
+ $this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
+ $this->assertEquals($user1, $cachedMounts[0]->getUser());
+ $this->assertEquals(4, $cachedMounts[0]->getRootId());
+ $this->assertEquals(3, $cachedMounts[0]->getStorageId());
+
+ $this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
+ $this->assertEquals($user2, $cachedMounts[1]->getUser());
+ $this->assertEquals(4, $cachedMounts[1]->getRootId());
+ $this->assertEquals(3, $cachedMounts[1]->getStorageId());
+ }
+
+ public function testGetMountsByRootId() {
+ $user1 = $this->userManager->get('u1');
+ $user2 = $this->userManager->get('u2');
+
+ $mount1 = new MountPoint($this->getStorage(1, 2), '/foo/');
+ $mount2 = new MountPoint($this->getStorage(3, 4), '/bar/');
+
+ $this->cache->registerMounts($user1, [$mount1, $mount2]);
+ $this->cache->registerMounts($user2, [$mount2]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForRootId(4);
+ $this->sortMounts($cachedMounts);
+
+ $this->assertCount(2, $cachedMounts);
+
+ $this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
+ $this->assertEquals($user1, $cachedMounts[0]->getUser());
+ $this->assertEquals(4, $cachedMounts[0]->getRootId());
+ $this->assertEquals(3, $cachedMounts[0]->getStorageId());
+
+ $this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
+ $this->assertEquals($user2, $cachedMounts[1]->getUser());
+ $this->assertEquals(4, $cachedMounts[1]->getRootId());
+ $this->assertEquals(3, $cachedMounts[1]->getStorageId());
+ }
+
+ private function sortMounts(&$mounts) {
+ usort($mounts, function (ICachedMountInfo $a, ICachedMountInfo $b) {
+ return strcmp($a->getUser()->getUID(), $b->getUser()->getUID());
+ });
+ }
+
+ private function createCacheEntry($internalPath, $storageId) {
+ $this->connection->insertIfNotExist('*PREFIX*filecache', [
+ 'storage' => $storageId,
+ 'path' => $internalPath,
+ 'path_hash' => md5($internalPath),
+ 'parent' => -1,
+ 'name' => basename($internalPath),
+ 'mimetype' => 0,
+ 'mimepart' => 0,
+ 'size' => 0,
+ 'storage_mtime' => 0,
+ 'encrypted' => 0,
+ 'unencrypted_size' => 0,
+ 'etag' => '',
+ 'permissions' => 31
+ ], ['storage', 'path_hash']);
+ $id = (int)$this->connection->lastInsertId('*PREFIX*filecache');
+ $this->fileIds[] = $id;
+ return $id;
+ }
+
+ public function testGetMountsForFileIdRootId() {
+ $user1 = $this->userManager->get('u1');
+
+ $rootId = $this->createCacheEntry('', 2);
+
+ $mount1 = new MountPoint($this->getStorage(2, $rootId), '/foo/');
+
+ $this->cache->registerMounts($user1, [$mount1]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForFileId($rootId);
+
+ $this->assertCount(1, $cachedMounts);
+
+ $this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
+ $this->assertEquals($user1, $cachedMounts[0]->getUser());
+ $this->assertEquals($rootId, $cachedMounts[0]->getRootId());
+ $this->assertEquals(2, $cachedMounts[0]->getStorageId());
+ }
+
+ public function testGetMountsForFileIdSubFolder() {
+ $user1 = $this->userManager->get('u1');
+
+ $rootId = $this->createCacheEntry('', 2);
+ $fileId = $this->createCacheEntry('/foo/bar', 2);
+
+ $mount1 = new MountPoint($this->getStorage(2, $rootId), '/foo/');
+
+ $this->cache->registerMounts($user1, [$mount1]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForFileId($fileId);
+
+ $this->assertCount(1, $cachedMounts);
+
+ $this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
+ $this->assertEquals($user1, $cachedMounts[0]->getUser());
+ $this->assertEquals($rootId, $cachedMounts[0]->getRootId());
+ $this->assertEquals(2, $cachedMounts[0]->getStorageId());
+ }
+
+ public function testGetMountsForFileIdSubFolderMount() {
+ $user1 = $this->userManager->get('u1');
+
+ $this->createCacheEntry('', 2);
+ $folderId = $this->createCacheEntry('/foo', 2);
+ $fileId = $this->createCacheEntry('/foo/bar', 2);
+
+ $mount1 = new MountPoint($this->getStorage(2, $folderId), '/foo/');
+
+ $this->cache->registerMounts($user1, [$mount1]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForFileId($fileId);
+
+ $this->assertCount(1, $cachedMounts);
+
+ $this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
+ $this->assertEquals($user1, $cachedMounts[0]->getUser());
+ $this->assertEquals($folderId, $cachedMounts[0]->getRootId());
+ $this->assertEquals(2, $cachedMounts[0]->getStorageId());
+ }
+
+ public function testGetMountsForFileIdSubFolderMountOutside() {
+ $user1 = $this->userManager->get('u1');
+
+ $this->createCacheEntry('', 2);
+ $folderId = $this->createCacheEntry('/foo', 2);
+ $fileId = $this->createCacheEntry('/bar/asd', 2);
+
+ $mount1 = new MountPoint($this->getStorage(2, $folderId), '/foo/');
+
+ $this->cache->registerMounts($user1, [$mount1]);
+
+ $this->clearCache();
+
+ $cachedMounts = $this->cache->getMountsForFileId($fileId);
+
+ $this->assertCount(0, $cachedMounts);
+ }
+}
diff --git a/tests/lib/files/etagtest.php b/tests/lib/files/etagtest.php
index 1a11b29cf00..d8e44000f9c 100644
--- a/tests/lib/files/etagtest.php
+++ b/tests/lib/files/etagtest.php
@@ -11,6 +11,13 @@ namespace Test\Files;
use OC\Files\Filesystem;
use OCP\Share;
+/**
+ * Class EtagTest
+ *
+ * @group DB
+ *
+ * @package Test\Files
+ */
class EtagTest extends \Test\TestCase {
private $datadir;
@@ -27,20 +34,20 @@ class EtagTest extends \Test\TestCase {
\OC_Hook::clear('OC_Filesystem', 'setup');
$application = new \OCA\Files_Sharing\AppInfo\Application();
$application->registerMountProviders();
- $application->setupPropagation();
\OCP\Share::registerBackend('file', 'OC_Share_Backend_File');
\OCP\Share::registerBackend('folder', 'OC_Share_Backend_Folder', 'file');
- $this->datadir = \OC_Config::getValue('datadirectory');
- $this->tmpDir = \OC_Helper::tmpFolder();
- \OC_Config::setValue('datadirectory', $this->tmpDir);
+ $config = \OC::$server->getConfig();
+ $this->datadir = $config->getSystemValue('datadirectory');
+ $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder();
+ $config->setSystemValue('datadirectory', $this->tmpDir);
$this->userBackend = new \Test\Util\User\Dummy();
\OC_User::useBackend($this->userBackend);
}
protected function tearDown() {
- \OC_Config::setValue('datadirectory', $this->datadir);
+ \OC::$server->getConfig()->setSystemValue('datadirectory', $this->datadir);
$this->logout();
parent::tearDown();
@@ -60,7 +67,7 @@ class EtagTest extends \Test\TestCase {
$files = array('/foo.txt', '/folder/bar.txt', '/folder/subfolder', '/folder/subfolder/qwerty.txt');
$originalEtags = $this->getEtags($files);
- $scanner = new \OC\Files\Utils\Scanner($user1, \OC::$server->getDatabaseConnection());
+ $scanner = new \OC\Files\Utils\Scanner($user1, \OC::$server->getDatabaseConnection(), \OC::$server->getLogger());
$scanner->backgroundScan('/');
$newEtags = $this->getEtags($files);
diff --git a/tests/lib/files/filesystem.php b/tests/lib/files/filesystem.php
index 15a7c235405..db1f22f894a 100644
--- a/tests/lib/files/filesystem.php
+++ b/tests/lib/files/filesystem.php
@@ -51,6 +51,13 @@ class DummyMountProvider implements IMountProvider {
}
}
+/**
+ * Class Filesystem
+ *
+ * @group DB
+ *
+ * @package Test\Files
+ */
class Filesystem extends \Test\TestCase {
const TEST_FILESYSTEM_USER1 = "test-filesystem-user1";
@@ -65,7 +72,7 @@ class Filesystem extends \Test\TestCase {
* @return array
*/
private function getStorageData() {
- $dir = \OC_Helper::tmpFolder();
+ $dir = \OC::$server->getTempManager()->getTemporaryFolder();
$this->tmpDirs[] = $dir;
return array('datadir' => $dir);
}
@@ -295,7 +302,7 @@ class Filesystem extends \Test\TestCase {
\OC\Files\Filesystem::mkdir('/bar');
// \OC\Files\Filesystem::file_put_contents('/bar//foo', 'foo');
- $tmpFile = \OC_Helper::tmpFile();
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile();
file_put_contents($tmpFile, 'foo');
$fh = fopen($tmpFile, 'r');
// \OC\Files\Filesystem::file_put_contents('/bar//foo', $fh);
@@ -307,7 +314,6 @@ class Filesystem extends \Test\TestCase {
* @expectedException \OC\User\NoUserException
*/
public function testLocalMountWhenUserDoesNotExist() {
- $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
$userId = $this->getUniqueID('user_');
\OC\Files\Filesystem::initMountPoints($userId);
@@ -319,7 +325,7 @@ class Filesystem extends \Test\TestCase {
public function testHomeMount() {
$userId = $this->getUniqueID('user_');
- \OC_User::createUser($userId, $userId);
+ \OC::$server->getUserManager()->createUser($userId, $userId);
\OC\Files\Filesystem::initMountPoints($userId);
@@ -334,7 +340,8 @@ class Filesystem extends \Test\TestCase {
$this->assertEquals('home::' . $userId, $homeMount->getId());
}
- \OC_User::deleteUser($userId);
+ $user = \OC::$server->getUserManager()->get($userId);
+ if ($user !== null) { $user->delete(); }
}
/**
@@ -345,7 +352,7 @@ class Filesystem extends \Test\TestCase {
if (getenv('RUN_OBJECTSTORE_TESTS')) {
$this->markTestSkipped('legacy storage unrelated to objectstore environments');
}
- $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
+ $datadir = \OC::$server->getConfig()->getSystemValue("datadirectory", \OC::$SERVERROOT . "/data");
$userId = $this->getUniqueID('user_');
// insert storage into DB by constructing it
@@ -354,7 +361,7 @@ class Filesystem extends \Test\TestCase {
// this will trigger the insert
$cache = $localStorage->getCache();
- \OC_User::createUser($userId, $userId);
+ \OC::$server->getUserManager()->createUser($userId, $userId);
\OC\Files\Filesystem::initMountPoints($userId);
$homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
@@ -362,7 +369,8 @@ class Filesystem extends \Test\TestCase {
$this->assertTrue($homeMount->instanceOfStorage('\OC\Files\Storage\Home'));
$this->assertEquals('local::' . $datadir . '/' . $userId . '/', $homeMount->getId());
- \OC_User::deleteUser($userId);
+ $user = \OC::$server->getUserManager()->get($userId);
+ if ($user !== null) { $user->delete(); }
// delete storage entry
$cache->clear();
}
@@ -377,11 +385,12 @@ class Filesystem extends \Test\TestCase {
*/
public function testMountDefaultCacheDir() {
$userId = $this->getUniqueID('user_');
- $oldCachePath = \OC_Config::getValue('cache_path', '');
+ $config = \OC::$server->getConfig();
+ $oldCachePath = $config->getSystemValue('cache_path', '');
// no cache path configured
- \OC_Config::setValue('cache_path', '');
+ $config->setSystemValue('cache_path', '');
- \OC_User::createUser($userId, $userId);
+ \OC::$server->getUserManager()->createUser($userId, $userId);
\OC\Files\Filesystem::initMountPoints($userId);
$this->assertEquals(
@@ -391,9 +400,10 @@ class Filesystem extends \Test\TestCase {
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache');
$this->assertTrue($storage->instanceOfStorage('\OCP\Files\IHomeStorage'));
$this->assertEquals('cache', $internalPath);
- \OC_User::deleteUser($userId);
+ $user = \OC::$server->getUserManager()->get($userId);
+ if ($user !== null) { $user->delete(); }
- \OC_Config::setValue('cache_path', $oldCachePath);
+ $config->setSystemValue('cache_path', $oldCachePath);
}
/**
@@ -403,12 +413,13 @@ class Filesystem extends \Test\TestCase {
public function testMountExternalCacheDir() {
$userId = $this->getUniqueID('user_');
- $oldCachePath = \OC_Config::getValue('cache_path', '');
+ $config = \OC::$server->getConfig();
+ $oldCachePath = $config->getSystemValue('cache_path', '');
// set cache path to temp dir
- $cachePath = \OC_Helper::tmpFolder() . '/extcache';
- \OC_Config::setValue('cache_path', $cachePath);
+ $cachePath = \OC::$server->getTempManager()->getTemporaryFolder() . '/extcache';
+ $config->setSystemValue('cache_path', $cachePath);
- \OC_User::createUser($userId, $userId);
+ \OC::$server->getUserManager()->createUser($userId, $userId);
\OC\Files\Filesystem::initMountPoints($userId);
$this->assertEquals(
@@ -418,9 +429,10 @@ class Filesystem extends \Test\TestCase {
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache');
$this->assertTrue($storage->instanceOfStorage('\OC\Files\Storage\Local'));
$this->assertEquals('', $internalPath);
- \OC_User::deleteUser($userId);
+ $user = \OC::$server->getUserManager()->get($userId);
+ if ($user !== null) { $user->delete(); }
- \OC_Config::setValue('cache_path', $oldCachePath);
+ $config->setSystemValue('cache_path', $oldCachePath);
}
public function testRegisterMountProviderAfterSetup() {
diff --git a/tests/lib/files/node/file.php b/tests/lib/files/node/file.php
index c431a2eb366..ccc777c499f 100644
--- a/tests/lib/files/node/file.php
+++ b/tests/lib/files/node/file.php
@@ -21,8 +21,16 @@ class File extends \Test\TestCase {
$this->user = new \OC\User\User('', new \Test\Util\User\Dummy);
}
+ protected function getMockStorage() {
+ $storage = $this->getMock('\OCP\Files\Storage');
+ $storage->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('home::someuser'));
+ return $storage;
+ }
+
protected function getFileInfo($data) {
- return new FileInfo('', null, '', $data, null);
+ return new FileInfo('', $this->getMockStorage(), '', $data, null);
}
public function testDelete() {
@@ -76,6 +84,8 @@ class File extends \Test\TestCase {
$test->assertInstanceOf('\OC\Files\Node\NonExistingFile', $node);
$test->assertEquals('foo', $node->getInternalPath());
$test->assertEquals('/bar/foo', $node->getPath());
+ $test->assertEquals(1, $node->getId());
+ $test->assertEquals('text/plain', $node->getMimeType());
$hooksRun++;
};
@@ -94,7 +104,7 @@ class File extends \Test\TestCase {
$view->expects($this->any())
->method('getFileInfo')
->with('/bar/foo')
- ->will($this->returnValue($this->getFileInfo(array('permissions' => \OCP\Constants::PERMISSION_ALL, 'fileid' => 1))));
+ ->will($this->returnValue($this->getFileInfo(array('permissions' => \OCP\Constants::PERMISSION_ALL, 'fileid' => 1, 'mimetype' => 'text/plain'))));
$view->expects($this->once())
->method('unlink')
diff --git a/tests/lib/files/node/folder.php b/tests/lib/files/node/folder.php
index 8c98256575e..09bf32561e6 100644
--- a/tests/lib/files/node/folder.php
+++ b/tests/lib/files/node/folder.php
@@ -16,6 +16,13 @@ use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OC\Files\View;
+/**
+ * Class Folder
+ *
+ * @group DB
+ *
+ * @package Test\Files\Node
+ */
class Folder extends \Test\TestCase {
private $user;
@@ -24,8 +31,16 @@ class Folder extends \Test\TestCase {
$this->user = new \OC\User\User('', new \Test\Util\User\Dummy);
}
+ protected function getMockStorage() {
+ $storage = $this->getMock('\OCP\Files\Storage');
+ $storage->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('home::someuser'));
+ return $storage;
+ }
+
protected function getFileInfo($data) {
- return new FileInfo('', null, '', $data, null);
+ return new FileInfo('', $this->getMockStorage(), '', $data, null);
}
public function testDelete() {
@@ -75,6 +90,7 @@ class Folder extends \Test\TestCase {
$test->assertInstanceOf('\OC\Files\Node\NonExistingFolder', $node);
$test->assertEquals('foo', $node->getInternalPath());
$test->assertEquals('/bar/foo', $node->getPath());
+ $test->assertEquals(1, $node->getId());
$hooksRun++;
};
diff --git a/tests/lib/files/node/hookconnector.php b/tests/lib/files/node/hookconnector.php
index 10566cf5fb1..e2a5e190687 100644
--- a/tests/lib/files/node/hookconnector.php
+++ b/tests/lib/files/node/hookconnector.php
@@ -17,6 +17,13 @@ use Test\TestCase;
use Test\Traits\MountProviderTrait;
use Test\Traits\UserTrait;
+/**
+ * Class HookConnector
+ *
+ * @group DB
+ *
+ * @package Test\Files\Node
+ */
class HookConnector extends TestCase {
use UserTrait;
use MountProviderTrait;
@@ -173,4 +180,24 @@ class HookConnector extends TestCase {
$this->assertEquals('/' . $this->userId . '/files/source', $hookSourceNode->getPath());
$this->assertEquals('/' . $this->userId . '/files/target', $hookTargetNode->getPath());
}
+
+ public function testPostDeleteMeta() {
+ $connector = new \OC\Files\Node\HookConnector($this->root, $this->view);
+ $connector->viewToNode();
+ $hookCalled = false;
+ /** @var Node $hookNode */
+ $hookNode = null;
+
+ $this->root->listen('\OC\Files', 'postDelete', function ($node) use (&$hookNode, &$hookCalled) {
+ $hookCalled = true;
+ $hookNode = $node;
+ });
+
+ Filesystem::file_put_contents('test.txt', 'asd');
+ $info = Filesystem::getFileInfo('test.txt');
+ Filesystem::unlink('test.txt');
+
+ $this->assertTrue($hookCalled);
+ $this->assertEquals($hookNode->getId(), $info->getId());
+ }
}
diff --git a/tests/lib/files/node/integration.php b/tests/lib/files/node/integration.php
index 5580b40a126..addc7e98f48 100644
--- a/tests/lib/files/node/integration.php
+++ b/tests/lib/files/node/integration.php
@@ -13,6 +13,13 @@ use OC\Files\Storage\Temporary;
use OC\Files\View;
use OC\User\User;
+/**
+ * Class IntegrationTests
+ *
+ * @group DB
+ *
+ * @package Test\Files\Node
+ */
class IntegrationTests extends \Test\TestCase {
/**
* @var \OC\Files\Node\Root $root
diff --git a/tests/lib/files/node/node.php b/tests/lib/files/node/node.php
index afcf4cbabaa..a1693b034fa 100644
--- a/tests/lib/files/node/node.php
+++ b/tests/lib/files/node/node.php
@@ -18,8 +18,16 @@ class Node extends \Test\TestCase {
$this->user = new \OC\User\User('', new \Test\Util\User\Dummy);
}
+ protected function getMockStorage() {
+ $storage = $this->getMock('\OCP\Files\Storage');
+ $storage->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('home::someuser'));
+ return $storage;
+ }
+
protected function getFileInfo($data) {
- return new FileInfo('', null, '', $data, null);
+ return new FileInfo('', $this->getMockStorage(), '', $data, null);
}
public function testStat() {
diff --git a/tests/lib/files/objectstore/swift.php b/tests/lib/files/objectstore/swift.php
index 6d59078aa7c..a63f5844145 100644
--- a/tests/lib/files/objectstore/swift.php
+++ b/tests/lib/files/objectstore/swift.php
@@ -23,6 +23,13 @@ namespace OCA\ObjectStore\Tests\Unit;
use OC\Files\ObjectStore\ObjectStoreStorage;
use OC\Files\ObjectStore\Swift as ObjectStoreToTest;
+/**
+ * Class Swift
+ *
+ * @group DB
+ *
+ * @package OCA\ObjectStore\Tests\Unit
+ */
class Swift extends \Test\Files\Storage\Storage {
/**
@@ -44,8 +51,9 @@ class Swift extends \Test\Files\Storage\Storage {
// create users
$users = array('test');
foreach($users as $userName) {
- \OC_User::deleteUser($userName);
- \OC_User::createUser($userName, $userName);
+ $user = \OC::$server->getUserManager()->get($userName);
+ if ($user !== null) { $user->delete(); }
+ \OC::$server->getUserManager()->createUser($userName, $userName);
}
// main test user
@@ -69,7 +77,8 @@ class Swift extends \Test\Files\Storage\Storage {
$users = array('test');
foreach($users as $userName) {
- \OC_User::deleteUser($userName);
+ $user = \OC::$server->getUserManager()->get($userName);
+ if ($user !== null) { $user->delete(); }
}
parent::tearDown();
}
diff --git a/tests/lib/files/pathverificationtest.php b/tests/lib/files/pathverificationtest.php
index 13fccd310f3..db393ce5e51 100644
--- a/tests/lib/files/pathverificationtest.php
+++ b/tests/lib/files/pathverificationtest.php
@@ -10,6 +10,13 @@ namespace Test\Files;
use OC\Files\Storage\Local;
use OC\Files\View;
+/**
+ * Class PathVerification
+ *
+ * @group DB
+ *
+ * @package Test\Files
+ */
class PathVerification extends \Test\TestCase {
/**
diff --git a/tests/lib/files/storage/commontest.php b/tests/lib/files/storage/commontest.php
index 2b70dc8713e..38faa9b0b21 100644
--- a/tests/lib/files/storage/commontest.php
+++ b/tests/lib/files/storage/commontest.php
@@ -22,6 +22,13 @@
namespace Test\Files\Storage;
+/**
+ * Class CommonTest
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class CommonTest extends Storage {
/**
* @var string tmpDir
@@ -30,7 +37,7 @@ class CommonTest extends Storage {
protected function setUp() {
parent::setUp();
- $this->tmpDir=\OC_Helper::tmpFolder();
+ $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder();
$this->instance=new \OC\Files\Storage\CommonTest(array('datadir'=>$this->tmpDir));
}
diff --git a/tests/lib/files/storage/copydirectory.php b/tests/lib/files/storage/copydirectory.php
index 3338747f49b..bc066268cda 100644
--- a/tests/lib/files/storage/copydirectory.php
+++ b/tests/lib/files/storage/copydirectory.php
@@ -36,6 +36,13 @@ class CopyDirectoryStorage extends StorageNoRecursiveCopy {
use \OC\Files\Storage\PolyFill\CopyDirectory;
}
+/**
+ * Class CopyDirectory
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class CopyDirectory extends Storage {
protected function setUp() {
diff --git a/tests/lib/files/storage/home.php b/tests/lib/files/storage/home.php
index b0670a22892..7e10f09d554 100644
--- a/tests/lib/files/storage/home.php
+++ b/tests/lib/files/storage/home.php
@@ -47,6 +47,13 @@ class DummyUser extends User {
}
}
+/**
+ * Class Home
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class Home extends Storage {
/**
* @var string tmpDir
@@ -63,7 +70,7 @@ class Home extends Storage {
protected function setUp() {
parent::setUp();
- $this->tmpDir = \OC_Helper::tmpFolder();
+ $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder();
$this->userId = $this->getUniqueID('user_');
$this->user = new DummyUser($this->userId, $this->tmpDir);
$this->instance = new \OC\Files\Storage\Home(array('user' => $this->user));
diff --git a/tests/lib/files/storage/homestoragequota.php b/tests/lib/files/storage/homestoragequota.php
new file mode 100644
index 00000000000..9a3c6b151fc
--- /dev/null
+++ b/tests/lib/files/storage/homestoragequota.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Test\Files\Storage;
+
+/**
+ * Class HomeStorageQuota
+ *
+ * @group DB
+ */
+class HomeStorageQuota extends \Test\TestCase {
+ /**
+ * Tests that the home storage is not wrapped when no quota exists.
+ */
+ function testHomeStorageWrapperWithoutQuota() {
+ $user1 = $this->getUniqueID();
+ \OC::$server->getUserManager()->createUser($user1, 'test');
+ \OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', 'none');
+ \OC_User::setUserId($user1);
+
+ \OC_Util::setupFS($user1);
+
+ $userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/');
+ $this->assertNotNull($userMount);
+ $this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $userMount->getStorage());
+
+ // clean up
+ \OC_User::setUserId('');
+ $user = \OC::$server->getUserManager()->get($user1);
+ if ($user !== null) { $user->delete(); }
+ \OC::$server->getConfig()->deleteAllUserValues($user1);
+ \OC_Util::tearDownFS();
+ }
+
+ /**
+ * Tests that the home storage is not wrapped when no quota exists.
+ */
+ function testHomeStorageWrapperWithQuota() {
+ $user1 = $this->getUniqueID();
+ \OC::$server->getUserManager()->createUser($user1, 'test');
+ \OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', '1024');
+ \OC_User::setUserId($user1);
+
+ \OC_Util::setupFS($user1);
+
+ $userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/');
+ $this->assertNotNull($userMount);
+ $this->assertTrue($userMount->getStorage()->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota'));
+
+ // ensure that root wasn't wrapped
+ $rootMount = \OC\Files\Filesystem::getMountManager()->find('/');
+ $this->assertNotNull($rootMount);
+ $this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $rootMount->getStorage());
+
+ // clean up
+ \OC_User::setUserId('');
+ $user = \OC::$server->getUserManager()->get($user1);
+ if ($user !== null) { $user->delete(); }
+ \OC::$server->getConfig()->deleteAllUserValues($user1);
+ \OC_Util::tearDownFS();
+ }
+
+}
diff --git a/tests/lib/files/storage/local.php b/tests/lib/files/storage/local.php
index d2b27117c3b..2583863b554 100644
--- a/tests/lib/files/storage/local.php
+++ b/tests/lib/files/storage/local.php
@@ -22,6 +22,13 @@
namespace Test\Files\Storage;
+/**
+ * Class Local
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage
+ */
class Local extends Storage {
/**
* @var string tmpDir
@@ -31,7 +38,7 @@ class Local extends Storage {
protected function setUp() {
parent::setUp();
- $this->tmpDir = \OC_Helper::tmpFolder();
+ $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder();
$this->instance = new \OC\Files\Storage\Local(array('datadir' => $this->tmpDir));
}
diff --git a/tests/lib/files/storage/storage.php b/tests/lib/files/storage/storage.php
index d381b4cdf40..95dd70bfdac 100644
--- a/tests/lib/files/storage/storage.php
+++ b/tests/lib/files/storage/storage.php
@@ -598,4 +598,17 @@ abstract class Storage extends \Test\TestCase {
$this->instance->mkdir('source');
$this->assertTrue($this->instance->isSharable('source'));
}
+
+ public function testStatAfterWrite() {
+ $this->instance->file_put_contents('foo.txt', 'bar');
+ $stat = $this->instance->stat('foo.txt');
+ $this->assertEquals(3, $stat['size']);
+
+ $fh = $this->instance->fopen('foo.txt', 'w');
+ fwrite($fh, 'qwerty');
+ fclose($fh);
+
+ $stat = $this->instance->stat('foo.txt');
+ $this->assertEquals(6, $stat['size']);
+ }
}
diff --git a/tests/lib/files/storage/wrapper/quota.php b/tests/lib/files/storage/wrapper/quota.php
index 441f3a39d32..d087a3eef33 100644
--- a/tests/lib/files/storage/wrapper/quota.php
+++ b/tests/lib/files/storage/wrapper/quota.php
@@ -9,8 +9,17 @@
namespace Test\Files\Storage\Wrapper;
//ensure the constants are loaded
+use OC\Files\Cache\CacheEntry;
+
\OC::$loader->load('\OC\Files\Filesystem');
+/**
+ * Class Quota
+ *
+ * @group DB
+ *
+ * @package Test\Files\Storage\Wrapper
+ */
class Quota extends \Test\Files\Storage\Storage {
/**
* @var string tmpDir
@@ -20,7 +29,7 @@ class Quota extends \Test\Files\Storage\Storage {
protected function setUp() {
parent::setUp();
- $this->tmpDir = \OC_Helper::tmpFolder();
+ $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder();
$storage = new \OC\Files\Storage\Local(array('datadir' => $this->tmpDir));
$this->instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => 10000000));
}
@@ -187,7 +196,7 @@ class Quota extends \Test\Files\Storage\Storage {
$cache->expects($this->once())
->method('get')
->with('files')
- ->will($this->returnValue(array('size' => 50)));
+ ->will($this->returnValue(new CacheEntry(['size' => 50])));
$instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => 1024, 'root' => 'files'));
diff --git a/tests/lib/files/storage/wrapper/wrapper.php b/tests/lib/files/storage/wrapper/wrapper.php
index 486cd0495c1..a5a678cb9f7 100644
--- a/tests/lib/files/storage/wrapper/wrapper.php
+++ b/tests/lib/files/storage/wrapper/wrapper.php
@@ -17,7 +17,7 @@ class Wrapper extends \Test\Files\Storage\Storage {
protected function setUp() {
parent::setUp();
- $this->tmpDir = \OC_Helper::tmpFolder();
+ $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder();
$storage = new \OC\Files\Storage\Local(array('datadir' => $this->tmpDir));
$this->instance = new \OC\Files\Storage\Wrapper\Wrapper(array('storage' => $storage));
}
diff --git a/tests/lib/files/utils/scanner.php b/tests/lib/files/utils/scanner.php
index 5492774f42e..7779e2778cb 100644
--- a/tests/lib/files/utils/scanner.php
+++ b/tests/lib/files/utils/scanner.php
@@ -30,16 +30,15 @@ class TestScanner extends \OC\Files\Utils\Scanner {
protected function getMounts($dir) {
return $this->mounts;
}
-
- public function getPropagator() {
- return $this->propagator;
- }
-
- public function setPropagator($propagator) {
- $this->propagator = $propagator;
- }
}
+/**
+ * Class Scanner
+ *
+ * @group DB
+ *
+ * @package Test\Files\Utils
+ */
class Scanner extends \Test\TestCase {
/**
* @var \Test\Util\User\Dummy
@@ -70,7 +69,7 @@ class Scanner extends \Test\TestCase {
$storage->file_put_contents('foo.txt', 'qwerty');
$storage->file_put_contents('folder/bar.txt', 'qwerty');
- $scanner = new TestScanner('', \OC::$server->getDatabaseConnection());
+ $scanner = new TestScanner('', \OC::$server->getDatabaseConnection(), \OC::$server->getLogger());
$scanner->addMount($mount);
$scanner->scan('');
@@ -92,7 +91,7 @@ class Scanner extends \Test\TestCase {
$storage->file_put_contents('foo.txt', 'qwerty');
$storage->file_put_contents('folder/bar.txt', 'qwerty');
- $scanner = new TestScanner('', \OC::$server->getDatabaseConnection());
+ $scanner = new TestScanner('', \OC::$server->getDatabaseConnection(), \OC::$server->getLogger());
$scanner->addMount($mount);
$scanner->scan('');
@@ -130,66 +129,13 @@ class Scanner extends \Test\TestCase {
$storage->file_put_contents('foo.txt', 'qwerty');
$storage->file_put_contents('folder/bar.txt', 'qwerty');
- $scanner = new \OC\Files\Utils\Scanner($uid, \OC::$server->getDatabaseConnection());
+ $scanner = new \OC\Files\Utils\Scanner($uid, \OC::$server->getDatabaseConnection(), \OC::$server->getLogger());
$this->assertFalse($cache->inCache('folder/bar.txt'));
$scanner->scan('/' . $uid . '/files/foo');
$this->assertTrue($cache->inCache('folder/bar.txt'));
}
- public function testChangePropagator() {
- /**
- * @var \OC\Files\Cache\ChangePropagator $propagator
- */
- $propagator = $this->getMock('\OC\Files\Cache\ChangePropagator', array('propagateChanges'), array(), '', false);
-
- $storage = new Temporary(array());
- $mount = new MountPoint($storage, '/foo');
- Filesystem::getMountManager()->addMount($mount);
- $cache = $storage->getCache();
-
- $storage->mkdir('folder');
- $storage->file_put_contents('foo.txt', 'qwerty');
- $storage->file_put_contents('folder/bar.txt', 'qwerty');
-
- $scanner = new TestScanner('', \OC::$server->getDatabaseConnection());
- $originalPropagator = $scanner->getPropagator();
- $scanner->setPropagator($propagator);
- $scanner->addMount($mount);
-
- $scanner->scan('');
-
- $changes = $propagator->getChanges();
- $parents = $propagator->getAllParents();
- sort($changes);
- sort($parents);
- $this->assertEquals(array('/foo', '/foo/folder', '/foo/folder/bar.txt', '/foo/foo.txt'), $changes);
- $this->assertEquals(array('/', '/foo', '/foo/folder'), $parents);
-
- $cache->put('foo.txt', array('storage_mtime' => time() - 50));
-
- $propagator = $this->getMock('\OC\Files\Cache\ChangePropagator', array('propagateChanges'), array(), '', false);
- $scanner->setPropagator($propagator);
- $storage->file_put_contents('foo.txt', 'asdasd');
-
- $scanner->scan('');
-
- $changes = $propagator->getChanges();
- $parents = $propagator->getAllParents();
- $this->assertEquals(array('/foo/foo.txt'), $changes);
- $this->assertEquals(array('/', '/foo'), $parents);
-
- $scanner->setPropagator($originalPropagator);
-
- $oldInfo = $cache->get('');
- $cache->put('foo.txt', array('storage_mtime' => time() - 70));
- $storage->file_put_contents('foo.txt', 'asdasd');
-
- $scanner->scan('');
- $newInfo = $cache->get('');
- $this->assertNotEquals($oldInfo['etag'], $newInfo['etag']);
- }
-
/**
* @return array
*/
@@ -214,7 +160,7 @@ class Scanner extends \Test\TestCase {
* @param string $invalidPath
*/
public function testInvalidPathScanning($invalidPath) {
- $scanner = new TestScanner('', \OC::$server->getDatabaseConnection());
+ $scanner = new TestScanner('', \OC::$server->getDatabaseConnection(), \OC::$server->getLogger());
$scanner->scan($invalidPath);
}
}
diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php
index f0bad5abd18..3e88a5306f8 100644
--- a/tests/lib/files/view.php
+++ b/tests/lib/files/view.php
@@ -40,6 +40,13 @@ class TemporaryNoLocal extends \OC\Files\Storage\Temporary {
}
}
+/**
+ * Class View
+ *
+ * @group DB
+ *
+ * @package Test\Files
+ */
class View extends \Test\TestCase {
/**
* @var \OC\Files\Storage\Storage[] $storages
@@ -750,7 +757,7 @@ class View extends \Test\TestCase {
* 228 is the max path length in windows
*/
$folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
- $tmpdirLength = strlen(\OC_Helper::tmpFolder());
+ $tmpdirLength = strlen(\OC::$server->getTempManager()->getTemporaryFolder());
if (\OC_Util::runningOnWindows()) {
$this->markTestSkipped('[Windows] ');
$depth = ((260 - $tmpdirLength) / 57);
@@ -2382,4 +2389,39 @@ class View extends \Test\TestCase {
$view = new \OC\Files\View('/' . $this->user . '/files');
$this->assertEquals('foo', $view->rmdir('mount'));
}
+
+ public function mimeFilterProvider() {
+ return [
+ [null, ['test1.txt', 'test2.txt', 'test3.md', 'test4.png']],
+ ['text/plain', ['test1.txt', 'test2.txt']],
+ ['text/markdown', ['test3.md']],
+ ['text', ['test1.txt', 'test2.txt', 'test3.md']],
+ ];
+ }
+
+ /**
+ * @param string $filter
+ * @param string[] $expected
+ * @dataProvider mimeFilterProvider
+ */
+ public function testGetDirectoryContentMimeFilter($filter, $expected) {
+ $storage1 = new Temporary();
+ $root = $this->getUniqueID('/');
+ \OC\Files\Filesystem::mount($storage1, array(), $root . '/');
+ $view = new \OC\Files\View($root);
+
+ $view->file_put_contents('test1.txt', 'asd');
+ $view->file_put_contents('test2.txt', 'asd');
+ $view->file_put_contents('test3.md', 'asd');
+ $view->file_put_contents('test4.png', '');
+
+ $content = $view->getDirectoryContent('', $filter);
+
+ $files = array_map(function(FileInfo $info) {
+ return $info->getName();
+ }, $content);
+ sort($files);
+
+ $this->assertEquals($expected, $files);
+ }
}
diff --git a/tests/lib/group.php b/tests/lib/group.php
index 066dddc738e..4bb888ed725 100644
--- a/tests/lib/group.php
+++ b/tests/lib/group.php
@@ -31,7 +31,7 @@ class Test_Group extends \Test\TestCase {
public function testSingleBackend() {
$userBackend = new \Test\Util\User\Dummy();
- \OC_User::getManager()->registerBackend($userBackend);
+ \OC::$server->getUserManager()->registerBackend($userBackend);
OC_Group::useBackend(new OC_Group_Dummy());
$group1 = $this->getUniqueID();
@@ -113,7 +113,7 @@ class Test_Group extends \Test\TestCase {
public function testUsersInGroup() {
OC_Group::useBackend(new OC_Group_Dummy());
$userBackend = new \Test\Util\User\Dummy();
- \OC_User::getManager()->registerBackend($userBackend);
+ \OC::$server->getUserManager()->registerBackend($userBackend);
$group1 = $this->getUniqueID();
$group2 = $this->getUniqueID();
@@ -142,7 +142,7 @@ class Test_Group extends \Test\TestCase {
public function testMultiBackend() {
$userBackend = new \Test\Util\User\Dummy();
- \OC_User::getManager()->registerBackend($userBackend);
+ \OC::$server->getUserManager()->registerBackend($userBackend);
$backend1 = new OC_Group_Dummy();
$backend2 = new OC_Group_Dummy();
OC_Group::useBackend($backend1);
diff --git a/tests/lib/group/backend.php b/tests/lib/group/backend.php
index 62c189489d7..238b83de5d7 100644
--- a/tests/lib/group/backend.php
+++ b/tests/lib/group/backend.php
@@ -1,25 +1,34 @@
<?php
/**
-* ownCloud
-*
-* @author Robin Appelman
-* @copyright 2012 Robin Appelman icewind@owncloud.com
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
-*
-*/
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Felix Moeller <mail@felixmoeller.de>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+/**
+ * Class Test_Group_Backend
+ *
+ * @group DB
+ */
abstract class Test_Group_Backend extends \Test\TestCase {
/**
* @var OC_Group_Backend $backend
@@ -29,10 +38,11 @@ abstract class Test_Group_Backend extends \Test\TestCase {
/**
* get a new unique group name
* test cases can override this in order to clean up created groups
+ *
* @return string
*/
public function getGroupName($name = null) {
- if(is_null($name)) {
+ if (is_null($name)) {
return $this->getUniqueID('test_');
} else {
return $name;
@@ -42,6 +52,7 @@ abstract class Test_Group_Backend extends \Test\TestCase {
/**
* get a new unique user name
* test cases can override this in order to clean up created user
+ *
* @return string
*/
public function getUserName() {
@@ -50,36 +61,36 @@ abstract class Test_Group_Backend extends \Test\TestCase {
public function testAddRemove() {
//get the number of groups we start with, in case there are exising groups
- $startCount=count($this->backend->getGroups());
+ $startCount = count($this->backend->getGroups());
- $name1=$this->getGroupName();
- $name2=$this->getGroupName();
+ $name1 = $this->getGroupName();
+ $name2 = $this->getGroupName();
$this->backend->createGroup($name1);
- $count=count($this->backend->getGroups())-$startCount;
+ $count = count($this->backend->getGroups()) - $startCount;
$this->assertEquals(1, $count);
- $this->assertTrue((array_search($name1, $this->backend->getGroups())!==false));
- $this->assertFalse((array_search($name2, $this->backend->getGroups())!==false));
+ $this->assertTrue((array_search($name1, $this->backend->getGroups()) !== false));
+ $this->assertFalse((array_search($name2, $this->backend->getGroups()) !== false));
$this->backend->createGroup($name2);
- $count=count($this->backend->getGroups())-$startCount;
+ $count = count($this->backend->getGroups()) - $startCount;
$this->assertEquals(2, $count);
- $this->assertTrue((array_search($name1, $this->backend->getGroups())!==false));
- $this->assertTrue((array_search($name2, $this->backend->getGroups())!==false));
+ $this->assertTrue((array_search($name1, $this->backend->getGroups()) !== false));
+ $this->assertTrue((array_search($name2, $this->backend->getGroups()) !== false));
$this->backend->deleteGroup($name2);
- $count=count($this->backend->getGroups())-$startCount;
+ $count = count($this->backend->getGroups()) - $startCount;
$this->assertEquals(1, $count);
- $this->assertTrue((array_search($name1, $this->backend->getGroups())!==false));
- $this->assertFalse((array_search($name2, $this->backend->getGroups())!==false));
+ $this->assertTrue((array_search($name1, $this->backend->getGroups()) !== false));
+ $this->assertFalse((array_search($name2, $this->backend->getGroups()) !== false));
}
public function testUser() {
- $group1=$this->getGroupName();
- $group2=$this->getGroupName();
+ $group1 = $this->getGroupName();
+ $group2 = $this->getGroupName();
$this->backend->createGroup($group1);
$this->backend->createGroup($group2);
- $user1=$this->getUserName();
- $user2=$this->getUserName();
+ $user1 = $this->getUserName();
+ $user2 = $this->getUserName();
$this->assertFalse($this->backend->inGroup($user1, $group1));
$this->assertFalse($this->backend->inGroup($user2, $group1));
@@ -138,4 +149,11 @@ abstract class Test_Group_Backend extends \Test\TestCase {
$result = $this->backend->countUsersInGroup($group, 'bar');
$this->assertSame(2, $result);
}
+
+ public function testAddDouble() {
+ $group = $this->getGroupName();
+
+ $this->backend->createGroup($group);
+ $this->backend->createGroup($group);
+ }
}
diff --git a/tests/lib/group/database.php b/tests/lib/group/database.php
index 10958a6ccdc..b0be5774c7d 100644
--- a/tests/lib/group/database.php
+++ b/tests/lib/group/database.php
@@ -1,31 +1,40 @@
<?php
/**
-* ownCloud
-*
-* @author Robin Appelman
-* @copyright 2012 Robin Appelman icewind@owncloud.com
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
-*
-*/
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+/**
+ * Class Test_Group_Database
+ *
+ * @group DB
+ */
class Test_Group_Database extends Test_Group_Backend {
- private $groups=array();
+ private $groups = array();
/**
* get a new unique group name
* test cases can override this in order to clean up created groups
+ *
* @return string
*/
public function getGroupName($name = null) {
@@ -36,13 +45,22 @@ class Test_Group_Database extends Test_Group_Backend {
protected function setUp() {
parent::setUp();
- $this->backend=new OC_Group_Database();
+ $this->backend = new OC_Group_Database();
}
protected function tearDown() {
- foreach($this->groups as $group) {
+ foreach ($this->groups as $group) {
$this->backend->deleteGroup($group);
}
parent::tearDown();
}
+
+ public function testAddDoubleNoCache() {
+ $group = $this->getGroupName();
+
+ $this->backend->createGroup($group);
+
+ $backend = new OC_Group_Database();
+ $this->assertFalse($backend->createGroup($group));
+ }
}
diff --git a/tests/lib/group/dummy.php b/tests/lib/group/dummy.php
index b4456c8f7e1..6836f89d3fe 100644
--- a/tests/lib/group/dummy.php
+++ b/tests/lib/group/dummy.php
@@ -20,6 +20,11 @@
*
*/
+/**
+ * Class Test_Group_Dummy
+ *
+ * @group DB
+ */
class Test_Group_Dummy extends Test_Group_Backend {
protected function setUp() {
parent::setUp();
diff --git a/tests/lib/helper.php b/tests/lib/helper.php
index ca3e0e46d82..89a981e6e23 100644
--- a/tests/lib/helper.php
+++ b/tests/lib/helper.php
@@ -21,7 +21,7 @@ class Test_Helper extends \Test\TestCase {
{
return array(
array('0 B', 0),
- array('1 kB', 1024),
+ array('1 KB', 1024),
array('9.5 MB', 10000000),
array('1.3 GB', 1395864371),
array('465.7 GB', 500000000000),
@@ -63,7 +63,7 @@ class Test_Helper extends \Test\TestCase {
function providesComputerFileSize(){
return [
[0.0, "0 B"],
- [1024.0, "1 kB"],
+ [1024.0, "1 KB"],
[1395864371.0, '1.3 GB'],
[9961472.0, "9.5 MB"],
[500041567437.0, "465.7 GB"],
@@ -71,60 +71,6 @@ class Test_Helper extends \Test\TestCase {
];
}
- function testGetMimeType() {
- $dir=OC::$SERVERROOT.'/tests/data';
- $result = OC_Helper::getMimeType($dir."/");
- $expected = 'httpd/unix-directory';
- $this->assertEquals($result, $expected);
-
- $result = OC_Helper::getMimeType($dir."/data.tar.gz");
- $expected = 'application/x-gzip';
- $this->assertEquals($result, $expected);
-
- $result = OC_Helper::getMimeType($dir."/data.zip");
- $expected = 'application/zip';
- $this->assertEquals($result, $expected);
-
- $result = OC_Helper::getMimeType($dir."/desktopapp.svg");
- $expected = 'image/svg+xml';
- $this->assertEquals($result, $expected);
-
- $result = OC_Helper::getMimeType($dir."/desktopapp.png");
- $expected = 'image/png';
- $this->assertEquals($result, $expected);
- }
-
- function testGetSecureMimeType() {
- $dir=OC::$SERVERROOT.'/tests/data';
-
- $result = OC_Helper::getSecureMimeType('image/svg+xml');
- $expected = 'text/plain';
- $this->assertEquals($result, $expected);
-
- $result = OC_Helper::getSecureMimeType('image/png');
- $expected = 'image/png';
- $this->assertEquals($result, $expected);
- }
-
- function testGetFileNameMimeType() {
- $this->assertEquals('text/plain', OC_Helper::getFileNameMimeType('foo.txt'));
- $this->assertEquals('image/png', OC_Helper::getFileNameMimeType('foo.png'));
- $this->assertEquals('image/png', OC_Helper::getFileNameMimeType('foo.bar.png'));
- $this->assertEquals('application/octet-stream', OC_Helper::getFileNameMimeType('.png'));
- $this->assertEquals('application/octet-stream', OC_Helper::getFileNameMimeType('foo'));
- $this->assertEquals('application/octet-stream', OC_Helper::getFileNameMimeType(''));
- }
-
- function testGetStringMimeType() {
- if (\OC_Util::runningOnWindows()) {
- $this->markTestSkipped('[Windows] Strings have mimetype application/octet-stream on Windows');
- }
-
- $result = OC_Helper::getStringMimeType("/data/data.tar.gz");
- $expected = 'text/plain; charset=us-ascii';
- $this->assertEquals($result, $expected);
- }
-
function testIsSubDirectory() {
$result = OC_Helper::isSubDirectory("./data/", "/anotherDirectory/");
$this->assertFalse($result);
@@ -164,18 +110,6 @@ class Test_Helper extends \Test\TestCase {
$this->assertEquals($result, $expected);
}
- function testMb_substr_replace() {
- $result = OC_Helper::mb_substr_replace("This is a teststring", "string", 5);
- $expected = "This string is a teststring";
- $this->assertEquals($result, $expected);
- }
-
- function testMb_str_replace() {
- $result = OC_Helper::mb_str_replace("teststring", "string", "This is a teststring");
- $expected = "This is a string";
- $this->assertEquals($result, $expected);
- }
-
function testRecursiveArraySearch() {
$haystack = array(
"Foo" => "own",
@@ -289,172 +223,6 @@ class Test_Helper extends \Test\TestCase {
/**
* @small
- * test absolute URL construction
- * @dataProvider provideDocRootURLs
- */
- function testMakeAbsoluteURLDocRoot($url, $expectedResult) {
- \OC::$WEBROOT = '';
- $result = \OC_Helper::makeURLAbsolute($url);
-
- $this->assertEquals($expectedResult, $result);
- }
-
- /**
- * @small
- * test absolute URL construction
- * @dataProvider provideSubDirURLs
- */
- function testMakeAbsoluteURLSubDir($url, $expectedResult) {
- \OC::$WEBROOT = '/owncloud';
- $result = \OC_Helper::makeURLAbsolute($url);
-
- $this->assertEquals($expectedResult, $result);
- }
-
- public function provideDocRootURLs() {
- return array(
- array('index.php', 'http://localhost/index.php'),
- array('/index.php', 'http://localhost/index.php'),
- array('/apps/index.php', 'http://localhost/apps/index.php'),
- array('apps/index.php', 'http://localhost/apps/index.php'),
- );
- }
-
- public function provideSubDirURLs() {
- return array(
- array('index.php', 'http://localhost/owncloud/index.php'),
- array('/index.php', 'http://localhost/owncloud/index.php'),
- array('/apps/index.php', 'http://localhost/owncloud/apps/index.php'),
- array('apps/index.php', 'http://localhost/owncloud/apps/index.php'),
- );
- }
-
- /**
- * @small
- * test linkTo URL construction
- * @dataProvider provideDocRootAppUrlParts
- */
- public function testLinkToDocRoot($app, $file, $args, $expectedResult) {
- \OC::$WEBROOT = '';
- $result = \OC_Helper::linkTo($app, $file, $args);
-
- $this->assertEquals($expectedResult, $result);
- }
-
- /**
- * @small
- * test linkTo URL construction in sub directory
- * @dataProvider provideSubDirAppUrlParts
- */
- public function testLinkToSubDir($app, $file, $args, $expectedResult) {
- \OC::$WEBROOT = '/owncloud';
- $result = \OC_Helper::linkTo($app, $file, $args);
-
- $this->assertEquals($expectedResult, $result);
- }
-
- /**
- * @return array
- */
- public function provideDocRootAppUrlParts() {
- return array(
- array('files', 'ajax/list.php', array(), '/index.php/apps/files/ajax/list.php'),
- array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), '/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'),
- array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/index.php?trut=trat&dut=dat'),
- );
- }
-
- /**
- * @return array
- */
- public function provideSubDirAppUrlParts() {
- return array(
- array('files', 'ajax/list.php', array(), '/owncloud/index.php/apps/files/ajax/list.php'),
- array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), '/owncloud/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'),
- array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), '/owncloud/index.php?trut=trat&dut=dat'),
- );
- }
-
- /**
- * @small
- * test linkToAbsolute URL construction
- * @dataProvider provideDocRootAppAbsoluteUrlParts
- */
- public function testLinkToAbsoluteDocRoot($app, $file, $args, $expectedResult) {
- \OC::$WEBROOT = '';
- $result = \OC_Helper::linkToAbsolute($app, $file, $args);
-
- $this->assertEquals($expectedResult, $result);
- }
-
- /**
- * @small
- * test linkToAbsolute URL construction in sub directory
- * @dataProvider provideSubDirAppAbsoluteUrlParts
- */
- public function testLinkToAbsoluteSubDir($app, $file, $args, $expectedResult) {
- \OC::$WEBROOT = '/owncloud';
- $result = \OC_Helper::linkToAbsolute($app, $file, $args);
-
- $this->assertEquals($expectedResult, $result);
- }
-
- /**
- * @return array
- */
- public function provideDocRootAppAbsoluteUrlParts() {
- return array(
- array('files', 'ajax/list.php', array(), 'http://localhost/index.php/apps/files/ajax/list.php'),
- array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'),
- array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/index.php?trut=trat&dut=dat'),
- );
- }
-
- /**
- * @return array
- */
- public function provideSubDirAppAbsoluteUrlParts() {
- return array(
- array('files', 'ajax/list.php', array(), 'http://localhost/owncloud/index.php/apps/files/ajax/list.php'),
- array('files', 'ajax/list.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/owncloud/index.php/apps/files/ajax/list.php?trut=trat&dut=dat'),
- array('', 'index.php', array('trut' => 'trat', 'dut' => 'dat'), 'http://localhost/owncloud/index.php?trut=trat&dut=dat'),
- );
- }
-
- /**
- * @small
- * test linkToRemoteBase URL construction
- */
- public function testLinkToRemoteBase() {
- \OC::$WEBROOT = '';
- $result = \OC_Helper::linkToRemoteBase('webdav');
- $this->assertEquals('/remote.php/webdav', $result);
-
- \OC::$WEBROOT = '/owncloud';
- $result = \OC_Helper::linkToRemoteBase('webdav');
- $this->assertEquals('/owncloud/remote.php/webdav', $result);
- }
-
- /**
- * @small
- * test linkToRemote URL construction
- */
- public function testLinkToRemote() {
- \OC::$WEBROOT = '';
- $result = \OC_Helper::linkToRemote('webdav');
- $this->assertEquals('http://localhost/remote.php/webdav/', $result);
- $result = \OC_Helper::linkToRemote('webdav', false);
- $this->assertEquals('http://localhost/remote.php/webdav', $result);
-
- \OC::$WEBROOT = '/owncloud';
- $result = \OC_Helper::linkToRemote('webdav');
- $this->assertEquals('http://localhost/owncloud/remote.php/webdav/', $result);
- $result = \OC_Helper::linkToRemote('webdav', false);
- $this->assertEquals('http://localhost/owncloud/remote.php/webdav', $result);
- }
-
- /**
- * @small
* test linkToPublic URL construction
*/
public function testLinkToPublic() {
@@ -493,7 +261,7 @@ class Test_Helper extends \Test\TestCase {
* Tests recursive folder deletion with rmdirr()
*/
public function testRecursiveFolderDeletion() {
- $baseDir = \OC_Helper::tmpFolder() . '/';
+ $baseDir = \OC::$server->getTempManager()->getTemporaryFolder() . '/';
mkdir($baseDir . 'a/b/c/d/e', 0777, true);
mkdir($baseDir . 'a/b/c1/d/e', 0777, true);
mkdir($baseDir . 'a/b/c2/d/e', 0777, true);
diff --git a/tests/lib/helperstorage.php b/tests/lib/helperstorage.php
index 8b5f41fc94c..3109b509549 100644
--- a/tests/lib/helperstorage.php
+++ b/tests/lib/helperstorage.php
@@ -8,8 +8,9 @@
/**
* Test the storage functions of OC_Helper
+ *
+ * @group DB
*/
-
class Test_Helper_Storage extends \Test\TestCase {
/** @var string */
private $user;
@@ -22,7 +23,7 @@ class Test_Helper_Storage extends \Test\TestCase {
parent::setUp();
$this->user = $this->getUniqueID('user_');
- \OC_User::createUser($this->user, $this->user);
+ \OC::$server->getUserManager()->createUser($this->user, $this->user);
$this->storage = \OC\Files\Filesystem::getStorage('/');
\OC\Files\Filesystem::tearDown();
@@ -44,7 +45,8 @@ class Test_Helper_Storage extends \Test\TestCase {
\OC\Files\Filesystem::mount($this->storage, array(), '/');
\OC_User::setUserId('');
- \OC_User::deleteUser($this->user);
+ $user = \OC::$server->getUserManager()->get($this->user);
+ if ($user !== null) { $user->delete(); }
\OC::$server->getConfig()->deleteAllUserValues($this->user);
parent::tearDown();
@@ -119,19 +121,19 @@ class Test_Helper_Storage extends \Test\TestCase {
\OC\Files\Filesystem::mount($extStorage, array(), '/' . $this->user . '/files/ext');
- $oldConfig = \OC_Config::getValue('quota_include_external_storage', false);
- \OC_Config::setValue('quota_include_external_storage', 'true');
-
$config = \OC::$server->getConfig();
- $userQuota = $config->setUserValue($this->user, 'files', 'quota', '25');
+ $oldConfig = $config->getSystemValue('quota_include_external_storage', false);
+ $config->setSystemValue('quota_include_external_storage', 'true');
+
+ $config->setUserValue($this->user, 'files', 'quota', '25');
$storageInfo = \OC_Helper::getStorageInfo('');
$this->assertEquals(3, $storageInfo['free']);
$this->assertEquals(22, $storageInfo['used']);
$this->assertEquals(25, $storageInfo['total']);
- \OC_Config::setValue('quota_include_external_storage', $oldConfig);
- $userQuota = $config->setUserValue($this->user, 'files', 'quota', 'default');
+ $config->setSystemValue('quota_include_external_storage', $oldConfig);
+ $config->setUserValue($this->user, 'files', 'quota', 'default');
}
/**
@@ -150,15 +152,16 @@ class Test_Helper_Storage extends \Test\TestCase {
\OC\Files\Filesystem::mount($extStorage, array(), '/' . $this->user . '/files/ext');
- $oldConfig = \OC_Config::getValue('quota_include_external_storage', false);
- \OC_Config::setValue('quota_include_external_storage', 'true');
+ $config = \OC::$server->getConfig();
+ $oldConfig = $config->getSystemValue('quota_include_external_storage', false);
+ $config->setSystemValue('quota_include_external_storage', 'true');
$storageInfo = \OC_Helper::getStorageInfo('');
$this->assertEquals(12, $storageInfo['free']);
$this->assertEquals(5, $storageInfo['used']);
$this->assertEquals(17, $storageInfo['total']);
- \OC_Config::setValue('quota_include_external_storage', $oldConfig);
+ $config->setSystemValue('quota_include_external_storage', $oldConfig);
}
diff --git a/tests/lib/installer.php b/tests/lib/installer.php
index b58a71b5a08..ca210ba31ef 100644
--- a/tests/lib/installer.php
+++ b/tests/lib/installer.php
@@ -14,14 +14,15 @@ class Test_Installer extends \Test\TestCase {
protected function setUp() {
parent::setUp();
- $this->appstore = OC_Config::getValue('appstoreenabled', true);
- OC_Config::setValue('appstoreenabled', true);
+ $config = \OC::$server->getConfig();
+ $this->appstore = $config->setSystemValue('appstoreenabled', true);
+ $config->setSystemValue('appstoreenabled', true);
OC_Installer::removeApp(self::$appid);
}
protected function tearDown() {
OC_Installer::removeApp(self::$appid);
- OC_Config::setValue('appstoreenabled', $this->appstore);
+ \OC::$server->getConfig()->setSystemValue('appstoreenabled', $this->appstore);
parent::tearDown();
}
@@ -31,12 +32,16 @@ class Test_Installer extends \Test\TestCase {
$pathOfTestApp .= '/../data/';
$pathOfTestApp .= 'testapp.zip';
- $tmp = OC_Helper::tmpFile('.zip');
+ $tmp = \OC::$server->getTempManager()->getTemporaryFile('.zip');
OC_Helper::copyr($pathOfTestApp, $tmp);
$data = array(
'path' => $tmp,
'source' => 'path',
+ 'appdata' => [
+ 'id' => 'Bar',
+ 'level' => 100,
+ ]
);
OC_Installer::installApp($data);
@@ -50,24 +55,32 @@ class Test_Installer extends \Test\TestCase {
$pathOfOldTestApp .= '/../data/';
$pathOfOldTestApp .= 'testapp.zip';
- $oldTmp = OC_Helper::tmpFile('.zip');
+ $oldTmp = \OC::$server->getTempManager()->getTemporaryFile('.zip');
OC_Helper::copyr($pathOfOldTestApp, $oldTmp);
$oldData = array(
'path' => $oldTmp,
'source' => 'path',
+ 'appdata' => [
+ 'id' => 'Bar',
+ 'level' => 100,
+ ]
);
$pathOfNewTestApp = __DIR__;
$pathOfNewTestApp .= '/../data/';
$pathOfNewTestApp .= 'testapp2.zip';
- $newTmp = OC_Helper::tmpFile('.zip');
+ $newTmp = \OC::$server->getTempManager()->getTemporaryFile('.zip');
OC_Helper::copyr($pathOfNewTestApp, $newTmp);
$newData = array(
'path' => $newTmp,
'source' => 'path',
+ 'appdata' => [
+ 'id' => 'Bar',
+ 'level' => 100,
+ ]
);
OC_Installer::installApp($oldData);
diff --git a/tests/lib/integritycheck/checkertest.php b/tests/lib/integritycheck/checkertest.php
new file mode 100644
index 00000000000..fac60b0c123
--- /dev/null
+++ b/tests/lib/integritycheck/checkertest.php
@@ -0,0 +1,1011 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Test\IntegrityCheck;
+
+use OC\IntegrityCheck\Checker;
+use OC\Memcache\NullCache;
+use OCP\ICache;
+use phpseclib\Crypt\RSA;
+use phpseclib\File\X509;
+use Test\TestCase;
+use OC\IntegrityCheck\Helpers\EnvironmentHelper;
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
+use OC\IntegrityCheck\Helpers\AppLocator;
+use OCP\IConfig;
+use OCP\ICacheFactory;
+use OCP\App\IAppManager;
+
+class CheckerTest extends TestCase {
+ /** @var EnvironmentHelper */
+ private $environmentHelper;
+ /** @var AppLocator */
+ private $appLocator;
+ /** @var Checker */
+ private $checker;
+ /** @var FileAccessHelper */
+ private $fileAccessHelper;
+ /** @var IConfig */
+ private $config;
+ /** @var ICacheFactory */
+ private $cacheFactory;
+ /** @var IAppManager */
+ private $appManager;
+
+ public function setUp() {
+ parent::setUp();
+ $this->environmentHelper = $this->getMock('\OC\IntegrityCheck\Helpers\EnvironmentHelper');
+ $this->fileAccessHelper = $this->getMock('\OC\IntegrityCheck\Helpers\FileAccessHelper');
+ $this->appLocator = $this->getMock('\OC\IntegrityCheck\Helpers\AppLocator');
+ $this->config = $this->getMock('\OCP\IConfig');
+ $this->cacheFactory = $this->getMock('\OCP\ICacheFactory');
+ $this->appManager = $this->getMock('\OCP\App\IAppManager');
+
+ $this->cacheFactory
+ ->expects($this->any())
+ ->method('create')
+ ->with('oc.integritycheck.checker')
+ ->will($this->returnValue(new NullCache()));
+
+ $this->checker = new Checker(
+ $this->environmentHelper,
+ $this->fileAccessHelper,
+ $this->appLocator,
+ $this->config,
+ $this->cacheFactory,
+ $this->appManager
+ );
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Directory does not exist.
+ */
+ public function testWriteAppSignatureOfNotExistingApp() {
+ $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt');
+ $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key');
+ $rsa = new RSA();
+ $rsa->loadKey($rsaPrivateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $this->checker->writeAppSignature('NotExistingApp', $x509, $rsa);
+ }
+
+ public function testWriteAppSignature() {
+ $expectedSignatureFileData = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "Y5yvXvcGHVPuRRatKVDUONWq1FpLXugZd6Km\/+aEHsQj7coVl9FeMj9OsWamBf7yRIw3dtNLguTLlAA9QAv\/b0uHN3JnbNZN+dwFOve4NMtqXfSDlWftqKN00VS+RJXpG1S2IIx9Poyp2NoghL\/5AuTv4GHiNb7zU\/DT\/kt71pUGPgPR6IIFaE+zHOD96vjYkrH+GfWZzKR0FCdLib9yyNvk+EGrcjKM6qjs2GKfS\/XFjj\/\/neDnh\/0kcPuKE3ZbofnI4TIDTv0CGqvOp7PtqVNc3Vy\/UKa7uF1PT0MAUKMww6EiMUSFZdUVP4WWF0Y72W53Qdtf1hrAZa2kfKyoK5kd7sQmCSKUPSU8978AUVZlBtTRlyT803IKwMV0iHMkw+xYB1sN2FlHup\/DESADqxhdgYuK35bCPvgkb4SBe4B8Voz\/izTvcP7VT5UvkYdAO+05\/jzdaHEmzmsD92CFfvX0q8O\/Y\/29ubftUJsqcHeMDKgcR4eZOE8+\/QVc\/89QO6WnKNuNuV+5bybO6g6PAdC9ZPsCvnihS61O2mwRXHLR3jv2UleFWm+lZEquPKtkhi6SLtDiijA4GV6dmS+dzujSLb7hGeD5o1plZcZ94uhWljl+QIp82+zU\/lYB1Zfr4Mb4e+V7r2gv7Fbv7y6YtjE2GIQwRhC5jq56bD0ZB+I=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->once())
+ ->method('file_put_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json',
+ $expectedSignatureFileData
+ );
+
+ $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt');
+ $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key');
+ $rsa = new RSA();
+ $rsa->loadKey($rsaPrivateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $this->checker->writeAppSignature(\OC::$SERVERROOT . '/tests/data/integritycheck/app/', $x509, $rsa);
+ }
+
+ public function testVerifyAppSignatureWithoutSignatureData() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $expected = [
+ 'EXCEPTION' => [
+ 'class' => 'OC\IntegrityCheck\Exceptions\InvalidSignatureException',
+ 'message' => 'Signature data not found.',
+ ],
+ ];
+ $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp'));
+ }
+
+ public function testVerifyAppSignatureWithValidSignatureData() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->appLocator
+ ->expects($this->once())
+ ->method('getAppPath')
+ ->with('SomeApp')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ '/resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $this->assertSame([], $this->checker->verifyAppSignature('SomeApp'));
+ }
+
+ public function testVerifyAppSignatureWithTamperedSignatureData() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->appLocator
+ ->expects($this->once())
+ ->method('getAppPath')
+ ->with('SomeApp')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "tampered",
+ "subfolder\/file.txt": "tampered"
+ },
+ "signature": "EL49UaSeyMAqyMtqId+tgOhhwgOevPZsRLX4j2blnybAB6fN07z0936JqZV7+eMPiE30Idx+UCY6rCFN531Kqe9vAOCdgtHUSOjjKyKc+lvULESlMb6YQcrZrvDlEMMjzjH49ewG7Ai8sNN6HrRUd9U8ws+ewSkW2DOOBItj\/21RBnkrSt+2AtGXGigEvuTm57HrCYDj8\/lSkumC2GVkjLUHeLOKYo4PRNOr6yP5mED5v7zo66AWvXl2fKv54InZcdxsAk35lyK9DGZbk\/027ZRd0AOHT3LImRLvQ+8EAg3XLlRUy0hOFGgPC+jYonMzgYvsAXAXi2j8LnLJlsLwpFwu1k1B+kZVPMumKZvP9OvJb70EirecXmz62V+Jiyuaq7ne4y7Kp5gKZT\/T8SeZ0lFtCmPfYyzBB0y8s5ldmTTmdVYHs54t\/OCCW82HzQZxnFNPzDTRa8HglsaMKrqPtW59+R4UvRKSWhB8M\/Ah57qgzycvPV4KMz\/FbD4l\/\/9chRKSlCfc2k3b8ZSHNmi+EzCKgJjWIoKdgN1yax94puU8jfn8UW+G7H9Y1Jsf\/jox6QLyYEgtV1vOHY2xLT7fVs2vhyvkN2MNjJnmQ70gFG5Qz2lBz5wi6ZpB+tOfCcpbLxWAkoWoIrmC\/Ilqh7mfmRZ43g5upjkepHNd93ONuY8=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ '/resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $expected = [
+ 'EXCEPTION' => [
+ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException',
+ 'message' => 'Signature could not get verified.',
+ ],
+ ];
+ $this->assertEquals($expected, $this->checker->verifyAppSignature('SomeApp'));
+ }
+
+ public function testVerifyAppSignatureWithTamperedFiles() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->appLocator
+ ->expects($this->once())
+ ->method('getAppPath')
+ ->with('SomeApp')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//appinfo/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ '/resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+
+ $expected = [
+ 'INVALID_HASH' => [
+ 'AnotherFile.txt' => [
+ 'expected' => '1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112',
+ 'current' => '7322348ba269c6d5522efe02f424fa3a0da319a7cd9c33142a5afe32a2d9af2da3a411f086fcfc96ff4301ea566f481dba0960c2abeef3594c4d930462f6584c',
+ ],
+ ],
+ 'FILE_MISSING' => [
+ 'subfolder/file.txt' => [
+ 'expected' => '410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b',
+ 'current' => '',
+ ],
+ ],
+ 'EXTRA_FILE' => [
+ 'UnecessaryFile' => [
+ 'expected' => '',
+ 'current' => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e',
+ ],
+ ],
+
+ ];
+ $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp'));
+ }
+
+ public function testVerifyAppSignatureWithTamperedFilesAndAlternatePath() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->appLocator
+ ->expects($this->never())
+ ->method('getAppPath')
+ ->with('SomeApp');
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//appinfo/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ '/resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+
+ $expected = [
+ 'INVALID_HASH' => [
+ 'AnotherFile.txt' => [
+ 'expected' => '1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112',
+ 'current' => '7322348ba269c6d5522efe02f424fa3a0da319a7cd9c33142a5afe32a2d9af2da3a411f086fcfc96ff4301ea566f481dba0960c2abeef3594c4d930462f6584c',
+ ],
+ ],
+ 'FILE_MISSING' => [
+ 'subfolder/file.txt' => [
+ 'expected' => '410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b',
+ 'current' => '',
+ ],
+ ],
+ 'EXTRA_FILE' => [
+ 'UnecessaryFile' => [
+ 'expected' => '',
+ 'current' => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e',
+ ],
+ ],
+
+ ];
+ $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp', \OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'));
+ }
+
+ public function testVerifyAppWithDifferentScope() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->appLocator
+ ->expects($this->once())
+ ->method('getAppPath')
+ ->with('SomeApp')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "eXesvDm3pkek12xSwMG10y9suRES79Nye3jYNe5KYq1tTUPqRRNgxmMGAfcUro0zpLeAr2YgHeSMWtglblGOW7pmwGVPZ0O1Y4r1fE6jnep0kW+35PLIaqCorIOnCAtSzDNKBhwd1ow3zW2wC0DFouuEkIO8u5Fw28g8E8dp8zEk1xMblNPy+xtWkmYHrVJ\/dQgun1bYOF2ZFtAzatwndTI\/bGsy1i3Wsl+x6HyWKQdq8y8VObtOqKDH7uERBEpB9DHVyKflj1v1gQuEH6BhaRdATc7ee0MiQdGblraIySwYRdfo2d8i82OVKrenMB3SLwyCvDPyQ9iKpTOnSF52ZBqaqSXKM2N\/RAkweeBFQQCwcHhqxvB0cfbyHcbkOLeCZe\/tsh68IxwTiYgzvLfl7sOZ5arnZbzrPpZmB+hfV2omkoJ1tDwOWz9hEmLLNtfo2OxyUH1m0+XFaC+Gbn4WkVDgf7YZkwUcG+Qoa3oKDNMss8MEyZxewl2iDGZcf402dlidHRprlfmXbAYuVQ08\/a0HxIKYPGh\/nsMGmwnO15CWtFpAbhUA\/D5oRjsIxnvXaMDg0iAFpdu\/5Ffsj7g3EPdBkiQHNYK7YU1RRx609eH0bZyiIYHdUPw7ikLupvrebZmELqi3mqDFO99u4eISlxFJlUbUND3L4BtmWTWrKwI=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIExjCCAq6gAwIBAgIUHSJjhJqMwr+3TkoiQFg4SVVYQ1gwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIzMjc1NVoXDTE2MTEwMzIzMjc1NVowFzEVMBMGA1UEAwwMQW5vdGhlclNjb3Bl\r\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA33npb5RmUkXrDT+TbwMf\r\n0zQ33SlzsjoGxCrbSwJOn6leGGInJ6ZrdzLL0WTi\/dTpg+Y\/JS+72XWm5NSjaTxo\r\n7OHc3cQBwXQj4tN6j\/y5qqY0GDLYufEkx2rpazqt9lBSJ72u1bGl2yoOXzYCz5i0\r\n60KsJXC9K44LKzGsarzbwAgskSVNkjAsPgjnCWZmcl6icpLi5Fz9rs2UMOWbdvdI\r\nAROsn0eC9E\/akmXTy5YMu6bAIGpvjZFHzyA83FQRbvv5o1V5Gsye\/VQLEgh7rqfz\r\nT\/jgWifP+JgoeB6otzuRZ3fFsmbBiyCIRtIOzQQflozhUlWtmiEGwg4GySuMUjEH\r\nA1LF86LO+ZzDQgd2oYNKmrQ8O+EcLqx9BpV4AFhEvqdk7uycJYPHs6yl+yfbzTeJ\r\n2Xd0yVAfd9r\/iDr36clLj2bzEObdl9xzKjcCIXE4Q0G4Pur41\/BJUDK9PI390ccQ\r\nnFjjVYBMsC859OwW64tMP0zkM9Vv72LCaEzaR8jqH0j11catqxunr+StfMcmxLTN\r\nbqBJbSEq4ER3mJxCTI2UrIVmdQ7+wRxgv3QTDNOZyqrz2L8A1Rpb3h0APxtQv+oA\r\n8KIZYID5\/qsS2V2jITkMQ8Nd1W3b0cZhZ600z+znh3jLJ0TYLvwN6\/qBQTUDaM2o\r\ng1+icMqXIXIeKuoPCVVsG7cCAwEAATANBgkqhkiG9w0BAQUFAAOCAgEAHc4F\/kOV\r\nHc8In5MmGg2YtjwZzjdeoC5TIPZczRqz0B+wRbJzN6aYryKZKLmP+wKpgRnJWDzp\r\nrgKGyyEQIAfK63DEv4B9p4N1B+B3aeMKsSpVcw7wbFTD57V5A7pURGoo31d0mw5L\r\nUIXZ2u+TUfGbzucMxLdFhTwjGpz9M6Kkm\/POxmV0tvLija5LdbdKnYR9BFmyu4IX\r\nqyoIAtComATNLl+3URu3SZxhE3NxhzMz+eAeNfh1KuIf2gWIIeDCXalVSJLym+OQ\r\nHFDpqRhJqfTMprrRlmmU7Zntgbj8\/RRZuXnBvH9cQ2KykLOb4UoCPlGUqOqKyP9m\r\nDJSFRiMJfpgMQUaJk1TLhKF+IR6FnmwURLEtkONJumtDQju9KaWPlhueONdyGi0p\r\nqxLVUo1Vb52XnPhk2GEEduxpDc9V5ePJ+pdcEdMifY\/uPNBRuBj2c87yq1DLH+U4\r\n3XzP1MlwjnBWZYuoFo0j6Jq0r\/MG6HjGdmkGIsRoheRi8Z8Scz5AW5QRkNz8pKop\r\nTELFqQy9g6TyQzzC8t6HZcpNe842ZUk4raEAbCZe\/XqxWMw5svPgNceBqM3fh7sZ\r\nBSykOHLaL8kiRO\/IS3y1yZEAuiWBvtxcTNLzBb+hdRpm2y8\/qH\/pKo+CMj1VzjNT\r\nD8YRQg0cjmDytJzHDrtV\/aTc9W1aPHun0vw=\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//appinfo/signature.json')
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ '/resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $expected = [
+ 'EXCEPTION' => [
+ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException',
+ 'message' => 'Certificate is not valid for required scope. (Requested: SomeApp, current: CN=AnotherScope)',
+ ],
+ ];
+ $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp'));
+ }
+
+ public function testVerifyAppWithDifferentScopeAndAlwaysTrustedCore() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->appLocator
+ ->expects($this->once())
+ ->method('getAppPath')
+ ->with('SomeApp')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(\OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json')
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ '/resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $this->assertSame([], $this->checker->verifyAppSignature('SomeApp'));
+ }
+
+ public function testWriteCoreSignature() {
+ $expectedSignatureFileData = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->environmentHelper
+ ->expects($this->any())
+ ->method('getServerRoot')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'));
+ $this->fileAccessHelper
+ ->expects($this->once())
+ ->method('file_put_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json',
+ $expectedSignatureFileData
+ );
+
+ $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt');
+ $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key');
+ $rsa = new RSA();
+ $rsa->loadKey($rsaPrivateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/app/');
+ }
+
+ public function testWriteCoreSignatureWithUnmodifiedHtaccess() {
+ $expectedSignatureFileData = '{
+ "hashes": {
+ ".htaccess": "dc479770a6232061e04a768ee1f9133fdb3aea7b3a99f7105b0e0b6197474733e8d14b5b2bbad054e6b62a410fe5d0b3d790242dee1e0f11274af2100f5289e2",
+ "subfolder\/.htaccess": "2c57b1e25050e11dc3ae975832f378c452159f7b69f818e47eeeafadd6ba568517461dcb4d843b90b906cd7c89d161bc1b89dff8e3ae0eb6f5088508c47befd1"
+ },
+ "signature": "nRtR377DB\/I\/4hmh9q3elMQYfSHnQFlNtjchNgrdfmUQqVmgkU\/4qgGyxDqYkV8mSMbH2gYysfP42nx\/3zSo7n0dBYDfU87Q6f96Cv597vEV27do8CaBkEk8Xjn2SxhHw8hVxracvE2OBAPxk0H3sRp\/cQBgjoXpju4kQin0N5E+DEJMh7Sp+u8aKoFpb+2FaAZJFn\/hnqxLTlVi2nyDxGL3U0eobWY+jWH9XPt52v3Hyh8TDhcAnQ1cN30B8Jn2+jkrm8ib+buchaCXHk0cPX72xuPECdwOEKLCBNrJa3FGSvO1zWiecnCgxCXgt+R8hUgsVPTsbrdFY2YRJGIhHndYZL98XzgG7cw85SnnMMe2SulzeL7xANGF8qiEVyiC7x83bbj5xOkeM\/CUTajrLBO3vyZ23KKOxvskjgI0t+Zw1zFsl+sYW0\/O\/V5WzPOwMwV8+iApQ8k9gEMiYQg98QLEMYnSohncmp0Z9qx2qFcQuHLcKJVa1J6wGtE\/EHR\/4d0aYPd6IRjg+qshCJmdzud\/12xjpGTl+BT0Hi0VsU5o7ZMi7WhmukZmmv8u0uZsvKREQNATm4cO4WCkYySt5O9gZEJOF+jjgeynDoAh09lyrNXIgMpM9ufm\/XEG\/I\/f2zIwbAUc6J6qks5OuYlJzW5vscTiOKhwcGZU9WBLgh0=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->environmentHelper
+ ->expects($this->any())
+ ->method('getServerRoot')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessUnmodified/'));
+ $this->fileAccessHelper
+ ->expects($this->once())
+ ->method('file_put_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessUnmodified//core/signature.json',
+ $expectedSignatureFileData
+ );
+
+ $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt');
+ $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key');
+ $rsa = new RSA();
+ $rsa->loadKey($rsaPrivateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessUnmodified/');
+ }
+
+ public function testWriteCoreSignatureWithInvalidModifiedHtaccess() {
+ $expectedSignatureFileData = '{
+ "hashes": {
+ ".htaccess": "4a54273dc8d697b2ca615acf2ae2c1ee3c1c643492cb04f42b10984fa9aacff1420dc829fd82f93ad3476fbd0cdab0251142c887dc8f872d03e39a3a3eb6d381"
+ },
+ "signature": "qpDddYGgAKNR3TszOgjPXRphUl2P9Ym5OQaetltocgZASGDkOun5D64+1D0QJRKb4SG2+48muxGOHyL2Ngos4NUrrSR+SIkywZacay82YQBCEdr7\/4MjW1WHRPjvboLwEJwViw0EdAjsWRpD68aPnzUGrGsy2BsCo06P5iwjk9cXcHxdjC9R39npvoC3QNvQ2jmNIbh1Lc4U97dbb+CsXEQCLU1OSa9p3q6cEFV98Easwt7uF\/DzHK+CbeZlxVZ0DwLh2\/ylT1PyGou8QC1b3vKAnPjLWMO+UsCPpCKhk3C5pV+5etQ8puGd+0x2t5tEU+qXxLzek91zWNC+rqgC\/WlqLKbwPb\/BCHs4zLGV55Q2fEQmT21x0KCUELdPs4dBnYP4Ox5tEDugtJujWFzOHzoY6gGa\/BY\/78pSZXmq9o8dWkBEtioWWvaNZ1rM0ddE83GBlBTgjigi9Ay1D++bUW\/FCBB7CMk6qyNlV81H+cBuIEODw2aymmkM9LLDD2Qbmvo8gHEPRjiQxPC5OpDlcdSNiL+zcxVxeuX4FpT+9xzz\/\/DRONhufxRpsbuCOMxd96RW7y9U2N2Uxb3Bzn\/BIqEayUUsdgZjfaGcXXYKR+chu\/LOwNYN6RlnLsgqL\/dhGKwlRVKXw1RA2\/af\/CpqyR7uVP6al1YJo\/YJ+5XJ6zE=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->once())
+ ->method('file_put_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithInvalidModifiedContent//core/signature.json',
+ $expectedSignatureFileData
+ );
+
+ $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt');
+ $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key');
+ $rsa = new RSA();
+ $rsa->loadKey($rsaPrivateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithInvalidModifiedContent/');
+ }
+
+ public function testWriteCoreSignatureWithValidModifiedHtaccess() {
+ $expectedSignatureFileData = '{
+ "hashes": {
+ ".htaccess": "a232e6a616c40635d0220e47ebaade40348aadf141a67a331b8870b8fae056584e52fe8b56c49468ee17b58f92cbcd269dc30ae598d6206e97f7d8bb00a766c6",
+ "subfolder\/.htaccess": "2c57b1e25050e11dc3ae975832f378c452159f7b69f818e47eeeafadd6ba568517461dcb4d843b90b906cd7c89d161bc1b89dff8e3ae0eb6f5088508c47befd1"
+ },
+ "signature": "LNHvrAFg7NJL9h8TanIFmiI3xnmNRz8pltVgRJpnQTqLJCkhZWV5+poHIii\/\/dI4NhBijsoN0AAJckf1KFzyeI2rOk3w+niaOEXX7khoJDgbxuz0kwN13Bxa1A6j0cMFqm9IIWet0JK9MKaL8K\/n3CzNYovXhRBdJsYTQVWvkaY5KMQgTP2roqgaLBABfI8+fuZVnKie1D737UJ3LhxesEtqr9mJEUSdYuN1QpaScdv7bMkX7xTcg02T5Ljs4F0KsKSME43Pzxm33qCQ\/Gyfsz\/iNKHYQztg9wPkSanbqvFnDtHhcIhKBsETCbNuBZqBk0AwYCupLIJTjC6SShHc4TtWiv834wtSmc1fYfzrsq7gJalJifFAaeGemzFwkePFlVqjdYc63KSqK8ut0jEcjKPAmJ+5NCUoxc8iASMJCesf31mzUPlw1L9LCBMA0aywDqkZYK4tJHZYMvXc4UkSs19OuAzUbXMoVHsJ03ftfC02gpg4hqZDSiBqYuyKMvt2xuutTA+xQcl3fQGUuNdSmBqUFm0D5cCvT10aZPNUXA2cnS+89u58QSxO1wEZJCYKOrDvX1oqOyJs\/c8GNip3LwheIF2KB8\/Zh83h8ZncDxuesAzq89IjV815K3P1G\/kSVPhvQapw1KMLu9rBDZ3FVvQw8K8fg5a7opBrK2ggGds=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->environmentHelper
+ ->expects($this->any())
+ ->method('getServerRoot')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent'));
+ $this->fileAccessHelper
+ ->expects($this->once())
+ ->method('file_put_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent/core/signature.json',
+ $expectedSignatureFileData
+ );
+
+ $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt');
+ $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key');
+ $rsa = new RSA();
+ $rsa->loadKey($rsaPrivateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent');
+ }
+
+ public function testVerifyCoreSignatureWithoutSignatureData() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $expected = [
+ 'EXCEPTION' => [
+ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException',
+ 'message' => 'Signature data not found.',
+ ],
+ ];
+ $this->assertSame($expected, $this->checker->verifyCoreSignature());
+ }
+
+ public function testVerifyCoreSignatureWithValidSignatureData() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->environmentHelper
+ ->expects($this->any())
+ ->method('getServerRoot')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $this->assertSame([], $this->checker->verifyCoreSignature());
+ }
+
+ public function testVerifyCoreSignatureWithValidSignatureDataAndNotAlphabeticOrder() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->environmentHelper
+ ->expects($this->any())
+ ->method('getServerRoot')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $this->assertSame([], $this->checker->verifyCoreSignature());
+ }
+
+ public function testVerifyCoreSignatureWithTamperedSignatureData() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->environmentHelper
+ ->expects($this->any())
+ ->method('getServerRoot')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "tampered",
+ "subfolder\/file.txt": "tampered"
+ },
+ "signature": "eXesvDm3pkek12xSwMG10y9suRES79Nye3jYNe5KYq1tTUPqRRNgxmMGAfcUro0zpLeAr2YgHeSMWtglblGOW7pmwGVPZ0O1Y4r1fE6jnep0kW+35PLIaqCorIOnCAtSzDNKBhwd1ow3zW2wC0DFouuEkIO8u5Fw28g8E8dp8zEk1xMblNPy+xtWkmYHrVJ\/dQgun1bYOF2ZFtAzatwndTI\/bGsy1i3Wsl+x6HyWKQdq8y8VObtOqKDH7uERBEpB9DHVyKflj1v1gQuEH6BhaRdATc7ee0MiQdGblraIySwYRdfo2d8i82OVKrenMB3SLwyCvDPyQ9iKpTOnSF52ZBqaqSXKM2N\/RAkweeBFQQCwcHhqxvB0cfbyHcbkOLeCZe\/tsh68IxwTiYgzvLfl7sOZ5arnZbzrPpZmB+hfV2omkoJ1tDwOWz9hEmLLNtfo2OxyUH1m0+XFaC+Gbn4WkVDgf7YZkwUcG+Qoa3oKDNMss8MEyZxewl2iDGZcf402dlidHRprlfmXbAYuVQ08\/a0HxIKYPGh\/nsMGmwnO15CWtFpAbhUA\/D5oRjsIxnvXaMDg0iAFpdu\/5Ffsj7g3EPdBkiQHNYK7YU1RRx609eH0bZyiIYHdUPw7ikLupvrebZmELqi3mqDFO99u4eISlxFJlUbUND3L4BtmWTWrKwI=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//core/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $expected = [
+ 'EXCEPTION' => [
+ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException',
+ 'message' => 'Signature could not get verified.',
+ ]
+ ];
+ $this->assertSame($expected, $this->checker->verifyCoreSignature());
+ }
+
+ public function testVerifyCoreSignatureWithTamperedFiles() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->environmentHelper
+ ->expects($this->any())
+ ->method('getServerRoot')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//core/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $expected = [
+ 'INVALID_HASH' => [
+ 'AnotherFile.txt' => [
+ 'expected' => '1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112',
+ 'current' => '7322348ba269c6d5522efe02f424fa3a0da319a7cd9c33142a5afe32a2d9af2da3a411f086fcfc96ff4301ea566f481dba0960c2abeef3594c4d930462f6584c',
+ ],
+ ],
+ 'FILE_MISSING' => [
+ 'subfolder/file.txt' => [
+ 'expected' => '410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b',
+ 'current' => '',
+ ],
+ ],
+ 'EXTRA_FILE' => [
+ 'UnecessaryFile' => [
+ 'expected' => '',
+ 'current' => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e',
+ ],
+ ],
+
+ ];
+ $this->assertSame($expected, $this->checker->verifyCoreSignature());
+ }
+
+ public function testVerifyCoreWithInvalidCertificate() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->environmentHelper
+ ->expects($this->any())
+ ->method('getServerRoot')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "eXesvDm3pkek12xSwMG10y9suRES79Nye3jYNe5KYq1tTUPqRRNgxmMGAfcUro0zpLeAr2YgHeSMWtglblGOW7pmwGVPZ0O1Y4r1fE6jnep0kW+35PLIaqCorIOnCAtSzDNKBhwd1ow3zW2wC0DFouuEkIO8u5Fw28g8E8dp8zEk1xMblNPy+xtWkmYHrVJ\/dQgun1bYOF2ZFtAzatwndTI\/bGsy1i3Wsl+x6HyWKQdq8y8VObtOqKDH7uERBEpB9DHVyKflj1v1gQuEH6BhaRdATc7ee0MiQdGblraIySwYRdfo2d8i82OVKrenMB3SLwyCvDPyQ9iKpTOnSF52ZBqaqSXKM2N\/RAkweeBFQQCwcHhqxvB0cfbyHcbkOLeCZe\/tsh68IxwTiYgzvLfl7sOZ5arnZbzrPpZmB+hfV2omkoJ1tDwOWz9hEmLLNtfo2OxyUH1m0+XFaC+Gbn4WkVDgf7YZkwUcG+Qoa3oKDNMss8MEyZxewl2iDGZcf402dlidHRprlfmXbAYuVQ08\/a0HxIKYPGh\/nsMGmwnO15CWtFpAbhUA\/D5oRjsIxnvXaMDg0iAFpdu\/5Ffsj7g3EPdBkiQHNYK7YU1RRx609eH0bZyiIYHdUPw7ikLupvrebZmELqi3mqDFO99u4eISlxFJlUbUND3L4BtmWTWrKwI=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUPYoweUxCPqbDW4ntuh7QvgyqSrgwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDIwNloXDTE2MTEwMzIyNDIwNlowDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJui3nDbjOIjxNnthdBZplphujsN6u8K\r\nQ\/62zAuSwzXVp0+3IMgM\/2sepklVE8YfCyVJ5+SUJqnqHoUWVRVfs8jL0wW6nrHM\r\n\/lsscAguWCee4iAdNOqI9kq4+DUau8J45e62XA9mrAo\/8\/NKzFE2y2WduDoQZcm+\r\n8+dwcUUHXw2jl8dfrmvEMYSqTNDdb4rGmQpeV+dr9BLqr+x03U1Q08qCG9j7mSOz\r\ncvJENjOvC5uzAh5LCuCgxqG4o+mPzB0FtNnwoRRu6IsF3Y3KacRqPc30fB\/iXDn5\r\nBPr14uNxTTYWoZJ1F0tZrLzRbXdjJJOC+dnQurTtXWZ8WjPB1BWQYK7fW6t82mkN\r\n2Qe2xen99gs9nX5yY\/sHM3TKSJdM7AVCEv\/emW3gNjkvWTtRlN\/Nc7X2ckNwXcvo\r\n0yi3fSPjzXpDgLbhp1FzrMlHDn1VzmRT3r8wLByWa\/hsxrJDsBzwunMJYhXhmeKb\r\n3wX0tN\/EUJTWBntpwVOIGnRPD51oBoQUOMaEAq\/kz8PgN181bWZkJbRuf+FWkijQ\r\no+HR2lVF1jWXXst5Uc+s9HN81Uly7X4O9MMg0QxT4+wymtGDs6AOkwMi9rgBTrRB\r\n3tLU3XL2UIwRXgmd8cPtTu\/I6Bm7LdyaYtZ3yJTxRewq3nZdWypqBhD8uhpIYVkf\r\no4bxmGkVAQVTAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAKKAX5EHgU1grODnJ0of\r\nspFpgB1K67YvclNUyuU6NQ6zBJx1\/w1RnM7uxLcxiiWj1BbUhwZQ0ojmEHeUyi6O\r\nGrDVajwhTccDMmja3u5adhEncx65\/H+lD85IPRRkS2qBDssMDdJHhZ0uI+40nI7M\r\nMq1kFjl+6wiuqZXqps66DuLbk45g\/ZlrFIrIo3Ix5vj0OVqwT+gO4LYirJK6KgVS\r\nUttbcEsc\/yKU9ThnM8\/n4m2jstZXfzKPgOsJrQcZrFOtpj+CWmBzVElBSPlDT3Nh\r\nHSgOeTFJ8bQBxj2iG5dLA+JZJQKxyJ1gy2ZtxIJ2GyvLtSe8NUSqvfPWOaAKEUV2\r\ngniytnEFLr+PcD+9EGux6jZNuj6HmtWVThTfD5VGFmtlVU2z71ZRYY0kn6J3mmFc\r\nS2ecEcCUwqG5YNLncEUCyZhC2klWql2SHyGctCEyWWY7ikIDjVzYt2EbcFvLNBnP\r\ntybN1TYHRRZxlug00CCoOE9EZfk46FkZpDvU6KmqJRofkNZ5sj+SffyGcwYwNrDH\r\nKqe8m+9lHf3CRTIDeMu8r2xl1I6M6ZZfjabbmVP9Jd6WN4s6f1FlXDWzhlT1N0Qw\r\nGzJj6xB+SPtS3UV05tBlvbfA4e06D5G9uD7Q8ONcINtMS0xsSJ2oo82AqlpvlF\/q\r\noj7YKHsaTVGA+FxBktZHfoxD\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $expected = [
+ 'EXCEPTION' => [
+ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException',
+ 'message' => 'Certificate is not valid.',
+ ]
+ ];
+ $this->assertSame($expected, $this->checker->verifyCoreSignature());
+ }
+
+ public function testVerifyCoreWithDifferentScope() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->environmentHelper
+ ->expects($this->any())
+ ->method('getServerRoot')
+ ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'));
+ $signatureDataFile = '{
+ "hashes": {
+ "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112",
+ "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b"
+ },
+ "signature": "EL49UaSeyMAqyMtqId+tgOhhwgOevPZsRLX4j2blnybAB6fN07z0936JqZV7+eMPiE30Idx+UCY6rCFN531Kqe9vAOCdgtHUSOjjKyKc+lvULESlMb6YQcrZrvDlEMMjzjH49ewG7Ai8sNN6HrRUd9U8ws+ewSkW2DOOBItj\/21RBnkrSt+2AtGXGigEvuTm57HrCYDj8\/lSkumC2GVkjLUHeLOKYo4PRNOr6yP5mED5v7zo66AWvXl2fKv54InZcdxsAk35lyK9DGZbk\/027ZRd0AOHT3LImRLvQ+8EAg3XLlRUy0hOFGgPC+jYonMzgYvsAXAXi2j8LnLJlsLwpFwu1k1B+kZVPMumKZvP9OvJb70EirecXmz62V+Jiyuaq7ne4y7Kp5gKZT\/T8SeZ0lFtCmPfYyzBB0y8s5ldmTTmdVYHs54t\/OCCW82HzQZxnFNPzDTRa8HglsaMKrqPtW59+R4UvRKSWhB8M\/Ah57qgzycvPV4KMz\/FbD4l\/\/9chRKSlCfc2k3b8ZSHNmi+EzCKgJjWIoKdgN1yax94puU8jfn8UW+G7H9Y1Jsf\/jox6QLyYEgtV1vOHY2xLT7fVs2vhyvkN2MNjJnmQ70gFG5Qz2lBz5wi6ZpB+tOfCcpbLxWAkoWoIrmC\/Ilqh7mfmRZ43g5upjkepHNd93ONuY8=",
+ "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----"
+}';
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'
+ )
+ ->will($this->returnValue($signatureDataFile));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_get_contents')
+ ->with(
+ \OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'
+ )
+ ->will($this->returnValue(file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')));
+
+ $expected = [
+ 'EXCEPTION' => [
+ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException',
+ 'message' => 'Certificate is not valid for required scope. (Requested: core, current: CN=SomeApp)',
+ ]
+ ];
+ $this->assertSame($expected, $this->checker->verifyCoreSignature());
+ }
+
+ public function testRunInstanceVerification() {
+ $this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker')
+ ->setConstructorArgs([
+ $this->environmentHelper,
+ $this->fileAccessHelper,
+ $this->appLocator,
+ $this->config,
+ $this->cacheFactory,
+ $this->appManager,
+ ])
+ ->setMethods([
+ 'verifyCoreSignature',
+ 'verifyAppSignature',
+ ])
+ ->getMock();
+
+ $this->checker
+ ->expects($this->at(0))
+ ->method('verifyCoreSignature');
+ $this->appLocator
+ ->expects($this->at(0))
+ ->Method('getAllApps')
+ ->will($this->returnValue([
+ 'files',
+ 'calendar',
+ 'contacts',
+ 'dav',
+ ]));
+ $this->appManager
+ ->expects($this->at(0))
+ ->method('isShipped')
+ ->with('files')
+ ->will($this->returnValue(true));
+ $this->checker
+ ->expects($this->at(1))
+ ->method('verifyAppSignature')
+ ->with('files');
+ $this->appManager
+ ->expects($this->at(1))
+ ->method('isShipped')
+ ->with('calendar')
+ ->will($this->returnValue(false));
+ $this->appLocator
+ ->expects($this->at(1))
+ ->method('getAppPath')
+ ->with('calendar')
+ ->will($this->returnValue('/apps/calendar'));
+ $this->fileAccessHelper
+ ->expects($this->at(0))
+ ->method('file_exists')
+ ->with('/apps/calendar/appinfo/signature.json')
+ ->will($this->returnValue(true));
+ $this->checker
+ ->expects($this->at(2))
+ ->method('verifyAppSignature')
+ ->with('calendar');
+ $this->appManager
+ ->expects($this->at(2))
+ ->method('isShipped')
+ ->with('contacts')
+ ->will($this->returnValue(false));
+ $this->appLocator
+ ->expects($this->at(2))
+ ->method('getAppPath')
+ ->with('contacts')
+ ->will($this->returnValue('/apps/contacts'));
+ $this->fileAccessHelper
+ ->expects($this->at(1))
+ ->method('file_exists')
+ ->with('/apps/contacts/appinfo/signature.json')
+ ->will($this->returnValue(false));
+ $this->appManager
+ ->expects($this->at(3))
+ ->method('isShipped')
+ ->with('dav')
+ ->will($this->returnValue(true));
+ $this->checker
+ ->expects($this->at(3))
+ ->method('verifyAppSignature')
+ ->with('dav');
+ $this->config
+ ->expects($this->once())
+ ->method('deleteAppValue')
+ ->with('core', 'oc.integritycheck.checker');
+
+ $this->checker->runInstanceVerification();
+ }
+
+ public function testVerifyAppSignatureWithoutSignatureDataAndCodeCheckerDisabled() {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue('stable'));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(true));
+
+ $expected = [];
+ $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp'));
+ }
+
+ /**
+ * @return array
+ */
+ public function channelDataProvider() {
+ return [
+ ['stable', true],
+ ['git', false],
+ ];
+ }
+
+ /**
+ * @param string $channel
+ * @param bool $isCodeSigningEnforced
+ * @dataProvider channelDataProvider
+ */
+ public function testIsCodeCheckEnforced($channel, $isCodeSigningEnforced) {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue($channel));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(false));
+
+ $this->assertSame($isCodeSigningEnforced, $this->checker->isCodeCheckEnforced());
+ }
+
+ /**
+ * @param string $channel
+ * @dataProvider channelDataProvider
+ */
+ public function testIsCodeCheckEnforcedWithDisabledConfigSwitch($channel) {
+ $this->environmentHelper
+ ->expects($this->once())
+ ->method('getChannel')
+ ->will($this->returnValue($channel));
+ $this->config
+ ->expects($this->any())
+ ->method('getSystemValue')
+ ->with('integrity.check.disabled', false)
+ ->will($this->returnValue(true));
+
+ $result = $this->invokePrivate($this->checker, 'isCodeCheckEnforced');
+ $this->assertSame(false, $result);
+ }
+}
diff --git a/tests/lib/integritycheck/helpers/AppLocatorTest.php b/tests/lib/integritycheck/helpers/AppLocatorTest.php
new file mode 100644
index 00000000000..d0083298b22
--- /dev/null
+++ b/tests/lib/integritycheck/helpers/AppLocatorTest.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Test\IntegrityCheck\Helpers;
+
+use OC\IntegrityCheck\Helpers\AppLocator;
+use Test\TestCase;
+
+class AppLocatorTest extends TestCase {
+ /** @var AppLocator */
+ private $locator;
+
+ public function setUp() {
+ parent::setUp();
+ $this->locator = new AppLocator();
+ }
+
+ public function testGetAppPath() {
+ $this->assertSame(\OC_App::getAppPath('files'), $this->locator->getAppPath('files'));
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage App not found
+ */
+ public function testGetAppPathNotExistentApp() {
+ $this->locator->getAppPath('aTotallyNotExistingApp');
+ }
+
+ public function testGetAllApps() {
+ $this->assertSame(\OC_App::getAllApps(), $this->locator->getAllApps());
+ }
+}
diff --git a/tests/lib/integritycheck/helpers/EnvironmentHelperTest.php b/tests/lib/integritycheck/helpers/EnvironmentHelperTest.php
new file mode 100644
index 00000000000..a1d1f671b07
--- /dev/null
+++ b/tests/lib/integritycheck/helpers/EnvironmentHelperTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Test\IntegrityCheck\Factories;
+
+use OC\IntegrityCheck\Helpers\EnvironmentHelper;
+use Test\TestCase;
+
+class EnvironmentHelperTest extends TestCase {
+ /** @var EnvironmentHelper */
+ private $environmentHelper;
+
+ public function setUp() {
+ $this->environmentHelper = new EnvironmentHelper();
+ return parent::setUp();
+ }
+
+ public function testGetServerRoot() {
+ $this->assertSame(\OC::$SERVERROOT, $this->environmentHelper->getServerRoot());
+ }
+
+ public function testGetChannel() {
+ $this->assertSame(\OC_Util::getChannel(), $this->environmentHelper->getChannel());
+ }
+}
diff --git a/tests/lib/integritycheck/helpers/FileAccessHelperTest.php b/tests/lib/integritycheck/helpers/FileAccessHelperTest.php
new file mode 100644
index 00000000000..740b14e61c4
--- /dev/null
+++ b/tests/lib/integritycheck/helpers/FileAccessHelperTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace Test\IntegrityCheck\Helpers;
+
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
+use Test\TestCase;
+
+class FileAccessHelperTest extends TestCase {
+ /** @var FileAccessHelper */
+ private $fileAccessHelper;
+
+ public function setUp() {
+ parent::setUp();
+ $this->fileAccessHelper = new FileAccessHelper();
+ }
+
+ public function testReadAndWrite() {
+ $tempManager = \OC::$server->getTempManager();
+ $filePath = $tempManager->getTemporaryFile();
+ $data = 'SomeDataGeneratedByIntegrityCheck';
+
+ $this->fileAccessHelper->file_put_contents($filePath, $data);
+ $this->assertSame($data, $this->fileAccessHelper->file_get_contents($filePath));
+ }
+}
diff --git a/tests/lib/l10n/factorytest.php b/tests/lib/l10n/factorytest.php
new file mode 100644
index 00000000000..9f5954d0ee1
--- /dev/null
+++ b/tests/lib/l10n/factorytest.php
@@ -0,0 +1,425 @@
+<?php
+/**
+ * Copyright (c) 2016 Joas Schilling <nickvergessen@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\L10N;
+
+use OC\L10N\Factory;
+use Test\TestCase;
+
+/**
+ * Class FactoryTest
+ *
+ * @package Test\L10N
+ * @group DB
+ */
+class FactoryTest extends TestCase {
+
+ /** @var \OCP\IConfig|\PHPUnit_Framework_MockObject_MockObject */
+ protected $config;
+
+ /** @var \OCP\IRequest|\PHPUnit_Framework_MockObject_MockObject */
+ protected $request;
+
+ /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject */
+ protected $userSession;
+
+ public function setUp() {
+ parent::setUp();
+
+ /** @var \OCP\IConfig $request */
+ $this->config = $this->getMockBuilder('OCP\IConfig')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ /** @var \OCP\IRequest $request */
+ $this->request = $this->getMockBuilder('OCP\IRequest')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->userSession = $this->getMock('\OCP\IUserSession');
+ }
+
+ /**
+ * @param array $methods
+ * @return Factory|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected function getFactory(array $methods = []) {
+ if (!empty($methods)) {
+ return $this->getMockBuilder('OC\L10N\Factory')
+ ->setConstructorArgs([
+ $this->config,
+ $this->request,
+ $this->userSession
+ ])
+ ->setMethods($methods)
+ ->getMock();
+ } else {
+ return new Factory($this->config, $this->request, $this->userSession);
+ }
+ }
+
+ public function dataFindAvailableLanguages() {
+ return [
+ [null],
+ ['files'],
+ ];
+ }
+
+ public function testFindLanguageWithExistingRequestLanguageAndNoApp() {
+ $factory = $this->getFactory(['languageExists']);
+ $this->invokePrivate($factory, 'requestLanguage', ['de']);
+ $factory->expects($this->once())
+ ->method('languageExists')
+ ->with(null, 'de')
+ ->willReturn(true);
+
+ $this->assertSame('de', $factory->findLanguage());
+ }
+
+ public function testFindLanguageWithExistingRequestLanguageAndApp() {
+ $factory = $this->getFactory(['languageExists']);
+ $this->invokePrivate($factory, 'requestLanguage', ['de']);
+ $factory->expects($this->once())
+ ->method('languageExists')
+ ->with('MyApp', 'de')
+ ->willReturn(true);
+
+ $this->assertSame('de', $factory->findLanguage('MyApp'));
+ }
+
+ public function testFindLanguageWithNotExistingRequestLanguageAndExistingStoredUserLanguage() {
+ $factory = $this->getFactory(['languageExists']);
+ $this->invokePrivate($factory, 'requestLanguage', ['de']);
+ $factory->expects($this->at(0))
+ ->method('languageExists')
+ ->with('MyApp', 'de')
+ ->willReturn(false);
+ $this->config
+ ->expects($this->once())
+ ->method('getSystemValue')
+ ->with('installed', false)
+ ->willReturn(true);
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->once())
+ ->method('getUID')
+ ->willReturn('MyUserUid');
+ $this->userSession
+ ->expects($this->exactly(2))
+ ->method('getUser')
+ ->willReturn($user);
+ $this->config
+ ->expects($this->once())
+ ->method('getUserValue')
+ ->with('MyUserUid', 'core', 'lang', null)
+ ->willReturn('jp');
+ $factory->expects($this->at(1))
+ ->method('languageExists')
+ ->with('MyApp', 'jp')
+ ->willReturn(true);
+
+ $this->assertSame('jp', $factory->findLanguage('MyApp'));
+ }
+
+ public function testFindLanguageWithNotExistingRequestLanguageAndNotExistingStoredUserLanguage() {
+ $factory = $this->getFactory(['languageExists']);
+ $this->invokePrivate($factory, 'requestLanguage', ['de']);
+ $factory->expects($this->at(0))
+ ->method('languageExists')
+ ->with('MyApp', 'de')
+ ->willReturn(false);
+ $this->config
+ ->expects($this->at(0))
+ ->method('getSystemValue')
+ ->with('installed', false)
+ ->willReturn(true);
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->once())
+ ->method('getUID')
+ ->willReturn('MyUserUid');
+ $this->userSession
+ ->expects($this->exactly(2))
+ ->method('getUser')
+ ->willReturn($user);
+ $this->config
+ ->expects($this->once())
+ ->method('getUserValue')
+ ->with('MyUserUid', 'core', 'lang', null)
+ ->willReturn('jp');
+ $factory->expects($this->at(1))
+ ->method('languageExists')
+ ->with('MyApp', 'jp')
+ ->willReturn(false);
+ $this->config
+ ->expects($this->at(2))
+ ->method('getSystemValue')
+ ->with('default_language', false)
+ ->willReturn('es');
+ $factory->expects($this->at(2))
+ ->method('languageExists')
+ ->with('MyApp', 'es')
+ ->willReturn(true);
+
+ $this->assertSame('es', $factory->findLanguage('MyApp'));
+ }
+
+ public function testFindLanguageWithNotExistingRequestLanguageAndNotExistingStoredUserLanguageAndNotExistingDefault() {
+ $factory = $this->getFactory(['languageExists']);
+ $this->invokePrivate($factory, 'requestLanguage', ['de']);
+ $factory->expects($this->at(0))
+ ->method('languageExists')
+ ->with('MyApp', 'de')
+ ->willReturn(false);
+ $this->config
+ ->expects($this->at(0))
+ ->method('getSystemValue')
+ ->with('installed', false)
+ ->willReturn(true);
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->once())
+ ->method('getUID')
+ ->willReturn('MyUserUid');
+ $this->userSession
+ ->expects($this->exactly(2))
+ ->method('getUser')
+ ->willReturn($user);
+ $this->config
+ ->expects($this->once())
+ ->method('getUserValue')
+ ->with('MyUserUid', 'core', 'lang', null)
+ ->willReturn('jp');
+ $factory->expects($this->at(1))
+ ->method('languageExists')
+ ->with('MyApp', 'jp')
+ ->willReturn(false);
+ $this->config
+ ->expects($this->at(2))
+ ->method('getSystemValue')
+ ->with('default_language', false)
+ ->willReturn('es');
+ $factory->expects($this->at(2))
+ ->method('languageExists')
+ ->with('MyApp', 'es')
+ ->willReturn(false);
+ $this->config
+ ->expects($this->never())
+ ->method('setUserValue');
+
+ $this->assertSame('en', $factory->findLanguage('MyApp'));
+ }
+
+ public function testFindLanguageWithNotExistingRequestLanguageAndNotExistingStoredUserLanguageAndNotExistingDefaultAndNoAppInScope() {
+ $factory = $this->getFactory(['languageExists']);
+ $this->invokePrivate($factory, 'requestLanguage', ['de']);
+ $factory->expects($this->at(0))
+ ->method('languageExists')
+ ->with('MyApp', 'de')
+ ->willReturn(false);
+ $this->config
+ ->expects($this->at(0))
+ ->method('getSystemValue')
+ ->with('installed', false)
+ ->willReturn(true);
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->once())
+ ->method('getUID')
+ ->willReturn('MyUserUid');
+ $this->userSession
+ ->expects($this->exactly(2))
+ ->method('getUser')
+ ->willReturn($user);
+ $this->config
+ ->expects($this->once())
+ ->method('getUserValue')
+ ->with('MyUserUid', 'core', 'lang', null)
+ ->willReturn('jp');
+ $factory->expects($this->at(1))
+ ->method('languageExists')
+ ->with('MyApp', 'jp')
+ ->willReturn(false);
+ $this->config
+ ->expects($this->at(2))
+ ->method('getSystemValue')
+ ->with('default_language', false)
+ ->willReturn('es');
+ $factory->expects($this->at(2))
+ ->method('languageExists')
+ ->with('MyApp', 'es')
+ ->willReturn(false);
+ $this->config
+ ->expects($this->never())
+ ->method('setUserValue')
+ ->with('MyUserUid', 'core', 'lang', 'en');
+
+
+ $this->assertSame('en', $factory->findLanguage('MyApp'));
+ }
+
+ /**
+ * @dataProvider dataFindAvailableLanguages
+ *
+ * @param string|null $app
+ */
+ public function testFindAvailableLanguages($app) {
+ $factory = $this->getFactory(['findL10nDir']);
+ $factory->expects($this->once())
+ ->method('findL10nDir')
+ ->with($app)
+ ->willReturn(\OC::$SERVERROOT . '/tests/data/l10n/');
+
+ $this->assertEquals(['cs', 'de', 'en', 'ru'], $factory->findAvailableLanguages($app), '', 0.0, 10, true);
+ }
+
+ public function dataLanguageExists() {
+ return [
+ [null, 'en', [], true],
+ [null, 'de', [], false],
+ [null, 'de', ['ru'], false],
+ [null, 'de', ['ru', 'de'], true],
+ ['files', 'en', [], true],
+ ['files', 'de', [], false],
+ ['files', 'de', ['ru'], false],
+ ['files', 'de', ['de', 'ru'], true],
+ ];
+ }
+
+ /**
+ * @dataProvider dataLanguageExists
+ *
+ * @param string|null $app
+ * @param string $lang
+ * @param string[] $availableLanguages
+ * @param string $expected
+ */
+ public function testLanguageExists($app, $lang, array $availableLanguages, $expected) {
+ $factory = $this->getFactory(['findAvailableLanguages']);
+ $factory->expects(($lang === 'en') ? $this->never() : $this->once())
+ ->method('findAvailableLanguages')
+ ->with($app)
+ ->willReturn($availableLanguages);
+
+ $this->assertSame($expected, $factory->languageExists($app, $lang));
+ }
+
+ public function dataSetLanguageFromRequest() {
+ return [
+ // Language is available
+ [null, 'de', null, ['de'], 'de', 'de'],
+ [null, 'de,en', null, ['de'], 'de', 'de'],
+ [null, 'de-DE,en-US;q=0.8,en;q=0.6', null, ['de'], 'de', 'de'],
+ // Language is not available
+ [null, 'de', null, ['ru'], 'en', 'en'],
+ [null, 'de,en', null, ['ru', 'en'], 'en', 'en'],
+ [null, 'de-DE,en-US;q=0.8,en;q=0.6', null, ['ru', 'en'], 'en', 'en'],
+ // Language is available, but request language is set
+ [null, 'de', 'ru', ['de'], 'de', 'ru'],
+ [null, 'de,en', 'ru', ['de'], 'de', 'ru'],
+ [null, 'de-DE,en-US;q=0.8,en;q=0.6', 'ru', ['de'], 'de', 'ru'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataSetLanguageFromRequest
+ *
+ * @param string|null $app
+ * @param string $header
+ * @param string|null $requestLanguage
+ * @param string[] $availableLanguages
+ * @param string $expected
+ * @param string $expectedLang
+ */
+ public function testSetLanguageFromRequest($app, $header, $requestLanguage, array $availableLanguages, $expected, $expectedLang) {
+ $factory = $this->getFactory(['findAvailableLanguages']);
+ $factory->expects($this->once())
+ ->method('findAvailableLanguages')
+ ->with($app)
+ ->willReturn($availableLanguages);
+
+ $this->request->expects($this->once())
+ ->method('getHeader')
+ ->with('ACCEPT_LANGUAGE')
+ ->willReturn($header);
+
+ if ($requestLanguage !== null) {
+ $this->invokePrivate($factory, 'requestLanguage', [$requestLanguage]);
+ }
+ $this->assertSame($expected, $factory->setLanguageFromRequest($app), 'Asserting returned language');
+ $this->assertSame($expectedLang, $this->invokePrivate($factory, 'requestLanguage'), 'Asserting stored language');
+ }
+
+ public function dataGetL10nFilesForApp() {
+ return [
+ [null, 'de', [\OC::$SERVERROOT . '/core/l10n/de.json']],
+ ['core', 'ru', [\OC::$SERVERROOT . '/core/l10n/ru.json']],
+ ['lib', 'ru', [\OC::$SERVERROOT . '/lib/l10n/ru.json']],
+ ['settings', 'de', [\OC::$SERVERROOT . '/settings/l10n/de.json']],
+ ['files', 'de', [\OC::$SERVERROOT . '/apps/files/l10n/de.json']],
+ ['files', '_lang_never_exists_', []],
+ ['_app_never_exists_', 'de', [\OC::$SERVERROOT . '/core/l10n/de.json']],
+ ];
+ }
+
+ /**
+ * @dataProvider dataGetL10nFilesForApp
+ *
+ * @param string|null $app
+ * @param string $expected
+ */
+ public function testGetL10nFilesForApp($app, $lang, $expected) {
+ $factory = $this->getFactory();
+ $this->assertSame($expected, $this->invokePrivate($factory, 'getL10nFilesForApp', [$app, $lang]));
+ }
+
+ public function dataFindL10NDir() {
+ return [
+ [null, \OC::$SERVERROOT . '/core/l10n/'],
+ ['core', \OC::$SERVERROOT . '/core/l10n/'],
+ ['lib', \OC::$SERVERROOT . '/lib/l10n/'],
+ ['settings', \OC::$SERVERROOT . '/settings/l10n/'],
+ ['files', \OC::$SERVERROOT . '/apps/files/l10n/'],
+ ['_app_never_exists_', \OC::$SERVERROOT . '/core/l10n/'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataFindL10NDir
+ *
+ * @param string|null $app
+ * @param string $expected
+ */
+ public function testFindL10NDir($app, $expected) {
+ $factory = $this->getFactory();
+ $this->assertSame($expected, $this->invokePrivate($factory, 'findL10nDir', [$app]));
+ }
+
+ public function dataCreatePluralFunction() {
+ return [
+ ['nplurals=2; plural=(n != 1);', 0, 1],
+ ['nplurals=2; plural=(n != 1);', 1, 0],
+ ['nplurals=2; plural=(n != 1);', 2, 1],
+ ['nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;', 0, 2],
+ ['nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;', 1, 0],
+ ['nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;', 2, 1],
+ ['nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;', 3, 1],
+ ['nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;', 4, 1],
+ ['nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;', 5, 2],
+ ];
+ }
+
+ /**
+ * @dataProvider dataCreatePluralFunction
+ *
+ * @param string $function
+ * @param int $count
+ * @param int $expected
+ */
+ public function testCreatePluralFunction($function, $count, $expected) {
+ $factory = $this->getFactory();
+ $fn = $factory->createPluralFunction($function);
+ $this->assertEquals($expected, $fn($count));
+ }
+}
diff --git a/tests/lib/l10n.php b/tests/lib/l10n/l10nlegacytest.php
index cb2f4179c4d..025f761fe5c 100644
--- a/tests/lib/l10n.php
+++ b/tests/lib/l10n/l10nlegacytest.php
@@ -6,11 +6,21 @@
* See the COPYING-README file.
*/
-class Test_L10n extends \Test\TestCase {
+namespace Test\L10N;
+
+
+use OC_L10N;
+use DateTime;
+
+/**
+ * Class Test_L10n
+ * @group DB
+ */
+class L10nLegacyTest extends \Test\TestCase {
public function testGermanPluralTranslations() {
$l = new OC_L10N('test');
- $transFile = OC::$SERVERROOT.'/tests/data/l10n/de.json';
+ $transFile = \OC::$SERVERROOT.'/tests/data/l10n/de.json';
$l->load($transFile);
$this->assertEquals('1 Datei', (string)$l->n('%n file', '%n files', 1));
@@ -19,7 +29,7 @@ class Test_L10n extends \Test\TestCase {
public function testRussianPluralTranslations() {
$l = new OC_L10N('test');
- $transFile = OC::$SERVERROOT.'/tests/data/l10n/ru.json';
+ $transFile = \OC::$SERVERROOT.'/tests/data/l10n/ru.json';
$l->load($transFile);
$this->assertEquals('1 файл', (string)$l->n('%n file', '%n files', 1));
@@ -44,7 +54,7 @@ class Test_L10n extends \Test\TestCase {
public function testCzechPluralTranslations() {
$l = new OC_L10N('test');
- $transFile = OC::$SERVERROOT.'/tests/data/l10n/cs.json';
+ $transFile = \OC::$SERVERROOT.'/tests/data/l10n/cs.json';
$l->load($transFile);
$this->assertEquals('1 okno', (string)$l->n('%n window', '%n windows', 1));
@@ -113,54 +123,8 @@ class Test_L10n extends \Test\TestCase {
$this->assertSame($expected, $l->l('firstday', 'firstday'));
}
- /**
- * @dataProvider findLanguageData
- */
- public function testFindLanguage($default, $preference, $expected) {
- OC_User::setUserId(null);
- if (is_null($default)) {
- OC_Config::deleteKey('default_language');
- } else {
- OC_Config::setValue('default_language', $default);
- }
- $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $preference;
-
- $reflection = new \ReflectionClass('OC_L10N');
- $prop = $reflection->getProperty('language');
- $prop->setAccessible(1);
- $prop->setValue('');
- $prop->setAccessible(0);
-
- $this->assertSame($expected, OC_L10N::findLanguage());
- }
-
- public function findLanguageData() {
- return array(
- // Exact match
- array(null, 'de-DE,en;q=0.5', 'de_DE'),
- array(null, 'de-DE,en-US;q=0.8,en;q=0.6', 'de_DE'),
-
- // Best match
- array(null, 'de-US,en;q=0.5', 'de'),
- array(null, 'de-US,en-US;q=0.8,en;q=0.6', 'de'),
-
- // The default_language config setting overrides browser preferences.
- array('es_AR', 'de-DE,en;q=0.5', 'es_AR'),
- array('es_AR', 'de-DE,en-US;q=0.8,en;q=0.6', 'es_AR'),
-
- // Worst case default to english
- array(null, '', 'en'),
- array(null, null, 'en'),
- );
- }
-
- public function testGetLanguageCode() {
- $l = OC_L10N::get('lib', 'de');
- $this->assertEquals('de', $l->getLanguageCode());
- }
-
public function testFactoryGetLanguageCode() {
- $factory = new \OC\L10N\Factory();
+ $factory = new \OC\L10N\Factory($this->getMock('OCP\IConfig'), $this->getMock('OCP\IRequest'), $this->getMock('OCP\IUserSession'));
$l = $factory->get('lib', 'de');
$this->assertEquals('de', $l->getLanguageCode());
}
diff --git a/tests/lib/l10n/l10ntest.php b/tests/lib/l10n/l10ntest.php
new file mode 100644
index 00000000000..0d175954bc1
--- /dev/null
+++ b/tests/lib/l10n/l10ntest.php
@@ -0,0 +1,165 @@
+<?php
+/**
+ * Copyright (c) 2016 Joas Schilling <nickvergessen@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\L10N;
+
+
+use DateTime;
+use OC\L10N\Factory;
+use OC\L10N\L10N;
+use OCP\IUserSession;
+use Test\TestCase;
+
+/**
+ * Class L10nTest
+ *
+ * @package Test\L10N
+ */
+class L10nTest extends TestCase {
+ /**
+ * @return Factory
+ */
+ protected function getFactory() {
+ /** @var \OCP\IConfig $config */
+ $config = $this->getMock('OCP\IConfig');
+ /** @var \OCP\IRequest $request */
+ $request = $this->getMock('OCP\IRequest');
+ /** @var IUserSession $userSession */
+ $userSession = $this->getMock('OCP\IUserSession');
+ return new Factory($config, $request, $userSession);
+ }
+
+ public function testGermanPluralTranslations() {
+ $transFile = \OC::$SERVERROOT.'/tests/data/l10n/de.json';
+ $l = new L10N($this->getFactory(), 'test', 'de', [$transFile]);
+
+ $this->assertEquals('1 Datei', (string) $l->n('%n file', '%n files', 1));
+ $this->assertEquals('2 Dateien', (string) $l->n('%n file', '%n files', 2));
+ }
+
+ public function testRussianPluralTranslations() {
+ $transFile = \OC::$SERVERROOT.'/tests/data/l10n/ru.json';
+ $l = new L10N($this->getFactory(), 'test', 'ru', [$transFile]);
+
+ $this->assertEquals('1 файл', (string)$l->n('%n file', '%n files', 1));
+ $this->assertEquals('2 файла', (string)$l->n('%n file', '%n files', 2));
+ $this->assertEquals('6 файлов', (string)$l->n('%n file', '%n files', 6));
+ $this->assertEquals('21 файл', (string)$l->n('%n file', '%n files', 21));
+ $this->assertEquals('22 файла', (string)$l->n('%n file', '%n files', 22));
+ $this->assertEquals('26 файлов', (string)$l->n('%n file', '%n files', 26));
+
+ /*
+ 1 file 1 файл 1 папка
+ 2-4 files 2-4 файла 2-4 папки
+ 5-20 files 5-20 файлов 5-20 папок
+ 21 files 21 файл 21 папка
+ 22-24 files 22-24 файла 22-24 папки
+ 25-30 files 25-30 файлов 25-30 папок
+ etc
+ 100 files 100 файлов, 100 папок
+ 1000 files 1000 файлов 1000 папок
+ */
+ }
+
+ public function testCzechPluralTranslations() {
+ $transFile = \OC::$SERVERROOT.'/tests/data/l10n/cs.json';
+ $l = new L10N($this->getFactory(), 'test', 'cs', [$transFile]);
+
+ $this->assertEquals('1 okno', (string)$l->n('%n window', '%n windows', 1));
+ $this->assertEquals('2 okna', (string)$l->n('%n window', '%n windows', 2));
+ $this->assertEquals('5 oken', (string)$l->n('%n window', '%n windows', 5));
+ }
+
+ public function localizationData() {
+ return array(
+ // timestamp as string
+ array('February 13, 2009 at 11:31:30 PM GMT+0', 'en', 'datetime', '1234567890'),
+ array('13. Februar 2009 um 23:31:30 GMT+0', 'de', 'datetime', '1234567890'),
+ array('February 13, 2009', 'en', 'date', '1234567890'),
+ array('13. Februar 2009', 'de', 'date', '1234567890'),
+ array('11:31:30 PM GMT+0', 'en', 'time', '1234567890'),
+ array('23:31:30 GMT+0', 'de', 'time', '1234567890'),
+
+ // timestamp as int
+ array('February 13, 2009 at 11:31:30 PM GMT+0', 'en', 'datetime', 1234567890),
+ array('13. Februar 2009 um 23:31:30 GMT+0', 'de', 'datetime', 1234567890),
+ array('February 13, 2009', 'en', 'date', 1234567890),
+ array('13. Februar 2009', 'de', 'date', 1234567890),
+ array('11:31:30 PM GMT+0', 'en', 'time', 1234567890),
+ array('23:31:30 GMT+0', 'de', 'time', 1234567890),
+
+ // DateTime object
+ array('February 13, 2009 at 11:31:30 PM GMT+0', 'en', 'datetime', new DateTime('@1234567890')),
+ array('13. Februar 2009 um 23:31:30 GMT+0', 'de', 'datetime', new DateTime('@1234567890')),
+ array('February 13, 2009', 'en', 'date', new DateTime('@1234567890')),
+ array('13. Februar 2009', 'de', 'date', new DateTime('@1234567890')),
+ array('11:31:30 PM GMT+0', 'en', 'time', new DateTime('@1234567890')),
+ array('23:31:30 GMT+0', 'de', 'time', new DateTime('@1234567890')),
+
+ // en_GB
+ array('13 February 2009 at 23:31:30 GMT+0', 'en_GB', 'datetime', new DateTime('@1234567890')),
+ array('13 February 2009', 'en_GB', 'date', new DateTime('@1234567890')),
+ array('23:31:30 GMT+0', 'en_GB', 'time', new DateTime('@1234567890')),
+ array('13 February 2009 at 23:31:30 GMT+0', 'en-GB', 'datetime', new DateTime('@1234567890')),
+ array('13 February 2009', 'en-GB', 'date', new DateTime('@1234567890')),
+ array('23:31:30 GMT+0', 'en-GB', 'time', new DateTime('@1234567890')),
+ );
+ }
+
+ /**
+ * @dataProvider localizationData
+ */
+ public function testNumericStringLocalization($expectedDate, $lang, $type, $value) {
+ $l = new L10N($this->getFactory(), 'test', $lang, []);
+ $this->assertSame($expectedDate, $l->l($type, $value));
+ }
+
+ public function firstDayData() {
+ return array(
+ array(1, 'de'),
+ array(0, 'en'),
+ );
+ }
+
+ /**
+ * @dataProvider firstDayData
+ * @param $expected
+ * @param $lang
+ */
+ public function testFirstWeekDay($expected, $lang) {
+ $l = new L10N($this->getFactory(), 'test', $lang, []);
+ $this->assertSame($expected, $l->l('firstday', 'firstday'));
+ }
+
+ public function jsDateData() {
+ return array(
+ array('dd.MM.yy', 'de'),
+ array('M/d/yy', 'en'),
+ );
+ }
+
+ /**
+ * @dataProvider jsDateData
+ * @param $expected
+ * @param $lang
+ */
+ public function testJSDate($expected, $lang) {
+ $l = new L10N($this->getFactory(), 'test', $lang, []);
+ $this->assertSame($expected, $l->l('jsdate', 'jsdate'));
+ }
+
+ public function testFactoryGetLanguageCode() {
+ $l = $this->getFactory()->get('lib', 'de');
+ $this->assertEquals('de', $l->getLanguageCode());
+ }
+
+ public function testServiceGetLanguageCode() {
+ $l = \OC::$server->getL10N('lib', 'de');
+ $this->assertEquals('de', $l->getLanguageCode());
+ }
+}
diff --git a/tests/lib/lock/dblockingprovider.php b/tests/lib/lock/dblockingprovider.php
index 2360052b4a0..2032110f4f0 100644
--- a/tests/lib/lock/dblockingprovider.php
+++ b/tests/lib/lock/dblockingprovider.php
@@ -23,6 +23,13 @@ namespace Test\Lock;
use OCP\Lock\ILockingProvider;
+/**
+ * Class DBLockingProvider
+ *
+ * @group DB
+ *
+ * @package Test\Lock
+ */
class DBLockingProvider extends LockingProvider {
/**
* @var \OC\Lock\DBLockingProvider
@@ -78,13 +85,7 @@ class DBLockingProvider extends LockingProvider {
$this->assertEquals(3, $this->getLockEntryCount());
- $this->instance->cleanEmptyLocks();
-
- $this->assertEquals(3, $this->getLockEntryCount());
-
- $this->instance->releaseAll();
-
- $this->instance->cleanEmptyLocks();
+ $this->instance->cleanExpiredLocks();
$this->assertEquals(2, $this->getLockEntryCount());
}
diff --git a/tests/lib/log/owncloud.php b/tests/lib/log/owncloud.php
index d977583612b..adecc49768c 100644
--- a/tests/lib/log/owncloud.php
+++ b/tests/lib/log/owncloud.php
@@ -15,6 +15,11 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * Class Test_Log_Owncloud
+ *
+ * @group DB
+ */
class Test_Log_Owncloud extends Test\TestCase
{
private $restore_logfile;
@@ -22,37 +27,40 @@ class Test_Log_Owncloud extends Test\TestCase
protected function setUp() {
parent::setUp();
- $restore_logfile = OC_Config::getValue("logfile");
- $restore_logdateformat = OC_Config::getValue('logdateformat');
+ $config = \OC::$server->getConfig();
+ $this->restore_logfile = $config->getSystemValue("logfile");
+ $this->restore_logdateformat = $config->getSystemValue('logdateformat');
- OC_Config::setValue("logfile", OC_Config::getValue('datadirectory') . "/logtest");
+ $config->setSystemValue("logfile", $config->getSystemValue('datadirectory') . "/logtest");
OC_Log_Owncloud::init();
}
protected function tearDown() {
+ $config = \OC::$server->getConfig();
if (isset($this->restore_logfile)) {
- OC_Config::setValue("logfile", $this->restore_logfile);
+ $config->getSystemValue("logfile", $this->restore_logfile);
} else {
- OC_Config::deleteKey("logfile");
+ $config->deleteSystemValue("logfile");
}
if (isset($this->restore_logdateformat)) {
- OC_Config::setValue("logdateformat", $this->restore_logdateformat);
+ $config->getSystemValue("logdateformat", $this->restore_logdateformat);
} else {
- OC_Config::deleteKey("restore_logdateformat");
+ $config->deleteSystemValue("restore_logdateformat");
}
OC_Log_Owncloud::init();
parent::tearDown();
}
public function testMicrosecondsLogTimestamp() {
+ $config = \OC::$server->getConfig();
# delete old logfile
- unlink(OC_Config::getValue('logfile'));
+ unlink($config->getSystemValue('logfile'));
# set format & write log line
- OC_Config::setValue('logdateformat', 'u');
+ $config->setSystemValue('logdateformat', 'u');
OC_Log_Owncloud::write('test', 'message', \OCP\Util::ERROR);
# read log line
- $handle = @fopen(OC_Config::getValue('logfile'), 'r');
+ $handle = @fopen($config->getSystemValue('logfile'), 'r');
$line = fread($handle, 1000);
fclose($handle);
diff --git a/tests/lib/notification/actiontest.php b/tests/lib/notification/actiontest.php
index a6157d6c56e..74c995280c9 100644
--- a/tests/lib/notification/actiontest.php
+++ b/tests/lib/notification/actiontest.php
@@ -23,7 +23,7 @@ namespace Test\Notification;
use OC\Notification\Action;
-use OC\Notification\IAction;
+use OCP\Notification\IAction;
use Test\TestCase;
class ActionTest extends TestCase {
@@ -49,7 +49,7 @@ class ActionTest extends TestCase {
*/
public function testSetLabel($label) {
$this->assertSame('', $this->action->getLabel());
- $this->action->setLabel($label);
+ $this->assertSame($this->action, $this->action->setLabel($label));
$this->assertSame($label, $this->action->getLabel());
}
@@ -68,7 +68,7 @@ class ActionTest extends TestCase {
/**
* @dataProvider dataSetLabelInvalid
- * @param string $label
+ * @param mixed $label
*
* @expectedException \InvalidArgumentException
*/
@@ -90,7 +90,7 @@ class ActionTest extends TestCase {
*/
public function testSetParsedLabel($label) {
$this->assertSame('', $this->action->getParsedLabel());
- $this->action->setParsedLabel($label);
+ $this->assertSame($this->action, $this->action->setParsedLabel($label));
$this->assertSame($label, $this->action->getParsedLabel());
}
@@ -108,7 +108,7 @@ class ActionTest extends TestCase {
/**
* @dataProvider dataSetParsedLabelInvalid
- * @param string $label
+ * @param mixed $label
*
* @expectedException \InvalidArgumentException
*/
@@ -132,7 +132,7 @@ class ActionTest extends TestCase {
*/
public function testSetLink($link, $type) {
$this->assertSame('', $this->action->getLink());
- $this->action->setLink($link, $type);
+ $this->assertSame($this->action, $this->action->setLink($link, $type));
$this->assertSame($link, $this->action->getLink());
$this->assertSame($type, $this->action->getRequestType());
}
@@ -162,8 +162,8 @@ class ActionTest extends TestCase {
/**
* @dataProvider dataSetLinkInvalid
- * @param string $link
- * @param string $type
+ * @param mixed $link
+ * @param mixed $type
*
* @expectedException \InvalidArgumentException
*/
@@ -171,6 +171,44 @@ class ActionTest extends TestCase {
$this->action->setLink($link, $type);
}
+ public function dataSetPrimary() {
+ return [
+ [true],
+ [false],
+ ];
+ }
+
+ /**
+ * @dataProvider dataSetPrimary
+ * @param bool $primary
+ */
+ public function testSetPrimary($primary) {
+ $this->assertSame(false, $this->action->isPrimary());
+ $this->assertSame($this->action, $this->action->setPrimary($primary));
+ $this->assertSame($primary, $this->action->isPrimary());
+ }
+
+ public function dataSetPrimaryInvalid() {
+ return [
+ [0],
+ [1],
+ [''],
+ [str_repeat('a', 257)],
+ [[]],
+ [[str_repeat('a', 257)]],
+ ];
+ }
+
+ /**
+ * @dataProvider dataSetPrimaryInvalid
+ * @param mixed $primary
+ *
+ * @expectedException \InvalidArgumentException
+ */
+ public function testSetPrimaryInvalid($primary) {
+ $this->action->setPrimary($primary);
+ }
+
public function testIsValid() {
$this->assertFalse($this->action->isValid());
$this->assertFalse($this->action->isValidParsed());
diff --git a/tests/lib/notification/managertest.php b/tests/lib/notification/managertest.php
index fa2a0586f90..4410781bc31 100644
--- a/tests/lib/notification/managertest.php
+++ b/tests/lib/notification/managertest.php
@@ -22,7 +22,7 @@
namespace Test\Notification;
use OC\Notification\Manager;
-use OC\Notification\IManager;
+use OCP\Notification\IManager;
use Test\TestCase;
class ManagerTest extends TestCase {
@@ -35,7 +35,7 @@ class ManagerTest extends TestCase {
}
public function testRegisterApp() {
- $app = $this->getMockBuilder('OC\Notification\IApp')
+ $app = $this->getMockBuilder('OCP\Notification\IApp')
->disableOriginalConstructor()
->getMock();
@@ -59,7 +59,7 @@ class ManagerTest extends TestCase {
* @expectedException \InvalidArgumentException
*/
public function testRegisterAppInvalid() {
- $notifier = $this->getMockBuilder('OC\Notification\INotifier')
+ $notifier = $this->getMockBuilder('OCP\Notification\INotifier')
->disableOriginalConstructor()
->getMock();
@@ -73,7 +73,7 @@ class ManagerTest extends TestCase {
}
public function testRegisterNotifier() {
- $notifier = $this->getMockBuilder('OC\Notification\INotifier')
+ $notifier = $this->getMockBuilder('OCP\Notification\INotifier')
->disableOriginalConstructor()
->getMock();
@@ -82,22 +82,30 @@ class ManagerTest extends TestCase {
};
$this->assertEquals([], $this->invokePrivate($this->manager, 'getNotifiers'));
+ $this->assertEquals([], $this->invokePrivate($this->manager, 'listNotifiers'));
- $this->manager->registerNotifier($closure);
+ $this->manager->registerNotifier($closure, function() {
+ return ['id' => 'test1', 'name' => 'Test One'];
+ });
$this->assertEquals([$notifier], $this->invokePrivate($this->manager, 'getNotifiers'));
+ $this->assertEquals(['test1' => 'Test One'], $this->invokePrivate($this->manager, 'listNotifiers'));
$this->assertEquals([$notifier], $this->invokePrivate($this->manager, 'getNotifiers'));
+ $this->assertEquals(['test1' => 'Test One'], $this->invokePrivate($this->manager, 'listNotifiers'));
- $this->manager->registerNotifier($closure);
+ $this->manager->registerNotifier($closure, function() {
+ return ['id' => 'test2', 'name' => 'Test Two'];
+ });
$this->assertEquals([$notifier, $notifier], $this->invokePrivate($this->manager, 'getNotifiers'));
+ $this->assertEquals(['test1' => 'Test One', 'test2' => 'Test Two'], $this->invokePrivate($this->manager, 'listNotifiers'));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testRegisterNotifierInvalid() {
- $app = $this->getMockBuilder('OC\Notification\IApp')
+ $app = $this->getMockBuilder('OCP\Notification\IApp')
->disableOriginalConstructor()
->getMock();
@@ -105,35 +113,92 @@ class ManagerTest extends TestCase {
return $app;
};
- $this->manager->registerNotifier($closure);
+ $this->manager->registerNotifier($closure, function() {
+ return ['id' => 'test1', 'name' => 'Test One'];
+ });
$this->invokePrivate($this->manager, 'getNotifiers');
}
+ public function dataRegisterNotifierInfoInvalid() {
+ return [
+ [null],
+ ['No array'],
+ [['id' => 'test1', 'name' => 'Test One', 'size' => 'Invalid']],
+ [['no-id' => 'test1', 'name' => 'Test One']],
+ [['id' => 'test1', 'no-name' => 'Test One']],
+ ];
+ }
+
+ /**
+ * @dataProvider dataRegisterNotifierInfoInvalid
+ * @expectedException \InvalidArgumentException
+ * @param mixed $data
+ */
+ public function testRegisterNotifierInfoInvalid($data) {
+ $app = $this->getMockBuilder('OCP\Notification\IApp')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $closure = function() use ($app) {
+ return $app;
+ };
+
+ $this->manager->registerNotifier($closure, function() use ($data) {
+ return $data;
+ });
+
+ $this->manager->listNotifiers();
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage The given notifier ID test1 is already in use
+ */
+ public function testRegisterNotifierInfoDuplicate() {
+ $app = $this->getMockBuilder('OCP\Notification\IApp')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $closure = function() use ($app) {
+ return $app;
+ };
+
+ $this->manager->registerNotifier($closure, function() {
+ return ['id' => 'test1', 'name' => 'Test One'];
+ });
+
+ $this->manager->registerNotifier($closure, function() {
+ return ['id' => 'test1', 'name' => 'Test One'];
+ });
+
+ $this->manager->listNotifiers();
+ }
+
public function testCreateNotification() {
$action = $this->manager->createNotification();
- $this->assertInstanceOf('OC\Notification\INotification', $action);
+ $this->assertInstanceOf('OCP\Notification\INotification', $action);
}
public function testNotify() {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
- $notification = $this->getMockBuilder('OC\Notification\INotification')
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ $notification = $this->getMockBuilder('OCP\Notification\INotification')
->disableOriginalConstructor()
->getMock();
$notification->expects($this->once())
->method('isValid')
->willReturn(true);
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app */
- $app = $this->getMockBuilder('OC\Notification\IApp')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app */
+ $app = $this->getMockBuilder('OCP\Notification\IApp')
->disableOriginalConstructor()
->getMock();
$app->expects($this->once())
->method('notify')
->with($notification);
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app2 */
- $app2 = $this->getMockBuilder('OC\Notification\IApp')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app2 */
+ $app2 = $this->getMockBuilder('OCP\Notification\IApp')
->disableOriginalConstructor()
->getMock();
$app2->expects($this->once())
@@ -154,8 +219,8 @@ class ManagerTest extends TestCase {
* @expectedException \InvalidArgumentException
*/
public function testNotifyInvalid() {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
- $notification = $this->getMockBuilder('OC\Notification\INotification')
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ $notification = $this->getMockBuilder('OCP\Notification\INotification')
->disableOriginalConstructor()
->getMock();
$notification->expects($this->once())
@@ -166,23 +231,23 @@ class ManagerTest extends TestCase {
}
public function testPrepare() {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
- $notification = $this->getMockBuilder('OC\Notification\INotification')
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ $notification = $this->getMockBuilder('OCP\Notification\INotification')
->disableOriginalConstructor()
->getMock();
$notification->expects($this->once())
->method('isValidParsed')
->willReturn(true);
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification2 */
- $notification2 = $this->getMockBuilder('OC\Notification\INotification')
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification2 */
+ $notification2 = $this->getMockBuilder('OCP\Notification\INotification')
->disableOriginalConstructor()
->getMock();
$notification2->expects($this->exactly(2))
->method('isValidParsed')
->willReturn(true);
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier */
- $notifier = $this->getMockBuilder('OC\Notification\INotifier')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier */
+ $notifier = $this->getMockBuilder('OCP\Notification\INotifier')
->disableOriginalConstructor()
->getMock();
$notifier->expects($this->once())
@@ -190,8 +255,8 @@ class ManagerTest extends TestCase {
->with($notification, 'en')
->willReturnArgument(0);
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier2 */
- $notifier2 = $this->getMockBuilder('OC\Notification\INotifier')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier2 */
+ $notifier2 = $this->getMockBuilder('OCP\Notification\INotifier')
->disableOriginalConstructor()
->getMock();
$notifier2->expects($this->once())
@@ -201,9 +266,13 @@ class ManagerTest extends TestCase {
$this->manager->registerNotifier(function() use ($notifier) {
return $notifier;
+ }, function() {
+ return ['id' => 'test1', 'name' => 'Test One'];
});
$this->manager->registerNotifier(function() use ($notifier2) {
return $notifier2;
+ }, function() {
+ return ['id' => 'test2', 'name' => 'Test Two'];
});
$this->assertEquals($notification2, $this->manager->prepare($notification, 'en'));
@@ -213,16 +282,16 @@ class ManagerTest extends TestCase {
* @expectedException \InvalidArgumentException
*/
public function testPrepareInvalid() {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
- $notification = $this->getMockBuilder('OC\Notification\INotification')
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ $notification = $this->getMockBuilder('OCP\Notification\INotification')
->disableOriginalConstructor()
->getMock();
$notification->expects($this->once())
->method('isValidParsed')
->willReturn(false);
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier */
- $notifier = $this->getMockBuilder('OC\Notification\INotifier')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier */
+ $notifier = $this->getMockBuilder('OCP\Notification\INotifier')
->disableOriginalConstructor()
->getMock();
$notifier->expects($this->once())
@@ -232,22 +301,24 @@ class ManagerTest extends TestCase {
$this->manager->registerNotifier(function() use ($notifier) {
return $notifier;
+ }, function() {
+ return ['id' => 'test1', 'name' => 'Test One'];
});
$this->manager->prepare($notification, 'de');
}
public function testPrepareNotifierThrows() {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
- $notification = $this->getMockBuilder('OC\Notification\INotification')
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ $notification = $this->getMockBuilder('OCP\Notification\INotification')
->disableOriginalConstructor()
->getMock();
$notification->expects($this->once())
->method('isValidParsed')
->willReturn(true);
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier */
- $notifier = $this->getMockBuilder('OC\Notification\INotifier')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $notifier */
+ $notifier = $this->getMockBuilder('OCP\Notification\INotifier')
->disableOriginalConstructor()
->getMock();
$notifier->expects($this->once())
@@ -257,6 +328,8 @@ class ManagerTest extends TestCase {
$this->manager->registerNotifier(function() use ($notifier) {
return $notifier;
+ }, function() {
+ return ['id' => 'test1', 'name' => 'Test One'];
});
$this->assertEquals($notification, $this->manager->prepare($notification, 'de'));
@@ -266,8 +339,8 @@ class ManagerTest extends TestCase {
* @expectedException \InvalidArgumentException
*/
public function testPrepareNoNotifier() {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
- $notification = $this->getMockBuilder('OC\Notification\INotification')
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ $notification = $this->getMockBuilder('OCP\Notification\INotification')
->disableOriginalConstructor()
->getMock();
$notification->expects($this->once())
@@ -278,21 +351,21 @@ class ManagerTest extends TestCase {
}
public function testMarkProcessed() {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
- $notification = $this->getMockBuilder('OC\Notification\INotification')
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ $notification = $this->getMockBuilder('OCP\Notification\INotification')
->disableOriginalConstructor()
->getMock();
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app */
- $app = $this->getMockBuilder('OC\Notification\IApp')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app */
+ $app = $this->getMockBuilder('OCP\Notification\IApp')
->disableOriginalConstructor()
->getMock();
$app->expects($this->once())
->method('markProcessed')
->with($notification);
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app2 */
- $app2 = $this->getMockBuilder('OC\Notification\IApp')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app2 */
+ $app2 = $this->getMockBuilder('OCP\Notification\IApp')
->disableOriginalConstructor()
->getMock();
$app2->expects($this->once())
@@ -310,13 +383,13 @@ class ManagerTest extends TestCase {
}
public function testGetCount() {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
- $notification = $this->getMockBuilder('OC\Notification\INotification')
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ $notification = $this->getMockBuilder('OCP\Notification\INotification')
->disableOriginalConstructor()
->getMock();
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app */
- $app = $this->getMockBuilder('OC\Notification\IApp')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app */
+ $app = $this->getMockBuilder('OCP\Notification\IApp')
->disableOriginalConstructor()
->getMock();
$app->expects($this->once())
@@ -324,8 +397,8 @@ class ManagerTest extends TestCase {
->with($notification)
->willReturn(21);
- /** @var \OC\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app2 */
- $app2 = $this->getMockBuilder('OC\Notification\IApp')
+ /** @var \OCP\Notification\IApp|\PHPUnit_Framework_MockObject_MockObject $app2 */
+ $app2 = $this->getMockBuilder('OCP\Notification\IApp')
->disableOriginalConstructor()
->getMock();
$app2->expects($this->once())
diff --git a/tests/lib/notification/notificationtest.php b/tests/lib/notification/notificationtest.php
index 8be49ebdc17..ee9454c77a0 100644
--- a/tests/lib/notification/notificationtest.php
+++ b/tests/lib/notification/notificationtest.php
@@ -23,7 +23,7 @@ namespace Test\Notification;
use OC\Notification\Notification;
-use OC\Notification\INotification;
+use OCP\Notification\INotification;
use Test\TestCase;
class NotificationTest extends TestCase {
@@ -62,14 +62,6 @@ class NotificationTest extends TestCase {
return $dataSets;
}
- protected function dataValidInt() {
- return [
- [0],
- [1],
- [time()],
- ];
- }
-
protected function dataInvalidInt() {
return [
[true],
@@ -93,7 +85,7 @@ class NotificationTest extends TestCase {
*/
public function testSetApp($app) {
$this->assertSame('', $this->notification->getApp());
- $this->notification->setApp($app);
+ $this->assertSame($this->notification, $this->notification->setApp($app));
$this->assertSame($app, $this->notification->getApp());
}
@@ -121,7 +113,7 @@ class NotificationTest extends TestCase {
*/
public function testSetUser($user) {
$this->assertSame('', $this->notification->getUser());
- $this->notification->setUser($user);
+ $this->assertSame($this->notification, $this->notification->setUser($user));
$this->assertSame($user, $this->notification->getUser());
}
@@ -139,52 +131,68 @@ class NotificationTest extends TestCase {
$this->notification->setUser($user);
}
- public function dataSetTimestamp() {
- return $this->dataValidInt();
+ public function dataSetDateTime() {
+ $past = new \DateTime();
+ $past->sub(new \DateInterval('P1Y'));
+ $current = new \DateTime();
+ $future = new \DateTime();
+ $future->add(new \DateInterval('P1Y'));
+
+ return [
+ [$past],
+ [$current],
+ [$future],
+ ];
}
/**
- * @dataProvider dataSetTimestamp
- * @param int $timestamp
+ * @dataProvider dataSetDateTime
+ * @param \DateTime $dateTime
*/
- public function testSetTimestamp($timestamp) {
- $this->assertSame(0, $this->notification->getTimestamp());
- $this->notification->setTimestamp($timestamp);
- $this->assertSame($timestamp, $this->notification->getTimestamp());
+ public function testSetDateTime(\DateTime $dateTime) {
+ $this->assertSame(0, $this->notification->getDateTime()->getTimestamp());
+ $this->assertSame($this->notification, $this->notification->setDateTime($dateTime));
+ $this->assertSame($dateTime, $this->notification->getDateTime());
}
- public function dataSetTimestampInvalid() {
- return $this->dataInvalidInt();
+ public function dataSetDateTimeZero() {
+ $nineTeenSeventy = new \DateTime();
+ $nineTeenSeventy->setTimestamp(0);
+ return [
+ [$nineTeenSeventy],
+ ];
}
/**
- * @dataProvider dataSetTimestampInvalid
- * @param mixed $timestamp
+ * @dataProvider dataSetDateTimeZero
+ * @param \DateTime $dateTime
*
* @expectedException \InvalidArgumentException
+ * @expectedMessage 'The given date time is invalid'
*/
- public function testSetTimestampInvalid($timestamp) {
- $this->notification->setTimestamp($timestamp);
+ public function testSetDateTimeZero($dateTime) {
+ $this->notification->setDateTime($dateTime);
}
public function dataSetObject() {
return [
- ['a', 1],
- [str_repeat('a', 64), time()],
+ ['a', '21', '21'],
+ [str_repeat('a', 64), 42, '42'],
];
}
/**
* @dataProvider dataSetObject
* @param string $type
- * @param int $id
+ * @param int|string $id
+ * @param string $exptectedId
*/
- public function testSetObject($type, $id) {
+ public function testSetObject($type, $id, $exptectedId) {
$this->assertSame('', $this->notification->getObjectType());
- $this->assertSame(0, $this->notification->getObjectId());
- $this->notification->setObject($type, $id);
+ $this->assertSame('', $this->notification->getObjectId());
+ $this->assertSame($this->notification, $this->notification->setObject($type, $id));
$this->assertSame($type, $this->notification->getObjectType());
- $this->assertSame($id, $this->notification->getObjectId());
+ $this->assertSame($exptectedId, $this->notification->getObjectId());
}
public function dataSetObjectTypeInvalid() {
@@ -203,7 +211,14 @@ class NotificationTest extends TestCase {
}
public function dataSetObjectIdInvalid() {
- return $this->dataInvalidInt();
+ return [
+ [true],
+ [false],
+ [''],
+ [str_repeat('a', 64 + 1)],
+ [[]],
+ [[str_repeat('a', 64 + 1)]],
+ ];
}
/**
@@ -233,7 +248,7 @@ class NotificationTest extends TestCase {
public function testSetSubject($subject, $parameters) {
$this->assertSame('', $this->notification->getSubject());
$this->assertSame([], $this->notification->getSubjectParameters());
- $this->notification->setSubject($subject, $parameters);
+ $this->assertSame($this->notification, $this->notification->setSubject($subject, $parameters));
$this->assertSame($subject, $this->notification->getSubject());
$this->assertSame($parameters, $this->notification->getSubjectParameters());
}
@@ -262,7 +277,7 @@ class NotificationTest extends TestCase {
*/
public function testSetParsedSubject($subject) {
$this->assertSame('', $this->notification->getParsedSubject());
- $this->notification->setParsedSubject($subject);
+ $this->assertSame($this->notification, $this->notification->setParsedSubject($subject));
$this->assertSame($subject, $this->notification->getParsedSubject());
}
@@ -296,7 +311,7 @@ class NotificationTest extends TestCase {
public function testSetMessage($message, $parameters) {
$this->assertSame('', $this->notification->getMessage());
$this->assertSame([], $this->notification->getMessageParameters());
- $this->notification->setMessage($message, $parameters);
+ $this->assertSame($this->notification, $this->notification->setMessage($message, $parameters));
$this->assertSame($message, $this->notification->getMessage());
$this->assertSame($parameters, $this->notification->getMessageParameters());
}
@@ -325,7 +340,7 @@ class NotificationTest extends TestCase {
*/
public function testSetParsedMessage($message) {
$this->assertSame('', $this->notification->getParsedMessage());
- $this->notification->setParsedMessage($message);
+ $this->assertSame($this->notification, $this->notification->setParsedMessage($message));
$this->assertSame($message, $this->notification->getParsedMessage());
}
@@ -353,7 +368,7 @@ class NotificationTest extends TestCase {
*/
public function testSetLink($link) {
$this->assertSame('', $this->notification->getLink());
- $this->notification->setLink($link);
+ $this->assertSame($this->notification, $this->notification->setLink($link));
$this->assertSame($link, $this->notification->getLink());
}
@@ -373,12 +388,12 @@ class NotificationTest extends TestCase {
public function testCreateAction() {
$action = $this->notification->createAction();
- $this->assertInstanceOf('OC\Notification\IAction', $action);
+ $this->assertInstanceOf('OCP\Notification\IAction', $action);
}
public function testAddAction() {
- /** @var \OC\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
- $action = $this->getMockBuilder('OC\Notification\IAction')
+ /** @var \OCP\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
+ $action = $this->getMockBuilder('OCP\Notification\IAction')
->disableOriginalConstructor()
->getMock();
$action->expects($this->once())
@@ -387,7 +402,7 @@ class NotificationTest extends TestCase {
$action->expects($this->never())
->method('isValidParsed');
- $this->notification->addAction($action);
+ $this->assertSame($this->notification, $this->notification->addAction($action));
$this->assertEquals([$action], $this->notification->getActions());
$this->assertEquals([], $this->notification->getParsedActions());
@@ -397,8 +412,8 @@ class NotificationTest extends TestCase {
* @expectedException \InvalidArgumentException
*/
public function testAddActionInvalid() {
- /** @var \OC\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
- $action = $this->getMockBuilder('OC\Notification\IAction')
+ /** @var \OCP\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
+ $action = $this->getMockBuilder('OCP\Notification\IAction')
->disableOriginalConstructor()
->getMock();
$action->expects($this->once())
@@ -411,8 +426,8 @@ class NotificationTest extends TestCase {
}
public function testAddActionSecondPrimary() {
- /** @var \OC\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
- $action = $this->getMockBuilder('OC\Notification\IAction')
+ /** @var \OCP\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
+ $action = $this->getMockBuilder('OCP\Notification\IAction')
->disableOriginalConstructor()
->getMock();
$action->expects($this->exactly(2))
@@ -422,15 +437,15 @@ class NotificationTest extends TestCase {
->method('isPrimary')
->willReturn(true);
- $this->notification->addAction($action);
+ $this->assertSame($this->notification, $this->notification->addAction($action));
$this->setExpectedException('\InvalidArgumentException');
$this->notification->addAction($action);
}
public function testAddParsedAction() {
- /** @var \OC\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
- $action = $this->getMockBuilder('OC\Notification\IAction')
+ /** @var \OCP\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
+ $action = $this->getMockBuilder('OCP\Notification\IAction')
->disableOriginalConstructor()
->getMock();
$action->expects($this->once())
@@ -439,7 +454,7 @@ class NotificationTest extends TestCase {
$action->expects($this->never())
->method('isValid');
- $this->notification->addParsedAction($action);
+ $this->assertSame($this->notification, $this->notification->addParsedAction($action));
$this->assertEquals([$action], $this->notification->getParsedActions());
$this->assertEquals([], $this->notification->getActions());
@@ -449,8 +464,8 @@ class NotificationTest extends TestCase {
* @expectedException \InvalidArgumentException
*/
public function testAddParsedActionInvalid() {
- /** @var \OC\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
- $action = $this->getMockBuilder('OC\Notification\IAction')
+ /** @var \OCP\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
+ $action = $this->getMockBuilder('OCP\Notification\IAction')
->disableOriginalConstructor()
->getMock();
$action->expects($this->once())
@@ -463,8 +478,8 @@ class NotificationTest extends TestCase {
}
public function testAddActionSecondParsedPrimary() {
- /** @var \OC\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
- $action = $this->getMockBuilder('OC\Notification\IAction')
+ /** @var \OCP\Notification\IAction|\PHPUnit_Framework_MockObject_MockObject $action */
+ $action = $this->getMockBuilder('OCP\Notification\IAction')
->disableOriginalConstructor()
->getMock();
$action->expects($this->exactly(2))
@@ -474,7 +489,7 @@ class NotificationTest extends TestCase {
->method('isPrimary')
->willReturn(true);
- $this->notification->addParsedAction($action);
+ $this->assertSame($this->notification, $this->notification->addParsedAction($action));
$this->setExpectedException('\InvalidArgumentException');
$this->notification->addParsedAction($action);
@@ -497,7 +512,7 @@ class NotificationTest extends TestCase {
* @param bool $expected
*/
public function testIsValid($isValidCommon, $subject, $expected) {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder('\OC\Notification\Notification')
->setMethods([
'isValidCommon',
@@ -528,7 +543,7 @@ class NotificationTest extends TestCase {
* @param bool $expected
*/
public function testIsParsedValid($isValidCommon, $subject, $expected) {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder('\OC\Notification\Notification')
->setMethods([
'isValidCommon',
@@ -553,12 +568,12 @@ class NotificationTest extends TestCase {
public function dataIsValidCommon() {
return [
- ['', '', 0, '', 0, false],
- ['app', '', 0, '', 0, false],
- ['app', 'user', 0, '', 0, false],
- ['app', 'user', time(), '', 0, false],
- ['app', 'user', time(), 'type', 0, false],
- ['app', 'user', time(), 'type', 42, true],
+ ['', '', 0, '', '', false],
+ ['app', '', 0, '', '', false],
+ ['app', 'user', 0, '', '', false],
+ ['app', 'user', time(), '', '', false],
+ ['app', 'user', time(), 'type', '', false],
+ ['app', 'user', time(), 'type', '42', true],
];
}
@@ -569,16 +584,16 @@ class NotificationTest extends TestCase {
* @param string $user
* @param int $timestamp
* @param string $objectType
- * @param int $objectId
+ * @param string $objectId
* @param bool $expected
*/
public function testIsValidCommon($app, $user, $timestamp, $objectType, $objectId, $expected) {
- /** @var \OC\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
+ /** @var \OCP\Notification\INotification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder('\OC\Notification\Notification')
->setMethods([
'getApp',
'getUser',
- 'getTimestamp',
+ 'getDateTime',
'getObjectType',
'getObjectId',
])
@@ -592,9 +607,12 @@ class NotificationTest extends TestCase {
->method('getUser')
->willReturn($user);
+ $dateTime = new \DateTime();
+ $dateTime->setTimestamp($timestamp);
+
$notification->expects($this->any())
- ->method('getTimestamp')
- ->willReturn($timestamp);
+ ->method('getDateTime')
+ ->willReturn($dateTime);
$notification->expects($this->any())
->method('getObjectType')
diff --git a/tests/lib/ocs/privatedata.php b/tests/lib/ocs/privatedata.php
index a9300f5beac..ce153bf07d6 100644
--- a/tests/lib/ocs/privatedata.php
+++ b/tests/lib/ocs/privatedata.php
@@ -20,6 +20,11 @@
*
*/
+/**
+ * Class Test_OC_OCS_Privatedata
+ *
+ * @group DB
+ */
class Test_OC_OCS_Privatedata extends \Test\TestCase {
private $appKey;
diff --git a/tests/lib/ocsclienttest.php b/tests/lib/ocsclienttest.php
index 80102eb62ee..66e4c4b938e 100644
--- a/tests/lib/ocsclienttest.php
+++ b/tests/lib/ocsclienttest.php
@@ -748,7 +748,7 @@ class OCSClientTest extends \Test\TestCase {
->expects($this->once())
->method('get')
->with(
- 'https://api.owncloud.com/v1/content/data/MyId',
+ 'https://api.owncloud.com/v1/content/data/166053',
[
'timeout' => 5,
'query' => ['version' => '8x1x0x7'],
@@ -779,8 +779,145 @@ class OCSClientTest extends \Test\TestCase {
'score' => 50,
'level' => 200,
];
- $this->assertSame($expected, $this->ocsClient->getApplication('MyId', [8, 1, 0, 7]));
+ $this->assertSame($expected, $this->ocsClient->getApplication(166053, [8, 1, 0, 7]));
}
+
+ public function testGetApplicationSuccessfulWithOldId() {
+ $this->config
+ ->expects($this->at(0))
+ ->method('getSystemValue')
+ ->with('appstoreenabled', true)
+ ->will($this->returnValue(true));
+ $this->config
+ ->expects($this->at(1))
+ ->method('getSystemValue')
+ ->with('appstoreurl', 'https://api.owncloud.com/v1')
+ ->will($this->returnValue('https://api.owncloud.com/v1'));
+
+ $response = $this->getMock('\OCP\Http\Client\IResponse');
+ $response
+ ->expects($this->once())
+ ->method('getBody')
+ ->will($this->returnValue('<?xml version="1.0"?>
+ <ocs>
+ <meta>
+ <status>ok</status>
+ <statuscode>100</statuscode>
+ <message></message>
+ </meta>
+ <data>
+ <content details="full">
+ <id>1337</id>
+ <name>Versioning</name>
+ <version>0.0.1</version>
+ <label>recommended</label>
+ <typeid>925</typeid>
+ <typename>ownCloud other</typename>
+ <language></language>
+ <personid>owncloud</personid>
+ <profilepage>http://opendesktop.org/usermanager/search.php?username=owncloud</profilepage>
+ <created>2014-07-07T16:34:40+02:00</created>
+ <changed>2014-07-07T16:34:40+02:00</changed>
+ <downloads>140</downloads>
+ <score>50</score>
+ <description>Placeholder for future updates</description>
+ <summary></summary>
+ <feedbackurl></feedbackurl>
+ <changelog></changelog>
+ <homepage></homepage>
+ <homepagetype></homepagetype>
+ <homepage2></homepage2>
+ <homepagetype2></homepagetype2>
+ <homepage3></homepage3>
+ <homepagetype3></homepagetype3>
+ <homepage4></homepage4>
+ <homepagetype4></homepagetype4>
+ <homepage5></homepage5>
+ <homepagetype5></homepagetype5>
+ <homepage6></homepage6>
+ <homepagetype6></homepagetype6>
+ <homepage7></homepage7>
+ <homepagetype7></homepagetype7>
+ <homepage8></homepage8>
+ <homepagetype8></homepagetype8>
+ <homepage9></homepage9>
+ <homepagetype9></homepagetype9>
+ <homepage10></homepage10>
+ <homepagetype10></homepagetype10>
+ <licensetype>16</licensetype>
+ <license>AGPL</license>
+ <donationpage></donationpage>
+ <comments>0</comments>
+ <commentspage>http://apps.owncloud.com/content/show.php?content=166053</commentspage>
+ <fans>0</fans>
+ <fanspage>http://apps.owncloud.com/content/show.php?action=fan&amp;content=166053</fanspage>
+ <knowledgebaseentries>0</knowledgebaseentries>
+ <knowledgebasepage>http://apps.owncloud.com/content/show.php?action=knowledgebase&amp;content=166053</knowledgebasepage>
+ <depend>ownCloud 7</depend>
+ <preview1></preview1>
+ <preview2></preview2>
+ <preview3></preview3>
+ <previewpic1></previewpic1>
+ <previewpic2></previewpic2>
+ <previewpic3></previewpic3>
+ <picsmall1></picsmall1>
+ <picsmall2></picsmall2>
+ <picsmall3></picsmall3>
+ <detailpage>https://apps.owncloud.com/content/show.php?content=166053</detailpage>
+ <downloadtype1></downloadtype1>
+ <downloadprice1>0</downloadprice1>
+ <downloadlink1>http://apps.owncloud.com/content/download.php?content=166053&amp;id=1</downloadlink1>
+ <downloadname1></downloadname1>
+ <downloadgpgfingerprint1></downloadgpgfingerprint1>
+ <downloadgpgsignature1></downloadgpgsignature1>
+ <downloadpackagename1></downloadpackagename1>
+ <downloadrepository1></downloadrepository1>
+ <downloadsize1>1</downloadsize1>
+ <approved>200</approved>
+ </content>
+ </data>
+ </ocs>
+ '));
+
+ $client = $this->getMock('\OCP\Http\Client\IClient');
+ $client
+ ->expects($this->once())
+ ->method('get')
+ ->with(
+ 'https://api.owncloud.com/v1/content/data/166053',
+ [
+ 'timeout' => 5,
+ 'query' => ['version' => '8x1x0x7'],
+ ]
+ )
+ ->will($this->returnValue($response));
+
+ $this->clientService
+ ->expects($this->once())
+ ->method('newClient')
+ ->will($this->returnValue($client));
+
+ $expected = [
+ 'id' => 166053,
+ 'name' => 'Versioning',
+ 'version' => '0.0.1',
+ 'type' => '925',
+ 'label' => 'recommended',
+ 'typename' => 'ownCloud other',
+ 'personid' => 'owncloud',
+ 'profilepage' => 'http://opendesktop.org/usermanager/search.php?username=owncloud',
+ 'detailpage' => 'https://apps.owncloud.com/content/show.php?content=166053',
+ 'preview1' => '',
+ 'preview2' => '',
+ 'preview3' => '',
+ 'changed' => 1404743680,
+ 'description' => 'Placeholder for future updates',
+ 'score' => 50,
+ 'level' => 200,
+ ];
+ $this->assertSame($expected, $this->ocsClient->getApplication(166053, [8, 1, 0, 7]));
+ }
+
public function testGetApplicationEmptyXml() {
$this->config
->expects($this->at(0))
diff --git a/tests/lib/preview.php b/tests/lib/preview.php
index e4c599c66cf..bc6f849cbe8 100644
--- a/tests/lib/preview.php
+++ b/tests/lib/preview.php
@@ -28,6 +28,13 @@ use OC\Files\View;
use Test\Traits\MountProviderTrait;
use Test\Traits\UserTrait;
+/**
+ * Class Preview
+ *
+ * @group DB
+ *
+ * @package Test
+ */
class Preview extends TestCase {
use UserTrait;
use MountProviderTrait;
diff --git a/tests/lib/preview/bitmap.php b/tests/lib/preview/bitmap.php
index 49112852e29..1e135ceb083 100644
--- a/tests/lib/preview/bitmap.php
+++ b/tests/lib/preview/bitmap.php
@@ -21,6 +21,13 @@
namespace Test\Preview;
+/**
+ * Class Bitmap
+ *
+ * @group DB
+ *
+ * @package Test\Preview
+ */
class Bitmap extends Provider {
public function setUp() {
diff --git a/tests/lib/preview/image.php b/tests/lib/preview/image.php
index af46f4e4a66..6c82ff85723 100644
--- a/tests/lib/preview/image.php
+++ b/tests/lib/preview/image.php
@@ -21,6 +21,13 @@
namespace Test\Preview;
+/**
+ * Class Image
+ *
+ * @group DB
+ *
+ * @package Test\Preview
+ */
class Image extends Provider {
public function setUp() {
diff --git a/tests/lib/preview/mp3.php b/tests/lib/preview/mp3.php
index ac3ab07a2bd..f6875a88ebd 100644
--- a/tests/lib/preview/mp3.php
+++ b/tests/lib/preview/mp3.php
@@ -21,6 +21,13 @@
namespace Test\Preview;
+/**
+ * Class MP3
+ *
+ * @group DB
+ *
+ * @package Test\Preview
+ */
class MP3 extends Provider {
public function setUp() {
diff --git a/tests/lib/preview/svg.php b/tests/lib/preview/svg.php
index 768569c72ed..ef5f4cff80f 100644
--- a/tests/lib/preview/svg.php
+++ b/tests/lib/preview/svg.php
@@ -21,6 +21,13 @@
namespace Test\Preview;
+/**
+ * Class SVG
+ *
+ * @group DB
+ *
+ * @package Test\Preview
+ */
class SVG extends Provider {
public function setUp() {
diff --git a/tests/lib/preview/txt.php b/tests/lib/preview/txt.php
index 8bda86f25e3..219b850be95 100644
--- a/tests/lib/preview/txt.php
+++ b/tests/lib/preview/txt.php
@@ -21,6 +21,13 @@
namespace Test\Preview;
+/**
+ * Class TXT
+ *
+ * @group DB
+ *
+ * @package Test\Preview
+ */
class TXT extends Provider {
public function setUp() {
diff --git a/tests/lib/repair/cleantags.php b/tests/lib/repair/cleantags.php
index a511daa03d6..9773a591777 100644
--- a/tests/lib/repair/cleantags.php
+++ b/tests/lib/repair/cleantags.php
@@ -11,6 +11,8 @@ namespace Test\Repair;
/**
* Tests for the cleaning the tags tables
*
+ * @group DB
+ *
* @see \OC\Repair\CleanTags
*/
class CleanTags extends \Test\TestCase {
@@ -165,20 +167,6 @@ class CleanTags extends \Test\TestCase {
* @return int
*/
protected function getLastInsertID($tableName, $idName) {
- $id = $this->connection->lastInsertId();
- if ($id) {
- return $id;
- }
-
- // FIXME !!!! ORACLE WORKAROUND DO NOT COPY
- // FIXME INSTEAD HELP FIXING DOCTRINE
- // FIXME https://github.com/owncloud/core/issues/13303
- // FIXME ALSO FIX https://github.com/owncloud/core/commit/2dd85ec984c12d3be401518f22c90d2327bec07a
- $qb = $this->connection->getQueryBuilder();
- $result = $qb->select($qb->createFunction('MAX(`' . $idName . '`)'))
- ->from($tableName)
- ->execute();
-
- return (int) $result->fetchColumn();
+ return $this->connection->lastInsertId("*PREFIX*$tableName");
}
}
diff --git a/tests/lib/repair/dropoldjobs.php b/tests/lib/repair/dropoldjobs.php
index 27d7860c63d..a85c6506dbb 100644
--- a/tests/lib/repair/dropoldjobs.php
+++ b/tests/lib/repair/dropoldjobs.php
@@ -13,6 +13,8 @@ use OCP\BackgroundJob\IJobList;
/**
* Tests for the dropping old tables
*
+ * @group DB
+ *
* @see \OC\Repair\DropOldTables
*/
class DropOldJobs extends \Test\TestCase {
diff --git a/tests/lib/repair/dropoldtables.php b/tests/lib/repair/dropoldtables.php
index 244d8837949..6ece8cf04d5 100644
--- a/tests/lib/repair/dropoldtables.php
+++ b/tests/lib/repair/dropoldtables.php
@@ -11,6 +11,8 @@ namespace Test\Repair;
/**
* Tests for the dropping old tables
*
+ * @group DB
+ *
* @see \OC\Repair\DropOldTables
*/
class DropOldTables extends \Test\TestCase {
diff --git a/tests/lib/repair/oldgroupmembershipsharestest.php b/tests/lib/repair/oldgroupmembershipsharestest.php
index 74f68bd7899..f02babab21d 100644
--- a/tests/lib/repair/oldgroupmembershipsharestest.php
+++ b/tests/lib/repair/oldgroupmembershipsharestest.php
@@ -11,6 +11,13 @@ namespace Test\Repair;
use OC\Repair\OldGroupMembershipShares;
use OC\Share\Constants;
+/**
+ * Class OldGroupMembershipSharesTest
+ *
+ * @group DB
+ *
+ * @package Test\Repair
+ */
class OldGroupMembershipSharesTest extends \Test\TestCase {
/** @var OldGroupMembershipShares */
@@ -72,7 +79,7 @@ class OldGroupMembershipSharesTest extends \Test\TestCase {
->orderBy('id', 'ASC')
->execute();
$rows = $result->fetchAll();
- $this->assertSame([['id' => $parent], ['id' => $group2], ['id' => $user1], ['id' => $member], ['id' => $notAMember]], $rows);
+ $this->assertEquals([['id' => $parent], ['id' => $group2], ['id' => $user1], ['id' => $member], ['id' => $notAMember]], $rows);
$result->closeCursor();
$repair->run();
@@ -83,7 +90,7 @@ class OldGroupMembershipSharesTest extends \Test\TestCase {
->orderBy('id', 'ASC')
->execute();
$rows = $result->fetchAll();
- $this->assertSame([['id' => $parent], ['id' => $group2], ['id' => $user1], ['id' => $member]], $rows);
+ $this->assertEquals([['id' => $parent], ['id' => $group2], ['id' => $user1], ['id' => $member]], $rows);
$result->closeCursor();
}
@@ -118,21 +125,6 @@ class OldGroupMembershipSharesTest extends \Test\TestCase {
->values($shareValues)
->execute();
- return $this->getLastShareId();
- }
-
- /**
- * @return int
- */
- protected function getLastShareId() {
- // select because lastInsertId does not work with OCI
- $query = $this->connection->getQueryBuilder();
- $result = $query->select('id')
- ->from('share')
- ->orderBy('id', 'DESC')
- ->execute();
- $row = $result->fetch();
- $result->closeCursor();
- return $row['id'];
+ return $this->connection->lastInsertId('*PREFIX*share');
}
}
diff --git a/tests/lib/repair/removegetetagentriestest.php b/tests/lib/repair/removegetetagentriestest.php
index 43b7bf323c0..12f0ae8a8d6 100644
--- a/tests/lib/repair/removegetetagentriestest.php
+++ b/tests/lib/repair/removegetetagentriestest.php
@@ -24,6 +24,13 @@ namespace Test\Repair;
use OC\Repair\RemoveGetETagEntries;
use Test\TestCase;
+/**
+ * Class RemoveGetETagEntriesTest
+ *
+ * @group DB
+ *
+ * @package Test\Repair
+ */
class RemoveGetETagEntriesTest extends TestCase {
/** @var \OCP\IDBConnection */
protected $connection;
diff --git a/tests/lib/repair/repaircollation.php b/tests/lib/repair/repaircollation.php
index 29dad190008..8d609aeed38 100644
--- a/tests/lib/repair/repaircollation.php
+++ b/tests/lib/repair/repaircollation.php
@@ -19,6 +19,8 @@ class TestCollationRepair extends \OC\Repair\Collation {
/**
* Tests for the converting of MySQL tables to InnoDB engine
*
+ * @group DB
+ *
* @see \OC\Repair\RepairMimeTypes
*/
class TestRepairCollation extends \Test\TestCase {
@@ -46,7 +48,7 @@ class TestRepairCollation extends \Test\TestCase {
protected function setUp() {
parent::setUp();
- $this->connection = \OC_DB::getConnection();
+ $this->connection = \OC::$server->getDatabaseConnection();
$this->config = \OC::$server->getConfig();
if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MySqlPlatform) {
$this->markTestSkipped("Test only relevant on MySql");
diff --git a/tests/lib/repair/repairinnodb.php b/tests/lib/repair/repairinnodb.php
index 33f7a0e2136..5c73b931367 100644
--- a/tests/lib/repair/repairinnodb.php
+++ b/tests/lib/repair/repairinnodb.php
@@ -10,6 +10,8 @@ namespace Test\Repair;
/**
* Tests for the converting of MySQL tables to InnoDB engine
*
+ * @group DB
+ *
* @see \OC\Repair\RepairMimeTypes
*/
class RepairInnoDB extends \Test\TestCase {
@@ -26,7 +28,7 @@ class RepairInnoDB extends \Test\TestCase {
protected function setUp() {
parent::setUp();
- $this->connection = \OC_DB::getConnection();
+ $this->connection = \OC::$server->getDatabaseConnection();
if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MySqlPlatform) {
$this->markTestSkipped("Test only relevant on MySql");
}
diff --git a/tests/lib/repair/repairinvalidsharestest.php b/tests/lib/repair/repairinvalidsharestest.php
index 005a2db2344..9655e0eacbc 100644
--- a/tests/lib/repair/repairinvalidsharestest.php
+++ b/tests/lib/repair/repairinvalidsharestest.php
@@ -16,6 +16,8 @@ use Test\TestCase;
/**
* Tests for repairing invalid shares
*
+ * @group DB
+ *
* @see \OC\Repair\RepairInvalidShares
*/
class RepairInvalidSharesTest extends TestCase {
@@ -162,7 +164,7 @@ class RepairInvalidSharesTest extends TestCase {
->orderBy('id', 'ASC')
->execute();
$rows = $result->fetchAll();
- $this->assertSame([['id' => $parent], ['id' => $validChild], ['id' => $invalidChild]], $rows);
+ $this->assertEquals([['id' => $parent], ['id' => $validChild], ['id' => $invalidChild]], $rows);
$result->closeCursor();
$this->repair->run();
@@ -173,7 +175,7 @@ class RepairInvalidSharesTest extends TestCase {
->orderBy('id', 'ASC')
->execute();
$rows = $result->fetchAll();
- $this->assertSame([['id' => $parent], ['id' => $validChild]], $rows);
+ $this->assertEquals([['id' => $parent], ['id' => $validChild]], $rows);
$result->closeCursor();
}
@@ -181,15 +183,7 @@ class RepairInvalidSharesTest extends TestCase {
* @return int
*/
protected function getLastShareId() {
- // select because lastInsertId does not work with OCI
- $query = $this->connection->getQueryBuilder();
- $result = $query->select('id')
- ->from('share')
- ->orderBy('id', 'DESC')
- ->execute();
- $row = $result->fetch();
- $result->closeCursor();
- return $row['id'];
+ return $this->connection->lastInsertId('*PREFIX*share');
}
}
diff --git a/tests/lib/repair/repairlegacystorage.php b/tests/lib/repair/repairlegacystorage.php
index e1edf704424..3ae6578f7ec 100644
--- a/tests/lib/repair/repairlegacystorage.php
+++ b/tests/lib/repair/repairlegacystorage.php
@@ -15,6 +15,8 @@ use Test\TestCase;
/**
* Tests for the converting of legacy storages to home storages.
*
+ * @group DB
+ *
* @see \OC\Repair\RepairLegacyStorages
*/
class RepairLegacyStorages extends TestCase {
@@ -97,7 +99,7 @@ class RepairLegacyStorages extends TestCase {
$numRows = $this->connection->executeUpdate($sql, array($storageId));
$this->assertEquals(1, $numRows);
- return \OC_DB::insertid('*PREFIX*storages');
+ return \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*storages');
}
/**
diff --git a/tests/lib/repair/repairmimetypes.php b/tests/lib/repair/repairmimetypes.php
index a0697776e73..a9ebb7bc88a 100644
--- a/tests/lib/repair/repairmimetypes.php
+++ b/tests/lib/repair/repairmimetypes.php
@@ -11,6 +11,8 @@ namespace Test\Repair;
/**
* Tests for the converting of legacy storages to home storages.
*
+ * @group DB
+ *
* @see \OC\Repair\RepairMimeTypes
*/
class RepairMimeTypes extends \Test\TestCase {
@@ -345,6 +347,27 @@ class RepairMimeTypes extends \Test\TestCase {
}
/**
+ * Test renaming the richdocuments additional office mime types
+ */
+ public function testRenameRichDocumentsMimeTypes() {
+ $currentMimeTypes = [
+ ['test.lwp', 'application/octet-stream'],
+ ['test.one', 'application/octet-stream'],
+ ['test.vsd', 'application/octet-stream'],
+ ['test.wpd', 'application/octet-stream'],
+ ];
+
+ $fixedMimeTypes = [
+ ['test.lwp', 'application/vnd.lotus-wordpro'],
+ ['test.one', 'application/msonenote'],
+ ['test.vsd', 'application/vnd.visio'],
+ ['test.wpd', 'application/vnd.wordperfect'],
+ ];
+
+ $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
+ }
+
+ /**
* Test renaming and splitting old office mime types when
* new ones already exist
*/
@@ -466,6 +489,10 @@ class RepairMimeTypes extends \Test\TestCase {
['test.hpp', 'text/x-h'],
['test.rss', 'application/rss+xml'],
['test.rtf', 'text/rtf'],
+ ['test.lwp', 'application/vnd.lotus-wordpro'],
+ ['test.one', 'application/msonenote'],
+ ['test.vsd', 'application/vnd.visio'],
+ ['test.wpd', 'application/vnd.wordperfect'],
];
$fixedMimeTypes = [
@@ -510,6 +537,10 @@ class RepairMimeTypes extends \Test\TestCase {
['test.hpp', 'text/x-h'],
['test.rss', 'application/rss+xml'],
['test.rtf', 'text/rtf'],
+ ['test.lwp', 'application/vnd.lotus-wordpro'],
+ ['test.one', 'application/msonenote'],
+ ['test.vsd', 'application/vnd.visio'],
+ ['test.wpd', 'application/vnd.wordperfect'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
diff --git a/tests/lib/repair/repairsqliteautoincrement.php b/tests/lib/repair/repairsqliteautoincrement.php
index 375319bb64a..6f0c2cb8d28 100644
--- a/tests/lib/repair/repairsqliteautoincrement.php
+++ b/tests/lib/repair/repairsqliteautoincrement.php
@@ -10,6 +10,8 @@ namespace Test\Repair;
/**
* Tests for fixing the SQLite id recycling
+ *
+ * @group DB
*/
class RepairSqliteAutoincrement extends \Test\TestCase {
@@ -36,7 +38,7 @@ class RepairSqliteAutoincrement extends \Test\TestCase {
protected function setUp() {
parent::setUp();
- $this->connection = \OC_DB::getConnection();
+ $this->connection = \OC::$server->getDatabaseConnection();
$this->config = \OC::$server->getConfig();
if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) {
$this->markTestSkipped("Test only relevant on Sqlite");
diff --git a/tests/lib/security/certificatemanager.php b/tests/lib/security/certificatemanager.php
index 092f9efdd18..e9ccea39efe 100644
--- a/tests/lib/security/certificatemanager.php
+++ b/tests/lib/security/certificatemanager.php
@@ -8,7 +8,14 @@
use \OC\Security\CertificateManager;
+/**
+ * Class CertificateManagerTest
+ *
+ * @group DB
+ */
class CertificateManagerTest extends \Test\TestCase {
+ use \Test\Traits\UserTrait;
+ use \Test\Traits\MountProviderTrait;
/** @var CertificateManager */
private $certificateManager;
@@ -19,7 +26,10 @@ class CertificateManagerTest extends \Test\TestCase {
parent::setUp();
$this->username = $this->getUniqueID('', 20);
- OC_User::createUser($this->username, $this->getUniqueID('', 20));
+ $this->createUser($this->username, '');
+
+ $storage = new \OC\Files\Storage\Temporary();
+ $this->registerMount($this->username, $storage, '/' . $this->username . '/');
\OC_Util::tearDownFS();
\OC_User::setUserId('');
@@ -34,7 +44,10 @@ class CertificateManagerTest extends \Test\TestCase {
}
protected function tearDown() {
- \OC_User::deleteUser($this->username);
+ $user = \OC::$server->getUserManager()->get($this->username);
+ if ($user !== null) {
+ $user->delete();
+ }
parent::tearDown();
}
@@ -50,14 +63,14 @@ class CertificateManagerTest extends \Test\TestCase {
$this->assertSame(array(), $this->certificateManager->listCertificates());
// Add some certificates
- $this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
+ $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
$certificateStore = array();
- $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__.'/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
+ $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
$this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates());
// Add another certificates
- $this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate');
- $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate');
+ $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate');
+ $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate');
$this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates());
}
@@ -87,7 +100,7 @@ class CertificateManagerTest extends \Test\TestCase {
* @param string $filename
*/
function testAddDangerousFile($filename) {
- $this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt'), $filename);
+ $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), $filename);
}
function testRemoveDangerousFile() {
@@ -95,7 +108,7 @@ class CertificateManagerTest extends \Test\TestCase {
}
function testRemoveExistingFile() {
- $this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
+ $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
$this->assertTrue($this->certificateManager->removeCertificate('GoodCertificate'));
}
diff --git a/tests/lib/security/credentialsmanager.php b/tests/lib/security/credentialsmanager.php
new file mode 100644
index 00000000000..72f061e05bb
--- /dev/null
+++ b/tests/lib/security/credentialsmanager.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+use \OCP\Security\ICrypto;
+use \OCP\IDBConnection;
+use \OC\Security\CredentialsManager;
+
+class CredentialsManagerTest extends \Test\TestCase {
+
+ /** @var ICrypto */
+ protected $crypto;
+
+ /** @var IDBConnection */
+ protected $dbConnection;
+
+ /** @var CredentialsManager */
+ protected $manager;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->crypto = $this->getMock('\OCP\Security\ICrypto');
+ $this->dbConnection = $this->getMockBuilder('\OC\DB\Connection')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->manager = new CredentialsManager($this->crypto, $this->dbConnection);
+ }
+
+ private function getQeuryResult($row) {
+ $result = $this->getMockBuilder('\Doctrine\DBAL\Driver\Statement')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $result->expects($this->any())
+ ->method('fetch')
+ ->will($this->returnValue($row));
+
+ return $result;
+ }
+
+ public function testStore() {
+ $userId = 'abc';
+ $identifier = 'foo';
+ $credentials = 'bar';
+
+ $this->crypto->expects($this->once())
+ ->method('encrypt')
+ ->with(json_encode($credentials))
+ ->willReturn('baz');
+
+ $this->dbConnection->expects($this->once())
+ ->method('setValues')
+ ->with(CredentialsManager::DB_TABLE,
+ ['user' => $userId, 'identifier' => $identifier],
+ ['credentials' => 'baz']
+ );
+
+ $this->manager->store($userId, $identifier, $credentials);
+ }
+
+ public function testRetrieve() {
+ $userId = 'abc';
+ $identifier = 'foo';
+
+ $this->crypto->expects($this->once())
+ ->method('decrypt')
+ ->with('baz')
+ ->willReturn(json_encode('bar'));
+
+ $qb = $this->getMockBuilder('\OC\DB\QueryBuilder\QueryBuilder')
+ ->setConstructorArgs([$this->dbConnection])
+ ->setMethods(['execute'])
+ ->getMock();
+ $qb->expects($this->once())
+ ->method('execute')
+ ->willReturn($this->getQeuryResult(['credentials' => 'baz']));
+
+ $this->dbConnection->expects($this->once())
+ ->method('getQueryBuilder')
+ ->willReturn($qb);
+
+ $this->manager->retrieve($userId, $identifier);
+ }
+
+}
diff --git a/tests/lib/security/csp/ContentSecurityPolicyManagerTest.php b/tests/lib/security/csp/ContentSecurityPolicyManagerTest.php
new file mode 100644
index 00000000000..975c35d3780
--- /dev/null
+++ b/tests/lib/security/csp/ContentSecurityPolicyManagerTest.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+use OC\Security\CSP\ContentSecurityPolicyManager;
+
+class ContentSecurityPolicyManagerTest extends \Test\TestCase {
+ /** @var ContentSecurityPolicyManager */
+ private $contentSecurityPolicyManager;
+
+ public function setUp() {
+ parent::setUp();
+ $this->contentSecurityPolicyManager = new ContentSecurityPolicyManager();
+ }
+
+ public function testAddDefaultPolicy() {
+ $this->contentSecurityPolicyManager->addDefaultPolicy(new \OCP\AppFramework\Http\ContentSecurityPolicy());
+ }
+
+ public function testGetDefaultPolicyWithPolicies() {
+ $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy();
+ $policy->addAllowedFontDomain('mydomain.com');
+ $policy->addAllowedImageDomain('anotherdomain.de');
+ $this->contentSecurityPolicyManager->addDefaultPolicy($policy);
+ $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy();
+ $policy->addAllowedFontDomain('example.com');
+ $policy->addAllowedImageDomain('example.org');
+ $policy->allowInlineScript(true);
+ $this->contentSecurityPolicyManager->addDefaultPolicy($policy);
+ $policy = new \OCP\AppFramework\Http\EmptyContentSecurityPolicy();
+ $policy->addAllowedChildSrcDomain('childdomain');
+ $policy->addAllowedFontDomain('anotherFontDomain');
+ $this->contentSecurityPolicyManager->addDefaultPolicy($policy);
+
+ $expected = new \OC\Security\CSP\ContentSecurityPolicy();
+ $expected->allowInlineScript(true);
+ $expected->addAllowedFontDomain('mydomain.com');
+ $expected->addAllowedFontDomain('example.com');
+ $expected->addAllowedFontDomain('anotherFontDomain');
+ $expected->addAllowedImageDomain('anotherdomain.de');
+ $expected->addAllowedImageDomain('example.org');
+ $expected->addAllowedChildSrcDomain('childdomain');
+ $expectedStringPolicy = 'default-src \'none\';script-src \'self\' \'unsafe-inline\' \'unsafe-eval\';style-src \'self\' \'unsafe-inline\';img-src \'self\' data: blob: anotherdomain.de example.org;font-src \'self\' mydomain.com example.com anotherFontDomain;connect-src \'self\';media-src \'self\';child-src childdomain';
+
+ $this->assertEquals($expected, $this->contentSecurityPolicyManager->getDefaultPolicy());
+ $this->assertSame($expectedStringPolicy, $this->contentSecurityPolicyManager->getDefaultPolicy()->buildPolicy());
+ }
+
+}
diff --git a/tests/lib/security/csrf/CsrfTokenGeneratorTest.php b/tests/lib/security/csrf/CsrfTokenGeneratorTest.php
new file mode 100644
index 00000000000..be7434f514f
--- /dev/null
+++ b/tests/lib/security/csrf/CsrfTokenGeneratorTest.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+class CsrfTokenGeneratorTest extends \Test\TestCase {
+ /** @var \OCP\Security\ISecureRandom */
+ private $random;
+ /** @var \OC\Security\CSRF\CsrfTokenGenerator */
+ private $csrfTokenGenerator;
+
+ public function setUp() {
+ parent::setUp();
+ $this->random = $this->getMockBuilder('\OCP\Security\ISecureRandom')
+ ->disableOriginalConstructor()->getMock();
+ $this->csrfTokenGenerator = new \OC\Security\CSRF\CsrfTokenGenerator($this->random);
+
+ }
+
+ public function testGenerateTokenWithCustomNumber() {
+ $this->random
+ ->expects($this->once())
+ ->method('generate')
+ ->with(3)
+ ->willReturn('abc');
+ $this->assertSame('abc', $this->csrfTokenGenerator->generateToken(3));
+ }
+
+ public function testGenerateTokenWithDefault() {
+ $this->random
+ ->expects($this->once())
+ ->method('generate')
+ ->with(32)
+ ->willReturn('12345678901234567890123456789012');
+ $this->assertSame('12345678901234567890123456789012', $this->csrfTokenGenerator->generateToken(32));
+ }
+}
+
diff --git a/tests/lib/security/csrf/CsrfTokenManagerTest.php b/tests/lib/security/csrf/CsrfTokenManagerTest.php
new file mode 100644
index 00000000000..145fc03c51e
--- /dev/null
+++ b/tests/lib/security/csrf/CsrfTokenManagerTest.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+class CsrfTokenManagerTest extends \Test\TestCase {
+ /** @var \OC\Security\CSRF\CsrfTokenManager */
+ private $csrfTokenManager;
+ /** @var \OC\Security\CSRF\CsrfTokenGenerator */
+ private $tokenGenerator;
+ /** @var \OC\Security\CSRF\TokenStorage\SessionStorage */
+ private $storageInterface;
+
+ public function setUp() {
+ parent::setUp();
+ $this->tokenGenerator = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenGenerator')
+ ->disableOriginalConstructor()->getMock();
+ $this->storageInterface = $this->getMockBuilder('\OC\Security\CSRF\TokenStorage\SessionStorage')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->csrfTokenManager = new \OC\Security\CSRF\CsrfTokenManager(
+ $this->tokenGenerator,
+ $this->storageInterface
+ );
+ }
+
+ public function testGetTokenWithExistingToken() {
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('hasToken')
+ ->willReturn(true);
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('getToken')
+ ->willReturn('MyExistingToken');
+
+ $expected = new \OC\Security\CSRF\CsrfToken('MyExistingToken');
+ $this->assertEquals($expected, $this->csrfTokenManager->getToken());
+ }
+
+ public function testGetTokenWithoutExistingToken() {
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('hasToken')
+ ->willReturn(false);
+ $this->tokenGenerator
+ ->expects($this->once())
+ ->method('generateToken')
+ ->willReturn('MyNewToken');
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('setToken')
+ ->with('MyNewToken');
+
+ $expected = new \OC\Security\CSRF\CsrfToken('MyNewToken');
+ $this->assertEquals($expected, $this->csrfTokenManager->getToken());
+ }
+
+ public function testRefreshToken() {
+ $this->tokenGenerator
+ ->expects($this->once())
+ ->method('generateToken')
+ ->willReturn('MyNewToken');
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('setToken')
+ ->with('MyNewToken');
+
+ $expected = new \OC\Security\CSRF\CsrfToken('MyNewToken');
+ $this->assertEquals($expected, $this->csrfTokenManager->refreshToken());
+ }
+
+ public function testRemoveToken() {
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('removeToken');
+
+ $this->csrfTokenManager->removeToken();
+ }
+
+ public function testIsTokenValidWithoutToken() {
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('hasToken')
+ ->willReturn(false);
+ $token = new \OC\Security\CSRF\CsrfToken('Token');
+
+ $this->assertSame(false, $this->csrfTokenManager->isTokenValid($token));
+ }
+
+ public function testIsTokenValidWithWrongToken() {
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('hasToken')
+ ->willReturn(true);
+ $token = new \OC\Security\CSRF\CsrfToken('Token');
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('getToken')
+ ->willReturn('MyToken');
+
+ $this->assertSame(false, $this->csrfTokenManager->isTokenValid($token));
+ }
+
+ public function testIsTokenValidWithValidToken() {
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('hasToken')
+ ->willReturn(true);
+ $token = new \OC\Security\CSRF\CsrfToken('XlQhHjgWCgBXAEI0Khl+IQEiCXN2LUcDHAQTQAc1HQs=:qgkUlg8l3m8WnkOG4XM9Az33pAt1vSVMx4hcJFsxdqc=');
+ $this->storageInterface
+ ->expects($this->once())
+ ->method('getToken')
+ ->willReturn('/3JKTq2ldmzcDr1f5zDJ7Wt0lEgqqfKF');
+
+ $this->assertSame(true, $this->csrfTokenManager->isTokenValid($token));
+ }
+}
diff --git a/tests/lib/security/csrf/CsrfTokenTest.php b/tests/lib/security/csrf/CsrfTokenTest.php
new file mode 100644
index 00000000000..62e6ad112e7
--- /dev/null
+++ b/tests/lib/security/csrf/CsrfTokenTest.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+class CsrfTokenTest extends \Test\TestCase {
+ public function testGetEncryptedValue() {
+ $csrfToken = new \OC\Security\CSRF\CsrfToken('MyCsrfToken');
+ $this->assertSame(33, strlen($csrfToken->getEncryptedValue()));
+ $this->assertSame(':', $csrfToken->getEncryptedValue()[16]);
+ }
+
+ public function testGetDecryptedValue() {
+ $csrfToken = new \OC\Security\CSRF\CsrfToken('XlQhHjgWCgBXAEI0Khl+IQEiCXN2LUcDHAQTQAc1HQs=:qgkUlg8l3m8WnkOG4XM9Az33pAt1vSVMx4hcJFsxdqc=');
+ $this->assertSame('/3JKTq2ldmzcDr1f5zDJ7Wt0lEgqqfKF', $csrfToken->getDecryptedValue());
+ }
+}
diff --git a/tests/lib/security/csrf/tokenstorage/SessionStorageTest.php b/tests/lib/security/csrf/tokenstorage/SessionStorageTest.php
new file mode 100644
index 00000000000..3a83f6a8c00
--- /dev/null
+++ b/tests/lib/security/csrf/tokenstorage/SessionStorageTest.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+class SessionStorageTest extends \Test\TestCase {
+ /** @var \OCP\ISession */
+ private $session;
+ /** @var \OC\Security\CSRF\TokenStorage\SessionStorage */
+ private $sessionStorage;
+
+ public function setUp() {
+ parent::setUp();
+ $this->session = $this->getMockBuilder('\OCP\ISession')
+ ->disableOriginalConstructor()->getMock();
+ $this->sessionStorage = new \OC\Security\CSRF\TokenStorage\SessionStorage($this->session);
+ }
+
+ /**
+ * @return array
+ */
+ public function getTokenDataProvider() {
+ return [
+ [
+ '',
+ ],
+ [
+ null,
+ ],
+ ];
+ }
+
+ /**
+ * @param string $token
+ * @dataProvider getTokenDataProvider
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Session does not contain a requesttoken
+ */
+ public function testGetTokenWithEmptyToken($token) {
+ $this->session
+ ->expects($this->once())
+ ->method('get')
+ ->with('requesttoken')
+ ->willReturn($token);
+ $this->sessionStorage->getToken();
+ }
+
+ public function testGetTokenWithValidToken() {
+ $this->session
+ ->expects($this->once())
+ ->method('get')
+ ->with('requesttoken')
+ ->willReturn('MyFancyCsrfToken');
+ $this->assertSame('MyFancyCsrfToken', $this->sessionStorage->getToken());
+ }
+
+ public function testSetToken() {
+ $this->session
+ ->expects($this->once())
+ ->method('set')
+ ->with('requesttoken', 'TokenToSet');
+ $this->sessionStorage->setToken('TokenToSet');
+ }
+
+ public function testRemoveToken() {
+ $this->session
+ ->expects($this->once())
+ ->method('remove')
+ ->with('requesttoken');
+ $this->sessionStorage->removeToken();
+ }
+
+ public function testHasTokenWithExistingToken() {
+ $this->session
+ ->expects($this->once())
+ ->method('exists')
+ ->with('requesttoken')
+ ->willReturn(true);
+ $this->assertSame(true, $this->sessionStorage->hasToken());
+ }
+
+ public function testHasTokenWithoutExistingToken() {
+ $this->session
+ ->expects($this->once())
+ ->method('exists')
+ ->with('requesttoken')
+ ->willReturn(false);
+ $this->assertSame(false, $this->sessionStorage->hasToken());
+ }
+}
diff --git a/tests/lib/security/securerandom.php b/tests/lib/security/securerandom.php
index d9bbd0e71e5..526066d92ee 100644
--- a/tests/lib/security/securerandom.php
+++ b/tests/lib/security/securerandom.php
@@ -42,7 +42,7 @@ class SecureRandomTest extends \Test\TestCase {
* @dataProvider stringGenerationProvider
*/
function testGetLowStrengthGeneratorLength($length, $expectedLength) {
- $generator = $this->rng->getLowStrengthGenerator();
+ $generator = $this->rng;
$this->assertEquals($expectedLength, strlen($generator->generate($length)));
}
@@ -51,24 +51,23 @@ class SecureRandomTest extends \Test\TestCase {
* @dataProvider stringGenerationProvider
*/
function testMediumLowStrengthGeneratorLength($length, $expectedLength) {
- $generator = $this->rng->getMediumStrengthGenerator();
+ $generator = $this->rng;
$this->assertEquals($expectedLength, strlen($generator->generate($length)));
}
/**
- * @expectedException \Exception
- * @expectedExceptionMessage Generator is not initialized
+ * @dataProvider stringGenerationProvider
*/
- function testUninitializedGenerate() {
- $this->rng->generate(30);
+ function testUninitializedGenerate($length, $expectedLength) {
+ $this->assertEquals($expectedLength, strlen($this->rng->generate($length)));
}
/**
* @dataProvider charCombinations
*/
public function testScheme($charName, $chars) {
- $generator = $this->rng->getMediumStrengthGenerator();
+ $generator = $this->rng;
$scheme = constant('OCP\Security\ISecureRandom::' . $charName);
$randomString = $generator->generate(100, $scheme);
$matchesRegex = preg_match('/^'.$chars.'+$/', $randomString);
diff --git a/tests/lib/security/stringutils.php b/tests/lib/security/stringutils.php
deleted file mode 100644
index 060315debb4..00000000000
--- a/tests/lib/security/stringutils.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-/**
- * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-use \OC\Security\StringUtils;
-
-class StringUtilsTest extends \Test\TestCase {
-
- public function dataProvider()
- {
- return array(
- array('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.'),
- array('', ''),
- array('我看这本书。 我看這本書', '我看这本书。 我看這本書'),
- array('GpKY9fSnWNJbES99zVGvA', 'GpKY9fSnWNJbES99zVGvA')
- );
- }
-
- /**
- * @dataProvider dataProvider
- */
- function testWrongEquals($string) {
- $this->assertFalse(StringUtils::equals($string, 'A Completely Wrong String'));
- $this->assertFalse(StringUtils::equals($string, null));
- }
-
- /**
- * @dataProvider dataProvider
- */
- function testTrueEquals($string, $expected) {
- $this->assertTrue(StringUtils::equals($string, $expected));
- }
-
-}
diff --git a/tests/lib/security/trusteddomainhelper.php b/tests/lib/security/trusteddomainhelper.php
index c8d5ffa587b..52a8f1be630 100644
--- a/tests/lib/security/trusteddomainhelper.php
+++ b/tests/lib/security/trusteddomainhelper.php
@@ -64,6 +64,8 @@ class TrustedDomainHelperTest extends \Test\TestCase {
// do not trust invalid localhosts
[$trustedHostTestList, 'localhost:1:2', false],
[$trustedHostTestList, 'localhost: evil.host', false],
+ // do not trust casting
+ [[1], '1', false],
];
}
diff --git a/tests/lib/server.php b/tests/lib/server.php
index 96a476bd4d1..d13f9be0c9e 100644
--- a/tests/lib/server.php
+++ b/tests/lib/server.php
@@ -24,6 +24,13 @@
namespace Test;
+/**
+ * Class Server
+ *
+ * @group DB
+ *
+ * @package Test
+ */
class Server extends \Test\TestCase {
/** @var \OC\Server */
protected $server;
@@ -31,7 +38,8 @@ class Server extends \Test\TestCase {
public function setUp() {
parent::setUp();
- $this->server = new \OC\Server('');
+ $config = new \OC\Config(\OC::$configDir);
+ $this->server = new \OC\Server('', $config);
}
public function dataTestQuery() {
@@ -54,9 +62,12 @@ class Server extends \Test\TestCase {
['CapabilitiesManager', '\OC\CapabilitiesManager'],
['ContactsManager', '\OC\ContactsManager'],
['ContactsManager', '\OCP\Contacts\IManager'],
+ ['ContentSecurityPolicyManager', '\OC\Security\CSP\ContentSecurityPolicyManager'],
+ ['CommentsManager', '\OCP\Comments\ICommentsManager'],
['Crypto', '\OC\Security\Crypto'],
['Crypto', '\OCP\Security\ICrypto'],
['CryptoWrapper', '\OC\Session\CryptoWrapper'],
+ ['CsrfTokenManager', '\OC\Security\CSRF\CsrfTokenManager'],
['DatabaseConnection', '\OC\DB\Connection'],
['DatabaseConnection', '\OCP\IDBConnection'],
@@ -85,6 +96,8 @@ class Server extends \Test\TestCase {
['HttpClientService', '\OCP\Http\Client\IClientService'],
['IniWrapper', '\bantu\IniGetWrapper\IniGetWrapper'],
+ ['MimeTypeDetector', '\OCP\Files\IMimeTypeDetector'],
+ ['MimeTypeDetector', '\OC\Files\Type\Detection'],
['JobList', '\OC\BackgroundJob\JobList'],
['JobList', '\OCP\BackgroundJob\IJobList'],
@@ -105,7 +118,7 @@ class Server extends \Test\TestCase {
['NavigationManager', '\OC\NavigationManager'],
['NavigationManager', '\OCP\INavigationManager'],
['NotificationManager', '\OC\Notification\Manager'],
- ['NotificationManager', '\OC\Notification\IManager'],
+ ['NotificationManager', '\OCP\Notification\IManager'],
['UserCache', '\OC\Cache\File'],
['UserCache', '\OCP\ICache'],
@@ -128,6 +141,8 @@ class Server extends \Test\TestCase {
['Search', '\OCP\ISearch'],
['SecureRandom', '\OC\Security\SecureRandom'],
['SecureRandom', '\OCP\Security\ISecureRandom'],
+ ['ShareManager', '\OC\Share20\Manager'],
+ ['ShareManager', '\OCP\Share\IManager'],
['SystemConfig', '\OC\SystemConfig'],
['URLGenerator', '\OC\URLGenerator'],
@@ -144,6 +159,9 @@ class Server extends \Test\TestCase {
['TempManager', '\OC\TempManager'],
['TempManager', '\OCP\ITempManager'],
['TrustedDomainHelper', '\OC\Security\TrustedDomainHelper'],
+
+ ['SystemTagManager', '\OCP\SystemTag\ISystemTagManager'],
+ ['SystemTagObjectMapper', '\OCP\SystemTag\ISystemTagObjectMapper'],
];
}
@@ -166,4 +184,16 @@ class Server extends \Test\TestCase {
$this->assertInstanceOf('\OC_EventSource', $this->server->createEventSource(), 'service returned by "createEventSource" did not return the right class');
$this->assertInstanceOf('\OCP\IEventSource', $this->server->createEventSource(), 'service returned by "createEventSource" did not return the right class');
}
+
+ public function testOverwriteDefaultCommentsManager() {
+ $config = $this->server->getConfig();
+ $defaultManagerFactory = $config->getSystemValue('comments.managerFactory', '\OC\Comments\ManagerFactory');
+
+ $config->setSystemValue('comments.managerFactory', '\Test\Comments\FakeFactory');
+
+ $manager = $this->server->getCommentsManager();
+ $this->assertInstanceOf('\OCP\Comments\ICommentsManager', $manager);
+
+ $config->setSystemValue('comments.managerFactory', $defaultManagerFactory);
+ }
}
diff --git a/tests/lib/setup.php b/tests/lib/setup.php
index 72c84520056..bc78c14008f 100644
--- a/tests/lib/setup.php
+++ b/tests/lib/setup.php
@@ -130,17 +130,4 @@ class Test_OC_Setup extends \Test\TestCase {
->will($this->returnValue('NotAnArray'));
$this->setupClass->getSupportedDatabases();
}
-
- /**
- * This is actual more an integration test whether the version parameter in the .htaccess
- * was updated as well when the version has been incremented.
- * If it hasn't this test will fail.
- */
- public function testHtaccessIsCurrent() {
- $result = self::invokePrivate(
- $this->setupClass,
- 'isCurrentHtaccess'
- );
- $this->assertTrue($result);
- }
}
diff --git a/tests/lib/share/MailNotificationsTest.php b/tests/lib/share/MailNotificationsTest.php
index c74fe406db1..66bec8653fb 100644
--- a/tests/lib/share/MailNotificationsTest.php
+++ b/tests/lib/share/MailNotificationsTest.php
@@ -20,8 +20,8 @@
*/
use OC\Share\MailNotifications;
-use OCP\IConfig;
use OCP\IL10N;
+use OCP\IUser;
use OCP\Mail\IMailer;
use OCP\ILogger;
use OCP\Defaults;
@@ -30,23 +30,21 @@ use OCP\Defaults;
* Class MailNotificationsTest
*/
class MailNotificationsTest extends \Test\TestCase {
- /** @var IConfig */
- private $config;
/** @var IL10N */
private $l10n;
- /** @var IMailer */
+ /** @var IMailer | PHPUnit_Framework_MockObject_MockObject */
private $mailer;
/** @var ILogger */
private $logger;
- /** @var Defaults */
+ /** @var Defaults | PHPUnit_Framework_MockObject_MockObject */
private $defaults;
+ /** @var IUser | PHPUnit_Framework_MockObject_MockObject */
+ private $user;
public function setUp() {
parent::setUp();
- $this->config = $this->getMockBuilder('\OCP\IConfig')
- ->disableOriginalConstructor()->getMock();
$this->l10n = $this->getMockBuilder('\OCP\IL10N')
->disableOriginalConstructor()->getMock();
$this->mailer = $this->getMockBuilder('\OCP\Mail\IMailer')
@@ -54,13 +52,30 @@ class MailNotificationsTest extends \Test\TestCase {
$this->logger = $this->getMockBuilder('\OCP\ILogger')
->disableOriginalConstructor()->getMock();
$this->defaults = $this->getMockBuilder('\OCP\Defaults')
- ->disableOriginalConstructor()->getMock();
+ ->disableOriginalConstructor()->getMock();
+ $this->user = $this->getMockBuilder('\OCP\IUser')
+ ->disableOriginalConstructor()->getMock();
$this->l10n->expects($this->any())
->method('t')
->will($this->returnCallback(function($text, $parameters = array()) {
return vsprintf($text, $parameters);
}));
+
+ $this->defaults
+ ->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue('UnitTestCloud'));
+
+ $this->user
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->willReturn('sharer@owncloud.com');
+ $this->user
+ ->expects($this->once())
+ ->method('getDisplayName')
+ ->willReturn('TestUser');
+
}
public function testSendLinkShareMailWithoutReplyTo() {
@@ -96,20 +111,8 @@ class MailNotificationsTest extends \Test\TestCase {
->with($message)
->will($this->returnValue([]));
- $this->defaults
- ->expects($this->once())
- ->method('getName')
- ->will($this->returnValue('UnitTestCloud'));
-
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('TestUser', 'settings', 'email', null)
- ->will($this->returnValue('sharer@owncloud.com'));
-
$mailNotifications = new MailNotifications(
- 'TestUser',
- $this->config,
+ $this->user,
$this->l10n,
$this->mailer,
$this->logger,
@@ -119,7 +122,23 @@ class MailNotificationsTest extends \Test\TestCase {
$this->assertSame([], $mailNotifications->sendLinkShareMail('lukas@owncloud.com', 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600));
}
- public function testSendLinkShareMailWithReplyTo() {
+ public function dataSendLinkShareMailWithReplyTo() {
+ return [
+ ['lukas@owncloud.com', ['lukas@owncloud.com']],
+ ['lukas@owncloud.com nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']],
+ ['lukas@owncloud.com,nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']],
+ ['lukas@owncloud.com, nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']],
+ ['lukas@owncloud.com;nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']],
+ ['lukas@owncloud.com; nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']],
+ ];
+ }
+
+ /**
+ * @dataProvider dataSendLinkShareMailWithReplyTo
+ * @param string $to
+ * @param array $expectedTo
+ */
+ public function testSendLinkShareMailWithReplyTo($to, array $expectedTo) {
$message = $this->getMockBuilder('\OC\Mail\Message')
->disableOriginalConstructor()->getMock();
@@ -130,7 +149,7 @@ class MailNotificationsTest extends \Test\TestCase {
$message
->expects($this->once())
->method('setTo')
- ->with(['lukas@owncloud.com']);
+ ->with($expectedTo);
$message
->expects($this->once())
->method('setHtmlBody');
@@ -156,75 +175,21 @@ class MailNotificationsTest extends \Test\TestCase {
->with($message)
->will($this->returnValue([]));
- $this->defaults
- ->expects($this->once())
- ->method('getName')
- ->will($this->returnValue('UnitTestCloud'));
-
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('TestUser', 'settings', 'email', null)
- ->will($this->returnValue('sharer@owncloud.com'));
-
$mailNotifications = new MailNotifications(
- 'TestUser',
- $this->config,
+ $this->user,
$this->l10n,
$this->mailer,
$this->logger,
$this->defaults
);
- $this->assertSame([], $mailNotifications->sendLinkShareMail('lukas@owncloud.com', 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600));
+ $this->assertSame([], $mailNotifications->sendLinkShareMail($to, 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600));
}
public function testSendLinkShareMailException() {
- $message = $this->getMockBuilder('\OC\Mail\Message')
- ->disableOriginalConstructor()->getMock();
-
- $message
- ->expects($this->once())
- ->method('setSubject')
- ->with('TestUser shared »MyFile« with you');
- $message
- ->expects($this->once())
- ->method('setTo')
- ->with(['lukas@owncloud.com']);
- $message
- ->expects($this->once())
- ->method('setHtmlBody');
- $message
- ->expects($this->once())
- ->method('setPlainBody');
- $message
- ->expects($this->once())
- ->method('setFrom')
- ->with([\OCP\Util::getDefaultEmailAddress('sharing-noreply') => 'TestUser via UnitTestCloud']);
-
- $this->mailer
- ->expects($this->once())
- ->method('createMessage')
- ->will($this->returnValue($message));
- $this->mailer
- ->expects($this->once())
- ->method('send')
- ->with($message)
- ->will($this->throwException(new Exception('Some Exception Message')));
-
- $this->defaults
- ->expects($this->once())
- ->method('getName')
- ->will($this->returnValue('UnitTestCloud'));
-
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('TestUser', 'settings', 'email', null)
- ->will($this->returnValue('sharer@owncloud.com'));
+ $this->setupMailerMock('TestUser shared »MyFile« with you', ['lukas@owncloud.com']);
$mailNotifications = new MailNotifications(
- 'TestUser',
- $this->config,
+ $this->user,
$this->l10n,
$this->mailer,
$this->logger,
@@ -234,4 +199,76 @@ class MailNotificationsTest extends \Test\TestCase {
$this->assertSame(['lukas@owncloud.com'], $mailNotifications->sendLinkShareMail('lukas@owncloud.com', 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600));
}
+ public function testSendInternalShareMail() {
+ $this->setupMailerMock('TestUser shared »welcome.txt« with you', ['recipient@owncloud.com' => 'Recipient'], false);
+
+ /** @var MailNotifications | PHPUnit_Framework_MockObject_MockObject $mailNotifications */
+ $mailNotifications = $this->getMock('OC\Share\MailNotifications',['getItemSharedWithUser'], [
+ $this->user,
+ $this->l10n,
+ $this->mailer,
+ $this->logger,
+ $this->defaults]);
+
+ $mailNotifications->method('getItemSharedWithUser')
+ ->withAnyParameters()
+ ->willReturn([
+ ['file_target' => '/welcome.txt']
+ ]);
+
+ $recipient = $this->getMockBuilder('\OCP\IUser')
+ ->disableOriginalConstructor()->getMock();
+ $recipient
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->willReturn('recipient@owncloud.com');
+ $recipient
+ ->expects($this->once())
+ ->method('getDisplayName')
+ ->willReturn('Recipient');
+
+ $recipientList = [$recipient];
+ $result = $mailNotifications->sendInternalShareMail($recipientList, '3', 'file');
+ $this->assertSame([], $result);
+
+ }
+
+ /**
+ * @param string $subject
+ */
+ protected function setupMailerMock($subject, $to, $exceptionOnSend = true) {
+ $message = $this->getMockBuilder('\OC\Mail\Message')
+ ->disableOriginalConstructor()->getMock();
+
+ $message
+ ->expects($this->once())
+ ->method('setSubject')
+ ->with($subject);
+ $message
+ ->expects($this->once())
+ ->method('setTo')
+ ->with($to);
+ $message
+ ->expects($this->once())
+ ->method('setHtmlBody');
+ $message
+ ->expects($this->once())
+ ->method('setPlainBody');
+ $message
+ ->expects($this->once())
+ ->method('setFrom')
+ ->with([\OCP\Util::getDefaultEmailAddress('sharing-noreply') => 'TestUser via UnitTestCloud']);
+
+ $this->mailer
+ ->expects($this->once())
+ ->method('createMessage')
+ ->will($this->returnValue($message));
+ if ($exceptionOnSend) {
+ $this->mailer
+ ->expects($this->once())
+ ->method('send')
+ ->with($message)
+ ->will($this->throwException(new Exception('Some Exception Message')));
+ }
+ }
}
diff --git a/tests/lib/share/helper.php b/tests/lib/share/helper.php
index e37a3db8bf0..eaa29c8cb90 100644
--- a/tests/lib/share/helper.php
+++ b/tests/lib/share/helper.php
@@ -19,6 +19,10 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * @group DB
+ * Class Test_Share_Helper
+ */
class Test_Share_Helper extends \Test\TestCase {
public function expireDateProvider() {
@@ -121,4 +125,37 @@ class Test_Share_Helper extends \Test\TestCase {
public function testSplitUserRemoteError($id) {
\OC\Share\Helper::splitUserRemote($id);
}
+
+ /**
+ * @dataProvider dataTestCompareServerAddresses
+ *
+ * @param string $server1
+ * @param string $server2
+ * @param bool $expected
+ */
+ public function testIsSameUserOnSameServer($user1, $server1, $user2, $server2, $expected) {
+ $this->assertSame($expected,
+ \OC\Share\Helper::isSameUserOnSameServer($user1, $server1, $user2, $server2)
+ );
+ }
+
+ public function dataTestCompareServerAddresses() {
+ return [
+ ['user1', 'http://server1', 'user1', 'http://server1', true],
+ ['user1', 'https://server1', 'user1', 'http://server1', true],
+ ['user1', 'http://serVer1', 'user1', 'http://server1', true],
+ ['user1', 'http://server1/', 'user1', 'http://server1', true],
+ ['user1', 'server1', 'user1', 'http://server1', true],
+ ['user1', 'http://server1', 'user1', 'http://server2', false],
+ ['user1', 'https://server1', 'user1', 'http://server2', false],
+ ['user1', 'http://serVer1', 'user1', 'http://serer2', false],
+ ['user1', 'http://server1/', 'user1', 'http://server2', false],
+ ['user1', 'server1', 'user1', 'http://server2', false],
+ ['user1', 'http://server1', 'user2', 'http://server1', false],
+ ['user1', 'https://server1', 'user2', 'http://server1', false],
+ ['user1', 'http://serVer1', 'user2', 'http://server1', false],
+ ['user1', 'http://server1/', 'user2', 'http://server1', false],
+ ['user1', 'server1', 'user2', 'http://server1', false],
+ ];
+ }
}
diff --git a/tests/lib/share/hooktests.php b/tests/lib/share/hooktests.php
index f980baf3574..7e6aaa259f2 100644
--- a/tests/lib/share/hooktests.php
+++ b/tests/lib/share/hooktests.php
@@ -25,6 +25,13 @@ namespace OC\Tests\Share;
use Test\TestCase;
+/**
+ * Class HookTests
+ *
+ * @group DB
+ *
+ * @package OC\Tests\Share
+ */
class HookTests extends TestCase {
protected function setUp() {
diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php
index e8127aefe8e..5162a03f367 100644
--- a/tests/lib/share/share.php
+++ b/tests/lib/share/share.php
@@ -19,6 +19,11 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * Class Test_Share
+ *
+ * @group DB
+ */
class Test_Share extends \Test\TestCase {
protected $itemType;
@@ -49,13 +54,13 @@ class Test_Share extends \Test\TestCase {
$this->user5 = $this->getUniqueID('user5_');
$this->user6 = $this->getUniqueID('user6_');
$this->groupAndUser = $this->getUniqueID('groupAndUser_');
- OC_User::createUser($this->user1, 'pass');
- OC_User::createUser($this->user2, 'pass');
- OC_User::createUser($this->user3, 'pass');
- OC_User::createUser($this->user4, 'pass');
- OC_User::createUser($this->user5, 'pass');
- OC_User::createUser($this->user6, 'pass'); // no group
- OC_User::createUser($this->groupAndUser, 'pass');
+ \OC::$server->getUserManager()->createUser($this->user1, 'pass');
+ \OC::$server->getUserManager()->createUser($this->user2, 'pass');
+ \OC::$server->getUserManager()->createUser($this->user3, 'pass');
+ \OC::$server->getUserManager()->createUser($this->user4, 'pass');
+ \OC::$server->getUserManager()->createUser($this->user5, 'pass');
+ \OC::$server->getUserManager()->createUser($this->user6, 'pass'); // no group
+ \OC::$server->getUserManager()->createUser($this->groupAndUser, 'pass');
OC_User::setUserId($this->user1);
OC_Group::clearBackends();
OC_Group::useBackend(new OC_Group_Dummy);
@@ -89,13 +94,20 @@ class Test_Share extends \Test\TestCase {
$query->execute(array('test'));
\OC::$server->getAppConfig()->setValue('core', 'shareapi_allow_resharing', $this->resharing);
- OC_User::deleteUser($this->user1);
- OC_User::deleteUser($this->user2);
- OC_User::deleteUser($this->user3);
- OC_User::deleteUser($this->user4);
- OC_User::deleteUser($this->user5);
- OC_User::deleteUser($this->user6);
- OC_User::deleteUser($this->groupAndUser);
+ $user = \OC::$server->getUserManager()->get($this->user1);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get($this->user2);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get($this->user3);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get($this->user4);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get($this->user5);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get($this->user6);
+ if ($user !== null) { $user->delete(); }
+ $user = \OC::$server->getUserManager()->get($this->groupAndUser);
+ if ($user !== null) { $user->delete(); }
OC_Group::deleteGroup($this->group1);
OC_Group::deleteGroup($this->group2);
@@ -370,7 +382,8 @@ class Test_Share extends \Test\TestCase {
// Remove user
OC_User::setUserId($this->user1);
- OC_User::deleteUser($this->user1);
+ $user = \OC::$server->getUserManager()->get($this->user1);
+ if ($user !== null) { $user->delete(); }
OC_User::setUserId($this->user2);
$this->assertEquals(array('test1.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
}
diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php
index f8b6f98be7c..60024989681 100644
--- a/tests/lib/share20/defaultshareprovidertest.php
+++ b/tests/lib/share20/defaultshareprovidertest.php
@@ -20,25 +20,33 @@
*/
namespace Test\Share20;
+use OC\Share20\Exception\ProviderException;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IUserManager;
use OCP\IGroupManager;
-use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
use OC\Share20\DefaultShareProvider;
+/**
+ * Class DefaultShareProviderTest
+ *
+ * @package Test\Share20
+ * @group DB
+ */
class DefaultShareProviderTest extends \Test\TestCase {
/** @var IDBConnection */
protected $dbConn;
- /** @var IUserManager */
+ /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */
protected $userManager;
- /** @var IGroupManager */
+ /** @var IGroupManager | \PHPUnit_Framework_MockObject_MockObject */
protected $groupManager;
- /** @var Folder */
- protected $userFolder;
+ /** @var IRootFolder | \PHPUnit_Framework_MockObject_MockObject */
+ protected $rootFolder;
/** @var DefaultShareProvider */
protected $provider;
@@ -47,7 +55,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->dbConn = \OC::$server->getDatabaseConnection();
$this->userManager = $this->getMock('OCP\IUserManager');
$this->groupManager = $this->getMock('OCP\IGroupManager');
- $this->userFolder = $this->getMock('OCP\Files\Folder');
+ $this->rootFolder = $this->getMock('OCP\Files\IRootFolder');
//Empty share table
$this->dbConn->getQueryBuilder()->delete('share')->execute();
@@ -56,7 +64,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->dbConn,
$this->userManager,
$this->groupManager,
- $this->userFolder
+ $this->rootFolder
);
}
@@ -65,7 +73,44 @@ class DefaultShareProviderTest extends \Test\TestCase {
}
/**
- * @expectedException OC\Share20\Exception\ShareNotFound
+ * @param int $shareType
+ * @param string $sharedWith
+ * @param string $sharedBy
+ * @param string $shareOwner
+ * @param string $itemType
+ * @param int $fileSource
+ * @param string $fileTarget
+ * @param int $permissions
+ * @param $token
+ * @param $expiration
+ * @return int
+ */
+ private function addShareToDB($shareType, $sharedWith, $sharedBy, $shareOwner,
+ $itemType, $fileSource, $fileTarget, $permissions, $token, $expiration,
+ $parent = null) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share');
+
+ if ($shareType) $qb->setValue('share_type', $qb->expr()->literal($shareType));
+ if ($sharedWith) $qb->setValue('share_with', $qb->expr()->literal($sharedWith));
+ if ($sharedBy) $qb->setValue('uid_initiator', $qb->expr()->literal($sharedBy));
+ if ($shareOwner) $qb->setValue('uid_owner', $qb->expr()->literal($shareOwner));
+ if ($itemType) $qb->setValue('item_type', $qb->expr()->literal($itemType));
+ if ($fileSource) $qb->setValue('file_source', $qb->expr()->literal($fileSource));
+ if ($fileTarget) $qb->setValue('file_target', $qb->expr()->literal($fileTarget));
+ if ($permissions) $qb->setValue('permissions', $qb->expr()->literal($permissions));
+ if ($token) $qb->setValue('token', $qb->expr()->literal($token));
+ if ($expiration) $qb->setValue('expiration', $qb->createNamedParameter($expiration, IQueryBuilder::PARAM_DATE));
+ if ($parent) $qb->setValue('parent', $qb->expr()->literal($parent));
+
+ $this->assertEquals(1, $qb->execute());
+ return$qb->getLastInsertId();
+ }
+
+
+
+ /**
+ * @expectedException \OCP\Share\Exceptions\ShareNotFound
*/
public function testGetShareByIdNotExist() {
$this->provider->getShareById(1);
@@ -86,52 +131,119 @@ class DefaultShareProviderTest extends \Test\TestCase {
]);
$qb->execute();
- // Get the id
- $qb = $this->dbConn->getQueryBuilder();
- $cursor = $qb->select('id')
- ->from('share')
- ->setMaxResults(1)
- ->orderBy('id', 'DESC')
- ->execute();
- $id = $cursor->fetch();
- $id = $id['id'];
- $cursor->closeCursor();
-
- $storage = $this->getMock('OC\Files\Storage\Storage');
- $storage
- ->expects($this->once())
- ->method('getOwner')
- ->willReturn('shareOwner');
- $path = $this->getMock('OCP\Files\File');
- $path
- ->expects($this->once())
- ->method('getStorage')
- ->wilLReturn($storage);
- $this->userFolder
- ->expects($this->once())
- ->method('getById')
- ->with(42)
- ->willReturn([$path]);
+ $id = $qb->getLastInsertId();
$sharedWith = $this->getMock('OCP\IUser');
$sharedBy = $this->getMock('OCP\IUser');
+ $sharedBy->method('getUID')->willReturn('sharedBy');
$shareOwner = $this->getMock('OCP\IUser');
- $this->userManager
- ->method('get')
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+
+ $sharedByPath = $this->getMock('\OCP\Files\File');
+ $ownerPath = $this->getMock('\OCP\Files\File');
+
+ $sharedByPath->method('getOwner')->willReturn($shareOwner);
+
+ $sharedByFolder = $this->getMock('\OCP\Files\Folder');
+ $sharedByFolder->method('getById')->with(42)->willReturn([$sharedByPath]);
+
+ $shareOwnerFolder = $this->getMock('\OCP\Files\Folder');
+ $shareOwnerFolder->method('getById')->with(42)->willReturn([$ownerPath]);
+
+ $this->rootFolder
+ ->method('getUserFolder')
->will($this->returnValueMap([
- ['sharedWith', $sharedWith],
- ['sharedBy', $sharedBy],
- ['shareOwner', $shareOwner],
+ ['sharedBy', $sharedByFolder],
+ ['shareOwner', $shareOwnerFolder],
]));
$share = $this->provider->getShareById($id);
$this->assertEquals($id, $share->getId());
$this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
- $this->assertEquals($sharedWith, $share->getSharedWith());
- $this->assertEquals($sharedBy, $share->getSharedBy());
- $this->assertEquals($shareOwner, $share->getShareOwner());
- $this->assertEquals($path, $share->getPath());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals('sharedBy', $share->getSharedBy());
+ $this->assertEquals('shareOwner', $share->getShareOwner());
+ $this->assertEquals($ownerPath, $share->getNode());
+ $this->assertEquals(13, $share->getPermissions());
+ $this->assertEquals(null, $share->getToken());
+ $this->assertEquals(null, $share->getExpirationDate());
+ $this->assertEquals('myTarget', $share->getTarget());
+ }
+
+ public function testGetShareByIdLazy() {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $qb->execute();
+
+ $id = $qb->getLastInsertId();
+
+ $this->rootFolder->expects($this->never())->method('getUserFolder');
+
+ $share = $this->provider->getShareById($id);
+
+ // We do not fetch the node so the rootfolder is never called.
+
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals('sharedBy', $share->getSharedBy());
+ $this->assertEquals('shareOwner', $share->getShareOwner());
+ $this->assertEquals(13, $share->getPermissions());
+ $this->assertEquals(null, $share->getToken());
+ $this->assertEquals(null, $share->getExpirationDate());
+ $this->assertEquals('myTarget', $share->getTarget());
+ }
+
+ public function testGetShareByIdLazy2() {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $qb->execute();
+
+ $id = $qb->getLastInsertId();
+
+ $ownerPath = $this->getMock('\OCP\Files\File');
+
+ $shareOwnerFolder = $this->getMock('\OCP\Files\Folder');
+ $shareOwnerFolder->method('getById')->with(42)->willReturn([$ownerPath]);
+
+ $this->rootFolder
+ ->method('getUserFolder')
+ ->with('shareOwner')
+ ->willReturn($shareOwnerFolder);
+
+ $share = $this->provider->getShareById($id);
+
+ // We fetch the node so the root folder is eventually called
+
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals('sharedBy', $share->getSharedBy());
+ $this->assertEquals('shareOwner', $share->getShareOwner());
+ $this->assertEquals($ownerPath, $share->getNode());
$this->assertEquals(13, $share->getPermissions());
$this->assertEquals(null, $share->getToken());
$this->assertEquals(null, $share->getExpirationDate());
@@ -154,61 +266,84 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->assertEquals(1, $qb->execute());
// Get the id
- $qb = $this->dbConn->getQueryBuilder();
- $cursor = $qb->select('id')
- ->from('share')
- ->setMaxResults(1)
- ->orderBy('id', 'DESC')
- ->execute();
- $id = $cursor->fetch();
- $id = $id['id'];
- $cursor->closeCursor();
-
- $storage = $this->getMock('OC\Files\Storage\Storage');
- $storage
- ->expects($this->once())
- ->method('getOwner')
- ->willReturn('shareOwner');
- $path = $this->getMock('OCP\Files\Folder');
- $path
- ->expects($this->once())
- ->method('getStorage')
- ->wilLReturn($storage);
- $this->userFolder
- ->expects($this->once())
- ->method('getById')
- ->with(42)
- ->willReturn([$path]);
+ $id = $qb->getLastInsertId();
$sharedWith = $this->getMock('OCP\IGroup');
$sharedBy = $this->getMock('OCP\IUser');
+ $sharedBy->method('getUID')->willReturn('sharedBy');
$shareOwner = $this->getMock('OCP\IUser');
- $this->userManager
- ->method('get')
- ->will($this->returnValueMap([
- ['sharedBy', $sharedBy],
- ['shareOwner', $shareOwner],
- ]));
- $this->groupManager
- ->expects($this->once())
- ->method('get')
- ->with('sharedWith')
- ->willReturn($sharedWith);
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+
+ $sharedByPath = $this->getMock('\OCP\Files\Folder');
+ $ownerPath = $this->getMock('\OCP\Files\Folder');
+
+ $sharedByPath->method('getOwner')->willReturn($shareOwner);
+
+ $sharedByFolder = $this->getMock('\OCP\Files\Folder');
+ $sharedByFolder->method('getById')->with(42)->willReturn([$sharedByPath]);
+
+ $shareOwnerFolder = $this->getMock('\OCP\Files\Folder');
+ $shareOwnerFolder->method('getById')->with(42)->willReturn([$ownerPath]);
+
+ $this->rootFolder
+ ->method('getUserFolder')
+ ->will($this->returnValueMap([
+ ['sharedBy', $sharedByFolder],
+ ['shareOwner', $shareOwnerFolder],
+ ]));
$share = $this->provider->getShareById($id);
$this->assertEquals($id, $share->getId());
$this->assertEquals(\OCP\Share::SHARE_TYPE_GROUP, $share->getShareType());
- $this->assertEquals($sharedWith, $share->getSharedWith());
- $this->assertEquals($sharedBy, $share->getSharedBy());
- $this->assertEquals($shareOwner, $share->getShareOwner());
- $this->assertEquals($path, $share->getPath());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals('sharedBy', $share->getSharedBy());
+ $this->assertEquals('shareOwner', $share->getShareOwner());
+ $this->assertEquals($ownerPath, $share->getNode());
$this->assertEquals(13, $share->getPermissions());
$this->assertEquals(null, $share->getToken());
$this->assertEquals(null, $share->getExpirationDate());
$this->assertEquals('myTarget', $share->getTarget());
}
+ public function testGetShareByIdUserGroupShare() {
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user0', 'user0', 'file', 42, 'myTarget', 31, null, null);
+ $this->addShareToDB(2, 'user1', 'user0', 'user0', 'file', 42, 'userTarget', 0, null, null, $id);
+
+ $user0 = $this->getMock('OCP\IUser');
+ $user0->method('getUID')->willReturn('user0');
+ $user1 = $this->getMock('OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+
+ $group0 = $this->getMock('OCP\IGroup');
+ $group0->method('inGroup')->with($user1)->willReturn(true);
+
+ $node = $this->getMock('\OCP\Files\Folder');
+ $node->method('getId')->willReturn(42);
+
+ $this->rootFolder->method('getUserFolder')->with('user0')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->willReturn([$node]);
+
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['user0', $user0],
+ ['user1', $user1],
+ ]));
+ $this->groupManager->method('get')->with('group0')->willReturn($group0);
+
+ $share = $this->provider->getShareById($id, 'user1');
+
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_GROUP, $share->getShareType());
+ $this->assertSame('group0', $share->getSharedWith());
+ $this->assertSame('user0', $share->getSharedBy());
+ $this->assertSame('user0', $share->getShareOwner());
+ $this->assertSame($node, $share->getNode());
+ $this->assertEquals(0, $share->getPermissions());
+ $this->assertEquals(null, $share->getToken());
+ $this->assertEquals(null, $share->getExpirationDate());
+ $this->assertEquals('userTarget', $share->getTarget());
+ }
+
public function testGetShareByIdLinkShare() {
$qb = $this->dbConn->getQueryBuilder();
@@ -226,35 +361,31 @@ class DefaultShareProviderTest extends \Test\TestCase {
]);
$this->assertEquals(1, $qb->execute());
- // Get the id
- $qb = $this->dbConn->getQueryBuilder();
- $cursor = $qb->select('id')
- ->from('share')
- ->setMaxResults(1)
- ->orderBy('id', 'DESC')
- ->execute();
- $id = $cursor->fetch();
- $id = $id['id'];
- $cursor->closeCursor();
-
- $storage = $this->getMock('OC\Files\Storage\Storage');
- $storage
- ->expects($this->once())
- ->method('getOwner')
- ->willReturn('shareOwner');
- $path = $this->getMock('OCP\Files\Node');
- $path
- ->expects($this->once())
- ->method('getStorage')
- ->wilLReturn($storage);
- $this->userFolder
- ->expects($this->once())
- ->method('getById')
- ->with(42)
- ->willReturn([$path]);
+ $id = $qb->getLastInsertId();
$sharedBy = $this->getMock('OCP\IUser');
+ $sharedBy->method('getUID')->willReturn('sharedBy');
$shareOwner = $this->getMock('OCP\IUser');
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+
+ $sharedByPath = $this->getMock('\OCP\Files\Folder');
+ $ownerPath = $this->getMock('\OCP\Files\Folder');
+
+ $sharedByPath->method('getOwner')->willReturn($shareOwner);
+
+ $sharedByFolder = $this->getMock('\OCP\Files\Folder');
+ $sharedByFolder->method('getById')->with(42)->willReturn([$sharedByPath]);
+
+ $shareOwnerFolder = $this->getMock('\OCP\Files\Folder');
+ $shareOwnerFolder->method('getById')->with(42)->willReturn([$ownerPath]);
+
+ $this->rootFolder
+ ->method('getUserFolder')
+ ->will($this->returnValueMap([
+ ['sharedBy', $sharedByFolder],
+ ['shareOwner', $shareOwnerFolder],
+ ]));
+
$this->userManager
->method('get')
->will($this->returnValueMap([
@@ -267,21 +398,95 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->assertEquals($id, $share->getId());
$this->assertEquals(\OCP\Share::SHARE_TYPE_LINK, $share->getShareType());
$this->assertEquals('sharedWith', $share->getPassword());
- $this->assertEquals($sharedBy, $share->getSharedBy());
- $this->assertEquals($shareOwner, $share->getShareOwner());
- $this->assertEquals($path, $share->getPath());
+ $this->assertEquals('sharedBy', $share->getSharedBy());
+ $this->assertEquals('shareOwner', $share->getShareOwner());
+ $this->assertEquals($ownerPath, $share->getNode());
$this->assertEquals(13, $share->getPermissions());
$this->assertEquals('token', $share->getToken());
$this->assertEquals(\DateTime::createFromFormat('Y-m-d H:i:s', '2000-01-02 00:00:00'), $share->getExpirationDate());
$this->assertEquals('myTarget', $share->getTarget());
}
- public function testGetShareByIdRemoteShare() {
+ public function testDeleteSingleShare() {
$qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+ $id = $qb->getLastInsertId();
+
+ $share = $this->getMock('OCP\Share\IShare');
+ $share->method('getId')->willReturn($id);
+
+ $provider = $this->getMockBuilder('OC\Share20\DefaultShareProvider')
+ ->setConstructorArgs([
+ $this->dbConn,
+ $this->userManager,
+ $this->groupManager,
+ $this->rootFolder,
+ ])
+ ->setMethods(['getShareById'])
+ ->getMock();
+
+ $provider->delete($share);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share');
+
+ $cursor = $qb->execute();
+ $result = $cursor->fetchAll();
+ $cursor->closeCursor();
+
+ $this->assertEmpty($result);
+ }
+
+ public function testDeleteSingleShareLazy() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ $id = $qb->getLastInsertId();
+
+ $this->rootFolder->expects($this->never())->method($this->anything());
+
+ $share = $this->provider->getShareById($id);
+ $this->provider->delete($share);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share');
+
+ $cursor = $qb->execute();
+ $result = $cursor->fetchAll();
+ $cursor->closeCursor();
+
+ $this->assertEmpty($result);
+ }
+
+ public function testDeleteGroupShareWithUserGroupShares() {
+ $qb = $this->dbConn->getQueryBuilder();
$qb->insert('share')
->values([
- 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_REMOTE),
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
'share_with' => $qb->expr()->literal('sharedWith'),
'uid_owner' => $qb->expr()->literal('sharedBy'),
'item_type' => $qb->expr()->literal('file'),
@@ -290,6 +495,62 @@ class DefaultShareProviderTest extends \Test\TestCase {
'permissions' => $qb->expr()->literal(13),
]);
$this->assertEquals(1, $qb->execute());
+ $id = $qb->getLastInsertId();
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(2),
+ 'share_with' => $qb->expr()->literal('sharedWithUser'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ 'parent' => $qb->expr()->literal($id),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ $share = $this->getMock('OCP\Share\IShare');
+ $share->method('getId')->willReturn($id);
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_GROUP);
+
+ $provider = $this->getMockBuilder('OC\Share20\DefaultShareProvider')
+ ->setConstructorArgs([
+ $this->dbConn,
+ $this->userManager,
+ $this->groupManager,
+ $this->rootFolder,
+ ])
+ ->setMethods(['getShareById'])
+ ->getMock();
+
+ $provider->delete($share);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share');
+
+ $cursor = $qb->execute();
+ $result = $cursor->fetchAll();
+ $cursor->closeCursor();
+
+ $this->assertEmpty($result);
+ }
+
+ public function testGetChildren() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $qb->execute();
// Get the id
$qb = $this->dbConn->getQueryBuilder();
@@ -302,353 +563,1399 @@ class DefaultShareProviderTest extends \Test\TestCase {
$id = $id['id'];
$cursor->closeCursor();
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('user1'),
+ 'uid_owner' => $qb->expr()->literal('user2'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(1),
+ 'file_target' => $qb->expr()->literal('myTarget1'),
+ 'permissions' => $qb->expr()->literal(2),
+ 'parent' => $qb->expr()->literal($id),
+ ]);
+ $qb->execute();
- $storage = $this->getMock('OC\Files\Storage\Storage');
- $storage
- ->expects($this->once())
- ->method('getOwner')
- ->willReturn('shareOwner');
- $path = $this->getMock('OCP\Files\Node');
- $path
- ->expects($this->once())
- ->method('getStorage')
- ->wilLReturn($storage);
- $this->userFolder
- ->expects($this->once())
- ->method('getById')
- ->with(42)
- ->willReturn([$path]);
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+ 'share_with' => $qb->expr()->literal('group1'),
+ 'uid_owner' => $qb->expr()->literal('user3'),
+ 'item_type' => $qb->expr()->literal('folder'),
+ 'file_source' => $qb->expr()->literal(3),
+ 'file_target' => $qb->expr()->literal('myTarget2'),
+ 'permissions' => $qb->expr()->literal(4),
+ 'parent' => $qb->expr()->literal($id),
+ ]);
+ $qb->execute();
- $sharedBy = $this->getMock('OCP\IUser');
$shareOwner = $this->getMock('OCP\IUser');
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+ $user1 = $this->getMock('OCP\IUser');
+ $user2 = $this->getMock('OCP\IUser');
+ $user2->method('getUID')->willReturn('user2');
+ $user3 = $this->getMock('OCP\IUser');
+ $user3->method('getUID')->willReturn('user3');
+
+ $user2Path = $this->getMock('\OCP\Files\File');
+ $user2Path->expects($this->once())->method('getOwner')->willReturn($shareOwner);
+ $user2Folder = $this->getMock('\OCP\Files\Folder');
+ $user2Folder->expects($this->once())
+ ->method('getById')
+ ->with(1)
+ ->willReturn([$user2Path]);
+
+ $user3Path = $this->getMock('\OCP\Files\Folder');
+ $user3Path->expects($this->once())->method('getOwner')->willReturn($shareOwner);
+ $user3Folder = $this->getMock('\OCP\Files\Folder');
+ $user3Folder->expects($this->once())
+ ->method('getById')
+ ->with(3)
+ ->willReturn([$user3Path]);
+
+ $ownerPath = $this->getMock('\OCP\Files\Folder');
+ $ownerFolder = $this->getMock('\OCP\Files\Folder');
+ $ownerFolder->method('getById')->willReturn([$ownerPath]);
+
+ $this->rootFolder
+ ->method('getUserFolder')
+ ->will($this->returnValueMap([
+ ['shareOwner', $ownerFolder],
+ ['user2', $user2Folder],
+ ['user3', $user3Folder],
+ ]));
+
$this->userManager
->method('get')
->will($this->returnValueMap([
- ['sharedBy', $sharedBy],
- ['shareOwner', $shareOwner],
+ ['user1', $user1],
+ ['user2', $user2],
+ ['user3', $user3],
]));
- $share = $this->provider->getShareById($id);
+ $group1 = $this->getMock('OCP\IGroup');
+ $this->groupManager
+ ->method('get')
+ ->will($this->returnValueMap([
+ ['group1', $group1]
+ ]));
+
+ $share = $this->getMock('\OCP\Share\IShare');
+ $share->method('getId')->willReturn($id);
+
+ $children = $this->provider->getChildren($share);
+
+ $this->assertCount(2, $children);
+
+ //Child1
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $children[0]->getShareType());
+ $this->assertEquals('user1', $children[0]->getSharedWith());
+ $this->assertEquals('user2', $children[0]->getSharedBy());
+ $this->assertEquals('shareOwner', $children[0]->getShareOwner());
+ $this->assertEquals($ownerPath, $children[0]->getNode());
+ $this->assertEquals(2, $children[0]->getPermissions());
+ $this->assertEquals(null, $children[0]->getToken());
+ $this->assertEquals(null, $children[0]->getExpirationDate());
+ $this->assertEquals('myTarget1', $children[0]->getTarget());
+
+ //Child2
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_GROUP, $children[1]->getShareType());
+ $this->assertEquals('group1', $children[1]->getSharedWith());
+ $this->assertEquals('user3', $children[1]->getSharedBy());
+ $this->assertEquals('shareOwner', $children[1]->getShareOwner());
+ $this->assertEquals($ownerPath, $children[1]->getNode());
+ $this->assertEquals(4, $children[1]->getPermissions());
+ $this->assertEquals(null, $children[1]->getToken());
+ $this->assertEquals(null, $children[1]->getExpirationDate());
+ $this->assertEquals('myTarget2', $children[1]->getTarget());
+ }
+
+ public function testCreateUserShare() {
+ $share = new \OC\Share20\Share($this->rootFolder);
+
+ $shareOwner = $this->getMock('OCP\IUser');
+ $shareOwner->method('getUID')->WillReturn('shareOwner');
+
+ $path = $this->getMock('\OCP\Files\File');
+ $path->method('getId')->willReturn(100);
+ $path->method('getOwner')->willReturn($shareOwner);
+
+ $ownerFolder = $this->getMock('OCP\Files\Folder');
+ $userFolder = $this->getMock('OCP\Files\Folder');
+ $this->rootFolder
+ ->method('getUserFolder')
+ ->will($this->returnValueMap([
+ ['sharedBy', $userFolder],
+ ['shareOwner', $ownerFolder],
+ ]));
+
+ $userFolder->method('getById')
+ ->with(100)
+ ->willReturn([$path]);
+ $ownerFolder->method('getById')
+ ->with(100)
+ ->willReturn([$path]);
+ $share->setShareType(\OCP\Share::SHARE_TYPE_USER);
+ $share->setSharedWith('sharedWith');
+ $share->setSharedBy('sharedBy');
+ $share->setShareOwner('shareOwner');
+ $share->setNode($path);
+ $share->setPermissions(1);
+ $share->setTarget('/target');
+
+ $share2 = $this->provider->create($share);
+
+ $this->assertNotNull($share2->getId());
+ $this->assertSame('ocinternal:'.$share2->getId(), $share2->getFullId());
+ $this->assertSame(\OCP\Share::SHARE_TYPE_USER, $share2->getShareType());
+ $this->assertSame('sharedWith', $share2->getSharedWith());
+ $this->assertSame('sharedBy', $share2->getSharedBy());
+ $this->assertSame('shareOwner', $share2->getShareOwner());
+ $this->assertSame(1, $share2->getPermissions());
+ $this->assertSame('/target', $share2->getTarget());
+ $this->assertLessThanOrEqual(new \DateTime(), $share2->getShareTime());
+ $this->assertSame($path, $share2->getNode());
+ }
+
+ public function testCreateGroupShare() {
+ $share = new \OC\Share20\Share($this->rootFolder);
+
+ $shareOwner = $this->getMock('\OCP\IUser');
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+
+ $path = $this->getMock('\OCP\Files\Folder');
+ $path->method('getId')->willReturn(100);
+ $path->method('getOwner')->willReturn($shareOwner);
+
+ $ownerFolder = $this->getMock('OCP\Files\Folder');
+ $userFolder = $this->getMock('OCP\Files\Folder');
+ $this->rootFolder
+ ->method('getUserFolder')
+ ->will($this->returnValueMap([
+ ['sharedBy', $userFolder],
+ ['shareOwner', $ownerFolder],
+ ]));
+
+ $userFolder->method('getById')
+ ->with(100)
+ ->willReturn([$path]);
+ $ownerFolder->method('getById')
+ ->with(100)
+ ->willReturn([$path]);
+
+ $share->setShareType(\OCP\Share::SHARE_TYPE_GROUP);
+ $share->setSharedWith('sharedWith');
+ $share->setSharedBy('sharedBy');
+ $share->setShareOwner('shareOwner');
+ $share->setNode($path);
+ $share->setPermissions(1);
+ $share->setTarget('/target');
+
+ $share2 = $this->provider->create($share);
+
+ $this->assertNotNull($share2->getId());
+ $this->assertSame('ocinternal:'.$share2->getId(), $share2->getFullId());
+ $this->assertSame(\OCP\Share::SHARE_TYPE_GROUP, $share2->getShareType());
+ $this->assertSame('sharedWith', $share2->getSharedWith());
+ $this->assertSame('sharedBy', $share2->getSharedBy());
+ $this->assertSame('shareOwner', $share2->getShareOwner());
+ $this->assertSame(1, $share2->getPermissions());
+ $this->assertSame('/target', $share2->getTarget());
+ $this->assertLessThanOrEqual(new \DateTime(), $share2->getShareTime());
+ $this->assertSame($path, $share2->getNode());
+ }
+
+ public function testCreateLinkShare() {
+ $share = new \OC\Share20\Share($this->rootFolder);
+
+ $shareOwner = $this->getMock('\OCP\IUser');
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+
+ $path = $this->getMock('\OCP\Files\Folder');
+ $path->method('getId')->willReturn(100);
+ $path->method('getOwner')->willReturn($shareOwner);
+
+ $ownerFolder = $this->getMock('OCP\Files\Folder');
+ $userFolder = $this->getMock('OCP\Files\Folder');
+ $this->rootFolder
+ ->method('getUserFolder')
+ ->will($this->returnValueMap([
+ ['sharedBy', $userFolder],
+ ['shareOwner', $ownerFolder],
+ ]));
+
+ $userFolder->method('getById')
+ ->with(100)
+ ->willReturn([$path]);
+ $ownerFolder->method('getById')
+ ->with(100)
+ ->willReturn([$path]);
+
+ $share->setShareType(\OCP\Share::SHARE_TYPE_LINK);
+ $share->setSharedBy('sharedBy');
+ $share->setShareOwner('shareOwner');
+ $share->setNode($path);
+ $share->setPermissions(1);
+ $share->setPassword('password');
+ $share->setToken('token');
+ $expireDate = new \DateTime();
+ $share->setExpirationDate($expireDate);
+ $share->setTarget('/target');
+
+ $share2 = $this->provider->create($share);
+
+ $this->assertNotNull($share2->getId());
+ $this->assertSame('ocinternal:'.$share2->getId(), $share2->getFullId());
+ $this->assertSame(\OCP\Share::SHARE_TYPE_LINK, $share2->getShareType());
+ $this->assertSame('sharedBy', $share2->getSharedBy());
+ $this->assertSame('shareOwner', $share2->getShareOwner());
+ $this->assertSame(1, $share2->getPermissions());
+ $this->assertSame('/target', $share2->getTarget());
+ $this->assertLessThanOrEqual(new \DateTime(), $share2->getShareTime());
+ $this->assertSame($path, $share2->getNode());
+ $this->assertSame('password', $share2->getPassword());
+ $this->assertSame('token', $share2->getToken());
+ $this->assertEquals($expireDate, $share2->getExpirationDate());
+ }
+
+ public function testGetShareByToken() {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_LINK),
+ 'share_with' => $qb->expr()->literal('password'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ 'token' => $qb->expr()->literal('secrettoken'),
+ ]);
+ $qb->execute();
+ $id = $qb->getLastInsertId();
+
+ $file = $this->getMock('\OCP\Files\File');
+
+ $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(42)->willReturn([$file]);
+
+ $share = $this->provider->getShareByToken('secrettoken');
$this->assertEquals($id, $share->getId());
- $this->assertEquals(\OCP\Share::SHARE_TYPE_REMOTE, $share->getShareType());
- $this->assertEquals('sharedWith', $share->getSharedWith());
- $this->assertEquals($sharedBy, $share->getSharedBy());
- $this->assertEquals($shareOwner, $share->getShareOwner());
- $this->assertEquals($path, $share->getPath());
- $this->assertEquals(13, $share->getPermissions());
- $this->assertEquals(null, $share->getToken());
- $this->assertEquals(null, $share->getExpirationDate());
- $this->assertEquals('myTarget', $share->getTarget());
+ $this->assertSame('shareOwner', $share->getShareOwner());
+ $this->assertSame('sharedBy', $share->getSharedBy());
+ $this->assertSame('secrettoken', $share->getToken());
+ $this->assertSame('password', $share->getPassword());
+ $this->assertSame(null, $share->getSharedWith());
}
- public function testDeleteSingleShare() {
+ /**
+ * @expectedException \OCP\Share\Exceptions\ShareNotFound
+ */
+ public function testGetShareByTokenNotFound() {
+ $this->provider->getShareByToken('invalidtoken');
+ }
+
+ public function testGetSharedWithUser() {
$qb = $this->dbConn->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
'share_with' => $qb->expr()->literal('sharedWith'),
- 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
'item_type' => $qb->expr()->literal('file'),
'file_source' => $qb->expr()->literal(42),
'file_target' => $qb->expr()->literal('myTarget'),
'permissions' => $qb->expr()->literal(13),
]);
$this->assertEquals(1, $qb->execute());
+ $id = $qb->getLastInsertId();
- // Get the id
$qb = $this->dbConn->getQueryBuilder();
- $cursor = $qb->select('id')
- ->from('share')
- ->setMaxResults(1)
- ->orderBy('id', 'DESC')
- ->execute();
- $id = $cursor->fetch();
- $id = $id['id'];
- $cursor->closeCursor();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith2'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner2'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy2'),
+ 'item_type' => $qb->expr()->literal('file2'),
+ 'file_source' => $qb->expr()->literal(43),
+ 'file_target' => $qb->expr()->literal('myTarget2'),
+ 'permissions' => $qb->expr()->literal(14),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+ $file = $this->getMock('\OCP\Files\File');
+ $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(42)->willReturn([$file]);
- $path = $this->getMock('OCP\Files\File');
- $path
- ->expects($this->exactly(2))
- ->method('getId')
- ->willReturn(42);
+ $share = $this->provider->getSharedWith('sharedWith', \OCP\Share::SHARE_TYPE_USER, null, 1 , 0);
+ $this->assertCount(1, $share);
- $sharedWith = $this->getMock('OCP\IUser');
- $sharedWith
- ->expects($this->once())
- ->method('getUID')
- ->willReturn('sharedWith');
- $sharedBy = $this->getMock('OCP\IUser');
- $sharedBy
- ->expects($this->once())
- ->method('getUID')
- ->willReturn('sharedBy');
-
- $share = $this->getMock('OC\Share20\IShare');
- $share
- ->method('getId')
- ->willReturn($id);
- $share
- ->expects($this->once())
- ->method('getShareType')
- ->willReturn(\OCP\Share::SHARE_TYPE_USER);
- $share
- ->expects($this->exactly(3))
- ->method('getPath')
- ->willReturn($path);
- $share
- ->expects($this->once())
- ->method('getSharedWith')
- ->willReturn($sharedWith);
- $share
- ->expects($this->once())
- ->method('getSharedBy')
- ->willReturn($sharedBy);
- $share
- ->expects($this->once())
- ->method('getTarget')
- ->willReturn('myTarget');
+ $share = $share[0];
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals('shareOwner', $share->getShareOwner());
+ $this->assertEquals('sharedBy', $share->getSharedBy());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+ }
- $provider = $this->getMockBuilder('OC\Share20\DefaultShareProvider')
- ->setConstructorArgs([
- $this->dbConn,
- $this->userManager,
- $this->groupManager,
- $this->userFolder,
- ]
- )
- ->setMethods(['deleteChildren', 'getShareById'])
- ->getMock();
- $provider
- ->expects($this->once())
- ->method('deleteChildren');
- $provider
- ->expects($this->once())
- ->method('getShareById')
- ->willReturn($share);
-
- $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listen'])->getMock();
- \OCP\Util::connectHook('OCP\Share', 'pre_unshare', $hookListner, 'listen');
- \OCP\Util::connectHook('OCP\Share', 'post_unshare', $hookListner, 'listen');
-
- $hookListnerExpects = [
- 'id' => $id,
- 'itemType' => 'file',
- 'itemSource' => 42,
- 'shareType' => \OCP\Share::SHARE_TYPE_USER,
- 'shareWith' => 'sharedWith',
- 'itemparent' => null,
- 'uidOwner' => 'sharedBy',
- 'fileSource' => 42,
- 'fileTarget' => 'myTarget',
- ];
-
- $hookListner
- ->expects($this->exactly(2))
- ->method('listen')
- ->with($hookListnerExpects);
+ public function testGetSharedWithGroup() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner2'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy2'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(43),
+ 'file_target' => $qb->expr()->literal('myTarget2'),
+ 'permissions' => $qb->expr()->literal(14),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+ $id = $qb->getLastInsertId();
+
+ $groups = [];
+ foreach(range(0, 100) as $i) {
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('getGID')->willReturn('group'.$i);
+ $groups[] = $group;
+ }
+
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('getGID')->willReturn('sharedWith');
+ $groups[] = $group;
+
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('getUID')->willReturn('sharedWith');
+ $owner = $this->getMock('\OCP\IUser');
+ $owner->method('getUID')->willReturn('shareOwner');
+ $initiator = $this->getMock('\OCP\IUser');
+ $initiator->method('getUID')->willReturn('sharedBy');
+
+ $this->userManager->method('get')->willReturnMap([
+ ['sharedWith', $user],
+ ['shareOwner', $owner],
+ ['sharedBy', $initiator],
+ ]);
+ $this->groupManager->method('getUserGroups')->with($user)->willReturn($groups);
+ $this->groupManager->method('get')->with('sharedWith')->willReturn($group);
+
+ $file = $this->getMock('\OCP\Files\File');
+ $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(42)->willReturn([$file]);
+
+ $share = $this->provider->getSharedWith('sharedWith', \OCP\Share::SHARE_TYPE_GROUP, null, 20 , 1);
+ $this->assertCount(1, $share);
+
+ $share = $share[0];
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals('shareOwner', $share->getShareOwner());
+ $this->assertEquals('sharedBy', $share->getSharedBy());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_GROUP, $share->getShareType());
+ }
- $provider->delete($share);
+ public function testGetSharedWithGroupUserModified() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+ $id = $qb->getLastInsertId();
+ /*
+ * Wrong share. Should not be taken by code.
+ */
$qb = $this->dbConn->getQueryBuilder();
- $qb->select('*')
- ->from('share');
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(2),
+ 'share_with' => $qb->expr()->literal('user2'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('wrongTarget'),
+ 'permissions' => $qb->expr()->literal(31),
+ 'parent' => $qb->expr()->literal($id),
+ ]);
+ $this->assertEquals(1, $qb->execute());
- $cursor = $qb->execute();
- $result = $cursor->fetchAll();
- $cursor->closeCursor();
+ /*
+ * Correct share. should be taken by code path.
+ */
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(2),
+ 'share_with' => $qb->expr()->literal('user'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('userTarget'),
+ 'permissions' => $qb->expr()->literal(0),
+ 'parent' => $qb->expr()->literal($id),
+ ]);
+ $this->assertEquals(1, $qb->execute());
- $this->assertEmpty($result);
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('getGID')->willReturn('sharedWith');
+ $groups = [$group];
+
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('getUID')->willReturn('user');
+ $owner = $this->getMock('\OCP\IUser');
+ $owner->method('getUID')->willReturn('shareOwner');
+ $initiator = $this->getMock('\OCP\IUser');
+ $initiator->method('getUID')->willReturn('sharedBy');
+
+ $this->userManager->method('get')->willReturnMap([
+ ['user', $user],
+ ['shareOwner', $owner],
+ ['sharedBy', $initiator],
+ ]);
+ $this->groupManager->method('getUserGroups')->with($user)->willReturn($groups);
+ $this->groupManager->method('get')->with('sharedWith')->willReturn($group);
+
+ $file = $this->getMock('\OCP\Files\File');
+ $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(42)->willReturn([$file]);
+
+ $share = $this->provider->getSharedWith('user', \OCP\Share::SHARE_TYPE_GROUP, null, -1, 0);
+ $this->assertCount(1, $share);
+
+ $share = $share[0];
+ $this->assertSame($id, $share->getId());
+ $this->assertSame('sharedWith', $share->getSharedWith());
+ $this->assertSame('shareOwner', $share->getShareOwner());
+ $this->assertSame('sharedBy', $share->getSharedBy());
+ $this->assertSame(\OCP\Share::SHARE_TYPE_GROUP, $share->getShareType());
+ $this->assertSame(0, $share->getPermissions());
+ $this->assertSame('userTarget', $share->getTarget());
+ }
+
+ public function testGetSharedWithUserWithNode() {
+ $this->addShareToDB(\OCP\Share::SHARE_TYPE_USER, 'user0', 'user1', 'user1',
+ 'file', 42, 'myTarget', 31, null, null, null);
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_USER, 'user0', 'user1', 'user1',
+ 'file', 43, 'myTarget', 31, null, null, null);
+
+ $user0 = $this->getMock('\OCP\IUser');
+ $user0->method('getUID')->willReturn('user0');
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+
+ $this->userManager->method('get')->willReturnMap([
+ ['user0', $user0],
+ ['user1', $user1],
+ ]);
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(43);
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(43)->willReturn([$file]);
+
+ $share = $this->provider->getSharedWith('user0', \OCP\Share::SHARE_TYPE_USER, $file, -1, 0);
+ $this->assertCount(1, $share);
+
+ $share = $share[0];
+ $this->assertEquals($id, $share->getId());
+ $this->assertSame('user0', $share->getSharedWith());
+ $this->assertSame('user1', $share->getShareOwner());
+ $this->assertSame('user1', $share->getSharedBy());
+ $this->assertSame($file, $share->getNode());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+ }
+
+ public function testGetSharedWithGroupWithNode() {
+ $this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user1', 'user1',
+ 'file', 42, 'myTarget', 31, null, null, null);
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user1', 'user1',
+ 'file', 43, 'myTarget', 31, null, null, null);
+
+ $user0 = $this->getMock('\OCP\IUser');
+ $user0->method('getUID')->willReturn('user0');
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+
+ $this->userManager->method('get')->willReturnMap([
+ ['user0', $user0],
+ ['user1', $user1],
+ ]);
+
+ $group0 = $this->getMock('\OCP\IGroup');
+ $group0->method('getGID')->willReturn('group0');
+
+ $this->groupManager->method('get')->with('group0')->willReturn($group0);
+ $this->groupManager->method('getUserGroups')->with($user0)->willReturn([$group0]);
+
+ $node = $this->getMock('\OCP\Files\Folder');
+ $node->method('getId')->willReturn(43);
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(43)->willReturn([$node]);
+
+ $share = $this->provider->getSharedWith('user0', \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
+ $this->assertCount(1, $share);
+
+ $share = $share[0];
+ $this->assertEquals($id, $share->getId());
+ $this->assertSame('group0', $share->getSharedWith());
+ $this->assertSame('user1', $share->getShareOwner());
+ $this->assertSame('user1', $share->getSharedBy());
+ $this->assertSame($node, $share->getNode());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_GROUP, $share->getShareType());
}
- public function testDeleteNestedShares() {
+ public function testGetSharesBy() {
$qb = $this->dbConn->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
'share_with' => $qb->expr()->literal('sharedWith'),
- 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
'item_type' => $qb->expr()->literal('file'),
'file_source' => $qb->expr()->literal(42),
'file_target' => $qb->expr()->literal('myTarget'),
'permissions' => $qb->expr()->literal(13),
]);
$this->assertEquals(1, $qb->execute());
+ $id = $qb->getLastInsertId();
- // Get the id
$qb = $this->dbConn->getQueryBuilder();
- $cursor = $qb->select('id')
- ->from('share')
- ->setMaxResults(1)
- ->orderBy('id', 'DESC')
- ->execute();
- $id1 = $cursor->fetch();
- $id1 = $id1['id'];
- $cursor->closeCursor();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy2'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('userTarget'),
+ 'permissions' => $qb->expr()->literal(0),
+ 'parent' => $qb->expr()->literal($id),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ $file = $this->getMock('\OCP\Files\File');
+ $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(42)->willReturn([$file]);
+ $share = $this->provider->getSharesBy('sharedBy', \OCP\Share::SHARE_TYPE_USER, null, false, 1, 0);
+ $this->assertCount(1, $share);
+ $share = $share[0];
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals('shareOwner', $share->getShareOwner());
+ $this->assertEquals('sharedBy', $share->getSharedBy());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+ $this->assertEquals(13, $share->getPermissions());
+ $this->assertEquals('myTarget', $share->getTarget());
+ }
+
+ public function testGetSharesNode() {
$qb = $this->dbConn->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
'share_with' => $qb->expr()->literal('sharedWith'),
- 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
'item_type' => $qb->expr()->literal('file'),
'file_source' => $qb->expr()->literal(42),
'file_target' => $qb->expr()->literal('myTarget'),
'permissions' => $qb->expr()->literal(13),
- 'parent' => $qb->expr()->literal($id1),
]);
$this->assertEquals(1, $qb->execute());
+ $id = $qb->getLastInsertId();
- // Get the id
$qb = $this->dbConn->getQueryBuilder();
- $cursor = $qb->select('id')
- ->from('share')
- ->setMaxResults(1)
- ->orderBy('id', 'DESC')
- ->execute();
- $id2 = $cursor->fetch();
- $id2 = $id2['id'];
- $cursor->closeCursor();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(43),
+ 'file_target' => $qb->expr()->literal('userTarget'),
+ 'permissions' => $qb->expr()->literal(0),
+ 'parent' => $qb->expr()->literal($id),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(42);
+ $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(42)->willReturn([$file]);
+
+ $share = $this->provider->getSharesBy('sharedBy', \OCP\Share::SHARE_TYPE_USER, $file, false, 1, 0);
+ $this->assertCount(1, $share);
+
+ $share = $share[0];
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals('shareOwner', $share->getShareOwner());
+ $this->assertEquals('sharedBy', $share->getSharedBy());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+ $this->assertEquals(13, $share->getPermissions());
+ $this->assertEquals('myTarget', $share->getTarget());
+ }
+ public function testGetSharesReshare() {
$qb = $this->dbConn->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
'share_with' => $qb->expr()->literal('sharedWith'),
- 'uid_owner' => $qb->expr()->literal('sharedBy'),
- 'item_type' => $qb->expr()->literal('file'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('shareOwner'),
+ 'item_type' => $qb->expr()->literal('file'),
'file_source' => $qb->expr()->literal(42),
'file_target' => $qb->expr()->literal('myTarget'),
'permissions' => $qb->expr()->literal(13),
- 'parent' => $qb->expr()->literal($id2),
]);
$this->assertEquals(1, $qb->execute());
+ $id1 = $qb->getLastInsertId();
- $storage = $this->getMock('OC\Files\Storage\Storage');
- $storage
- ->method('getOwner')
- ->willReturn('shareOwner');
- $path = $this->getMock('OCP\Files\Node');
- $path
- ->method('getStorage')
- ->wilLReturn($storage);
- $this->userFolder
- ->method('getById')
- ->with(42)
- ->willReturn([$path]);
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('shareOwner'),
+ 'uid_initiator' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('userTarget'),
+ 'permissions' => $qb->expr()->literal(0),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+ $id2 = $qb->getLastInsertId();
- $sharedWith = $this->getMock('OCP\IUser');
- $sharedWith
- ->method('getUID')
- ->willReturn('sharedWith');
- $sharedBy = $this->getMock('OCP\IUser');
- $sharedBy
- ->method('getUID')
- ->willReturn('sharedBy');
- $shareOwner = $this->getMock('OCP\IUser');
- $this->userManager
- ->method('get')
- ->will($this->returnValueMap([
- ['sharedWith', $sharedWith],
- ['sharedBy', $sharedBy],
- ['shareOwner', $shareOwner],
- ]));
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(42);
+ $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(42)->willReturn([$file]);
- $share = $this->provider->getShareById($id1);
- $this->provider->delete($share);
+ $shares = $this->provider->getSharesBy('shareOwner', \OCP\Share::SHARE_TYPE_USER, null, true, -1, 0);
+ $this->assertCount(2, $shares);
+
+ $share = $shares[0];
+ $this->assertEquals($id1, $share->getId());
+ $this->assertSame('sharedWith', $share->getSharedWith());
+ $this->assertSame('shareOwner', $share->getShareOwner());
+ $this->assertSame('shareOwner', $share->getSharedBy());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+ $this->assertEquals(13, $share->getPermissions());
+ $this->assertEquals('myTarget', $share->getTarget());
+ $share = $shares[1];
+ $this->assertEquals($id2, $share->getId());
+ $this->assertSame('sharedWith', $share->getSharedWith());
+ $this->assertSame('shareOwner', $share->getShareOwner());
+ $this->assertSame('sharedBy', $share->getSharedBy());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+ $this->assertEquals(0, $share->getPermissions());
+ $this->assertEquals('userTarget', $share->getTarget());
+ }
+
+ public function testDeleteFromSelfGroupNoCustomShare() {
$qb = $this->dbConn->getQueryBuilder();
- $qb->select('*')
- ->from('share');
+ $stmt = $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+ 'share_with' => $qb->expr()->literal('group'),
+ 'uid_owner' => $qb->expr()->literal('user1'),
+ 'uid_initiator' => $qb->expr()->literal('user1'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(1),
+ 'file_target' => $qb->expr()->literal('myTarget1'),
+ 'permissions' => $qb->expr()->literal(2)
+ ])->execute();
+ $this->assertEquals(1, $stmt);
+ $id = $qb->getLastInsertId();
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user2 = $this->getMock('\OCP\IUser');
+ $user2->method('getUID')->willReturn('user2');
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['user1', $user1],
+ ['user2', $user2],
+ ]));
+
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('getGID')->willReturn('group');
+ $group->method('inGroup')->with($user2)->willReturn(true);
+ $this->groupManager->method('get')->with('group')->willReturn($group);
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(1);
+
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
- $cursor = $qb->execute();
- $result = $cursor->fetchAll();
- $cursor->closeCursor();
+ $share = $this->provider->getShareById($id);
- $this->assertEmpty($result);
+ $this->provider->deleteFromSelf($share, 'user2');
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(2)))
+ ->execute();
+
+ $shares = $stmt->fetchAll();
+ $stmt->closeCursor();
+
+ $this->assertCount(1, $shares);
+ $share2 = $shares[0];
+ $this->assertEquals($id, $share2['parent']);
+ $this->assertEquals(0, $share2['permissions']);
+ $this->assertEquals('user2', $share2['share_with']);
+ }
+
+ public function testDeleteFromSelfGroupAlreadyCustomShare() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+ 'share_with' => $qb->expr()->literal('group'),
+ 'uid_owner' => $qb->expr()->literal('user1'),
+ 'uid_initiator' => $qb->expr()->literal('user1'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(1),
+ 'file_target' => $qb->expr()->literal('myTarget1'),
+ 'permissions' => $qb->expr()->literal(2)
+ ])->execute();
+ $this->assertEquals(1, $stmt);
+ $id = $qb->getLastInsertId();
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(2),
+ 'share_with' => $qb->expr()->literal('user2'),
+ 'uid_owner' => $qb->expr()->literal('user1'),
+ 'uid_initiator' => $qb->expr()->literal('user1'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(1),
+ 'file_target' => $qb->expr()->literal('myTarget1'),
+ 'permissions' => $qb->expr()->literal(2),
+ 'parent' => $qb->expr()->literal($id),
+ ])->execute();
+ $this->assertEquals(1, $stmt);
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user2 = $this->getMock('\OCP\IUser');
+ $user2->method('getUID')->willReturn('user2');
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['user1', $user1],
+ ['user2', $user2],
+ ]));
+
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('getGID')->willReturn('group');
+ $group->method('inGroup')->with($user2)->willReturn(true);
+ $this->groupManager->method('get')->with('group')->willReturn($group);
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(1);
+
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+ $share = $this->provider->getShareById($id);
+
+ $this->provider->deleteFromSelf($share, 'user2');
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(2)))
+ ->execute();
+
+ $shares = $stmt->fetchAll();
+ $stmt->closeCursor();
+
+ $this->assertCount(1, $shares);
+ $share2 = $shares[0];
+ $this->assertEquals($id, $share2['parent']);
+ $this->assertEquals(0, $share2['permissions']);
+ $this->assertEquals('user2', $share2['share_with']);
}
/**
- * @expectedException \OC\Share20\Exception\BackendError
+ * @expectedException \OC\Share20\Exception\ProviderException
+ * @expectedExceptionMessage Recipient not in receiving group
*/
- public function testDeleteFails() {
- $share = $this->getMock('OC\Share20\IShare');
- $share
- ->method('getId')
- ->willReturn(42);
- $share
- ->expects($this->once())
- ->method('getShareType')
- ->willReturn(\OCP\Share::SHARE_TYPE_LINK);
-
- $path = $this->getMock('OCP\Files\Folder');
- $path
- ->expects($this->exactly(2))
- ->method('getId')
- ->willReturn(100);
- $share
- ->expects($this->exactly(3))
- ->method('getPath')
- ->willReturn($path);
+ public function testDeleteFromSelfGroupUserNotInGroup() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+ 'share_with' => $qb->expr()->literal('group'),
+ 'uid_owner' => $qb->expr()->literal('user1'),
+ 'uid_initiator' => $qb->expr()->literal('user1'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(1),
+ 'file_target' => $qb->expr()->literal('myTarget1'),
+ 'permissions' => $qb->expr()->literal(2)
+ ])->execute();
+ $this->assertEquals(1, $stmt);
+ $id = $qb->getLastInsertId();
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user2 = $this->getMock('\OCP\IUser');
+ $user2->method('getUID')->willReturn('user2');
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['user1', $user1],
+ ['user2', $user2],
+ ]));
+
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('getGID')->willReturn('group');
+ $group->method('inGroup')->with($user2)->willReturn(false);
+ $this->groupManager->method('get')->with('group')->willReturn($group);
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(1);
+
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
- $sharedBy = $this->getMock('OCP\IUser');
- $sharedBy
- ->expects($this->once())
- ->method('getUID');
- $share
- ->expects($this->once())
- ->method('getSharedBy')
- ->willReturn($sharedBy);
-
- $expr = $this->getMock('OCP\DB\QueryBuilder\IExpressionBuilder');
- $qb = $this->getMock('OCP\DB\QueryBuilder\IQueryBuilder');
- $qb->expects($this->once())
- ->method('delete')
- ->will($this->returnSelf());
- $qb->expects($this->once())
- ->method('expr')
- ->willReturn($expr);
- $qb->expects($this->once())
- ->method('where')
- ->will($this->returnSelf());
- $qb->expects($this->once())
- ->method('setParameter')
- ->will($this->returnSelf());
- $qb->expects($this->once())
- ->method('execute')
- ->will($this->throwException(new \Exception));
-
- $db = $this->getMock('OCP\IDBConnection');
- $db->expects($this->once())
- ->method('getQueryBuilder')
- ->with()
- ->willReturn($qb);
+ $share = $this->provider->getShareById($id);
- $provider = $this->getMockBuilder('OC\Share20\DefaultShareProvider')
- ->setConstructorArgs([
- $db,
- $this->userManager,
- $this->groupManager,
- $this->userFolder,
- ]
- )
- ->setMethods(['deleteChildren', 'getShareById'])
- ->getMock();
- $provider
- ->expects($this->once())
- ->method('deleteChildren')
- ->with($share);
- $provider
- ->expects($this->once())
- ->method('getShareById')
- ->with(42)
- ->willReturn($share);
-
- $provider->delete($share);
+ $this->provider->deleteFromSelf($share, 'user2');
+ }
+
+ public function testDeleteFromSelfUser() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('user2'),
+ 'uid_owner' => $qb->expr()->literal('user1'),
+ 'uid_initiator' => $qb->expr()->literal('user1'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(1),
+ 'file_target' => $qb->expr()->literal('myTarget1'),
+ 'permissions' => $qb->expr()->literal(2)
+ ])->execute();
+ $this->assertEquals(1, $stmt);
+ $id = $qb->getLastInsertId();
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user2 = $this->getMock('\OCP\IUser');
+ $user2->method('getUID')->willReturn('user2');
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['user1', $user1],
+ ['user2', $user2],
+ ]));
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(1);
+
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+ $share = $this->provider->getShareById($id);
+
+ $this->provider->deleteFromSelf($share, 'user2');
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
+ ->execute();
+
+ $shares = $stmt->fetchAll();
+ $stmt->closeCursor();
+
+ $this->assertCount(0, $shares);
+ }
+
+ /**
+ * @expectedException \OC\Share20\Exception\ProviderException
+ * @expectedExceptionMessage Recipient does not match
+ */
+ public function testDeleteFromSelfUserNotRecipient() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('user2'),
+ 'uid_owner' => $qb->expr()->literal('user1'),
+ 'uid_initiator' => $qb->expr()->literal('user1'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(1),
+ 'file_target' => $qb->expr()->literal('myTarget1'),
+ 'permissions' => $qb->expr()->literal(2)
+ ])->execute();
+ $this->assertEquals(1, $stmt);
+ $id = $qb->getLastInsertId();
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user2 = $this->getMock('\OCP\IUser');
+ $user2->method('getUID')->willReturn('user2');
+ $user3 = $this->getMock('\OCP\IUser');
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['user1', $user1],
+ ['user2', $user2],
+ ]));
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(1);
+
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+ $share = $this->provider->getShareById($id);
+
+ $this->provider->deleteFromSelf($share, $user3);
+ }
+
+ /**
+ * @expectedException \OC\Share20\Exception\ProviderException
+ * @expectedExceptionMessage Invalid shareType
+ */
+ public function testDeleteFromSelfLink() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_LINK),
+ 'uid_owner' => $qb->expr()->literal('user1'),
+ 'uid_initiator' => $qb->expr()->literal('user1'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(1),
+ 'file_target' => $qb->expr()->literal('myTarget1'),
+ 'permissions' => $qb->expr()->literal(2),
+ 'token' => $qb->expr()->literal('token'),
+ ])->execute();
+ $this->assertEquals(1, $stmt);
+ $id = $qb->getLastInsertId();
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['user1', $user1],
+ ]));
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(1);
+
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+ $share = $this->provider->getShareById($id);
+
+ $this->provider->deleteFromSelf($share, $user1);
+ }
+
+ public function testUpdateUser() {
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_USER, 'user0', 'user1', 'user2',
+ 'file', 42, 'target', 31, null, null);
+
+ $users = [];
+ for($i = 0; $i < 6; $i++) {
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('getUID')->willReturn('user'.$i);
+ $users['user'.$i] = $user;
+ }
+
+ $this->userManager->method('get')->will(
+ $this->returnCallback(function($userId) use ($users) {
+ return $users[$userId];
+ })
+ );
+
+ $file1 = $this->getMock('\OCP\Files\File');
+ $file1->method('getId')->willReturn(42);
+ $file2 = $this->getMock('\OCP\Files\File');
+ $file2->method('getId')->willReturn(43);
+
+ $folder1 = $this->getMock('\OCP\Files\Folder');
+ $folder1->method('getById')->with(42)->willReturn([$file1]);
+ $folder2 = $this->getMock('\OCP\Files\Folder');
+ $folder2->method('getById')->with(43)->willReturn([$file2]);
+
+ $this->rootFolder->method('getUserFolder')->will($this->returnValueMap([
+ ['user2', $folder1],
+ ['user5', $folder2],
+ ]));
+
+ $share = $this->provider->getShareById($id);
+
+ $share->setSharedWith('user3');
+ $share->setSharedBy('user4');
+ $share->setShareOwner('user5');
+ $share->setNode($file2);
+ $share->setPermissions(1);
+
+ $share2 = $this->provider->update($share);
+
+ $this->assertEquals($id, $share2->getId());
+ $this->assertSame('user3', $share2->getSharedWith());
+ $this->assertSame('user4', $share2->getSharedBy());
+ $this->assertSame('user5', $share2->getShareOwner());
+ $this->assertSame(1, $share2->getPermissions());
+ }
+
+ public function testUpdateLink() {
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_LINK, null, 'user1', 'user2',
+ 'file', 42, 'target', 31, null, null);
+
+ $users = [];
+ for($i = 0; $i < 6; $i++) {
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('getUID')->willReturn('user'.$i);
+ $users['user'.$i] = $user;
+ }
+
+ $this->userManager->method('get')->will(
+ $this->returnCallback(function($userId) use ($users) {
+ return $users[$userId];
+ })
+ );
+
+ $file1 = $this->getMock('\OCP\Files\File');
+ $file1->method('getId')->willReturn(42);
+ $file2 = $this->getMock('\OCP\Files\File');
+ $file2->method('getId')->willReturn(43);
+
+ $folder1 = $this->getMock('\OCP\Files\Folder');
+ $folder1->method('getById')->with(42)->willReturn([$file1]);
+ $folder2 = $this->getMock('\OCP\Files\Folder');
+ $folder2->method('getById')->with(43)->willReturn([$file2]);
+
+ $this->rootFolder->method('getUserFolder')->will($this->returnValueMap([
+ ['user2', $folder1],
+ ['user5', $folder2],
+ ]));
+
+ $share = $this->provider->getShareById($id);
+
+ $share->setPassword('password');
+ $share->setSharedBy('user4');
+ $share->setShareOwner('user5');
+ $share->setNode($file2);
+ $share->setPermissions(1);
+
+ $share2 = $this->provider->update($share);
+
+ $this->assertEquals($id, $share2->getId());
+ $this->assertEquals('password', $share->getPassword());
+ $this->assertSame('user4', $share2->getSharedBy());
+ $this->assertSame('user5', $share2->getShareOwner());
+ $this->assertSame(1, $share2->getPermissions());
+ }
+
+ public function testUpdateLinkRemovePassword() {
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_LINK, 'foo', 'user1', 'user2',
+ 'file', 42, 'target', 31, null, null);
+
+ $users = [];
+ for($i = 0; $i < 6; $i++) {
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('getUID')->willReturn('user'.$i);
+ $users['user'.$i] = $user;
+ }
+
+ $this->userManager->method('get')->will(
+ $this->returnCallback(function($userId) use ($users) {
+ return $users[$userId];
+ })
+ );
+
+ $file1 = $this->getMock('\OCP\Files\File');
+ $file1->method('getId')->willReturn(42);
+ $file2 = $this->getMock('\OCP\Files\File');
+ $file2->method('getId')->willReturn(43);
+
+ $folder1 = $this->getMock('\OCP\Files\Folder');
+ $folder1->method('getById')->with(42)->willReturn([$file1]);
+ $folder2 = $this->getMock('\OCP\Files\Folder');
+ $folder2->method('getById')->with(43)->willReturn([$file2]);
+
+ $this->rootFolder->method('getUserFolder')->will($this->returnValueMap([
+ ['user2', $folder1],
+ ['user5', $folder2],
+ ]));
+
+ $share = $this->provider->getShareById($id);
+
+ $share->setPassword(null);
+ $share->setSharedBy('user4');
+ $share->setShareOwner('user5');
+ $share->setNode($file2);
+ $share->setPermissions(1);
+
+ $share2 = $this->provider->update($share);
+
+ $this->assertEquals($id, $share2->getId());
+ $this->assertEquals(null, $share->getPassword());
+ $this->assertSame('user4', $share2->getSharedBy());
+ $this->assertSame('user5', $share2->getShareOwner());
+ $this->assertSame(1, $share2->getPermissions());
+ }
+
+ public function testUpdateGroupNoSub() {
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user1', 'user2',
+ 'file', 42, 'target', 31, null, null);
+
+ $users = [];
+ for($i = 0; $i < 6; $i++) {
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('getUID')->willReturn('user'.$i);
+ $users['user'.$i] = $user;
+ }
+
+ $this->userManager->method('get')->will(
+ $this->returnCallback(function($userId) use ($users) {
+ return $users[$userId];
+ })
+ );
+
+ $groups = [];
+ for($i = 0; $i < 2; $i++) {
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('getGID')->willReturn('group'.$i);
+ $groups['group'.$i] = $group;
+ }
+
+ $this->groupManager->method('get')->will(
+ $this->returnCallback(function($groupId) use ($groups) {
+ return $groups[$groupId];
+ })
+ );
+
+ $file1 = $this->getMock('\OCP\Files\File');
+ $file1->method('getId')->willReturn(42);
+ $file2 = $this->getMock('\OCP\Files\File');
+ $file2->method('getId')->willReturn(43);
+
+ $folder1 = $this->getMock('\OCP\Files\Folder');
+ $folder1->method('getById')->with(42)->willReturn([$file1]);
+ $folder2 = $this->getMock('\OCP\Files\Folder');
+ $folder2->method('getById')->with(43)->willReturn([$file2]);
+
+ $this->rootFolder->method('getUserFolder')->will($this->returnValueMap([
+ ['user2', $folder1],
+ ['user5', $folder2],
+ ]));
+
+ $share = $this->provider->getShareById($id);
+
+ $share->setSharedWith('group0');
+ $share->setSharedBy('user4');
+ $share->setShareOwner('user5');
+ $share->setNode($file2);
+ $share->setPermissions(1);
+
+ $share2 = $this->provider->update($share);
+
+ $this->assertEquals($id, $share2->getId());
+ // Group shares do not allow updating the recipient
+ $this->assertSame('group0', $share2->getSharedWith());
+ $this->assertSame('user4', $share2->getSharedBy());
+ $this->assertSame('user5', $share2->getShareOwner());
+ $this->assertSame(1, $share2->getPermissions());
+ }
+
+ public function testUpdateGroupSubShares() {
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user1', 'user2',
+ 'file', 42, 'target', 31, null, null);
+
+ $id2 = $this->addShareToDB(2, 'user0', 'user1', 'user2',
+ 'file', 42, 'mytarget', 31, null, null, $id);
+
+ $id3 = $this->addShareToDB(2, 'user3', 'user1', 'user2',
+ 'file', 42, 'mytarget2', 0, null, null, $id);
+
+ $users = [];
+ for($i = 0; $i < 6; $i++) {
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('getUID')->willReturn('user'.$i);
+ $users['user'.$i] = $user;
+ }
+
+ $this->userManager->method('get')->will(
+ $this->returnCallback(function($userId) use ($users) {
+ return $users[$userId];
+ })
+ );
+
+ $groups = [];
+ for($i = 0; $i < 2; $i++) {
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('getGID')->willReturn('group'.$i);
+ $groups['group'.$i] = $group;
+ }
+
+ $this->groupManager->method('get')->will(
+ $this->returnCallback(function($groupId) use ($groups) {
+ return $groups[$groupId];
+ })
+ );
+
+ $file1 = $this->getMock('\OCP\Files\File');
+ $file1->method('getId')->willReturn(42);
+ $file2 = $this->getMock('\OCP\Files\File');
+ $file2->method('getId')->willReturn(43);
+
+ $folder1 = $this->getMock('\OCP\Files\Folder');
+ $folder1->method('getById')->with(42)->willReturn([$file1]);
+ $folder2 = $this->getMock('\OCP\Files\Folder');
+ $folder2->method('getById')->with(43)->willReturn([$file2]);
+
+ $this->rootFolder->method('getUserFolder')->will($this->returnValueMap([
+ ['user2', $folder1],
+ ['user5', $folder2],
+ ]));
+
+ $share = $this->provider->getShareById($id);
+
+ $share->setSharedWith('group0');
+ $share->setSharedBy('user4');
+ $share->setShareOwner('user5');
+ $share->setNode($file2);
+ $share->setPermissions(1);
+
+ $share2 = $this->provider->update($share);
+
+ $this->assertEquals($id, $share2->getId());
+ // Group shares do not allow updating the recipient
+ $this->assertSame('group0', $share2->getSharedWith());
+ $this->assertSame('user4', $share2->getSharedBy());
+ $this->assertSame('user5', $share2->getShareOwner());
+ $this->assertSame(1, $share2->getPermissions());
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $stmt = $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('parent', $qb->createNamedParameter($id)))
+ ->orderBy('id')
+ ->execute();
+
+ $shares = $stmt->fetchAll();
+
+ $this->assertSame('user0', $shares[0]['share_with']);
+ $this->assertSame('user4', $shares[0]['uid_initiator']);
+ $this->assertSame('user5', $shares[0]['uid_owner']);
+ $this->assertSame(1, (int)$shares[0]['permissions']);
+
+ $this->assertSame('user3', $shares[1]['share_with']);
+ $this->assertSame('user4', $shares[1]['uid_initiator']);
+ $this->assertSame('user5', $shares[1]['uid_owner']);
+ $this->assertSame(0, (int)$shares[1]['permissions']);
+
+
+ $stmt->closeCursor();
+ }
+
+ public function testMoveUserShare() {
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_USER, 'user0', 'user1', 'user1', 'file',
+ 42, 'mytaret', 31, null, null);
+
+ $user0 = $this->getMock('\OCP\IUser');
+ $user0->method('getUID')->willReturn('user0');
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['user0', $user0],
+ ['user1', $user1],
+ ]));
+
+ $file = $this->getMock('\OCP\Files\File');
+ $file->method('getId')->willReturn(42);
+
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->willReturn([$file]);
+
+ $share = $this->provider->getShareById($id, null);
+
+ $share->setTarget('/newTarget');
+ $this->provider->move($share, $user0);
+
+ $share = $this->provider->getShareById($id, null);
+ $this->assertSame('/newTarget', $share->getTarget());
+ }
+
+ public function testMoveGroupShare() {
+ $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user1', 'user1', 'file',
+ 42, 'mytaret', 31, null, null);
+
+ $user0 = $this->getMock('\OCP\IUser');
+ $user0->method('getUID')->willReturn('user0');
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+
+ $group0 = $this->getMock('\OCP\IGroup');
+ $group0->method('getGID')->willReturn('group0');
+ $group0->method('inGroup')->with($user0)->willReturn(true);
+
+ $this->groupManager->method('get')->with('group0')->willReturn($group0);
+
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['user0', $user0],
+ ['user1', $user1],
+ ]));
+
+ $folder = $this->getMock('\OCP\Files\Folder');
+ $folder->method('getId')->willReturn(42);
+
+ $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+ $this->rootFolder->method('getById')->willReturn([$folder]);
+
+ $share = $this->provider->getShareById($id, 'user0');
+
+ $share->setTarget('/newTarget');
+ $this->provider->move($share, 'user0');
+
+ $share = $this->provider->getShareById($id, 'user0');
+ $this->assertSame('/newTarget', $share->getTarget());
+
+ $share->setTarget('/ultraNewTarget');
+ $this->provider->move($share, 'user0');
+
+ $share = $this->provider->getShareById($id, 'user0');
+ $this->assertSame('/ultraNewTarget', $share->getTarget());
}
}
diff --git a/tests/lib/share20/managertest.php b/tests/lib/share20/managertest.php
index fc6c30692f5..131bc7fbfd2 100644
--- a/tests/lib/share20/managertest.php
+++ b/tests/lib/share20/managertest.php
@@ -20,179 +20,2129 @@
*/
namespace Test\Share20;
+use OCP\Files\IRootFolder;
+use OCP\IUserManager;
+use OCP\Share\IProviderFactory;
+use OCP\Share\IShare;
use OC\Share20\Manager;
use OC\Share20\Exception;
-
-use OCP\IUser;
-use OCP\IUserManager;
-use OCP\IGroupManager;
+use OC\Share20\Share;
+use OCP\IL10N;
use OCP\ILogger;
-use OCP\IAppConfig;
-use OCP\Files\Folder;
-use OCP\Share20\IShareProvider;
+use OCP\IConfig;
+use OCP\Share\IShareProvider;
+use OCP\Security\ISecureRandom;
+use OCP\Security\IHasher;
+use OCP\Files\Mount\IMountManager;
+use OCP\IGroupManager;
+/**
+ * Class ManagerTest
+ *
+ * @package Test\Share20
+ * @group DB
+ */
class ManagerTest extends \Test\TestCase {
/** @var Manager */
protected $manager;
-
- /** @var IUser */
- protected $user;
-
- /** @var IUserManager */
- protected $userManager;
-
- /** @var IGroupManager */
- protected $groupManager;
-
/** @var ILogger */
protected $logger;
-
- /** @var IAppConfig */
- protected $appConfig;
-
- /** @var Folder */
- protected $userFolder;
-
- /** @var IShareProvider */
+ /** @var IConfig */
+ protected $config;
+ /** @var ISecureRandom */
+ protected $secureRandom;
+ /** @var IHasher */
+ protected $hasher;
+ /** @var IShareProvider | \PHPUnit_Framework_MockObject_MockObject */
protected $defaultProvider;
+ /** @var IMountManager */
+ protected $mountManager;
+ /** @var IGroupManager */
+ protected $groupManager;
+ /** @var IL10N */
+ protected $l;
+ /** @var DummyFactory */
+ protected $factory;
+ /** @var IUserManager */
+ protected $userManager;
+ /** @var IRootFolder | \PHPUnit_Framework_MockObject_MockObject */
+ protected $rootFolder;
public function setUp() {
- $this->user = $this->getMock('\OCP\IUser');
- $this->userManager = $this->getMock('\OCP\IUserManager');
- $this->groupManager = $this->getMock('\OCP\IGroupManager');
$this->logger = $this->getMock('\OCP\ILogger');
- $this->appConfig = $this->getMock('\OCP\IAppConfig');
- $this->userFolder = $this->getMock('\OCP\Files\Folder');
- $this->defaultProvider = $this->getMock('\OC\Share20\IShareProvider');
+ $this->config = $this->getMock('\OCP\IConfig');
+ $this->secureRandom = $this->getMock('\OCP\Security\ISecureRandom');
+ $this->hasher = $this->getMock('\OCP\Security\IHasher');
+ $this->mountManager = $this->getMock('\OCP\Files\Mount\IMountManager');
+ $this->groupManager = $this->getMock('\OCP\IGroupManager');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+ $this->rootFolder = $this->getMock('\OCP\Files\IRootFolder');
+
+ $this->l = $this->getMock('\OCP\IL10N');
+ $this->l->method('t')
+ ->will($this->returnCallback(function($text, $parameters = []) {
+ return vsprintf($text, $parameters);
+ }));
+
+ $this->factory = new DummyFactory(\OC::$server);
$this->manager = new Manager(
- $this->user,
- $this->userManager,
- $this->groupManager,
$this->logger,
- $this->appConfig,
- $this->userFolder,
- $this->defaultProvider
+ $this->config,
+ $this->secureRandom,
+ $this->hasher,
+ $this->mountManager,
+ $this->groupManager,
+ $this->l,
+ $this->factory,
+ $this->userManager,
+ $this->rootFolder
);
+
+ $this->defaultProvider = $this->getMockBuilder('\OC\Share20\DefaultShareProvider')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->defaultProvider->method('identifier')->willReturn('default');
+ $this->factory->setProvider($this->defaultProvider);
+
+
}
/**
- * @expectedException OC\Share20\Exception\ShareNotFound
+ * @return \PHPUnit_Framework_MockObject_MockBuilder
+ */
+ private function createManagerMock() {
+ return $this->getMockBuilder('\OC\Share20\Manager')
+ ->setConstructorArgs([
+ $this->logger,
+ $this->config,
+ $this->secureRandom,
+ $this->hasher,
+ $this->mountManager,
+ $this->groupManager,
+ $this->l,
+ $this->factory,
+ $this->userManager,
+ $this->rootFolder
+ ]);
+ }
+
+ /**
+ * @expectedException \OCP\Share\Exceptions\ShareNotFound
*/
public function testDeleteNoShareId() {
- $share = $this->getMock('\OC\Share20\IShare');
+ $share = $this->getMock('\OCP\Share\IShare');
$share
->expects($this->once())
- ->method('getId')
+ ->method('getFullId')
->with()
->willReturn(null);
$this->manager->deleteShare($share);
}
- public function testDelete() {
- $share = $this->getMock('\OC\Share20\IShare');
+ public function dataTestDelete() {
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('getUID')->willReturn('sharedWithUser');
- $share
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('getGID')->willReturn('sharedWithGroup');
+
+ return [
+ [\OCP\Share::SHARE_TYPE_USER, 'sharedWithUser'],
+ [\OCP\Share::SHARE_TYPE_GROUP, 'sharedWithGroup'],
+ [\OCP\Share::SHARE_TYPE_LINK, ''],
+ [\OCP\Share::SHARE_TYPE_REMOTE, 'foo@bar.com'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestDelete
+ */
+ public function testDelete($shareType, $sharedWith) {
+ $manager = $this->createManagerMock()
+ ->setMethods(['getShareById', 'deleteChildren'])
+ ->getMock();
+
+ $path = $this->getMock('\OCP\Files\File');
+ $path->method('getId')->willReturn(1);
+
+ $share = $this->manager->newShare();
+ $share->setId(42)
+ ->setProviderId('prov')
+ ->setShareType($shareType)
+ ->setSharedWith($sharedWith)
+ ->setSharedBy('sharedBy')
+ ->setNode($path)
+ ->setTarget('myTarget');
+
+ $manager->expects($this->once())->method('getShareById')->with('prov:42')->willReturn($share);
+ $manager->expects($this->once())->method('deleteChildren')->with($share);
+
+ $this->defaultProvider
->expects($this->once())
- ->method('getId')
- ->with()
- ->willReturn(42);
+ ->method('delete')
+ ->with($share);
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['pre', 'post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'pre_unshare', $hookListner, 'pre');
+ \OCP\Util::connectHook('OCP\Share', 'post_unshare', $hookListner, 'post');
+
+ $hookListnerExpectsPre = [
+ 'id' => 42,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => $shareType,
+ 'shareWith' => $sharedWith,
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget',
+ ];
+
+ $hookListnerExpectsPost = [
+ 'id' => 42,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => $shareType,
+ 'shareWith' => $sharedWith,
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget',
+ 'deletedShares' => [
+ [
+ 'id' => 42,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => $shareType,
+ 'shareWith' => $sharedWith,
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget',
+ ],
+ ],
+ ];
+
+
+ $hookListner
+ ->expects($this->exactly(1))
+ ->method('pre')
+ ->with($hookListnerExpectsPre);
+ $hookListner
+ ->expects($this->exactly(1))
+ ->method('post')
+ ->with($hookListnerExpectsPost);
+
+ $manager->deleteShare($share);
+ }
+
+ public function testDeleteLazyShare() {
+ $manager = $this->createManagerMock()
+ ->setMethods(['getShareById', 'deleteChildren'])
+ ->getMock();
+
+ $share = $this->manager->newShare();
+ $share->setId(42)
+ ->setProviderId('prov')
+ ->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setSharedWith('sharedWith')
+ ->setSharedBy('sharedBy')
+ ->setShareOwner('shareOwner')
+ ->setTarget('myTarget')
+ ->setNodeId(1)
+ ->setNodeType('file');
+
+ $this->rootFolder->expects($this->never())->method($this->anything());
+
+ $manager->expects($this->once())->method('getShareById')->with('prov:42')->willReturn($share);
+ $manager->expects($this->once())->method('deleteChildren')->with($share);
+
$this->defaultProvider
->expects($this->once())
->method('delete')
->with($share);
- $this->manager->deleteShare($share);
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['pre', 'post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'pre_unshare', $hookListner, 'pre');
+ \OCP\Util::connectHook('OCP\Share', 'post_unshare', $hookListner, 'post');
+
+ $hookListnerExpectsPre = [
+ 'id' => 42,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_USER,
+ 'shareWith' => 'sharedWith',
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget',
+ ];
+
+ $hookListnerExpectsPost = [
+ 'id' => 42,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_USER,
+ 'shareWith' => 'sharedWith',
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget',
+ 'deletedShares' => [
+ [
+ 'id' => 42,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_USER,
+ 'shareWith' => 'sharedWith',
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget',
+ ],
+ ],
+ ];
+
+
+ $hookListner
+ ->expects($this->exactly(1))
+ ->method('pre')
+ ->with($hookListnerExpectsPre);
+ $hookListner
+ ->expects($this->exactly(1))
+ ->method('post')
+ ->with($hookListnerExpectsPost);
+
+ $manager->deleteShare($share);
}
- /**
- * @expectedException OC\Share20\Exception\ShareNotFound
- */
- public function testGetShareByIdNotFoundInBackend() {
+ public function testDeleteNested() {
+ $manager = $this->createManagerMock()
+ ->setMethods(['getShareById'])
+ ->getMock();
+
+ $path = $this->getMock('\OCP\Files\File');
+ $path->method('getId')->willReturn(1);
+
+ $share1 = $this->manager->newShare();
+ $share1->setId(42)
+ ->setProviderId('prov')
+ ->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setSharedWith('sharedWith1')
+ ->setSharedBy('sharedBy1')
+ ->setNode($path)
+ ->setTarget('myTarget1');
+
+ $share2 = $this->manager->newShare();
+ $share2->setId(43)
+ ->setProviderId('prov')
+ ->setShareType(\OCP\Share::SHARE_TYPE_GROUP)
+ ->setSharedWith('sharedWith2')
+ ->setSharedBy('sharedBy2')
+ ->setNode($path)
+ ->setTarget('myTarget2')
+ ->setParent(42);
+
+ $share3 = $this->manager->newShare();
+ $share3->setId(44)
+ ->setProviderId('prov')
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setSharedBy('sharedBy3')
+ ->setNode($path)
+ ->setTarget('myTarget3')
+ ->setParent(43);
+
+ $manager->expects($this->once())->method('getShareById')->with('prov:42')->willReturn($share1);
+
+ $this->defaultProvider
+ ->method('getChildren')
+ ->will($this->returnValueMap([
+ [$share1, [$share2]],
+ [$share2, [$share3]],
+ [$share3, []],
+ ]));
+
+ $this->defaultProvider
+ ->method('delete')
+ ->withConsecutive($share3, $share2, $share1);
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['pre', 'post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'pre_unshare', $hookListner, 'pre');
+ \OCP\Util::connectHook('OCP\Share', 'post_unshare', $hookListner, 'post');
+
+ $hookListnerExpectsPre = [
+ 'id' => 42,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_USER,
+ 'shareWith' => 'sharedWith1',
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy1',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget1',
+ ];
+
+ $hookListnerExpectsPost = [
+ 'id' => 42,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_USER,
+ 'shareWith' => 'sharedWith1',
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy1',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget1',
+ 'deletedShares' => [
+ [
+ 'id' => 44,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_LINK,
+ 'shareWith' => '',
+ 'itemparent' => 43,
+ 'uidOwner' => 'sharedBy3',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget3',
+ ],
+ [
+ 'id' => 43,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_GROUP,
+ 'shareWith' => 'sharedWith2',
+ 'itemparent' => 42,
+ 'uidOwner' => 'sharedBy2',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget2',
+ ],
+ [
+ 'id' => 42,
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_USER,
+ 'shareWith' => 'sharedWith1',
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy1',
+ 'fileSource' => 1,
+ 'fileTarget' => 'myTarget1',
+ ],
+ ],
+ ];
+
+ $hookListner
+ ->expects($this->exactly(1))
+ ->method('pre')
+ ->with($hookListnerExpectsPre);
+ $hookListner
+ ->expects($this->exactly(1))
+ ->method('post')
+ ->with($hookListnerExpectsPost);
+
+ $manager->deleteShare($share1);
+ }
+
+ public function testDeleteChildren() {
+ $manager = $this->createManagerMock()
+ ->setMethods(['deleteShare'])
+ ->getMock();
+
+ $share = $this->getMock('\OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER);
+
+ $child1 = $this->getMock('\OCP\Share\IShare');
+ $child1->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER);
+ $child2 = $this->getMock('\OCP\Share\IShare');
+ $child2->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER);
+ $child3 = $this->getMock('\OCP\Share\IShare');
+ $child3->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER);
+
+ $shares = [
+ $child1,
+ $child2,
+ $child3,
+ ];
+
+ $this->defaultProvider
+ ->expects($this->exactly(4))
+ ->method('getChildren')
+ ->will($this->returnCallback(function($_share) use ($share, $shares) {
+ if ($_share === $share) {
+ return $shares;
+ }
+ return [];
+ }));
+
+ $this->defaultProvider
+ ->expects($this->exactly(3))
+ ->method('delete')
+ ->withConsecutive($child1, $child2, $child3);
+
+ $result = $this->invokePrivate($manager, 'deleteChildren', [$share]);
+ $this->assertSame($shares, $result);
+ }
+
+ public function testGetShareById() {
+ $share = $this->getMock('\OCP\Share\IShare');
+
$this->defaultProvider
->expects($this->once())
->method('getShareById')
->with(42)
- ->will($this->throwException(new \OC\Share20\Exception\ShareNotFound()));
+ ->willReturn($share);
- $this->manager->getShareById(42);
+ $this->assertEquals($share, $this->manager->getShareById('default:42'));
}
/**
- * @expectedException OC\Share20\Exception\ShareNotFound
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage Passwords are enforced for link shares
*/
- public function testGetShareByIdNotAuthorized() {
- $otherUser1 = $this->getMock('\OCP\IUser');
- $otherUser2 = $this->getMock('\OCP\IUser');
- $otherUser3 = $this->getMock('\OCP\IUser');
+ public function testVerifyPasswordNullButEnforced() {
+ $this->config->method('getAppValue')->will($this->returnValueMap([
+ ['core', 'shareapi_enforce_links_password', 'no', 'yes'],
+ ]));
- $share = $this->getMock('\OC\Share20\IShare');
- $share
- ->expects($this->once())
- ->method('getSharedWith')
- ->with()
- ->willReturn($otherUser1);
- $share
+ $this->invokePrivate($this->manager, 'verifyPassword', [null]);
+ }
+
+ public function testVerifyPasswordNull() {
+ $this->config->method('getAppValue')->will($this->returnValueMap([
+ ['core', 'shareapi_enforce_links_password', 'no', 'no'],
+ ]));
+
+ $result = $this->invokePrivate($this->manager, 'verifyPassword', [null]);
+ $this->assertNull($result);
+ }
+
+ public function testVerifyPasswordHook() {
+ $this->config->method('getAppValue')->will($this->returnValueMap([
+ ['core', 'shareapi_enforce_links_password', 'no', 'no'],
+ ]));
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listner'])->getMock();
+ \OCP\Util::connectHook('\OC\Share', 'verifyPassword', $hookListner, 'listner');
+
+ $hookListner->expects($this->once())
+ ->method('listner')
+ ->with([
+ 'password' => 'password',
+ 'accepted' => true,
+ 'message' => ''
+ ]);
+
+ $result = $this->invokePrivate($this->manager, 'verifyPassword', ['password']);
+ $this->assertNull($result);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage password not accepted
+ */
+ public function testVerifyPasswordHookFails() {
+ $this->config->method('getAppValue')->will($this->returnValueMap([
+ ['core', 'shareapi_enforce_links_password', 'no', 'no'],
+ ]));
+
+ $dummy = new DummyPassword();
+ \OCP\Util::connectHook('\OC\Share', 'verifyPassword', $dummy, 'listner');
+ $this->invokePrivate($this->manager, 'verifyPassword', ['password']);
+ }
+
+ public function createShare($id, $type, $path, $sharedWith, $sharedBy, $shareOwner,
+ $permissions, $expireDate = null, $password = null) {
+ $share = $this->getMock('\OCP\Share\IShare');
+
+ $share->method('getShareType')->willReturn($type);
+ $share->method('getSharedWith')->willReturn($sharedWith);
+ $share->method('getSharedBy')->willReturn($sharedBy);
+ $share->method('getSharedOwner')->willReturn($shareOwner);
+ $share->method('getNode')->willReturn($path);
+ $share->method('getPermissions')->willReturn($permissions);
+ $share->method('getExpirationDate')->willReturn($expireDate);
+ $share->method('getPassword')->willReturn($password);
+
+ return $share;
+ }
+
+ public function dataGeneralChecks() {
+ $user0 = 'user0';
+ $user2 = 'user1';
+ $group0 = 'group0';
+
+ $file = $this->getMock('\OCP\Files\File');
+ $node = $this->getMock('\OCP\Files\Node');
+
+ $data = [
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $file, null, $user0, $user0, 31, null, null), 'SharedWith is not a valid user', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $file, $group0, $user0, $user0, 31, null, null), 'SharedWith is not a valid user', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $file, 'foo@bar.com', $user0, $user0, 31, null, null), 'SharedWith is not a valid user', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $file, null, $user0, $user0, 31, null, null), 'SharedWith is not a valid group', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $file, $user2, $user0, $user0, 31, null, null), 'SharedWith is not a valid group', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $file, 'foo@bar.com', $user0, $user0, 31, null, null), 'SharedWith is not a valid group', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $file, $user2, $user0, $user0, 31, null, null), 'SharedWith should be empty', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $file, $group0, $user0, $user0, 31, null, null), 'SharedWith should be empty', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $file, 'foo@bar.com', $user0, $user0, 31, null, null), 'SharedWith should be empty', true],
+ [$this->createShare(null, -1, $file, null, $user0, $user0, 31, null, null), 'unkown share type', true],
+
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $file, $user2, null, $user0, 31, null, null), 'SharedBy should be set', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $file, $group0, null, $user0, 31, null, null), 'SharedBy should be set', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $file, null, null, $user0, 31, null, null), 'SharedBy should be set', true],
+
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $file, $user0, $user0, $user0, 31, null, null), 'Can\'t share with yourself', true],
+
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, null, $user2, $user0, $user0, 31, null, null), 'Path should be set', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, null, $group0, $user0, $user0, 31, null, null), 'Path should be set', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, null, null, $user0, $user0, 31, null, null), 'Path should be set', true],
+
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $node, $user2, $user0, $user0, 31, null, null), 'Path should be either a file or a folder', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $node, $group0, $user0, $user0, 31, null, null), 'Path should be either a file or a folder', true],
+ [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $node, null, $user0, $user0, 31, null, null), 'Path should be either a file or a folder', true],
+ ];
+
+ $nonShareAble = $this->getMock('\OCP\Files\Folder');
+ $nonShareAble->method('isShareable')->willReturn(false);
+ $nonShareAble->method('getPath')->willReturn('path');
+
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $nonShareAble, $user2, $user0, $user0, 31, null, null), 'You are not allowed to share path', true];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $nonShareAble, $group0, $user0, $user0, 31, null, null), 'You are not allowed to share path', true];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $nonShareAble, null, $user0, $user0, 31, null, null), 'You are not allowed to share path', true];
+
+ $limitedPermssions = $this->getMock('\OCP\Files\File');
+ $limitedPermssions->method('isShareable')->willReturn(true);
+ $limitedPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ);
+ $limitedPermssions->method('getPath')->willReturn('path');
+
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $limitedPermssions, $user2, $user0, $user0, null, null, null), 'A share requires permissions', true];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, null, null, null), 'A share requires permissions', true];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $limitedPermssions, null, $user0, $user0, null, null, null), 'A share requires permissions', true];
+
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $limitedPermssions, $user2, $user0, $user0, 31, null, null), 'Cannot increase permissions of path', true];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, 17, null, null), 'Cannot increase permissions of path', true];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $limitedPermssions, null, $user0, $user0, 3, null, null), 'Cannot increase permissions of path', true];
+
+ $allPermssions = $this->getMock('\OCP\Files\Folder');
+ $allPermssions->method('isShareable')->willReturn(true);
+ $allPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL);
+
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $allPermssions, $user2, $user0, $user0, 30, null, null), 'Shares need at least read permissions', true];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 2, null, null), 'Shares need at least read permissions', true];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $allPermssions, null, $user0, $user0, 16, null, null), 'Shares need at least read permissions', true];
+
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $allPermssions, $user2, $user0, $user0, 31, null, null), null, false];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 3, null, null), null, false];
+ $data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $allPermssions, null, $user0, $user0, 17, null, null), null, false];
+
+ return $data;
+ }
+
+ /**
+ * @dataProvider dataGeneralChecks
+ *
+ * @param $share
+ * @param $exceptionMessage
+ */
+ public function testGeneralChecks($share, $exceptionMessage, $exception) {
+ $thrown = null;
+
+ $this->userManager->method('userExists')->will($this->returnValueMap([
+ ['user0', true],
+ ['user1', true],
+ ]));
+
+ $this->groupManager->method('groupExists')->will($this->returnValueMap([
+ ['group0', true],
+ ]));
+
+ try {
+ $this->invokePrivate($this->manager, 'generalCreateChecks', [$share]);
+ $thrown = false;
+ } catch (\OCP\Share\Exceptions\GenericShareException $e) {
+ $this->assertEquals($exceptionMessage, $e->getHint());
+ $thrown = true;
+ } catch(\InvalidArgumentException $e) {
+ $this->assertEquals($exceptionMessage, $e->getMessage());
+ $thrown = true;
+ }
+
+ $this->assertSame($exception, $thrown);
+ }
+
+ /**
+ * @expectedException \OCP\Share\Exceptions\GenericShareException
+ * @expectedExceptionMessage Expiration date is in the past
+ */
+ public function testvalidateExpirationDateInPast() {
+
+ // Expire date in the past
+ $past = new \DateTime();
+ $past->sub(new \DateInterval('P1D'));
+
+ $share = $this->manager->newShare();
+ $share->setExpirationDate($past);
+
+ $this->invokePrivate($this->manager, 'validateExpirationDate', [$share]);
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage Expiration date is enforced
+ */
+ public function testvalidateExpirationDateEnforceButNotSet() {
+ $share = $this->manager->newShare();
+
+ $this->config->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
+ ]));
+
+ $this->invokePrivate($this->manager, 'validateExpirationDate', [$share]);
+ }
+
+ public function testvalidateExpirationDateEnforceToFarIntoFuture() {
+ // Expire date in the past
+ $future = new \DateTime();
+ $future->add(new \DateInterval('P7D'));
+
+ $share = $this->manager->newShare();
+ $share->setExpirationDate($future);
+
+ $this->config->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
+ ['core', 'shareapi_expire_after_n_days', '7', '3'],
+ ]));
+
+ try {
+ $this->invokePrivate($this->manager, 'validateExpirationDate', [$share]);
+ } catch (\OCP\Share\Exceptions\GenericShareException $e) {
+ $this->assertEquals('Cannot set expiration date more than 3 days in the future', $e->getMessage());
+ $this->assertEquals('Cannot set expiration date more than 3 days in the future', $e->getHint());
+ $this->assertEquals(404, $e->getCode());
+ }
+ }
+
+ public function testvalidateExpirationDateEnforceValid() {
+ // Expire date in the past
+ $future = new \DateTime();
+ $future->add(new \DateInterval('P2D'));
+ $future->setTime(0,0,0);
+
+ $expected = clone $future;
+ $future->setTime(1,2,3);
+
+ $share = $this->manager->newShare();
+ $share->setExpirationDate($future);
+
+ $this->config->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
+ ['core', 'shareapi_expire_after_n_days', '7', '3'],
+ ]));
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock();
+ \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListner, 'listener');
+ $hookListner->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) {
+ return $data['expirationDate'] == $future;
+ }));
+
+ $future = $this->invokePrivate($this->manager, 'validateExpirationDate', [$share]);
+
+ $this->assertEquals($expected, $future);
+ }
+
+ public function testvalidateExpirationDateNoDateNoDefaultNull() {
+ $date = new \DateTime();
+ $date->add(new \DateInterval('P5D'));
+
+ $expected = clone $date;
+ $expected->setTime(0,0,0);
+
+ $share = $this->manager->newShare();
+ $share->setExpirationDate($date);
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock();
+ \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListner, 'listener');
+ $hookListner->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
+ return $data['expirationDate'] == $expected;
+ }));
+
+ $res = $this->invokePrivate($this->manager, 'validateExpirationDate', [$share]);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testvalidateExpirationDateNoDateNoDefault() {
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock();
+ \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListner, 'listener');
+ $hookListner->expects($this->once())->method('listener')->with($this->callback(function ($data) {
+ return $data['expirationDate'] === null;
+ }));
+
+ $share = $this->manager->newShare();
+
+ $date = $this->invokePrivate($this->manager, 'validateExpirationDate', [$share]);
+
+ $this->assertNull($date);
+ }
+
+ public function testvalidateExpirationDateNoDateDefault() {
+ $future = new \DateTime();
+ $future->add(new \DateInterval('P3D'));
+ $future->setTime(0,0,0);
+
+ $expected = clone $future;
+
+ $share = $this->manager->newShare();
+ $share->setExpirationDate($future);
+
+ $this->config->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_default_expire_date', 'no', 'yes'],
+ ['core', 'shareapi_expire_after_n_days', '7', '3'],
+ ]));
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock();
+ \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListner, 'listener');
+ $hookListner->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
+ return $data['expirationDate'] == $expected;
+ }));
+
+ $this->invokePrivate($this->manager, 'validateExpirationDate', [$share]);
+
+ $this->assertEquals($expected, $share->getExpirationDate());
+ }
+
+ public function testValidateExpirationDateHookModification() {
+ $nextWeek = new \DateTime();
+ $nextWeek->add(new \DateInterval('P7D'));
+ $nextWeek->setTime(0,0,0);
+
+ $save = clone $nextWeek;
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock();
+ \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListner, 'listener');
+ $hookListner->expects($this->once())->method('listener')->will($this->returnCallback(function ($data) {
+ $data['expirationDate']->sub(new \DateInterval('P2D'));
+ }));
+
+ $share = $this->manager->newShare();
+ $share->setExpirationDate($nextWeek);
+
+ $this->invokePrivate($this->manager, 'validateExpirationDate', [$share]);
+
+ $save->sub(new \DateInterval('P2D'));
+ $this->assertEquals($save, $share->getExpirationDate());
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Invalid date!
+ */
+ public function testValidateExpirationDateHookException() {
+ $nextWeek = new \DateTime();
+ $nextWeek->add(new \DateInterval('P7D'));
+ $nextWeek->setTime(0,0,0);
+
+ $share = $this->manager->newShare();
+ $share->setExpirationDate($nextWeek);
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock();
+ \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListner, 'listener');
+ $hookListner->expects($this->once())->method('listener')->will($this->returnCallback(function ($data) {
+ $data['accepted'] = false;
+ $data['message'] = 'Invalid date!';
+ }));
+
+ $this->invokePrivate($this->manager, 'validateExpirationDate', [$share]);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Only sharing with group members is allowed
+ */
+ public function testUserCreateChecksShareWithGroupMembersOnlyDifferentGroups() {
+ $share = $this->manager->newShare();
+
+ $sharedBy = $this->getMock('\OCP\IUser');
+ $sharedWith = $this->getMock('\OCP\IUser');
+ $share->setSharedBy('sharedBy')->setSharedWith('sharedWith');
+
+ $this->groupManager
+ ->method('getUserGroupIds')
+ ->will(
+ $this->returnValueMap([
+ [$sharedBy, ['group1']],
+ [$sharedWith, ['group2']],
+ ])
+ );
+
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['sharedBy', $sharedBy],
+ ['sharedWith', $sharedWith],
+ ]));
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
+ ]));
+
+ $this->invokePrivate($this->manager, 'userCreateChecks', [$share]);
+ }
+
+ public function testUserCreateChecksShareWithGroupMembersOnlySharedGroup() {
+ $share = $this->manager->newShare();
+
+ $sharedBy = $this->getMock('\OCP\IUser');
+ $sharedWith = $this->getMock('\OCP\IUser');
+ $share->setSharedBy('sharedBy')->setSharedWith('sharedWith');
+
+ $path = $this->getMock('\OCP\Files\Node');
+ $share->setNode($path);
+
+ $this->groupManager
+ ->method('getUserGroupIds')
+ ->will(
+ $this->returnValueMap([
+ [$sharedBy, ['group1', 'group3']],
+ [$sharedWith, ['group2', 'group3']],
+ ])
+ );
+
+ $this->userManager->method('get')->will($this->returnValueMap([
+ ['sharedBy', $sharedBy],
+ ['sharedWith', $sharedWith],
+ ]));
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
+ ]));
+
+ $this->defaultProvider
+ ->method('getSharesByPath')
+ ->with($path)
+ ->willReturn([]);
+
+ $this->invokePrivate($this->manager, 'userCreateChecks', [$share]);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Path already shared with this user
+ */
+ public function testUserCreateChecksIdenticalShareExists() {
+ $share = $this->manager->newShare();
+ $share2 = $this->manager->newShare();
+
+ $sharedWith = $this->getMock('\OCP\IUser');
+ $path = $this->getMock('\OCP\Files\Node');
+
+ $share->setSharedWith('sharedWith')->setNode($path)
+ ->setProviderId('foo')->setId('bar');
+
+ $share2->setSharedWith('sharedWith')->setNode($path)
+ ->setProviderId('foo')->setId('baz');
+
+ $this->defaultProvider
+ ->method('getSharesByPath')
+ ->with($path)
+ ->willReturn([$share2]);
+
+ $this->invokePrivate($this->manager, 'userCreateChecks', [$share]);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Path already shared with this user
+ */
+ public function testUserCreateChecksIdenticalPathSharedViaGroup() {
+ $share = $this->manager->newShare();
+
+ $sharedWith = $this->getMock('\OCP\IUser');
+ $sharedWith->method('getUID')->willReturn('sharedWith');
+
+ $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith);
+
+ $path = $this->getMock('\OCP\Files\Node');
+
+ $share->setSharedWith('sharedWith')
+ ->setNode($path)
+ ->setShareOwner('shareOwner')
+ ->setProviderId('foo')
+ ->setId('bar');
+
+ $share2 = $this->manager->newShare();
+ $share2->setShareType(\OCP\Share::SHARE_TYPE_GROUP)
+ ->setShareOwner('shareOwner2')
+ ->setProviderId('foo')
+ ->setId('baz')
+ ->setSharedWith('group');
+
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('inGroup')
+ ->with($sharedWith)
+ ->willReturn(true);
+
+ $this->groupManager->method('get')->with('group')->willReturn($group);
+
+ $this->defaultProvider
+ ->method('getSharesByPath')
+ ->with($path)
+ ->willReturn([$share2]);
+
+ $this->invokePrivate($this->manager, 'userCreateChecks', [$share]);
+ }
+
+ public function testUserCreateChecksIdenticalPathNotSharedWithUser() {
+ $share = $this->manager->newShare();
+ $sharedWith = $this->getMock('\OCP\IUser');
+ $path = $this->getMock('\OCP\Files\Node');
+ $share->setSharedWith('sharedWith')
+ ->setNode($path)
+ ->setShareOwner('shareOwner')
+ ->setProviderId('foo')
+ ->setId('bar');
+
+ $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith);
+
+ $share2 = $this->manager->newShare();
+ $share2->setShareType(\OCP\Share::SHARE_TYPE_GROUP)
+ ->setShareOwner('shareOwner2')
+ ->setProviderId('foo')
+ ->setId('baz');
+
+ $group = $this->getMock('\OCP\IGroup');
+ $group->method('inGroup')
+ ->with($sharedWith)
+ ->willReturn(false);
+
+ $this->groupManager->method('get')->with('group')->willReturn($group);
+
+ $share2->setSharedWith('group');
+
+ $this->defaultProvider
+ ->method('getSharesByPath')
+ ->with($path)
+ ->willReturn([$share2]);
+
+ $this->invokePrivate($this->manager, 'userCreateChecks', [$share]);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Only sharing within your own groups is allowed
+ */
+ public function testGroupCreateChecksShareWithGroupMembersOnlyNotInGroup() {
+ $share = $this->manager->newShare();
+
+ $user = $this->getMock('\OCP\IUser');
+ $group = $this->getMock('\OCP\IGroup');
+ $share->setSharedBy('user')->setSharedWith('group');
+
+ $group->method('inGroup')->with($user)->willReturn(false);
+
+ $this->groupManager->method('get')->with('group')->willReturn($group);
+ $this->userManager->method('get')->with('user')->willReturn($user);
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
+ ]));
+
+ $this->invokePrivate($this->manager, 'groupCreateChecks', [$share]);
+ }
+
+ public function testGroupCreateChecksShareWithGroupMembersOnlyInGroup() {
+ $share = $this->manager->newShare();
+
+ $user = $this->getMock('\OCP\IUser');
+ $group = $this->getMock('\OCP\IGroup');
+ $share->setSharedBy('user')->setSharedWith('group');
+
+ $this->userManager->method('get')->with('user')->willReturn($user);
+ $this->groupManager->method('get')->with('group')->willReturn($group);
+
+ $group->method('inGroup')->with($user)->willReturn(true);
+
+ $path = $this->getMock('\OCP\Files\Node');
+ $share->setNode($path);
+
+ $this->defaultProvider->method('getSharesByPath')
+ ->with($path)
+ ->willReturn([]);
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
+ ]));
+
+ $this->invokePrivate($this->manager, 'groupCreateChecks', [$share]);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Path already shared with this group
+ */
+ public function testGroupCreateChecksPathAlreadySharedWithSameGroup() {
+ $share = $this->manager->newShare();
+
+ $path = $this->getMock('\OCP\Files\Node');
+ $share->setSharedWith('sharedWith')
+ ->setNode($path)
+ ->setProviderId('foo')
+ ->setId('bar');
+
+ $share2 = $this->manager->newShare();
+ $share2->setSharedWith('sharedWith')
+ ->setProviderId('foo')
+ ->setId('baz');
+
+ $this->defaultProvider->method('getSharesByPath')
+ ->with($path)
+ ->willReturn([$share2]);
+
+ $this->invokePrivate($this->manager, 'groupCreateChecks', [$share]);
+ }
+
+ public function testGroupCreateChecksPathAlreadySharedWithDifferentGroup() {
+ $share = $this->manager->newShare();
+
+ $share->setSharedWith('sharedWith');
+
+ $path = $this->getMock('\OCP\Files\Node');
+ $share->setNode($path);
+
+ $share2 = $this->manager->newShare();
+ $share2->setSharedWith('sharedWith2');
+
+ $this->defaultProvider->method('getSharesByPath')
+ ->with($path)
+ ->willReturn([$share2]);
+
+ $this->invokePrivate($this->manager, 'groupCreateChecks', [$share]);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Link sharing not allowed
+ */
+ public function testLinkCreateChecksNoLinkSharesAllowed() {
+ $share = $this->manager->newShare();
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_allow_links', 'yes', 'no'],
+ ]));
+
+ $this->invokePrivate($this->manager, 'linkCreateChecks', [$share]);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Link shares can't have reshare permissions
+ */
+ public function testLinkCreateChecksSharePermissions() {
+ $share = $this->manager->newShare();
+
+ $share->setPermissions(\OCP\Constants::PERMISSION_SHARE);
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_allow_links', 'yes', 'yes'],
+ ]));
+
+ $this->invokePrivate($this->manager, 'linkCreateChecks', [$share]);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Link shares can't have delete permissions
+ */
+ public function testLinkCreateChecksDeletePermissions() {
+ $share = $this->manager->newShare();
+
+ $share->setPermissions(\OCP\Constants::PERMISSION_DELETE);
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_allow_links', 'yes', 'yes'],
+ ]));
+
+ $this->invokePrivate($this->manager, 'linkCreateChecks', [$share]);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Public upload not allowed
+ */
+ public function testLinkCreateChecksNoPublicUpload() {
+ $share = $this->manager->newShare();
+
+ $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_allow_links', 'yes', 'yes'],
+ ['core', 'shareapi_allow_public_upload', 'yes', 'no']
+ ]));
+
+ $this->invokePrivate($this->manager, 'linkCreateChecks', [$share]);
+ }
+
+ public function testLinkCreateChecksPublicUpload() {
+ $share = $this->manager->newShare();
+
+ $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_allow_links', 'yes', 'yes'],
+ ['core', 'shareapi_allow_public_upload', 'yes', 'yes']
+ ]));
+
+ $this->invokePrivate($this->manager, 'linkCreateChecks', [$share]);
+ }
+
+ public function testLinkCreateChecksReadOnly() {
+ $share = $this->manager->newShare();
+
+ $share->setPermissions(\OCP\Constants::PERMISSION_READ);
+
+ $this->config
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_allow_links', 'yes', 'yes'],
+ ['core', 'shareapi_allow_public_upload', 'yes', 'no']
+ ]));
+
+ $this->invokePrivate($this->manager, 'linkCreateChecks', [$share]);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Path contains files shared with you
+ */
+ public function testPathCreateChecksContainsSharedMount() {
+ $path = $this->getMock('\OCP\Files\Folder');
+ $path->method('getPath')->willReturn('path');
+
+ $mount = $this->getMock('\OCP\Files\Mount\IMountPoint');
+ $storage = $this->getMock('\OCP\Files\Storage');
+ $mount->method('getStorage')->willReturn($storage);
+ $storage->method('instanceOfStorage')->with('\OCA\Files_Sharing\ISharedStorage')->willReturn(true);
+
+ $this->mountManager->method('findIn')->with('path')->willReturn([$mount]);
+
+ $this->invokePrivate($this->manager, 'pathCreateChecks', [$path]);
+ }
+
+ public function testPathCreateChecksContainsNoSharedMount() {
+ $path = $this->getMock('\OCP\Files\Folder');
+ $path->method('getPath')->willReturn('path');
+
+ $mount = $this->getMock('\OCP\Files\Mount\IMountPoint');
+ $storage = $this->getMock('\OCP\Files\Storage');
+ $mount->method('getStorage')->willReturn($storage);
+ $storage->method('instanceOfStorage')->with('\OCA\Files_Sharing\ISharedStorage')->willReturn(false);
+
+ $this->mountManager->method('findIn')->with('path')->willReturn([$mount]);
+
+ $this->invokePrivate($this->manager, 'pathCreateChecks', [$path]);
+ }
+
+ public function testPathCreateChecksContainsNoFolder() {
+ $path = $this->getMock('\OCP\Files\File');
+
+ $this->invokePrivate($this->manager, 'pathCreateChecks', [$path]);
+ }
+
+ public function dataIsSharingDisabledForUser() {
+ $data = [];
+
+ // No exclude groups
+ $data[] = ['no', null, null, null, false];
+
+ // empty exclude list, user no groups
+ $data[] = ['yes', '', json_encode(['']), [], false];
+
+ // empty exclude list, user groups
+ $data[] = ['yes', '', json_encode(['']), ['group1', 'group2'], false];
+
+ // Convert old list to json
+ $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), [], false];
+
+ // Old list partly groups in common
+ $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false];
+
+ // Old list only groups in common
+ $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], true];
+
+ // New list partly in common
+ $data[] = ['yes', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false];
+
+ // New list only groups in common
+ $data[] = ['yes', json_encode(['group1', 'group2']), null, ['group2'], true];
+
+ return $data;
+ }
+
+ /**
+ * @dataProvider dataIsSharingDisabledForUser
+ *
+ * @param string $excludeGroups
+ * @param string $groupList
+ * @param string $setList
+ * @param string[] $groupIds
+ * @param bool $expected
+ */
+ public function testIsSharingDisabledForUser($excludeGroups, $groupList, $setList, $groupIds, $expected) {
+ $user = $this->getMock('\OCP\IUser');
+
+ $this->config->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_exclude_groups', 'no', $excludeGroups],
+ ['core', 'shareapi_exclude_groups_list', '', $groupList],
+ ]));
+
+ if ($setList !== null) {
+ $this->config->expects($this->once())
+ ->method('setAppValue')
+ ->with('core', 'shareapi_exclude_groups_list', $setList);
+ } else {
+ $this->config->expects($this->never())
+ ->method('setAppValue');
+ }
+
+ $this->groupManager->method('getUserGroupIds')
+ ->with($user)
+ ->willReturn($groupIds);
+
+ $this->userManager->method('get')->with('user')->willReturn($user);
+
+ $res = $this->manager->sharingDisabledForUser('user');
+ $this->assertEquals($expected, $res);
+ }
+
+ public function dataCanShare() {
+ $data = [];
+
+ /*
+ * [expected, sharing enabled, disabled for user]
+ */
+
+ $data[] = [false, 'no', false];
+ $data[] = [false, 'no', true];
+ $data[] = [true, 'yes', false];
+ $data[] = [false, 'yes', true];
+
+ return $data;
+ }
+
+ /**
+ * @dataProvider dataCanShare
+ *
+ * @param bool $expected
+ * @param string $sharingEnabled
+ * @param bool $disabledForUser
+ */
+ public function testCanShare($expected, $sharingEnabled, $disabledForUser) {
+ $this->config->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['core', 'shareapi_enabled', 'yes', $sharingEnabled],
+ ]));
+
+ $manager = $this->createManagerMock()
+ ->setMethods(['sharingDisabledForUser'])
+ ->getMock();
+
+ $manager->method('sharingDisabledForUser')->willReturn($disabledForUser);
+
+ $user = $this->getMock('\OCP\IUser');
+ $share = $this->manager->newShare();
+ $share->setSharedBy('user');
+
+ $res = $this->invokePrivate($manager, 'canShare', [$share]);
+ $this->assertEquals($expected, $res);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage The Share API is disabled
+ */
+ public function testCreateShareCantShare() {
+ $manager = $this->createManagerMock()
+ ->setMethods(['canShare'])
+ ->getMock();
+
+ $manager->expects($this->once())->method('canShare')->willReturn(false);
+ $share = $this->manager->newShare();
+ $manager->createShare($share);
+ }
+
+ public function testCreateShareUser() {
+ $manager = $this->createManagerMock()
+ ->setMethods(['canShare', 'generalCreateChecks', 'userCreateChecks', 'pathCreateChecks'])
+ ->getMock();
+
+ $shareOwner = $this->getMock('\OCP\IUser');
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+
+ $path = $this->getMock('\OCP\Files\File');
+ $path->method('getOwner')->willReturn($shareOwner);
+ $path->method('getName')->willReturn('target');
+
+ $share = $this->createShare(
+ null,
+ \OCP\Share::SHARE_TYPE_USER,
+ $path,
+ 'sharedWith',
+ 'sharedBy',
+ null,
+ \OCP\Constants::PERMISSION_ALL);
+
+ $manager->expects($this->once())
+ ->method('canShare')
+ ->with($share)
+ ->willReturn(true);
+ $manager->expects($this->once())
+ ->method('generalCreateChecks')
+ ->with($share);;
+ $manager->expects($this->once())
+ ->method('userCreateChecks')
+ ->with($share);;
+ $manager->expects($this->once())
+ ->method('pathCreateChecks')
+ ->with($path);
+
+ $this->defaultProvider
->expects($this->once())
- ->method('getSharedBy')
- ->with()
- ->willReturn($otherUser2);
- $share
+ ->method('create')
+ ->with($share)
+ ->will($this->returnArgument(0));
+
+ $share->expects($this->once())
+ ->method('setShareOwner')
+ ->with('shareOwner');
+ $share->expects($this->once())
+ ->method('setTarget')
+ ->with('/target');
+
+ $manager->createShare($share);
+ }
+
+ public function testCreateShareGroup() {
+ $manager = $this->createManagerMock()
+ ->setMethods(['canShare', 'generalCreateChecks', 'groupCreateChecks', 'pathCreateChecks'])
+ ->getMock();
+
+ $shareOwner = $this->getMock('\OCP\IUser');
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+
+ $path = $this->getMock('\OCP\Files\File');
+ $path->method('getOwner')->willReturn($shareOwner);
+ $path->method('getName')->willReturn('target');
+
+ $share = $this->createShare(
+ null,
+ \OCP\Share::SHARE_TYPE_GROUP,
+ $path,
+ 'sharedWith',
+ 'sharedBy',
+ null,
+ \OCP\Constants::PERMISSION_ALL);
+
+ $manager->expects($this->once())
+ ->method('canShare')
+ ->with($share)
+ ->willReturn(true);
+ $manager->expects($this->once())
+ ->method('generalCreateChecks')
+ ->with($share);;
+ $manager->expects($this->once())
+ ->method('groupCreateChecks')
+ ->with($share);;
+ $manager->expects($this->once())
+ ->method('pathCreateChecks')
+ ->with($path);
+
+ $this->defaultProvider
->expects($this->once())
- ->method('getShareOwner')
- ->with()
- ->willReturn($otherUser3);
+ ->method('create')
+ ->with($share)
+ ->will($this->returnArgument(0));
+
+ $share->expects($this->once())
+ ->method('setShareOwner')
+ ->with('shareOwner');
+ $share->expects($this->once())
+ ->method('setTarget')
+ ->with('/target');
+
+ $manager->createShare($share);
+ }
+
+ public function testCreateShareLink() {
+ $manager = $this->createManagerMock()
+ ->setMethods([
+ 'canShare',
+ 'generalCreateChecks',
+ 'linkCreateChecks',
+ 'pathCreateChecks',
+ 'validateExpirationDate',
+ 'verifyPassword',
+ ])
+ ->getMock();
+
+ $shareOwner = $this->getMock('\OCP\IUser');
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+
+ $path = $this->getMock('\OCP\Files\File');
+ $path->method('getOwner')->willReturn($shareOwner);
+ $path->method('getName')->willReturn('target');
+ $path->method('getId')->willReturn(1);
+
+ $date = new \DateTime();
+
+ $share = $this->manager->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setNode($path)
+ ->setSharedBy('sharedBy')
+ ->setPermissions(\OCP\Constants::PERMISSION_ALL)
+ ->setExpirationDate($date)
+ ->setPassword('password');
+
+ $manager->expects($this->once())
+ ->method('canShare')
+ ->with($share)
+ ->willReturn(true);
+ $manager->expects($this->once())
+ ->method('generalCreateChecks')
+ ->with($share);;
+ $manager->expects($this->once())
+ ->method('linkCreateChecks')
+ ->with($share);;
+ $manager->expects($this->once())
+ ->method('pathCreateChecks')
+ ->with($path);
+ $manager->expects($this->once())
+ ->method('validateExpirationDate')
+ ->with($share);
+ $manager->expects($this->once())
+ ->method('verifyPassword')
+ ->with('password');
+
+ $this->hasher->expects($this->once())
+ ->method('hash')
+ ->with('password')
+ ->willReturn('hashed');
+
+ $this->secureRandom->method('getMediumStrengthGenerator')
+ ->will($this->returnSelf());
+ $this->secureRandom->method('generate')
+ ->willReturn('token');
$this->defaultProvider
->expects($this->once())
- ->method('getShareById')
- ->with(42)
+ ->method('create')
+ ->with($share)
+ ->will($this->returnCallback(function(Share $share) {
+ return $share->setId(42);
+ }));
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['pre', 'post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'pre_shared', $hookListner, 'pre');
+ \OCP\Util::connectHook('OCP\Share', 'post_shared', $hookListner, 'post');
+
+ $hookListnerExpectsPre = [
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_LINK,
+ 'uidOwner' => 'sharedBy',
+ 'permissions' => 31,
+ 'fileSource' => 1,
+ 'expiration' => $date,
+ 'token' => 'token',
+ 'run' => true,
+ 'error' => '',
+ 'itemTarget' => '/target',
+ 'shareWith' => null,
+ ];
+
+ $hookListnerExpectsPost = [
+ 'itemType' => 'file',
+ 'itemSource' => 1,
+ 'shareType' => \OCP\Share::SHARE_TYPE_LINK,
+ 'uidOwner' => 'sharedBy',
+ 'permissions' => 31,
+ 'fileSource' => 1,
+ 'expiration' => $date,
+ 'token' => 'token',
+ 'id' => 42,
+ 'itemTarget' => '/target',
+ 'fileTarget' => '/target',
+ 'shareWith' => null,
+ ];
+
+ $hookListner->expects($this->once())
+ ->method('pre')
+ ->with($this->equalTo($hookListnerExpectsPre));
+ $hookListner->expects($this->once())
+ ->method('post')
+ ->with($this->equalTo($hookListnerExpectsPost));
+
+ /** @var IShare $share */
+ $share = $manager->createShare($share);
+
+ $this->assertSame('shareOwner', $share->getShareOwner());
+ $this->assertEquals('/target', $share->getTarget());
+ $this->assertSame($date, $share->getExpirationDate());
+ $this->assertEquals('token', $share->getToken());
+ $this->assertEquals('hashed', $share->getPassword());
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage I won't let you share
+ */
+ public function testCreateShareHookError() {
+ $manager = $this->createManagerMock()
+ ->setMethods([
+ 'canShare',
+ 'generalCreateChecks',
+ 'userCreateChecks',
+ 'pathCreateChecks',
+ ])
+ ->getMock();
+
+ $shareOwner = $this->getMock('\OCP\IUser');
+ $shareOwner->method('getUID')->willReturn('shareOwner');
+
+ $path = $this->getMock('\OCP\Files\File');
+ $path->method('getOwner')->willReturn($shareOwner);
+ $path->method('getName')->willReturn('target');
+
+ $share = $this->createShare(
+ null,
+ \OCP\Share::SHARE_TYPE_USER,
+ $path,
+ 'sharedWith',
+ 'sharedBy',
+ null,
+ \OCP\Constants::PERMISSION_ALL);
+
+ $manager->expects($this->once())
+ ->method('canShare')
+ ->with($share)
+ ->willReturn(true);
+ $manager->expects($this->once())
+ ->method('generalCreateChecks')
+ ->with($share);;
+ $manager->expects($this->once())
+ ->method('userCreateChecks')
+ ->with($share);;
+ $manager->expects($this->once())
+ ->method('pathCreateChecks')
+ ->with($path);
+
+ $share->expects($this->once())
+ ->method('setShareOwner')
+ ->with('shareOwner');
+ $share->expects($this->once())
+ ->method('setTarget')
+ ->with('/target');
+
+ $dummy = new DummyCreate();
+ \OCP\Util::connectHook('OCP\Share', 'pre_shared', $dummy, 'listner');
+
+ $manager->createShare($share);
+ }
+
+ public function testGetShareByToken() {
+ $factory = $this->getMock('\OCP\Share\IProviderFactory');
+
+ $manager = new Manager(
+ $this->logger,
+ $this->config,
+ $this->secureRandom,
+ $this->hasher,
+ $this->mountManager,
+ $this->groupManager,
+ $this->l,
+ $factory,
+ $this->userManager,
+ $this->rootFolder
+ );
+
+ $share = $this->getMock('\OCP\Share\IShare');
+
+ $factory->expects($this->once())
+ ->method('getProviderForType')
+ ->with(\OCP\Share::SHARE_TYPE_LINK)
+ ->willReturn($this->defaultProvider);
+
+ $this->defaultProvider->expects($this->once())
+ ->method('getShareByToken')
+ ->with('token')
->willReturn($share);
- $this->manager->getShareById(42);
+ $ret = $manager->getShareByToken('token');
+ $this->assertSame($share, $ret);
}
- public function dataGetShareById() {
- return [
- ['getSharedWith'],
- ['getSharedBy'],
- ['getShareOwner'],
- ];
+ public function testCheckPasswordNoLinkShare() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER);
+ $this->assertFalse($this->manager->checkPassword($share, 'password'));
+ }
+
+ public function testCheckPasswordNoPassword() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_LINK);
+ $this->assertFalse($this->manager->checkPassword($share, 'password'));
+
+ $share->method('getPassword')->willReturn('password');
+ $this->assertFalse($this->manager->checkPassword($share, null));
+ }
+
+ public function testCheckPasswordInvalidPassword() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_LINK);
+ $share->method('getPassword')->willReturn('password');
+
+ $this->hasher->method('verify')->with('invalidpassword', 'password', '')->willReturn(false);
+
+ $this->assertFalse($this->manager->checkPassword($share, 'invalidpassword'));
+ }
+
+ public function testCheckPasswordValidPassword() {
+ $share = $this->getMock('\OCP\Share\IShare');
+ $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_LINK);
+ $share->method('getPassword')->willReturn('passwordHash');
+
+ $this->hasher->method('verify')->with('password', 'passwordHash', '')->willReturn(true);
+
+ $this->assertTrue($this->manager->checkPassword($share, 'password'));
+ }
+
+ public function testCheckPasswordUpdateShare() {
+ $share = $this->manager->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setPassword('passwordHash');
+
+ $this->hasher->method('verify')->with('password', 'passwordHash', '')
+ ->will($this->returnCallback(function($pass, $hash, &$newHash) {
+ $newHash = 'newHash';
+
+ return true;
+ }));
+
+ $this->defaultProvider->expects($this->once())
+ ->method('update')
+ ->with($this->callback(function (\OCP\Share\IShare $share) {
+ return $share->getPassword() === 'newHash';
+ }));
+
+ $this->assertTrue($this->manager->checkPassword($share, 'password'));
}
/**
- * @dataProvider dataGetShareById
+ * @expectedException Exception
+ * @expectedExceptionMessage The Share API is disabled
*/
- public function testGetShareById($currentUserIs) {
- $otherUser1 = $this->getMock('\OCP\IUser');
- $otherUser2 = $this->getMock('\OCP\IUser');
- $otherUser3 = $this->getMock('\OCP\IUser');
+ public function testUpdateShareCantShare() {
+ $manager = $this->createManagerMock()
+ ->setMethods(['canShare'])
+ ->getMock();
- $share = $this->getMock('\OC\Share20\IShare');
- $share
- ->method('getSharedWith')
- ->with()
- ->willReturn($currentUserIs === 'getSharedWith' ? $this->user : $otherUser1);
- $share
- ->method('getSharedBy')
- ->with()
- ->willReturn($currentUserIs === 'getSharedBy' ? $this->user : $otherUser2);
- $share
- ->method('getShareOwner')
- ->with()
- ->willReturn($currentUserIs === 'getShareOwner' ? $this->user : $otherUser3);
+ $manager->expects($this->once())->method('canShare')->willReturn(false);
+ $share = $this->manager->newShare();
+ $manager->updateShare($share);
+ }
- $this->defaultProvider
- ->expects($this->once())
- ->method('getShareById')
- ->with(42)
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Can't change share type
+ */
+ public function testUpdateShareCantChangeShareType() {
+ $manager = $this->createManagerMock()
+ ->setMethods([
+ 'canShare',
+ 'getShareById'
+ ])
+ ->getMock();
+
+ $originalShare = $this->manager->newShare();
+ $originalShare->setShareType(\OCP\Share::SHARE_TYPE_GROUP);
+
+ $manager->expects($this->once())->method('canShare')->willReturn(true);
+ $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
+
+ $share = $this->manager->newShare();
+ $share->setProviderId('foo')
+ ->setId('42')
+ ->setShareType(\OCP\Share::SHARE_TYPE_USER);
+
+ $manager->updateShare($share);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Can only update recipient on user shares
+ */
+ public function testUpdateShareCantChangeRecipientForGroupShare() {
+ $manager = $this->createManagerMock()
+ ->setMethods([
+ 'canShare',
+ 'getShareById'
+ ])
+ ->getMock();
+
+ $originalShare = $this->manager->newShare();
+ $originalShare->setShareType(\OCP\Share::SHARE_TYPE_GROUP)
+ ->setSharedWith('origGroup');
+
+ $manager->expects($this->once())->method('canShare')->willReturn(true);
+ $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
+
+ $share = $this->manager->newShare();
+ $share->setProviderId('foo')
+ ->setId('42')
+ ->setShareType(\OCP\Share::SHARE_TYPE_GROUP)
+ ->setSharedWith('newGroup');
+
+ $manager->updateShare($share);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Can't share with the share owner
+ */
+ public function testUpdateShareCantShareWithOwner() {
+ $manager = $this->createManagerMock()
+ ->setMethods([
+ 'canShare',
+ 'getShareById'
+ ])
+ ->getMock();
+
+ $originalShare = $this->manager->newShare();
+ $originalShare->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setSharedWith('sharedWith');
+
+ $manager->expects($this->once())->method('canShare')->willReturn(true);
+ $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
+
+ $share = $this->manager->newShare();
+ $share->setProviderId('foo')
+ ->setId('42')
+ ->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setSharedWith('newUser')
+ ->setShareOwner('newUser');
+
+ $manager->updateShare($share);
+ }
+
+ public function testUpdateShareUser() {
+ $manager = $this->createManagerMock()
+ ->setMethods([
+ 'canShare',
+ 'getShareById',
+ 'generalCreateChecks',
+ 'userCreateChecks',
+ 'pathCreateChecks',
+ ])
+ ->getMock();
+
+ $originalShare = $this->manager->newShare();
+ $originalShare->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setSharedWith('origUser')
+ ->setPermissions(1);
+
+ $node = $this->getMock('\OCP\Files\File');
+ $node->method('getId')->willReturn(100);
+ $node->method('getPath')->willReturn('/newUser/files/myPath');
+
+ $manager->expects($this->once())->method('canShare')->willReturn(true);
+ $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
+
+ $share = $this->manager->newShare();
+ $share->setProviderId('foo')
+ ->setId('42')
+ ->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setSharedWith('origUser')
+ ->setShareOwner('newUser')
+ ->setSharedBy('sharer')
+ ->setPermissions(31)
+ ->setNode($node);
+
+ $this->defaultProvider->expects($this->once())
+ ->method('update')
+ ->with($share)
+ ->willReturn($share);
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListner, 'post');
+ $hookListner->expects($this->never())->method('post');
+
+ $this->rootFolder->method('getUserFolder')->with('newUser')->will($this->returnSelf());
+ $this->rootFolder->method('getRelativePath')->with('/newUser/files/myPath')->willReturn('/myPath');
+
+ $hookListner2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListner2, 'post');
+ $hookListner2->expects($this->once())->method('post')->with([
+ 'itemType' => 'file',
+ 'itemSource' => 100,
+ 'shareType' => \OCP\Share::SHARE_TYPE_USER,
+ 'shareWith' => 'origUser',
+ 'uidOwner' => 'sharer',
+ 'permissions' => 31,
+ 'path' => '/myPath',
+ ]);
+
+ $manager->updateShare($share);
+ }
+
+ public function testUpdateShareGroup() {
+ $manager = $this->createManagerMock()
+ ->setMethods([
+ 'canShare',
+ 'getShareById',
+ 'generalCreateChecks',
+ 'groupCreateChecks',
+ 'pathCreateChecks',
+ ])
+ ->getMock();
+
+ $originalShare = $this->manager->newShare();
+ $originalShare->setShareType(\OCP\Share::SHARE_TYPE_GROUP)
+ ->setSharedWith('origUser')
+ ->setPermissions(31);
+
+ $manager->expects($this->once())->method('canShare')->willReturn(true);
+ $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
+
+ $node = $this->getMock('\OCP\Files\File');
+
+ $share = $this->manager->newShare();
+ $share->setProviderId('foo')
+ ->setId('42')
+ ->setShareType(\OCP\Share::SHARE_TYPE_GROUP)
+ ->setSharedWith('origUser')
+ ->setShareOwner('owner')
+ ->setNode($node)
+ ->setPermissions(31);
+
+ $this->defaultProvider->expects($this->once())
+ ->method('update')
+ ->with($share)
->willReturn($share);
- $this->assertEquals($share, $this->manager->getShareById(42));
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListner, 'post');
+ $hookListner->expects($this->never())->method('post');
+
+ $hookListner2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListner2, 'post');
+ $hookListner2->expects($this->never())->method('post');
+
+ $manager->updateShare($share);
+ }
+
+ public function testUpdateShareLink() {
+ $manager = $this->createManagerMock()
+ ->setMethods([
+ 'canShare',
+ 'getShareById',
+ 'generalCreateChecks',
+ 'linkCreateChecks',
+ 'pathCreateChecks',
+ 'verifyPassword',
+ 'validateExpirationDate',
+ ])
+ ->getMock();
+
+ $originalShare = $this->manager->newShare();
+ $originalShare->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setPermissions(15);
+
+ $tomorrow = new \DateTime();
+ $tomorrow->setTime(0,0,0);
+ $tomorrow->add(new \DateInterval('P1D'));
+
+ $file = $this->getMock('OCP\Files\File', [], [], 'File');
+ $file->method('getId')->willReturn(100);
+
+ $share = $this->manager->newShare();
+ $share->setProviderId('foo')
+ ->setId('42')
+ ->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setSharedBy('owner')
+ ->setShareOwner('owner')
+ ->setPassword('password')
+ ->setExpirationDate($tomorrow)
+ ->setNode($file)
+ ->setPermissions(15);
+
+ $manager->expects($this->once())->method('canShare')->willReturn(true);
+ $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
+ $manager->expects($this->once())->method('validateExpirationDate')->with($share);
+
+ $this->defaultProvider->expects($this->once())
+ ->method('update')
+ ->with($share)
+ ->willReturn($share);
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListner, 'post');
+ $hookListner->expects($this->once())->method('post')->with([
+ 'itemType' => 'file',
+ 'itemSource' => 100,
+ 'date' => $tomorrow,
+ 'uidOwner' => 'owner',
+ ]);
+
+ $hookListner2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListner2, 'post');
+ $hookListner2->expects($this->never())->method('post');
+
+
+ $manager->updateShare($share);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Can't change target of link share
+ */
+ public function testMoveShareLink() {
+ $share = $this->manager->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_LINK);
+
+ $recipient = $this->getMock('\OCP\IUser');
+
+ $this->manager->moveShare($share, $recipient);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Invalid recipient
+ */
+ public function testMoveShareUserNotRecipient() {
+ $share = $this->manager->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_USER);
+
+ $share->setSharedWith('sharedWith');
+
+ $this->manager->moveShare($share, 'recipient');
+ }
+
+ public function testMoveShareUser() {
+ $share = $this->manager->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_USER);
+
+ $share->setSharedWith('recipient');
+
+ $this->defaultProvider->method('move')->with($share, 'recipient')->will($this->returnArgument(0));
+
+ $this->manager->moveShare($share, 'recipient');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Invalid recipient
+ */
+ public function testMoveShareGroupNotRecipient() {
+ $share = $this->manager->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_GROUP);
+
+ $sharedWith = $this->getMock('\OCP\IGroup');
+ $share->setSharedWith('shareWith');
+
+ $recipient = $this->getMock('\OCP\IUser');
+ $sharedWith->method('inGroup')->with($recipient)->willReturn(false);
+
+ $this->groupManager->method('get')->with('shareWith')->willReturn($sharedWith);
+ $this->userManager->method('get')->with('recipient')->willReturn($recipient);
+
+ $this->manager->moveShare($share, 'recipient');
+ }
+
+ public function testMoveShareGroup() {
+ $share = $this->manager->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_GROUP);
+
+ $group = $this->getMock('\OCP\IGroup');
+ $share->setSharedWith('group');
+
+ $recipient = $this->getMock('\OCP\IUser');
+ $group->method('inGroup')->with($recipient)->willReturn(true);
+
+ $this->groupManager->method('get')->with('group')->willReturn($group);
+ $this->userManager->method('get')->with('recipient')->willReturn($recipient);
+
+ $this->defaultProvider->method('move')->with($share, 'recipient')->will($this->returnArgument(0));
+
+ $this->manager->moveShare($share, 'recipient');
+ }
+}
+
+class DummyPassword {
+ public function listner($array) {
+ $array['accepted'] = false;
+ $array['message'] = 'password not accepted';
+ }
+}
+
+class DummyCreate {
+ public function listner($array) {
+ $array['run'] = false;
+ $array['error'] = 'I won\'t let you share!';
}
}
+
+class DummyFactory implements IProviderFactory {
+
+ /** @var IShareProvider */
+ private $provider;
+
+ public function __construct(\OCP\IServerContainer $serverContainer) {
+
+ }
+
+ /**
+ * @param IShareProvider $provider
+ */
+ public function setProvider($provider) {
+ $this->provider = $provider;
+ }
+
+ /**
+ * @param string $id
+ * @return IShareProvider
+ */
+ public function getProvider($id) {
+ return $this->provider;
+ }
+
+ /**
+ * @param int $shareType
+ * @return IShareProvider
+ */
+ public function getProviderForType($shareType) {
+ return $this->provider;
+ }
+} \ No newline at end of file
diff --git a/tests/lib/streamwrappers.php b/tests/lib/streamwrappers.php
index 6216c5a4be8..7175683a60b 100644
--- a/tests/lib/streamwrappers.php
+++ b/tests/lib/streamwrappers.php
@@ -20,6 +20,11 @@
*
*/
+/**
+ * Class Test_StreamWrappers
+ *
+ * @group DB
+ */
class Test_StreamWrappers extends \Test\TestCase {
private static $trashBinStatus;
@@ -50,7 +55,7 @@ class Test_StreamWrappers extends \Test\TestCase {
public function testCloseStream() {
//ensure all basic stream stuff works
$sourceFile = OC::$SERVERROOT . '/tests/data/lorem.txt';
- $tmpFile = OC_Helper::TmpFile('.txt');
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile('.txt');
$file = 'close://' . $tmpFile;
$this->assertTrue(file_exists($file));
file_put_contents($file, file_get_contents($sourceFile));
@@ -60,7 +65,7 @@ class Test_StreamWrappers extends \Test\TestCase {
$this->assertFalse(file_exists($file));
//test callback
- $tmpFile = OC_Helper::TmpFile('.txt');
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile('.txt');
$file = 'close://' . $tmpFile;
$actual = false;
$callback = function($path) use (&$actual) { $actual = $path; };
diff --git a/tests/lib/systemtag/systemtagmanagertest.php b/tests/lib/systemtag/systemtagmanagertest.php
new file mode 100644
index 00000000000..64220205ade
--- /dev/null
+++ b/tests/lib/systemtag/systemtagmanagertest.php
@@ -0,0 +1,424 @@
+<?php
+
+/**
+ * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ *
+*/
+
+namespace Test\SystemTag;
+
+use OC\SystemTag\SystemTagManager;
+use OC\SystemTag\SystemTagObjectMapper;
+use OCP\IDBConnection;
+use OCP\SystemTag\ISystemTag;
+use OCP\SystemTag\ISystemTagManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Test\TestCase;
+
+/**
+ * Class TestSystemTagManager
+ *
+ * @group DB
+ * @package Test\SystemTag
+ */
+class SystemTagManagerTest extends TestCase {
+
+ /**
+ * @var ISystemTagManager
+ **/
+ private $tagManager;
+
+ /**
+ * @var IDBConnection
+ */
+ private $connection;
+
+ /**
+ * @var EventDispatcherInterface
+ */
+ private $dispatcher;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->connection = \OC::$server->getDatabaseConnection();
+
+ $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')
+ ->getMock();
+
+ $this->tagManager = new SystemTagManager(
+ $this->connection,
+ $this->dispatcher
+ );
+ $this->pruneTagsTables();
+ }
+
+ public function tearDown() {
+ $this->pruneTagsTables();
+ parent::tearDown();
+ }
+
+ protected function pruneTagsTables() {
+ $query = $this->connection->getQueryBuilder();
+ $query->delete(SystemTagObjectMapper::RELATION_TABLE)->execute();
+ $query->delete(SystemTagManager::TAG_TABLE)->execute();
+ }
+
+ public function getAllTagsDataProvider() {
+ return [
+ [
+ // no tags at all
+ []
+ ],
+ [
+ // simple
+ [
+ ['one', false, false],
+ ['two', false, false],
+ ]
+ ],
+ [
+ // duplicate names, different flags
+ [
+ ['one', false, false],
+ ['one', true, false],
+ ['one', false, true],
+ ['one', true, true],
+ ['two', false, false],
+ ['two', false, true],
+ ]
+ ]
+ ];
+ }
+
+ /**
+ * @dataProvider getAllTagsDataProvider
+ */
+ public function testGetAllTags($testTags) {
+ $testTagsById = [];
+ foreach ($testTags as $testTag) {
+ $tag = $this->tagManager->createTag($testTag[0], $testTag[1], $testTag[2]);
+ $testTagsById[$tag->getId()] = $tag;
+ }
+
+ $tagList = $this->tagManager->getAllTags();
+
+ $this->assertCount(count($testTags), $tagList);
+
+ foreach ($testTagsById as $testTagId => $testTag) {
+ $this->assertTrue(isset($tagList[$testTagId]));
+ $this->assertSameTag($tagList[$testTagId], $testTag);
+ }
+ }
+
+ public function getAllTagsFilteredDataProvider() {
+ return [
+ [
+ [
+ // no tags at all
+ ],
+ null,
+ null,
+ []
+ ],
+ // filter by visibile only
+ [
+ // none visible
+ [
+ ['one', false, false],
+ ['two', false, false],
+ ],
+ true,
+ null,
+ []
+ ],
+ [
+ // one visible
+ [
+ ['one', true, false],
+ ['two', false, false],
+ ],
+ true,
+ null,
+ [
+ ['one', true, false],
+ ]
+ ],
+ [
+ // one invisible
+ [
+ ['one', true, false],
+ ['two', false, false],
+ ],
+ false,
+ null,
+ [
+ ['two', false, false],
+ ]
+ ],
+ // filter by name pattern
+ [
+ [
+ ['one', true, false],
+ ['one', false, false],
+ ['two', true, false],
+ ],
+ null,
+ 'on',
+ [
+ ['one', true, false],
+ ['one', false, false],
+ ]
+ ],
+ // filter by name pattern and visibility
+ [
+ // one visible
+ [
+ ['one', true, false],
+ ['two', true, false],
+ ['one', false, false],
+ ],
+ true,
+ 'on',
+ [
+ ['one', true, false],
+ ]
+ ],
+ // filter by name pattern in the middle
+ [
+ // one visible
+ [
+ ['abcdefghi', true, false],
+ ['two', true, false],
+ ],
+ null,
+ 'def',
+ [
+ ['abcdefghi', true, false],
+ ]
+ ]
+ ];
+ }
+
+ /**
+ * @dataProvider getAllTagsFilteredDataProvider
+ */
+ public function testGetAllTagsFiltered($testTags, $visibilityFilter, $nameSearch, $expectedResults) {
+ foreach ($testTags as $testTag) {
+ $this->tagManager->createTag($testTag[0], $testTag[1], $testTag[2]);
+ }
+
+ $testTagsById = [];
+ foreach ($expectedResults as $expectedTag) {
+ $tag = $this->tagManager->getTag($expectedTag[0], $expectedTag[1], $expectedTag[2]);
+ $testTagsById[$tag->getId()] = $tag;
+ }
+
+ $tagList = $this->tagManager->getAllTags($visibilityFilter, $nameSearch);
+
+ $this->assertCount(count($testTagsById), $tagList);
+
+ foreach ($testTagsById as $testTagId => $testTag) {
+ $this->assertTrue(isset($tagList[$testTagId]));
+ $this->assertSameTag($tagList[$testTagId], $testTag);
+ }
+ }
+
+ public function oneTagMultipleFlagsProvider() {
+ return [
+ ['one', false, false],
+ ['one', true, false],
+ ['one', false, true],
+ ['one', true, true],
+ ];
+ }
+
+ /**
+ * @dataProvider oneTagMultipleFlagsProvider
+ * @expectedException \OCP\SystemTag\TagAlreadyExistsException
+ */
+ public function testCreateDuplicate($name, $userVisible, $userAssignable) {
+ try {
+ $this->tagManager->createTag($name, $userVisible, $userAssignable);
+ } catch (\Exception $e) {
+ $this->assertTrue(false, 'No exception thrown for the first create call');
+ }
+ $this->tagManager->createTag($name, $userVisible, $userAssignable);
+ }
+
+ /**
+ * @dataProvider oneTagMultipleFlagsProvider
+ */
+ public function testGetExistingTag($name, $userVisible, $userAssignable) {
+ $tag1 = $this->tagManager->createTag($name, $userVisible, $userAssignable);
+ $tag2 = $this->tagManager->getTag($name, $userVisible, $userAssignable);
+
+ $this->assertSameTag($tag1, $tag2);
+ }
+
+ public function testGetExistingTagById() {
+ $tag1 = $this->tagManager->createTag('one', true, false);
+ $tag2 = $this->tagManager->createTag('two', false, true);
+
+ $tagList = $this->tagManager->getTagsByIds([$tag1->getId(), $tag2->getId()]);
+
+ $this->assertCount(2, $tagList);
+
+ $this->assertSameTag($tag1, $tagList[$tag1->getId()]);
+ $this->assertSameTag($tag2, $tagList[$tag2->getId()]);
+ }
+
+ /**
+ * @expectedException \OCP\SystemTag\TagNotFoundException
+ */
+ public function testGetNonExistingTag() {
+ $this->tagManager->getTag('nonexist', false, false);
+ }
+
+ /**
+ * @expectedException \OCP\SystemTag\TagNotFoundException
+ */
+ public function testGetNonExistingTagsById() {
+ $tag1 = $this->tagManager->createTag('one', true, false);
+ $this->tagManager->getTagsByIds([$tag1->getId(), 100, 101]);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testGetInvalidTagIdFormat() {
+ $tag1 = $this->tagManager->createTag('one', true, false);
+ $this->tagManager->getTagsByIds([$tag1->getId() . 'suffix']);
+ }
+
+ public function updateTagProvider() {
+ return [
+ [
+ // update name
+ ['one', true, true],
+ ['two', true, true]
+ ],
+ [
+ // update one flag
+ ['one', false, true],
+ ['one', true, true]
+ ],
+ [
+ // update all flags
+ ['one', false, false],
+ ['one', true, true]
+ ],
+ [
+ // update all
+ ['one', false, false],
+ ['two', true, true]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider updateTagProvider
+ */
+ public function testUpdateTag($tagCreate, $tagUpdated) {
+ $tag1 = $this->tagManager->createTag(
+ $tagCreate[0],
+ $tagCreate[1],
+ $tagCreate[2]
+ );
+ $this->tagManager->updateTag(
+ $tag1->getId(),
+ $tagUpdated[0],
+ $tagUpdated[1],
+ $tagUpdated[2]
+ );
+ $tag2 = $this->tagManager->getTag(
+ $tagUpdated[0],
+ $tagUpdated[1],
+ $tagUpdated[2]
+ );
+
+ $this->assertEquals($tag2->getId(), $tag1->getId());
+ $this->assertEquals($tag2->getName(), $tagUpdated[0]);
+ $this->assertEquals($tag2->isUserVisible(), $tagUpdated[1]);
+ $this->assertEquals($tag2->isUserAssignable(), $tagUpdated[2]);
+ }
+
+ /**
+ * @dataProvider updateTagProvider
+ * @expectedException \OCP\SystemTag\TagAlreadyExistsException
+ */
+ public function testUpdateTagDuplicate($tagCreate, $tagUpdated) {
+ $this->tagManager->createTag(
+ $tagCreate[0],
+ $tagCreate[1],
+ $tagCreate[2]
+ );
+ $tag2 = $this->tagManager->createTag(
+ $tagUpdated[0],
+ $tagUpdated[1],
+ $tagUpdated[2]
+ );
+
+ // update to match the first tag
+ $this->tagManager->updateTag(
+ $tag2->getId(),
+ $tagCreate[0],
+ $tagCreate[1],
+ $tagCreate[2]
+ );
+ }
+
+ public function testDeleteTags() {
+ $tag1 = $this->tagManager->createTag('one', true, false);
+ $tag2 = $this->tagManager->createTag('two', false, true);
+
+ $this->tagManager->deleteTags([$tag1->getId(), $tag2->getId()]);
+
+ $this->assertEmpty($this->tagManager->getAllTags());
+ }
+
+ /**
+ * @expectedException \OCP\SystemTag\TagNotFoundException
+ */
+ public function testDeleteNonExistingTag() {
+ $this->tagManager->deleteTags([100]);
+ }
+
+ public function testDeleteTagRemovesRelations() {
+ $tag1 = $this->tagManager->createTag('one', true, false);
+ $tag2 = $this->tagManager->createTag('two', true, true);
+
+ $tagMapper = new SystemTagObjectMapper($this->connection, $this->tagManager, $this->dispatcher);
+
+ $tagMapper->assignTags(1, 'testtype', $tag1->getId());
+ $tagMapper->assignTags(1, 'testtype', $tag2->getId());
+ $tagMapper->assignTags(2, 'testtype', $tag1->getId());
+
+ $this->tagManager->deleteTags($tag1->getId());
+
+ $tagIdMapping = $tagMapper->getTagIdsForObjects(
+ [1, 2],
+ 'testtype'
+ );
+
+ $this->assertEquals([
+ 1 => [$tag2->getId()],
+ 2 => [],
+ ], $tagIdMapping);
+ }
+
+ /**
+ * @param ISystemTag $tag1
+ * @param ISystemTag $tag2
+ */
+ private function assertSameTag($tag1, $tag2) {
+ $this->assertEquals($tag1->getId(), $tag2->getId());
+ $this->assertEquals($tag1->getName(), $tag2->getName());
+ $this->assertEquals($tag1->isUserVisible(), $tag2->isUserVisible());
+ $this->assertEquals($tag1->isUserAssignable(), $tag2->isUserAssignable());
+ }
+
+}
diff --git a/tests/lib/systemtag/systemtagobjectmappertest.php b/tests/lib/systemtag/systemtagobjectmappertest.php
new file mode 100644
index 00000000000..5c8204f6a87
--- /dev/null
+++ b/tests/lib/systemtag/systemtagobjectmappertest.php
@@ -0,0 +1,354 @@
+<?php
+
+/**
+ * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ *
+*/
+
+namespace Test\SystemTag;
+
+use OC\SystemTag\SystemTag;
+use OC\SystemTag\SystemTagManager;
+use OC\SystemTag\SystemTagObjectMapper;
+use OCP\IDBConnection;
+use OCP\SystemTag\ISystemTag;
+use OCP\SystemTag\ISystemTagManager;
+use OCP\SystemTag\ISystemTagObjectMapper;
+use OCP\SystemTag\TagNotFoundException;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Test\TestCase;
+
+/**
+ * Class TestSystemTagObjectMapper
+ *
+ * @group DB
+ * @package Test\SystemTag
+ */
+class SystemTagObjectMapperTest extends TestCase {
+
+ /**
+ * @var ISystemTagManager
+ **/
+ private $tagManager;
+
+ /**
+ * @var ISystemTagObjectMapper
+ **/
+ private $tagMapper;
+
+ /**
+ * @var IDBConnection
+ */
+ private $connection;
+
+ /**
+ * @var EventDispatcherInterface
+ */
+ private $dispatcher;
+
+ /**
+ * @var ISystemTag
+ */
+ private $tag1;
+
+ /**
+ * @var ISystemTag
+ */
+ private $tag2;
+
+ /**
+ * @var ISystemTag
+ */
+ private $tag3;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->connection = \OC::$server->getDatabaseConnection();
+ $this->pruneTagsTables();
+
+ $this->tagManager = $this->getMockBuilder('OCP\SystemTag\ISystemTagManager')
+ ->getMock();
+
+ $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')
+ ->getMock();
+
+ $this->tagMapper = new SystemTagObjectMapper(
+ $this->connection,
+ $this->tagManager,
+ $this->dispatcher
+ );
+
+ $this->tag1 = new SystemTag(1, 'testtag1', false, false);
+ $this->tag2 = new SystemTag(2, 'testtag2', true, false);
+ $this->tag3 = new SystemTag(3, 'testtag3', false, false);
+
+ $this->tagManager->expects($this->any())
+ ->method('getTagsByIds')
+ ->will($this->returnCallback(function($tagIds) {
+ $result = [];
+ if (in_array(1, $tagIds)) {
+ $result[1] = $this->tag1;
+ }
+ if (in_array(2, $tagIds)) {
+ $result[2] = $this->tag2;
+ }
+ if (in_array(3, $tagIds)) {
+ $result[3] = $this->tag3;
+ }
+ return $result;
+ }));
+
+ $this->tagMapper->assignTags(1, 'testtype', $this->tag1->getId());
+ $this->tagMapper->assignTags(1, 'testtype', $this->tag2->getId());
+ $this->tagMapper->assignTags(2, 'testtype', $this->tag1->getId());
+ $this->tagMapper->assignTags(3, 'anothertype', $this->tag1->getId());
+ }
+
+ public function tearDown() {
+ $this->pruneTagsTables();
+ parent::tearDown();
+ }
+
+ protected function pruneTagsTables() {
+ $query = $this->connection->getQueryBuilder();
+ $query->delete(SystemTagObjectMapper::RELATION_TABLE)->execute();
+ $query->delete(SystemTagManager::TAG_TABLE)->execute();
+ }
+
+ public function testGetTagsForObjects() {
+ $tagIdMapping = $this->tagMapper->getTagIdsForObjects(
+ [1, 2, 3, 4],
+ 'testtype'
+ );
+
+ $this->assertEquals([
+ 1 => [$this->tag1->getId(), $this->tag2->getId()],
+ 2 => [$this->tag1->getId()],
+ 3 => [],
+ 4 => [],
+ ], $tagIdMapping);
+ }
+
+ public function testGetObjectsForTags() {
+ $objectIds = $this->tagMapper->getObjectIdsForTags(
+ [$this->tag1->getId(), $this->tag2->getId(), $this->tag3->getId()],
+ 'testtype'
+ );
+
+ $this->assertEquals([
+ 1,
+ 2,
+ ], $objectIds);
+ }
+
+ /**
+ * @expectedException \OCP\SystemTag\TagNotFoundException
+ */
+ public function testGetObjectsForNonExistingTag() {
+ $this->tagMapper->getObjectIdsForTags(
+ [100],
+ 'testtype'
+ );
+ }
+
+ public function testAssignUnassignTags() {
+ $this->tagMapper->unassignTags(1, 'testtype', [$this->tag1->getId()]);
+
+ $tagIdMapping = $this->tagMapper->getTagIdsForObjects(1, 'testtype');
+ $this->assertEquals([
+ 1 => [$this->tag2->getId()],
+ ], $tagIdMapping);
+
+ $this->tagMapper->assignTags(1, 'testtype', [$this->tag1->getId()]);
+ $this->tagMapper->assignTags(1, 'testtype', $this->tag3->getId());
+
+ $tagIdMapping = $this->tagMapper->getTagIdsForObjects(1, 'testtype');
+
+ $this->assertEquals([
+ 1 => [$this->tag1->getId(), $this->tag2->getId(), $this->tag3->getId()],
+ ], $tagIdMapping);
+ }
+
+ public function testReAssignUnassignTags() {
+ // reassign tag1
+ $this->tagMapper->assignTags(1, 'testtype', [$this->tag1->getId()]);
+
+ // tag 3 was never assigned
+ $this->tagMapper->unassignTags(1, 'testtype', [$this->tag3->getId()]);
+
+ $this->assertTrue(true, 'No error when reassigning/unassigning');
+ }
+
+ /**
+ * @expectedException \OCP\SystemTag\TagNotFoundException
+ */
+ public function testAssignNonExistingTags() {
+ $this->tagMapper->assignTags(1, 'testtype', [100]);
+ }
+
+ public function testAssignNonExistingTagInArray() {
+ $caught = false;
+ try {
+ $this->tagMapper->assignTags(1, 'testtype', [100, $this->tag3->getId()]);
+ } catch (TagNotFoundException $e) {
+ $caught = true;
+ }
+
+ $this->assertTrue($caught, 'Exception thrown');
+
+ $tagIdMapping = $this->tagMapper->getTagIdsForObjects(
+ [1],
+ 'testtype'
+ );
+
+ $this->assertEquals([
+ 1 => [$this->tag1->getId(), $this->tag2->getId()],
+ ], $tagIdMapping, 'None of the tags got assigned');
+ }
+
+ /**
+ * @expectedException \OCP\SystemTag\TagNotFoundException
+ */
+ public function testUnassignNonExistingTags() {
+ $this->tagMapper->unassignTags(1, 'testtype', [100]);
+ }
+
+ public function testUnassignNonExistingTagsInArray() {
+ $caught = false;
+ try {
+ $this->tagMapper->unassignTags(1, 'testtype', [100, $this->tag1->getId()]);
+ } catch (TagNotFoundException $e) {
+ $caught = true;
+ }
+
+ $this->assertTrue($caught, 'Exception thrown');
+
+ $tagIdMapping = $this->tagMapper->getTagIdsForObjects(
+ [1],
+ 'testtype'
+ );
+
+ $this->assertEquals([
+ 1 => [$this->tag1->getId(), $this->tag2->getId()],
+ ], $tagIdMapping, 'None of the tags got unassigned');
+ }
+
+ public function testHaveTagAllMatches() {
+ $this->assertTrue(
+ $this->tagMapper->haveTag(
+ [1],
+ 'testtype',
+ $this->tag1->getId(),
+ true
+ ),
+ 'object 1 has the tag tag1'
+ );
+
+ $this->assertTrue(
+ $this->tagMapper->haveTag(
+ [1, 2],
+ 'testtype',
+ $this->tag1->getId(),
+ true
+ ),
+ 'object 1 and object 2 ALL have the tag tag1'
+ );
+
+ $this->assertFalse(
+ $this->tagMapper->haveTag(
+ [1, 2],
+ 'testtype',
+ $this->tag2->getId(),
+ true
+ ),
+ 'object 1 has tag2 but not object 2, so not ALL of them'
+ );
+
+ $this->assertFalse(
+ $this->tagMapper->haveTag(
+ [2],
+ 'testtype',
+ $this->tag2->getId(),
+ true
+ ),
+ 'object 2 does not have tag2'
+ );
+
+ $this->assertFalse(
+ $this->tagMapper->haveTag(
+ [3],
+ 'testtype',
+ $this->tag2->getId(),
+ true
+ ),
+ 'object 3 does not have tag1 due to different type'
+ );
+ }
+
+ public function testHaveTagAtLeastOneMatch() {
+ $this->assertTrue(
+ $this->tagMapper->haveTag(
+ [1],
+ 'testtype',
+ $this->tag1->getId(),
+ false
+ ),
+ 'object1 has the tag tag1'
+ );
+
+ $this->assertTrue(
+ $this->tagMapper->haveTag(
+ [1, 2],
+ 'testtype',
+ $this->tag1->getId(),
+ false
+ ),
+ 'object 1 and object 2 both the tag tag1'
+ );
+
+ $this->assertTrue(
+ $this->tagMapper->haveTag(
+ [1, 2],
+ 'testtype',
+ $this->tag2->getId(),
+ false
+ ),
+ 'at least object 1 has the tag tag2'
+ );
+
+ $this->assertFalse(
+ $this->tagMapper->haveTag(
+ [2],
+ 'testtype',
+ $this->tag2->getId(),
+ false
+ ),
+ 'object 2 does not have tag2'
+ );
+
+ $this->assertFalse(
+ $this->tagMapper->haveTag(
+ [3],
+ 'testtype',
+ $this->tag2->getId(),
+ false
+ ),
+ 'object 3 does not have tag1 due to different type'
+ );
+ }
+
+ /**
+ * @expectedException \OCP\SystemTag\TagNotFoundException
+ */
+ public function testHaveTagNonExisting() {
+ $this->tagMapper->haveTag(
+ [1],
+ 'testtype',
+ 100
+ );
+ }
+}
diff --git a/tests/lib/tags.php b/tests/lib/tags.php
index 1a13d64679d..91472d5ceb8 100644
--- a/tests/lib/tags.php
+++ b/tests/lib/tags.php
@@ -20,12 +20,17 @@
*
*/
+/**
+ * Class Test_Tags
+ *
+ * @group DB
+ */
class Test_Tags extends \Test\TestCase {
protected $objectType;
- /** @var \OC\IUser */
+ /** @var \OCP\IUser */
protected $user;
- /** @var \OC\IUserSession */
+ /** @var \OCP\IUserSession */
protected $userSession;
protected $backupGlobals = FALSE;
/** @var \OC\Tagging\TagMapper */
@@ -39,7 +44,7 @@ class Test_Tags extends \Test\TestCase {
OC_User::clearBackends();
OC_User::useBackend('dummy');
$userId = $this->getUniqueID('user_');
- OC_User::createUser($userId, 'pass');
+ \OC::$server->getUserManager()->createUser($userId, 'pass');
OC_User::setUserId($userId);
$this->user = new OC\User\User($userId, null);
$this->userSession = $this->getMock('\OCP\IUserSession');
@@ -55,7 +60,7 @@ class Test_Tags extends \Test\TestCase {
}
protected function tearDown() {
- $conn = \OC_DB::getConnection();
+ $conn = \OC::$server->getDatabaseConnection();
$conn->executeQuery('DELETE FROM `*PREFIX*vcategory_to_object`');
$conn->executeQuery('DELETE FROM `*PREFIX*vcategory`');
@@ -194,7 +199,7 @@ class Test_Tags extends \Test\TestCase {
$tagId = $tagData[0]['id'];
$tagType = $tagData[0]['type'];
- $conn = \OC_DB::getConnection();
+ $conn = \OC::$server->getDatabaseConnection();
$statement = $conn->prepare(
'INSERT INTO `*PREFIX*vcategory_to_object` ' .
'(`objid`, `categoryid`, `type`) VALUES ' .
@@ -285,7 +290,7 @@ class Test_Tags extends \Test\TestCase {
$tagger->tagAs(1, $testTag);
$otherUserId = $this->getUniqueID('user2_');
- OC_User::createUser($otherUserId, 'pass');
+ \OC::$server->getUserManager()->createUser($otherUserId, 'pass');
OC_User::setUserId($otherUserId);
$otherUserSession = $this->getMock('\OCP\IUserSession');
$otherUserSession
diff --git a/tests/lib/testcase.php b/tests/lib/testcase.php
index 8cfa2a72598..008b96b3417 100644
--- a/tests/lib/testcase.php
+++ b/tests/lib/testcase.php
@@ -25,13 +25,56 @@ namespace Test;
use OC\Command\QueueBus;
use OC\Files\Filesystem;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
use OCP\Security\ISecureRandom;
abstract class TestCase extends \PHPUnit_Framework_TestCase {
+ /** @var \OC\Command\QueueBus */
+ private $commandBus;
+
+ /** @var IDBConnection */
+ static protected $realDatabase = null;
+ static private $wasDatabaseAllowed = false;
+
+ /** @var array */
+ protected $services = [];
+
/**
- * @var \OC\Command\QueueBus
+ * @param string $name
+ * @param mixed $newService
+ * @return bool
*/
- private $commandBus;
+ public function overwriteService($name, $newService) {
+ if (isset($this->services[$name])) {
+ return false;
+ }
+
+ $this->services[$name] = \OC::$server->query($name);
+ \OC::$server->registerService($name, function () use ($newService) {
+ return $newService;
+ });
+
+ return true;
+ }
+
+ /**
+ * @param string $name
+ * @return bool
+ */
+ public function restoreService($name) {
+ if (isset($this->services[$name])) {
+ $oldService = $this->services[$name];
+ \OC::$server->registerService($name, function () use ($oldService) {
+ return $oldService;
+ });
+
+
+ unset($this->services[$name]);
+ return true;
+ }
+
+ return false;
+ }
protected function getTestTraits() {
$traits = [];
@@ -49,6 +92,18 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
}
protected function setUp() {
+ // detect database access
+ self::$wasDatabaseAllowed = true;
+ if (!$this->IsDatabaseAccessAllowed()) {
+ self::$wasDatabaseAllowed = false;
+ if (is_null(self::$realDatabase)) {
+ self::$realDatabase = \OC::$server->getDatabaseConnection();
+ }
+ \OC::$server->registerService('DatabaseConnection', function () {
+ $this->fail('Your test case is not allowed to access the database.');
+ });
+ }
+
// overwrite the command bus with one we can run ourselves
$this->commandBus = new QueueBus();
\OC::$server->registerService('AsyncCommandBus', function () {
@@ -65,6 +120,14 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
}
protected function tearDown() {
+ // restore database connection
+ if (!$this->IsDatabaseAccessAllowed()) {
+ \OC::$server->registerService('DatabaseConnection', function () {
+ return self::$realDatabase;
+ });
+ }
+
+ // further cleanup
$hookExceptions = \OC_Hook::$thrownExceptions;
\OC_Hook::$thrownExceptions = [];
\OC::$server->getLockingProvider()->releaseAll();
@@ -72,6 +135,12 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
throw $hookExceptions[0];
}
+ // fail hard if xml errors have not been cleaned up
+ $errors = libxml_get_errors();
+ libxml_clear_errors();
+ $this->assertEquals([], $errors);
+
+ // tearDown the traits
$traits = $this->getTestTraits();
foreach ($traits as $trait) {
$methodName = 'tearDown' . basename(str_replace('\\', '/', $trait));
@@ -121,7 +190,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
* @return string
*/
protected static function getUniqueID($prefix = '', $length = 13) {
- return $prefix . \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(
+ return $prefix . \OC::$server->getSecureRandom()->generate(
$length,
// Do not use dots and slashes as we use the value for file names
ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER
@@ -129,12 +198,21 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
}
public static function tearDownAfterClass() {
+ if (!self::$wasDatabaseAllowed && self::$realDatabase !== null) {
+ // in case an error is thrown in a test, PHPUnit jumps straight to tearDownAfterClass,
+ // so we need the database again
+ \OC::$server->registerService('DatabaseConnection', function () {
+ return self::$realDatabase;
+ });
+ }
$dataDir = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data-autotest');
- $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ if (self::$wasDatabaseAllowed && \OC::$server->getDatabaseConnection()) {
+ $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
- self::tearDownAfterClassCleanShares($queryBuilder);
- self::tearDownAfterClassCleanStorages($queryBuilder);
- self::tearDownAfterClassCleanFileCache($queryBuilder);
+ self::tearDownAfterClassCleanShares($queryBuilder);
+ self::tearDownAfterClassCleanStorages($queryBuilder);
+ self::tearDownAfterClassCleanFileCache($queryBuilder);
+ }
self::tearDownAfterClassCleanStrayDataFiles($dataDir);
self::tearDownAfterClassCleanStrayHooks();
self::tearDownAfterClassCleanStrayLocks();
@@ -316,4 +394,18 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
return true;
}
}
+
+ private function IsDatabaseAccessAllowed() {
+ // on travis-ci.org we allow database access in any case - otherwise
+ // this will break all apps right away
+ if (true == getenv('TRAVIS')) {
+ return true;
+ }
+ $annotations = $this->getAnnotations();
+ if (isset($annotations['class']['group']) && in_array('DB', $annotations['class']['group'])) {
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/tests/lib/updater.php b/tests/lib/updater.php
index 1651fe1759d..8ee77b9f81e 100644
--- a/tests/lib/updater.php
+++ b/tests/lib/updater.php
@@ -24,9 +24,10 @@ namespace OC;
use OCP\IConfig;
use OCP\ILogger;
+use OC\IntegrityCheck\Checker;
class UpdaterTest extends \Test\TestCase {
- /** @var IConfig */
+ /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
private $config;
/** @var HTTPHelper */
private $httpHelper;
@@ -34,6 +35,8 @@ class UpdaterTest extends \Test\TestCase {
private $logger;
/** @var Updater */
private $updater;
+ /** @var Checker */
+ private $checker;
public function setUp() {
parent::setUp();
@@ -46,10 +49,14 @@ class UpdaterTest extends \Test\TestCase {
$this->logger = $this->getMockBuilder('\\OCP\\ILogger')
->disableOriginalConstructor()
->getMock();
+ $this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker')
+ ->disableOriginalConstructor()
+ ->getMock();
$this->updater = new Updater(
$this->httpHelper,
$this->config,
+ $this->checker,
$this->logger
);
}
@@ -59,7 +66,7 @@ class UpdaterTest extends \Test\TestCase {
* @return string
*/
private function buildUpdateUrl($baseUrl) {
- return $baseUrl . '?version='.implode('x', \OC_Util::getVersion()).'xinstalledatxlastupdatedatx'.\OC_Util::getChannel().'x'.\OC_Util::getEditionString().'x';
+ return $baseUrl . '?version='.implode('x', \OCP\Util::getVersion()).'xinstalledatxlastupdatedatx'.\OC_Util::getChannel().'x'.\OC_Util::getEditionString().'x';
}
/**
@@ -129,9 +136,33 @@ class UpdaterTest extends \Test\TestCase {
['9.0.0.0', '8.0.0.0', '7.0', false],
['9.1.0.0', '8.0.0.0', '7.0', false],
['8.2.0.0', '8.1.0.0', '8.0', false],
+
+ // With debug enabled
+ ['8.0.0.0', '8.2.0.0', '8.1', false, true],
+ ['8.1.0.0', '8.2.0.0', '8.1', true, true],
+ ['8.2.0.1', '8.2.0.1', '8.1', true, true],
+ ['8.3.0.0', '8.2.0.0', '8.1', true, true],
];
}
+ /**
+ * @dataProvider versionCompatibilityTestData
+ *
+ * @param string $oldVersion
+ * @param string $newVersion
+ * @param string $allowedVersion
+ * @param bool $result
+ * @param bool $debug
+ */
+ public function testIsUpgradePossible($oldVersion, $newVersion, $allowedVersion, $result, $debug = false) {
+ $this->config->expects($this->any())
+ ->method('getSystemValue')
+ ->with('debug', false)
+ ->willReturn($debug);
+
+ $this->assertSame($result, $this->updater->isUpgradePossible($oldVersion, $newVersion, $allowedVersion));
+ }
+
public function testSetSimulateStepEnabled() {
$this->updater->setSimulateStepEnabled(true);
$this->assertSame(true, $this->invokePrivate($this->updater, 'simulateStepEnabled'));
@@ -153,18 +184,6 @@ class UpdaterTest extends \Test\TestCase {
$this->assertSame(false, $this->invokePrivate($this->updater, 'skip3rdPartyAppsDisable'));
}
- /**
- * @dataProvider versionCompatibilityTestData
- *
- * @param string $oldVersion
- * @param string $newVersion
- * @param bool $result
- */
- public function testIsUpgradePossible($oldVersion, $newVersion, $allowedVersion, $result) {
- $updater = new Updater($this->httpHelper, $this->config, $this->logger);
- $this->assertSame($result, $updater->isUpgradePossible($oldVersion, $newVersion, $allowedVersion));
- }
-
public function testCheckInCache() {
$expectedResult = [
'version' => '8.0.4.2',
diff --git a/tests/lib/urlgenerator.php b/tests/lib/urlGenerator.php
index a5ab483109f..07103225baa 100644
--- a/tests/lib/urlgenerator.php
+++ b/tests/lib/urlGenerator.php
@@ -6,7 +6,12 @@
* See the COPYING-README file.
*/
-class Test_Urlgenerator extends \Test\TestCase {
+/**
+ * Class Test_UrlGenerator
+ *
+ * @group DB
+ */
+class Test_UrlGenerator extends \Test\TestCase {
/**
* @small
diff --git a/tests/lib/user.php b/tests/lib/user.php
index 3c068be2826..c4c74cbc254 100644
--- a/tests/lib/user.php
+++ b/tests/lib/user.php
@@ -9,6 +9,13 @@
namespace Test;
+/**
+ * Class User
+ *
+ * @group DB
+ *
+ * @package Test
+ */
class User extends TestCase {
/**
* @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend
@@ -19,7 +26,7 @@ class User extends TestCase {
parent::setUp();
$this->backend = $this->getMock('\Test\Util\User\Dummy');
- $manager = \OC_User::getManager();
+ $manager = \OC::$server->getUserManager();
$manager->registerBackend($this->backend);
}
@@ -44,30 +51,5 @@ class User extends TestCase {
$uid = \OC_User::checkPassword('foo', 'bar');
$this->assertEquals($uid, 'foo');
}
-
- public function testDeleteUser() {
- $fail = \OC_User::deleteUser('victim');
- $this->assertFalse($fail);
-
- $success = \OC_User::createUser('victim', 'password');
-
- $success = \OC_User::deleteUser('victim');
- $this->assertTrue($success);
- }
-
- public function testCreateUser(){
- $this->backend->expects($this->any())
- ->method('implementsActions')
- ->will($this->returnCallback(function ($actions) {
- if ($actions === \OC_USER_BACKEND_CREATE_USER) {
- return true;
- } else {
- return false;
- }
- }));
-
- $user = \OC_User::createUser('newuser', 'newpassword');
- $this->assertEquals('newuser', $user->getUid());
- }
-} \ No newline at end of file
+}
diff --git a/tests/lib/user/database.php b/tests/lib/user/database.php
index 3a6be1ceee5..ba44d333a8c 100644
--- a/tests/lib/user/database.php
+++ b/tests/lib/user/database.php
@@ -20,6 +20,11 @@
*
*/
+/**
+ * Class Test_User_Database
+ *
+ * @group DB
+ */
class Test_User_Database extends Test_User_Backend {
/** @var array */
private $users;
diff --git a/tests/lib/user/manager.php b/tests/lib/user/manager.php
index df673f581c4..90e2f67c995 100644
--- a/tests/lib/user/manager.php
+++ b/tests/lib/user/manager.php
@@ -9,6 +9,13 @@
namespace Test\User;
+/**
+ * Class Manager
+ *
+ * @group DB
+ *
+ * @package Test\User
+ */
class Manager extends \Test\TestCase {
public function testGetBackends() {
$userDummyBackend = $this->getMock('\Test\Util\User\Dummy');
@@ -441,11 +448,25 @@ class Manager extends \Test\TestCase {
}
public function testDeleteUser() {
- $manager = new \OC\User\Manager();
+ $config = $this->getMockBuilder('OCP\IConfig')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $config
+ ->expects($this->at(0))
+ ->method('getUserValue')
+ ->with('foo', 'core', 'enabled')
+ ->will($this->returnValue(true));
+ $config
+ ->expects($this->at(1))
+ ->method('getUserValue')
+ ->with('foo', 'login', 'lastLogin')
+ ->will($this->returnValue(0));
+
+ $manager = new \OC\User\Manager($config);
$backend = new \Test\Util\User\Dummy();
- $backend->createUser('foo', 'bar');
$manager->registerBackend($backend);
+ $backend->createUser('foo', 'bar');
$this->assertTrue($manager->userExists('foo'));
$manager->get('foo')->delete();
$this->assertFalse($manager->userExists('foo'));
diff --git a/tests/lib/user/session.php b/tests/lib/user/session.php
index d9dace2ef05..1c042dec9f0 100644
--- a/tests/lib/user/session.php
+++ b/tests/lib/user/session.php
@@ -12,6 +12,10 @@ namespace Test\User;
use OC\Session\Memory;
use OC\User\User;
+/**
+ * @group DB
+ * @package Test\User
+ */
class Session extends \Test\TestCase {
public function testGetUser() {
$session = $this->getMock('\OC\Session\Memory', array(), array(''));
@@ -95,6 +99,8 @@ class Session extends \Test\TestCase {
public function testLoginValidPasswordEnabled() {
$session = $this->getMock('\OC\Session\Memory', array(), array(''));
+ $session->expects($this->once())
+ ->method('regenerateId');
$session->expects($this->exactly(2))
->method('set')
->with($this->callback(function ($key) {
@@ -148,6 +154,8 @@ class Session extends \Test\TestCase {
$session = $this->getMock('\OC\Session\Memory', array(), array(''));
$session->expects($this->never())
->method('set');
+ $session->expects($this->once())
+ ->method('regenerateId');
$managerMethods = get_class_methods('\OC\User\Manager');
//keep following methods intact in order to ensure hooks are
@@ -179,10 +187,12 @@ class Session extends \Test\TestCase {
$userSession->login('foo', 'bar');
}
- public function testLoginInValidPassword() {
+ public function testLoginInvalidPassword() {
$session = $this->getMock('\OC\Session\Memory', array(), array(''));
$session->expects($this->never())
->method('set');
+ $session->expects($this->once())
+ ->method('regenerateId');
$managerMethods = get_class_methods('\OC\User\Manager');
//keep following methods intact in order to ensure hooks are
@@ -217,6 +227,8 @@ class Session extends \Test\TestCase {
$session = $this->getMock('\OC\Session\Memory', array(), array(''));
$session->expects($this->never())
->method('set');
+ $session->expects($this->once())
+ ->method('regenerateId');
$manager = $this->getMock('\OC\User\Manager');
@@ -244,6 +256,8 @@ class Session extends \Test\TestCase {
}
},
'foo'));
+ $session->expects($this->once())
+ ->method('regenerateId');
$managerMethods = get_class_methods('\OC\User\Manager');
//keep following methods intact in order to ensure hooks are
@@ -292,6 +306,8 @@ class Session extends \Test\TestCase {
$session = $this->getMock('\OC\Session\Memory', array(), array(''));
$session->expects($this->never())
->method('set');
+ $session->expects($this->once())
+ ->method('regenerateId');
$managerMethods = get_class_methods('\OC\User\Manager');
//keep following methods intact in order to ensure hooks are
@@ -334,6 +350,8 @@ class Session extends \Test\TestCase {
$session = $this->getMock('\OC\Session\Memory', array(), array(''));
$session->expects($this->never())
->method('set');
+ $session->expects($this->once())
+ ->method('regenerateId');
$managerMethods = get_class_methods('\OC\User\Manager');
//keep following methods intact in order to ensure hooks are
diff --git a/tests/lib/user/user.php b/tests/lib/user/user.php
index bc1365d35bf..a8d688d9c88 100644
--- a/tests/lib/user/user.php
+++ b/tests/lib/user/user.php
@@ -11,6 +11,13 @@ namespace Test\User;
use OC\Hooks\PublicEmitter;
+/**
+ * Class User
+ *
+ * @group DB
+ *
+ * @package Test\User
+ */
class User extends \Test\TestCase {
public function testDisplayName() {
/**
@@ -335,7 +342,8 @@ class User extends \Test\TestCase {
$backend->expects($this->once())
->method('setDisplayName')
- ->with('foo','Foo');
+ ->with('foo','Foo')
+ ->willReturn(true);
$user = new \OC\User\User('foo', $backend);
$this->assertTrue($user->setDisplayName('Foo'));
@@ -454,4 +462,21 @@ class User extends \Test\TestCase {
$this->assertTrue($user->delete());
$this->assertEquals(2, $hooksCalled);
}
+
+ public function testGetCloudId() {
+ /**
+ * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend
+ */
+ $backend = $this->getMock('\Test\Util\User\Dummy');
+ $urlGenerator = $this->getMockBuilder('\OC\URLGenerator')
+ ->setMethods(['getAbsoluteURL'])
+ ->disableOriginalConstructor()->getMock();
+ $urlGenerator
+ ->expects($this->any())
+ ->method('getAbsoluteURL')
+ ->withAnyParameters()
+ ->willReturn('http://localhost:8888/owncloud');
+ $user = new \OC\User\User('foo', $backend, null, null, $urlGenerator);
+ $this->assertEquals("foo@localhost:8888/owncloud", $user->getCloudId());
+ }
}
diff --git a/tests/lib/util.php b/tests/lib/util.php
index 9974e799d08..7880d56f63b 100644
--- a/tests/lib/util.php
+++ b/tests/lib/util.php
@@ -8,7 +8,7 @@
*/
class Test_Util extends \Test\TestCase {
public function testGetVersion() {
- $version = \OC_Util::getVersion();
+ $version = \OCP\Util::getVersion();
$this->assertTrue(is_array($version));
foreach ($version as $num) {
$this->assertTrue(is_int($num));
@@ -89,22 +89,23 @@ class Test_Util extends \Test\TestCase {
});
}
- function testCallRegister() {
- $result = strlen(OC_Util::callRegister());
- $this->assertEquals(71, $result);
- }
-
function testSanitizeHTML() {
- $badArray = array(
+ $badArray = [
'While it is unusual to pass an array',
'this function actually <blink>supports</blink> it.',
- 'And therefore there needs to be a <script>alert("Unit"+\'test\')</script> for it!'
- );
- $goodArray = array(
+ 'And therefore there needs to be a <script>alert("Unit"+\'test\')</script> for it!',
+ [
+ 'And It Even May <strong>Nest</strong>',
+ ],
+ ];
+ $goodArray = [
'While it is unusual to pass an array',
'this function actually &lt;blink&gt;supports&lt;/blink&gt; it.',
- 'And therefore there needs to be a &lt;script&gt;alert(&quot;Unit&quot;+&#039;test&#039;)&lt;/script&gt; for it!'
- );
+ 'And therefore there needs to be a &lt;script&gt;alert(&quot;Unit&quot;+&#039;test&#039;)&lt;/script&gt; for it!',
+ [
+ 'And It Even May &lt;strong&gt;Nest&lt;/strong&gt;'
+ ],
+ ];
$result = OC_Util::sanitizeHTML($badArray);
$this->assertEquals($goodArray, $result);
@@ -132,34 +133,31 @@ class Test_Util extends \Test\TestCase {
$this->assertEquals($expected, \OC_Util::fileInfoLoaded());
}
- function testGenerateRandomBytes() {
- $result = strlen(OC_Util::generateRandomBytes(59));
- $this->assertEquals(59, $result);
- }
-
function testGetDefaultEmailAddress() {
$email = \OCP\Util::getDefaultEmailAddress("no-reply");
$this->assertEquals('no-reply@localhost', $email);
}
function testGetDefaultEmailAddressFromConfig() {
- OC_Config::setValue('mail_domain', 'example.com');
+ $config = \OC::$server->getConfig();
+ $config->setSystemValue('mail_domain', 'example.com');
$email = \OCP\Util::getDefaultEmailAddress("no-reply");
$this->assertEquals('no-reply@example.com', $email);
- OC_Config::deleteKey('mail_domain');
+ $config->deleteSystemValue('mail_domain');
}
function testGetConfiguredEmailAddressFromConfig() {
- OC_Config::setValue('mail_domain', 'example.com');
- OC_Config::setValue('mail_from_address', 'owncloud');
+ $config = \OC::$server->getConfig();
+ $config->setSystemValue('mail_domain', 'example.com');
+ $config->setSystemValue('mail_from_address', 'owncloud');
$email = \OCP\Util::getDefaultEmailAddress("no-reply");
$this->assertEquals('owncloud@example.com', $email);
- OC_Config::deleteKey('mail_domain');
- OC_Config::deleteKey('mail_from_address');
+ $config->deleteSystemValue('mail_domain');
+ $config->deleteSystemValue('mail_from_address');
}
function testGetInstanceIdGeneratesValidId() {
- OC_Config::deleteKey('instanceid');
+ \OC::$server->getConfig()->deleteSystemValue('instanceid');
$instanceId = OC_Util::getInstanceId();
$this->assertStringStartsWith('oc', $instanceId);
$matchesRegex = preg_match('/^[a-z0-9]+$/', $instanceId);
@@ -167,55 +165,6 @@ class Test_Util extends \Test\TestCase {
}
/**
- * Tests that the home storage is not wrapped when no quota exists.
- */
- function testHomeStorageWrapperWithoutQuota() {
- $user1 = $this->getUniqueID();
- \OC_User::createUser($user1, 'test');
- \OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', 'none');
- \OC_User::setUserId($user1);
-
- \OC_Util::setupFS($user1);
-
- $userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/');
- $this->assertNotNull($userMount);
- $this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $userMount->getStorage());
-
- // clean up
- \OC_User::setUserId('');
- \OC_User::deleteUser($user1);
- \OC::$server->getConfig()->deleteAllUserValues($user1);
- \OC_Util::tearDownFS();
- }
-
- /**
- * Tests that the home storage is not wrapped when no quota exists.
- */
- function testHomeStorageWrapperWithQuota() {
- $user1 = $this->getUniqueID();
- \OC_User::createUser($user1, 'test');
- \OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', '1024');
- \OC_User::setUserId($user1);
-
- \OC_Util::setupFS($user1);
-
- $userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/');
- $this->assertNotNull($userMount);
- $this->assertTrue($userMount->getStorage()->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota'));
-
- // ensure that root wasn't wrapped
- $rootMount = \OC\Files\Filesystem::getMountManager()->find('/');
- $this->assertNotNull($rootMount);
- $this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $rootMount->getStorage());
-
- // clean up
- \OC_User::setUserId('');
- \OC_User::deleteUser($user1);
- \OC::$server->getConfig()->deleteAllUserValues($user1);
- \OC_Util::tearDownFS();
- }
-
- /**
* @dataProvider baseNameProvider
*/
public function testBaseName($expected, $file) {
@@ -289,38 +238,30 @@ class Test_Util extends \Test\TestCase {
* @param bool $expected expected result
*/
function testIsSharingDisabledForUser($groups, $membership, $excludedGroups, $expected) {
- $uid = "user1";
- \OC_User::setUserId($uid);
-
- \OC_User::createUser($uid, "passwd");
-
- foreach ($groups as $group) {
- \OC_Group::createGroup($group);
- }
-
- foreach ($membership as $group) {
- \OC_Group::addToGroup($uid, $group);
- }
-
- $appConfig = \OC::$server->getAppConfig();
- $appConfig->setValue('core', 'shareapi_exclude_groups_list', json_encode($excludedGroups));
- $appConfig->setValue('core', 'shareapi_exclude_groups', 'yes');
-
- $result = \OCP\Util::isSharingDisabledForUser();
+ $config = $this->getMockBuilder('OCP\IConfig')->disableOriginalConstructor()->getMock();
+ $groupManager = $this->getMockBuilder('OCP\IGroupManager')->disableOriginalConstructor()->getMock();
+ $user = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock();
+
+ $config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('core', 'shareapi_exclude_groups', 'no')
+ ->will($this->returnValue('yes'));
+ $config
+ ->expects($this->at(1))
+ ->method('getAppValue')
+ ->with('core', 'shareapi_exclude_groups_list')
+ ->will($this->returnValue(json_encode($excludedGroups)));
+
+ $groupManager
+ ->expects($this->at(0))
+ ->method('getUserGroupIds')
+ ->with($user)
+ ->will($this->returnValue($membership));
+
+ $result = \OC_Util::isSharingDisabledForUser($config, $groupManager, $user);
$this->assertSame($expected, $result);
-
- // cleanup
- \OC_User::deleteUser($uid);
- \OC_User::setUserId('');
-
- foreach ($groups as $group) {
- \OC_Group::deleteGroup($group);
- }
-
- $appConfig->setValue('core', 'shareapi_exclude_groups_list', '');
- $appConfig->setValue('core', 'shareapi_exclude_groups', 'no');
-
}
public function dataProviderForTestIsSharingDisabledForUser() {
@@ -395,23 +336,44 @@ class Test_Util extends \Test\TestCase {
);
}
+ public function testGetDefaultPageUrlWithRedirectUrlWithoutFrontController() {
+ putenv('front_controller_active=false');
+
+ $_REQUEST['redirect_url'] = 'myRedirectUrl.com';
+ $this->assertSame('http://localhost'.\OC::$WEBROOT.'/myRedirectUrl.com', OC_Util::getDefaultPageUrl());
+ }
+
+ public function testGetDefaultPageUrlWithRedirectUrlRedirectBypassWithoutFrontController() {
+ putenv('front_controller_active=false');
+
+ $_REQUEST['redirect_url'] = 'myRedirectUrl.com@foo.com:a';
+ $this->assertSame('http://localhost'.\OC::$WEBROOT.'/index.php/apps/files/', OC_Util::getDefaultPageUrl());
+ }
+
+ public function testGetDefaultPageUrlWithRedirectUrlRedirectBypassWithFrontController() {
+ putenv('front_controller_active=true');
+ $_REQUEST['redirect_url'] = 'myRedirectUrl.com@foo.com:a';
+ $this->assertSame('http://localhost'.\OC::$WEBROOT.'/apps/files/', OC_Util::getDefaultPageUrl());
+ }
+
/**
* Test needUpgrade() when the core version is increased
*/
public function testNeedUpgradeCore() {
- $oldConfigVersion = OC_Config::getValue('version', '0.0.0');
+ $config = \OC::$server->getConfig();
+ $oldConfigVersion = $config->getSystemValue('version', '0.0.0');
$oldSessionVersion = \OC::$server->getSession()->get('OC_Version');
$this->assertFalse(\OCP\Util::needUpgrade());
- OC_Config::setValue('version', '7.0.0.0');
+ $config->setSystemValue('version', '7.0.0.0');
\OC::$server->getSession()->set('OC_Version', array(7, 0, 0, 1));
self::invokePrivate(new \OCP\Util, 'needUpgradeCache', array(null));
$this->assertTrue(\OCP\Util::needUpgrade());
- OC_Config::setValue('version', $oldConfigVersion);
- $oldSessionVersion = \OC::$server->getSession()->set('OC_Version', $oldSessionVersion);
+ $config->setSystemValue('version', $oldConfigVersion);
+ \OC::$server->getSession()->set('OC_Version', $oldSessionVersion);
self::invokePrivate(new \OCP\Util, 'needUpgradeCache', array(null));
$this->assertFalse(\OCP\Util::needUpgrade());
@@ -435,6 +397,97 @@ class Test_Util extends \Test\TestCase {
$this->assertNotEmpty($errors);
}
}
+
+ protected function setUp() {
+ parent::setUp();
+
+ \OC_Util::$scripts = [];
+ \OC_Util::$styles = [];
+ }
+ protected function tearDown() {
+ parent::tearDown();
+
+ \OC_Util::$scripts = [];
+ \OC_Util::$styles = [];
+ }
+
+ public function testAddScript() {
+ \OC_Util::addScript('core', 'myFancyJSFile1');
+ \OC_Util::addScript('myApp', 'myFancyJSFile2');
+ \OC_Util::addScript('core', 'myFancyJSFile0', true);
+ \OC_Util::addScript('core', 'myFancyJSFile10', true);
+ // add duplicate
+ \OC_Util::addScript('core', 'myFancyJSFile1');
+
+ $this->assertEquals([
+ 'core/js/myFancyJSFile10',
+ 'core/js/myFancyJSFile0',
+ 'core/js/myFancyJSFile1',
+ 'myApp/l10n/en',
+ 'myApp/js/myFancyJSFile2',
+ ], \OC_Util::$scripts);
+ $this->assertEquals([], \OC_Util::$styles);
+ }
+
+ public function testAddVendorScript() {
+ \OC_Util::addVendorScript('core', 'myFancyJSFile1');
+ \OC_Util::addVendorScript('myApp', 'myFancyJSFile2');
+ \OC_Util::addVendorScript('core', 'myFancyJSFile0', true);
+ \OC_Util::addVendorScript('core', 'myFancyJSFile10', true);
+ // add duplicate
+ \OC_Util::addVendorScript('core', 'myFancyJSFile1');
+
+ $this->assertEquals([
+ 'core/vendor/myFancyJSFile10',
+ 'core/vendor/myFancyJSFile0',
+ 'core/vendor/myFancyJSFile1',
+ 'myApp/vendor/myFancyJSFile2',
+ ], \OC_Util::$scripts);
+ $this->assertEquals([], \OC_Util::$styles);
+ }
+
+ public function testAddTranslations() {
+ \OC_Util::addTranslations('appId', 'de');
+
+ $this->assertEquals([
+ 'appId/l10n/de'
+ ], \OC_Util::$scripts);
+ $this->assertEquals([], \OC_Util::$styles);
+ }
+
+ public function testAddStyle() {
+ \OC_Util::addStyle('core', 'myFancyCSSFile1');
+ \OC_Util::addStyle('myApp', 'myFancyCSSFile2');
+ \OC_Util::addStyle('core', 'myFancyCSSFile0', true);
+ \OC_Util::addStyle('core', 'myFancyCSSFile10', true);
+ // add duplicate
+ \OC_Util::addStyle('core', 'myFancyCSSFile1');
+
+ $this->assertEquals([], \OC_Util::$scripts);
+ $this->assertEquals([
+ 'core/css/myFancyCSSFile10',
+ 'core/css/myFancyCSSFile0',
+ 'core/css/myFancyCSSFile1',
+ 'myApp/css/myFancyCSSFile2',
+ ], \OC_Util::$styles);
+ }
+
+ public function testAddVendorStyle() {
+ \OC_Util::addVendorStyle('core', 'myFancyCSSFile1');
+ \OC_Util::addVendorStyle('myApp', 'myFancyCSSFile2');
+ \OC_Util::addVendorStyle('core', 'myFancyCSSFile0', true);
+ \OC_Util::addVendorStyle('core', 'myFancyCSSFile10', true);
+ // add duplicate
+ \OC_Util::addVendorStyle('core', 'myFancyCSSFile1');
+
+ $this->assertEquals([], \OC_Util::$scripts);
+ $this->assertEquals([
+ 'core/vendor/myFancyCSSFile10',
+ 'core/vendor/myFancyCSSFile0',
+ 'core/vendor/myFancyCSSFile1',
+ 'myApp/vendor/myFancyCSSFile2',
+ ], \OC_Util::$styles);
+ }
}
/**
diff --git a/tests/lib/utilcheckserver.php b/tests/lib/utilcheckserver.php
index bb9b7a24452..94e7fd2f779 100644
--- a/tests/lib/utilcheckserver.php
+++ b/tests/lib/utilcheckserver.php
@@ -8,6 +8,8 @@
/**
* Tests for server check functions
+ *
+ * @group DB
*/
class Test_Util_CheckServer extends \Test\TestCase {
@@ -35,7 +37,7 @@ class Test_Util_CheckServer extends \Test\TestCase {
protected function setUp() {
parent::setUp();
- $this->datadir = \OC_Helper::tmpFolder();
+ $this->datadir = \OC::$server->getTempManager()->getTemporaryFolder();
file_put_contents($this->datadir . '/.ocdata', '');
\OC::$server->getSession()->set('checkServer_succeeded', false);
@@ -121,7 +123,7 @@ class Test_Util_CheckServer extends \Test\TestCase {
$result = \OC_Util::checkServer($this->getConfig(array(
'installed' => true,
- 'version' => implode('.', OC_Util::getVersion())
+ 'version' => implode('.', \OCP\Util::getVersion())
)));
$this->assertCount(1, $result);
}
@@ -132,7 +134,7 @@ class Test_Util_CheckServer extends \Test\TestCase {
public function testDataDirWritable() {
$result = \OC_Util::checkServer($this->getConfig(array(
'installed' => true,
- 'version' => implode('.', OC_Util::getVersion())
+ 'version' => implode('.', \OCP\Util::getVersion())
)));
$this->assertEmpty($result);
}
@@ -148,7 +150,7 @@ class Test_Util_CheckServer extends \Test\TestCase {
chmod($this->datadir, 0300);
$result = \OC_Util::checkServer($this->getConfig(array(
'installed' => true,
- 'version' => implode('.', OC_Util::getVersion())
+ 'version' => implode('.', \OCP\Util::getVersion())
)));
$this->assertCount(1, $result);
}
@@ -160,7 +162,7 @@ class Test_Util_CheckServer extends \Test\TestCase {
chmod($this->datadir, 0300);
$result = \OC_Util::checkServer($this->getConfig(array(
'installed' => false,
- 'version' => implode('.', OC_Util::getVersion())
+ 'version' => implode('.', \OCP\Util::getVersion())
)));
chmod($this->datadir, 0700); //needed for cleanup
$this->assertEmpty($result);
diff --git a/tests/phpunit-autotest-external.xml b/tests/phpunit-autotest-external.xml
index b9402bfa572..31d2e395a01 100644
--- a/tests/phpunit-autotest-external.xml
+++ b/tests/phpunit-autotest-external.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<phpunit bootstrap="bootstrap.php"
- strict="true"
verbose="true"
timeoutForSmallTests="900"
timeoutForMediumTests="900"
diff --git a/tests/settings/controller/AppSettingsControllerTest.php b/tests/settings/controller/AppSettingsControllerTest.php
index 09595d05661..dba5728ca4b 100644
--- a/tests/settings/controller/AppSettingsControllerTest.php
+++ b/tests/settings/controller/AppSettingsControllerTest.php
@@ -220,9 +220,14 @@ class AppSettingsControllerTest extends TestCase {
public function testViewApps() {
$this->config
- ->expects($this->once())
+ ->expects($this->at(0))
->method('getSystemValue')
->with('appstore.experimental.enabled', false);
+ $this->config
+ ->expects($this->at(1))
+ ->method('getSystemValue')
+ ->with('appstoreenabled', true)
+ ->will($this->returnValue(true));
$this->navigationManager
->expects($this->once())
->method('setActiveEntry')
@@ -231,7 +236,7 @@ class AppSettingsControllerTest extends TestCase {
$policy = new ContentSecurityPolicy();
$policy->addAllowedImageDomain('https://apps.owncloud.com');
- $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'enabled'], 'user');
+ $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'enabled', 'appstoreEnabled' => true], 'user');
$expected->setContentSecurityPolicy($policy);
$this->assertEquals($expected, $this->appSettingsController->viewApps());
@@ -239,9 +244,14 @@ class AppSettingsControllerTest extends TestCase {
public function testViewAppsNotEnabled() {
$this->config
- ->expects($this->once())
+ ->expects($this->at(0))
->method('getSystemValue')
->with('appstore.experimental.enabled', false);
+ $this->config
+ ->expects($this->at(1))
+ ->method('getSystemValue')
+ ->with('appstoreenabled', true)
+ ->will($this->returnValue(true));
$this->navigationManager
->expects($this->once())
->method('setActiveEntry')
@@ -250,9 +260,33 @@ class AppSettingsControllerTest extends TestCase {
$policy = new ContentSecurityPolicy();
$policy->addAllowedImageDomain('https://apps.owncloud.com');
- $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'disabled'], 'user');
+ $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'disabled', 'appstoreEnabled' => true], 'user');
$expected->setContentSecurityPolicy($policy);
$this->assertEquals($expected, $this->appSettingsController->viewApps('disabled'));
}
+
+ public function testViewAppsAppstoreNotEnabled() {
+ $this->config
+ ->expects($this->at(0))
+ ->method('getSystemValue')
+ ->with('appstore.experimental.enabled', false);
+ $this->config
+ ->expects($this->at(1))
+ ->method('getSystemValue')
+ ->with('appstoreenabled', true)
+ ->will($this->returnValue(false));
+ $this->navigationManager
+ ->expects($this->once())
+ ->method('setActiveEntry')
+ ->with('core_apps');
+
+ $policy = new ContentSecurityPolicy();
+ $policy->addAllowedImageDomain('https://apps.owncloud.com');
+
+ $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'enabled', 'appstoreEnabled' => false], 'user');
+ $expected->setContentSecurityPolicy($policy);
+
+ $this->assertEquals($expected, $this->appSettingsController->viewApps());
+ }
}
diff --git a/tests/settings/controller/CertificateControllerTest.php b/tests/settings/controller/CertificateControllerTest.php
index 023d7753cca..2fdbbb8b0ac 100644
--- a/tests/settings/controller/CertificateControllerTest.php
+++ b/tests/settings/controller/CertificateControllerTest.php
@@ -44,12 +44,15 @@ class CertificateControllerTest extends \Test\TestCase {
private $l10n;
/** @var IAppManager */
private $appManager;
+ /** @var ICertificateManager */
+ private $systemCertificateManager;
public function setUp() {
parent::setUp();
$this->request = $this->getMock('\OCP\IRequest');
$this->certificateManager = $this->getMock('\OCP\ICertificateManager');
+ $this->systemCertificateManager = $this->getMock('\OCP\ICertificateManager');
$this->l10n = $this->getMock('\OCP\IL10N');
$this->appManager = $this->getMock('OCP\App\IAppManager');
@@ -59,6 +62,7 @@ class CertificateControllerTest extends \Test\TestCase {
'settings',
$this->request,
$this->certificateManager,
+ $this->systemCertificateManager,
$this->l10n,
$this->appManager
]
diff --git a/tests/settings/controller/CheckSetupControllerTest.php b/tests/settings/controller/CheckSetupControllerTest.php
index ebba18de5fd..c22ddb2e120 100644
--- a/tests/settings/controller/CheckSetupControllerTest.php
+++ b/tests/settings/controller/CheckSetupControllerTest.php
@@ -21,7 +21,10 @@
namespace OC\Settings\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataDisplayResponse;
use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\RedirectResponse;
use OCP\Http\Client\IClientService;
use OCP\IConfig;
use OCP\IL10N;
@@ -29,6 +32,7 @@ use OCP\IRequest;
use OCP\IURLGenerator;
use OC_Util;
use Test\TestCase;
+use OC\IntegrityCheck\Checker;
/**
* Mock version_compare
@@ -63,6 +67,8 @@ class CheckSetupControllerTest extends TestCase {
private $util;
/** @var IL10N */
private $l10n;
+ /** @var Checker */
+ private $checker;
public function setUp() {
parent::setUp();
@@ -86,6 +92,8 @@ class CheckSetupControllerTest extends TestCase {
->will($this->returnCallback(function($message, array $replace) {
return vsprintf($message, $replace);
}));
+ $this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker')
+ ->disableOriginalConstructor()->getMock();
$this->checkSetupController = $this->getMockBuilder('\OC\Settings\Controller\CheckSetupController')
->setConstructorArgs([
'settings',
@@ -95,6 +103,7 @@ class CheckSetupControllerTest extends TestCase {
$this->urlGenerator,
$this->util,
$this->l10n,
+ $this->checker,
])
->setMethods(['getCurlVersion'])->getMock();
}
@@ -317,10 +326,6 @@ class CheckSetupControllerTest extends TestCase {
$this->clientService->expects($this->once())
->method('newClient')
->will($this->returnValue($client));
-
- $this->util->expects($this->once())
- ->method('isHtaccessWorking')
- ->will($this->returnValue(true));
$this->urlGenerator->expects($this->at(0))
->method('linkToDocs')
->with('admin-performance')
@@ -338,7 +343,6 @@ class CheckSetupControllerTest extends TestCase {
$expected = new DataResponse(
[
'serverHasInternetConnection' => false,
- 'dataDirectoryProtected' => true,
'isMemcacheConfigured' => true,
'memcacheDocs' => 'http://doc.owncloud.org/server/go.php?to=admin-performance',
'isUrandomAvailable' => self::invokePrivate($this->checkSetupController, 'isUrandomAvailable'),
@@ -351,6 +355,8 @@ class CheckSetupControllerTest extends TestCase {
'forwardedForHeadersWorking' => true,
'reverseProxyDocs' => 'reverse-proxy-doc-link',
'isCorrectMemcachedPHPModuleInstalled' => true,
+ 'hasPassedCodeIntegrityCheck' => null,
+ 'codeIntegrityCheckerDocumentation' => null,
]
);
$this->assertEquals($expected, $this->checkSetupController->check());
@@ -366,6 +372,7 @@ class CheckSetupControllerTest extends TestCase {
$this->urlGenerator,
$this->util,
$this->l10n,
+ $this->checker
])
->setMethods(null)->getMock();
@@ -596,4 +603,441 @@ class CheckSetupControllerTest extends TestCase {
->will($this->returnValue([]));
$this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated'));
}
+
+ public function testRescanFailedIntegrityCheck() {
+ $this->checker
+ ->expects($this->once())
+ ->method('runInstanceVerification');
+ $this->urlGenerator
+ ->expects($this->once())
+ ->method('linkToRoute')
+ ->with('settings_admin')
+ ->will($this->returnValue('/admin'));
+
+ $expected = new RedirectResponse('/admin');
+ $this->assertEquals($expected, $this->checkSetupController->rescanFailedIntegrityCheck());
+ }
+
+ public function testGetFailedIntegrityCheckFilesWithNoErrorsFound() {
+ $this->checker
+ ->expects($this->once())
+ ->method('getResults')
+ ->will($this->returnValue([]));
+
+ $expected = new DataDisplayResponse(
+ 'No errors have been found.',
+ Http::STATUS_OK,
+ [
+ 'Content-Type' => 'text/plain',
+ ]
+ );
+ $this->assertEquals($expected, $this->checkSetupController->getFailedIntegrityCheckFiles());
+ }
+
+ public function testGetFailedIntegrityCheckFilesWithSomeErrorsFound() {
+ $this->checker
+ ->expects($this->once())
+ ->method('getResults')
+ ->will($this->returnValue(array ( 'core' => array ( 'EXTRA_FILE' => array('/testfile' => array()), 'INVALID_HASH' => array ( '/.idea/workspace.xml' => array ( 'expected' => 'f1c5e2630d784bc9cb02d5a28f55d6f24d06dae2a0fee685f3c2521b050955d9d452769f61454c9ddfa9c308146ade10546cfa829794448eaffbc9a04a29d216', 'current' => 'ce08bf30bcbb879a18b49239a9bec6b8702f52452f88a9d32142cad8d2494d5735e6bfa0d8642b2762c62ca5be49f9bf4ec231d4a230559d4f3e2c471d3ea094', ), '/lib/private/integritycheck/checker.php' => array ( 'expected' => 'c5a03bacae8dedf8b239997901ba1fffd2fe51271d13a00cc4b34b09cca5176397a89fc27381cbb1f72855fa18b69b6f87d7d5685c3b45aee373b09be54742ea', 'current' => '88a3a92c11db91dec1ac3be0e1c87f862c95ba6ffaaaa3f2c3b8f682187c66f07af3a3b557a868342ef4a271218fe1c1e300c478e6c156c5955ed53c40d06585', ), '/settings/controller/checksetupcontroller.php' => array ( 'expected' => '3e1de26ce93c7bfe0ede7c19cb6c93cadc010340225b375607a7178812e9de163179b0dc33809f451e01f491d93f6f5aaca7929685d21594cccf8bda732327c4', 'current' => '09563164f9904a837f9ca0b5f626db56c838e5098e0ccc1d8b935f68fa03a25c5ec6f6b2d9e44a868e8b85764dafd1605522b4af8db0ae269d73432e9a01e63a', ), ), ), 'bookmarks' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'dav' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'encryption' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'external' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'federation' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_antivirus' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_drop' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_external' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_pdfviewer' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_sharing' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_trashbin' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_versions' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_videoviewer' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'firstrunwizard' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'gitsmart' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'logreader' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature could not get verified.', ), ), 'password_policy' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'provisioning_api' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'sketch' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'threatblock' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'two_factor_auth' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'user_ldap' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'user_shibboleth' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), )));
+
+ $expected = new DataDisplayResponse(
+ 'Technical information
+=====================
+The following list covers which files have failed the integrity check. Please read
+the previous linked documentation to learn more about the errors and how to fix
+them.
+
+Results
+=======
+- core
+ - EXTRA_FILE
+ - /testfile
+ - INVALID_HASH
+ - /.idea/workspace.xml
+ - /lib/private/integritycheck/checker.php
+ - /settings/controller/checksetupcontroller.php
+- bookmarks
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- dav
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- encryption
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- external
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- federation
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- files
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- files_antivirus
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- files_drop
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- files_external
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- files_pdfviewer
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- files_sharing
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- files_trashbin
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- files_versions
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- files_videoviewer
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- firstrunwizard
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- gitsmart
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- logreader
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature could not get verified.
+- password_policy
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- provisioning_api
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- sketch
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- threatblock
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- two_factor_auth
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- user_ldap
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+- user_shibboleth
+ - EXCEPTION
+ - OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ - Signature data not found.
+
+Raw output
+==========
+Array
+(
+ [core] => Array
+ (
+ [EXTRA_FILE] => Array
+ (
+ [/testfile] => Array
+ (
+ )
+
+ )
+
+ [INVALID_HASH] => Array
+ (
+ [/.idea/workspace.xml] => Array
+ (
+ [expected] => f1c5e2630d784bc9cb02d5a28f55d6f24d06dae2a0fee685f3c2521b050955d9d452769f61454c9ddfa9c308146ade10546cfa829794448eaffbc9a04a29d216
+ [current] => ce08bf30bcbb879a18b49239a9bec6b8702f52452f88a9d32142cad8d2494d5735e6bfa0d8642b2762c62ca5be49f9bf4ec231d4a230559d4f3e2c471d3ea094
+ )
+
+ [/lib/private/integritycheck/checker.php] => Array
+ (
+ [expected] => c5a03bacae8dedf8b239997901ba1fffd2fe51271d13a00cc4b34b09cca5176397a89fc27381cbb1f72855fa18b69b6f87d7d5685c3b45aee373b09be54742ea
+ [current] => 88a3a92c11db91dec1ac3be0e1c87f862c95ba6ffaaaa3f2c3b8f682187c66f07af3a3b557a868342ef4a271218fe1c1e300c478e6c156c5955ed53c40d06585
+ )
+
+ [/settings/controller/checksetupcontroller.php] => Array
+ (
+ [expected] => 3e1de26ce93c7bfe0ede7c19cb6c93cadc010340225b375607a7178812e9de163179b0dc33809f451e01f491d93f6f5aaca7929685d21594cccf8bda732327c4
+ [current] => 09563164f9904a837f9ca0b5f626db56c838e5098e0ccc1d8b935f68fa03a25c5ec6f6b2d9e44a868e8b85764dafd1605522b4af8db0ae269d73432e9a01e63a
+ )
+
+ )
+
+ )
+
+ [bookmarks] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [dav] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [encryption] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [external] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [federation] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [files] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [files_antivirus] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [files_drop] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [files_external] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [files_pdfviewer] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [files_sharing] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [files_trashbin] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [files_versions] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [files_videoviewer] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [firstrunwizard] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [gitsmart] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [logreader] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature could not get verified.
+ )
+
+ )
+
+ [password_policy] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [provisioning_api] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [sketch] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [threatblock] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [two_factor_auth] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [user_ldap] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+ [user_shibboleth] => Array
+ (
+ [EXCEPTION] => Array
+ (
+ [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException
+ [message] => Signature data not found.
+ )
+
+ )
+
+)
+',
+ Http::STATUS_OK,
+ [
+ 'Content-Type' => 'text/plain',
+ ]
+ );
+ $this->assertEquals($expected, $this->checkSetupController->getFailedIntegrityCheckFiles());
+ }
}
diff --git a/tests/settings/controller/EncryptionControllerTest.php b/tests/settings/controller/EncryptionControllerTest.php
index 2446b8c7b9e..a3bb4c45a27 100644
--- a/tests/settings/controller/EncryptionControllerTest.php
+++ b/tests/settings/controller/EncryptionControllerTest.php
@@ -90,6 +90,9 @@ class EncryptionControllerTest extends TestCase {
}
public function testStartMigrationSuccessful() {
+ // we need to be able to autoload the class we're mocking
+ \OC::$loader->addValidRoot(\OC_App::getAppPath('encryption'));
+
$migration = $this->getMockBuilder('\\OCA\\Encryption\\Migration')
->disableOriginalConstructor()->getMock();
$this->encryptionController
diff --git a/tests/settings/controller/userscontrollertest.php b/tests/settings/controller/userscontrollertest.php
index f4b05671ce8..38fc1ee6102 100644
--- a/tests/settings/controller/userscontrollertest.php
+++ b/tests/settings/controller/userscontrollertest.php
@@ -14,6 +14,8 @@ use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
/**
+ * @group DB
+ *
* @package OC\Settings\Controller
*/
class UsersControllerTest extends \Test\TestCase {
@@ -52,6 +54,30 @@ class UsersControllerTest extends \Test\TestCase {
->disableOriginalConstructor()->getMock();
$this->container['OCP\\App\\IAppManager'] = $this->getMockBuilder('OCP\\App\\IAppManager')
->disableOriginalConstructor()->getMock();
+
+
+ /*
+ * Set default avtar behaviour for whole testsuite
+ */
+ $this->container['OCP\\IAvatarManager'] = $this->getMock('OCP\IAvatarManager');
+
+ $avatarExists = $this->getMock('OCP\IAvatar');
+ $avatarExists->method('exists')->willReturn(true);
+ $avatarNotExists = $this->getMock('OCP\IAvatar');
+ $avatarNotExists->method('exists')->willReturn(false);
+ $this->container['OCP\\IAvatarManager']
+ ->method('getAvatar')
+ ->will($this->returnValueMap([
+ ['foo', $avatarExists],
+ ['bar', $avatarExists],
+ ['admin', $avatarNotExists],
+ ]));
+
+ $this->container['Config']
+ ->method('getSystemValue')
+ ->with('enable_avatars', true)
+ ->willReturn(true);
+
}
public function testIndexAdmin() {
@@ -68,6 +94,10 @@ class UsersControllerTest extends \Test\TestCase {
->method('getDisplayName')
->will($this->returnValue('M. Foo'));
$foo
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('foo@bar.com'));
+ $foo
->method('getLastLogin')
->will($this->returnValue(500));
$foo
@@ -89,6 +119,10 @@ class UsersControllerTest extends \Test\TestCase {
->will($this->returnValue('S. Admin'));
$admin
->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('admin@bar.com'));
+ $admin
+ ->expects($this->once())
->method('getLastLogin')
->will($this->returnValue(12));
$admin
@@ -110,6 +144,10 @@ class UsersControllerTest extends \Test\TestCase {
->method('getDisplayName')
->will($this->returnValue('B. Ar'));
$bar
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('bar@dummy.com'));
+ $bar
->method('getLastLogin')
->will($this->returnValue(3999));
$bar
@@ -145,11 +183,11 @@ class UsersControllerTest extends \Test\TestCase {
->with('bar')
->will($this->returnValue($bar));
$this->container['Config']
- ->expects($this->exactly(6))
+ ->expects($this->exactly(3))
->method('getUserValue')
- ->will($this->onConsecutiveCalls(1024, 'foo@bar.com',
- 404, 'admin@bar.com',
- 2323, 'bar@dummy.com'));
+ ->will($this->onConsecutiveCalls(1024,
+ 404,
+ 2323));
$subadmin = $this->getMockBuilder('\OC\SubAdmin')
->disableOriginalConstructor()
@@ -174,7 +212,6 @@ class UsersControllerTest extends \Test\TestCase {
->method('getSubAdmin')
->will($this->returnValue($subadmin));
-
$expectedResponse = new DataResponse(
array(
0 => array(
@@ -188,6 +225,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => 'OC_User_Database',
'email' => 'foo@bar.com',
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
),
1 => array(
'name' => 'admin',
@@ -200,6 +238,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => '\Test\Util\User\Dummy',
'email' => 'admin@bar.com',
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => false,
),
2 => array(
'name' => 'bar',
@@ -212,6 +251,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => '\Test\Util\User\Dummy',
'email' => 'bar@dummy.com',
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
),
)
);
@@ -240,6 +280,10 @@ class UsersControllerTest extends \Test\TestCase {
->method('getDisplayName')
->will($this->returnValue('M. Foo'));
$foo
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('foo@bar.com'));
+ $foo
->method('getLastLogin')
->will($this->returnValue(500));
$foo
@@ -261,6 +305,10 @@ class UsersControllerTest extends \Test\TestCase {
->will($this->returnValue('S. Admin'));
$admin
->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('admin@bar.com'));
+ $admin
+ ->expects($this->once())
->method('getLastLogin')
->will($this->returnValue(12));
$admin
@@ -282,6 +330,10 @@ class UsersControllerTest extends \Test\TestCase {
->method('getDisplayName')
->will($this->returnValue('B. Ar'));
$bar
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('bar@dummy.com'));
+ $bar
->method('getLastLogin')
->will($this->returnValue(3999));
$bar
@@ -326,12 +378,12 @@ class UsersControllerTest extends \Test\TestCase {
->with('admin')
->will($this->returnValue($admin));
$this->container['Config']
- ->expects($this->exactly(6))
+ ->expects($this->exactly(3))
->method('getUserValue')
->will($this->onConsecutiveCalls(
- 2323, 'bar@dummy.com',
- 1024, 'foo@bar.com',
- 404, 'admin@bar.com'
+ 2323,
+ 1024,
+ 404
));
$subgroup1 = $this->getMockBuilder('\OCP\IGroup')
@@ -375,6 +427,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => '\Test\Util\User\Dummy',
'email' => 'bar@dummy.com',
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
],
1=> [
'name' => 'foo',
@@ -387,6 +440,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => 'OC_User_Database',
'email' => 'foo@bar.com',
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
],
2 => [
'name' => 'admin',
@@ -399,6 +453,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => '\Test\Util\User\Dummy',
'email' => 'admin@bar.com',
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => false,
],
]
);
@@ -425,6 +480,10 @@ class UsersControllerTest extends \Test\TestCase {
->method('getDisplayName')
->will($this->returnValue('M. Foo'));
$foo
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('foo@bar.com'));
+ $foo
->method('getLastLogin')
->will($this->returnValue(500));
$foo
@@ -446,6 +505,10 @@ class UsersControllerTest extends \Test\TestCase {
->will($this->returnValue('S. Admin'));
$admin
->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('admin@bar.com'));
+ $admin
+ ->expects($this->once())
->method('getLastLogin')
->will($this->returnValue(12));
$admin
@@ -467,6 +530,10 @@ class UsersControllerTest extends \Test\TestCase {
->method('getDisplayName')
->will($this->returnValue('B. Ar'));
$bar
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue('bar@dummy.com'));
+ $bar
->method('getLastLogin')
->will($this->returnValue(3999));
$bar
@@ -487,11 +554,9 @@ class UsersControllerTest extends \Test\TestCase {
->method('getUserGroupIds')
->will($this->onConsecutiveCalls(array('Users', 'Support'), array('admins', 'Support'), array('External Users')));
$this->container['Config']
- ->expects($this->exactly(6))
+ ->expects($this->exactly(3))
->method('getUserValue')
- ->will($this->onConsecutiveCalls(1024, 'foo@bar.com',
- 404, 'admin@bar.com',
- 2323, 'bar@dummy.com'));
+ ->will($this->onConsecutiveCalls(1024, 404, 2323));
$subadmin = $this->getMockBuilder('\OC\SubAdmin')
->disableOriginalConstructor()
@@ -517,6 +582,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => 'OC_User_Database',
'email' => 'foo@bar.com',
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
),
1 => array(
'name' => 'admin',
@@ -529,6 +595,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => '\Test\Util\User\Dummy',
'email' => 'admin@bar.com',
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => false,
),
2 => array(
'name' => 'bar',
@@ -541,6 +608,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => '\Test\Util\User\Dummy',
'email' => 'bar@dummy.com',
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
),
)
);
@@ -562,6 +630,10 @@ class UsersControllerTest extends \Test\TestCase {
->method('getDisplayName')
->will($this->returnValue('M. Foo'));
$user
+ ->expects($this->once())
+ ->method('getEMailAddress')
+ ->will($this->returnValue(null));
+ $user
->method('getLastLogin')
->will($this->returnValue(500));
$user
@@ -608,6 +680,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => 'OC_User_Database',
'email' => null,
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
)
)
);
@@ -679,6 +752,7 @@ class UsersControllerTest extends \Test\TestCase {
'subadmin' => array(),
'email' => null,
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
),
Http::STATUS_CREATED
);
@@ -767,6 +841,7 @@ class UsersControllerTest extends \Test\TestCase {
'subadmin' => [],
'email' => null,
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
),
Http::STATUS_CREATED
);
@@ -849,6 +924,7 @@ class UsersControllerTest extends \Test\TestCase {
'subadmin' => array(),
'email' => null,
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
),
Http::STATUS_CREATED
);
@@ -944,6 +1020,7 @@ class UsersControllerTest extends \Test\TestCase {
'subadmin' => [],
'email' => null,
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
),
Http::STATUS_CREATED
);
@@ -1440,6 +1517,7 @@ class UsersControllerTest extends \Test\TestCase {
'backend' => $backend,
'email' => null,
'isRestoreDisabled' => false,
+ 'isAvatarAvailable' => true,
];
return [$user, $result];
@@ -1601,11 +1679,11 @@ class UsersControllerTest extends \Test\TestCase {
*/
public function setEmailAddressData() {
return [
- /* mailAddress, isValid, expectsUpdate, expectsDelete, canChangeDisplayName, responseCode */
- [ '', true, false, true, true, Http::STATUS_OK ],
- [ 'foo@local', true, true, false, true, Http::STATUS_OK],
- [ 'foo@bar@local', false, false, false, true, Http::STATUS_UNPROCESSABLE_ENTITY],
- [ 'foo@local', true, false, false, false, Http::STATUS_FORBIDDEN],
+ /* mailAddress, isValid, expectsUpdate, canChangeDisplayName, responseCode */
+ [ '', true, true, true, Http::STATUS_OK ],
+ [ 'foo@local', true, true, true, Http::STATUS_OK],
+ [ 'foo@bar@local', false, false, true, Http::STATUS_UNPROCESSABLE_ENTITY],
+ [ 'foo@local', true, false, false, Http::STATUS_FORBIDDEN],
];
}
@@ -1617,7 +1695,7 @@ class UsersControllerTest extends \Test\TestCase {
* @param bool $expectsUpdate
* @param bool $expectsDelete
*/
- public function testSetEmailAddress($mailAddress, $isValid, $expectsUpdate, $expectsDelete, $canChangeDisplayName, $responseCode) {
+ public function testSetEmailAddress($mailAddress, $isValid, $expectsUpdate, $canChangeDisplayName, $responseCode) {
$this->container['IsAdmin'] = true;
$user = $this->getMockBuilder('\OC\User\User')
@@ -1630,6 +1708,13 @@ class UsersControllerTest extends \Test\TestCase {
->expects($this->any())
->method('canChangeDisplayName')
->will($this->returnValue($canChangeDisplayName));
+ $user
+ ->expects($expectsUpdate ? $this->once() : $this->never())
+ ->method('setEMailAddress')
+ ->with(
+ $this->equalTo($mailAddress)
+ );
+
$this->container['UserSession']
->expects($this->atLeastOnce())
->method('getUser')
@@ -1652,26 +1737,6 @@ class UsersControllerTest extends \Test\TestCase {
->will($this->returnValue($user));
}
- $this->container['Config']
- ->expects(($expectsUpdate) ? $this->once() : $this->never())
- ->method('setUserValue')
- ->with(
- $this->equalTo($user->getUID()),
- $this->equalTo('settings'),
- $this->equalTo('email'),
- $this->equalTo($mailAddress)
-
- );
- $this->container['Config']
- ->expects(($expectsDelete) ? $this->once() : $this->never())
- ->method('deleteUserValue')
- ->with(
- $this->equalTo($user->getUID()),
- $this->equalTo('settings'),
- $this->equalTo('email')
-
- );
-
$response = $this->container['UsersController']->setMailAddress($user->getUID(), $mailAddress);
$this->assertSame($responseCode, $response->getStatus());
@@ -1746,4 +1811,173 @@ class UsersControllerTest extends \Test\TestCase {
$this->assertEquals($expectedResponse, $response);
}
+ public function testSetDisplayNameNull() {
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('getUID')->willReturn('userName');
+
+ $this->container['UserSession']
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($user);
+
+ $expectedResponse = new DataResponse(
+ [
+ 'status' => 'error',
+ 'data' => [
+ 'message' => 'Authentication error',
+ ],
+ ]
+ );
+ $response = $this->container['UsersController']->setDisplayName(null, 'displayName');
+
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ public function dataSetDisplayName() {
+ $data = [];
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user1->method('canChangeDisplayName')->willReturn(true);
+ $data[] = [$user1, $user1, false, false, true];
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user1->method('canChangeDisplayName')->willReturn(false);
+ $data[] = [$user1, $user1, false, false, false];
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user2 = $this->getMock('\OCP\IUser');
+ $user2->method('getUID')->willReturn('user2');
+ $user2->method('canChangeDisplayName')->willReturn(true);
+ $data[] = [$user1, $user2, false, false, false];
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user2 = $this->getMock('\OCP\IUser');
+ $user2->method('getUID')->willReturn('user2');
+ $user2->method('canChangeDisplayName')->willReturn(true);
+ $data[] = [$user1, $user2, true, false, true];
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->method('getUID')->willReturn('user1');
+ $user2 = $this->getMock('\OCP\IUser');
+ $user2->method('getUID')->willReturn('user2');
+ $user2->method('canChangeDisplayName')->willReturn(true);
+ $data[] = [$user1, $user2, false, true, true];
+
+ return $data;
+ }
+
+ /**
+ * @dataProvider dataSetDisplayName
+ */
+ public function testSetDisplayName($currentUser, $editUser, $isAdmin, $isSubAdmin, $valid) {
+ $this->container['UserSession']
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($currentUser);
+ $this->container['UserManager']
+ ->expects($this->once())
+ ->method('get')
+ ->with($editUser->getUID())
+ ->willReturn($editUser);
+
+ $subadmin = $this->getMockBuilder('\OC\SubAdmin')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $subadmin
+ ->method('isUserAccessible')
+ ->with($currentUser, $editUser)
+ ->willReturn($isSubAdmin);
+
+ $this->container['GroupManager']
+ ->method('getSubAdmin')
+ ->willReturn($subadmin);
+ $this->container['GroupManager']
+ ->method('isAdmin')
+ ->with($currentUser->getUID())
+ ->willReturn($isAdmin);
+
+ if ($valid === true) {
+ $editUser->expects($this->once())
+ ->method('setDisplayName')
+ ->with('newDisplayName')
+ ->willReturn(true);
+ $expectedResponse = new DataResponse(
+ [
+ 'status' => 'success',
+ 'data' => [
+ 'message' => 'Your full name has been changed.',
+ 'username' => $editUser->getUID(),
+ 'displayName' => 'newDisplayName',
+ ],
+ ]
+ );
+ } else {
+ $editUser->expects($this->never())->method('setDisplayName');
+ $expectedResponse = new DataResponse(
+ [
+ 'status' => 'error',
+ 'data' => [
+ 'message' => 'Authentication error',
+ ],
+ ]
+ );
+ }
+
+ $response = $this->container['UsersController']->setDisplayName($editUser->getUID(), 'newDisplayName');
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ public function testSetDisplayNameFails() {
+ $user = $this->getMock('\OCP\IUser');
+ $user->method('canChangeDisplayname')->willReturn(true);
+ $user->method('getUID')->willReturn('user');
+ $user->expects($this->once())
+ ->method('setDisplayName')
+ ->with('newDisplayName')
+ ->willReturn(false);
+ $user->method('getDisplayName')->willReturn('oldDisplayName');
+
+ $this->container['UserSession']
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($user);
+ $this->container['UserManager']
+ ->expects($this->once())
+ ->method('get')
+ ->with($user->getUID())
+ ->willReturn($user);
+
+ $subadmin = $this->getMockBuilder('\OC\SubAdmin')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $subadmin
+ ->method('isUserAccessible')
+ ->with($user, $user)
+ ->willReturn(false);
+
+ $this->container['GroupManager']
+ ->method('getSubAdmin')
+ ->willReturn($subadmin);
+ $this->container['GroupManager']
+ ->expects($this->once())
+ ->method('isAdmin')
+ ->with($user->getUID())
+ ->willReturn(false);
+
+ $expectedResponse = new DataResponse(
+ [
+ 'status' => 'error',
+ 'data' => [
+ 'message' => 'Unable to change full name',
+ 'displayName' => 'oldDisplayName',
+ ],
+ ]
+ );
+ $response = $this->container['UsersController']->setDisplayName($user->getUID(), 'newDisplayName');
+ $this->assertEquals($expectedResponse, $response);
+ }
}
diff --git a/tests/startsessionlistener.php b/tests/startsessionlistener.php
index 1f3573555ca..88544cc6ce9 100644
--- a/tests/startsessionlistener.php
+++ b/tests/startsessionlistener.php
@@ -44,4 +44,7 @@ class StartSessionListener implements PHPUnit_Framework_TestListener {
public function endTestSuite(PHPUnit_Framework_TestSuite $suite) {
}
+ public function addWarning(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_Warning $e, $time) {
+ }
+
}
diff --git a/version.php b/version.php
index 7f45f5899e1..44bddca0700 100644
--- a/version.php
+++ b/version.php
@@ -3,10 +3,10 @@
* @author Frank Karlitschek <frank@owncloud.org>
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
- * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
@@ -25,7 +25,7 @@
// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
// when updating major/minor version number.
-$OC_Version = array(9, 0, 0, 2);
+$OC_Version = array(9, 0, 0, 10);
// The human readable string
$OC_VersionString = '9.0 pre alpha';