aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/dav/appinfo/v1/caldav.php1
-rw-r--r--apps/dav/appinfo/v1/carddav.php1
-rw-r--r--apps/dav/lib/Command/CreateCalendar.php3
-rw-r--r--apps/dav/lib/Connector/Sabre/Principal.php6
-rw-r--r--apps/dav/lib/RootCollection.php3
-rw-r--r--apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php2
-rw-r--r--apps/dav/tests/unit/CardDAV/CardDavBackendTest.php2
-rw-r--r--apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php143
-rw-r--r--apps/files_versions/lib/AppInfo/Application.php4
-rw-r--r--apps/files_versions/lib/Storage.php61
-rw-r--r--apps/files_versions/tests/StorageTest.php116
-rw-r--r--apps/provisioning_api/l10n/ro.js8
-rw-r--r--apps/provisioning_api/l10n/ro.json6
-rw-r--r--apps/settings/l10n/pl.js2
-rw-r--r--apps/settings/l10n/pl.json2
-rw-r--r--core/Command/User/Report.php3
-rw-r--r--lib/private/Comments/Manager.php2
-rw-r--r--lib/private/Preview/Generator.php1
-rw-r--r--lib/private/Preview/Movie.php9
19 files changed, 292 insertions, 83 deletions
diff --git a/apps/dav/appinfo/v1/caldav.php b/apps/dav/appinfo/v1/caldav.php
index b1543ba3cef..28840fcef4c 100644
--- a/apps/dav/appinfo/v1/caldav.php
+++ b/apps/dav/appinfo/v1/caldav.php
@@ -52,6 +52,7 @@ $principalBackend = new Principal(
\OC::$server->query(\OCA\DAV\CalDAV\Proxy\ProxyMapper::class),
\OC::$server->get(KnownUserService::class),
\OC::$server->getConfig(),
+ \OC::$server->getL10NFactory(),
'principals/'
);
$db = \OC::$server->getDatabaseConnection();
diff --git a/apps/dav/appinfo/v1/carddav.php b/apps/dav/appinfo/v1/carddav.php
index 637ae3eed1a..53449b91c4b 100644
--- a/apps/dav/appinfo/v1/carddav.php
+++ b/apps/dav/appinfo/v1/carddav.php
@@ -55,6 +55,7 @@ $principalBackend = new Principal(
\OC::$server->query(\OCA\DAV\CalDAV\Proxy\ProxyMapper::class),
\OC::$server->get(KnownUserService::class),
\OC::$server->getConfig(),
+ \OC::$server->getL10NFactory(),
'principals/'
);
$db = \OC::$server->getDatabaseConnection();
diff --git a/apps/dav/lib/Command/CreateCalendar.php b/apps/dav/lib/Command/CreateCalendar.php
index 4d2012b0d39..1d818809245 100644
--- a/apps/dav/lib/Command/CreateCalendar.php
+++ b/apps/dav/lib/Command/CreateCalendar.php
@@ -87,7 +87,8 @@ class CreateCalendar extends Command {
\OC::$server->getAppManager(),
\OC::$server->query(ProxyMapper::class),
\OC::$server->get(KnownUserService::class),
- \OC::$server->getConfig()
+ \OC::$server->getConfig(),
+ \OC::$server->getL10NFactory(),
);
$random = \OC::$server->getSecureRandom();
$logger = \OC::$server->getLogger();
diff --git a/apps/dav/lib/Connector/Sabre/Principal.php b/apps/dav/lib/Connector/Sabre/Principal.php
index 5e81e155d74..4a422fa9628 100644
--- a/apps/dav/lib/Connector/Sabre/Principal.php
+++ b/apps/dav/lib/Connector/Sabre/Principal.php
@@ -50,6 +50,7 @@ use OCP\IGroupManager;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
+use OCP\L10N\IFactory;
use OCP\Share\IManager as IShareManager;
use Sabre\DAV\Exception;
use Sabre\DAV\PropPatch;
@@ -89,6 +90,8 @@ class Principal implements BackendInterface {
/** @var IConfig */
private $config;
+ /** @var IFactory */
+ private $languageFactory;
public function __construct(IUserManager $userManager,
IGroupManager $groupManager,
@@ -98,6 +101,7 @@ class Principal implements BackendInterface {
ProxyMapper $proxyMapper,
KnownUserService $knownUserService,
IConfig $config,
+ IFactory $languageFactory,
string $principalPrefix = 'principals/users/') {
$this->userManager = $userManager;
$this->groupManager = $groupManager;
@@ -109,6 +113,7 @@ class Principal implements BackendInterface {
$this->proxyMapper = $proxyMapper;
$this->knownUserService = $knownUserService;
$this->config = $config;
+ $this->languageFactory = $languageFactory;
}
use PrincipalProxyTrait {
@@ -508,6 +513,7 @@ class Principal implements BackendInterface {
'uri' => $this->principalPrefix . '/' . $userId,
'{DAV:}displayname' => is_null($displayName) ? $userId : $displayName,
'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
+ '{http://nextcloud.com/ns}language' => $this->languageFactory->getUserLanguage($user),
];
$email = $user->getEMailAddress();
diff --git a/apps/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php
index aa81d2ff222..8d921414d51 100644
--- a/apps/dav/lib/RootCollection.php
+++ b/apps/dav/lib/RootCollection.php
@@ -73,7 +73,8 @@ class RootCollection extends SimpleCollection {
\OC::$server->getAppManager(),
$proxyMapper,
\OC::$server->get(KnownUserService::class),
- \OC::$server->getConfig()
+ \OC::$server->getConfig(),
+ \OC::$server->getL10NFactory()
);
$groupPrincipalBackend = new GroupPrincipalBackend($groupManager, $userSession, $shareManager, $config);
$calendarResourcePrincipalBackend = new ResourcePrincipalBackend($db, $userSession, $groupManager, $logger, $proxyMapper);
diff --git a/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php b/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php
index 94e099f523e..c659e2ccc6d 100644
--- a/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php
+++ b/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php
@@ -37,6 +37,7 @@ use OCP\IGroupManager;
use OCP\ILogger;
use OCP\IUserManager;
use OCP\IUserSession;
+use OCP\L10N\IFactory;
use OCP\Security\ISecureRandom;
use OCP\Share\IManager as ShareManager;
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
@@ -94,6 +95,7 @@ abstract class AbstractCalDavBackend extends TestCase {
$this->createMock(ProxyMapper::class),
$this->createMock(KnownUserService::class),
$this->createMock(IConfig::class),
+ $this->createMock(IFactory::class)
])
->setMethods(['getPrincipalByPath', 'getGroupMembership'])
->getMock();
diff --git a/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php b/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php
index fb9522519a5..7eda691d199 100644
--- a/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php
+++ b/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php
@@ -46,6 +46,7 @@ use OCP\IGroupManager;
use OCP\IL10N;
use OCP\IUserManager;
use OCP\IUserSession;
+use OCP\L10N\IFactory;
use OCP\Share\IManager as ShareManager;
use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\PropPatch;
@@ -141,6 +142,7 @@ class CardDavBackendTest extends TestCase {
$this->createMock(ProxyMapper::class),
$this->createMock(KnownUserService::class),
$this->createMock(IConfig::class),
+ $this->createMock(IFactory::class)
])
->setMethods(['getPrincipalByPath', 'getGroupMembership'])
->getMock();
diff --git a/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php b/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php
index acaa82dca8b..ba65edf2dd1 100644
--- a/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php
+++ b/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php
@@ -33,6 +33,7 @@ use OC\KnownUser\KnownUserService;
use OC\User\User;
use OCA\DAV\CalDAV\Proxy\Proxy;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
+use OCA\DAV\Connector\Sabre\Principal;
use OCP\App\IAppManager;
use OCP\IConfig;
use OCP\IGroup;
@@ -40,38 +41,42 @@ use OCP\IGroupManager;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
+use OCP\L10N\IFactory;
use OCP\Share\IManager;
use PHPUnit\Framework\MockObject\MockObject;
+use Sabre\DAV\Exception;
use Sabre\DAV\PropPatch;
use Test\TestCase;
class PrincipalTest extends TestCase {
- /** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject */
+ /** @var IUserManager | MockObject */
private $userManager;
- /** @var \OCA\DAV\Connector\Sabre\Principal */
+ /** @var Principal */
private $connector;
- /** @var IGroupManager | \PHPUnit\Framework\MockObject\MockObject */
+ /** @var IGroupManager | MockObject */
private $groupManager;
- /** @var IManager | \PHPUnit\Framework\MockObject\MockObject */
+ /** @var IManager | MockObject */
private $shareManager;
- /** @var IUserSession | \PHPUnit\Framework\MockObject\MockObject */
+ /** @var IUserSession | MockObject */
private $userSession;
- /** @var IAppManager | \PHPUnit\Framework\MockObject\MockObject */
+ /** @var IAppManager | MockObject */
private $appManager;
- /** @var ProxyMapper | \PHPUnit\Framework\MockObject\MockObject */
+ /** @var ProxyMapper | MockObject */
private $proxyMapper;
/** @var KnownUserService|MockObject */
private $knownUserService;
- /** @var IConfig | \PHPUnit\Framework\MockObject\MockObject */
+ /** @var IConfig | MockObject */
private $config;
+ /** @var IFactory|MockObject */
+ private $languageFactory;
protected function setUp(): void {
$this->userManager = $this->createMock(IUserManager::class);
@@ -82,8 +87,9 @@ class PrincipalTest extends TestCase {
$this->proxyMapper = $this->createMock(ProxyMapper::class);
$this->knownUserService = $this->createMock(KnownUserService::class);
$this->config = $this->createMock(IConfig::class);
+ $this->languageFactory = $this->createMock(IFactory::class);
- $this->connector = new \OCA\DAV\Connector\Sabre\Principal(
+ $this->connector = new Principal(
$this->userManager,
$this->groupManager,
$this->shareManager,
@@ -91,37 +97,38 @@ class PrincipalTest extends TestCase {
$this->appManager,
$this->proxyMapper,
$this->knownUserService,
- $this->config
+ $this->config,
+ $this->languageFactory
);
parent::setUp();
}
- public function testGetPrincipalsByPrefixWithoutPrefix() {
+ public function testGetPrincipalsByPrefixWithoutPrefix(): void {
$response = $this->connector->getPrincipalsByPrefix('');
$this->assertSame([], $response);
}
- public function testGetPrincipalsByPrefixWithUsers() {
+ public function testGetPrincipalsByPrefixWithUsers(): void {
$fooUser = $this->createMock(User::class);
$fooUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getUID')
->willReturn('foo');
$fooUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getDisplayName')
->willReturn('Dr. Foo-Bar');
$fooUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getEMailAddress')
->willReturn('');
$barUser = $this->createMock(User::class);
$barUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getUID')
->willReturn('bar');
$barUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getEMailAddress')
->willReturn('bar@nextcloud.com');
$this->userManager
@@ -130,16 +137,24 @@ class PrincipalTest extends TestCase {
->with('')
->willReturn([$fooUser, $barUser]);
+ $this->languageFactory
+ ->expects($this->exactly(2))
+ ->method('getUserLanguage')
+ ->withConsecutive([$fooUser], [$barUser])
+ ->willReturnOnConsecutiveCalls('de', 'en');
+
$expectedResponse = [
0 => [
'uri' => 'principals/users/foo',
'{DAV:}displayname' => 'Dr. Foo-Bar',
'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
+ '{http://nextcloud.com/ns}language' => 'de',
],
1 => [
'uri' => 'principals/users/bar',
'{DAV:}displayname' => 'bar',
'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
+ '{http://nextcloud.com/ns}language' => 'en',
'{http://sabredav.org/ns}email-address' => 'bar@nextcloud.com',
]
];
@@ -147,7 +162,7 @@ class PrincipalTest extends TestCase {
$this->assertSame($expectedResponse, $response);
}
- public function testGetPrincipalsByPrefixEmpty() {
+ public function testGetPrincipalsByPrefixEmpty(): void {
$this->userManager
->expects($this->once())
->method('search')
@@ -158,10 +173,10 @@ class PrincipalTest extends TestCase {
$this->assertSame([], $response);
}
- public function testGetPrincipalsByPathWithoutMail() {
+ public function testGetPrincipalsByPathWithoutMail(): void {
$fooUser = $this->createMock(User::class);
$fooUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getUID')
->willReturn('foo');
$this->userManager
@@ -170,23 +185,30 @@ class PrincipalTest extends TestCase {
->with('foo')
->willReturn($fooUser);
+ $this->languageFactory
+ ->expects($this->once())
+ ->method('getUserLanguage')
+ ->with($fooUser)
+ ->willReturn('de');
+
$expectedResponse = [
'uri' => 'principals/users/foo',
'{DAV:}displayname' => 'foo',
'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
+ '{http://nextcloud.com/ns}language' => 'de'
];
$response = $this->connector->getPrincipalByPath('principals/users/foo');
$this->assertSame($expectedResponse, $response);
}
- public function testGetPrincipalsByPathWithMail() {
+ public function testGetPrincipalsByPathWithMail(): void {
$fooUser = $this->createMock(User::class);
$fooUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getEMailAddress')
->willReturn('foo@nextcloud.com');
$fooUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getUID')
->willReturn('foo');
$this->userManager
@@ -195,17 +217,24 @@ class PrincipalTest extends TestCase {
->with('foo')
->willReturn($fooUser);
+ $this->languageFactory
+ ->expects($this->once())
+ ->method('getUserLanguage')
+ ->with($fooUser)
+ ->willReturn('de');
+
$expectedResponse = [
'uri' => 'principals/users/foo',
'{DAV:}displayname' => 'foo',
'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
+ '{http://nextcloud.com/ns}language' => 'de',
'{http://sabredav.org/ns}email-address' => 'foo@nextcloud.com',
];
$response = $this->connector->getPrincipalByPath('principals/users/foo');
$this->assertSame($expectedResponse, $response);
}
- public function testGetPrincipalsByPathEmpty() {
+ public function testGetPrincipalsByPathEmpty(): void {
$this->userManager
->expects($this->once())
->method('get')
@@ -213,17 +242,17 @@ class PrincipalTest extends TestCase {
->willReturn(null);
$response = $this->connector->getPrincipalByPath('principals/users/foo');
- $this->assertSame(null, $response);
+ $this->assertNull($response);
}
- public function testGetGroupMemberSet() {
+ public function testGetGroupMemberSet(): void {
$response = $this->connector->getGroupMemberSet('principals/users/foo');
$this->assertSame([], $response);
}
- public function testGetGroupMemberSetEmpty() {
- $this->expectException(\Sabre\DAV\Exception::class);
+ public function testGetGroupMemberSetEmpty(): void {
+ $this->expectException(Exception::class);
$this->expectExceptionMessage('Principal not found');
$this->userManager
@@ -235,10 +264,10 @@ class PrincipalTest extends TestCase {
$this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-read');
}
- public function testGetGroupMemberSetProxyRead() {
+ public function testGetGroupMemberSetProxyRead(): void {
$fooUser = $this->createMock(User::class);
$fooUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getUID')
->willReturn('foo');
$this->userManager
@@ -267,10 +296,10 @@ class PrincipalTest extends TestCase {
$this->assertEquals(['proxyId1'], $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-read'));
}
- public function testGetGroupMemberSetProxyWrite() {
+ public function testGetGroupMemberSetProxyWrite(): void {
$fooUser = $this->createMock(User::class);
$fooUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getUID')
->willReturn('foo');
$this->userManager
@@ -299,7 +328,7 @@ class PrincipalTest extends TestCase {
$this->assertEquals(['proxyId2', 'proxyId3'], $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-write'));
}
- public function testGetGroupMembership() {
+ public function testGetGroupMembership(): void {
$fooUser = $this->createMock(User::class);
$group1 = $this->createMock(IGroup::class);
$group1->expects($this->once())
@@ -347,8 +376,8 @@ class PrincipalTest extends TestCase {
}
- public function testGetGroupMembershipEmpty() {
- $this->expectException(\Sabre\DAV\Exception::class);
+ public function testGetGroupMembershipEmpty(): void {
+ $this->expectException(Exception::class);
$this->expectExceptionMessage('Principal not found');
$this->userManager
@@ -361,22 +390,22 @@ class PrincipalTest extends TestCase {
}
- public function testSetGroupMembership() {
- $this->expectException(\Sabre\DAV\Exception::class);
+ public function testSetGroupMembership(): void {
+ $this->expectException(Exception::class);
$this->expectExceptionMessage('Setting members of the group is not supported yet');
$this->connector->setGroupMemberSet('principals/users/foo', ['foo']);
}
- public function testSetGroupMembershipProxy() {
+ public function testSetGroupMembershipProxy(): void {
$fooUser = $this->createMock(User::class);
$fooUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getUID')
->willReturn('foo');
$barUser = $this->createMock(User::class);
$barUser
- ->expects($this->exactly(1))
+ ->expects($this->once())
->method('getUID')
->willReturn('bar');
$this->userManager
@@ -415,15 +444,15 @@ class PrincipalTest extends TestCase {
$this->connector->setGroupMemberSet('principals/users/foo/calendar-proxy-write', ['principals/users/bar']);
}
- public function testUpdatePrincipal() {
+ public function testUpdatePrincipal(): void {
$this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch([])));
}
- public function testSearchPrincipalsWithEmptySearchProperties() {
+ public function testSearchPrincipalsWithEmptySearchProperties(): void {
$this->assertSame([], $this->connector->searchPrincipals('principals/users', []));
}
- public function testSearchPrincipalsWithWrongPrefixPath() {
+ public function testSearchPrincipalsWithWrongPrefixPath(): void {
$this->assertSame([], $this->connector->searchPrincipals('principals/groups',
['{http://sabredav.org/ns}email-address' => 'foo']));
}
@@ -431,7 +460,7 @@ class PrincipalTest extends TestCase {
/**
* @dataProvider searchPrincipalsDataProvider
*/
- public function testSearchPrincipals($sharingEnabled, $groupsOnly, $test, $result) {
+ public function testSearchPrincipals($sharingEnabled, $groupsOnly, $test, $result): void {
$this->shareManager->expects($this->once())
->method('shareAPIEnabled')
->willReturn($sharingEnabled);
@@ -515,7 +544,7 @@ class PrincipalTest extends TestCase {
'{DAV:}displayname' => 'User 12'], $test));
}
- public function searchPrincipalsDataProvider() {
+ public function searchPrincipalsDataProvider(): array {
return [
[true, false, 'allof', ['principals/users/user3']],
[true, false, 'anyof', ['principals/users/user2', 'principals/users/user3', 'principals/users/user4']],
@@ -526,7 +555,7 @@ class PrincipalTest extends TestCase {
];
}
- public function testSearchPrincipalByCalendarUserAddressSet() {
+ public function testSearchPrincipalByCalendarUserAddressSet(): void {
$this->shareManager->expects($this->exactly(2))
->method('shareAPIEnabled')
->willReturn(true);
@@ -556,7 +585,7 @@ class PrincipalTest extends TestCase {
['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set' => 'user@example.com']));
}
- public function testSearchPrincipalWithEnumerationDisabledDisplayname() {
+ public function testSearchPrincipalWithEnumerationDisabledDisplayname(): void {
$this->shareManager->expects($this->once())
->method('shareAPIEnabled')
->willReturn(true);
@@ -595,7 +624,7 @@ class PrincipalTest extends TestCase {
['{DAV:}displayname' => 'User 2']));
}
- public function testSearchPrincipalWithEnumerationDisabledDisplaynameOnFullMatch() {
+ public function testSearchPrincipalWithEnumerationDisabledDisplaynameOnFullMatch(): void {
$this->shareManager->expects($this->once())
->method('shareAPIEnabled')
->willReturn(true);
@@ -616,7 +645,7 @@ class PrincipalTest extends TestCase {
['{DAV:}displayname' => 'User 2']));
}
- public function testSearchPrincipalWithEnumerationDisabledEmail() {
+ public function testSearchPrincipalWithEnumerationDisabledEmail(): void {
$this->shareManager->expects($this->once())
->method('shareAPIEnabled')
->willReturn(true);
@@ -655,7 +684,7 @@ class PrincipalTest extends TestCase {
['{http://sabredav.org/ns}email-address' => 'user2@foo.bar']));
}
- public function testSearchPrincipalWithEnumerationDisabledEmailOnFullMatch() {
+ public function testSearchPrincipalWithEnumerationDisabledEmailOnFullMatch(): void {
$this->shareManager->expects($this->once())
->method('shareAPIEnabled')
->willReturn(true);
@@ -677,7 +706,7 @@ class PrincipalTest extends TestCase {
['{http://sabredav.org/ns}email-address' => 'user2@foo.bar']));
}
- public function testSearchPrincipalWithEnumerationLimitedDisplayname() {
+ public function testSearchPrincipalWithEnumerationLimitedDisplayname(): void {
$this->shareManager->expects($this->at(0))
->method('shareAPIEnabled')
->willReturn(true);
@@ -738,7 +767,7 @@ class PrincipalTest extends TestCase {
['{DAV:}displayname' => 'User']));
}
- public function testSearchPrincipalWithEnumerationLimitedMail() {
+ public function testSearchPrincipalWithEnumerationLimitedMail(): void {
$this->shareManager->expects($this->at(0))
->method('shareAPIEnabled')
->willReturn(true);
@@ -799,7 +828,7 @@ class PrincipalTest extends TestCase {
['{http://sabredav.org/ns}email-address' => 'user']));
}
- public function testFindByUriSharingApiDisabled() {
+ public function testFindByUriSharingApiDisabled(): void {
$this->shareManager->expects($this->once())
->method('shareApiEnabled')
->willReturn(false);
@@ -810,7 +839,7 @@ class PrincipalTest extends TestCase {
/**
* @dataProvider findByUriWithGroupRestrictionDataProvider
*/
- public function testFindByUriWithGroupRestriction($uri, $email, $expects) {
+ public function testFindByUriWithGroupRestriction($uri, $email, $expects): void {
$this->shareManager->expects($this->once())
->method('shareApiEnabled')
->willReturn(true);
@@ -854,7 +883,7 @@ class PrincipalTest extends TestCase {
$this->assertEquals($expects, $this->connector->findByUri($uri, 'principals/users'));
}
- public function findByUriWithGroupRestrictionDataProvider() {
+ public function findByUriWithGroupRestrictionDataProvider(): array {
return [
['mailto:user2@foo.bar', 'user2@foo.bar', 'principals/users/user2'],
['mailto:user3@foo.bar', 'user3@foo.bar', null],
@@ -864,7 +893,7 @@ class PrincipalTest extends TestCase {
/**
* @dataProvider findByUriWithoutGroupRestrictionDataProvider
*/
- public function testFindByUriWithoutGroupRestriction($uri, $email, $expects) {
+ public function testFindByUriWithoutGroupRestriction($uri, $email, $expects): void {
$this->shareManager->expects($this->once())
->method('shareApiEnabled')
->willReturn(true);
@@ -886,7 +915,7 @@ class PrincipalTest extends TestCase {
$this->assertEquals($expects, $this->connector->findByUri($uri, 'principals/users'));
}
- public function findByUriWithoutGroupRestrictionDataProvider() {
+ public function findByUriWithoutGroupRestrictionDataProvider(): array {
return [
['mailto:user2@foo.bar', 'user2@foo.bar', 'principals/users/user2'],
['mailto:user3@foo.bar', 'user3@foo.bar', 'principals/users/user3'],
diff --git a/apps/files_versions/lib/AppInfo/Application.php b/apps/files_versions/lib/AppInfo/Application.php
index f0d182043c1..c994cd2f54a 100644
--- a/apps/files_versions/lib/AppInfo/Application.php
+++ b/apps/files_versions/lib/AppInfo/Application.php
@@ -48,6 +48,7 @@ use OCP\IGroupManager;
use OCP\IServerContainer;
use OCP\IUserManager;
use OCP\IUserSession;
+use OCP\L10N\IFactory;
use OCP\Share\IManager as IShareManager;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
@@ -79,7 +80,8 @@ class Application extends App implements IBootstrap {
$server->get(IAppManager::class),
$server->get(ProxyMapper::class),
$server->get(KnownUserService::class),
- $server->get(IConfig::class)
+ $server->get(IConfig::class),
+ $server->get(IFactory::class),
);
});
diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php
index 374b5f412ae..a6674ab244b 100644
--- a/apps/files_versions/lib/Storage.php
+++ b/apps/files_versions/lib/Storage.php
@@ -37,8 +37,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
+
namespace OCA\Files_Versions;
+use OC\Files\Search\SearchBinaryOperator;
+use OC\Files\Search\SearchComparison;
+use OC\Files\Search\SearchQuery;
use OC_User;
use OC\Files\Filesystem;
use OC\Files\View;
@@ -46,11 +50,16 @@ use OCA\Files_Versions\AppInfo\Application;
use OCA\Files_Versions\Command\Expire;
use OCA\Files_Versions\Events\CreateVersionEvent;
use OCA\Files_Versions\Versions\IVersionManager;
+use OCP\Files\FileInfo;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\Node;
use OCP\Command\IBus;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\IMimeTypeDetector;
-use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
+use OCP\Files\Search\ISearchBinaryOperator;
+use OCP\Files\Search\ISearchComparison;
use OCP\Files\StorageNotAvailableException;
use OCP\IURLGenerator;
use OCP\IUser;
@@ -495,38 +504,54 @@ class Storage {
/**
* Expire versions that older than max version retention time
+ *
* @param string $uid
*/
public static function expireOlderThanMaxForUser($uid) {
+ /** @var IRootFolder $root */
+ $root = \OC::$server->get(IRootFolder::class);
+ try {
+ /** @var Folder $versionsRoot */
+ $versionsRoot = $root->get('/' . $uid . '/files_versions');
+ } catch (NotFoundException $e) {
+ return;
+ }
+
$expiration = self::getExpiration();
$threshold = $expiration->getMaxAgeAsTimestamp();
- $versions = self::getAllVersions($uid);
- if (!$threshold || empty($versions['all'])) {
+ if (!$threshold) {
return;
}
- $toDelete = [];
- foreach (array_reverse($versions['all']) as $key => $version) {
- if ((int)$version['version'] < $threshold) {
- $toDelete[$key] = $version;
- } else {
- //Versions are sorted by time - nothing mo to iterate.
- break;
- }
- }
+ $allVersions = $versionsRoot->search(new SearchQuery(
+ new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [
+ new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', FileInfo::MIMETYPE_FOLDER),
+ ]),
+ 0,
+ 0,
+ []
+ ));
- $view = new View('/' . $uid . '/files_versions');
- if (!empty($toDelete)) {
- foreach ($toDelete as $version) {
- \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $version['path'].'.v'.$version['version'], 'trigger' => self::DELETE_TRIGGER_RETENTION_CONSTRAINT]);
- self::deleteVersion($view, $version['path'] . '.v' . $version['version']);
- \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $version['path'].'.v'.$version['version'], 'trigger' => self::DELETE_TRIGGER_RETENTION_CONSTRAINT]);
+ /** @var Node[] $versions */
+ $versions = array_filter($allVersions, function (Node $info) use ($threshold) {
+ $versionsBegin = strrpos($info->getName(), '.v');
+ if ($versionsBegin === false) {
+ return false;
}
+ $version = (int)substr($info->getName(), $versionsBegin + 2);
+ return $version < $threshold;
+ });
+
+ foreach ($versions as $version) {
+ \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $version->getInternalPath(), 'trigger' => self::DELETE_TRIGGER_RETENTION_CONSTRAINT]);
+ $version->delete();
+ \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $version->getInternalPath(), 'trigger' => self::DELETE_TRIGGER_RETENTION_CONSTRAINT]);
}
}
/**
* translate a timestamp into a string like "5 days ago"
+ *
* @param int $timestamp
* @return string for example "5 days ago"
*/
diff --git a/apps/files_versions/tests/StorageTest.php b/apps/files_versions/tests/StorageTest.php
new file mode 100644
index 00000000000..d16b9ecdfd8
--- /dev/null
+++ b/apps/files_versions/tests/StorageTest.php
@@ -0,0 +1,116 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2021 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\files_versions\tests;
+
+use OCA\Files_Versions\Expiration;
+use OCA\Files_Versions\Hooks;
+use OCA\Files_Versions\Storage;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use Test\TestCase;
+use Test\Traits\UserTrait;
+
+/**
+ * @group DB
+ */
+class StorageTest extends TestCase {
+ use UserTrait;
+
+ private $versionsRoot;
+ private $userFolder;
+ private $expireTimestamp = 10;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $expiration = $this->createMock(Expiration::class);
+ $expiration->method('getMaxAgeAsTimestamp')
+ ->willReturnCallback(function () {
+ return $this->expireTimestamp;
+ });
+ $this->overwriteService(Expiration::class, $expiration);
+
+ Hooks::connectHooks();
+
+ $this->createUser('version_test', '');
+ $this->loginAsUser('version_test');
+ /** @var IRootFolder $root */
+ $root = \OC::$server->get(IRootFolder::class);
+ $this->userFolder = $root->getUserFolder('version_test');
+ }
+
+
+ protected function createPastFile(string $path, int $mtime) {
+ try {
+ $file = $this->userFolder->get($path);
+ } catch (NotFoundException $e) {
+ $file = $this->userFolder->newFile($path);
+ }
+ $file->putContent((string)$mtime);
+ $file->touch($mtime);
+ }
+
+ public function testExpireMaxAge() {
+ $this->userFolder->newFolder('folder1');
+ $this->userFolder->newFolder('folder1/sub1');
+ $this->userFolder->newFolder('folder2');
+
+ $this->createPastFile('file1', 100);
+ $this->createPastFile('file1', 500);
+ $this->createPastFile('file1', 900);
+
+ $this->createPastFile('folder1/file2', 100);
+ $this->createPastFile('folder1/file2', 200);
+ $this->createPastFile('folder1/file2', 300);
+
+ $this->createPastFile('folder1/sub1/file3', 400);
+ $this->createPastFile('folder1/sub1/file3', 500);
+ $this->createPastFile('folder1/sub1/file3', 600);
+
+ $this->createPastFile('folder2/file4', 100);
+ $this->createPastFile('folder2/file4', 600);
+ $this->createPastFile('folder2/file4', 800);
+
+ $this->assertCount(2, Storage::getVersions('version_test', 'file1'));
+ $this->assertCount(2, Storage::getVersions('version_test', 'folder1/file2'));
+ $this->assertCount(2, Storage::getVersions('version_test', 'folder1/sub1/file3'));
+ $this->assertCount(2, Storage::getVersions('version_test', 'folder2/file4'));
+
+ $this->expireTimestamp = 150;
+ Storage::expireOlderThanMaxForUser('version_test');
+
+ $this->assertCount(1, Storage::getVersions('version_test', 'file1'));
+ $this->assertCount(1, Storage::getVersions('version_test', 'folder1/file2'));
+ $this->assertCount(2, Storage::getVersions('version_test', 'folder1/sub1/file3'));
+ $this->assertCount(1, Storage::getVersions('version_test', 'folder2/file4'));
+
+ $this->expireTimestamp = 550;
+ Storage::expireOlderThanMaxForUser('version_test');
+
+ $this->assertCount(0, Storage::getVersions('version_test', 'file1'));
+ $this->assertCount(0, Storage::getVersions('version_test', 'folder1/file2'));
+ $this->assertCount(0, Storage::getVersions('version_test', 'folder1/sub1/file3'));
+ $this->assertCount(1, Storage::getVersions('version_test', 'folder2/file4'));
+ }
+}
diff --git a/apps/provisioning_api/l10n/ro.js b/apps/provisioning_api/l10n/ro.js
new file mode 100644
index 00000000000..27c147485f2
--- /dev/null
+++ b/apps/provisioning_api/l10n/ro.js
@@ -0,0 +1,8 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Provisioning API" : "API de provizionare",
+ "This application enables a set of APIs that external systems can use to manage users, groups and apps." : "Această aplicație pornește un set de API-uri ce pot fi folosite de systemele externe pentru a gestiona utilizatori, grupuri și aplicații. ",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query user\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin users\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Această aplicație permite unui set de API-uri ce pot fi folosite de sustemele externe pentru a creea, edita, șterge și a interoga utilizatori\n\t\tatribute, interogare, setare și eliminare grupuri, setare cote și interogare stocare totală utilizată în Nextcloud. Utilizatorii grupului admin\n\t\tpot de asemenea iteroga Nextcloud și îndeplini aceleași funcții ca și grupul de admini pe care îi și gestionează. API-ul permite \n\t\tunui administrator să caute aplicații active Nextcloud, informații despre aplicații și informații legate de activarea sau dezactivarea unei aplicații de la distanță.\n\t\tOdată ce aplicația este activată, solicitările HTTP pot fi utilizate printr-un antet Basic Auth pentru a efectua oricare dintre funcțiile\n\t\tmenționate mai sus. Mai multe informații sunt prezente în documentatie de provizionare de API, inclusiv exemple de interogări\n\t\tși răspunsul primit de la server."
+},
+"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));");
diff --git a/apps/provisioning_api/l10n/ro.json b/apps/provisioning_api/l10n/ro.json
new file mode 100644
index 00000000000..7fdcd734afb
--- /dev/null
+++ b/apps/provisioning_api/l10n/ro.json
@@ -0,0 +1,6 @@
+{ "translations": {
+ "Provisioning API" : "API de provizionare",
+ "This application enables a set of APIs that external systems can use to manage users, groups and apps." : "Această aplicație pornește un set de API-uri ce pot fi folosite de systemele externe pentru a gestiona utilizatori, grupuri și aplicații. ",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query user\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin users\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Această aplicație permite unui set de API-uri ce pot fi folosite de sustemele externe pentru a creea, edita, șterge și a interoga utilizatori\n\t\tatribute, interogare, setare și eliminare grupuri, setare cote și interogare stocare totală utilizată în Nextcloud. Utilizatorii grupului admin\n\t\tpot de asemenea iteroga Nextcloud și îndeplini aceleași funcții ca și grupul de admini pe care îi și gestionează. API-ul permite \n\t\tunui administrator să caute aplicații active Nextcloud, informații despre aplicații și informații legate de activarea sau dezactivarea unei aplicații de la distanță.\n\t\tOdată ce aplicația este activată, solicitările HTTP pot fi utilizate printr-un antet Basic Auth pentru a efectua oricare dintre funcțiile\n\t\tmenționate mai sus. Mai multe informații sunt prezente în documentatie de provizionare de API, inclusiv exemple de interogări\n\t\tși răspunsul primit de la server."
+},"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"
+} \ No newline at end of file
diff --git a/apps/settings/l10n/pl.js b/apps/settings/l10n/pl.js
index 471fd30edf0..396d49afa9b 100644
--- a/apps/settings/l10n/pl.js
+++ b/apps/settings/l10n/pl.js
@@ -130,7 +130,7 @@ OC.L10N.register(
"There are some user imported SSL certificates present, that are not used anymore with Nextcloud 21. They can be imported on the command line via \"occ security:certificates:import\" command. Their paths inside the data directory are shown below." : "Istnieją pewne certyfikaty SSL zaimportowane przez użytkownika, które nie są już używane z Nextcloud 21. Można je zaimportować z wiersza poleceń za pomocą polecenia \"occ security:certificates:import\". Ich ścieżki w katalogu danych są pokazane poniżej.",
"The old server-side-encryption format is enabled. We recommend disabling this." : "Stary format szyfrowania po stronie serwera jest włączony. Zalecamy wyłączenie jego.",
"MariaDB version \"%s\" is used. Nextcloud 21 will no longer support this version and requires MariaDB 10.2 or higher." : "Używana jest MariaDB w wersji \"%s\". Nextcloud 21 nie będzie już obsługiwać tej wersji i wymagać będzie MariaDB 10.2 lub nowszej.",
- "MySQL version \"%s\" is used. Nextcloud 21 will no longer support this version and requires MySQL 8.0 or MariaDB 10.2 or higher." : "Używana jest MySQL w wersji \"%s\". Nextcloud 21 nie będzie już obsługiwać tej wersji i wymagać będzie MySQL 8.0 lub MariaDB 10.2, lub nowszej.",
+ "MySQL version \"%s\" is used. Nextcloud 21 will no longer support this version and requires MySQL 8.0 or MariaDB 10.2 or higher." : "Używana jest MySQL w wersji \"%s\". Nextcloud 21 nie będzie już obsługiwać tej wersji i wymagać będzie MySQL 8.0 lub MariaDB 10.2, albo nowszej.",
"PostgreSQL version \"%s\" is used. Nextcloud 21 will no longer support this version and requires PostgreSQL 9.6 or higher." : "Używana jest PostgreSQL w wersji \"%s\". Nextcloud 21 nie będzie już obsługiwał tej wersji i wymagać będzie PostgreSQL 9.6 lub nowszego.",
"Nextcloud settings" : "Ustawienia Nextcloud",
"Two-factor authentication can be enforced for all users and specific groups. If they do not have a two-factor provider configured, they will be unable to log into the system." : "Uwierzytelnianie dwuskładnikowe może być wymuszane dla wszystkich użytkowników i określonych grup. Jeśli nie mają skonfigurowanego dostawcy logowania dwuskładnikowego, nie będą mogli zalogować się do systemu.",
diff --git a/apps/settings/l10n/pl.json b/apps/settings/l10n/pl.json
index b81bab68c80..b802217237f 100644
--- a/apps/settings/l10n/pl.json
+++ b/apps/settings/l10n/pl.json
@@ -128,7 +128,7 @@
"There are some user imported SSL certificates present, that are not used anymore with Nextcloud 21. They can be imported on the command line via \"occ security:certificates:import\" command. Their paths inside the data directory are shown below." : "Istnieją pewne certyfikaty SSL zaimportowane przez użytkownika, które nie są już używane z Nextcloud 21. Można je zaimportować z wiersza poleceń za pomocą polecenia \"occ security:certificates:import\". Ich ścieżki w katalogu danych są pokazane poniżej.",
"The old server-side-encryption format is enabled. We recommend disabling this." : "Stary format szyfrowania po stronie serwera jest włączony. Zalecamy wyłączenie jego.",
"MariaDB version \"%s\" is used. Nextcloud 21 will no longer support this version and requires MariaDB 10.2 or higher." : "Używana jest MariaDB w wersji \"%s\". Nextcloud 21 nie będzie już obsługiwać tej wersji i wymagać będzie MariaDB 10.2 lub nowszej.",
- "MySQL version \"%s\" is used. Nextcloud 21 will no longer support this version and requires MySQL 8.0 or MariaDB 10.2 or higher." : "Używana jest MySQL w wersji \"%s\". Nextcloud 21 nie będzie już obsługiwać tej wersji i wymagać będzie MySQL 8.0 lub MariaDB 10.2, lub nowszej.",
+ "MySQL version \"%s\" is used. Nextcloud 21 will no longer support this version and requires MySQL 8.0 or MariaDB 10.2 or higher." : "Używana jest MySQL w wersji \"%s\". Nextcloud 21 nie będzie już obsługiwać tej wersji i wymagać będzie MySQL 8.0 lub MariaDB 10.2, albo nowszej.",
"PostgreSQL version \"%s\" is used. Nextcloud 21 will no longer support this version and requires PostgreSQL 9.6 or higher." : "Używana jest PostgreSQL w wersji \"%s\". Nextcloud 21 nie będzie już obsługiwał tej wersji i wymagać będzie PostgreSQL 9.6 lub nowszego.",
"Nextcloud settings" : "Ustawienia Nextcloud",
"Two-factor authentication can be enforced for all users and specific groups. If they do not have a two-factor provider configured, they will be unable to log into the system." : "Uwierzytelnianie dwuskładnikowe może być wymuszane dla wszystkich użytkowników i określonych grup. Jeśli nie mają skonfigurowanego dostawcy logowania dwuskładnikowego, nie będą mogli zalogować się do systemu.",
diff --git a/core/Command/User/Report.php b/core/Command/User/Report.php
index 9df828ca7da..149abc006f9 100644
--- a/core/Command/User/Report.php
+++ b/core/Command/User/Report.php
@@ -90,6 +90,9 @@ class Report extends Command {
$rows[] = ['user directories', $userDirectoryCount];
}
+ $activeUsers = $this->userManager->countSeenUsers();
+ $rows[] = ['active users', $activeUsers];
+
$disabledUsers = $this->config->getUsersForUserValue('core', 'enabled', 'false');
$disabledUsersCount = count($disabledUsers);
$rows[] = ['disabled users', $disabledUsersCount];
diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php
index b20e028dcab..21caf6823f8 100644
--- a/lib/private/Comments/Manager.php
+++ b/lib/private/Comments/Manager.php
@@ -656,7 +656,7 @@ class Manager implements ICommentsManager {
$unreadComments = array_fill_keys($objectIds, 0);
foreach (array_chunk($objectIds, 1000) as $chunk) {
- $query->setParameter('ids', $chunk, IQueryBuilder::PARAM_INT_ARRAY);
+ $query->setParameter('ids', $chunk, IQueryBuilder::PARAM_STR_ARRAY);
$result = $query->executeQuery();
while ($row = $result->fetch()) {
diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php
index 454439a6f65..6e1e0997a68 100644
--- a/lib/private/Preview/Generator.php
+++ b/lib/private/Preview/Generator.php
@@ -224,6 +224,7 @@ class Generator {
$previewProviders = $this->previewManager->getProviders();
foreach ($previewProviders as $supportedMimeType => $providers) {
+ // Filter out providers that does not support this mime
if (!preg_match($supportedMimeType, $mimeType)) {
continue;
}
diff --git a/lib/private/Preview/Movie.php b/lib/private/Preview/Movie.php
index 80f2b5eb763..e7fc7745996 100644
--- a/lib/private/Preview/Movie.php
+++ b/lib/private/Preview/Movie.php
@@ -31,6 +31,7 @@ namespace OC\Preview;
use OCP\Files\File;
use OCP\IImage;
+use Psr\Log\LoggerInterface;
class Movie extends ProviderV2 {
public static $avconvBinary;
@@ -78,13 +79,13 @@ class Movie extends ProviderV2 {
$cmd = self::$avconvBinary . ' -y -ss ' . escapeshellarg($second) .
' -i ' . escapeshellarg($absPath) .
' -an -f mjpeg -vframes 1 -vsync 1 ' . escapeshellarg($tmpPath) .
- ' > /dev/null 2>&1';
+ ' 2>&1';
} else {
$cmd = self::$ffmpegBinary . ' -y -ss ' . escapeshellarg($second) .
' -i ' . escapeshellarg($absPath) .
' -f mjpeg -vframes 1' .
' ' . escapeshellarg($tmpPath) .
- ' > /dev/null 2>&1';
+ ' 2>&1';
}
exec($cmd, $output, $returnCode);
@@ -99,6 +100,10 @@ class Movie extends ProviderV2 {
return $image;
}
}
+
+ $logger = \OC::$server->get(LoggerInterface::class);
+ $logger->error('Movie preview generation failed Output: {output}', ['app' => 'core', 'output' => $output]);
+
unlink($tmpPath);
return null;
}