diff options
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | apps/dav/lib/carddav/carddavbackend.php | 8 | ||||
-rw-r--r-- | apps/dav/tests/travis/caldavtest/config/serverinfo.dtd | 43 | ||||
-rw-r--r-- | apps/dav/tests/travis/caldavtest/config/serverinfo.xml | 854 | ||||
-rw-r--r-- | apps/dav/tests/travis/caldavtest/tests/CardDAV/current-user-principal.xml | 150 | ||||
-rw-r--r-- | apps/dav/tests/travis/carddavtester.sh | 28 | ||||
-rw-r--r-- | apps/dav/tests/unit/carddav/carddavbackendtest.php | 1 | ||||
-rw-r--r-- | apps/files_sharing/tests/share.php | 16 | ||||
-rw-r--r-- | build/integration/features/bootstrap/FeatureContext.php | 29 | ||||
-rw-r--r-- | build/integration/features/sharing-v1.feature | 27 | ||||
-rw-r--r-- | lib/base.php | 9 | ||||
-rw-r--r-- | lib/private/files/fileinfo.php | 20 | ||||
-rw-r--r-- | lib/private/files/node/node.php | 4 | ||||
-rw-r--r-- | lib/private/files/view.php | 19 | ||||
-rw-r--r-- | lib/public/files/fileinfo.php | 8 | ||||
-rw-r--r-- | settings/templates/apps.php | 2 | ||||
-rw-r--r-- | tests/lib/files/view.php | 54 |
17 files changed, 1253 insertions, 21 deletions
diff --git a/.travis.yml b/.travis.yml index 95e8a2f7de4..49a9e07e3fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,8 @@ matrix: include: - php: 5.4 env: DB=pgsql;TC=litmus-v1 + - php: 5.4 + env: DB=pgsql;TC=carddavtester # - php: 5.4 # env: DB=mysql;TC=caldavtester diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php index 7b16262a680..b2597baedc6 100644 --- a/apps/dav/lib/carddav/carddavbackend.php +++ b/apps/dav/lib/carddav/carddavbackend.php @@ -134,7 +134,7 @@ class CardDavBackend implements BackendInterface, SyncSupport { * @param string $principalUri * @param string $url Just the 'basename' of the url. * @param array $properties - * @return void + * @throws BadRequest */ function createAddressBook($principalUri, $url, array $properties) { $values = [ @@ -160,6 +160,12 @@ class CardDavBackend implements BackendInterface, SyncSupport { } + // Fallback to make sure the displayname is set. Some clients may refuse + // to work with addressbooks not having a displayname. + if(is_null($values['displayname'])) { + $values['displayname'] = $url; + } + $query = $this->db->getQueryBuilder(); $query->insert('addressbooks') ->values([ diff --git a/apps/dav/tests/travis/caldavtest/config/serverinfo.dtd b/apps/dav/tests/travis/caldavtest/config/serverinfo.dtd new file mode 100644 index 00000000000..d642f4f90cd --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/config/serverinfo.dtd @@ -0,0 +1,43 @@ +<!-- + Copyright (c) 2006-2015 Apple Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<!ELEMENT serverinfo (host, path, nonsslport, sslport, unix?, + host2?, nonsslport2?, sslport2?, unix2?, + authtype?, waitcount?, waitdelay?, waitsuccess?, + features?, substitutions)? > + + <!ELEMENT host (#PCDATA)> + <!ELEMENT path (#PCDATA)> + <!ELEMENT nonsslport (#PCDATA)> + <!ELEMENT sslport (#PCDATA)> + <!ELEMENT unix (#PCDATA)> + <!ELEMENT host2 (#PCDATA)> + <!ELEMENT nonsslport2 (#PCDATA)> + <!ELEMENT sslport2 (#PCDATA)> + <!ELEMENT unix2 (#PCDATA)> + <!ELEMENT authtype (#PCDATA)> + <!ELEMENT waitdelay (#PCDATA)> + <!ELEMENT waitcount (#PCDATA)> + <!ELEMENT waitsuccess (#PCDATA)> + <!ELEMENT features (feature*)> + <!ELEMENT feature (#PCDATA)> + <!ELEMENT substitutions (substitution|repeat)*> + <!ELEMENT repeat (substitution+)> + <!ATTLIST repeat count CDATA "1"> + <!ELEMENT substitution (key, value)> + <!ELEMENT key (#PCDATA)> + <!ELEMENT value (#PCDATA)> + diff --git a/apps/dav/tests/travis/caldavtest/config/serverinfo.xml b/apps/dav/tests/travis/caldavtest/config/serverinfo.xml new file mode 100644 index 00000000000..b85a8639e4e --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/config/serverinfo.xml @@ -0,0 +1,854 @@ +<?xml version="1.0" standalone="no"?> + +<!DOCTYPE serverinfo SYSTEM + "/home/deepdiver/Development/ownCloud/master/apps/dav/tests/travis/caldavtest/config/serverinfo.dtd"> + +<!-- + Copyright (c) 2006-2015 Apple Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<serverinfo> + <host>localhost</host> + <nonsslport>8888</nonsslport> + <authtype>basic</authtype> + <!-- <unix>/tmp/caldavd_requests/unsecured.sock</unix> --> + + <waitcount>120</waitcount> + <waitdelay>0.25</waitdelay> + <waitsuccess>30</waitsuccess> + + <features> + <!-- Generic WebDAV extensions --> + <feature>COPY Method</feature> <!-- COPY method --> + <feature>MOVE Method</feature> <!-- MOVE method --> + <feature>Extended MKCOL</feature> <!-- Extended MKCOL --> + + <!-- ACL related --> + <feature>ACL Method</feature> <!-- ACL method --> + <feature>acl-principal-prop-set REPORT</feature> <!-- ACL acl-principal-prop-set REPORT --> + <feature>principal-match REPORT</feature> <!-- ACL principal-match REPORT --> + <feature>principal-property-search REPORT</feature> <!-- ACL principal-property-search REPORT --> + <feature>principal-search-property-set REPORT</feature> <!-- ACL principal-search-property-set REPORT --> + <feature>calendarserver-principal-search REPORT</feature> <!-- ACL calendarserver-principal-search REPORT --> + + <feature>add-member</feature> <!-- Add-member used to create resources --> + <!-- <feature>auth-on-root</feature> --> <!-- Whether the server requires authentication on the root URI --> + <feature>brief</feature> <!-- Brief header for PROPFIND, REPORT --> + <feature>bulk-post</feature> <!-- Bulk POST requests --> + <feature>ctag</feature> <!-- ctag extension --> + <feature>current-user-principal</feature> <!-- current-user-principal extension --> + <feature>directory listing</feature> <!-- GET on collection --> + <feature>extended-principal-search</feature> <!-- Extended principal-property-search REPORT extension --> + <feature>expand-property</feature> <!-- Expand property REPORT --> + <feature>only-proxy-groups</feature> <!-- Group-membership only includes delegated-to groups --> + <feature>limits</feature> <!-- max-collections and max-resources limits --> + <feature>own-root</feature> <!-- / is owned by this service --> + <feature>prefer</feature> <!-- Prefer header overall support --> + <feature>prefer-minimal</feature> <!-- Prefer header return=minimal --> + <feature>prefer-representation</feature> <!-- Prefer header return=representation --> + <feature>prefer-noroot</feature> <!-- Prefer header depth-noroot --> + <feature>quota</feature> <!-- WebDAV QUOTA --> + <!-- <feature>quota-on-resources</feature> --> <!-- WebDAV QUOTA on calendar and address book object resources --> + <feature>resource-id</feature> <!-- WebDAV BIND DAV:resource-id property --> + <feature>sync-report</feature> <!-- WebDAV collection sync REPORT --> + <!-- <feature>sync-report-limit</feature> --> <!-- WebDAV collection sync REPORT DAV:limit support --> + <feature>sync-report-home</feature> <!-- WebDAV collection sync REPORT on Homes --> + <feature>sync-report-config-token</feature> <!-- Sync REPORT token includes configuration component --> + <feature>well-known</feature> <!-- well-known feature --> + + <!-- <feature>per-object-ACLs</feature> --> <!-- ACL for objects in calendar/address books --> + <!-- <feature>regular-collection</feature> --> <!-- Regular collections allowed in calendar/address book homes --> + + <feature>json-data</feature> <!-- jCal and jCard support --> + + <!-- CalendarServer specific extensions --> + <feature>control-api</feature> <!-- Control API support --> + + <!-- CalDAV specific extension --> + <feature>caldav</feature> <!-- Basic CalDAV feature enabler --> + <feature>attachments-collection</feature> <!-- Server uses a collection in same WebDAV tree to store attachments --> + <feature>auto-accept</feature> <!-- Auto-accept for rooms & locations --> + <feature>auto-accept-modes</feature> <!-- Auto-accept modes --> + <feature>client-fix-TRANSP</feature> <!-- fix client TRANSP --> + <!-- <feature>dropbox</feature> --> <!-- dropbox extension --> + <feature>default-alarms</feature> <!-- default alarms extension --> + <feature>EMAIL parameter</feature> <!-- Server normalizes cuaddress and adds EMAIL parameter --> + <feature>extended-freebusy</feature> <!-- Extended freebusy response --> + <feature>freebusy-url</feature> <!-- Freebusy URL --> + <feature>group-attendee-expansion</feature> <!-- Auto-expansion of group attendees --> + <feature>implicit-scheduling</feature> <!-- CalDAV scheduling - implicit --> + <feature>location-resource-tracking</feature> <!-- Server tracks who makes unscheduled changes to locations and resources --> + <feature>managed-attachments</feature> <!-- CalDAV Managed Attachments --> + <feature>maskuid</feature> <!-- maskuid extension --> + <feature>no-duplicate-uids</feature> <!-- duplicate UIDs in same home not supported --> + <feature>partstat-timestamp</feature> <!-- Time stamps when PARTSTAT changes extension --> + <!-- <feature>podding</feature> --> <!-- Podded server --> + <feature>private-comments</feature> <!-- private-comments extension --> + <feature>private-events</feature> <!-- private-events extension --> + <feature>proxy</feature> <!-- calendar-user-proxy extension --> + <!-- <feature>proxy-authz</feature> --> <!-- sudo user extension --> + <feature>recurrence-splitting</feature> <!-- Recurring components can be split --> + <feature>remove-duplicate-alarms</feature> <!-- Server removes any duplicate alarms on PUT --> + <feature>query-extended</feature> <!-- calendar-query-extended extension --> + <feature>shared-calendars</feature> <!-- Shared calendars extension --> + <feature>share-calendars-to-groups</feature> <!-- Share calendars to groups extension --> + <feature>schedule-changes</feature> <!-- schedule-changes property extension --> + <feature>split-calendars</feature> <!-- Calendars are split by component type --> + <feature>supported-component-sets</feature> <!-- CALDAV:supported-calendar-component-sets on calendar homes --> + <feature>supported-component-sets-one</feature> <!-- Only single component calendars allowed to be created --> + <feature>timerange-low-limit</feature> <!-- Time-range only valid one year back --> + <feature>timerange-high-limit</feature> <!-- Time-range only valid 5 years ahead --> + <feature>timezones-by-reference</feature> <!-- Timezones by reference enabled --> + <feature>timezone-service</feature> <!-- Timezone service extension for Wiki --> + <feature>timezone-std-service</feature> <!-- Timezone standard service extension --> + <!-- <feature>trash-collection</feature> --> <!-- Trash collection enabled --> + <feature>travel-time-busy</feature> <!-- Travel time appears as busy --> + <feature>vavailability</feature> <!-- VAVAILABILITY on inbox --> + <!-- <feature>vpoll</feature> --> <!-- VPOLL support for store and scheduling --> + <feature>webcal</feature> <!-- Internet calendar subscription via GET on calendar collection --> + + <!-- CardDAV specific extension --> + <feature>carddav</feature> <!-- Basic CardDAV feature enabler --> + <feature>default-addressbook</feature> <!-- Default address book behavior --> + <feature>shared-addressbooks</feature> <!-- Shared address books extension --> + <feature>shared-addressbook-groups</feature> <!-- Shared address book groups extension --> + <feature>directory-gateway</feature> <!-- Directory gateway extension --> + + </features> + + <substitutions> + <!-- Useful xpath shortcuts for verifiers --> + <substitution> + <key>$multistatus-response-prefix:</key> + <value>/{DAV:}multistatus/{DAV:}response</value> + </substitution> + <substitution> + <key>$multistatus-href-prefix:</key> + <value>/{DAV:}multistatus/{DAV:}response/{DAV:}href</value> + </substitution> + <substitution> + <key>$verify-response-prefix:</key> + <value>{DAV:}response/{DAV:}propstat/{DAV:}prop</value> + </substitution> + <substitution> + <key>$verify-property-prefix:</key> + <value>/{DAV:}multistatus/{DAV:}response/{DAV:}propstat/{DAV:}prop</value> + </substitution> + <substitution> + <key>$verify-bad-response:</key> + <value>/{DAV:}multistatus/{DAV:}response/{DAV:}status</value> + </substitution> + <substitution> + <key>$verify-error-response:</key> + <value>/{DAV:}multistatus/{DAV:}response/{DAV:}error</value> + </substitution> + <substitution> + <key>$CALDAV:</key> + <value>urn:ietf:params:xml:ns:caldav</value> + </substitution> + <substitution> + <key>$CARDDAV:</key> + <value>urn:ietf:params:xml:ns:carddav</value> + </substitution> + <substitution> + <key>$CS:</key> + <value>http://calendarserver.org/ns/</value> + </substitution> + + <!-- Server configuration settings --> + <!-- $host: and $hostssl: are implicitly added by CalDAVTester based + on the host/nonsslport/sslport values and ssl command line switch --> + + <!-- relative path to caldav root--> + <substitution> + <key>$root:</key> + <value>/remote.php/dav/</value> + </substitution> + + <!-- relative path to main principal collection--> + <substitution> + <key>$principalcollection:</key> + <value>$root:principals/</value> + </substitution> + + <!-- the core recored type collections--> + <substitution> + <key>$uidstype:</key> + <value>__uids__</value> + </substitution> + <substitution> + <key>$userstype:</key> + <value>users</value> + </substitution> + <substitution> + <key>$groupstype:</key> + <value>groups</value> + </substitution> + <substitution> + <key>$locationstype:</key> + <value>locations</value> + </substitution> + <substitution> + <key>$resourcestype:</key> + <value>resources</value> + </substitution> + + <!-- relative path to record type principal collections--> + <substitution> + <key>$principals_uids:</key> + <value>$principalcollection:$uidstype:/</value> + </substitution> + <substitution> + <key>$principals_users:</key> + <value>$principalcollection:$userstype:/</value> + </substitution> + <substitution> + <key>$principals_groups:</key> + <value>$principalcollection:$groupstype:/</value> + </substitution> + <substitution> + <key>$principals_resources:</key> + <value>$principalcollection:$resourcestype:/</value> + </substitution> + <substitution> + <key>$principals_locations:</key> + <value>$principalcollection:$locationstype:/</value> + </substitution> + + <!-- relative path to calendars collection--> + <substitution> + <key>$calendars:</key> + <value>$root:calendars/</value> + </substitution> + + <!-- relative path to record type calendar collections--> + <substitution> + <key>$calendars_uids:</key> + <value>$calendars:$uidstype:/</value> + </substitution> + <substitution> + <key>$calendars_users:</key> + <value>$calendars:$userstype:/</value> + </substitution> + <substitution> + <key>$calendars_resources:</key> + <value>$calendars:$resourcestype:/</value> + </substitution> + <substitution> + <key>$calendars_locations:</key> + <value>$calendars:$locationstype:/</value> + </substitution> + + <!-- primary calendar name--> + <substitution> + <key>$calendar:</key> + <value>calendar</value> + </substitution> + + <!-- primary tasks-only calendar name--> + <substitution> + <key>$tasks:</key> + <value>tasks</value> + </substitution> + + <!-- primary polls-only calendar name--> + <substitution> + <key>$polls:</key> + <value>polls</value> + </substitution> + + <!-- inbox name--> + <substitution> + <key>$inbox:</key> + <value>inbox</value> + </substitution> + + <!-- outbox name--> + <substitution> + <key>$outbox:</key> + <value>outbox</value> + </substitution> + + <!-- dropbox name--> + <substitution> + <key>$dropbox:</key> + <value>dropbox</value> + </substitution> + + <!-- attachments name--> + <substitution> + <key>$attachments:</key> + <value>dropbox</value> + </substitution> + + <!-- notification name--> + <substitution> + <key>$notification:</key> + <value>notification</value> + </substitution> + + <!-- freebusy name--> + <substitution> + <key>$freebusy:</key> + <value>freebusy</value> + </substitution> + + <!-- Sync home collection items - use "-" to include the home resource--> + <substitution> + <key>$calendar_home_items_initial_sync:</key> + <value>[-,$calendar:/,$tasks:/,$inbox:/,$outbox:/,$freebusy:,$notification:/]</value> + </substitution> + + <!-- Sync collection extra items - use "-" to include the collection--> + <substitution> + <key>$calendar_sync_extra_items:</key> + <value>[-]</value> + </substitution> + + <!-- Sync collection extra count - gets added to the totalcount value--> + <substitution> + <key>$calendar_sync_extra_count:</key> + <value>1</value> <!-- the request-uri resource is returned when no token passed--> + </substitution> + + <!-- server-to-server inbox--> + <substitution> + <key>$servertoserver:</key> + <value>$root:inbox</value> + </substitution> + + <!-- timezone service--> + <substitution> + <key>$timezoneservice:</key> + <value>$root:timezones</value> + </substitution> + + <!-- timezone std service--> + <substitution> + <key>$timezonestdservice:</key> + <value>$root:stdtimezones</value> + </substitution> + + <!-- relative path to addressbooks collection--> + <substitution> + <key>$addressbooks:</key> + <value>$root:addressbooks/</value> + </substitution> + + <!-- relative path to record type addressbook collections--> + <substitution> + <key>$addressbooks_uids:</key> + <value>$addressbooks:$uidstype:/</value> + </substitution> + <substitution> + <key>$addressbooks_users:</key> + <value>$addressbooks:$userstype:/</value> + </substitution> + + <!-- primary addressbook name --> + <substitution> + <key>$addressbook:</key> + <value>addressbook</value> + </substitution> + + <!-- directory name --> + <substitution> + <key>$directory:</key> + <value>$root:directory/</value> + </substitution> + + <!-- POST add-member URI suffix --> + <substitution> + <key>$add-member:</key> + <value>;add-member</value> + </substitution> + + <!-- user id for admin user --> + <substitution> + <key>$useradmin:</key> + <value>admin</value> + </substitution> + <!-- guid for admin user --> + <substitution> + <key>$useradminguid:</key> + <value>0C8BDE62-E600-4696-83D3-8B5ECABDFD2E</value> + </substitution> + <!-- password for admin user --> + <substitution> + <key>$pswdadmin:</key> + <value>admin</value> + </substitution> + + <!-- relative path to admin principal resource--> + <substitution> + <key>$principal_admin:</key> + <value>$principals_users:$useradmin:/</value> + </substitution> + <substitution> + <key>$principaluri_admin:</key> + <value>$principals_uids:$useradminguid:/</value> + </substitution> + + <!-- user id for apprentice user --> + <substitution> + <key>$userapprentice:</key> + <value>apprentice</value> + </substitution> + <!-- guid for apprentice user --> + <substitution> + <key>$userapprenticeguid:</key> + <value>29B6C503-11DF-43EC-8CCA-40C7003149CE</value> + </substitution> + <!-- password for admin user --> + <substitution> + <key>$pswdapprentice:</key> + <value>apprentice</value> + </substitution> + + <!-- relative path to apprentice principal resource--> + <substitution> + <key>$principal_apprentice:</key> + <value>$principals_users:$userapprentice:/</value> + </substitution> + <substitution> + <key>$principaluri_apprentice:</key> + <value>$principals_uids:$userapprenticeguid:/</value> + </substitution> + + <!-- user id for proxy user --> + <substitution> + <key>$userproxy:</key> + <value>superuser</value> + </substitution> + <!-- password for proxy user --> + <substitution> + <key>$pswdproxy:</key> + <value>superuser</value> + </substitution> + + <!-- Forty user accounts --> + <repeat count="40"> + <!-- user id --> + <substitution> + <key>$userid%d:</key> + <value>user%02d</value> + </substitution> + <!-- user guid --> + <substitution> + <key>$userguid%d:</key> + <value>10000000-0000-0000-0000-000000000%03d</value> + </substitution> + <!-- user name --> + <substitution> + <key>$username%d:</key> + <value>User %02d</value> + </substitution> + <!-- user name URI encoded --> + <substitution> + <key>$username-encoded%d:</key> + <value>User%%20%02d</value> + </substitution> + <!-- first name --> + <substitution> + <key>$firstname%d:</key> + <value>User</value> + </substitution> + <!-- last name --> + <substitution> + <key>$lastname%d:</key> + <value>%02d</value> + </substitution> + <!-- password --> + <substitution> + <key>$pswd%d:</key> + <value>user%02d</value> + </substitution> + <!-- relative path to user principal resource--> + <substitution> + <key>$principal%d:</key> + <value>$principals_users:$userid%d:/</value> + </substitution> + <substitution> + <key>$principaluri%d:</key> + <value>$principalcollection:$userid%d:/</value> + </substitution> + <substitution> + <key>$principal%dnoslash:</key> + <value>$principals_users:$userid%d:</value> + </substitution> + + <!-- relative path to user calendar home--> + <substitution> + <key>$calendarhome%d:</key> + <value>$calendars_uids:$userguid%d:</value> + </substitution> + <!-- relative path to user alternate calendar home--> + <substitution> + <key>$calendarhomealt%d:</key> + <value>$calendars_users:$userid%d:</value> + </substitution> + <!-- relative path to user calendar--> + <substitution> + <key>$calendarpath%d:</key> + <value>$calendarhome%d:/$calendar:</value> + </substitution> + <!-- relative path to user alternate calendar--> + <substitution> + <key>$calendarpathalt%d:</key> + <value>$calendarhomealt%d:/$calendar:</value> + </substitution> + <!-- relative path to user tasks calendar--> + <substitution> + <key>$taskspath%d:</key> + <value>$calendarhome%d:/$tasks:</value> + </substitution> + <!-- relative path to user polls calendar--> + <substitution> + <key>$pollspath%d:</key> + <value>$calendarhome%d:/$polls:</value> + </substitution> + <!-- relative path to user inbox--> + <substitution> + <key>$inboxpath%d:</key> + <value>$calendarhome%d:/$inbox:</value> + </substitution> + <!-- relative path to user outbox--> + <substitution> + <key>$outboxpath%d:</key> + <value>$calendarhome%d:/$outbox:</value> + </substitution> + <!-- relative path to user dropbox--> + <substitution> + <key>$dropboxpath%d:</key> + <value>$calendarhome%d:/$dropbox:</value> + </substitution> + <!-- relative path to user notification--> + <substitution> + <key>$notificationpath%d:</key> + <value>$calendarhome%d:/$notification:</value> + </substitution> + <!-- relative path to user freebusy--> + <substitution> + <key>$freebusypath%d:</key> + <value>$calendarhome%d:/$freebusy:</value> + </substitution> + <substitution> + <key>$email%d:</key> + <value>$userid%d:@example.com</value> + </substitution> + <!-- calendar user address of user--> + <substitution> + <key>$cuaddr%d:</key> + <value>mailto:$email%d:</value> + </substitution> + <substitution> + <key>$cuaddralt%d:</key> + <value>$cuaddr%d:</value> + </substitution> + <substitution> + <key>$cuaddraltnoslash%d:</key> + <value>$cuaddr%d:</value> + </substitution> + <substitution> + <key>$cuaddrurn%d:</key> + <value>urn:x-uid:$userguid%d:</value> + </substitution> + + <!-- relative path to user addressbook home--> + <substitution> + <key>$addressbookhome%d:</key> + <value>$addressbooks_uids:$userguid%d:</value> + </substitution> + <!-- relative path to user addressbook--> + <substitution> + <key>$addressbookpath%d:</key> + <value>$addressbookhome%d:/$addressbook:</value> + </substitution> + </repeat> + + <!-- Ten public accounts --> + <repeat count="10"> + <!-- user id --> + <substitution> + <key>$publicuserid%d:</key> + <value>public%02d</value> + </substitution> + <!-- user guid --> + <substitution> + <key>$publicuserguid%d:</key> + <value>50000000-0000-0000-0000-0000000000%02d</value> + </substitution> + <!-- user name --> + <substitution> + <key>$publicusername%d:</key> + <value>Public %02d</value> + </substitution> + <!-- password --> + <substitution> + <key>$publicpswd%d:</key> + <value>public%02d</value> + </substitution> + <!-- relative path to user principal resource--> + <substitution> + <key>$publicprincipal%d:</key> + <value>$principals_users:$publicuserid%d:/</value> + </substitution> + <substitution> + <key>$publicprincipaluri%d:</key> + <value>$principals_uids:$publicuserguid%d:/</value> + </substitution> + <!-- relative path to user calendar home--> + <substitution> + <key>$publiccalendarhome%d:</key> + <value>$calendars_uids:$publicuserguid%d:</value> + </substitution> + <!-- relative path to user calendar--> + <substitution> + <key>$publiccalendarpath%d:</key> + <value>$calendars_uids:$publicuserguid%d:/$calendar:</value> + </substitution> + <substitution> + <key>$publicemail%d:</key> + <value>$publicuserid%d:@example.com</value> + </substitution> + <!-- calendar user address of user--> + <substitution> + <key>$publiccuaddr%d:</key> + <value>mailto:$publicemail%d:</value> + </substitution> + <substitution> + <key>$publiccuaddralt%d:</key> + <value>$publiccuaddr%d:</value> + </substitution> + <substitution> + <key>$publiccuaddrurn%d:</key> + <value>urn:x-uid:$publicuserguid%d:</value> + </substitution> + </repeat> + + <!-- Twenty resource accounts --> + <repeat count="20"> + <substitution> + <key>$resourceid%d:</key> + <value>resource%02d</value> + </substitution> + <!-- resource guid--> + <substitution> + <key>$resourceguid%d:</key> + <value>40000000-0000-0000-0000-000000000%03d</value> + </substitution> + <!-- resource name--> + <substitution> + <key>$resourcename%d:</key> + <value>Resource %02d</value> + </substitution> + <!-- relative path to first resource calendar home--> + <substitution> + <key>$rcalendarhome%d:</key> + <value>$calendars_uids:$resourceguid%d:</value> + </substitution> + <!-- relative path to first resource calendar home--> + <substitution> + <key>$rcalendarpath%d:</key> + <value>$calendars_uids:$resourceguid%d:/$calendar:</value> + </substitution> + <!-- relative path to first resource inbox--> + <substitution> + <key>$rinboxpath%d:</key> + <value>$calendars_uids:$resourceguid%d:/$inbox:</value> + </substitution> + <!-- relative path to first resource outbox--> + <substitution> + <key>$routboxpath%d:</key> + <value>$calendars_uids:$resourceguid%d:/$outbox:</value> + </substitution> + <!-- relative path to first resource principal resource--> + <substitution> + <key>$rprincipal%d:</key> + <value>$principals_resources:$resourceid%d:/</value> + </substitution> + <substitution> + <key>$rprincipaluri%d:</key> + <value>$principals_uids:$resourceguid%d:/</value> + </substitution> + <substitution> + <key>$rcuaddralt%d:</key> + <value>$rcuaddrurn%d:</value> + </substitution> + <substitution> + <key>$rcuaddrurn%d:</key> + <value>urn:x-uid:$resourceguid%d:</value> + </substitution> + </repeat> + + <!-- Ten Location accounts --> + <repeat count="10"> + <substitution> + <key>$locationid%d:</key> + <value>location%02d</value> + </substitution> + <!-- location guid--> + <substitution> + <key>$locationguid%d:</key> + <value>30000000-0000-0000-0000-000000000%03d</value> + </substitution> + <!-- location name--> + <substitution> + <key>$locationname%d:</key> + <value>Location %02d</value> + </substitution> + <!-- relative path to first location calendar home--> + <substitution> + <key>$lcalendarhome%d:</key> + <value>$calendars_uids:$locationguid%d:</value> + </substitution> + <!-- relative path to first location calendar home--> + <substitution> + <key>$lcalendarpath%d:</key> + <value>$calendars_uids:$locationguid%d:/$calendar:</value> + </substitution> + <!-- relative path to first location inbox--> + <substitution> + <key>$linboxpath%d:</key> + <value>$calendars_uids:$locationguid%d:/$inbox:</value> + </substitution> + <!-- relative path to first location outbox--> + <substitution> + <key>$loutboxpath%d:</key> + <value>$calendars_uids:$locationguid%d:/$outbox:</value> + </substitution> + <!-- relative path to first location principal resource--> + <substitution> + <key>$lprincipal%d:</key> + <value>$principals_resources:$locationid%d:/</value> + </substitution> + <substitution> + <key>$lprincipaluri%d:</key> + <value>$principals_uids:$locationguid%d:/</value> + </substitution> + <substitution> + <key>$lcuaddralt%d:</key> + <value>$lprincipaluri%d:</value> + </substitution> + <substitution> + <key>$lcuaddrurn%d:</key> + <value>urn:x-uid:$locationguid%d:</value> + </substitution> + </repeat> + + + <!-- Ten Group accounts --> + <repeat count="40"> + <substitution> + <key>$groupid%d:</key> + <value>group%02d</value> + </substitution> + <!-- group guid--> + <substitution> + <key>$groupguid%d:</key> + <value>20000000-0000-0000-0000-000000000%03d</value> + </substitution> + <!-- group name--> + <substitution> + <key>$groupname%d:</key> + <value>Group %02d</value> + </substitution> + <!-- relative path to first group principal resource--> + <substitution> + <key>$gprincipal%d:</key> + <value>$principals_resources:$groupid%d:/</value> + </substitution> + <substitution> + <key>$gprincipaluri%d:</key> + <value>$principals_uids:$groupguid%d:/</value> + </substitution> + <substitution> + <key>$gemail%d:</key> + <value>$groupid%d:@example.com</value> + </substitution> + <substitution> + <key>$gcuaddralt%d:</key> + <value>$gprincipaluri%d:</value> + </substitution> + <substitution> + <key>$gcuaddrurn%d:</key> + <value>urn:x-uid:$groupguid%d:</value> + </substitution> + </repeat> + + <!-- User with non-ascii name --> + <substitution> + <key>$i18nid:</key> + <value>i18nuser</value> + </substitution> + <!-- group guid--> + <substitution> + <key>$i18nguid:</key> + <value>860B3EE9-6D7C-4296-9639-E6B998074A78</value> + </substitution> + <!-- group name--> + <substitution> + <key>$i18nname:</key> + <value>まだ</value> + </substitution> + <!-- password --> + <substitution> + <key>$i18npswd:</key> + <value>i18nuser</value> + </substitution> + <!-- relative path to user calendar--> + <substitution> + <key>$i18ncalendarpath:</key> + <value>$calendars_uids:$i18nguid:/$calendar:</value> + </substitution> + <substitution> + <key>$i18nemail:</key> + <value>$i18nid:@example.com</value> + </substitution> + <!-- CUAddrs --> + <substitution> + <key>$i18ncuaddr:</key> + <value>mailto:$i18nemail:</value> + </substitution> + <substitution> + <key>$i18ncuaddrurn:</key> + <value>urn:x-uid:$i18nguid:</value> + </substitution> + + <!-- relative path to disabled group principal resource--> + <substitution> + <key>$principaldisabled:</key> + <value>$principals_groups:disabledgroup/</value> + </substitution> + <substitution> + <key>$principaluridisabled:</key> + <value>$principals_uids:disabledgroup/</value> + </substitution> + <!-- calendar user address of disabled group--> + <substitution> + <key>$cuaddrdisabled:</key> + <value>$principals_uids:disabledgroup/</value> + </substitution> + + <!-- Override some of the above definitions for special cases --> + + <!-- calendar user address of second user--> + <substitution> + <key>$cuaddr2:</key> + <value>MAILTO:$email2:</value> + </substitution> + + </substitutions> +</serverinfo> diff --git a/apps/dav/tests/travis/caldavtest/tests/CardDAV/current-user-principal.xml b/apps/dav/tests/travis/caldavtest/tests/CardDAV/current-user-principal.xml new file mode 100644 index 00000000000..dd206bbcfb8 --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/tests/CardDAV/current-user-principal.xml @@ -0,0 +1,150 @@ +<?xml version="1.0" standalone="no"?> + +<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd"> + +<!-- + Copyright (c) 2006-2015 Apple Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<caldavtest> + <description>Test DAV:current-user-principal support</description> + + <require-feature> + <feature>carddav</feature> + </require-feature> + + <start/> + + <test-suite name='Check for the property on /'> + <require-feature> + <feature>own-root</feature> + </require-feature> + <test name='1'> + <description>Check for authenticated property on /</description> + <request> + <method>PROPFIND</method> + <ruri>$root:</ruri> + <header> + <name>Depth</name> + <value>0</value> + </header> + <data> + <content-type>text/xml; charset=utf-8</content-type> + <filepath>Resource/CardDAV/vcurrent-user-principal/1.xml</filepath> + </data> + <verify> + <callback>propfindItems</callback> + <arg> + <name>okprops</name> + <value><![CDATA[{DAV:}current-user-principal$<D:href xmlns:D="DAV:">$principaluri1:</D:href>]]></value> + </arg> + </verify> + </request> + </test> + <test name='3'> + <description>Check for authenticated property on / (user02)</description> + <request user="$userid2:" pswd="$pswd2:"> + <method>PROPFIND</method> + <ruri>$root:</ruri> + <header> + <name>Depth</name> + <value>0</value> + </header> + <data> + <content-type>text/xml; charset=utf-8</content-type> + <filepath>Resource/CardDAV/vcurrent-user-principal/1.xml</filepath> + </data> + <verify> + <callback>propfindItems</callback> + <arg> + <name>okprops</name> + <value><![CDATA[{DAV:}current-user-principal$<D:href xmlns:D="DAV:">$principaluri2:</D:href>]]></value> + </arg> + </verify> + </request> + </test> + </test-suite> + + <test-suite name='Check for the property on /principals/'> + <test name='1'> + <description>Check for authenticated property on /</description> + <request> + <method>PROPFIND</method> + <ruri>$principalcollection:</ruri> + <header> + <name>Depth</name> + <value>0</value> + </header> + <data> + <content-type>text/xml; charset=utf-8</content-type> + <filepath>Resource/CardDAV/vcurrent-user-principal/1.xml</filepath> + </data> + <verify> + <callback>propfindItems</callback> + <arg> + <name>okprops</name> + <value><![CDATA[{DAV:}current-user-principal$<D:href xmlns:D="DAV:">$principaluri1:</D:href>]]></value> + </arg> + </verify> + </request> + </test> + <test name='2'> + <description>Check for unauthenticated property on /</description> + <request auth="no"> + <method>PROPFIND</method> + <ruri>$principalcollection:</ruri> + <header> + <name>Depth</name> + <value>0</value> + </header> + <data> + <content-type>text/xml; charset=utf-8</content-type> + <filepath>Resource/CardDAV/vcurrent-user-principal/1.xml</filepath> + </data> + <verify> + <callback>statusCode</callback> + <arg> + <name>status</name> + <value>401</value> + </arg> + </verify> + </request> + </test> + <test name='3'> + <description>Check for authenticated property on / (user02)</description> + <request user="$userid2:" pswd="$pswd2:"> + <method>PROPFIND</method> + <ruri>$principalcollection:</ruri> + <header> + <name>Depth</name> + <value>0</value> + </header> + <data> + <content-type>text/xml; charset=utf-8</content-type> + <filepath>Resource/CardDAV/vcurrent-user-principal/1.xml</filepath> + </data> + <verify> + <callback>propfindItems</callback> + <arg> + <name>okprops</name> + <value><![CDATA[{DAV:}current-user-principal$<D:href xmlns:D="DAV:">$principaluri2:</D:href>]]></value> + </arg> + </verify> + </request> + </test> + </test-suite> + + <end/> +</caldavtest> diff --git a/apps/dav/tests/travis/carddavtester.sh b/apps/dav/tests/travis/carddavtester.sh new file mode 100644 index 00000000000..a128872f42a --- /dev/null +++ b/apps/dav/tests/travis/carddavtester.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +SCRIPT=`realpath $0` +SCRIPTPATH=`dirname $SCRIPT` + + +# start the server +php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../.." & + + +if [ ! -f CalDAVTester/run.py ]; then + cd "$SCRIPTPATH" + git clone https://github.com/DeepDiver1975/CalDAVTester.git + cd "$SCRIPTPATH/CalDAVTester" + python run.py -s + cd "$SCRIPTPATH" +fi + +# create test user +cd "$SCRIPTPATH/../../../../" +OC_PASS=user01 php occ user:add --password-from-env user01 +OC_PASS=user02 php occ user:add --password-from-env user02 +cd "$SCRIPTPATH/../../../../" + +# run the tests +cd "$SCRIPTPATH/CalDAVTester" +PYTHONPATH="$SCRIPTPATH/pycalendar/src" python testcaldav.py --print-details-onfail -s "$SCRIPTPATH/caldavtest/config/serverinfo.xml" -o cdt.txt \ + "$SCRIPTPATH/caldavtest/tests/CardDAV/current-user-principal.xml" + diff --git a/apps/dav/tests/unit/carddav/carddavbackendtest.php b/apps/dav/tests/unit/carddav/carddavbackendtest.php index f7456e9634c..79ef36d8097 100644 --- a/apps/dav/tests/unit/carddav/carddavbackendtest.php +++ b/apps/dav/tests/unit/carddav/carddavbackendtest.php @@ -60,6 +60,7 @@ class CardDavBackendTest extends TestCase { $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER); $this->assertEquals(1, count($books)); + $this->assertEquals('Example', $books[0]['{DAV:}displayname']); // update it's display name $patch = new PropPatch([ diff --git a/apps/files_sharing/tests/share.php b/apps/files_sharing/tests/share.php index abff820c168..896191dfe51 100644 --- a/apps/files_sharing/tests/share.php +++ b/apps/files_sharing/tests/share.php @@ -322,6 +322,22 @@ class Test_Files_Sharing extends OCA\Files_sharing\Tests\TestCase { ); } + public function testFileOwner() { + + $fileinfo = $this->view->getFileInfo($this->filename); + + $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_ALL); + + $this->assertTrue($result); + + $this->loginHelper(\Test_Files_Sharing::TEST_FILES_SHARING_API_USER2); + + $info = \OC\Files\Filesystem::getFileInfo($this->filename); + + $this->assertSame(\Test_Files_Sharing::TEST_FILES_SHARING_API_USER1, $info->getOwner()->getUID()); + } + /** * @dataProvider dataProviderGetUsersSharingFile * diff --git a/build/integration/features/bootstrap/FeatureContext.php b/build/integration/features/bootstrap/FeatureContext.php index 69fa018d0e6..4a0299d6e49 100644 --- a/build/integration/features/bootstrap/FeatureContext.php +++ b/build/integration/features/bootstrap/FeatureContext.php @@ -672,7 +672,10 @@ class FeatureContext implements Context, SnippetAcceptingContext { public function isFieldInResponse($field, $content_expected){ $data = $this->response->xml()->data[0]; foreach($data as $element) { - if ($element->$field == $content_expected){ + if ($content_expected == "A_NUMBER"){ + return is_numeric((string)$element->$field); + } + elseif ($element->$field == $content_expected){ return True; } } @@ -744,10 +747,32 @@ class FeatureContext implements Context, SnippetAcceptingContext { */ public function deletingLastShare(){ $share_id = $this->lastShareData->data[0]->id; - $url = "/apps/files_sharing/api/v{$this->apiVersion}/shares/$share_id"; + $url = "/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id"; $this->sendingToWith("DELETE", $url, null); } + /** + * @When /^Getting info of last share$/ + */ + public function gettingInfoOfLastShare(){ + $share_id = $this->lastShareData->data[0]->id; + $url = "/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id"; + $this->sendingToWith("GET", $url, null); + } + + /** + * @Then /^Share fields of last share match with$/ + * @param \Behat\Gherkin\Node\TableNode|null $formData + */ + public function checkShareFields($body){ + if ($body instanceof \Behat\Gherkin\Node\TableNode) { + $fd = $body->getRowsHash(); + foreach($fd as $field => $value) { + PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse($field, $value)); + } + } + } + public static function removeFile($path, $filename){ if (file_exists("$path" . "$filename")) { unlink("$path" . "$filename"); diff --git a/build/integration/features/sharing-v1.feature b/build/integration/features/sharing-v1.feature index b73fb39d5da..36e729d2a13 100644 --- a/build/integration/features/sharing-v1.feature +++ b/build/integration/features/sharing-v1.feature @@ -108,6 +108,33 @@ Feature: sharing And User "user2" should be included in the response And User "user3" should not be included in the response + Scenario: getting share info of a share + Given user "user0" exists + And user "user1" exists + And file "textfile0.txt" from user "user0" is shared with user "user1" + And As an "user0" + When Getting info of last share + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And Share fields of last share match with + | id | A_NUMBER | + | item_type | file | + | item_source | A_NUMBER | + | share_type | 0 | + | share_with | user1 | + | file_source | A_NUMBER | + | file_target | /textfile0.txt | + | path | /textfile0.txt | + | permissions | 23 | + | stime | A_NUMBER | + | storage | A_NUMBER | + | mail_send | 0 | + | uid_owner | user0 | + | storage_id | home::user0 | + | file_parent | A_NUMBER | + | share_with_displayname | user1 | + | displayname_owner | user0 | + Scenario: delete a share Given user "user0" exists And user "user1" exists diff --git a/lib/base.php b/lib/base.php index f44c4ff5bf2..feaf46e83f1 100644 --- a/lib/base.php +++ b/lib/base.php @@ -673,6 +673,15 @@ class OC { header('HTTP/1.1 400 Bad Request'); header('Status: 400 Bad Request'); + \OC::$server->getLogger()->warning( + 'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.', + [ + 'app' => 'core', + 'remoteAddress' => $request->getRemoteAddress(), + 'host' => $host, + ] + ); + $tmpl = new OCP\Template('core', 'untrustedDomain', 'guest'); $tmpl->assign('domain', $request->server['SERVER_NAME']); $tmpl->printPage(); diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index cf9524241dd..bb810dd45ed 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -28,6 +28,8 @@ namespace OC\Files; +use OCP\IUser; + class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { /** * @var array $data @@ -55,18 +57,25 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { private $mount; /** + * @var IUser + */ + private $owner; + + /** * @param string|boolean $path * @param Storage\Storage $storage * @param string $internalPath * @param array $data * @param \OCP\Files\Mount\IMountPoint $mount + * @param \OCP\IUser|null $owner */ - public function __construct($path, $storage, $internalPath, $data, $mount) { + public function __construct($path, $storage, $internalPath, $data, $mount, $owner= null) { $this->path = $path; $this->storage = $storage; $this->internalPath = $internalPath; $this->data = $data; $this->mount = $mount; + $this->owner = $owner; } public function offsetSet($offset, $value) { @@ -267,4 +276,13 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { public function getMountPoint() { return $this->mount; } + + /** + * Get the owner of the file + * + * @return \OCP\IUser + */ + public function getOwner() { + return $this->owner; + } } diff --git a/lib/private/files/node/node.php b/lib/private/files/node/node.php index 943d12122e6..1b52243fcb4 100644 --- a/lib/private/files/node/node.php +++ b/lib/private/files/node/node.php @@ -347,4 +347,8 @@ class Node implements \OCP\Files\Node { public function getMountPoint() { return $this->getFileInfo()->getMountPoint(); } + + public function getOwner() { + return $this->getFileInfo()->getOwner(); + } } diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 887b18530d7..7dd83588ec6 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -1250,7 +1250,8 @@ class View { $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE; } - return new FileInfo($path, $storage, $internalPath, $data, $mount); + $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath)); + return new FileInfo($path, $storage, $internalPath, $data, $mount, $owner); } /** @@ -1316,7 +1317,8 @@ class View { if (\OCP\Util::isSharingDisabledForUser()) { $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } - $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount); + $owner = \OC::$server->getUserManager()->get($storage->getOwner($content['path'])); + $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner); } //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders @@ -1385,7 +1387,8 @@ class View { $rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } - $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount); + $owner = \OC::$server->getUserManager()->get($subStorage->getOwner('')); + $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner); } } } @@ -1507,7 +1510,8 @@ class View { $internalPath = $result['path']; $path = $mountPoint . $result['path']; $result['path'] = substr($mountPoint . $result['path'], $rootLength); - $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount); + $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath)); + $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner); } } @@ -1525,7 +1529,8 @@ class View { $internalPath = $result['path']; $result['path'] = rtrim($relativeMountPoint . $result['path'], '/'); $path = rtrim($mountPoint . $internalPath, '/'); - $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount); + $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath)); + $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner); } } } @@ -1666,6 +1671,7 @@ class View { $mount = $this->getMount($path); $storage = $mount->getStorage(); $internalPath = $mount->getInternalPath($this->getAbsolutePath($path)); + $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath)); return new FileInfo( $this->getAbsolutePath($path), $storage, @@ -1680,7 +1686,8 @@ class View { 'encrypted' => false, 'permissions' => \OCP\Constants::PERMISSION_ALL ], - $mount + $mount, + $owner ); } diff --git a/lib/public/files/fileinfo.php b/lib/public/files/fileinfo.php index accbe04e044..1af13302af0 100644 --- a/lib/public/files/fileinfo.php +++ b/lib/public/files/fileinfo.php @@ -229,4 +229,12 @@ interface FileInfo { * @since 8.0.0 */ public function getMountPoint(); + + /** + * Get the owner of the file + * + * @return \OCP\IUser + * @since 9.0.0 + */ + public function getOwner(); } diff --git a/settings/templates/apps.php b/settings/templates/apps.php index 1838465f9ce..3168fd8beeb 100644 --- a/settings/templates/apps.php +++ b/settings/templates/apps.php @@ -139,7 +139,7 @@ script( </div> <div id="app-settings-content" class="apps-experimental"> - <input type="checkbox" id="enable-experimental-apps" <?php if($_['experimentalEnabled']) { print_unescaped('checked="checked"'); }?>> + <input type="checkbox" id="enable-experimental-apps" <?php if($_['experimentalEnabled']) { print_unescaped('checked="checked"'); }?> class="checkbox"> <label for="enable-experimental-apps"><?php p($l->t('Enable experimental apps')) ?></label> <p> <small> diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php index a7979146b85..f0bad5abd18 100644 --- a/tests/lib/files/view.php +++ b/tests/lib/files/view.php @@ -11,6 +11,7 @@ use OC\Files\Cache\Watcher; use OC\Files\Storage\Common; use OC\Files\Mount\MountPoint; use OC\Files\Storage\Temporary; +use OCP\Files\FileInfo; use OCP\Lock\ILockingProvider; class TemporaryNoTouch extends \OC\Files\Storage\Temporary { @@ -1560,6 +1561,7 @@ class View extends \Test\TestCase { $this->assertTrue($view->rename('mount1', 'renamed_mount'), 'Can rename mount point'); $this->assertTrue($view->rename('mount2', 'sub/moved_mount'), 'Can move a mount point into a subdirectory'); } + /** * Test that moving a mount point into another is forbidden */ @@ -1582,6 +1584,7 @@ class View extends \Test\TestCase { $this->assertFalse($view->rename('mount1', 'mount2'), 'Cannot overwrite another mount point'); $this->assertFalse($view->rename('mount1', 'mount2/sub'), 'Cannot move a mount point into another'); } + /** * Test that moving a mount point into a shared folder is forbidden */ @@ -1765,7 +1768,7 @@ class View extends \Test\TestCase { $storage->expects($this->once()) ->method($operation) ->will($this->returnCallback( - function() use ($view, $lockedPath, &$lockTypeDuring){ + function () use ($view, $lockedPath, &$lockTypeDuring) { $lockTypeDuring = $this->getFileLockType($view, $lockedPath); return true; @@ -1808,7 +1811,7 @@ class View extends \Test\TestCase { $storage->expects($this->once()) ->method('fopen') ->will($this->returnCallback( - function() use ($view, $path, &$lockTypeDuring){ + function () use ($view, $path, &$lockTypeDuring) { $lockTypeDuring = $this->getFileLockType($view, $path); return fopen('php://temp', 'r+'); @@ -1846,7 +1849,7 @@ class View extends \Test\TestCase { $storage->expects($this->once()) ->method('fopen') ->will($this->returnCallback( - function() use ($view, $path, &$lockTypeDuring){ + function () use ($view, $path, &$lockTypeDuring) { $lockTypeDuring = $this->getFileLockType($view, $path); return fopen('php://temp', 'r+'); @@ -1903,7 +1906,7 @@ class View extends \Test\TestCase { $storage->expects($this->once()) ->method($operation) ->will($this->returnCallback( - function() { + function () { throw new \Exception('Simulated exception'); } )); @@ -1993,7 +1996,7 @@ class View extends \Test\TestCase { $storage->expects($this->once()) ->method($operation) ->will($this->returnCallback( - function() use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring){ + function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) { $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath); $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath); @@ -2044,7 +2047,7 @@ class View extends \Test\TestCase { $storage->expects($this->once()) ->method('copy') ->will($this->returnCallback( - function() { + function () { throw new \Exception(); } )); @@ -2097,6 +2100,37 @@ class View extends \Test\TestCase { $view->unlockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE); } + /** + * Test rename operation: unlock first path when second path was locked + */ + public function testGetOwner() { + $this->loginAsUser('test'); + + $view = new \OC\Files\View('/test/files/'); + + $path = 'foo.txt'; + $view->file_put_contents($path, 'meh'); + + $this->assertEquals('test', $view->getFileInfo($path)->getOwner()->getUID()); + + $folderInfo = $view->getDirectoryContent(''); + $folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) { + return $info->getName() === 'foo.txt'; + })); + + $this->assertEquals('test', $folderInfo[0]->getOwner()->getUID()); + + $subStorage = new Temporary(); + \OC\Files\Filesystem::mount($subStorage, [], '/test/files/asd'); + + $folderInfo = $view->getDirectoryContent(''); + $folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) { + return $info->getName() === 'asd'; + })); + + $this->assertEquals('test', $folderInfo[0]->getOwner()->getUID()); + } + public function lockFileRenameOrCopyCrossStorageDataProvider() { return [ ['rename', 'moveFromStorage', ILockingProvider::LOCK_EXCLUSIVE], @@ -2141,7 +2175,7 @@ class View extends \Test\TestCase { $storage2->expects($this->once()) ->method($storageOperation) ->will($this->returnCallback( - function() use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring){ + function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) { $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath); $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath); @@ -2188,7 +2222,7 @@ class View extends \Test\TestCase { $mount->expects($this->once()) ->method('moveMount') ->will($this->returnCallback( - function($target) use ($mount, $view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring, &$lockTypeSharedRootDuring){ + function ($target) use ($mount, $view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring, &$lockTypeSharedRootDuring) { $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath, true); $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath, true); @@ -2253,14 +2287,14 @@ class View extends \Test\TestCase { $eventHandler->expects($this->any()) ->method('preCallback') ->will($this->returnCallback( - function() use ($view, $path, $onMountPoint, &$lockTypePre){ + function () use ($view, $path, $onMountPoint, &$lockTypePre) { $lockTypePre = $this->getFileLockType($view, $path, $onMountPoint); } )); $eventHandler->expects($this->any()) ->method('postCallback') ->will($this->returnCallback( - function() use ($view, $path, $onMountPoint, &$lockTypePost){ + function () use ($view, $path, $onMountPoint, &$lockTypePost) { $lockTypePost = $this->getFileLockType($view, $path, $onMountPoint); } )); |