Compare commits

...

298 Commits

Author SHA1 Message Date
C Montero-Luque
6774f60240 9.0.1 RC2 2016-04-01 23:00:23 +02:00
Thomas Müller
9c800f62dd Merge pull request #23590 from owncloud/fix-themes-for-stable9
[stable9] Fix for themes with .jpg backgrounds
2016-04-01 11:02:42 +02:00
Thomas Müller
059df32542 Merge pull request #23684 from owncloud/stable9-backport-23676
[stable9] Properly handle return values of OC_App::getAppInfo()
2016-04-01 11:02:09 +02:00
Morris Jobke
43579e784f Properly handle return values of OC_App::getAppInfo()
* fixes #23668
2016-04-01 09:16:47 +02:00
Thomas Müller
193a33a8ad Merge pull request #23709 from owncloud/stable9-make-sure-that-encrypted-version-is-set
[stable9] Make sure that the encrypted version is set
2016-04-01 09:08:50 +02:00
Thomas Müller
b84746ce36 Merge pull request #23710 from owncloud/fix_encryption_versions_on_external_storages_9.0
[stable9] fix creation of versions of encrypted files on external storages
2016-04-01 09:08:09 +02:00
Bjoern Schiessle
2cb45e71ea fix creation of versions of encrypted files on external storages
in order to create a 1:1 copy of a file if a version gets created
we need to store this information on copyBetweenStorage(). This
allows us to by-pass the encryption wrapper if we read the source file.
2016-03-31 23:18:45 +02:00
Thomas Müller
e3cc82df38 Merge pull request #23518 from owncloud/stable9-gdrive-stream-download
[stable9] GDrive stream download with RetryWrapper
2016-03-31 23:14:49 +02:00
Frank Karlitschek
05fd4f2da0 Merge pull request #23522 from owncloud/stable9-dropbox-stream-download
[stable9] Dropbox stream download with RetryWrapper
2016-03-31 21:18:29 +02:00
Lukas Reschke
d16553d2d8 Make sure that the encrypted version is set
The code path called when using external storage with WebDAV is using `\OC\Files\Storage\Wrapper\Encryption::getMetaData` which did not contain the actual encrypted version inside the cache entry version. This lead to the following:

1. User uploaded a file
2. File is created and `\OC\Files\Storage\Wrapper\Encryption::getMetaData` is called. It has an empty `encryptedVersion` but sets `encrypted` to either `true` or `false`.
3. The call when updating the file cache will use the old version.
2016-03-31 20:39:35 +02:00
Thomas Müller
8453073fdb Merge pull request #23689 from owncloud/revert-23629
Revert "Explicitly add the current principal to the acl in case of gr…
2016-03-31 12:32:34 +02:00
Thomas Müller
b6fb3148c2 Revert "Explicitly add the current principal to the acl in case of group sharing"
This reverts commit 52f4acf23d.
2016-03-31 11:22:47 +02:00
Thomas Müller
cfe0a6450e Merge pull request #23673 from owncloud/stable9-fix-sftp-retry-wrapper
[stable9] Use RetryWrapper for SFTP storage
2016-03-31 11:12:29 +02:00
Thomas Müller
5f5e13351a Merge pull request #23552 from owncloud/fix-group-sharing-for-v1-caldav-and-carddav-stable9
Fix group sharing for v1 caldav and carddav stable9
2016-03-31 11:12:12 +02:00
Thomas Müller
ef8b75960c Handle group shares of addressbooks on v1 as well ... now FINALLY .... 2016-03-31 09:07:36 +02:00
Thomas Müller
f28817aed5 Fix acls for calendar objects and cards - fixes #23273 2016-03-31 09:07:36 +02:00
Thomas Müller
cb300d164e Return proper current-user-principal on v1 endpoints - fixes #23306 2016-03-31 09:05:39 +02:00
Thomas Müller
e664e582fb Fix group shares on v1 caldav and carddav - fixes #23328 2016-03-31 09:05:39 +02:00
Thomas Müller
9bd5fd23e7 Merge pull request #23629 from owncloud/fix-group-sharing-access-stable9
Explicitly add the current principal to the acl in case of group sharing
2016-03-31 09:04:07 +02:00
Thomas Müller
835e24826d Merge pull request #23640 from owncloud/backport-23545-lock-mountpoint-on-removal
[9.0] Lock the mountpoint while removing
2016-03-31 08:59:28 +02:00
Thomas Müller
8d6aff69a8 Merge pull request #23659 from owncloud/backport-23654-xcache-availablility
[9.0] xcache.var_size with 64M should evaluate to isAvailable
2016-03-31 08:58:18 +02:00
Joas Schilling
7c7e079a36 Lock the mountpoint while removing 2016-03-30 23:50:10 +02:00
Lukas Reschke
1f7b037a59 Use RetryWrapper for SFTP storage
Equivalent to https://github.com/owncloud/core/pull/23442

Required for making encryption work with external storage reliable.
2016-03-30 23:01:42 +02:00
Vincent Petry
99843c06f9 GDrive stream download with RetryWrapper 2016-03-30 18:43:01 +02:00
Thomas Müller
ed88f7b8b5 Merge pull request #23664 from owncloud/stable9-share-displayownerfix
[stable9] Fix displaying owner before share icon in file list
2016-03-30 18:42:49 +02:00
Thomas Müller
03f89d8242 Merge pull request #23662 from owncloud/make-google-drive-drumpf-again
[stable9] Use the shipped cacerts.pem instead of the global one
2016-03-30 18:41:36 +02:00
Vincent Petry
f981661195 Fix displaying owner before share icon in file list
Initial display of owner was missing
2016-03-30 18:10:56 +02:00
Thomas Müller
424c2b8263 Merge pull request #23652 from owncloud/stable9_23651
[Stable 9] Non moveable mount points should always be UPDATE+DELETE shareable
2016-03-30 17:01:41 +02:00
Thomas Müller
2ab503f70a Merge pull request #23641 from owncloud/avatar-remove-9
[9.0] only remove avatars from the folder we store them in
2016-03-30 17:00:53 +02:00
Thomas Müller
cdff098357 Merge pull request #23618 from owncloud/backport-23543-activity-emails-always-short
Backport 23543 activity emails always short
2016-03-30 16:59:22 +02:00
Lukas Reschke
57596e1415 Use the shipped cacerts.pem instead of the global one
The one we ship may cause problems since Equifax is not included anymore (SHA-1 certs) are deprecated. We should just be consistent here and also use the certificate file which is used by the other calls in the library.
2016-03-30 16:55:26 +02:00
Joas Schilling
dd8d1c2b94 xcache.var_size with 64M should evaluate to isAvailable 2016-03-30 16:43:28 +02:00
Roeland Jago Douma
2660cf80c3 Non moveable mount points should always be UPDATE+DELETE shareable
Fixes #23536

The new sharing code is much stricter in checking permissions. However
for non moveable mounts the permissions UPDATE+DELETE are not reported
on the mount point.

This is just a quick fix.

* Updated unit tests
2016-03-30 13:42:08 +02:00
Robin Appelman
3cadc45ca5 only remove avatars from the folder we store them in 2016-03-30 10:25:37 +02:00
Thomas Müller
8c9842fbd9 Fix unit test 2016-03-30 10:01:17 +02:00
Thomas Müller
456035a750 Merge pull request #23631 from owncloud/stable9-upload-white
[stable9] correct form of upload-white icon to be same as upload icon
2016-03-30 09:09:20 +02:00
C Montero-Luque
fb77aa2e62 9.0.1 RC1 2016-03-29 22:03:08 +02:00
Jan-Christoph Borchardt
3b4999c835 correct form of upload-white icon to be same as upload icon 2016-03-29 19:18:54 +02:00
Thomas Müller
52f4acf23d Explicitly add the current principal to the acl in case of group sharing 2016-03-29 19:09:31 +02:00
Thomas Müller
6b7c694a42 Merge pull request #23582 from owncloud/avatar-save-failure-9
[9.0] dont die when we cant save the resized avatar, log instead
2016-03-29 18:49:22 +02:00
Thomas Müller
605abf9088 Merge pull request #23570 from owncloud/stable9-dav-sharetypes-remote
[stable9] Return remote shares in oc:share-types Webdav property
2016-03-29 18:41:25 +02:00
Joas Schilling
b5922e467a Allow the activity app to set the current user when sending emails 2016-03-29 09:12:12 +02:00
Joas Schilling
1733b6e8c8 We are only formatting an object when it's not null 2016-03-29 09:11:48 +02:00
Daniel Hansson
c066882309 [stable9] Fix for themes with .jpg backgrounds
Without this all themes with .jpg or .jpeg are broken.
2016-03-26 15:10:04 +01:00
Robin Appelman
b456035aa7 dont die when we cant save the resized avatar, log instead 2016-03-25 14:13:17 +01:00
Thomas Müller
03f461591e Merge pull request #23550 from owncloud/backport-23542
[stable9] getAppPath can return false
2016-03-24 22:44:31 +01:00
Vincent Petry
1f4738c372 Return remote shares in oc:share-types Webdav property
Fixes web UI to properly display the share status icon when an outgoing
remote share exists
2016-03-24 17:22:09 +01:00
Thomas Müller
af7c34d9a6 Merge pull request #23401 from owncloud/backport-23282-stable9
[stable9] fix writing to cache when fallback server should be used immediately
2016-03-24 13:30:44 +01:00
Thomas Müller
515ebc02b0 Merge pull request #23539 from owncloud/backport-23530
[stable9] Backport 23530
2016-03-24 13:06:00 +01:00
Lukas Reschke
0bb7644150 getAppPath can return false
Fixes https://github.com/owncloud/core/issues/23533
2016-03-24 12:22:42 +01:00
Thomas Müller
c9eadb7b77 Merge pull request #23520 from owncloud/node-get-from-cache-9
[9.0] Query the cache when checking if a node exists
2016-03-24 11:58:48 +01:00
Lukas Reschke
2139130ec8 Check if request is sent from official ownCloud client
There are authentication backends such as Shibboleth that do send no Basic Auth credentials for DAV requests. This means that the ownCloud DAV backend would consider these requests coming from an untrusted source and require higher levels of security checks. (e.g. a CSRF check)

While an elegant solution would rely on authenticating via token (so that one can properly ensure that the request came indeed from a trusted client) this is a okay'ish workaround for this problem until we have something more reliable in the authentication code.
2016-03-24 09:00:35 +01:00
Vincent Petry
195cf4111e Dropbox stream download with RetryWrapper 2016-03-23 18:07:13 +01:00
Vincent Petry
443d72ee87 Fix dropbox storage to not store the whole file in memory
Since the library can only store the full response in memory on
download, we use an alternate client lib and set the correct headers to
be able to stream the content to a temp file.
2016-03-23 18:07:13 +01:00
Robin Appelman
5a630c6a0e properly use fileinfo objects 2016-03-23 17:13:32 +01:00
Robin Appelman
24670b4218 set watch policy in test 2016-03-23 17:13:28 +01:00
Robin Appelman
c864420d6c improve reuse in getUserFolder 2016-03-23 17:13:24 +01:00
Robin Appelman
f77ce8829c pass the fileinfo to the node if available 2016-03-23 17:13:21 +01:00
Robin Appelman
70a5233f69 Query the cache when checking if a node exists 2016-03-23 17:13:17 +01:00
Thomas Müller
5ca10cf6f8 Merge pull request #23308 from owncloud/smb-not-available-9
[9.0] handle connection errors as storage not available in smb
2016-03-23 11:03:15 +01:00
Thomas Müller
0009bf244b Merge pull request #23464 from owncloud/stable9-backport-23443
[stable9] Log more information by default
2016-03-23 09:13:10 +01:00
Thomas Müller
3d0e4bdc82 Merge pull request #23493 from owncloud/stable9_22679
[Stable 9] When the Share API is disabled do not return shares
2016-03-23 08:07:06 +01:00
Thomas Müller
6edf403f3f Merge pull request #23475 from owncloud/stable9-RealRancor-exclude_lost_and_found
[stable9] Exclude lost+found dir in integrity check
2016-03-23 08:06:36 +01:00
Lukas Reschke
43516ebef9 Only use the user session if ownCloud is already installed
When installing ownCloud with autotest and MySQL some log entries may be created which will invoke the logging class. IUserSession has a dependency on the database which will make the installation fail => 💣
2016-03-22 22:27:35 +01:00
C Montero-Luque
53f95373ba 9.0.1 beta 2016-03-22 17:01:51 -04:00
Thomas Müller
a9c13dc58a Merge pull request #23361 from owncloud/stable9-gdrive-chunkupload
[stable9] Chunk upload for GDrive
2016-03-22 21:27:14 +01:00
Roeland Jago Douma
7fb32f8358 When the Share API is disabled do not return shares
Fixes #22668

Block everything in the OCS Share API
2016-03-22 19:51:01 +01:00
Thomas Müller
656c7f38b6 Merge pull request #23478 from owncloud/backport-l10n
Backport translations to stable9
2016-03-22 17:44:59 +01:00
Thomas Müller
97dc57a143 Merge pull request #23456 from owncloud/backport-23329-stable9
[stable9] Avatar must be saved after login is done and external storages set up…
2016-03-22 17:40:48 +01:00
Thomas Müller
3b98e8c56d Merge pull request #23467 from owncloud/early-creation-of-birthday-calendar-stable9
Create the contact birthday calendar right away as soon as the comman…
2016-03-22 17:28:11 +01:00
Thomas Müller
1a100c69ba Merge pull request #23473 from owncloud/stable9_23398
[stable 9]  Allow blocking of group sharing
2016-03-22 17:16:23 +01:00
Thomas Müller
03fcbc8ceb Merge pull request #23479 from owncloud/backport-23461-activity-without-sharing
[9.0] Fix "AutoloadNotAllowedException" when files_sharing is disabled
2016-03-22 17:15:24 +01:00
Thomas Müller
49b5b1b08c Merge pull request #23447 from owncloud/smb-permissions-9
[9.0] properly use smb permissions
2016-03-22 17:12:41 +01:00
Thomas Müller
2da2f26e56 Merge pull request #23466 from owncloud/backport-23448-exception-on-enabling-default-app
[9.0] Do not abort with an exception when a default app can not be enabled
2016-03-22 16:26:06 +01:00
Thomas Müller
d60f39e4f2 Merge pull request #23442 from owncloud/fix_22286_9.0
[stable9] apply retry wrapper to make sure that we always read/write a complete block
2016-03-22 16:23:54 +01:00
Thomas Müller
329e72a286 Merge pull request #23480 from owncloud/backport-23404-stable9
[stable9] adjust PrincipalUri as returned from Sabre to effective username
2016-03-22 16:20:22 +01:00
Arthur Schiwon
90a2be58f8 adjust PrincipalUri as returned from Sabre to effective username
backport of #23404
2016-03-22 15:24:01 +01:00
Thomas Müller
9b2fdc5358 Merge pull request #23359 from owncloud/streams-0.4-9
[9.0] Update icewind/streams and icewind/smb
2016-03-22 15:10:36 +01:00
Joas Schilling
0d9edd80f1 Fix "AutoloadNotAllowedException" when files_sharing is disabled 2016-03-22 15:01:52 +01:00
Joas Schilling
4fdb2254a4 Backport translations to stable9 2016-03-22 13:10:33 +01:00
RealRancor
b3ead7568d Exclude lost+found dir in integrity check 2016-03-22 12:59:18 +01:00
Roeland Jago Douma
f8f292ab16 Fix js strings if group sharing is disabled 2016-03-22 12:37:45 +01:00
Roeland Jago Douma
c7f1b82b4b Respect disabled group sharing in sharee endpoint
* Fix tests
2016-03-22 12:37:34 +01:00
Roeland Jago Douma
aa75cfcf14 Block group sharing in API and in share manager
* Fix tests
2016-03-22 12:37:20 +01:00
Roeland Jago Douma
e9fc791e9f Add config to sharemanager 2016-03-22 12:37:08 +01:00
Roeland Jago Douma
4d8c81a2d9 Add allow sharing with groups checkbox to admin page 2016-03-22 12:36:59 +01:00
Thomas Müller
ad852ca24a Create the contact birthday calendar right away as soon as the command is executed once - fixes #23203 2016-03-22 10:31:53 +01:00
Joas Schilling
50e94db4d5 Do not abort with an exception when a default app can not be enabled 2016-03-22 10:28:59 +01:00
Thomas Müller
ae2c207b6e Merge pull request #23453 from owncloud/generate-birthdays-on-upgrade-stable9
Generate birthdays on upgrade stable9
2016-03-22 10:17:41 +01:00
Thomas Müller
f5fe2b4d08 Merge pull request #23462 from owncloud/backport-23422-comments-activities
[9.0] Add comment icons and "You commented" translations
2016-03-22 10:05:25 +01:00
Robin Appelman
77afc18b82 properly use smb permissions 2016-03-22 09:57:38 +01:00
Vincent Petry
3a955ca43c Adjusted 3rdparty submodule commit 2016-03-22 09:46:32 +01:00
Robin Appelman
204288f4a5 update icewind/smb to 1.0.8 2016-03-22 09:46:32 +01:00
Robin Appelman
8af75c734a update icewind/streams to 0.4.0 and icewind/smb to 1.0.7 in files_external 2016-03-22 09:46:32 +01:00
Lukas Reschke
177ad39854 Log more information by default
This modifies the logger to add the following logging information by default:

- Request Method
- Request URL
- Current user
2016-03-22 09:46:02 +01:00
Joas Schilling
d59860aacd Add comment icons and "You commented" translations 2016-03-22 08:55:32 +01:00
Arthur Schiwon
f6b6813f5f Avatar must be saved after login is done and external storages set up properly, fixes #21555 2016-03-21 22:20:50 +01:00
Thomas Müller
da95db78d0 Merge pull request #23436 from owncloud/backport-23388-infinite-cronjob
[9.0] Do not create a new job when it failed to connect atm
2016-03-21 18:05:30 +01:00
Thomas Müller
3d19a179c7 Merge pull request #23383 from owncloud/backport-use-raw-path
[stable9] Use raw PATH_INFO
2016-03-21 18:03:10 +01:00
Thomas Müller
3f4be066f9 Generate birthdays on upgrade from 8.2 as well 2016-03-21 17:53:03 +01:00
Thomas Müller
419adc8d50 Birthday events are generated on upgrade 2016-03-21 17:52:59 +01:00
Bjoern Schiessle
627724bc6a apply retry wrapper to make sure that we always read/write a complete block 2016-03-21 15:18:13 +01:00
Thomas Müller
b3fef39006 Merge pull request #23307 from owncloud/stable9-update-sabre3.0.8-fseek-only
[stable9] Update 3rdparty submodule for sabre 3.0.8 update
2016-03-21 14:31:18 +01:00
Thomas Müller
3d9187e231 Merge pull request #23390 from owncloud/stable9-share-keepoptioncheckboxinblocks
[stable9] Keep share checkboxes together
2016-03-21 14:15:40 +01:00
Joas Schilling
1a239b2f0d Do not create a new job when it failed to connect atm 2016-03-21 14:00:29 +01:00
Thomas Müller
6afac05937 Merge pull request #23389 from owncloud/backport-23287-fed-share-action-links
[9.0] Make sure to append the web root as per doc
2016-03-21 11:16:15 +01:00
Thomas Müller
571de654cd Merge pull request #23378 from owncloud/stable9-backport-23370
[stable9] Update avatar on username change if avatar is set
2016-03-21 09:49:32 +01:00
Thomas Müller
546a0929a6 Merge pull request #23163 from owncloud/stable9-wording
[stable9] Adjust wording a bit
2016-03-21 09:48:49 +01:00
Thomas Müller
fefaa1fd87 Merge pull request #23293 from owncloud/backport-23108
[stable9] Ensure that stored version is at least 1 for cross-storage copy
2016-03-21 09:48:15 +01:00
Thomas Müller
ce0f68c7ce Merge pull request #23382 from owncloud/backport-fix-htaccess-issues
[stable9] Write .htaccess update only if not already written
2016-03-21 09:42:57 +01:00
Thomas Müller
660c0da0a9 Merge pull request #23384 from owncloud/stable9-dav-sharesproperty
[stable9] Add webdav share-types property to fix favorites/tags share status icon
2016-03-21 09:42:36 +01:00
Thomas Müller
179ac2b98c Merge pull request #23387 from owncloud/stable9-systemtags-create-same-prefix
[stable9] Allow creating tags where another one with same prefix exists
2016-03-21 09:42:18 +01:00
Arthur Schiwon
d282affec2 fix writing to cache when fallback server should be used immediately 2016-03-18 20:34:23 +01:00
Vincent Petry
8ef8be6be5 Keep share checkboxes together
- removed leading spaces before markup which can affect rendering in
  some cases
- added shareOption CSS class to group and keep share option checkbox +
  label
- moved ".showCruds" arrow into the matching shareOption to keep the
  arrow together with the checkbox
2016-03-18 14:16:26 +01:00
Joas Schilling
064e13511f Make sure to append the web root as per doc 2016-03-18 13:36:51 +01:00
Vincent Petry
a7dfc70e2e Allow creating tags where another one with same prefix exists
When creating a new entry, compare the full tag name and not only the
prefix.
2016-03-18 12:32:29 +01:00
Roeland Jago Douma
df056e1299 Remove duplicated copyright 2016-03-18 11:38:02 +01:00
Roeland Jago Douma
26deb0a897 Add intergration tests
Intergration tests to ensure the share-types property is set correctly.

* Unshared item
* Shared with user
* Shared with group
* Shared by link
* Shared with user & group & link
2016-03-18 11:37:56 +01:00
Vincent Petry
3c77311397 Display share status info in favorite list
Returns the shareTypes share status info to the favorites file list.
2016-03-18 11:36:43 +01:00
Vincent Petry
fb705fa305 Add webdav property for share info in PROPFIND response 2016-03-18 11:36:39 +01:00
Vincent Petry
c513317c49 Update 3rdparty submodule for sabre 3.0.8 update 2016-03-18 11:03:41 +01:00
Lukas Reschke
d9b632c001 Use raw PATH_INFO
PATH_INFO will be empty at this point and thus the logic in base.php did not catch this. Changing this to "getRawPathInfo" will ensure that the path info is properly read.

Fixes https://github.com/owncloud/core/issues/23199
2016-03-18 10:30:26 +01:00
Lukas Reschke
1fdf790c8f Write .htaccess update only if not already written
The ownCloud update routine also runs the "updateHtaccess" code in case only an application gets updated. This leads to having entries multiple time in the .htaccess file leading to unpredictable behaviour.

With 9.0 we added the "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####" entry to the .htaccess file, this change uses it to ensure that only to the .htaccess gets written if the file has not been modified already. Since the .htaccess modifications are optional this is not a big deal.

Without this change updates of applications can break the rewrite rules (ending in endless redirects) as well as breaking the code integrity checker.
2016-03-18 09:18:46 +01:00
Morris Jobke
d65c3a77e2 Update avatar on username change if avatar is set
* fixes #20455
2016-03-18 08:51:29 +01:00
Thomas Müller
382b18e85e Merge pull request #23309 from owncloud/backport-23164-stable9
[stable9] Prevent certain DBs throwing exceptions on same-value updates
2016-03-17 20:52:11 +01:00
Thomas Müller
9e5c5c804b Merge pull request #23358 from owncloud/stable9-backport-occ-typos
Some typo corrections in occ command output
2016-03-17 20:50:41 +01:00
Thomas Müller
7d80b20368 Merge pull request #23355 from owncloud/stable9_backport_23346
[Stable 9] Set proper public webdav permissions when public upload disabled
2016-03-17 17:14:13 +01:00
Vincent Petry
1e1c0885c6 Only use GDrive chunks when needed 2016-03-17 16:12:42 +01:00
Vincent Petry
8e0b78c746 Chunk upload for GDrive
Instead of storing the WHOLE file in memory in a PHP variable, use the
library's chunk upload support.
2016-03-17 16:12:38 +01:00
Carla Schroder
e7152f495c Some typo corrections in occ command output 2016-03-17 07:05:34 -07:00
Thomas Müller
00ef623f1c Merge pull request #23259 from owncloud/backport-22998
[stable9] Delay check till scanner is used
2016-03-17 14:29:39 +01:00
Roeland Jago Douma
9dfcb55a2f Set proper public webdav permissions when public upload disabled
Fixes #23325

It can happen that a user shares a folder with public upload. And some
time later the admin disables public upload on the server.

To make sure this is handled correctly we need to check the config value
and reduce the permissions.

Fix is kept small to be easy backportable.
2016-03-17 13:54:53 +01:00
Thomas Müller
ec4c5a3e75 Merge pull request #23128 from owncloud/contacts_calendar_name_color-stable9
add title and color to birthday calendar
2016-03-17 13:08:03 +01:00
Thomas Müller
f46225fa2c Merge pull request #23335 from owncloud/ext-user-mounting-gui-stable9
[stable9] Display external storage GUI even if user mounting disabled
2016-03-17 12:25:53 +01:00
Thomas Müller
f28f6a3001 Merge pull request #23302 from owncloud/fed-unshare-with-9
[9.0] Specify the target user when unsharing a federated share
2016-03-17 10:07:19 +01:00
Thomas Müller
25027c31ff Merge pull request #23313 from owncloud/check-syntax-travis-stable9
[stable9] Execute parallel-lint
2016-03-17 09:29:26 +01:00
Joas Schilling
b8af6e703a Don't try to execute a dav syntax test 2016-03-17 09:07:55 +01:00
Robin McCorkell
403eb87f4d Display external storage GUI even if user mounting disabled 2016-03-16 22:10:36 +00:00
Thomas Müller
ed4ed0e26f Merge pull request #23319 from owncloud/backport-23189-1
[stable9] Require at least libxml 2.7.0
2016-03-16 21:53:33 +01:00
Thomas Müller
24dcdf9d5c Merge pull request #23324 from owncloud/stable9-backport-23253
[stable9] Give swift 15 seconds after startup
2016-03-16 21:53:09 +01:00
Morris Jobke
3a773f4eca Give swift 15 seconds after startup 2016-03-16 18:08:42 +01:00
Lukas Reschke
e71ebf334d [stable9] Execute parallel-lint
Backport of #22994 and #23303
2016-03-16 17:31:18 +01:00
Thomas Müller
08b9193919 Merge pull request #23315 from owncloud/travis-stable9
Execute travis on stable9 as well
2016-03-16 17:29:27 +01:00
Lukas Reschke
dbcb037639 Require at least libxml 2.7.0
Fixes https://github.com/owncloud/core/issues/23168
2016-03-16 17:13:13 +01:00
Thomas Müller
adbc5bbd1f Merge pull request #23271 from owncloud/backport-23192
[stable9] Backport 23192
2016-03-16 16:50:04 +01:00
Thomas Müller
4720719b08 Merge pull request #23270 from owncloud/backport-fix-support-for-php7-in-htaccess
[stable9] Backport fix support for php7 in htaccess
2016-03-16 16:49:38 +01:00
Morris Jobke
7b818d9442 Execute travis on stable9 as well
Backport of #23100 to stable9
2016-03-16 15:39:07 +01:00
Robin McCorkell
aa91d50d04 Prevent certain DBs throwing exceptions on same-value updates
A PreconditionNotMetException must only be thrown if explicit
preconditions are specified for setValues(), not if the value is merely
the same as was already in the DB.
2016-03-16 14:50:00 +01:00
Robin Appelman
95cd1671b3 handle connection errors as storage not available in smb 2016-03-16 14:47:03 +01:00
Robin Appelman
8c035ae6f6 Specify the target user when unsharing a federated share 2016-03-16 13:29:04 +01:00
Thomas Müller
d54106dada Merge pull request #23264 from owncloud/fix_22907_9.0
allow group shares, even if not all public keys are available
2016-03-16 11:18:51 +01:00
Lukas Reschke
f9ad57ee52 Ensure that stored version is at least 1 for cross-storage copy
In case of a move operation from an unencrypted to an encrypted
storage the old encrypted version would stay with "0" while the
correct value would be "1". Thus we manually set the value to "1"
for those cases.

See also https://github.com/owncloud/core/issues/23078
2016-03-16 10:37:41 +01:00
Lukas Reschke
cdadd4cd1b Fallback for crappy ancient distributions
Fixes https://github.com/owncloud/core/issues/23181
2016-03-15 17:14:53 +01:00
Lukas Reschke
6f7fc6c5db always_populate_raw_post_data has been removed with PHP 7.0 2016-03-15 17:03:19 +01:00
Lukas Reschke
9ef7340dc7 Add support for custom values in integrity checker 2016-03-15 17:03:16 +01:00
Lukas Reschke
d1978a6950 Replace all required values 2016-03-15 17:03:13 +01:00
Lukas Reschke
dfc7e6b421 Duplicate block for PHP 7 2016-03-15 17:03:09 +01:00
Thomas Müller
b580d26270 Merge pull request #23237 from owncloud/backport-22901
[stable9] Add DAV authenticated also to other scopes
2016-03-15 16:03:35 +01:00
Thomas Müller
5466a800fa Merge pull request #23252 from owncloud/invalid-share-storage-9
[9.0] dont break when there is an invalid share
2016-03-15 15:59:24 +01:00
Bjoern Schiessle
0f372a2a8c allow group shares, even if not all public keys are available 2016-03-15 15:13:55 +01:00
Lukas Reschke
987146d5db Delay check till scanner is used
Fixes https://github.com/owncloud/core/issues/22973 and https://github.com/owncloud/core/issues/22987
2016-03-15 14:39:16 +01:00
Robin Appelman
9d688e655d move failedstorage to core 2016-03-15 12:49:12 +01:00
Robin Appelman
f29440dbbc dont break when there is an invalid share 2016-03-15 12:49:06 +01:00
Thomas Müller
5a6b2956d8 Merge pull request #23022 from owncloud/stable9_backport_22602
[stable 9]   Do not check all chunks of a chunked upload if we do not need to
2016-03-15 12:15:45 +01:00
Thomas Müller
99de93a6c6 Merge pull request #23075 from owncloud/backport-23074-oracle-ext-storage
[9.0] Correctly escape join statements and use selectAlias
2016-03-15 12:13:54 +01:00
Thomas Müller
4159187a6e Merge pull request #23229 from owncloud/backport-23218-memcached-exceptions-on-success
[9.0] Fix errors in memcached implementation
2016-03-15 12:10:23 +01:00
Thomas Müller
6f64c99653 Merge pull request #23230 from owncloud/backport-23191
[stable9] Verify the getResponse returns a ResponseInterface
2016-03-15 12:09:55 +01:00
Thomas Müller
ce0f28c123 Merge pull request #23231 from owncloud/backport-23190
[stable9] Use proper URLs for search results
2016-03-15 12:07:45 +01:00
Thomas Müller
cca3a249fd Merge pull request #23240 from owncloud/backport-23222
backport of #23222
2016-03-15 12:07:15 +01:00
Thomas Müller
0608455b01 Merge pull request #23247 from owncloud/stable9_backport_23226
[stable 9] Generate a valid URL for link notification
2016-03-15 12:06:41 +01:00
Roeland Jago Douma
3a5e90fa03 Generate a valid URL for link notification
fixes #23197

* Updated unit test
2016-03-15 07:34:53 +01:00
Phiber2000
e2c557ab82 backport of #23222 (#23225) 2016-03-14 17:59:40 +01:00
Lukas Reschke
e1727477ac Add DAV authenticated also to other scopes
Fixes https://github.com/owncloud/core/issues/22893
2016-03-14 17:57:37 +01:00
Thomas Müller
cf232c4182 Merge pull request #23112 from owncloud/backport-23086-stable9
[9.0] remove deprecated ldap_sort
2016-03-14 17:16:36 +01:00
Thomas Müller
efa673136e Merge pull request #23223 from owncloud/backport-23091-case-insensitive-group-sharing
[9.0] Case insensitive group sharing
2016-03-14 16:33:51 +01:00
Thomas Müller
3380a3af74 Merge pull request #22949 from owncloud/stable9-fix-group-share-migration-for-calendars-and-contacts
Fix group sharing and sharing permissions - fixes #22932
2016-03-14 16:31:08 +01:00
Thomas Müller
80d0e43fc7 Merge pull request #22933 from owncloud/stable9-backport-22872
[stable9] Update error text for link passwords
2016-03-14 16:20:00 +01:00
Lukas Reschke
effc522572 Use proper URLs for search results
Fixes https://github.com/owncloud/core/issues/23136
2016-03-14 16:16:25 +01:00
Thomas Müller
689f3dea45 Merge pull request #22943 from owncloud/backport-22800-stable9
[9.0] don't hide server not available exception, fixes #20536
2016-03-14 16:15:50 +01:00
Lukas Reschke
3a73f97706 Verify the getResponse returns a ResponseInterface
Can also return `null` as per PHPDoc. Regression added by 97f5c095f4

Fixes https://github.com/owncloud/core/issues/23145
2016-03-14 16:15:18 +01:00
Thomas Müller
a09ffb274b Merge pull request #23065 from owncloud/stable9-add-rewrite-rules-after-setup
[stable9] Add base rewrite rule only when RewriteBase is defined
2016-03-14 16:14:21 +01:00
Thomas Müller
2609bf3500 Merge pull request #23114 from owncloud/no-fatal-error-if-DSTART-is-not-set-stable9
No fatal error if dstart is not set stable9
2016-03-14 16:14:03 +01:00
Joas Schilling
9190885b4e Fix errors in memcached implementation 2016-03-14 16:13:35 +01:00
Thomas Müller
f79195853e Merge pull request #23221 from owncloud/backport-23214-url-cache-key-length
[9.0] Shorter cache key for URL entries
2016-03-14 16:08:29 +01:00
Thomas Müller
884a3b9bb4 Merge pull request #23105 from owncloud/readonly-birthday-cal-stable9
The birthday_calendar is read-only
2016-03-14 16:07:42 +01:00
Joas Schilling
a9ed80869a Correctly lower the search input as well 2016-03-14 13:48:45 +01:00
Joas Schilling
8e49a99896 Add integration tests for sharee API 2016-03-14 13:48:21 +01:00
Joas Schilling
5b593450c3 Return the correct group casing in sharee api 2016-03-14 13:48:13 +01:00
Joas Schilling
69cf557d0b Shorter cache key for URL entries 2016-03-14 13:34:34 +01:00
Thomas Müller
5c38c1c845 Merge pull request #23156 from owncloud/add-port-support-to-trusteddomain-stable9
Explicitly check for port
2016-03-14 12:30:58 +01:00
Thomas Müller
dac69225d2 Merge pull request #23102 from owncloud/stable9-backport-23094
[stable9] Fake LOCK statement for Windows 7, 8 and 10 network mounts
2016-03-13 19:51:26 +01:00
Lukas Reschke
f984718921 Adjust wording a bit
**Before:**
> Your PHP version (5.4.16) is no longer supported by PHP. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP.

**After:**
> You are currently running PHP 5.4.0. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by the PHP Group as soon as your distribution supports it.

Fixes https://github.com/owncloud/enterprise/issues/1170
2016-03-11 17:46:21 +01:00
Thomas Müller
b752a08d63 Merge pull request #23127 from owncloud/fix-getOwner-on-fileshome-stable9
getOwner is not available on FileHome - fixes #23116
2016-03-11 15:05:20 +01:00
Lukas Reschke
9bc99bb297 Explicitly check for port
The setup uses `\OCP\IRequest::getInsecureServerHost` which in some cases can also include a port. This makes the trusted domain check fail thus.

I've decided to add this here that way because adjusting the setup would require parsing the host properly. This is not something that can be done very good in PHP. Check the following example for why `parse_url` is not our friend: https://3v4l.org/k501Z
2016-03-11 14:54:20 +01:00
Thomas Müller
e3de44ea51 Merge pull request #23060 from owncloud/stable9_backport_23056
[stable 9] Add mimetype to OCS Share API output
2016-03-11 14:51:21 +01:00
Thomas Müller
aeb480a8c3 Merge pull request #23113 from owncloud/allow-migrating-all-calendars-stable9
Allow to migrate calendars of all users
2016-03-10 23:10:41 +01:00
Georg Ehrke
b0c7eba7d0 add title and color to birthday calendar 2016-03-10 22:55:32 +01:00
Thomas Müller
e89f27e191 getOwner is not available on FileHome - fixes #23116 2016-03-10 22:51:02 +01:00
Lukas Reschke
bd17cc793c Improved rewrite rule
As per https://github.com/owncloud/core/issues/23098 and https://github.com/owncloud/core/issues/23117
2016-03-10 22:18:53 +01:00
Thomas Müller
62a36ee884 The birthday_calendar is read-only 2016-03-10 21:36:11 +01:00
Thomas Müller
a58e374956 Merge pull request #22909 from owncloud/backport-22244-prevent-calendar-proppatch
[9.0] Prevent calendar proppatch for share recipients
2016-03-10 21:32:38 +01:00
Roeland Jago Douma
67c4759017 Add intergration tests 2016-03-10 21:20:49 +01:00
Thomas Müller
36b543c490 fixes #23004 2016-03-10 17:59:02 +01:00
Thomas Müller
8465f9b6c6 fixes #23020 2016-03-10 17:58:53 +01:00
Thomas Müller
281a0e9e03 Merge pull request #23096 from owncloud/stable9_backport_23084
[stable 9] Fix MKCOL for IE11 as well
2016-03-10 17:49:01 +01:00
Joas Schilling
7126b64088 Allow to migrate calendars of all users 2016-03-10 17:47:08 +01:00
Arthur Schiwon
38d137c34c remove deprecated ldap_sort 2016-03-10 17:08:25 +01:00
Morris Jobke
098ce188b7 Fake LOCK statement for Windows 7, 8 and 10 network mounts
* fixes #22596
2016-03-10 15:57:33 +01:00
Thomas Müller
730620cfb2 Merge pull request #22912 from owncloud/stable9-diskfreespace-filesworkaround
[stable9] Fix call to disk_free_space when a file is provided
2016-03-10 15:31:38 +01:00
Roeland Jago Douma
dd7131512d Fix MKCOL for IE11 as well
Using https://github.com/owncloud/core/pull/22274 we have to patch the
iedavclient.js as well.
2016-03-10 15:18:58 +01:00
Thomas Müller
85168315ab Merge pull request #23071 from owncloud/backport-23032-no-response-on-cli
[9.0] Do not set response status in CLI in case of error
2016-03-10 10:54:25 +01:00
Joas Schilling
09febaad49 Correctly escape join statements and use selectAlias 2016-03-10 10:28:39 +01:00
Thomas Müller
83894b58fe Merge pull request #23016 from owncloud/stable9_backport_23008
[stable 9] Select queries in the default share provider should query for file/folder
2016-03-10 09:10:22 +01:00
Vincent Petry
f374368568 Do not set response status in CLI in case of error 2016-03-10 08:57:29 +01:00
Thomas Müller
4030b82c97 Merge pull request #23030 from owncloud/require-xmlreader
[stable9] Add XMLReader as requirement
2016-03-10 08:26:48 +01:00
Thomas Müller
4e90bc017e Merge pull request #22825 from owncloud/backport-22778-stable9
[backport] [stable9] untangle different user manager instances, fixes #22770
2016-03-10 08:26:11 +01:00
Lukas Reschke
b315a5ee29 Add base rewrite rule only when RewriteBase is defined
In case Apache is configured with an `Alias` such as with the ownCloud packages the rewrite rules will fail when no valid RewriteBase is configured.
2016-03-09 22:41:32 +01:00
Thomas Müller
b017434302 Merge pull request #23024 from owncloud/stable9-backport-22986
[stable9] Remove disabled autocorrect for new file names
2016-03-09 21:44:47 +01:00
Roeland Jago Douma
48cdf38d00 Add mimetype to OCS Share API output
Fixes #23044
2016-03-09 21:28:38 +01:00
Vincent Petry
11f76b2918 Fix call to disk_free_space when a file is provided
In the case of shared files, we have to call free_space() on the file
name. This has the side-effect that when uploading to a local storage
without quota set, it will call disk_free_space with the file name,
which fails.

This fix uses the parent folder in case the given path is a file.
2016-03-09 15:53:37 +01:00
Lukas Reschke
316f86f2a3 Add XMLReader as requirement
The SabreDAV release in 9.0 requires XMLReader, while this is usually compiled in by default some distributions like Gentoo don't.

Without this ownCloud gives a fatal 500 error instead of telling people to enable XMLReader.

Fixes https://github.com/owncloud/core/issues/23003
2016-03-09 15:29:08 +01:00
Thomas Müller
bd144efeb1 Merge pull request #22990 from owncloud/stable9-backport-has-key
[stable9] Use "hasKey" instead of checking the value
2016-03-09 15:04:59 +01:00
Morris Jobke
88b9db44a0 Remove disabled autocorrect for new file names
* ref #22784
2016-03-09 14:59:57 +01:00
Roeland Jago Douma
91c7d293ca Added tests
* Unit tests for OC_Filechunking to verify the isComplete function
* Intergration tests to show that shuffling chunks is all fine
2016-03-09 14:48:42 +01:00
Roeland Jago Douma
313b881d2b Do not check all chunks of a chunked upload if we do not need to
Fixes #22601

Before we did a full test on all chunks to verify if a chunked upload
was completed. This is unneeded since if we are missing one chunk we can
already fail.

Also we look from back to front since it is much more likely that we
find a missing chunk thus can error out early.
2016-03-09 14:48:31 +01:00
Roeland Jago Douma
9120448302 Select queries in the default share provider should query for file/folder
There can be leftover calendar and contacts shares in the oc_share
table. We need to filter those out properly.
2016-03-09 13:56:35 +01:00
Thomas Müller
d4d4b8d51a Merge pull request #22841 from owncloud/stable9_22830
[Stable 9] Rename and move permissions are set when a file is updatable
2016-03-09 12:27:03 +01:00
Thomas Müller
b955ce6141 Merge pull request #22886 from owncloud/stable9-show-version-to-update-to
[stable9] Show version to update to properly
2016-03-09 12:26:53 +01:00
Thomas Müller
e2b43c4095 Merge pull request #22908 from owncloud/backport-22904-group-manager-wrong-return
[9.0] Make sure that the return value is an array
2016-03-09 12:26:42 +01:00
Thomas Müller
d84cccb911 Merge pull request #22919 from owncloud/backport-double-url-encoding
[stable9] Remove double URL encoding
2016-03-09 12:26:29 +01:00
Thomas Müller
c2a16e0584 Merge pull request #22922 from owncloud/stable9-share-archivenamedownloadall
[stable9] Fix archive file name when downloading public share
2016-03-09 12:26:18 +01:00
Thomas Müller
d652c87f86 Merge pull request #22924 from owncloud/stable9-versions-fixmtimetooltip
[stable9] Fix tooltip for versions mtime
2016-03-09 12:26:04 +01:00
Thomas Müller
72d4e672b2 Merge pull request #22925 from owncloud/stable9-trash-returnfalseon401
[stable9] Return false on 401 in file list + trash file list
2016-03-09 12:25:47 +01:00
Thomas Müller
95201a829f Merge pull request #22926 from owncloud/stable9-files-newmenu-removebrowsercomplete
[stable9] Remove browser autocomplete in new file menu
2016-03-09 12:25:30 +01:00
Thomas Müller
734b3e1408 Merge pull request #22965 from owncloud/stable9-fix-gdrive
[stable9] Fix compatibility with PHP 5.4
2016-03-09 12:20:24 +01:00
Lukas Reschke
ddf56b84d4 Use "hasKey" instead of checking the value
If the check is negative it would depending on the used cache store the value as an empty string. When reading the value this check would thus return "false" even if a value exists.
2016-03-09 09:19:11 +01:00
Lukas Reschke
1975ffa9e7 Fix compatibility with PHP 5.4
Fixes https://github.com/owncloud/core/issues/22960
2016-03-08 19:58:49 +01:00
C Montero-Luque
81f694d83e 9.0.0 2016-03-08 08:48:12 -05:00
Thomas Müller
8d6a6667e5 Fix group sharing and sharing permissions - fixes #22932 2016-03-08 14:45:36 +01:00
Thomas Müller
f9a80a9c12 Merge pull request #22945 from owncloud/stable9-fixsharemountrecursion
[stable9] Fix share mounting recursion
2016-03-08 14:42:04 +01:00
Vincent Petry
d63f5561fb Fix share mounting recursion 2016-03-08 12:58:46 +01:00
Arthur Schiwon
213dfa2b85 don't hide server not available exception, fixes #20536 2016-03-08 12:40:12 +01:00
Morris Jobke
859303164e Update error text for link passwords
* this removes the old tooltip first before showing
  the new one to update the text - otherwise the old
  text will be shown
2016-03-08 09:00:37 +01:00
Vincent Petry
795331212a Remove browser autocomplete in new file menu 2016-03-07 22:04:36 +01:00
Vincent Petry
c9476115b0 Return false on 401 in file list + trash file list
This gives a chance to the global ajax error handler to do its work if
the session expired.
2016-03-07 22:02:19 +01:00
Vincent Petry
cfd9c7f6b9 Fix tooltip for versions mtime
It was missing a call to jquery.tooltip
2016-03-07 21:58:17 +01:00
Vincent Petry
ebfc8b67d7 Remove "files" arg from download URL in public link page
When no files were specified for download, it means folder download.
In this case, no need to pass an empty "files" argument.
2016-03-07 21:48:15 +01:00
Vincent Petry
f9e1d4d56e Fix archive file name when downloading public share
When download a public link share folder using the button on the top
right, it doesn't provide a list of files.

This fix makes sure to trigger the correct logic when no file list was
given.
2016-03-07 21:48:10 +01:00
Lukas Reschke
fab42c7cd2 Remove double URL encoding
ZipStreamer as bundled with 9.0 will properly encode the filename already.

Fixes https://github.com/owncloud/core/issues/22836#issuecomment-193336245
2016-03-07 19:33:50 +01:00
C. Montero Luque
9232a124e2 Merge pull request #22913 from owncloud/fix-failing-migration-stable9
Fix failing migration stable9
2016-03-07 11:33:14 -05:00
Thomas Müller
b5a06ecd5c Calendar and addressbook migration commands are always available 2016-03-07 15:24:23 +01:00
Thomas Müller
79811b5806 Handle addressbook migration issue by writing the faulty event to the log and continue 2016-03-07 15:24:13 +01:00
Thomas Müller
6413fffdcb Handle calendar migration issue by writing the faulty event to the log and continue 2016-03-07 15:24:03 +01:00
Thomas Müller
b3b57621b7 Merge pull request #22897 from owncloud/backport-22896
[9.0] Correctly default to null and add type hint
2016-03-07 14:59:49 +01:00
Thomas Müller
6bfeb4595d Merge pull request #22906 from owncloud/stable9-quota-allowuploadwhenfreespaceisunlimited
[stable9] Fix uploading to fed shares where free space is unlimited
2016-03-07 14:58:31 +01:00
Joas Schilling
5af8ebe3bd Allow to change properties of readonly calendars 2016-03-07 13:58:44 +01:00
Joas Schilling
27f3dcc682 Allow to hide a shared calendar 2016-03-07 13:58:32 +01:00
Thomas Müller
b1a1a46193 For 9.0 we don't have the possibility to store calendar and addressbook properties on a per-user basis and therefore we simple don't allow this for now 2016-03-07 13:58:24 +01:00
Joas Schilling
71b3033b35 Make sure that the return value is an array 2016-03-07 13:55:33 +01:00
Vincent Petry
c1876ea51c Fix uploading when free space is unlimited
A federated share can report unlimited quota as -3, so the
ajax/upload.php code needs to be adjusted to block uploads when the free
space is unlimited.
2016-03-07 12:41:36 +01:00
Joas Schilling
9ec89b99b1 Correctly default to null and add type hint 2016-03-07 10:55:01 +01:00
C Montero-Luque
0945cb7a0e 9.0.0 RC3 2016-03-06 17:51:05 -05:00
Thomas Müller
6f4712a314 Merge pull request #22884 from owncloud/backport-cache-results
[stable9] Cache results of testRemoteUrl
2016-03-06 19:57:53 +01:00
Thomas Müller
d043b6ba91 Merge pull request #22889 from owncloud/stable9-use-custom-header
[stable9] Use custom header
2016-03-06 19:53:19 +01:00
Lukas Reschke
ef66729980 Use custom header
PHP in CGI mode eats the Authorization header => 💣
2016-03-05 23:07:11 +01:00
Lukas Reschke
17f5f19187 Show version to update to properly
Properly shows the version that will be updated to.
2016-03-05 22:02:55 +01:00
Lukas Reschke
71e3f7f866 Cache results of testRemoteUrl
Otherwise setting up the storage will result in a HTTP request and thus slowing down ownCloud.

Replaces https://github.com/owncloud/core/pull/22855
2016-03-05 21:09:58 +01:00
C Montero-Luque
0a5f34ab80 9.0.0 RC2 2016-03-04 18:08:02 -05:00
C. Montero Luque
5488bb74fe Merge pull request #22879 from owncloud/stable9-backport-use-clob-for-timezone
[stable9] Use CLOB for timezone
2016-03-04 18:02:45 -05:00
C. Montero Luque
4b85660984 Merge pull request #22871 from owncloud/enable-federation-app-stable9
[stable9] Automatically enabled federation app
2016-03-04 18:02:32 -05:00
C. Montero Luque
5080c34d78 Merge pull request #22867 from owncloud/stable9-backport-22865
[stable9] Run cleanup of expired DB file locks to background job
2016-03-04 17:45:07 -05:00
C. Montero Luque
5d402fc817 Merge pull request #22848 from owncloud/stable9-fileactions-downloadspinnerfix
[stable9] Fix download spinner to work with CSS styles
2016-03-04 16:41:26 -05:00
Lukas Reschke
fb62043cc1 [stable9] Use CLOB for timezone
TEXT defaults to a length of 255 which is going to fail in some cases as the timezone can be rather long.

This changes it back to a CLOB as it has been before as well: owncloudarchive/calendar@8d8bb68. I'm not super convinced that CLOB is the best choice here but at least it seems to work.

Fixes #22876

Backport of https://github.com/owncloud/core/pull/22878 to stable9
2016-03-04 22:12:54 +01:00
C. Montero Luque
b3c9ed8d5c Merge pull request #22782 from owncloud/backport-22776-doc-fix
Add Versions app header to config.sample.php
2016-03-04 16:10:35 -05:00
Morris Jobke
9737290e39 Run cleanup of expired DB file locks to background job
* fixes #22819

The old way fired a DELETE statement on each destruction of the
DBLockingProvider. Which could cause a lot of queries. It's enough
to run this every 5 minutes in a background job, which in the end
could result in file locks that exists 5 minutes longer - in the
worst case and for not properly released locks.

This makes the DB based locking a lot more performant and could
result in a similar performance to the Redis based locking provider.
2016-03-04 20:13:05 +01:00
C. Montero Luque
121ff350d4 Merge branch 'stable9' into enable-federation-app-stable9 2016-03-04 13:38:02 -05:00
C. Montero Luque
bb0c304482 Merge pull request #22861 from owncloud/stable9-trashbin-checkpath
[stable9] Properly check path validity before deleting to trash
2016-03-04 13:33:23 -05:00
Lukas Reschke
c9c85b8d4a Adjust OCS test 2016-03-04 17:59:57 +01:00
Lukas Reschke
eb59aa8be4 Automatically enabled federation app 2016-03-04 17:40:45 +01:00
Vincent Petry
96d45e90dc Properly check path validity before deleting to trash
This prevents deleting the whole "files" folder of the user whenever
$ownerPath is empty. This can happen in concurrency situations.
2016-03-04 15:33:02 +01:00
Thomas Müller
0655f25406 Merge pull request #22858 from owncloud/stable9-release-channel
[stable9] Add release channel selection back
2016-03-04 15:29:37 +01:00
Thomas Müller
434747f450 Merge pull request #22832 from owncloud/external-unavailable-recheck9
[9.0] allow availability recheck for external storages
2016-03-04 15:29:27 +01:00
Lukas Reschke
7ff2b9232b Add release channel selection back
Allows to select the release channels again and also shows the last check date
2016-03-04 14:39:14 +01:00
Thomas Müller
3d28f364c5 Merge pull request #22852 from owncloud/backport-22851-php54-for-comments
[9.0] ucwords does not support delimiter on 5.4
2016-03-04 14:05:45 +01:00
Joas Schilling
62399f7852 ucwords does not support delimiter on 5.4 2016-03-04 12:20:50 +01:00
Thomas Müller
4fc6deaaf0 Merge pull request #22822 from owncloud/stable9-exclude-assets
[stable9] Exclude the assets folder from integrity check
2016-03-04 11:50:24 +01:00
Vincent Petry
e6c6ee8d2a Fix download spinner to work with CSS styles
A recent change replaced img elements with CSS icons for file actions.
This fix adjusts the logic to work properly with CSS icons instead of
images.
2016-03-04 10:50:41 +01:00
Roeland Jago Douma
3673cfae3c Rename and move permissions are set when a file is updatable
* Fix unit tests
2016-03-04 09:37:52 +01:00
Thomas Müller
4da858b3b7 Merge pull request #22829 from owncloud/stable9-revert-22264-read-version-from-info.xml-only
[stable9] Revert "No longer evaluate appinfo/version"
2016-03-04 08:55:52 +01:00
Vincent Petry
8e8f5cdddf Properly set exception in FailedStorage 2016-03-03 20:07:22 +01:00
Robin Appelman
f603c57751 allow availability recheck for external storages 2016-03-03 20:07:18 +01:00
Vincent Petry
e155f28f5e Revert "No longer evaluate appinfo/version" 2016-03-03 18:42:23 +01:00
Arthur Schiwon
dd556d77da untangle different user manager instances, fixes #22770 2016-03-03 17:26:52 +01:00
Lukas Reschke
750fc9ae26 Merge pull request #22818 from owncloud/backport-fix-encryption-on-version-restore
[stable9] Keep "encryptedVersion" when calling `\OC\Files\View::copy`
2016-03-03 16:18:51 +01:00
Lukas Reschke
4186bcbdf2 Exclude the assets folder from integrity check
We should not scan the assets folder as this can contain user specific content. Partially addresses https://github.com/owncloud/core/issues/22803
2016-03-03 16:00:34 +01:00
Lukas Reschke
98f79173ed Keep "encryptedVersion" when calling \OC\Files\View::copy
When calling `\OC\Files\View::copy` we should also keep the version to ensure that the file will always have the correct version attached and can be successfully decrypted.

To test this the following steps are necessary (from https://github.com/owncloud/core/issues/22781#issuecomment-191328982):

1. setup a new ownCloud 9.0 beta2
2. enable encryption
2. upload a docx (5.7MB large)
3. upload the same file again and overwrite the existing file
4. I can download the original file and the first version
5. I restore the first version
6. restored version can no longer be downloaded with the error described above

The manual cache operation in `\OCA\Files_Versions\Storage` is unfortunately necessary since `\OCA\Files_Versions\Storage::copyFileContents` is not using `\OCP\Files\Storage::moveFromStorage` in the case when an object storage is used. Due to the workaround added in 54cea05271 the stream is directly copied and thus bypassing the FS.
2016-03-03 14:41:53 +01:00
RealRancor
8d07cb4d85 Add Versions app header to config.sample.php 2016-03-02 15:33:09 +01:00
C Montero-Luque
445957a0e2 9.0.0 RC1 2016-03-01 16:59:42 -05:00
997 changed files with 8810 additions and 2181 deletions

View File

@@ -37,6 +37,17 @@
SetEnv htaccessWorking true
</IfModule>
</IfModule>
<IfModule mod_php7.c>
php_value upload_max_filesize 513M
php_value post_max_size 513M
php_value memory_limit 512M
php_value mbstring.func_overload 0
php_value default_charset 'UTF-8'
php_value output_buffering 0
<IfModule mod_env.c>
SetEnv htaccessWorking true
</IfModule>
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
@@ -51,9 +62,9 @@
# 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)$
RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$
RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
RewriteCond %{REQUEST_FILENAME} !/remote.php
RewriteCond %{REQUEST_FILENAME} !/public.php
@@ -65,7 +76,6 @@
RewriteCond %{REQUEST_FILENAME} !/updater/
RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
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

View File

@@ -13,7 +13,7 @@ env:
branches:
only:
- master
# - /^stable\d+(\.\d+)?$/
- /^stable\d+(\.\d+)?$/
addons:
apt:
@@ -29,6 +29,7 @@ install:
script:
- sh -c "if [ '$TC' = 'syntax' ]; then composer install && vendor/bin/parallel-lint --exclude vendor/jakub-onderka/ --exclude 3rdparty/symfony/polyfill-php70/Resources/stubs/ --exclude 3rdparty/patchwork/utf8/src/Patchwork/Utf8/Bootup/ --exclude 3rdparty/paragonie/random_compat/lib/ .; fi"
- sh -c "if [ '$TEST_DAV' != '1' ]; then echo \"Not testing DAV\"; fi"
- sh -c "if [ '$TEST_DAV' = '1' ]; then echo \"Testing DAV\"; fi"
@@ -42,5 +43,13 @@ matrix:
env: DB=sqlite;TC=carddav
- php: 5.4
env: DB=sqlite;TC=caldav
- php: 5.4
env: DB=sqlite;TC=syntax;TEST_DAV=0
- php: 5.5
env: DB=sqlite;TC=syntax;TEST_DAV=0
- php: 5.6
env: DB=sqlite;TC=syntax;TEST_DAV=0
- php: 7.0
env: DB=sqlite;TC=syntax;TEST_DAV=0
fast_finish: true

View File

@@ -105,7 +105,7 @@ class Extension implements IExtension {
public function getTypeIcon($type) {
switch ($type) {
case self::APP_NAME:
return false;
return 'icon-comment';
}
return false;
@@ -150,6 +150,9 @@ class Extension implements IExtension {
switch ($text) {
case self::ADD_COMMENT_SUBJECT:
if ($this->authorIsCurrentUser($params[0])) {
return (string) $l->t('You commented');
}
return (string) $l->t('%1$s commented', $params);
case self::ADD_COMMENT_MESSAGE:
return $this->convertParameterToComment($params[0], 120);
@@ -168,6 +171,9 @@ class Extension implements IExtension {
switch ($text) {
case self::ADD_COMMENT_SUBJECT:
if ($this->authorIsCurrentUser($params[0])) {
return (string) $l->t('You commented on %2$s', $params);
}
return (string) $l->t('%1$s commented on %2$s', $params);
case self::ADD_COMMENT_MESSAGE:
return $this->convertParameterToComment($params[0]);
@@ -176,6 +182,21 @@ class Extension implements IExtension {
return false;
}
/**
* Check if the author is the current user
*
* @param string $user Parameter e.g. `<user display-name="admin">admin</user>`
* @return bool
*/
protected function authorIsCurrentUser($user) {
try {
return strip_tags($user) === $this->activityManager->getCurrentUserId();
} catch (\UnexpectedValueException $e) {
// FIXME this is awkward, but we have no access to the current user in emails
return false;
}
}
/**
* The extension can define the type of parameters for translation
*

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Uložit",
"Allowed characters {count} of {max}" : "Povolených znaků {count} z {max}",
"{count} unread comments" : "{count} nepřečtených komentářů",
"Comment" : "Komentář"
"Comment" : "Komentář",
"<strong>Comments</strong> for files" : "<strong>Komentáře</strong> souborů"
},
"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;");

View File

@@ -14,6 +14,7 @@
"Save" : "Uložit",
"Allowed characters {count} of {max}" : "Povolených znaků {count} z {max}",
"{count} unread comments" : "{count} nepřečtených komentářů",
"Comment" : "Komentář"
"Comment" : "Komentář",
"<strong>Comments</strong> for files" : "<strong>Komentáře</strong> souborů"
},"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Speichern",
"Allowed characters {count} of {max}" : "Erlaubte Zeichen {count} von {max}",
"{count} unread comments" : "{count} ungelesene Kommentare",
"Comment" : "Kommentar"
"Comment" : "Kommentar",
"<strong>Comments</strong> for files" : "<strong>Kommentare</strong> für Dateien"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Speichern",
"Allowed characters {count} of {max}" : "Erlaubte Zeichen {count} von {max}",
"{count} unread comments" : "{count} ungelesene Kommentare",
"Comment" : "Kommentar"
"Comment" : "Kommentar",
"<strong>Comments</strong> for files" : "<strong>Kommentare</strong> für Dateien"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Speichern",
"Allowed characters {count} of {max}" : "{count} von {max} Zeichen benutzt",
"{count} unread comments" : "[count] ungelesene Kommentare",
"Comment" : "Kommentar"
"Comment" : "Kommentar",
"<strong>Comments</strong> for files" : "<strong>Kommentare</strong> für Dateien"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Speichern",
"Allowed characters {count} of {max}" : "{count} von {max} Zeichen benutzt",
"{count} unread comments" : "[count] ungelesene Kommentare",
"Comment" : "Kommentar"
"Comment" : "Kommentar",
"<strong>Comments</strong> for files" : "<strong>Kommentare</strong> für Dateien"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Save",
"Allowed characters {count} of {max}" : "Allowed characters {count} of {max}",
"{count} unread comments" : "{count} unread comments",
"Comment" : "Comment"
"Comment" : "Comment",
"<strong>Comments</strong> for files" : "<strong>Comments</strong> for files"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Save",
"Allowed characters {count} of {max}" : "Allowed characters {count} of {max}",
"{count} unread comments" : "{count} unread comments",
"Comment" : "Comment"
"Comment" : "Comment",
"<strong>Comments</strong> for files" : "<strong>Comments</strong> for files"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Konservi",
"Allowed characters {count} of {max}" : "Permesataj karakteroj: {count} el {max}",
"{count} unread comments" : "{count} nelegitaj komentoj",
"Comment" : "Komento"
"Comment" : "Komento",
"<strong>Comments</strong> for files" : "<strong>Komentoj</strong> por dosieroj"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Konservi",
"Allowed characters {count} of {max}" : "Permesataj karakteroj: {count} el {max}",
"{count} unread comments" : "{count} nelegitaj komentoj",
"Comment" : "Komento"
"Comment" : "Komento",
"<strong>Comments</strong> for files" : "<strong>Komentoj</strong> por dosieroj"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Guardar",
"Allowed characters {count} of {max}" : "Caracteres permitidos {count} de {max}",
"{count} unread comments" : "{count} comentarios no leídos",
"Comment" : "Comentario"
"Comment" : "Comentario",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> en archivos"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Guardar",
"Allowed characters {count} of {max}" : "Caracteres permitidos {count} de {max}",
"{count} unread comments" : "{count} comentarios no leídos",
"Comment" : "Comentario"
"Comment" : "Comentario",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> en archivos"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Tallenna",
"Allowed characters {count} of {max}" : "Sallittujen merkkien määrä {count}/{max}",
"{count} unread comments" : "{count} lukematonta kommenttia",
"Comment" : "Kommentti"
"Comment" : "Kommentti",
"<strong>Comments</strong> for files" : "<strong>Kommentit</strong> tiedostoille"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Tallenna",
"Allowed characters {count} of {max}" : "Sallittujen merkkien määrä {count}/{max}",
"{count} unread comments" : "{count} lukematonta kommenttia",
"Comment" : "Kommentti"
"Comment" : "Kommentti",
"<strong>Comments</strong> for files" : "<strong>Kommentit</strong> tiedostoille"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Enregistrer",
"Allowed characters {count} of {max}" : "{count} sur {max} caractères autorisés",
"{count} unread comments" : "{count} commentaires non lus",
"Comment" : "Commenter"
"Comment" : "Commenter",
"<strong>Comments</strong> for files" : "<strong>Commentaires</strong> pour les fichiers"
},
"nplurals=2; plural=(n > 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Enregistrer",
"Allowed characters {count} of {max}" : "{count} sur {max} caractères autorisés",
"{count} unread comments" : "{count} commentaires non lus",
"Comment" : "Commenter"
"Comment" : "Commenter",
"<strong>Comments</strong> for files" : "<strong>Commentaires</strong> pour les fichiers"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "שמירה",
"Allowed characters {count} of {max}" : "תווים מותרים {count} מתוך {max}",
"{count} unread comments" : "{count} תגובות שלא נקראו",
"Comment" : "תגובה"
"Comment" : "תגובה",
"<strong>Comments</strong> for files" : "<strong>תגובות</strong> לקבצים"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "שמירה",
"Allowed characters {count} of {max}" : "תווים מותרים {count} מתוך {max}",
"{count} unread comments" : "{count} תגובות שלא נקראו",
"Comment" : "תגובה"
"Comment" : "תגובה",
"<strong>Comments</strong> for files" : "<strong>תגובות</strong> לקבצים"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -3,6 +3,11 @@ OC.L10N.register(
{
"Cancel" : "Mégsem",
"Save" : "Mentés",
"Comment" : "Komment"
"Comment" : "Komment",
"<strong>Comments</strong> for files" : "<strong>Hozzászólások</strong> a fájlokhoz",
"Delete comment" : "Hozzászólás törlése",
"Edit comment" : "Hozzászólás szerkesztése",
"No other comments available" : "Nincs több hozzászólás.",
"Post" : "Küldés"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -1,6 +1,11 @@
{ "translations": {
"Cancel" : "Mégsem",
"Save" : "Mentés",
"Comment" : "Komment"
"Comment" : "Komment",
"<strong>Comments</strong> for files" : "<strong>Hozzászólások</strong> a fájlokhoz",
"Delete comment" : "Hozzászólás törlése",
"Edit comment" : "Hozzászólás szerkesztése",
"No other comments available" : "Nincs több hozzászólás.",
"Post" : "Küldés"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Simpan",
"Allowed characters {count} of {max}" : "Karakter yang diizinkan {count} dari {max}",
"{count} unread comments" : "{count} komentar belum dibaca",
"Comment" : "Komentar"
"Comment" : "Komentar",
"<strong>Comments</strong> for files" : "<strong>Komentar</strong> untuk berkas"
},
"nplurals=1; plural=0;");

View File

@@ -14,6 +14,7 @@
"Save" : "Simpan",
"Allowed characters {count} of {max}" : "Karakter yang diizinkan {count} dari {max}",
"{count} unread comments" : "{count} komentar belum dibaca",
"Comment" : "Komentar"
"Comment" : "Komentar",
"<strong>Comments</strong> for files" : "<strong>Komentar</strong> untuk berkas"
},"pluralForm" :"nplurals=1; plural=0;"
}

View File

@@ -3,6 +3,11 @@ OC.L10N.register(
{
"Cancel" : "Hætta við",
"Save" : "Vista",
"Comment" : "Athugasemd"
"Comment" : "Athugasemd",
"<strong>Comments</strong> for files" : "<strong>Athugasemdir</strong> við skrár",
"Delete comment" : "Eyða athugasemd",
"Edit comment" : "Breyta athugasemd",
"No other comments available" : "Engar aðrar athugasemdir eru tiltækar",
"Post" : "Senda"
},
"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);");

View File

@@ -1,6 +1,11 @@
{ "translations": {
"Cancel" : "Hætta við",
"Save" : "Vista",
"Comment" : "Athugasemd"
"Comment" : "Athugasemd",
"<strong>Comments</strong> for files" : "<strong>Athugasemdir</strong> við skrár",
"Delete comment" : "Eyða athugasemd",
"Edit comment" : "Breyta athugasemd",
"No other comments available" : "Engar aðrar athugasemdir eru tiltækar",
"Post" : "Senda"
},"pluralForm" :"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Salva",
"Allowed characters {count} of {max}" : "Caratteri consentiti {count} di {max}",
"{count} unread comments" : "{count} commenti non letti",
"Comment" : "Commento"
"Comment" : "Commento",
"<strong>Comments</strong> for files" : "<strong>Commenti</strong> sui file"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Salva",
"Allowed characters {count} of {max}" : "Caratteri consentiti {count} di {max}",
"{count} unread comments" : "{count} commenti non letti",
"Comment" : "Commento"
"Comment" : "Commento",
"<strong>Comments</strong> for files" : "<strong>Commenti</strong> sui file"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "保存",
"Allowed characters {count} of {max}" : "入力文字数 {count} / {max}",
"{count} unread comments" : "未読コメント数 {count}",
"Comment" : "コメント"
"Comment" : "コメント",
"<strong>Comments</strong> for files" : "ファイルについての<strong>コメント</strong>"
},
"nplurals=1; plural=0;");

View File

@@ -14,6 +14,7 @@
"Save" : "保存",
"Allowed characters {count} of {max}" : "入力文字数 {count} / {max}",
"{count} unread comments" : "未読コメント数 {count}",
"Comment" : "コメント"
"Comment" : "コメント",
"<strong>Comments</strong> for files" : "ファイルについての<strong>コメント</strong>"
},"pluralForm" :"nplurals=1; plural=0;"
}

View File

@@ -3,6 +3,11 @@ OC.L10N.register(
{
"Cancel" : "취소",
"Save" : "저장",
"Comment" : "설명"
"Comment" : "설명",
"<strong>Comments</strong> for files" : "파일에 <strong>댓글</strong> 남기기",
"Delete comment" : "댓글 삭제",
"Edit comment" : "댓글 편집",
"No other comments available" : "더 이상 댓글 없음",
"Post" : "게시"
},
"nplurals=1; plural=0;");

View File

@@ -1,6 +1,11 @@
{ "translations": {
"Cancel" : "취소",
"Save" : "저장",
"Comment" : "설명"
"Comment" : "설명",
"<strong>Comments</strong> for files" : "파일에 <strong>댓글</strong> 남기기",
"Delete comment" : "댓글 삭제",
"Edit comment" : "댓글 편집",
"No other comments available" : "더 이상 댓글 없음",
"Post" : "게시"
},"pluralForm" :"nplurals=1; plural=0;"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Lagre",
"Allowed characters {count} of {max}" : "Antall tegn tillatt {count} av {max}",
"{count} unread comments" : "{count} uleste kommentarer",
"Comment" : "Kommentar"
"Comment" : "Kommentar",
"<strong>Comments</strong> for files" : "<strong>Kommentarer</strong> for filer"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Lagre",
"Allowed characters {count} of {max}" : "Antall tegn tillatt {count} av {max}",
"{count} unread comments" : "{count} uleste kommentarer",
"Comment" : "Kommentar"
"Comment" : "Kommentar",
"<strong>Comments</strong> for files" : "<strong>Kommentarer</strong> for filer"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Bewaren",
"Allowed characters {count} of {max}" : "{count} van de {max} toegestane tekens",
"{count} unread comments" : "{count} ongelezen reacties",
"Comment" : "Reactie"
"Comment" : "Reactie",
"<strong>Comments</strong> for files" : "<strong>Reacties</strong> voor bestanden"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Bewaren",
"Allowed characters {count} of {max}" : "{count} van de {max} toegestane tekens",
"{count} unread comments" : "{count} ongelezen reacties",
"Comment" : "Reactie"
"Comment" : "Reactie",
"<strong>Comments</strong> for files" : "<strong>Reacties</strong> voor bestanden"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -3,6 +3,11 @@ OC.L10N.register(
{
"Cancel" : "Anuluj",
"Save" : "Zapisz",
"Comment" : "Komentarz"
"Comment" : "Komentarz",
"<strong>Comments</strong> for files" : "<strong>Komentarze</strong> dla plików",
"Delete comment" : "Skasuj komentarz",
"Edit comment" : "Edytuj komentarz",
"No other comments available" : "Nie ma więcej komentarzy",
"Post" : "Zapisz"
},
"nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");

View File

@@ -1,6 +1,11 @@
{ "translations": {
"Cancel" : "Anuluj",
"Save" : "Zapisz",
"Comment" : "Komentarz"
"Comment" : "Komentarz",
"<strong>Comments</strong> for files" : "<strong>Komentarze</strong> dla plików",
"Delete comment" : "Skasuj komentarz",
"Edit comment" : "Edytuj komentarz",
"No other comments available" : "Nie ma więcej komentarzy",
"Post" : "Zapisz"
},"pluralForm" :"nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Salvar",
"Allowed characters {count} of {max}" : "Caracteres permitidos {count} de {max}",
"{count} unread comments" : "{count} comentários não lidos",
"Comment" : "Comentário"
"Comment" : "Comentário",
"<strong>Comments</strong> for files" : "<strong>Comentários</strong> por arquivos"
},
"nplurals=2; plural=(n > 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Salvar",
"Allowed characters {count} of {max}" : "Caracteres permitidos {count} de {max}",
"{count} unread comments" : "{count} comentários não lidos",
"Comment" : "Comentário"
"Comment" : "Comentário",
"<strong>Comments</strong> for files" : "<strong>Comentários</strong> por arquivos"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Guardar",
"Allowed characters {count} of {max}" : "{count} de {max} caracteres restantes",
"{count} unread comments" : "{count} comentários não lidos",
"Comment" : "Comentário"
"Comment" : "Comentário",
"<strong>Comments</strong> for files" : "<strong>Comentários</strong> para ficheiros"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Guardar",
"Allowed characters {count} of {max}" : "{count} de {max} caracteres restantes",
"{count} unread comments" : "{count} comentários não lidos",
"Comment" : "Comentário"
"Comment" : "Comentário",
"<strong>Comments</strong> for files" : "<strong>Comentários</strong> para ficheiros"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Сохранить",
"Allowed characters {count} of {max}" : "Допустимых символов {count} из {max}",
"{count} unread comments" : "{count} непрочитанных комментариев",
"Comment" : "Коментарий"
"Comment" : "Коментарий",
"<strong>Comments</strong> for files" : "<strong>Комментарии</strong> к файлам"
},
"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);");

View File

@@ -14,6 +14,7 @@
"Save" : "Сохранить",
"Allowed characters {count} of {max}" : "Допустимых символов {count} из {max}",
"{count} unread comments" : "{count} непрочитанных комментариев",
"Comment" : "Коментарий"
"Comment" : "Коментарий",
"<strong>Comments</strong> for files" : "<strong>Комментарии</strong> к файлам"
},"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);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Shrani",
"Allowed characters {count} of {max}" : "Dovoljeni znaki: {count} od {max}",
"{count} unread comments" : "{count} neprebranih opomb",
"Comment" : "Opomba"
"Comment" : "Opomba",
"<strong>Comments</strong> for files" : "<strong>Opombe</strong> datotek"
},
"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);");

View File

@@ -14,6 +14,7 @@
"Save" : "Shrani",
"Allowed characters {count} of {max}" : "Dovoljeni znaki: {count} od {max}",
"{count} unread comments" : "{count} neprebranih opomb",
"Comment" : "Opomba"
"Comment" : "Opomba",
"<strong>Comments</strong> for files" : "<strong>Opombe</strong> datotek"
},"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Ruaje",
"Allowed characters {count} of {max}" : "Shenja të lejuara {count} nga {max}",
"{count} unread comments" : "{count} komente të palexuar",
"Comment" : "Koment"
"Comment" : "Koment",
"<strong>Comments</strong> for files" : "<strong>Komente</strong> për kartela"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Ruaje",
"Allowed characters {count} of {max}" : "Shenja të lejuara {count} nga {max}",
"{count} unread comments" : "{count} komente të palexuar",
"Comment" : "Koment"
"Comment" : "Koment",
"<strong>Comments</strong> for files" : "<strong>Komente</strong> për kartela"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -3,6 +3,11 @@ OC.L10N.register(
{
"Cancel" : "Одустани",
"Save" : "Сачувај",
"Comment" : "Коментар"
"Comment" : "Коментар",
"<strong>Comments</strong> for files" : "<strong>Коментари</strong> фајлова",
"Delete comment" : "Обриши коментар",
"Edit comment" : "Уреди коментар",
"No other comments available" : "Нема других коментара",
"Post" : "Објави"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");

View File

@@ -1,6 +1,11 @@
{ "translations": {
"Cancel" : "Одустани",
"Save" : "Сачувај",
"Comment" : "Коментар"
"Comment" : "Коментар",
"<strong>Comments</strong> for files" : "<strong>Коментари</strong> фајлова",
"Delete comment" : "Обриши коментар",
"Edit comment" : "Уреди коментар",
"No other comments available" : "Нема других коментара",
"Post" : "Објави"
},"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);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Spara",
"Allowed characters {count} of {max}" : "Tillåtet antal tecken {count} av {max}",
"{count} unread comments" : "{count} olästa kommentarer",
"Comment" : "Kommentar"
"Comment" : "Kommentar",
"<strong>Comments</strong> for files" : "<strong>Kommentarer</strong> till filer"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Spara",
"Allowed characters {count} of {max}" : "Tillåtet antal tecken {count} av {max}",
"{count} unread comments" : "{count} olästa kommentarer",
"Comment" : "Kommentar"
"Comment" : "Kommentar",
"<strong>Comments</strong> for files" : "<strong>Kommentarer</strong> till filer"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -12,6 +12,7 @@ OC.L10N.register(
"Edit comment" : "แก้ไขความคิดเห็น",
"[Deleted user]" : "[ผู้ใช้ถูกลบไปแล้ว]",
"Save" : "บันทึก",
"Comment" : "แสดงความคิดเห็น"
"Comment" : "แสดงความคิดเห็น",
"<strong>Comments</strong> for files" : "<strong>แสดงความคิดเห็น</strong> สำหรับไฟล์"
},
"nplurals=1; plural=0;");

View File

@@ -10,6 +10,7 @@
"Edit comment" : "แก้ไขความคิดเห็น",
"[Deleted user]" : "[ผู้ใช้ถูกลบไปแล้ว]",
"Save" : "บันทึก",
"Comment" : "แสดงความคิดเห็น"
"Comment" : "แสดงความคิดเห็น",
"<strong>Comments</strong> for files" : "<strong>แสดงความคิดเห็น</strong> สำหรับไฟล์"
},"pluralForm" :"nplurals=1; plural=0;"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Kaydet",
"Allowed characters {count} of {max}" : "İzin verilen karakterler {count} {max}",
"{count} unread comments" : "{count} okunmamış yorumlar",
"Comment" : "Yorum"
"Comment" : "Yorum",
"<strong>Comments</strong> for files" : "Dosyalar için <strong>Yorumlar</strong>"
},
"nplurals=2; plural=(n > 1);");

View File

@@ -14,6 +14,7 @@
"Save" : "Kaydet",
"Allowed characters {count} of {max}" : "İzin verilen karakterler {count} {max}",
"{count} unread comments" : "{count} okunmamış yorumlar",
"Comment" : "Yorum"
"Comment" : "Yorum",
"<strong>Comments</strong> for files" : "Dosyalar için <strong>Yorumlar</strong>"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "Зберегти",
"Allowed characters {count} of {max}" : "Доступно символів {count} з {max}",
"{count} unread comments" : "{count} непрочитаних коментарів",
"Comment" : "Коментар"
"Comment" : "Коментар",
"<strong>Comments</strong> for files" : "<strong>Коментарі</strong> до файлів"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");

View File

@@ -14,6 +14,7 @@
"Save" : "Зберегти",
"Allowed characters {count} of {max}" : "Доступно символів {count} з {max}",
"{count} unread comments" : "{count} непрочитаних коментарів",
"Comment" : "Коментар"
"Comment" : "Коментар",
"<strong>Comments</strong> for files" : "<strong>Коментарі</strong> до файлів"
},"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);"
}

View File

@@ -16,6 +16,7 @@ OC.L10N.register(
"Save" : "保存",
"Allowed characters {count} of {max}" : "当前字数: {count},最大允许:{max}",
"{count} unread comments" : "{count} 条未读评论",
"Comment" : "评论"
"Comment" : "评论",
"<strong>Comments</strong> for files" : "<strong>评论文件</strong>"
},
"nplurals=1; plural=0;");

View File

@@ -14,6 +14,7 @@
"Save" : "保存",
"Allowed characters {count} of {max}" : "当前字数: {count},最大允许:{max}",
"{count} unread comments" : "{count} 条未读评论",
"Comment" : "评论"
"Comment" : "评论",
"<strong>Comments</strong> for files" : "<strong>评论文件</strong>"
},"pluralForm" :"nplurals=1; plural=0;"
}

View File

@@ -99,18 +99,24 @@ class Application extends App {
$container->registerService('MigrateAddressbooks', function($c) {
/** @var IAppContainer $c */
$db = $c->getServer()->getDatabaseConnection();
$logger = $c->getServer()->getLogger();
return new MigrateAddressbooks(
new AddressBookAdapter($db),
$c->query('CardDavBackend')
$c->query('CardDavBackend'),
$logger,
null
);
});
$container->registerService('MigrateCalendars', function($c) {
/** @var IAppContainer $c */
$db = $c->getServer()->getDatabaseConnection();
$logger = $c->getServer()->getLogger();
return new MigrateCalendars(
new CalendarAdapter($db),
$c->query('CalDavBackend')
$c->query('CalDavBackend'),
$logger,
null
);
});
@@ -204,4 +210,19 @@ class Application extends App {
$this->getContainer()->getServer()->getLogger()->logException($ex);
}
}
public function generateBirthdays() {
try {
/** @var BirthdayService $migration */
$migration = $this->getContainer()->query('BirthdayService');
$userManager = $this->getContainer()->getServer()->getUserManager();
$userManager->callForAllUsers(function($user) use($migration) {
/** @var IUser $user */
$migration->syncUser($user->getUID());
});
} catch (\Exception $ex) {
$this->getContainer()->getServer()->getLogger()->logException($ex);
}
}
}

View File

@@ -283,7 +283,7 @@ CREATE TABLE calendarobjects (
description TEXT,
calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0',
calendarcolor VARBINARY(10),
timezone TEXT,
timezone CLOB,
components VARBINARY(20),
transparent TINYINT(1) NOT NULL DEFAULT '0',
UNIQUE(principaluri, uri)
@@ -337,7 +337,7 @@ CREATE TABLE calendarobjects (
</field>
<field>
<name>timezone</name>
<type>text</type>
<type>clob</type>
</field>
<field>
<name>components</name>

View File

@@ -5,7 +5,7 @@
<description>ownCloud WebDAV endpoint</description>
<licence>AGPL</licence>
<author>owncloud.org</author>
<version>0.1.4</version>
<version>0.1.6</version>
<default_enable/>
<types>
<filesystem/>

View File

@@ -25,3 +25,4 @@ $app = new Application();
$app->setupCron();
$app->migrateAddressbooks();
$app->migrateCalendars();
$app->generateBirthdays();

View File

@@ -29,7 +29,6 @@ use OCA\DAV\Command\SyncSystemAddressBook;
$dbConnection = \OC::$server->getDatabaseConnection();
$userManager = OC::$server->getUserManager();
$groupManager = OC::$server->getGroupManager();
$config = \OC::$server->getConfig();
$app = new Application();
@@ -38,12 +37,5 @@ $application->add(new CreateCalendar($userManager, $groupManager, $dbConnection)
$application->add(new CreateAddressBook($userManager, $app->getContainer()->query('CardDavBackend')));
$application->add(new SyncSystemAddressBook($app->getSyncService()));
$application->add(new SyncBirthdayCalendar($userManager, $app->getContainer()->query('BirthdayService')));
// 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));
$migration = $app->getContainer()->query('MigrateCalendars');
$application->add(new MigrateCalendars($userManager, $migration));
}
$application->add(new MigrateAddressbooks($userManager, $app->getContainer()->query('MigrateAddressbooks')));
$application->add(new MigrateCalendars($userManager, $app->getContainer()->query('MigrateCalendars')));

View File

@@ -23,3 +23,4 @@ use OCA\Dav\AppInfo\Application;
$app = new Application();
$app->setupCron();
$app->generateBirthdays();

View File

@@ -23,11 +23,12 @@
// Backends
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\Connector\LegacyDAVACL;
use OCA\DAV\CalDAV\CalendarRoot;
use OCA\DAV\Connector\Sabre\Auth;
use OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin;
use OCA\DAV\Connector\Sabre\MaintenancePlugin;
use OCA\DAV\Connector\Sabre\Principal;
use Sabre\CalDAV\CalendarRoot;
$authBackend = new Auth(
\OC::$server->getSession(),
@@ -65,7 +66,7 @@ $server->addPlugin(new MaintenancePlugin());
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, 'ownCloud'));
$server->addPlugin(new \Sabre\CalDAV\Plugin());
$acl = new \OCA\DAV\Connector\LegacyDAVACL();
$acl = new LegacyDAVACL();
$server->addPlugin($acl);
$server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());

View File

@@ -61,8 +61,8 @@ class MigrateCalendars extends Command {
protected function execute(InputInterface $input, OutputInterface $output) {
$this->service->setup();
if ($input->hasArgument('user')) {
$user = $input->getArgument('user');
$user = $input->getArgument('user');
if (!is_null($user)) {
if (!$this->userManager->userExists($user)) {
throw new \InvalidArgumentException("User <$user> in unknown.");
}

View File

@@ -61,8 +61,8 @@ class SyncBirthdayCalendar extends Command {
* @param OutputInterface $output
*/
protected function execute(InputInterface $input, OutputInterface $output) {
if ($input->hasArgument('user')) {
$user = $input->getArgument('user');
$user = $input->getArgument('user');
if (!is_null($user)) {
if (!$this->userManager->userExists($user)) {
throw new \InvalidArgumentException("User <$user> in unknown.");
}

View File

@@ -50,8 +50,7 @@ class BirthdayService {
$book = $this->cardDavBackEnd->getAddressBookById($addressBookId);
$principalUri = $book['principaluri'];
$calendarUri = self::BIRTHDAY_CALENDAR_URI;
$calendar = $this->ensureCalendarExists($principalUri, $calendarUri, []);
$calendar = $this->ensureCalendarExists($principalUri);
$objectUri = $book['uri'] . '-' . $cardUri. '.ics';
$calendarData = $this->buildBirthdayFromContact($cardData);
$existing = $this->calDavBackEnd->getCalendarObject($calendar['id'], $objectUri);
@@ -77,27 +76,27 @@ class BirthdayService {
public function onCardDeleted($addressBookId, $cardUri) {
$book = $this->cardDavBackEnd->getAddressBookById($addressBookId);
$principalUri = $book['principaluri'];
$calendarUri = self::BIRTHDAY_CALENDAR_URI;
$calendar = $this->ensureCalendarExists($principalUri, $calendarUri, []);
$calendar = $this->ensureCalendarExists($principalUri);
$objectUri = $book['uri'] . '-' . $cardUri. '.ics';
$this->calDavBackEnd->deleteCalendarObject($calendar['id'], $objectUri);
}
/**
* @param string $principal
* @param string $id
* @param array $properties
* @return array|null
* @throws \Sabre\DAV\Exception\BadRequest
*/
public function ensureCalendarExists($principal, $id, $properties) {
$book = $this->calDavBackEnd->getCalendarByUri($principal, $id);
public function ensureCalendarExists($principal) {
$book = $this->calDavBackEnd->getCalendarByUri($principal, self::BIRTHDAY_CALENDAR_URI);
if (!is_null($book)) {
return $book;
}
$this->calDavBackEnd->createCalendar($principal, $id, $properties);
$this->calDavBackEnd->createCalendar($principal, self::BIRTHDAY_CALENDAR_URI, [
'{DAV:}displayname' => 'Contact birthdays',
'{http://apple.com/ns/ical/}calendar-color' => '#FFFFCA',
]);
return $this->calDavBackEnd->getCalendarByUri($principal, $id);
return $this->calDavBackEnd->getCalendarByUri($principal, self::BIRTHDAY_CALENDAR_URI);
}
/**
@@ -156,7 +155,9 @@ class BirthdayService {
* @param string $user
*/
public function syncUser($user) {
$books = $this->cardDavBackEnd->getAddressBooksForUser('principals/users/'.$user);
$principal = 'principals/users/'.$user;
$this->ensureCalendarExists($principal);
$books = $this->cardDavBackEnd->getAddressBooksForUser($principal);
foreach($books as $book) {
$cards = $this->cardDavBackEnd->getCards($book['id']);
foreach($cards as $card) {

View File

@@ -138,6 +138,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
* @return array
*/
function getCalendarsForUser($principalUri) {
$principalUriOriginal = $principalUri;
$principalUri = $this->convertPrincipal($principalUri, true);
$fields = array_values($this->propertyMap);
$fields[] = 'id';
@@ -184,7 +185,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$stmt->closeCursor();
// query for shared calendars
$principals = $this->principalBackend->getGroupMembership($principalUri);
$principals = $this->principalBackend->getGroupMembership($principalUriOriginal, true);
$principals[]= $principalUri;
$fields = array_values($this->propertyMap);
@@ -194,6 +195,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$fields[] = 'a.components';
$fields[] = 'a.principaluri';
$fields[] = 'a.transparent';
$fields[] = 's.access';
$query = $this->db->getQueryBuilder();
$result = $query->select($fields)
->from('dav_shares', 's')
@@ -221,6 +223,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
'{' . 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'],
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only' => (int)$row['access'] === Backend::ACCESS_READ,
];
foreach($this->propertyMap as $xmlName=>$dbName) {
@@ -815,9 +818,9 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
function getCalendarObjectByUID($principalUri, $uid) {
$query = $this->db->getQueryBuilder();
$query->select([$query->createFunction('c.`uri` AS `calendaruri`'), $query->createFunction('co.`uri` AS `objecturi`')])
$query->selectAlias('c.uri', 'calendaruri')->selectAlias('co.uri', 'objecturi')
->from('calendarobjects', 'co')
->leftJoin('co', 'calendars', 'c', 'co.`calendarid` = c.`id`')
->leftJoin('co', 'calendars', 'c', $query->expr()->eq('co.calendarid', 'c.id'))
->where($query->expr()->eq('c.principaluri', $query->createNamedParameter($principalUri)))
->andWhere($query->expr()->eq('co.uid', $query->createNamedParameter($uid)));
@@ -1294,7 +1297,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
if (!$componentType) {
throw new \Sabre\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
}
if ($componentType === 'VEVENT') {
if ($componentType === 'VEVENT' && $component->DTSTART) {
$firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp();
// Finding the last occurence is a bit harder
if (!isset($component->RRULE)) {
@@ -1333,7 +1336,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
'etag' => md5($calendarData),
'size' => strlen($calendarData),
'componentType' => $componentType,
'firstOccurence' => $firstOccurence,
'firstOccurence' => is_null($firstOccurence) ? null : max(0, $firstOccurence),
'lastOccurence' => $lastOccurence,
'uid' => $uid,
];

View File

@@ -22,10 +22,20 @@
namespace OCA\DAV\CalDAV;
use OCA\DAV\DAV\Sharing\IShareable;
use Sabre\CalDAV\Backend\BackendInterface;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\PropPatch;
class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
public function __construct(BackendInterface $caldavBackend, $calendarInfo) {
parent::__construct($caldavBackend, $calendarInfo);
if ($this->getName() === BirthdayService::BIRTHDAY_CALENDAR_URI) {
$this->calendarInfo['{http://sabredav.org/ns}read-only'] = true;
}
}
/**
* Updates the list of shares.
*
@@ -76,7 +86,31 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
}
function getACL() {
$acl = parent::getACL();
$acl = [
[
'privilege' => '{DAV:}read',
'principal' => $this->getOwner(),
'protected' => true,
]];
$acl[] = [
'privilege' => '{DAV:}write',
'principal' => $this->getOwner(),
'protected' => true,
];
if ($this->getOwner() !== parent::getOwner()) {
$acl[] = [
'privilege' => '{DAV:}read',
'principal' => parent::getOwner(),
'protected' => true,
];
if ($this->canWrite()) {
$acl[] = [
'privilege' => '{DAV:}write',
'principal' => parent::getOwner(),
'protected' => true,
];
}
}
/** @var CalDavBackend $calDavBackend */
$calDavBackend = $this->caldavBackend;
@@ -84,11 +118,7 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
}
function getChildACL() {
$acl = parent::getChildACL();
/** @var CalDavBackend $calDavBackend */
$calDavBackend = $this->caldavBackend;
return $calDavBackend->applyShareAcl($this->getResourceId(), $acl);
return $this->getACL();
}
function getOwner() {
@@ -99,10 +129,6 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
}
function delete() {
if ($this->getName() === BirthdayService::BIRTHDAY_CALENDAR_URI) {
throw new Forbidden();
}
if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) {
$principal = 'principal:' . parent::getOwner();
$shares = $this->getShares();
@@ -122,4 +148,21 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
}
parent::delete();
}
function propPatch(PropPatch $propPatch) {
$mutations = $propPatch->getMutations();
// If this is a shared calendar, the user can only change the enabled property, to hide it.
if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal']) && (sizeof($mutations) !== 1 || !isset($mutations['{http://owncloud.org/ns}calendar-enabled']))) {
throw new Forbidden();
}
parent::propPatch($propPatch);
}
private function canWrite() {
if (isset($this->calendarInfo['{http://owncloud.org/ns}read-only'])) {
return !$this->calendarInfo['{http://owncloud.org/ns}read-only'];
}
return true;
}
}

View File

@@ -21,15 +21,13 @@
namespace OCA\DAV\CardDAV;
use OCA\DAV\DAV\Sharing\IShareable;
use Sabre\CardDAV\Card;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\PropPatch;
class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
public function __construct(CardDavBackend $carddavBackend, array $addressBookInfo) {
parent::__construct($carddavBackend, $addressBookInfo);
}
/**
* Updates the list of shares.
*
@@ -73,7 +71,31 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
}
function getACL() {
$acl = parent::getACL();
$acl = [
[
'privilege' => '{DAV:}read',
'principal' => $this->getOwner(),
'protected' => true,
]];
$acl[] = [
'privilege' => '{DAV:}write',
'principal' => $this->getOwner(),
'protected' => true,
];
if ($this->getOwner() !== parent::getOwner()) {
$acl[] = [
'privilege' => '{DAV:}read',
'principal' => parent::getOwner(),
'protected' => true,
];
if ($this->canWrite()) {
$acl[] = [
'privilege' => '{DAV:}write',
'principal' => parent::getOwner(),
'protected' => true,
];
}
}
if ($this->getOwner() === 'principals/system/system') {
$acl[] = [
'privilege' => '{DAV:}read',
@@ -82,49 +104,24 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
];
}
// 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);
return $this->getACL();
}
function getChild($name) {
$obj = $this->carddavBackend->getCard($this->getResourceId(), $name);
$obj = $this->carddavBackend->getCard($this->addressBookInfo['id'], $name);
if (!$obj) {
throw new NotFound('Card not found');
}
$obj['acl'] = $this->getChildACL();
return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
}
/**
@@ -162,10 +159,24 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
parent::delete();
}
function propPatch(PropPatch $propPatch) {
if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
throw new Forbidden();
}
parent::propPatch($propPatch);
}
public function getContactsGroups() {
/** @var CardDavBackend $cardDavBackend */
$cardDavBackend = $this->carddavBackend;
return $cardDavBackend->collectCardProperties($this->getResourceId(), 'CATEGORIES');
}
private function canWrite() {
if (isset($this->addressBookInfo['{http://owncloud.org/ns}read-only'])) {
return !$this->addressBookInfo['{http://owncloud.org/ns}read-only'];
}
return true;
}
}

View File

@@ -1,45 +0,0 @@
<?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'];
}
}

View File

@@ -62,10 +62,6 @@ class CardDavBackend implements BackendInterface, SyncSupport {
'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;
/** @var EventDispatcherInterface */
private $dispatcher;
@@ -78,7 +74,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
*/
public function __construct(IDBConnection $db,
Principal $principalBackend,
$dispatcher ) {
EventDispatcherInterface $dispatcher = null) {
$this->db = $db;
$this->principalBackend = $principalBackend;
$this->dispatcher = $dispatcher;
@@ -103,6 +99,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @return array
*/
function getAddressBooksForUser($principalUri) {
$principalUriOriginal = $principalUri;
$principalUri = $this->convertPrincipal($principalUri, true);
$query = $this->db->getQueryBuilder();
$query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
@@ -126,7 +123,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
$result->closeCursor();
// query for shared calendars
$principals = $this->principalBackend->getGroupMembership($principalUri);
$principals = $this->principalBackend->getGroupMembership($principalUriOriginal, true);
$principals[]= $principalUri;
$query = $this->db->getQueryBuilder();
@@ -153,7 +150,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
'{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,
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only' => (int)$row['access'] === Backend::ACCESS_READ,
];
}
}

View File

@@ -23,7 +23,10 @@
namespace OCA\DAV\Connector;
use OCA\DAV\Connector\Sabre\DavAclPlugin;
use Sabre\DAV\INode;
use Sabre\DAV\PropFind;
use Sabre\HTTP\URLUtil;
use Sabre\DAVACL\Xml\Property\Principal;
class LegacyDAVACL extends DavAclPlugin {
@@ -67,4 +70,16 @@ class LegacyDAVACL extends DavAclPlugin {
}
return "principals/$name";
}
function propFind(PropFind $propFind, INode $node) {
/* Overload current-user-principal */
$propFind->handle('{DAV:}current-user-principal', function () {
if ($url = parent::getCurrentUserPrincipal()) {
return new Principal(Principal::HREF, $url . '/');
} else {
return new Principal(Principal::UNAUTHENTICATED);
}
});
parent::propFind($propFind, $node);
}
}

View File

@@ -61,6 +61,11 @@ class PublicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
return false;
}
if ((int)$linkItem['share_type'] === \OCP\Share::SHARE_TYPE_LINK &&
$this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') !== 'yes') {
$this->share['permissions'] &= ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
}
// check if the share is password protected
if (isset($linkItem['share_with'])) {
if ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_LINK) {

View File

@@ -30,6 +30,7 @@
namespace OCA\DAV\Connector\Sabre;
use Exception;
use OC\AppFramework\Http\Request;
use OCP\IRequest;
use OCP\ISession;
use OCP\IUserSession;
@@ -48,6 +49,8 @@ class Auth extends AbstractBasic {
private $userSession;
/** @var IRequest */
private $request;
/** @var string */
private $currentUser;
/**
* @param ISession $session
@@ -130,7 +133,46 @@ class Auth extends AbstractBasic {
$msg = $e->getMessage();
throw new ServiceUnavailable("$class: $msg");
}
}
}
/**
* Checks whether a CSRF check is required on the request
*
* @return bool
*/
private function requiresCSRFCheck() {
// GET requires no check at all
if($this->request->getMethod() === 'GET') {
return false;
}
// Official ownCloud clients require no checks
if($this->request->isUserAgent([
Request::USER_AGENT_OWNCLOUD_DESKTOP,
Request::USER_AGENT_OWNCLOUD_ANDROID,
Request::USER_AGENT_OWNCLOUD_IOS,
])) {
return false;
}
// If not logged-in no check is required
if(!$this->userSession->isLoggedIn()) {
return false;
}
// POST always requires a check
if($this->request->getMethod() === 'POST') {
return true;
}
// If logged-in AND DAV authenticated no check is required
if($this->userSession->isLoggedIn() &&
$this->isDavAuthenticated($this->userSession->getUser()->getUID())) {
return false;
}
return true;
}
/**
* @param RequestInterface $request
@@ -139,27 +181,33 @@ class Auth extends AbstractBasic {
* @throws NotAuthenticated
*/
private function auth(RequestInterface $request, ResponseInterface $response) {
// If request is not GET and not authenticated via WebDAV a requesttoken is required
if($this->userSession->isLoggedIn() &&
$this->request->getMethod() !== 'GET' &&
!$this->isDavAuthenticated($this->userSession->getUser()->getUID())) {
if(!$this->request->passesCSRFCheck()) {
$forcedLogout = false;
if(!$this->request->passesCSRFCheck() &&
$this->requiresCSRFCheck()) {
// In case of a fail with POST we need to recheck the credentials
if($this->request->getMethod() === 'POST') {
$forcedLogout = true;
} else {
$response->setStatus(401);
throw new \Sabre\DAV\Exception\NotAuthenticated('CSRF check not passed.');
}
}
if (\OC_User::handleApacheAuth() ||
//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, $this->principalPrefix . $user];
if($forcedLogout) {
$this->userSession->logout();
} else {
if (\OC_User::handleApacheAuth() ||
//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, $this->principalPrefix . $user];
}
}
if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) {
@@ -169,6 +217,12 @@ class Auth extends AbstractBasic {
throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
}
return parent::check($request, $response);
$data = parent::check($request, $response);
if($data[0] === true) {
$startPos = strrpos($data[1], '/') + 1;
$user = $this->userSession->getUser()->getUID();
$data[1] = substr_replace($data[1], $user, $startPos);
}
return $data;
}
}

View File

@@ -235,6 +235,16 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
$propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
return $node->getEtag();
});
$propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) {
$owner = $node->getOwner();
return $owner->getUID();
});
$propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) {
$owner = $node->getOwner();
$displayName = $owner->getDisplayName();
return $displayName;
});
}
if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
@@ -267,16 +277,6 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
return $node->getSize();
});
}
$propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) {
$owner = $node->getOwner();
return $owner->getUID();
});
$propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) {
$owner = $node->getOwner();
$displayName = $owner->getDisplayName();
return $displayName;
});
}
/**

View File

@@ -230,7 +230,7 @@ abstract class Node implements \Sabre\DAV\INode {
if ($this->info->isDeletable()) {
$p .= 'D';
}
if ($this->info->isDeletable()) {
if ($this->info->isUpdateable()) {
$p .= 'NV'; // Renameable, Moveable
}
if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) {

View File

@@ -132,10 +132,11 @@ class Principal implements BackendInterface {
* Returns the list of groups a principal is a member of
*
* @param string $principal
* @param bool $needGroups
* @return array
* @throws Exception
*/
public function getGroupMembership($principal) {
public function getGroupMembership($principal, $needGroups = false) {
list($prefix, $name) = URLUtil::splitPath($principal);
if ($prefix === $this->principalPrefix) {
@@ -144,7 +145,7 @@ class Principal implements BackendInterface {
throw new Exception('Principal not found');
}
if ($this->hasGroups) {
if ($this->hasGroups || $needGroups) {
$groups = $this->groupManager->getUserGroups($user);
$groups = array_map(function($group) {
/** @var IGroup $group */

View File

@@ -110,6 +110,7 @@ class ServerFactory {
if($this->request->isUserAgent([
'/WebDAVFS/',
'/Microsoft Office OneNote 2013/',
'/Microsoft-WebDAV-MiniRedir/',
])) {
$server->addPlugin(new \OCA\DAV\Connector\Sabre\FakeLockerPlugin());
}
@@ -136,6 +137,12 @@ class ServerFactory {
if($this->userSession->isLoggedIn()) {
$server->addPlugin(new \OCA\DAV\Connector\Sabre\TagsPlugin($objectTree, $this->tagManager));
$server->addPlugin(new \OCA\DAV\Connector\Sabre\SharesPlugin(
$objectTree,
$this->userSession,
$userFolder,
\OC::$server->getShareManager()
));
$server->addPlugin(new \OCA\DAV\Connector\Sabre\CommentPropertiesPlugin(\OC::$server->getCommentsManager(), $this->userSession));
$server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesReportPlugin(
$objectTree,

View File

@@ -0,0 +1,177 @@
<?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\Connector\Sabre;
use \Sabre\DAV\PropFind;
use \Sabre\DAV\PropPatch;
use OCP\IUserSession;
use OCP\Share\IShare;
use OCA\DAV\Connector\Sabre\ShareTypeList;
/**
* Sabre Plugin to provide share-related properties
*/
class SharesPlugin extends \Sabre\DAV\ServerPlugin {
const NS_OWNCLOUD = 'http://owncloud.org/ns';
const SHARETYPES_PROPERTYNAME = '{http://owncloud.org/ns}share-types';
/**
* Reference to main server object
*
* @var \Sabre\DAV\Server
*/
private $server;
/**
* @var \OCP\Share\IManager
*/
private $shareManager;
/**
* @var \Sabre\DAV\Tree
*/
private $tree;
/**
* @var string
*/
private $userId;
/**
* @var \OCP\Files\Folder
*/
private $userFolder;
/**
* @var IShare[]
*/
private $cachedShareTypes;
/**
* @param \Sabre\DAV\Tree $tree tree
* @param IUserSession $userSession user session
* @param \OCP\Files\Folder $userFolder user home folder
* @param \OCP\Share\IManager $shareManager share manager
*/
public function __construct(
\Sabre\DAV\Tree $tree,
IUserSession $userSession,
\OCP\Files\Folder $userFolder,
\OCP\Share\IManager $shareManager
) {
$this->tree = $tree;
$this->shareManager = $shareManager;
$this->userFolder = $userFolder;
$this->userId = $userSession->getUser()->getUID();
$this->cachedShareTypes = [];
}
/**
* 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
*/
public function initialize(\Sabre\DAV\Server $server) {
$server->xml->namespacesMap[self::NS_OWNCLOUD] = 'oc';
$server->xml->elementMap[self::SHARETYPES_PROPERTYNAME] = 'OCA\\DAV\\Connector\\Sabre\\ShareTypeList';
$server->protectedProperties[] = self::SHARETYPES_PROPERTYNAME;
$this->server = $server;
$this->server->on('propFind', array($this, 'handleGetProperties'));
}
/**
* Return a list of share types for outgoing shares
*
* @param \OCP\Files\Node $node file node
*
* @return int[] array of share types
*/
private function getShareTypes(\OCP\Files\Node $node) {
$shareTypes = [];
$requestedShareTypes = [
\OCP\Share::SHARE_TYPE_USER,
\OCP\Share::SHARE_TYPE_GROUP,
\OCP\Share::SHARE_TYPE_LINK,
\OCP\Share::SHARE_TYPE_REMOTE
];
foreach ($requestedShareTypes as $requestedShareType) {
// one of each type is enough to find out about the types
$shares = $this->shareManager->getSharesBy(
$this->userId,
$requestedShareType,
$node,
false,
1
);
if (!empty($shares)) {
$shareTypes[] = $requestedShareType;
}
}
return $shareTypes;
}
/**
* Adds shares to propfind response
*
* @param PropFind $propFind propfind object
* @param \Sabre\DAV\INode $sabreNode sabre node
*/
public function handleGetProperties(
PropFind $propFind,
\Sabre\DAV\INode $sabreNode
) {
if (!($sabreNode instanceof \OCA\DAV\Connector\Sabre\Node)) {
return;
}
// need prefetch ?
if ($sabreNode instanceof \OCA\DAV\Connector\Sabre\Directory
&& $propFind->getDepth() !== 0
&& !is_null($propFind->getStatus(self::SHARETYPES_PROPERTYNAME))
) {
$folderNode = $this->userFolder->get($propFind->getPath());
$children = $folderNode->getDirectoryListing();
$this->cachedShareTypes[$folderNode->getId()] = $this->getShareTypes($folderNode);
foreach ($children as $childNode) {
$this->cachedShareTypes[$childNode->getId()] = $this->getShareTypes($childNode);
}
}
$propFind->handle(self::SHARETYPES_PROPERTYNAME, function() use ($sabreNode) {
if (isset($this->cachedShareTypes[$sabreNode->getId()])) {
$shareTypes = $this->cachedShareTypes[$sabreNode->getId()];
} else {
$node = $this->userFolder->get($sabreNode->getPath());
$shareTypes = $this->getShareTypes($node);
}
return new ShareTypeList($shareTypes);
});
}
}

View File

@@ -0,0 +1,87 @@
<?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\Connector\Sabre;
use Sabre\Xml\Element;
use Sabre\Xml\Reader;
use Sabre\Xml\Writer;
/**
* ShareTypeList property
*
* This property contains multiple "share-type" elements, each containing a share type.
*/
class ShareTypeList implements Element {
const NS_OWNCLOUD = 'http://owncloud.org/ns';
/**
* Share types
*
* @var int[]
*/
private $shareTypes;
/**
* @param int[] $shareTypes
*/
public function __construct($shareTypes) {
$this->shareTypes = $shareTypes;
}
/**
* Returns the share types
*
* @return int[]
*/
public function getShareTypes() {
return $this->shareTypes;
}
/**
* The deserialize method is called during xml parsing.
*
* @param Reader $reader
* @return mixed
*/
static function xmlDeserialize(Reader $reader) {
$shareTypes = [];
foreach ($reader->parseInnerTree() as $elem) {
if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}share-type') {
$shareTypes[] = (int)$elem['value'];
}
}
return new self($shareTypes);
}
/**
* The xmlSerialize metod is called during xml writing.
*
* @param Writer $writer
* @return void
*/
function xmlSerialize(Writer $writer) {
foreach ($this->shareTypes as $shareType) {
$writer->writeElement('{' . self::NS_OWNCLOUD . '}share-type', $shareType);
}
}
}

View File

@@ -190,6 +190,14 @@ class Backend {
'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'],
'protected' => true,
];
} else if ($this->resourceType === 'calendar') {
// Allow changing the properties of read only calendars,
// so users can change the visibility.
$acl[] = [
'privilege' => '{DAV:}write-properties',
'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'],
'protected' => true,
];
}
}
return $acl;

View File

@@ -28,6 +28,11 @@ use Sabre\HTTP\URLUtil;
class FilesHome implements ICollection {
/**
* @var array
*/
private $principalInfo;
/**
* FilesHome constructor.
*

View File

@@ -23,10 +23,8 @@ namespace OCA\Dav\Migration;
use OCA\DAV\CardDAV\AddressBook;
use OCA\DAV\CardDAV\CardDavBackend;
use OCP\ILogger;
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 {
@@ -37,15 +35,26 @@ class MigrateAddressbooks {
/** @var CardDavBackend */
private $backend;
/** @var ILogger */
private $logger;
/** @var OutputInterface */
private $consoleOutput;
/**
* @param AddressBookAdapter $adapter
* @param CardDavBackend $backend
*/
function __construct(AddressBookAdapter $adapter,
CardDavBackend $backend
CardDavBackend $backend,
ILogger $logger,
OutputInterface $consoleOutput = null
) {
$this->adapter = $adapter;
$this->backend = $backend;
$this->logger = $logger;
$this->consoleOutput = $consoleOutput;
}
/**
@@ -80,7 +89,17 @@ class MigrateAddressbooks {
*/
private function migrateBook($addressBookId, $newAddressBookId) {
$this->adapter->foreachCard($addressBookId, function($card) use ($newAddressBookId) {
$this->backend->createCard($newAddressBookId, $card['uri'], $card['carddata']);
try {
$this->backend->createCard($newAddressBookId, $card['uri'], $card['carddata']);
} catch (\Exception $ex) {
$eventId = $card['id'];
$addressBookId = $card['addressbookid'];
$msg = "One event could not be migrated. (id: $eventId, addressbookid: $addressBookId)";
$this->logger->logException($ex, ['app' => 'dav', 'message' => $msg]);
if (!is_null($this->consoleOutput)) {
$this->consoleOutput->writeln($msg);
}
}
});
}
@@ -96,11 +115,12 @@ class MigrateAddressbooks {
$add = array_map(function($s) {
$prefix = 'principal:principals/users/';
if ($s['share_type'] === 1) {
if ((int)$s['share_type'] === 1) {
$prefix = 'principal:principals/groups/';
}
return [
'href' => $prefix . $s['share_with']
'href' => $prefix . $s['share_with'],
'readOnly' => !((int)$s['permissions'] === 31)
];
}, $shares);

View File

@@ -23,9 +23,7 @@ namespace OCA\Dav\Migration;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\Calendar;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use OCP\ILogger;
use Symfony\Component\Console\Output\OutputInterface;
class MigrateCalendars {
@@ -36,15 +34,25 @@ class MigrateCalendars {
/** @var CalDavBackend */
private $backend;
/** @var ILogger */
private $logger;
/** @var OutputInterface */
private $consoleOutput;
/**
* @param CalendarAdapter $adapter
* @param CalDavBackend $backend
*/
function __construct(CalendarAdapter $adapter,
CalDavBackend $backend
CalDavBackend $backend,
ILogger $logger,
OutputInterface $consoleOutput = null
) {
$this->adapter = $adapter;
$this->backend = $backend;
$this->logger = $logger;
$this->consoleOutput = $consoleOutput;
}
/**
@@ -82,7 +90,17 @@ class MigrateCalendars {
*/
private function migrateCalendar($calendarId, $newCalendarId) {
$this->adapter->foreachCalendarObject($calendarId, function($calObject) use ($newCalendarId) {
$this->backend->createCalendarObject($newCalendarId, $calObject['uri'], $calObject['calendardata']);
try {
$this->backend->createCalendarObject($newCalendarId, $calObject['uri'], $calObject['calendardata']);
} catch (\Exception $ex) {
$eventId = $calObject['id'];
$calendarId = $calObject['calendarId'];
$msg = "One event could not be migrated. (id: $eventId, calendarid: $calendarId)";
$this->logger->logException($ex, ['app' => 'dav', 'message' => $msg]);
if (!is_null($this->consoleOutput)) {
$this->consoleOutput->writeln($msg);
}
}
});
}
@@ -98,11 +116,12 @@ class MigrateCalendars {
$add = array_map(function($s) {
$prefix = 'principal:principals/users/';
if ($s['share_type'] === 1) {
if ((int)$s['share_type'] === 1) {
$prefix = 'principal:principals/groups/';
}
return [
'href' => $prefix . $s['share_with']
'href' => $prefix . $s['share_with'],
'readOnly' => !((int)$s['permissions'] === 31)
];
}, $shares);

View File

@@ -57,11 +57,11 @@ class CalDavBackendTest extends TestCase {
->disableOriginalConstructor()
->setMethods(['getPrincipalByPath', 'getGroupMembership'])
->getMock();
$this->principal->method('getPrincipalByPath')
$this->principal->expects($this->any())->method('getPrincipalByPath')
->willReturn([
'uri' => 'principals/best-friend'
]);
$this->principal->method('getGroupMembership')
$this->principal->expects($this->any())->method('getGroupMembership')
->withAnyParameters()
->willReturn([self::UNIT_TEST_GROUP]);
@@ -446,6 +446,21 @@ EOD;
$this->assertEquals(0, count($sos));
}
/**
* @dataProvider providesCalDataForGetDenormalizedData
*/
public function testGetDenormalizedData($expectedFirstOccurance, $calData) {
$actual = $this->invokePrivate($this->backend, 'getDenormalizedData', [$calData]);
$this->assertEquals($expectedFirstOccurance, $actual['firstOccurence']);
}
public function providesCalDataForGetDenormalizedData() {
return [
[0, "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nDTSTART;VALUE=DATE:16040222\r\nDTEND;VALUE=DATE:16040223\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"],
[null, "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"]
];
}
private function assertAcl($principal, $privilege, $acl) {
foreach($acl as $a) {
if ($a['principal'] === $principal && $a['privilege'] === $privilege) {

View File

@@ -23,6 +23,7 @@ namespace OCA\DAV\Tests\Unit\CalDAV;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\Calendar;
use Sabre\DAV\PropPatch;
use Test\TestCase;
class CalendarTest extends TestCase {
@@ -31,7 +32,7 @@ class CalendarTest extends TestCase {
/** @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([
$backend->expects($this->any())->method('getShares')->willReturn([
['href' => 'principal:user2']
]);
$calendarInfo = [
@@ -51,7 +52,7 @@ class CalendarTest extends TestCase {
/** @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([
$backend->expects($this->any())->method('getShares')->willReturn([
['href' => 'principal:group2']
]);
$calendarInfo = [
@@ -63,4 +64,103 @@ class CalendarTest extends TestCase {
$c = new Calendar($backend, $calendarInfo);
$c->delete();
}
public function dataPropPatch() {
return [
[[], true],
[[
'{http://owncloud.org/ns}calendar-enabled' => true,
], false],
[[
'{DAV:}displayname' => true,
], true],
[[
'{DAV:}displayname' => true,
'{http://owncloud.org/ns}calendar-enabled' => true,
], true],
];
}
/**
* @dataProvider dataPropPatch
*/
public function testPropPatch($mutations, $throws) {
/** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */
$backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock();
$calendarInfo = [
'{http://owncloud.org/ns}owner-principal' => 'user1',
'principaluri' => 'user2',
'id' => 666,
'uri' => 'default'
];
$c = new Calendar($backend, $calendarInfo);
if ($throws) {
$this->setExpectedException('\Sabre\DAV\Exception\Forbidden');
}
$c->propPatch(new PropPatch($mutations));
if (!$throws) {
$this->assertTrue(true);
}
}
/**
* @dataProvider providesReadOnlyInfo
*/
public function testAcl($expectsWrite, $readOnlyValue, $hasOwnerSet) {
/** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */
$backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock();
$backend->expects($this->any())->method('applyShareAcl')->willReturnArgument(1);
$calendarInfo = [
'principaluri' => 'user2',
'id' => 666,
'uri' => 'default'
];
if (!is_null($readOnlyValue)) {
$calendarInfo['{http://owncloud.org/ns}read-only'] = $readOnlyValue;
}
if ($hasOwnerSet) {
$calendarInfo['{http://owncloud.org/ns}owner-principal'] = 'user1';
}
$c = new Calendar($backend, $calendarInfo);
$acl = $c->getACL();
$childAcl = $c->getChildACL();
$expectedAcl = [[
'privilege' => '{DAV:}read',
'principal' => $hasOwnerSet ? 'user1' : 'user2',
'protected' => true
], [
'privilege' => '{DAV:}write',
'principal' => $hasOwnerSet ? 'user1' : 'user2',
'protected' => true
]];
if ($hasOwnerSet) {
$expectedAcl[] = [
'privilege' => '{DAV:}read',
'principal' => 'user2',
'protected' => true
];
if ($expectsWrite) {
$expectedAcl[] = [
'privilege' => '{DAV:}write',
'principal' => 'user2',
'protected' => true
];
}
}
$this->assertEquals($expectedAcl, $acl);
$this->assertEquals($expectedAcl, $childAcl);
}
public function providesReadOnlyInfo() {
return [
'read-only property not set' => [true, null, true],
'read-only property is false' => [true, false, true],
'read-only property is true' => [false, true, true],
'read-only property not set and no owner' => [true, null, false],
'read-only property is false and no owner' => [true, false, false],
'read-only property is true and no owner' => [false, true, false],
];
}
}

View File

@@ -23,6 +23,7 @@ namespace OCA\DAV\Tests\Unit\CardDAV;
use OCA\DAV\CardDAV\AddressBook;
use OCA\DAV\CardDAV\CardDavBackend;
use Sabre\DAV\PropPatch;
use Test\TestCase;
class AddressBookTest extends TestCase {
@@ -31,7 +32,7 @@ class AddressBookTest extends TestCase {
/** @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([
$backend->expects($this->any())->method('getShares')->willReturn([
['href' => 'principal:user2']
]);
$calendarInfo = [
@@ -50,7 +51,7 @@ class AddressBookTest extends TestCase {
/** @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([
$backend->expects($this->any())->method('getShares')->willReturn([
['href' => 'principal:group2']
]);
$calendarInfo = [
@@ -61,4 +62,78 @@ class AddressBookTest extends TestCase {
$c = new AddressBook($backend, $calendarInfo);
$c->delete();
}
}
/**
* @expectedException \Sabre\DAV\Exception\Forbidden
*/
public function testPropPatch() {
/** @var \PHPUnit_Framework_MockObject_MockObject | CardDavBackend $backend */
$backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock();
$calendarInfo = [
'{http://owncloud.org/ns}owner-principal' => 'user1',
'principaluri' => 'user2',
'id' => 666
];
$c = new AddressBook($backend, $calendarInfo);
$c->propPatch(new PropPatch([]));
}
/**
* @dataProvider providesReadOnlyInfo
*/
public function testAcl($expectsWrite, $readOnlyValue, $hasOwnerSet) {
/** @var \PHPUnit_Framework_MockObject_MockObject | CardDavBackend $backend */
$backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock();
$backend->expects($this->any())->method('applyShareAcl')->willReturnArgument(1);
$calendarInfo = [
'principaluri' => 'user2',
'id' => 666,
'uri' => 'default'
];
if (!is_null($readOnlyValue)) {
$calendarInfo['{http://owncloud.org/ns}read-only'] = $readOnlyValue;
}
if ($hasOwnerSet) {
$calendarInfo['{http://owncloud.org/ns}owner-principal'] = 'user1';
}
$c = new AddressBook($backend, $calendarInfo);
$acl = $c->getACL();
$childAcl = $c->getChildACL();
$expectedAcl = [[
'privilege' => '{DAV:}read',
'principal' => $hasOwnerSet ? 'user1' : 'user2',
'protected' => true
], [
'privilege' => '{DAV:}write',
'principal' => $hasOwnerSet ? 'user1' : 'user2',
'protected' => true
]];
if ($hasOwnerSet) {
$expectedAcl[] = [
'privilege' => '{DAV:}read',
'principal' => 'user2',
'protected' => true
];
if ($expectsWrite) {
$expectedAcl[] = [
'privilege' => '{DAV:}write',
'principal' => 'user2',
'protected' => true
];
}
}
$this->assertEquals($expectedAcl, $acl);
$this->assertEquals($expectedAcl, $childAcl);
}
public function providesReadOnlyInfo() {
return [
'read-only property not set' => [true, null, true],
'read-only property is false' => [true, false, true],
'read-only property is true' => [false, true, true],
'read-only property not set and no owner' => [true, null, false],
'read-only property is false and no owner' => [true, false, false],
'read-only property is true and no owner' => [false, true, false],
];
}}

View File

@@ -198,10 +198,7 @@ class Auth extends TestCase {
$this->assertFalse($this->invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
}
/**
* @expectedException \Sabre\DAV\Exception\NotAuthenticated
* @expectedExceptionMessage CSRF check not passed.
*/
public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForNonGet() {
$request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
->disableOriginalConstructor()
@@ -210,27 +207,182 @@ class Auth extends TestCase {
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->once())
->expects($this->any())
->method('isLoggedIn')
->will($this->returnValue(true));
$this->request
->expects($this->any())
->method('getMethod')
->willReturn('POST');
$this->session
->expects($this->once())
->expects($this->any())
->method('get')
->with('AUTHENTICATED_TO_DAV_BACKEND')
->will($this->returnValue(null));
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()
->getMock();
$user->expects($this->once())
$user->expects($this->any())
->method('getUID')
->will($this->returnValue('MyWrongDavUser'));
$this->userSession
->expects($this->once())
->expects($this->any())
->method('getUser')
->will($this->returnValue($user));
$this->request
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(false);
$expectedResponse = [
false,
"No 'Authorization: Basic' header found. Either the client didn't send one, or the server is mis-configured",
];
$response = $this->auth->check($request, $response);
$this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response);
$this->assertSame($expectedResponse, $response);
}
public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenAndCorrectlyDavAuthenticated() {
$request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
->disableOriginalConstructor()
->getMock();
$response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->any())
->method('isLoggedIn')
->willReturn(true);
$this->request
->expects($this->any())
->method('getMethod')
->willReturn('PROPFIND');
$this->request
->expects($this->any())
->method('isUserAgent')
->with([
'/^Mozilla\/5\.0 \([A-Za-z ]+\) (mirall|csyncoC)\/.*$/',
'/^Mozilla\/5\.0 \(Android\) ownCloud\-android.*$/',
'/^Mozilla\/5\.0 \(iOS\) ownCloud\-iOS.*$/',
])
->willReturn(false);
$this->session
->expects($this->any())
->method('get')
->with('AUTHENTICATED_TO_DAV_BACKEND')
->will($this->returnValue('LoggedInUser'));
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()
->getMock();
$user->expects($this->any())
->method('getUID')
->will($this->returnValue('LoggedInUser'));
$this->userSession
->expects($this->any())
->method('getUser')
->will($this->returnValue($user));
$this->request
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(false);
$this->auth->check($request, $response);
}
/**
* @expectedException \Sabre\DAV\Exception\NotAuthenticated
* @expectedExceptionMessage CSRF check not passed.
*/
public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenAndIncorrectlyDavAuthenticated() {
$request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
->disableOriginalConstructor()
->getMock();
$response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->any())
->method('isLoggedIn')
->willReturn(true);
$this->request
->expects($this->any())
->method('getMethod')
->willReturn('PROPFIND');
$this->request
->expects($this->any())
->method('isUserAgent')
->with([
'/^Mozilla\/5\.0 \([A-Za-z ]+\) (mirall|csyncoC)\/.*$/',
'/^Mozilla\/5\.0 \(Android\) ownCloud\-android.*$/',
'/^Mozilla\/5\.0 \(iOS\) ownCloud\-iOS.*$/',
])
->willReturn(false);
$this->session
->expects($this->any())
->method('get')
->with('AUTHENTICATED_TO_DAV_BACKEND')
->will($this->returnValue('AnotherUser'));
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()
->getMock();
$user->expects($this->any())
->method('getUID')
->will($this->returnValue('LoggedInUser'));
$this->userSession
->expects($this->any())
->method('getUser')
->will($this->returnValue($user));
$this->request
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(false);
$this->auth->check($request, $response);
}
public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForNonGetAndDesktopClient() {
$request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
->disableOriginalConstructor()
->getMock();
$response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->any())
->method('isLoggedIn')
->will($this->returnValue(true));
$this->request
->expects($this->any())
->method('getMethod')
->willReturn('POST');
$this->request
->expects($this->any())
->method('isUserAgent')
->with([
'/^Mozilla\/5\.0 \([A-Za-z ]+\) (mirall|csyncoC)\/.*$/',
'/^Mozilla\/5\.0 \(Android\) ownCloud\-android.*$/',
'/^Mozilla\/5\.0 \(iOS\) ownCloud\-iOS.*$/',
])
->willReturn(true);
$this->session
->expects($this->any())
->method('get')
->with('AUTHENTICATED_TO_DAV_BACKEND')
->will($this->returnValue(null));
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()
->getMock();
$user->expects($this->any())
->method('getUID')
->will($this->returnValue('MyWrongDavUser'));
$this->userSession
->expects($this->any())
->method('getUser')
->will($this->returnValue($user));
$this->request
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(false);
$this->auth->check($request, $response);
}
public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForGet() {
@@ -241,26 +393,26 @@ class Auth extends TestCase {
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->exactly(2))
->expects($this->any())
->method('isLoggedIn')
->will($this->returnValue(true));
$this->session
->expects($this->once())
->expects($this->any())
->method('get')
->with('AUTHENTICATED_TO_DAV_BACKEND')
->will($this->returnValue(null));
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()
->getMock();
$user->expects($this->once())
$user->expects($this->any())
->method('getUID')
->will($this->returnValue('MyWrongDavUser'));
$this->userSession
->expects($this->once())
->expects($this->any())
->method('getUser')
->will($this->returnValue($user));
$this->request
->expects($this->once())
->expects($this->any())
->method('getMethod')
->willReturn('GET');
@@ -268,7 +420,6 @@ class Auth extends TestCase {
$this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response);
}
public function testAuthenticateAlreadyLoggedInWithCsrfTokenForGet() {
$request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
->disableOriginalConstructor()
@@ -277,22 +428,22 @@ class Auth extends TestCase {
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->exactly(2))
->expects($this->any())
->method('isLoggedIn')
->will($this->returnValue(true));
$this->session
->expects($this->exactly(2))
->expects($this->any())
->method('get')
->with('AUTHENTICATED_TO_DAV_BACKEND')
->will($this->returnValue(null));
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()
->getMock();
$user->expects($this->exactly(2))
$user->expects($this->any())
->method('getUID')
->will($this->returnValue('MyWrongDavUser'));
$this->userSession
->expects($this->exactly(2))
->expects($this->any())
->method('getUser')
->will($this->returnValue($user));
$this->request
@@ -368,6 +519,10 @@ class Auth extends TestCase {
->method('get')
->with('AUTHENTICATED_TO_DAV_BACKEND')
->will($this->returnValue('MyTestUser'));
$this->request
->expects($this->once())
->method('getMethod')
->willReturn('GET');
$httpRequest
->expects($this->atLeastOnce())
->method('getHeader')
@@ -407,15 +562,15 @@ class Auth extends TestCase {
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()
->getMock();
$user->expects($this->exactly(2))
$user->expects($this->exactly(3))
->method('getUID')
->will($this->returnValue('MyTestUser'));
$this->userSession
->expects($this->exactly(2))
->expects($this->exactly(3))
->method('getUser')
->will($this->returnValue($user));
$response = $this->auth->check($server->httpRequest, $server->httpResponse);
$this->assertEquals([true, 'principals/users/username'], $response);
$this->assertEquals([true, 'principals/users/MyTestUser'], $response);
}
public function testAuthenticateInvalidCredentials() {

View File

@@ -109,8 +109,6 @@ class FilesPlugin extends \Test\TestCase {
return $node;
}
/**
*/
public function testGetPropertiesForFile() {
$node = $this->createTestNode('\OCA\DAV\Connector\Sabre\File');
@@ -165,6 +163,56 @@ class FilesPlugin extends \Test\TestCase {
$this->assertEquals(array(self::SIZE_PROPERTYNAME), $propFind->get404Properties());
}
public function testGetPropertiesForFileHome() {
$node = $this->createTestNode('\OCA\DAV\Files\FilesHome');
$propFind = new \Sabre\DAV\PropFind(
'/dummyPath',
array(
self::GETETAG_PROPERTYNAME,
self::FILEID_PROPERTYNAME,
self::INTERNAL_FILEID_PROPERTYNAME,
self::SIZE_PROPERTYNAME,
self::PERMISSIONS_PROPERTYNAME,
self::DOWNLOADURL_PROPERTYNAME,
self::OWNER_ID_PROPERTYNAME,
self::OWNER_DISPLAY_NAME_PROPERTYNAME
),
0
);
$user = $this->getMockBuilder('\OC\User\User')
->disableOriginalConstructor()->getMock();
$user->expects($this->never())->method('getUID');
$user->expects($this->never())->method('getDisplayName');
$node->expects($this->never())->method('getDirectDownload');
$node->expects($this->never())->method('getOwner');
$node->expects($this->never())->method('getSize');
$this->plugin->handleGetProperties(
$propFind,
$node
);
$this->assertEquals(null, $propFind->get(self::GETETAG_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::FILEID_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::INTERNAL_FILEID_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::SIZE_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::PERMISSIONS_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::OWNER_ID_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::OWNER_DISPLAY_NAME_PROPERTYNAME));
$this->assertEquals(['{DAV:}getetag',
'{http://owncloud.org/ns}id',
'{http://owncloud.org/ns}fileid',
'{http://owncloud.org/ns}size',
'{http://owncloud.org/ns}permissions',
'{http://owncloud.org/ns}downloadURL',
'{http://owncloud.org/ns}owner-id',
'{http://owncloud.org/ns}owner-display-name'
], $propFind->get404Properties());
}
public function testGetPropertiesStorageNotAvailable() {
$node = $this->createTestNode('\OCA\DAV\Connector\Sabre\File');

View File

@@ -31,8 +31,8 @@ class Node extends \Test\TestCase {
array(\OCP\Constants::PERMISSION_ALL, 'file', true, false, 'SRDNVW'),
array(\OCP\Constants::PERMISSION_ALL, 'file', true, true, 'SRMDNVW'),
array(\OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE, 'file', true, false, 'SDNVW'),
array(\OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_UPDATE, 'file', false, false, 'RDNV'),
array(\OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_DELETE, 'file', false, false, 'RW'),
array(\OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_UPDATE, 'file', false, false, 'RD'),
array(\OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_DELETE, 'file', false, false, 'RNVW'),
array(\OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE, 'file', false, false, 'RDNVW'),
array(\OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE, 'dir', false, false, 'RDNV'),
);

View File

@@ -0,0 +1,259 @@
<?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\Connector\Sabre;
class SharesPlugin extends \Test\TestCase {
const SHARETYPES_PROPERTYNAME = \OCA\DAV\Connector\Sabre\SharesPlugin::SHARETYPES_PROPERTYNAME;
/**
* @var \Sabre\DAV\Server
*/
private $server;
/**
* @var \Sabre\DAV\Tree
*/
private $tree;
/**
* @var \OCP\Share\IManager
*/
private $shareManager;
/**
* @var \OCP\Files\Folder
*/
private $userFolder;
/**
* @var \OCA\DAV\Connector\Sabre\SharesPlugin
*/
private $plugin;
public function setUp() {
parent::setUp();
$this->server = new \Sabre\DAV\Server();
$this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
->disableOriginalConstructor()
->getMock();
$this->shareManager = $this->getMock('\OCP\Share\IManager');
$user = $this->getMock('\OCP\IUser');
$user->expects($this->once())
->method('getUID')
->will($this->returnValue('user1'));
$userSession = $this->getMock('\OCP\IUserSession');
$userSession->expects($this->once())
->method('getUser')
->will($this->returnValue($user));
$this->userFolder = $this->getMock('\OCP\Files\Folder');
$this->plugin = new \OCA\DAV\Connector\Sabre\SharesPlugin(
$this->tree,
$userSession,
$this->userFolder,
$this->shareManager
);
$this->plugin->initialize($this->server);
}
/**
* @dataProvider sharesGetPropertiesDataProvider
*/
public function testGetProperties($shareTypes) {
$sabreNode = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Node')
->disableOriginalConstructor()
->getMock();
$sabreNode->expects($this->any())
->method('getId')
->will($this->returnValue(123));
$sabreNode->expects($this->once())
->method('getPath')
->will($this->returnValue('/subdir'));
// node API nodes
$node = $this->getMock('\OCP\Files\Folder');
$this->userFolder->expects($this->once())
->method('get')
->with('/subdir')
->will($this->returnValue($node));
$this->shareManager->expects($this->any())
->method('getSharesBy')
->with(
$this->equalTo('user1'),
$this->anything(),
$this->anything(),
$this->equalTo(false),
$this->equalTo(1)
)
->will($this->returnCallback(function($userId, $requestedShareType, $node, $flag, $limit) use ($shareTypes){
if (in_array($requestedShareType, $shareTypes)) {
return ['dummyshare'];
}
return [];
}));
$propFind = new \Sabre\DAV\PropFind(
'/dummyPath',
[self::SHARETYPES_PROPERTYNAME],
0
);
$this->plugin->handleGetProperties(
$propFind,
$sabreNode
);
$result = $propFind->getResultForMultiStatus();
$this->assertEmpty($result[404]);
unset($result[404]);
$this->assertEquals($shareTypes, $result[200][self::SHARETYPES_PROPERTYNAME]->getShareTypes());
}
/**
* @dataProvider sharesGetPropertiesDataProvider
*/
public function testPreloadThenGetProperties($shareTypes) {
$sabreNode1 = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File')
->disableOriginalConstructor()
->getMock();
$sabreNode1->expects($this->any())
->method('getId')
->will($this->returnValue(111));
$sabreNode1->expects($this->never())
->method('getPath');
$sabreNode2 = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File')
->disableOriginalConstructor()
->getMock();
$sabreNode2->expects($this->any())
->method('getId')
->will($this->returnValue(222));
$sabreNode2->expects($this->never())
->method('getPath');
$sabreNode = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory')
->disableOriginalConstructor()
->getMock();
$sabreNode->expects($this->any())
->method('getId')
->will($this->returnValue(123));
// never, because we use getDirectoryListing from the Node API instead
$sabreNode->expects($this->never())
->method('getChildren');
$sabreNode->expects($this->any())
->method('getPath')
->will($this->returnValue('/subdir'));
// node API nodes
$node = $this->getMock('\OCP\Files\Folder');
$node->expects($this->any())
->method('getId')
->will($this->returnValue(123));
$node1 = $this->getMock('\OCP\Files\File');
$node1->expects($this->any())
->method('getId')
->will($this->returnValue(111));
$node2 = $this->getMock('\OCP\Files\File');
$node2->expects($this->any())
->method('getId')
->will($this->returnValue(222));
$node->expects($this->once())
->method('getDirectoryListing')
->will($this->returnValue([$node1, $node2]));
$this->userFolder->expects($this->once())
->method('get')
->with('/subdir')
->will($this->returnValue($node));
$this->shareManager->expects($this->any())
->method('getSharesBy')
->with(
$this->equalTo('user1'),
$this->anything(),
$this->anything(),
$this->equalTo(false),
$this->equalTo(1)
)
->will($this->returnCallback(function($userId, $requestedShareType, $node, $flag, $limit) use ($shareTypes){
if ($node->getId() === 111 && in_array($requestedShareType, $shareTypes)) {
return ['dummyshare'];
}
return [];
}));
// simulate sabre recursive PROPFIND traversal
$propFindRoot = new \Sabre\DAV\PropFind(
'/subdir',
[self::SHARETYPES_PROPERTYNAME],
1
);
$propFind1 = new \Sabre\DAV\PropFind(
'/subdir/test.txt',
[self::SHARETYPES_PROPERTYNAME],
0
);
$propFind2 = new \Sabre\DAV\PropFind(
'/subdir/test2.txt',
[self::SHARETYPES_PROPERTYNAME],
0
);
$this->plugin->handleGetProperties(
$propFindRoot,
$sabreNode
);
$this->plugin->handleGetProperties(
$propFind1,
$sabreNode1
);
$this->plugin->handleGetProperties(
$propFind2,
$sabreNode2
);
$result = $propFind1->getResultForMultiStatus();
$this->assertEmpty($result[404]);
unset($result[404]);
$this->assertEquals($shareTypes, $result[200][self::SHARETYPES_PROPERTYNAME]->getShareTypes());
}
function sharesGetPropertiesDataProvider() {
return [
[[]],
[[\OCP\Share::SHARE_TYPE_USER]],
[[\OCP\Share::SHARE_TYPE_GROUP]],
[[\OCP\Share::SHARE_TYPE_LINK]],
[[\OCP\Share::SHARE_TYPE_REMOTE]],
[[\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP]],
[[\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK]],
[[\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_LINK]],
[[\OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK]],
[[\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_REMOTE]],
];
}
}

View File

@@ -22,21 +22,32 @@ namespace OCA\DAV\Tests\Unit\Migration;
use OCA\DAV\CardDAV\CardDavBackend;
use OCA\Dav\Migration\AddressBookAdapter;
use OCP\ILogger;
use Test\TestCase;
class MigrateAddressbookTest extends TestCase {
public function testMigration() {
/** @var AddressBookAdapter | \PHPUnit_Framework_MockObject_MockObject $adapter */
$adapter = $this->mockAdapter();
$adapter = $this->mockAdapter([
['share_type' => '1', 'share_with' => 'users', 'permissions' => '31'],
['share_type' => '2', 'share_with' => 'adam', 'permissions' => '1'],
]);
/** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $cardDav */
$cardDav = $this->getMockBuilder('\OCA\Dav\CardDAV\CardDAVBackend')->disableOriginalConstructor()->getMock();
$cardDav->method('createAddressBook')->willReturn(666);
$cardDav->expects($this->any())->method('createAddressBook')->willReturn(666);
$cardDav->expects($this->any())->method('getAddressBookById')->willReturn([]);
$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');
$cardDav->expects($this->once())->method('updateShares')->with($this->anything(), [
['href' => 'principal:principals/groups/users', 'readOnly' => false],
['href' => 'principal:principals/users/adam', 'readOnly' => true]
]);
/** @var ILogger $logger */
$logger = $this->getMockBuilder('\OCP\ILogger')->disableOriginalConstructor()->getMock();
$m = new \OCA\Dav\Migration\MigrateAddressbooks($adapter, $cardDav);
$m = new \OCA\Dav\Migration\MigrateAddressbooks($adapter, $cardDav, $logger, null);
$m->migrateForUser('test01');
}
@@ -45,7 +56,7 @@ class MigrateAddressbookTest extends TestCase {
*/
private function mockAdapter($shares = []) {
$adapter = $this->getMockBuilder('\OCA\Dav\Migration\AddressBookAdapter')->disableOriginalConstructor()->getMock();
$adapter->method('foreachBook')->willReturnCallback(function ($user, \Closure $callBack) {
$adapter->expects($this->any())->method('foreachBook')->willReturnCallback(function ($user, \Closure $callBack) {
$callBack([
'id' => 0,
'userid' => $user,
@@ -56,14 +67,14 @@ class MigrateAddressbookTest extends TestCase {
'active' => 1
]);
});
$adapter->method('foreachCard')->willReturnCallback(function ($addressBookId, \Closure $callBack) {
$adapter->expects($this->any())->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);
$adapter->expects($this->any())->method('getShares')->willReturn($shares);
return $adapter;
}

View File

@@ -22,32 +22,42 @@ namespace OCA\DAV\Tests\Unit\Migration;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\Dav\Migration\CalendarAdapter;
use OCP\ILogger;
use Test\TestCase;
class MigrateCalendarTest extends TestCase {
public function testMigration() {
/** @var CalendarAdapter | \PHPUnit_Framework_MockObject_MockObject $adapter */
$adapter = $this->mockAdapter();
$adapter = $this->mockAdapter([
['share_type' => '1', 'share_with' => 'users', 'permissions' => '31'],
['share_type' => '2', 'share_with' => 'adam', 'permissions' => '1'],
]);
/** @var CalDavBackend | \PHPUnit_Framework_MockObject_MockObject $cardDav */
$cardDav = $this->getMockBuilder('\OCA\Dav\CalDAV\CalDAVBackend')->disableOriginalConstructor()->getMock();
$cardDav->method('createCalendar')->willReturn(666);
$cardDav->expects($this->any())->method('createCalendar')->willReturn(666);
$cardDav->expects($this->once())->method('createCalendar')->with('principals/users/test01', 'test_contacts');
$cardDav->expects($this->once())->method('createCalendarObject')->with(666, '63f0dd6c-39d5-44be-9d34-34e7a7441fc2.ics', 'BEGIN:VCARD');
$cardDav->expects($this->once())->method('updateShares')->with($this->anything(), [
['href' => 'principal:principals/groups/users', 'readOnly' => false],
['href' => 'principal:principals/users/adam', 'readOnly' => true]
]);
/** @var ILogger $logger */
$logger = $this->getMockBuilder('\OCP\ILogger')->disableOriginalConstructor()->getMock();
$m = new \OCA\Dav\Migration\MigrateCalendars($adapter, $cardDav);
$m = new \OCA\Dav\Migration\MigrateCalendars($adapter, $cardDav, $logger, null);
$m->migrateForUser('test01');
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject
*/
private function mockAdapter($shares = []) {
private function mockAdapter($shares = [], $calData = 'BEGIN:VCARD') {
$adapter = $this->getMockBuilder('\OCA\Dav\Migration\CalendarAdapter')
->disableOriginalConstructor()
->getMock();
$adapter->method('foreachCalendar')->willReturnCallback(function ($user, \Closure $callBack) {
$adapter->expects($this->any())->method('foreachCalendar')->willReturnCallback(function ($user, \Closure $callBack) {
$callBack([
// calendarorder | calendarcolor | timezone | components
'id' => 0,
@@ -62,15 +72,14 @@ class MigrateCalendarTest extends TestCase {
'components' => 'VEVENT,VTODO,VJOURNAL'
]);
});
$adapter->method('foreachCalendarObject')->willReturnCallback(function ($addressBookId, \Closure $callBack) {
$adapter->expects($this->any())->method('foreachCalendarObject')->willReturnCallback(function ($addressBookId, \Closure $callBack) use ($calData) {
$callBack([
'userid' => $addressBookId,
'uri' => '63f0dd6c-39d5-44be-9d34-34e7a7441fc2.ics',
'calendardata' => 'BEGIN:VCARD'
'calendardata' => $calData
]);
});
$adapter->method('getShares')->willReturn($shares);
$adapter->expects($this->any())->method('getShares')->willReturn($shares);
return $adapter;
}
}

View File

@@ -51,6 +51,7 @@ OC.L10N.register(
"Enable password recovery:" : "Die Passwort-Wiederherstellung aktivieren:",
"Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" : "Durch die Aktivierung dieser Option haben Sie die Möglichkeit, wieder auf Ihre verschlüsselten Dateien zugreifen zu können, wenn Sie Ihr Passwort verloren haben.",
"Enabled" : "Aktiviert",
"Disabled" : "Deaktiviert"
"Disabled" : "Deaktiviert",
"one-time password for server-side-encryption" : "Einmalpasswort für Serverseitige Verschlüsselung"
},
"nplurals=2; plural=(n != 1);");

Some files were not shown because too many files have changed in this diff Show More